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