| @@ -92,6 +92,7 @@ class Api::V1::IssuesController < Api::V1::BaseController | |||||
| :keyword, :author_id, | :keyword, :author_id, | ||||
| :milestone_id, :assigner_id, | :milestone_id, :assigner_id, | ||||
| :status_id, | :status_id, | ||||
| :begin_date, :end_date, | |||||
| :sort_by, :sort_direction, | :sort_by, :sort_direction, | ||||
| :issue_tag_ids) | :issue_tag_ids) | ||||
| end | end | ||||
| @@ -39,6 +39,7 @@ class ClaimsController < ApplicationController | |||||
| journal = Journal.new(journal_params) | journal = Journal.new(journal_params) | ||||
| if journal.save | if journal.save | ||||
| SendTemplateMessageJob.perform_later('IssueClaim', current_user.id, @issue&.id) | |||||
| render file: 'app/views/claims/list.json.jbuilder' | render file: 'app/views/claims/list.json.jbuilder' | ||||
| else | else | ||||
| normal_status(-1,"新建声明关联评论操作失败") | normal_status(-1,"新建声明关联评论操作失败") | ||||
| @@ -37,7 +37,7 @@ class InstallationsController < ApplicationController | |||||
| # 注册bot对应oauth应用 | # 注册bot对应oauth应用 | ||||
| Doorkeeper::Application.create!(name: @bot.name, uid: @bot.client_id, secret: @bot.client_secret, redirect_uri: "https://gitlink.org.cn") | Doorkeeper::Application.create!(name: @bot.name, uid: @bot.client_id, secret: @bot.client_secret, redirect_uri: "https://gitlink.org.cn") | ||||
| # 注册bot对应用户 | # 注册bot对应用户 | ||||
| result = autologin_register(User.generate_user_login('b'), nil, "#{SecureRandom.hex(6)}", 'bot', nil, nickname: @bot.name) | |||||
| result = autologin_register(User.generate_user_login('b'), nil, "#{SecureRandom.hex(6)}", 'bot', nil, @bot.name) | |||||
| tip_exception(-1, result[:message]) if result[:message].present? | tip_exception(-1, result[:message]) if result[:message].present? | ||||
| @bot.uid = result[:user][:id] | @bot.uid = result[:user][:id] | ||||
| @bot.save | @bot.save | ||||
| @@ -56,13 +56,21 @@ class SendTemplateMessageJob < ApplicationJob | |||||
| operator = User.find_by_id(operator_id) | operator = User.find_by_id(operator_id) | ||||
| issue = Issue.find_by_id(issue_id) | issue = Issue.find_by_id(issue_id) | ||||
| return unless operator.present? && issue.present? | return unless operator.present? && issue.present? | ||||
| receivers = User.where(id: issue.assigners.pluck(:id).append(issue&.author_id)).where.not(id: operator&.id) | |||||
| receivers = User.where(id: (issue.assigners.pluck(:id).append(issue&.author_id) + issue.claim_users.pluck(:id)).uniq).where.not(id: operator&.id) | |||||
| receivers_string, content, notification_url = MessageTemplate::IssueChanged.get_message_content(receivers, operator, issue, change_params.symbolize_keys) | receivers_string, content, notification_url = MessageTemplate::IssueChanged.get_message_content(receivers, operator, issue, change_params.symbolize_keys) | ||||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_id: issue.id, change_params: change_params.symbolize_keys}) | Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_id: issue.id, change_params: change_params.symbolize_keys}) | ||||
| receivers.find_each do |receiver| | receivers.find_each do |receiver| | ||||
| receivers_email_string, email_title, email_content = MessageTemplate::IssueChanged.get_email_message_content(receiver, operator, issue, change_params) | receivers_email_string, email_title, email_content = MessageTemplate::IssueChanged.get_email_message_content(receiver, operator, issue, change_params) | ||||
| Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) | Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) | ||||
| end | end | ||||
| when 'IssueClaim' | |||||
| operator_id, issue_id = args[0], args[1] | |||||
| operator = User.find_by_id(operator_id) | |||||
| issue = Issue.find_by_id(issue_id) | |||||
| return unless operator.present? && issue.present? | |||||
| receivers = User.where(id: issue.claim_users.pluck(:id).append(issue.author_id)).where.not(id: operator&.id) | |||||
| receivers_string, content, notification_url = MessageTemplate::IssueClaim.get_message_content(receivers, operator, issue) | |||||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_id: issue.id}) | |||||
| when 'IssueExpire' | when 'IssueExpire' | ||||
| issue_id = args[0] | issue_id = args[0] | ||||
| issue = Issue.find_by_id(issue_id) | issue = Issue.find_by_id(issue_id) | ||||
| @@ -17,5 +17,6 @@ | |||||
| class Claim < ApplicationRecord | class Claim < ApplicationRecord | ||||
| belongs_to :user, foreign_key: :user_id | belongs_to :user, foreign_key: :user_id | ||||
| belongs_to :issue | |||||
| scope :claim_includes, ->{includes(:user)} | scope :claim_includes, ->{includes(:user)} | ||||
| end | end | ||||
| @@ -65,6 +65,7 @@ class Issue < ApplicationRecord | |||||
| has_many :journals, :as => :journalized, :dependent => :destroy | has_many :journals, :as => :journalized, :dependent => :destroy | ||||
| has_many :journal_details, through: :journals | has_many :journal_details, through: :journals | ||||
| has_many :claims, :dependent => :destroy | has_many :claims, :dependent => :destroy | ||||
| has_many :claim_users, through: :claims, source: :user | |||||
| has_many :issue_tags_relates, dependent: :destroy | has_many :issue_tags_relates, dependent: :destroy | ||||
| has_many :issue_tags, through: :issue_tags_relates | has_many :issue_tags, through: :issue_tags_relates | ||||
| has_many :issue_times, dependent: :destroy | has_many :issue_times, dependent: :destroy | ||||
| @@ -30,9 +30,9 @@ class IssueTag < ApplicationRecord | |||||
| def self.init_data(project_id) | def self.init_data(project_id) | ||||
| data = [ | data = [ | ||||
| ["缺陷", "表示项目存在问题", "#d92d4c"], | |||||
| ["缺陷", "表示存在意外问题或错误", "#d92d4c"], | |||||
| ["功能", "表示新功能申请", "#ee955a"], | ["功能", "表示新功能申请", "#ee955a"], | ||||
| ["疑问", "表示存在的问题", "#2d6ddc"], | |||||
| ["疑问", "表示存在疑惑", "#2d6ddc"], | |||||
| ["支持", "表示特定功能或特定需求", "#019549"], | ["支持", "表示特定功能或特定需求", "#019549"], | ||||
| ["任务", "表示需要分配的任务", "#c1a30d"], | ["任务", "表示需要分配的任务", "#c1a30d"], | ||||
| ["协助", "表示需要社区用户协助", "#2a0dc1"], | ["协助", "表示需要社区用户协助", "#2a0dc1"], | ||||
| @@ -82,8 +82,8 @@ class Journal < ApplicationRecord | |||||
| content += "将标记由<b>#{old_value}</b>更改为<b>#{new_value}</b>" | content += "将标记由<b>#{old_value}</b>更改为<b>#{new_value}</b>" | ||||
| end | end | ||||
| when 'assigner' | when 'assigner' | ||||
| old_value = User.where(id: detail.old_value.split(",")).pluck(:nickname).join("、") | |||||
| new_value = User.where(id: detail.value.split(",")).pluck(:nickname).join("、") | |||||
| old_value = User.where(id: detail.old_value.split(",")).map{|u| u.real_name}.join("、") | |||||
| new_value = User.where(id: detail.value.split(",")).map{|u| u.real_name}.join("、") | |||||
| if old_value.nil? || old_value.blank? | if old_value.nil? || old_value.blank? | ||||
| content += "添加负责人<b>#{new_value}</b>" | content += "添加负责人<b>#{new_value}</b>" | ||||
| else | else | ||||
| @@ -121,6 +121,10 @@ class Journal < ApplicationRecord | |||||
| old_value = detail.old_value | old_value = detail.old_value | ||||
| new_value = detail.value | new_value = detail.value | ||||
| content += "结束日期" | content += "结束日期" | ||||
| when 'assigned_to_id' | |||||
| old_value = User.find_by_id(detail.old_value)&.real_name | |||||
| new_value = User.find_by_id(detail.value)&.real_name | |||||
| content += "负责人" | |||||
| end | end | ||||
| if old_value.nil? || old_value.blank? | if old_value.nil? || old_value.blank? | ||||
| content += "设置为<b>#{new_value}</b>" | content += "设置为<b>#{new_value}</b>" | ||||
| @@ -24,6 +24,7 @@ class MessageTemplate < ApplicationRecord | |||||
| self.create(type: 'MessageTemplate::IssueAtme', sys_notice: '<b>{nickname}</b> 在疑修 <b>{title}</b> 中@我', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') | self.create(type: 'MessageTemplate::IssueAtme', sys_notice: '<b>{nickname}</b> 在疑修 <b>{title}</b> 中@我', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') | ||||
| email_html = File.read("#{email_template_html_dir}/issue_changed.html") | email_html = File.read("#{email_template_html_dir}/issue_changed.html") | ||||
| self.create(type: 'MessageTemplate::IssueChanged', sys_notice: '在项目 <b>{nickname2}/{repository}</b> 的疑修 <b>{title}</b> 中:{ifassigner}{nickname1}将负责人从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifstatus}{nickname1}将状态从 <b>{status1}</b> 修改为 <b>{status2}</b> {endstatus}{iftracker}{nickname1}将类型从 <b>{tracker1}</b> 修改为 <b>{tracker2}</b> {endtracker}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifdoneratio}{nickname1}将完成度从 <b>{doneratio1}</b> 修改为 <b>{doneratio2}</b> {enddoneratio}{ifbranch}{nickname1}将指定分支从 <b>{branch1}</b> 修改为 <b>{branch2}</b> {endbranch}{ifstartdate}{nickname1}将开始日期从 <b>{startdate1}</b> 修改为 <b>{startdate2}</b> {endstartdate}{ifduedate}{nickname1}将结束日期从 <b>{duedate1}</b> 修改为 <b>{duedate2}</b> {endduedate}', email: email_html, email_title: "#{PLATFORM}: 疑修 {title} 有状态变更", notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') | self.create(type: 'MessageTemplate::IssueChanged', sys_notice: '在项目 <b>{nickname2}/{repository}</b> 的疑修 <b>{title}</b> 中:{ifassigner}{nickname1}将负责人从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifstatus}{nickname1}将状态从 <b>{status1}</b> 修改为 <b>{status2}</b> {endstatus}{iftracker}{nickname1}将类型从 <b>{tracker1}</b> 修改为 <b>{tracker2}</b> {endtracker}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifdoneratio}{nickname1}将完成度从 <b>{doneratio1}</b> 修改为 <b>{doneratio2}</b> {enddoneratio}{ifbranch}{nickname1}将指定分支从 <b>{branch1}</b> 修改为 <b>{branch2}</b> {endbranch}{ifstartdate}{nickname1}将开始日期从 <b>{startdate1}</b> 修改为 <b>{startdate2}</b> {endstartdate}{ifduedate}{nickname1}将结束日期从 <b>{duedate1}</b> 修改为 <b>{duedate2}</b> {endduedate}', email: email_html, email_title: "#{PLATFORM}: 疑修 {title} 有状态变更", notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') | ||||
| self.create(type: 'MessageTemplate::IssueClaim', sys_notice: '在 <b>{nickname2}/{repository}</b> 的疑修 <b>{title}</b> 中, <b>{nickname1}</b> 新建了一条声明', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') | |||||
| email_html = File.read("#{email_template_html_dir}/issue_expire.html") | email_html = File.read("#{email_template_html_dir}/issue_expire.html") | ||||
| self.create(type: 'MessageTemplate::IssueExpire', sys_notice: '疑修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: "#{PLATFORM}: 疑修截止日期到达最后一天") | self.create(type: 'MessageTemplate::IssueExpire', sys_notice: '疑修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: "#{PLATFORM}: 疑修截止日期到达最后一天") | ||||
| email_html = File.read("#{email_template_html_dir}/issue_deleted.html") | email_html = File.read("#{email_template_html_dir}/issue_deleted.html") | ||||
| @@ -0,0 +1,31 @@ | |||||
| # == 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::IssueClaim < MessageTemplate | |||||
| # MessageTemplate::IssueAtme.get_message_content(User.where(login: 'yystopf'), User.last, Issue.last) | |||||
| def self.get_message_content(receivers, operator, issue) | |||||
| return '', '', '' if receivers.blank? | |||||
| project = issue&.project | |||||
| owner = project&.owner | |||||
| content = sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).gsub('{repository}', project&.name).gsub('{title}', issue&.subject) | |||||
| url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', issue&.project_issues_index.to_s) | |||||
| return receivers_string(receivers), content, url | |||||
| rescue => e | |||||
| Rails.logger.info("MessageTemplate::IssueClaim.get_message_content [ERROR] #{e}") | |||||
| return 0, '', '' | |||||
| end | |||||
| end | |||||
| @@ -2,6 +2,7 @@ class Api::V1::Issues::ListService < ApplicationService | |||||
| include ActiveModel::Model | include ActiveModel::Model | ||||
| attr_reader :project, :only_name, :category, :participant_category, :keyword, :author_id, :issue_tag_ids | attr_reader :project, :only_name, :category, :participant_category, :keyword, :author_id, :issue_tag_ids | ||||
| attr_reader :begin_date, :end_date | |||||
| attr_reader :milestone_id, :assigner_id, :status_id, :sort_by, :sort_direction, :current_user | attr_reader :milestone_id, :assigner_id, :status_id, :sort_by, :sort_direction, :current_user | ||||
| attr_accessor :queried_issues, :total_issues_count, :closed_issues_count, :opened_issues_count | attr_accessor :queried_issues, :total_issues_count, :closed_issues_count, :opened_issues_count | ||||
| @@ -22,6 +23,8 @@ class Api::V1::Issues::ListService < ApplicationService | |||||
| @milestone_id = params[:milestone_id] | @milestone_id = params[:milestone_id] | ||||
| @assigner_id = params[:assigner_id] | @assigner_id = params[:assigner_id] | ||||
| @status_id = params[:status_id] | @status_id = params[:status_id] | ||||
| @begin_date = params[:begin_date] | |||||
| @end_date = params[:end_date] | |||||
| @sort_by = params[:sort_by].present? ? params[:sort_by] : 'issues.updated_on' | @sort_by = params[:sort_by].present? ? params[:sort_by] : 'issues.updated_on' | ||||
| @sort_direction = (params[:sort_direction].present? ? params[:sort_direction] : 'desc').downcase | @sort_direction = (params[:sort_direction].present? ? params[:sort_direction] : 'desc').downcase | ||||
| @current_user = current_user | @current_user = current_user | ||||
| @@ -68,6 +71,10 @@ class Api::V1::Issues::ListService < ApplicationService | |||||
| # status_id | # status_id | ||||
| issues = issues.where(status_id: status_id) if status_id.present? | issues = issues.where(status_id: status_id) if status_id.present? | ||||
| if begin_date&.present? || end_date&.present? | |||||
| issues = issues.where("issues.created_on between ? and ?", begin_date&.present? ? begin_date.to_time : Time.now.beginning_of_day, end_date&.present? ? end_date.to_time.end_of_day : Time.now.end_of_day) | |||||
| end | |||||
| # keyword | # keyword | ||||
| issues = issues.ransack(id_eq: keyword).result.or(issues.ransack(subject_or_description_cont: keyword).result) if keyword.present? | issues = issues.ransack(id_eq: keyword).result.or(issues.ransack(subject_or_description_cont: keyword).result) if keyword.present? | ||||
| @@ -5,7 +5,7 @@ json.total_count @issues.total_count | |||||
| json.has_created_issues @project.issues.size > 0 | json.has_created_issues @project.issues.size > 0 | ||||
| json.issues @issues.each do |issue| | json.issues @issues.each do |issue| | ||||
| if params[:only_name].present? | if params[:only_name].present? | ||||
| json.(issue, :id, :subject) | |||||
| json.(issue, :id, :subject, :project_issues_index) | |||||
| else | else | ||||
| json.partial! "simple_detail", locals: {issue: issue} | json.partial! "simple_detail", locals: {issue: issue} | ||||
| end | end | ||||
| @@ -14,5 +14,5 @@ else | |||||
| json.name user["name"] | json.name user["name"] | ||||
| json.image_url user["avatar_url"] | json.image_url user["avatar_url"] | ||||
| db_user = User.find_by_id(user["id"]) | db_user = User.find_by_id(user["id"]) | ||||
| json.contribution_perc db_user.contribution_perc(project) | |||||
| json.contribution_perc db_user.contribution_perc(project) if db_user.present? | |||||
| end | end | ||||