Merge branch 'pre_trustie_server' into trustie_server

This commit is contained in:
xiaoxiaoqiong 2022-06-02 16:41:51 +08:00
commit b3dfc72546
11 changed files with 553 additions and 422 deletions

View File

@ -2,8 +2,24 @@ class Admins::MessageTemplatesController < Admins::BaseController
before_action :get_template, only: [:edit, :update, :destroy] before_action :get_template, only: [:edit, :update, :destroy]
def index def index
message_templates = MessageTemplate.group(:type).count.keys message_templates = MessageTemplate.ransack(sys_notice_or_email_or_email_title_cont: params[:search]).result
@message_templates = kaminari_array_paginate(message_templates) @message_templates = kaminari_paginate(message_templates)
end
def new
@message_template = MessageTemplate::CustomTip.new
end
def create
@message_template = MessageTemplate::CustomTip.new(ignore_params)
if @message_template.save!
redirect_to admins_message_templates_path
flash[:success] = "创建消息模板成功"
else
render :new
flash[:danger] = "创建消息模板失败"
end
end end
def edit def edit

View File

@ -1,7 +1,7 @@
class NoticesController < ApplicationController class NoticesController < ApplicationController
def create def create
tip_exception("参数有误") if params["source"].blank? return tip_exception("参数有误") if params["source"].blank?
user_id = params[:user_id] user_id = params[:user_id]
if params["source"] == "CompetitionBegin" if params["source"] == "CompetitionBegin"
@ -13,9 +13,21 @@ class NoticesController < ApplicationController
elsif params["source"] == "CompetitionReview" elsif params["source"] == "CompetitionReview"
competition_id = params[:competition_id] competition_id = params[:competition_id]
SendTemplateMessageJob.perform_later('CompetitionReview', user_id, competition_id) SendTemplateMessageJob.perform_later('CompetitionReview', user_id, competition_id)
elsif params["source"] == "CustomTip"
users_id = params[:users_id]
props = params[:props].to_unsafe_hash
return tip_exception("参数有误") unless props.is_a?(Hash) && users_id.is_a?(Array)
template_id = params[:template_id]
SendTemplateMessageJob.perform_later('CustomTip', users_id, template_id, props)
else else
tip_exception("#{params["source"]}未配置") tip_exception("#{params["source"]}未配置")
end end
render_ok render_ok
end end
private
def params_props
params.require(:notice).permit(:props)
end
end end

View File

@ -4,6 +4,24 @@ class SendTemplateMessageJob < ApplicationJob
def perform(source, *args) def perform(source, *args)
Rails.logger.info "SendTemplateMessageJob [args] #{args}" Rails.logger.info "SendTemplateMessageJob [args] #{args}"
case source case source
when 'CustomTip'
receivers_id, template_id, props = args[0], args[1], args[2]
template = MessageTemplate.find_by_id(template_id)
return unless template.present?
receivers = User.where(id: receivers_id).or(User.where(mail: receivers_id))
not_exists_receivers = receivers_id - receivers.pluck(:id) - receivers.pluck(:mail)
receivers_string, content, notification_url = MessageTemplate::CustomTip.get_message_content(receivers, template, props)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {receivers_id: receivers_id, template_id: template_id, props: props})
receivers.find_each do |receiver|
receivers_email_string, email_title, email_content = MessageTemplate::CustomTip.get_email_message_content(receiver, template, props)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
not_exists_receivers.each do |mail|
valid_email_regex = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/i
next unless (mail =~ valid_email_regex)
email_title, email_content = MessageTemplate::CustomTip.get_email_content(template, props)
Notice::Write::EmailCreateService.call(mail, email_title, email_content)
end
when 'FollowTip' when 'FollowTip'
watcher_id = args[0] watcher_id = args[0]
watcher = Watcher.find_by_id(watcher_id) watcher = Watcher.find_by_id(watcher_id)

View File

@ -16,8 +16,7 @@ class MessageTemplate < ApplicationRecord
PLATFORM = 'GitLink' PLATFORM = 'GitLink'
def self.build_init_data def self.build_init_data
MessageTemplate::IssueAssignerExpire.destroy_all MessageTemplate.where.not(type: 'MessageTemplate::CustomTip').destroy_all
MessageTemplate::IssueCreatorExpire.destroy_all
self.create(type: 'MessageTemplate::FollowedTip', sys_notice: '<b>{nickname}</b> 关注了你', notification_url: '{baseurl}/{login}') self.create(type: 'MessageTemplate::FollowedTip', sys_notice: '<b>{nickname}</b> 关注了你', notification_url: '{baseurl}/{login}')
email_html = File.read("#{email_template_html_dir}/issue_assigned.html") email_html = File.read("#{email_template_html_dir}/issue_assigned.html")
self.create(type: 'MessageTemplate::IssueAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个疑修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 指派给你一个疑修") self.create(type: 'MessageTemplate::IssueAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个疑修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 指派给你一个疑修")

View File

@ -0,0 +1,70 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 统一模板(
class MessageTemplate::CustomTip < MessageTemplate
# MessageTemplate::CustomTip.get_message_content(User.where(login: 'yystopf'), "hahah")
def self.get_message_content(receivers, template, props={})
return '', '', '' if receivers.blank? || template.blank?
content = template.sys_notice
notification_url = template.notification_url
props.each do |k, v|
content.gsub!("{#{k}}", v)
notification_url.gsub!("{#{k}}", v)
end
notification_url.gsub!('{baseurl}', base_url)
return receivers_string(receivers), content, notification_url
rescue => e
Rails.logger.info("MessageTemplate::CustomTip.get_message_content [ERROR] #{e}")
return '', '', ''
end
def self.get_email_message_content(receiver, template, props={})
return '', '', '' if receiver.blank? || template.blank?
title = template.email_title
content = template.email
props.each do |k, v|
title.gsub!("{#{k}}", v)
content.gsub!("{#{k}}", v)
end
content.gsub!('{receiver}', receiver&.real_name)
title.gsub!('{platform}', PLATFORM)
content.gsub!('{platform}', PLATFORM)
content.gsub!('{baseurl}', base_url)
return receiver&.mail, title, content
rescue => e
Rails.logger.info("MessageTemplate::CustomTip.get_email_message_content [ERROR] #{e}")
return '', '', ''
end
def self.get_email_content(template, props = {})
return '', '', '' if template.blank?
title = template.email_title
content = template.email
props.each do |k, v|
title.gsub!("{#{k}}", v)
content.gsub!("{#{k}}", v)
end
title.gsub!('{platform}', PLATFORM)
content.gsub!('{platform}', PLATFORM)
return title, content
rescue => e
Rails.logger.info("MessageTemplate::CustomTip.get_email_content [ERROR] #{e}")
return '', ''
end
end

View File

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

View File

@ -11,8 +11,8 @@
</thead> </thead>
<tbody> <tbody>
<% if message_templates.present? %> <% if message_templates.present? %>
<% message_templates.each_with_index do |message_template_type, index| %> <% message_templates.each_with_index do |message_template, index| %>
<% message_template = message_template_type.constantize.last%> <%# message_template = message_template_type.constantize.last%>
<tr class="project-language-item-<%= message_template.id %>"> <tr class="project-language-item-<%= message_template.id %>">
<td><%= list_index_no((params[:page] || 1).to_i, index) %></td> <td><%= list_index_no((params[:page] || 1).to_i, index) %></td>
<td><%= message_template.simple_type %></td> <td><%= message_template.simple_type %></td>

View File

@ -3,7 +3,13 @@
<% end %> <% end %>
<div id="admins-message-templates-content"> <div id="admins-message-templates-content">
<div class="box search-form-container project-list-form"> <div class="box search-form-container project-list-form">
<%= link_to "初始化数据", init_data_admins_message_templates_path, class: "btn btn-primary pull-right", "data-disabled-with":"...初始化数据" %> <%= form_tag(admins_message_templates_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %>
<%= text_field_tag(:search, params[:search], class: 'form-control col-12 col-md-2 mr-3', placeholder: '名称检索') %>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<input type="reset" class="btn btn-secondary clear-btn" value="清空"/>
<% end %>
<%= link_to "初始化数据", init_data_admins_message_templates_path, class: "btn btn-primary mr-3 pull-right", "data-disabled-with":"...初始化数据" %>
<%= link_to "新增", new_admins_message_template_path, remote: true, class: "btn btn-primary pull-right", "data-disabled-with":"...新增" %>
</div> </div>
<div class="box admin-list-container message-templates-list-container"> <div class="box admin-list-container message-templates-list-container">
<%= render partial: 'admins/message_templates/list', locals: { message_templates: @message_templates } %> <%= render partial: 'admins/message_templates/list', locals: { message_templates: @message_templates } %>

View File

@ -0,0 +1,2 @@
$("#admins-message-templates-content").html("<%= j render partial: 'admins/message_templates/form', locals:{type: 'create'} %>")
createMDEditor('message-template-email-editor', { height: 500, placeholder: '请输入邮件模版' });

View File

@ -1,6 +1,6 @@
json.total_count @projects.total_count json.total_count @projects.total_count
json.projects @projects.each do |project| json.projects @projects.each do |project|
json.(project, :id, :name, :identifier, :description, :forked_count, :praises_count, :forked_from_project_id) json.(project, :id, :name, :identifier, :description, :forked_count, :praises_count, :forked_from_project_id, :is_public)
json.mirror_url project.repository&.mirror_url json.mirror_url project.repository&.mirror_url
json.type project.numerical_for_project_type json.type project.numerical_for_project_type
json.praised project.praised_by?(current_user) json.praised project.praised_by?(current_user)

View File

@ -729,7 +729,7 @@ Rails.application.routes.draw do
get :history get :history
end end
end end
resources :message_templates, only: [:index, :edit, :update] do resources :message_templates, only: [:index, :new, :create, :edit, :update] do
collection do collection do
get :init_data get :init_data
end end