fluke/devops-service/db/mongo/models/project.rb
Tim Lianov 03dc3d8d99 v3
2018-04-04 22:44:39 +03:00

240 lines
8.9 KiB
Ruby

require "db/mongo/models/environment/environment"
require "db/mongo/models/user"
require "db/mongo/models/environment/environments_array"
require "json"
require "hooks"
require "lib/project/type/types_factory"
require "exceptions/invalid_record"
require "exceptions/record_not_found"
#require "db/validators/environment/environments"
require "db/validators/project/named_tasks"
module Devops
module Model
class Project
include Hooks
include Hooks::InstanceHooks
define_hook :before_create
define_hook :after_create
define_hook :before_delete
define_hook :after_delete
include ::Mongoid::Document
include ::Mongoid::Timestamps::CreatedInt
include ::ActiveModel::Validations
#attr_accessor :components
store_in collection: "projects"
field :_id, as: :'id', overwrite: true, type: String
field :environments, type: EnvironmentsArray, default: ->{ [] }
field :type, type: String
field :owner, type: String
field :project_users, type: Array, default: ->{ [] }
field :archived, type: Boolean
field :description, type: String
field :run_list, type: Array, default: ->{ [] }
field :named_tasks, type: Array, default: ->{ [] }
MAX_ID_LEN = 100
ID_REGEX = /\A[\w\-\.]{1,#{MAX_ID_LEN}}\z/
validates_presence_of :id, message: "'id' is undefined"
validates_length_of :id, minimum: 1, maximum: MAX_ID_LEN
validates_format_of :id, with: ID_REGEX, message: "invalid id, it should contains 'a-zA-Z0-9-.' symbols"
validates_uniqueness_of :id, on: :create
validates_length_of :description, maximum: 500
validates_presence_of :owner, message: "'owner' is undefined"
validates :named_tasks, proper_named_tasks_format: true
=begin
TODO:
set_field_validators :named_tasks, [::Validators::FieldValidator::Nil,
::Validators::FieldValidator::FieldType::Array,
::Validators::FieldValidator::NamedTasks]
set_validators ::Validators::DeployEnv::RunList,
::Validators::DeployEnv::DeployEnvs
=end
validates_length_of :description, maximum: 500
#TODO: self.named_tasks = p["named_tasks"] || []
def initialize hash
raise InvalidRecord.new("Parameter 'id' is not a string") unless hash["id"].is_a?(String)
raise InvalidRecord.new("Parameter 'environments' is not an array") unless hash["environments"].is_a?(Array) or hash["environments"].nil?
raise InvalidRecord.new("Parameter 'run_list' is not an array") unless hash["run_list"].is_a?(Array) or hash["run_list"].nil?
raise InvalidRecord.new("Parameter 'project_users' is not an array") unless hash["project_users"].is_a?(Array) or hash["project_users"].nil?
super(hash)
end
def self.find_with_environment id, environment
Project.find_by({_id: id, environments:{'$elemMatch' => {id: environment}}})
end
def self.find_with_category id, environment, category
Project.find_by(
_id: id,
environments: {
'$elemMatch' => {
id: environment,
categories: {'$elemMatch' => {id: category}}
}
}
)
end
# TODO: extract to handler or parser
def self.list_fields
['deploy_envs', 'type', 'description', 'named_tasks']
end
def self.check_user_authorization project_id, env, user_id
# find({'_id' => project_id}).projection({environments:{'$elemMatch' => {id:env}}})
project = find(project_id)
if !project.check_authorization(user_id, env)
raise Devops::Exception::Unauthorized.new("User '#{user_id}' is unauthorized to work with project '#{project_id}' and environment '#{env}'")
end
project
rescue Mongoid::Errors::DocumentNotFound
raise Devops::Exception::RecordNotFound.new("Project with id '#{project_id}' not found")
end
def environment env
de = self.environments.detect {|e| e.id == env}
raise Devops::Exception::RecordNotFound.new("Project '#{self.id}' does not have deploy environment '#{env}'") if de.nil?
de
end
def add_environment environment
self.push(environments: environment.to_hash)
DevopsLogger.logger.info("Added environment '#{environment.id}' to project '#{self.id}'")
DevopsLogger.logger.debug("Added environment: #{environment.to_hash.inspect}")
end
def add_category env, category
env.categories.push category
category_hash = category.to_hash
Project.where('_id' => self.id, 'environments.id' => env.id).push('environments.$.categories' => category_hash)
DevopsLogger.logger.debug("Added category '#{category.id}' to project '#{self.id}' and environment '#{env.id}'")
DevopsLogger.logger.debug("Added category: #{category_hash.inspect}")
category
end
def delete_category env, category_id
bsize = env.categories.size
env.categories.delete_if{|c| c.id == category_id}
if bsize == env.categories.size
raise Devops::Exception::RecordNotFound.new("Category '#{category_id}' in project '#{id}' and deploy environment '#{env}' does not exist")
else
Project.where({'_id' => self.id, 'environments.id' => env.id}).pull('environments.$.categories' => {'id' => category_id})
DevopsLogger.logger.info("Category '#{category_id}' removed from project '#{self.id}' and environment '#{env.id}'")
end
end
# user could be a String or an Array of strings.
# if env is nil, add given user(s) to all project's envs,
# otherwise only to specified one.
def add_authorized_user user, env=nil
return if user.nil?
new_users = ( user.is_a?(Array) ? user : [ user ] )
environments = env.nil? ? self.environments : [ self.environment(env) ]
environments.each do |e|
e.add_users new_users
Devops::Db.connector.set_project_environment_field(self.id, e.id, {users: e.users})
end
end
def remove_authorized_user user, env=nil
return if user.nil?
users = ( user.is_a?(Array) ? user : [ user ] )
environments = env.nil? ? self.environments : [ self.environment(env) ]
environments.each do |e|
e.users = e.users - users
Devops::Db.connector.set_project_environment_field(self.id, e.id, {users: e.users})
end
end
def check_authorization user_id, env
return true if user_id == self.owner or user_id == User::ROOT_USER_NAME
return true if is_sandbox?
e = self.environment(env)
return e.users.include? user_id
rescue Devops::Exception::RecordNotFound => e
return false
end
def is_sandbox?
id.start_with?('sandbox-')
end
def delete_environment env
self.environments.delete_if {|e| e.id == env}
Project.where('_id' => self.id).pull('environments' => {'id' => env})
end
def to_hash
hash = self.attributes.clone
hash["id"] = hash.delete("_id")
hash.delete('archived') unless hash['archived']
hash
end
# TODO: why symbols here?
def to_hash_list
{
id: self.id,
description: self.description,
owner: self.owner,
run_list: self.run_list,
project_users: self.project_users,
created_at: self.created_at
}
end
def deploy_info environment, build_number=nil
{
"use_json_file" => false,
# "run_list" => Set.new.merge(self.run_list).merge(environment.run_list).to_a,
"project" => self.id,
"project_info" => {
"project" => self.id,
"environment" => environment.id,
"deployers" => environment.users
}
}
end
=begin
def extract_servers env, params
@handler.extract_servers(self, env, params)
end
# maybe it worth to move components functionality to devops-nibr?
#TODO: create validator
def validate_components
raise InvalidRecord.new "Components is not a hash" unless self.components.is_a?(Hash)
self.components.each do |id, c|
raise InvalidRecord.new "Component '#{id}' has no attribute 'fileid'" unless c.key?("fileid")
end
end
=end
# def self.create_roles_response roles
# return "error in creating roles" unless roles
# info = ''
# info += "Project roles '#{roles[:new].join("', '")}' have been automaticaly created" unless roles[:new].nil?
# info += " Project roles '#{roles[:exist].join("', '")}' weren't created because they exist" unless roles[:exist].nil?
# info += " Project roles '#{roles[:error].join("', '")}' weren't created because of internal error" unless roles[:error].nil?
# info
# end
end
end
end