diff --git a/app/models/project.rb b/app/models/project.rb index 1edc088f6..0489c8c82 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,412 +1,419 @@ -# == Schema Information -# -# Table name: projects -# -# id :integer not null, primary key -# name :string(255) default(""), not null -# description :text(4294967295) -# homepage :string(255) default("") -# is_public :boolean default("1"), not null -# parent_id :integer -# created_on :datetime -# updated_on :datetime -# identifier :string(255) -# status :integer default("1"), not null -# lft :integer -# rgt :integer -# inherit_members :boolean default("0"), not null -# project_type :integer default("0") -# hidden_repo :boolean default("0"), not null -# attachmenttype :integer default("1") -# user_id :integer -# dts_test :integer default("0") -# enterprise_name :string(255) -# organization_id :integer -# project_new_type :integer -# gpid :integer -# forked_from_project_id :integer -# forked_count :integer default("0") -# publish_resource :integer default("0") -# visits :integer default("0") -# hot :integer default("0") -# invite_code :string(255) -# qrcode :string(255) -# qrcode_expiretime :integer default("0") -# script :text(65535) -# training_status :integer default("0") -# rep_identifier :string(255) -# project_category_id :integer -# project_language_id :integer -# praises_count :integer default("0") -# watchers_count :integer default("0") -# issues_count :integer default("0") -# pull_requests_count :integer default("0") -# language :string(255) -# versions_count :integer default("0") -# issue_tags_count :integer default("0") -# closed_issues_count :integer default("0") -# open_devops :boolean default("0") -# gitea_webhook_id :integer -# open_devops_count :integer default("0") -# recommend :boolean default("0") -# platform :integer default("0") -# license_id :integer -# ignore_id :integer -# default_branch :string(255) default("master") -# website :string(255) -# lesson_url :string(255) -# is_pinned :boolean default("0") -# recommend_index :integer default("0") -# -# Indexes -# -# index_projects_on_forked_from_project_id (forked_from_project_id) -# index_projects_on_identifier (identifier) -# index_projects_on_invite_code (invite_code) -# index_projects_on_is_public (is_public) -# index_projects_on_lft (lft) -# index_projects_on_license_id (license_id) -# index_projects_on_name (name) -# index_projects_on_platform (platform) -# index_projects_on_project_category_id (project_category_id) -# index_projects_on_project_language_id (project_language_id) -# index_projects_on_project_type (project_type) -# index_projects_on_recommend (recommend) -# index_projects_on_rgt (rgt) -# index_projects_on_status (status) -# index_projects_on_updated_on (updated_on) -# - -class Project < ApplicationRecord - include Matchable - include Publicable - include Watchable - include ProjectOperable - include Dcodes - - # common:开源托管项目 - # mirror:普通镜像项目,没有定时同步功能 - # sync_mirror:同步镜像项目,有系统定时同步功能,且用户可手动同步操作 - # - enum project_type: { sync_mirror: 2, mirror: 1, common: 0 } - - # forge: trustie平台项目, educoder: educoder平台项目, 默认为forge平台 - enum platform: { forge: 0, educoder: 1 } - - belongs_to :ignore, optional: true - belongs_to :license, optional: true - belongs_to :owner, class_name: 'Owner', foreign_key: :user_id, optional: true - belongs_to :organization_extension, foreign_key: :user_id, primary_key: :organization_id, optional: true, counter_cache: :num_projects - belongs_to :project_category, optional: true , :counter_cache => true - belongs_to :project_language, optional: true , :counter_cache => true - belongs_to :forked_from_project, class_name: 'Project', optional: true, foreign_key: :forked_from_project_id - has_many :project_trends, dependent: :destroy - has_many :watchers, as: :watchable, dependent: :destroy - has_many :fork_users, dependent: :destroy - has_many :forked_users, class_name: 'ForkUser', foreign_key: :fork_project_id, dependent: :destroy - has_many :forked_projects, class_name: 'Project', foreign_key: :forked_from_project_id - has_one :project_educoder, dependent: :destroy - - has_one :project_score, dependent: :destroy - has_one :repository, dependent: :destroy - has_many :pull_requests, dependent: :destroy - has_many :issue_tags, -> { order("issue_tags.created_at DESC") }, dependent: :destroy - has_many :issues, dependent: :destroy - # has_many :user_grades, dependent: :destroy - has_many :attachments, as: :container, dependent: :destroy - has_one :project_score, dependent: :destroy - has_many :versions, -> { order("versions.created_on DESC, versions.name DESC") }, dependent: :destroy - has_many :praise_treads, as: :praise_tread_object, dependent: :destroy - has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" - has_one :project_detail, dependent: :destroy - has_many :project_units, dependent: :destroy - has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy - has_many :pinned_projects, dependent: :destroy - has_many :has_pinned_users, through: :pinned_projects, source: :user - has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id - has_many :user_trace_tasks, dependent: :destroy - after_create :incre_user_statistic, :incre_platform_statistic - after_save :check_project_members - before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data - before_destroy :decre_project_common, :decre_forked_from_project_count - after_destroy :decre_user_statistic, :decre_platform_statistic - scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :description, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)} - scope :no_anomory_projects, -> {where("projects.user_id is not null and projects.user_id != ?", 2)} - scope :recommend, -> { visible.project_statics_select.where(recommend: true) } - scope :pinned, -> {where(is_pinned: true)} - - delegate :content, to: :project_detail, allow_nil: true - delegate :name, to: :license, prefix: true, allow_nil: true - - def self.all_visible(user_id=nil) - user_projects_sql = Project.joins(:owner).where(users: {type: 'User'}).to_sql - org_public_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'common'})).to_sql - if user_id.present? - org_limit_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'limited'})).to_sql - org_privacy_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension, :organization_users).where(organization_extensions: {visibility: 'privacy'}, organization_users: {user_id: user_id})).to_sql - return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } UNION #{ org_limit_projects_sql } UNION #{org_privacy_projects_sql} ) AS projects").visible - else - return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } ) AS projects").visible - end - end - - def reset_cache_data - CacheAsyncResetJob.set(wait: 5.seconds).perform_later("project_common_service", self.id) - if changes[:user_id].present? - CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1}, changes[:user_id].first) - CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1}, changes[:user_id].last) - end - if changes[:project_language_id].present? - first_language = ProjectLanguage.find_by_id(changes[:project_language_id].first) - last_language = ProjectLanguage.find_by_id(changes[:project_language_id].last) - CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}, self.user_id) - CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}, self.user_id) - CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}) - CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}) - end - if changes[:is_public].present? - if changes[:is_public][0] && !changes[:is_public][1] - CacheAsyncClearJob.perform_later('project_rank_service', self.id) - end - if !changes[:is_public][0] && changes[:is_public][1] - $redis_cache.srem("v2-project-rank-deleted", self.id) - end - end - end - - def decre_project_common - CacheAsyncClearJob.perform_later('project_common_service', self.id) - end - - def decre_forked_from_project_count - forked_project = self.forked_from_project - if forked_project.present? - forked_project.decrement(:forked_count, 1) - forked_project.save - end - end - - def incre_user_statistic - CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}, self.user_id) - end - - def decre_user_statistic - CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}, self.user_id) - end - - def incre_platform_statistic - CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}) - end - - def decre_platform_statistic - CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}) - end - - def is_full_public - owner = self.owner - if owner.is_a?(Organization) - return self.is_public && owner&.visibility == "common" - else - return self.is_public - end - end - - def reset_unmember_followed - if changes[:is_public].present? && changes[:is_public] == [true, false] - self.watchers.where.not(user_id: self.all_collaborators).destroy_all - end - end - - def set_invite_code - if self.invite_code.nil? - self.invite_code= self.generate_dcode('invite_code', 6) - end - end - - def set_recommend_and_is_pinned - self.recommend = self.recommend_index.zero? ? false : true - # 私有项目不允许设置精选和推荐 - unless self.is_public - self.recommend = false - self.recommend_index = 0 - self.is_pinned = false - end - end - - def self.search_project(search) - ransack(name_or_identifier_cont: search) - end - # 创建者 - def creator - User.find(user_id).full_name - end - - def members_user_infos - members.joins(:roles).where("roles.name in ('Manager', 'Developer', 'Reporter')").joins("left join users on members.user_id = users.id ").includes(:user).where("users.type = ?", "User") - # members.joins("left join users on members.user_id = users.id").select("users.id", "users.login","users.firstname","users.lastname") - # .pluck("users.id", "users.login","users.lastname", "users.firstname") - end - - def to_param - self.identifier.parameterize - end - - def get_issues_count(status_id) - if status_id.present? - self&.issues.issue_issue.select(:id, :status_id).where(status_id: status_id)&.pluck(:id).size - else - self&.issues.issue_issue.select(:id)&.pluck(:id).size - end - end - - def get_pull_requests_count(status_id) - if status_id.present? - self&.pull_requests.select(:id, :status).where(status: status_id)&.pluck(:id).size - else - self&.pull_requests.select(:id)&.pluck(:id).size - end - end - - #创建项目管理员 - def check_project_members - return if owner.is_a?(Organization) - unless members.present? && members.exists?(user_id: self.user_id) - member_params = { - user_id: self.user_id, - project_id: self.id - } - user_member = Member.new(member_params) - if user_member.save - role_id = Role.select(:id,:position).where(position: 3)&.first&.id - MemberRole.create!(member_id: user_member.id ,role_id: role_id) - end - end - end - - - def self.init_bluck_repository - Project.includes(:repository).find_each do |project| - puts project.id - next if project.owner.blank? - if project.repository.blank? - puts "########### start create repositoy #############" - Repository.create!(project_id: project.id, identifier: Project.generate_identifier, user_id: project&.owner&.id) - end - end - end - - def self.generate_identifier - str_arr = (("a".."z").to_a + ("A".."Z").to_a) - - str = str_arr.shuffle[0..8].join - while Repository.exists?(identifier: str) - str = str_arr.shuffle[0..8].join - end - str - end - - def self.list_user_projects(user_id) - projects = Project.is_private.select(:id,:user_id) - user_not_show_1 = projects.where("user_id != ?",user_id).pluck(:id).uniq - - user_show_2 = projects.joins(:members).where("members.user_id = ?", user_id).pluck(:id).uniq - Project.where.not(id: (user_not_show_1 - user_show_2).uniq) - end - - def members_count - members.select(:id).size - end - - - def can_visited? - is_public? || User.current.admin? || member?(User.current) - end - - def releases_size(current_user_id, type) - if current_user_id == self.user_id && type.to_s == "all" - self.repository.version_releases_count - else - self.repository.version_releases.releases_size - end - end - - def contributor_users - self.pull_requests.select(:user_id).pluck(:user_id).uniq.size - end - - def open_issues_count - issues_count - closed_issues_count - end - - def numerical_for_project_type - self.class.name.constantize.project_types["#{self.project_type}"] - end - - def watched_by? user - watchers.pluck(:user_id).include? user&.id - end - - def praised_by? user - praise_treads.pluck(:user_id).include? user&.id - end - - def get_premission user - return "Owner" if owner?(user) - return "Manager" if manager?(user) - return "Developer" if develper?(user) - return "Reporter" if reporter?(user) - - return "" - end - - def fork_project - Project.find_by(id: self.forked_from_project_id) - end - - def self.members_projects(member_user_id) - joins(:members).where(members: { user_id: member_user_id}) - end - - def self.find_with_namespace(namespace_path, identifier) - logger.info "########namespace_path: #{namespace_path} ########identifier: #{identifier} " - - user = Owner.find_by_login namespace_path - project = user&.projects&.find_by(identifier: identifier) || Project.find_by(identifier: "#{namespace_path}/#{identifier}") - return nil if project.blank? - - [project, user] - end - - def ci_reactivate? - open_devops_count > 0 - end - - def ci_reactivate!(ci_repo) - ci_repo.update_column(:repo_active, 1) - update_column(:open_devops, true) - increment!(:open_devops_count) - end - - def self.sync_educoder_shixun(url, private_token, page, per_page) - SyncEducoderShixunJob.perform_later(url, private_token, page, per_page) - end - - def self.update_common_projects_count! - ps = ProjectStatistic.first - ps.increment!(:common_projects_count) unless ps.blank? - end - - def self.update_mirror_projects_count! - ps = ProjectStatistic.first - ps.increment!(:mirror_projects_count) unless ps.blank? - end - - def set_updated_on(time) - return if time.blank? - update_column(:updated_on, time) - end - - def is_transfering - applied_transfer_project&.common? ? true : false - end -end +# == Schema Information +# +# Table name: projects +# +# id :integer not null, primary key +# name :string(255) default(""), not null +# description :text(4294967295) +# homepage :string(255) default("") +# is_public :boolean default("1"), not null +# parent_id :integer +# created_on :datetime +# updated_on :datetime +# identifier :string(255) +# status :integer default("1"), not null +# lft :integer +# rgt :integer +# inherit_members :boolean default("0"), not null +# project_type :integer default("0") +# hidden_repo :boolean default("0"), not null +# attachmenttype :integer default("1") +# user_id :integer +# dts_test :integer default("0") +# enterprise_name :string(255) +# organization_id :integer +# project_new_type :integer +# gpid :integer +# forked_from_project_id :integer +# forked_count :integer default("0") +# publish_resource :integer default("0") +# visits :integer default("0") +# hot :integer default("0") +# invite_code :string(255) +# qrcode :string(255) +# qrcode_expiretime :integer default("0") +# script :text(65535) +# training_status :integer default("0") +# rep_identifier :string(255) +# project_category_id :integer +# project_language_id :integer +# praises_count :integer default("0") +# watchers_count :integer default("0") +# issues_count :integer default("0") +# pull_requests_count :integer default("0") +# language :string(255) +# versions_count :integer default("0") +# issue_tags_count :integer default("0") +# closed_issues_count :integer default("0") +# open_devops :boolean default("0") +# gitea_webhook_id :integer +# open_devops_count :integer default("0") +# recommend :boolean default("0") +# platform :integer default("0") +# license_id :integer +# ignore_id :integer +# default_branch :string(255) default("master") +# website :string(255) +# lesson_url :string(255) +# is_pinned :boolean default("0") +# recommend_index :integer default("0") +# +# Indexes +# +# index_projects_on_forked_from_project_id (forked_from_project_id) +# index_projects_on_identifier (identifier) +# index_projects_on_invite_code (invite_code) +# index_projects_on_is_public (is_public) +# index_projects_on_lft (lft) +# index_projects_on_license_id (license_id) +# index_projects_on_name (name) +# index_projects_on_platform (platform) +# index_projects_on_project_category_id (project_category_id) +# index_projects_on_project_language_id (project_language_id) +# index_projects_on_project_type (project_type) +# index_projects_on_recommend (recommend) +# index_projects_on_rgt (rgt) +# index_projects_on_status (status) +# index_projects_on_updated_on (updated_on) +# + +class Project < ApplicationRecord + include Matchable + include Publicable + include Watchable + include ProjectOperable + include Dcodes + + # common:开源托管项目 + # mirror:普通镜像项目,没有定时同步功能 + # sync_mirror:同步镜像项目,有系统定时同步功能,且用户可手动同步操作 + # + enum project_type: { sync_mirror: 2, mirror: 1, common: 0 } + + # forge: trustie平台项目, educoder: educoder平台项目, 默认为forge平台 + enum platform: { forge: 0, educoder: 1 } + + belongs_to :ignore, optional: true + belongs_to :license, optional: true + belongs_to :owner, class_name: 'Owner', foreign_key: :user_id, optional: true + belongs_to :organization_extension, foreign_key: :user_id, primary_key: :organization_id, optional: true, counter_cache: :num_projects + belongs_to :project_category, optional: true , :counter_cache => true + belongs_to :project_language, optional: true , :counter_cache => true + belongs_to :forked_from_project, class_name: 'Project', optional: true, foreign_key: :forked_from_project_id + has_many :project_trends, dependent: :destroy + has_many :watchers, as: :watchable, dependent: :destroy + has_many :fork_users, dependent: :destroy + has_many :forked_users, class_name: 'ForkUser', foreign_key: :fork_project_id, dependent: :destroy + has_many :forked_projects, class_name: 'Project', foreign_key: :forked_from_project_id + has_one :project_educoder, dependent: :destroy + + has_one :project_score, dependent: :destroy + has_one :repository, dependent: :destroy + has_many :pull_requests, dependent: :destroy + has_many :issue_tags, -> { order("issue_tags.created_at DESC") }, dependent: :destroy + has_many :issues, dependent: :destroy + # has_many :user_grades, dependent: :destroy + has_many :attachments, as: :container, dependent: :destroy + has_one :project_score, dependent: :destroy + has_many :versions, -> { order("versions.created_on DESC, versions.name DESC") }, dependent: :destroy + has_many :praise_treads, as: :praise_tread_object, dependent: :destroy + has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" + has_one :project_detail, dependent: :destroy + has_many :project_units, dependent: :destroy + has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy + has_many :pinned_projects, dependent: :destroy + has_many :has_pinned_users, through: :pinned_projects, source: :user + has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id + has_many :user_trace_tasks, dependent: :destroy + after_create :incre_user_statistic, :incre_platform_statistic + after_save :check_project_members + before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data + before_destroy :decre_project_common, :decre_forked_from_project_count + after_destroy :decre_user_statistic, :decre_platform_statistic + scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :description, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)} + scope :no_anomory_projects, -> {where("projects.user_id is not null and projects.user_id != ?", 2)} + scope :recommend, -> { visible.project_statics_select.where(recommend: true) } + scope :pinned, -> {where(is_pinned: true)} + + delegate :content, to: :project_detail, allow_nil: true + delegate :name, to: :license, prefix: true, allow_nil: true + + validate :validate_sensitive_string + + def self.all_visible(user_id=nil) + user_projects_sql = Project.joins(:owner).where(users: {type: 'User'}).to_sql + org_public_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'common'})).to_sql + if user_id.present? + org_limit_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'limited'})).to_sql + org_privacy_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension, :organization_users).where(organization_extensions: {visibility: 'privacy'}, organization_users: {user_id: user_id})).to_sql + return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } UNION #{ org_limit_projects_sql } UNION #{org_privacy_projects_sql} ) AS projects").visible + else + return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } ) AS projects").visible + end + end + + def reset_cache_data + CacheAsyncResetJob.set(wait: 5.seconds).perform_later("project_common_service", self.id) + if changes[:user_id].present? + CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1}, changes[:user_id].first) + CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1}, changes[:user_id].last) + end + if changes[:project_language_id].present? + first_language = ProjectLanguage.find_by_id(changes[:project_language_id].first) + last_language = ProjectLanguage.find_by_id(changes[:project_language_id].last) + CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}, self.user_id) + CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}, self.user_id) + CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}) + CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}) + end + if changes[:is_public].present? + if changes[:is_public][0] && !changes[:is_public][1] + CacheAsyncClearJob.perform_later('project_rank_service', self.id) + end + if !changes[:is_public][0] && changes[:is_public][1] + $redis_cache.srem("v2-project-rank-deleted", self.id) + end + end + end + + def decre_project_common + CacheAsyncClearJob.perform_later('project_common_service', self.id) + end + + def decre_forked_from_project_count + forked_project = self.forked_from_project + if forked_project.present? + forked_project.decrement(:forked_count, 1) + forked_project.save + end + end + + def incre_user_statistic + CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}, self.user_id) + end + + def decre_user_statistic + CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}, self.user_id) + end + + def incre_platform_statistic + CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}) + end + + def decre_platform_statistic + CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}) + end + + def is_full_public + owner = self.owner + if owner.is_a?(Organization) + return self.is_public && owner&.visibility == "common" + else + return self.is_public + end + end + + def reset_unmember_followed + if changes[:is_public].present? && changes[:is_public] == [true, false] + self.watchers.where.not(user_id: self.all_collaborators).destroy_all + end + end + + def set_invite_code + if self.invite_code.nil? + self.invite_code= self.generate_dcode('invite_code', 6) + end + end + + def set_recommend_and_is_pinned + self.recommend = self.recommend_index.zero? ? false : true + # 私有项目不允许设置精选和推荐 + unless self.is_public + self.recommend = false + self.recommend_index = 0 + self.is_pinned = false + end + end + + def self.search_project(search) + ransack(name_or_identifier_cont: search) + end + # 创建者 + def creator + User.find(user_id).full_name + end + + def members_user_infos + members.joins(:roles).where("roles.name in ('Manager', 'Developer', 'Reporter')").joins("left join users on members.user_id = users.id ").includes(:user).where("users.type = ?", "User") + # members.joins("left join users on members.user_id = users.id").select("users.id", "users.login","users.firstname","users.lastname") + # .pluck("users.id", "users.login","users.lastname", "users.firstname") + end + + def to_param + self.identifier.parameterize + end + + def get_issues_count(status_id) + if status_id.present? + self&.issues.issue_issue.select(:id, :status_id).where(status_id: status_id)&.pluck(:id).size + else + self&.issues.issue_issue.select(:id)&.pluck(:id).size + end + end + + def get_pull_requests_count(status_id) + if status_id.present? + self&.pull_requests.select(:id, :status).where(status: status_id)&.pluck(:id).size + else + self&.pull_requests.select(:id)&.pluck(:id).size + end + end + + #创建项目管理员 + def check_project_members + return if owner.is_a?(Organization) + unless members.present? && members.exists?(user_id: self.user_id) + member_params = { + user_id: self.user_id, + project_id: self.id + } + user_member = Member.new(member_params) + if user_member.save + role_id = Role.select(:id,:position).where(position: 3)&.first&.id + MemberRole.create!(member_id: user_member.id ,role_id: role_id) + end + end + end + + + def self.init_bluck_repository + Project.includes(:repository).find_each do |project| + puts project.id + next if project.owner.blank? + if project.repository.blank? + puts "########### start create repositoy #############" + Repository.create!(project_id: project.id, identifier: Project.generate_identifier, user_id: project&.owner&.id) + end + end + end + + def self.generate_identifier + str_arr = (("a".."z").to_a + ("A".."Z").to_a) + + str = str_arr.shuffle[0..8].join + while Repository.exists?(identifier: str) + str = str_arr.shuffle[0..8].join + end + str + end + + def self.list_user_projects(user_id) + projects = Project.is_private.select(:id,:user_id) + user_not_show_1 = projects.where("user_id != ?",user_id).pluck(:id).uniq + + user_show_2 = projects.joins(:members).where("members.user_id = ?", user_id).pluck(:id).uniq + Project.where.not(id: (user_not_show_1 - user_show_2).uniq) + end + + def members_count + members.select(:id).size + end + + + def can_visited? + is_public? || User.current.admin? || member?(User.current) + end + + def releases_size(current_user_id, type) + if current_user_id == self.user_id && type.to_s == "all" + self.repository.version_releases_count + else + self.repository.version_releases.releases_size + end + end + + def contributor_users + self.pull_requests.select(:user_id).pluck(:user_id).uniq.size + end + + def open_issues_count + issues_count - closed_issues_count + end + + def numerical_for_project_type + self.class.name.constantize.project_types["#{self.project_type}"] + end + + def watched_by? user + watchers.pluck(:user_id).include? user&.id + end + + def praised_by? user + praise_treads.pluck(:user_id).include? user&.id + end + + def get_premission user + return "Owner" if owner?(user) + return "Manager" if manager?(user) + return "Developer" if develper?(user) + return "Reporter" if reporter?(user) + + return "" + end + + def fork_project + Project.find_by(id: self.forked_from_project_id) + end + + def self.members_projects(member_user_id) + joins(:members).where(members: { user_id: member_user_id}) + end + + def self.find_with_namespace(namespace_path, identifier) + logger.info "########namespace_path: #{namespace_path} ########identifier: #{identifier} " + + user = Owner.find_by_login namespace_path + project = user&.projects&.find_by(identifier: identifier) || Project.find_by(identifier: "#{namespace_path}/#{identifier}") + return nil if project.blank? + + [project, user] + end + + def ci_reactivate? + open_devops_count > 0 + end + + def ci_reactivate!(ci_repo) + ci_repo.update_column(:repo_active, 1) + update_column(:open_devops, true) + increment!(:open_devops_count) + end + + def self.sync_educoder_shixun(url, private_token, page, per_page) + SyncEducoderShixunJob.perform_later(url, private_token, page, per_page) + end + + def self.update_common_projects_count! + ps = ProjectStatistic.first + ps.increment!(:common_projects_count) unless ps.blank? + end + + def self.update_mirror_projects_count! + ps = ProjectStatistic.first + ps.increment!(:mirror_projects_count) unless ps.blank? + end + + def set_updated_on(time) + return if time.blank? + update_column(:updated_on, time) + end + + def is_transfering + applied_transfer_project&.common? ? true : false + end + + def validate_sensitive_string + raise("项目名称包含敏感词汇,请重新输入") if name && !HarmoniousDictionary.clean?(name) + raise("项目描述包含敏感词汇,请重新输入") if description && !HarmoniousDictionary.clean?(description) + end +end