diff --git a/app/jobs/send_template_message_job.rb b/app/jobs/send_template_message_job.rb index a5b1434c7..a0191cee3 100644 --- a/app/jobs/send_template_message_job.rb +++ b/app/jobs/send_template_message_job.rb @@ -45,8 +45,12 @@ class SendTemplateMessageJob < ApplicationJob issue = Issue.find_by_id(issue_id) return unless operator.present? && issue.present? receivers = User.where(id: [issue&.assigned_to_id, issue&.author_id]).where.not(id: operator&.id) - receivers_string, content, notification_url = MessageTemplate::IssueChanged.get_message_content(receivers, operator, issue, change_params) + 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}) + receivers.find_each do |receiver| + 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) + end when 'IssueCreatorExpire' issue_id = args[0] issue = Issue.find_by_id(issue_id) @@ -61,6 +65,10 @@ class SendTemplateMessageJob < ApplicationJob receivers = User.where(id: [issue_assigned_to_id, issue_author_id]).where.not(id: operator&.id) receivers_string, content, notification_url = MessageTemplate::IssueDeleted.get_message_content(receivers, operator, issue_title) Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_title: issue_title}) + receivers.find_each do |receiver| + receivers_email_string, email_title, email_content = MessageTemplate::IssueDeleted.get_email_message_content(receiver, operator, issue_title) + Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) + end when 'OrganizationJoined' user_id, organization_id = args[0], args[1] user = User.find_by_id(user_id) @@ -203,7 +211,7 @@ class SendTemplateMessageJob < ApplicationJob return unless operator.present? && project.present? receivers = project.all_managers.where.not(id: operator&.id) receivers_string, content, notification_url = MessageTemplate::ProjectSettingChanged.get_message_content(receivers, operator, project, change_params.symbolize_keys) - Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id, change_params: change_params}) + Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id, change_params: change_params.symbolize_keys}) receivers.find_each do |receiver| receivers_email_string, email_title, email_content = MessageTemplate::ProjectSettingChanged.get_email_message_content(receiver, operator, project, change_params.symbolize_keys) Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) @@ -238,6 +246,10 @@ class SendTemplateMessageJob < ApplicationJob receivers = User.where(id: [issue&.assigned_to_id, pull_request&.user_id]).where.not(id: operator&.id) receivers_string, content, notification_url = MessageTemplate::PullRequestChanged.get_message_content(receivers, operator, pull_request, change_params.symbolize_keys) Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, pull_request_id: pull_request.id, change_params: change_params}) + receivers.find_each do |receiver| + receivers_email_string, email_title, email_content = MessageTemplate::PullRequestChanged.get_email_message_content(receiver, operator, pull_request, change_params.symbolize_keys) + Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) + end when 'PullRequestClosed' operator_id, pull_request_id = args[0], args[1] operator = User.find_by_id(operator_id) @@ -246,6 +258,10 @@ class SendTemplateMessageJob < ApplicationJob receivers = User.where(id: [pull_request&.issue&.assigned_to_id, pull_request&.user_id]).where.not(id: operator&.id) receivers_string, content, notification_url = MessageTemplate::PullRequestClosed.get_message_content(receivers, operator, pull_request) Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, pull_request_id: pull_request.id}) + receivers.find_each do |receiver| + receivers_email_string, email_title, email_content = MessageTemplate::PullRequestClosed.get_email_message_content(receiver, operator, pull_request) + Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) + end when 'PullRequestMerged' operator_id, pull_request_id = args[0], args[1] operator = User.find_by_id(operator_id) @@ -254,6 +270,10 @@ class SendTemplateMessageJob < ApplicationJob receivers = User.where(id: [pull_request&.issue&.assigned_to_id, pull_request&.user_id]).where.not(id: operator&.id) receivers_string, content, notification_url = MessageTemplate::PullRequestMerged.get_message_content(receivers, operator, pull_request) Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, pull_request_id: pull_request.id}) + receivers.find_each do |receiver| + receivers_email_string, email_title, email_content = MessageTemplate::PullRequestMerged.get_email_message_content(receiver, operator, pull_request) + Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) + end end end end \ No newline at end of file diff --git a/app/models/message_template.rb b/app/models/message_template.rb index 2c8c96869..8d3f622b6 100644 --- a/app/models/message_template.rb +++ b/app/models/message_template.rb @@ -20,16 +20,19 @@ class MessageTemplate < ApplicationRecord self.create(type: 'MessageTemplate::IssueAssigned', sys_notice: '{nickname1}在 {nickname2}/{repository} 指派给你一个易修:{title}', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: '{nickname1} 在 {nickname2}/{repository} 指派给你一个易修') self.create(type: 'MessageTemplate::IssueAssignerExpire', sys_notice: '您负责的易修 {title} 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') self.create(type: 'MessageTemplate::IssueAtme', sys_notice: '{nickname} 在易修 {title} 中@我', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') - self.create(type: 'MessageTemplate::IssueChanged', sys_notice: '在项目 {nickname2}/{repository} 的易修 {title} 中:{ifassigner}{nickname1}将负责人从 {assigner1} 修改为 {assigner2} {endassigner}{ifstatus}{nickname1}将状态从 {status1} 修改为 {status2} {endstatus}{iftracker}{nickname1}将类型从 {tracker1} 修改为 {tracker2} {endtracker}{ifpriority}{nickname1}将优先级从 {priority1} 修改为 {priority2} {endpriority}{ifmilestone}{nickname1}将里程碑从 {milestone1} 修改为 {milestone2} {endmilestone}{iftag}{nickname1}将标记从 {tag1} 修改为 {tag2} {endtag}{ifdoneratio}{nickname1}将完成度从 {doneratio1} 修改为 {doneratio2} {enddoneratio}{ifbranch}{nickname1}将指定分支从 {branch1} 修改为 {branch2} {endbranch}{ifstartdate}{nickname1}将开始日期从 {startdate1} 修改为 {startdate2} {endstartdate}{ifduedate}{nickname1}将结束日期从 {duedate1} 修改为 {duedate2} {endduedate}', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') + email_html = File.read("#{email_template_html_dir}/issue_changed.html") + self.create(type: 'MessageTemplate::IssueChanged', sys_notice: '在项目 {nickname2}/{repository} 的易修 {title} 中:{ifassigner}{nickname1}将负责人从 {assigner1} 修改为 {assigner2} {endassigner}{ifstatus}{nickname1}将状态从 {status1} 修改为 {status2} {endstatus}{iftracker}{nickname1}将类型从 {tracker1} 修改为 {tracker2} {endtracker}{ifpriority}{nickname1}将优先级从 {priority1} 修改为 {priority2} {endpriority}{ifmilestone}{nickname1}将里程碑从 {milestone1} 修改为 {milestone2} {endmilestone}{iftag}{nickname1}将标记从 {tag1} 修改为 {tag2} {endtag}{ifdoneratio}{nickname1}将完成度从 {doneratio1} 修改为 {doneratio2} {enddoneratio}{ifbranch}{nickname1}将指定分支从 {branch1} 修改为 {branch2} {endbranch}{ifstartdate}{nickname1}将开始日期从 {startdate1} 修改为 {startdate2} {endstartdate}{ifduedate}{nickname1}将结束日期从 {duedate1} 修改为 {duedate2} {endduedate}', email: email_html, email_title: '易修 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') self.create(type: 'MessageTemplate::IssueCreatorExpire', sys_notice: '您发布的易修 {title} 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') - self.create(type: 'MessageTemplate::IssueDeleted', sys_notice: '{nickname}已将易修 {title} 删除', notification_url: '') + email_html = File.read("#{email_template_html_dir}/issue_deleted.html") + self.create(type: 'MessageTemplate::IssueDeleted', sys_notice: '{nickname}已将易修 {title} 删除', email: email_html, email_title: '易修 {title} 有状态变更', notification_url: '') self.create(type: 'MessageTemplate::IssueJournal', sys_notice: '{nickname}评论易修{title}:{notes}', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') self.create(type: 'MessageTemplate::LoginIpTip', sys_notice: '您的账号{nickname}于{login_time)在非常用的IP地址{ip}登录,如非本人操作,请立即修改密码', notification_url: '') email_html = File.read("#{email_template_html_dir}/organization_joined.html") self.create(type: 'MessageTemplate::OrganizationJoined', sys_notice: '你已加入 {organization} 组织', notification_url: '{baseurl}/{login}', email: email_html, email_title: '你已加入 {organization} 组织') email_html = File.read("#{email_template_html_dir}/organization_left.html") self.create(type: 'MessageTemplate::OrganizationLeft', sys_notice: '你已被移出 {organization} 组织', notification_url: '', email: email_html, email_title: '你已被移出 {organization} 组织') - self.create(type: 'MessageTemplate::OrganizationRole', sys_notice: '组织 {organization} 已把你的角色改为 {role}', notification_url: '{baseurl}/{login}') + email_html = File.read("#{email_template_html_dir}/organization_role.html") + self.create(type: 'MessageTemplate::OrganizationRole', sys_notice: '组织 {organization} 已把你的角色改为 {role}', email: email_html, email_title: '在 {organization} 组织你的账号有权限变更', notification_url: '{baseurl}/{login}') self.create(type: 'MessageTemplate::ProjectDeleted', sys_notice: '你关注的仓库{nickname}/{repository}已被删除', notification_url: '') self.create(type: 'MessageTemplate::ProjectFollowed', sys_notice: '{nickname} 关注了你管理的仓库', notification_url: '{baseurl}/{login}') self.create(type: 'MessageTemplate::ProjectForked', sys_notice: '{nickname1} 复刻了你管理的仓库{nickname1}/{repository1}到{nickname2}/{repository2}', notification_url: '{baseurl}/{owner}/{identifier}') @@ -46,19 +49,23 @@ class MessageTemplate < ApplicationRecord self.create(type: 'MessageTemplate::ProjectMilestone', sys_notice: '{nickname1}在 {nickname2}/{repository} 创建了一个里程碑:{title}', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}') self.create(type: 'MessageTemplate::ProjectPraised', sys_notice: '{nickname} 点赞了你管理的仓库', notification_url: '{baseurl}/{login}') email_html = File.read("#{email_template_html_dir}/project_pull_request.html") - self.create(type: 'MessageTemplate::ProjectPullRequest', sys_notice: '{nickname1}在 {nickname2}/{repository} 提交了一个合并请求:{title}', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}/Messagecount', email: email_html, email_title: '{nickname1} 在 {nickname2}/{repository} 提交了一个合并请求') - self.create(type: 'MessageTemplate::ProjectRole', sys_notice: '仓库 {repository} 已把你的角色改为 {role}', notification_url: '{baseurl}/{owner}/{identifier}') + self.create(type: 'MessageTemplate::ProjectPullRequest', sys_notice: '{nickname1}在 {nickname2}/{repository} 提交了一个合并请求:{title}', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: '{nickname1} 在 {nickname2}/{repository} 提交了一个合并请求') + email_html = File.read("#{email_template_html_dir}/project_role.html") + self.create(type: 'MessageTemplate::ProjectRole', sys_notice: '仓库 {nickname}/{repository} 已把你的角色改为 {role}', email: email_html, email_title: '在 {nickname}/{repository} 项目你的账号有权限变更', notification_url: '{baseurl}/{owner}/{identifier}') email_html = File.read("#{email_template_html_dir}/project_setting_changed.html") self.create(type: 'MessageTemplate::ProjectSettingChanged', sys_notice: '{nickname1}更改了 {nickname2}/{repository} 仓库设置:{ifname}更改项目名称为"{name}"{endname}{ifdescription}更改项目简介为"{description}"{enddescription}{ifcategory}更改项目类别为"{category}"{endcategory}{iflanguage}更改项目语言为"{language}"{endlanguage}{ifpermission}将仓库设为"{permission}"{endpermission}{ifnavbar}将项目导航更改为"{navbar}"{endnavbar}', notification_url: '{baseurl}/{owner}/{identifier}/settings', email: email_html, email_title: '您管理的仓库 {nickname2}/{repository} 仓库设置已被更改') self.create(type: 'MessageTemplate::ProjectTransfer', sys_notice: '你关注的仓库{nickname1}/{repository1}已被转移至{nickname2}/{repository2}', notification_url: '{baseurl}/{owner}/{identifier}') self.create(type: 'MessageTemplate::ProjectVersion', sys_notice: '{nickname1}在 {nickname2}/{repository} 创建了发行版:{title}', notification_url: '{baseurl}/{owner}/{identifier}/releases') email_html = File.read("#{email_template_html_dir}/pull_request_assigned.html") - self.create(type: 'MessageTemplate::PullRequestAssigned', sys_notice: '{nickname1}在 {nickname2}/{repository} 指派给你一个合并请求:{title}', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}/Messagecount', email: email_html, email_title: '{nickname1} 在 {nickname2}/{repository} 指派给你一个合并请求') - self.create(type: 'MessageTemplate::PullRequestAtme', sys_notice: '{nickname} 在合并请求 {title} 中@我', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}/Messagecount') - self.create(type: 'MessageTemplate::PullRequestChanged', sys_notice: '在项目{nickname2}/{repository}的合并请求 {title} 中:{ifassigner}{nickname1}将审查成员从 {assigner1} 修改为 {assigner2} {endassigner}{ifmilestone}{nickname1}将里程碑从 {milestone1} 修改为 {milestone2} {endmilestone}{iftag}{nickname1}将标记从 {tag1} 修改为 {tag2} {endtag}{ifpriority}{nickname1}将优先级从 {priority1} 修改为 {priority2} {endpriority}', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}/Messagecount') - self.create(type: 'MessageTemplate::PullRequestClosed', sys_notice: '你提交的合并请求:{title} 被拒绝', notification_url: '') - self.create(type: 'MessageTemplate::PullRequestJournal', sys_notice: '{nickname}评论合并请求{title}:{notes}', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}/Messagecount') - self.create(type: 'MessageTemplate::PullRequestMerged', sys_notice: '你提交的合并请求:{title} 已通过', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}/Messagecount') + self.create(type: 'MessageTemplate::PullRequestAssigned', sys_notice: '{nickname1}在 {nickname2}/{repository} 指派给你一个合并请求:{title}', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: '{nickname1} 在 {nickname2}/{repository} 指派给你一个合并请求') + self.create(type: 'MessageTemplate::PullRequestAtme', sys_notice: '{nickname} 在合并请求 {title} 中@我', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}') + email_html = File.read("#{email_template_html_dir}/pull_request_changed.html") + self.create(type: 'MessageTemplate::PullRequestChanged', sys_notice: '在项目{nickname2}/{repository}的合并请求 {title} 中:{ifassigner}{nickname1}将审查成员从 {assigner1} 修改为 {assigner2} {endassigner}{ifmilestone}{nickname1}将里程碑从 {milestone1} 修改为 {milestone2} {endmilestone}{iftag}{nickname1}将标记从 {tag1} 修改为 {tag2} {endtag}{ifpriority}{nickname1}将优先级从 {priority1} 修改为 {priority2} {endpriority}', email: email_html, email_title: '合并请求 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}') + email_html = File.read("#{email_template_html_dir}/pull_request_closed.html") + self.create(type: 'MessageTemplate::PullRequestClosed', sys_notice: '你提交的合并请求:{title} 被拒绝', email: email_html, email_title: '合并请求 {title} 有状态变更', notification_url: '') + self.create(type: 'MessageTemplate::PullRequestJournal', sys_notice: '{nickname}评论合并请求{title}:{notes}', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}') + email_html = File.read("#{email_template_html_dir}/pull_request_merged.html") + self.create(type: 'MessageTemplate::PullRequestMerged', sys_notice: '你提交的合并请求:{title} 已通过', email: email_html, email_title: '合并请求 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}') end def self.sys_notice diff --git a/app/models/message_template/issue_changed.rb b/app/models/message_template/issue_changed.rb index 6b9e79763..7edc8f05d 100644 --- a/app/models/message_template/issue_changed.rb +++ b/app/models/message_template/issue_changed.rb @@ -17,6 +17,12 @@ class MessageTemplate::IssueChanged < MessageTemplate # MessageTemplate::IssueChanged.get_message_content(User.where(login: 'yystopf'), User.last, Issue.last, {status_id: [1, 2], assigned_to_id: [nil, 203], tracker_id: [4, 3], priority_id: [2, 4], fixed_version_id: [nil, 5], due_date: ['', '2021-09-11'], done_ratio: [0, 40], issue_tags_value: ["", "7"], branch_name: ["", "master"]}) def self.get_message_content(receivers, operator, issue, change_params) + receivers.each do |receiver| + if receiver.user_template_message_setting.present? + receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["CreateOrAssign::IssueChanged"] + end + end + return '', '', '' if receivers.blank? return '', '', '' if change_params.blank? project = issue&.project owner = project&.owner @@ -180,4 +186,183 @@ class MessageTemplate::IssueChanged < MessageTemplate Rails.logger.info("MessageTemplate::IssueAssigned.get_message_content [ERROR] #{e}") return '', '', '' end + + def self.get_email_message_content(receiver, operator, issue, change_params) + if receiver.user_template_message_setting.present? + return '', '', '' unless receiver.user_template_message_setting.email_body["CreateOrAssign::IssueChanged"] + end + project = issue&.project + owner = project&.owner + title = email_title + title.gsub!('{title}', issue&.subject) + content = email + content.gsub!('{receiver}', receiver&.real_name) + content.gsub!('{baseurl}', base_url) + content.gsub!('{login1}', operator&.login) + content.gsub!('{nickname1}', operator&.real_name) + content.gsub!('{login2}', owner&.login) + content.gsub!('{nickname2}', owner&.real_name) + content.gsub!('{identifier}', project&.identifier) + content.gsub!('{repository}', project&.name) + content.gsub!('{title}', issue&.subject) + content.gsub!('{id}', issue&.id.to_s) + change_count = change_params.keys.size + # 易修负责人修改 + if change_params[:assigned_to_id].present? + assigner1 = User.find_by_id(change_params[:assigned_to_id][0]) + assigner2 = User.find_by_id(change_params[:assigned_to_id][1]) + if change_count > 1 + content.sub!('{ifassigner}', '
') + else + content.sub!('{ifassigner}', '') + end + content.sub!('{endassigner}', '') + content.gsub!('{assigner1}', assigner1.present? ? assigner1&.real_name : '未指派成员') + content.gsub!('{assigner2}', assigner2.present? ? assigner2&.real_name : '未指派成员') + else + content.gsub!(/({ifassigner})(.*)({endassigner})/, '') + end + # 易修状态修改 + if change_params[:status_id].present? + status1 = IssueStatus.find_by_id(change_params[:status_id][0]) + status2 = IssueStatus.find_by_id(change_params[:status_id][1]) + if change_count > 1 + content.sub!('{ifstatus}', '
') + else + content.sub!('{ifstatus}', '') + end + content.sub!('{endstatus}', '') + content.gsub!('{status1}', status1&.name) + content.gsub!('{status2}', status2&.name) + else + content.gsub!(/({ifstatus})(.*)({endstatus})/, '') + end + # 易修类型修改 + if change_params[:tracker_id].present? + tracker1 = Tracker.find_by_id(change_params[:tracker_id][0]) + tracker2 = Tracker.find_by_id(change_params[:tracker_id][1]) + if change_count > 1 + content.sub!('{iftracker}', '
') + else + content.sub!('{iftracker}', '') + end + content.sub!('{endtracker}', '') + content.gsub!('{tracker1}', tracker1&.name) + content.gsub!('{tracker2}', tracker2&.name) + else + content.gsub!(/({iftracker})(.*)({endtracker})/, '') + end + # 易修里程碑修改 + if change_params[:fixed_version_id].present? + fix_version1 = Version.find_by_id(change_params[:fixed_version_id][0]) + fix_version2 = Version.find_by_id(change_params[:fixed_version_id][1]) + if change_count > 1 + content.sub!('{ifmilestone}', '
') + else + content.sub!('{ifmilestone}', '') + end + content.sub!('{endmilestone}', '') + content.gsub!('{milestone1}', fix_version1.present? ? fix_version1&.name : '未选择里程碑') + content.gsub!('{milestone2}', fix_version2.present? ? fix_version2&.name : '未选择里程碑') + else + content.gsub!(/({ifmilestone})(.*)({endmilestone})/, '') + end + # 易修标记修改 + if change_params[:issue_tags_value].present? + issue_tags1 = IssueTag.where(id: change_params[:issue_tags_value][0]).distinct + issue_tags2 = IssueTag.where(id: change_params[:issue_tags_value][1]).distinct + tag1 = issue_tags1.pluck(:name).join(",").blank? ? '未选择标记' : issue_tags1.pluck(:name).join(",") + tag2 = issue_tags2.pluck(:name).join(",").blank? ? '未选择标记' : issue_tags2.pluck(:name).join(",") + if change_count > 1 + content.sub!('{iftag}', '
') + else + content.sub!('{iftag}', '') + end + content.sub!('{endtag}', '') + content.gsub!('{tag1}', tag1) + content.gsub!('{tag2}', tag2) + else + content.gsub!(/({iftag})(.*)({endtag})()/, '') + end + # 易修优先级修改 + if change_params[:priority_id].present? + priority1 = IssuePriority.find_by_id(change_params[:priority_id][0]) + priority2 = IssuePriority.find_by_id(change_params[:priority_id][1]) + if change_count > 1 + content.sub!('{ifpriority}', '
') + else + content.sub!('{ifpriority}', '') + end + content.sub!('{endpriority}', '') + content.gsub!('{priority1}', priority1&.name) + content.gsub!('{priority2}', priority2&.name) + else + content.gsub!(/({ifpriority})(.*)({endpriority})/, '') + end + # 易修完成度修改 + if change_params[:done_ratio].present? + doneratio1 = change_params[:done_ratio][0] + doneratio2 = change_params[:done_ratio][1] + if change_count > 1 + content.sub!('{ifdoneratio}', '
') + else + content.sub!('{ifdoneratio}', '') + end + content.sub!('{enddoneratio}', '') + content.gsub!('{doneratio1}', "#{doneratio1}%") + content.gsub!('{doneratio2}', "#{doneratio2}%") + else + content.gsub!(/({ifdoneratio})(.*)({enddoneratio})/, '') + end + # 易修指定分支修改 + if change_params[:branch_name].present? + branch1 = change_params[:branch_name][0].blank? ? '分支未指定' : change_params[:branch_name][0] + branch2 = change_params[:branch_name][1].blank? ? '分支未指定' : change_params[:branch_name][1] + if change_count > 1 + content.sub!('{ifbranch}', '
') + else + content.sub!('{ifbranch}', '') + end + content.sub!('{endbranch}', '') + content.gsub!('{branch1}', branch1) + content.gsub!('{branch2}', branch2) + else + content.gsub!(/({ifbranch})(.*)({endbranch})/, '') + end + # 易修开始日期修改 + if change_params[:start_date].present? + startdate1 = change_params[:start_date][0].blank? ? "未选择开始日期" : change_params[:start_date][0] + startdate2 = change_params[:start_date][1].blank? ? "未选择开始日期" : change_params[:start_date][1] + if change_count > 1 + content.sub!('{ifstartdate}', '
') + else + content.sub!('{ifstartdate}', '') + end + content.sub!('{endstartdate}', '') + content.gsub!('{startdate1}', startdate1 ) + content.gsub!('{startdate2}', startdate2) + else + content.gsub!(/({ifstartdate})(.*)({endstartdate})/, '') + end + # 易修结束日期修改 + if change_params[:due_date].present? + duedate1 = change_params[:due_date][0].blank? ? '未选择结束日期' : change_params[:due_date][0] + duedate2 = change_params[:due_date][1].blank? ? '未选择结束日期' : change_params[:due_date][1] + if change_count > 1 + content.sub!('{ifduedate}', '
') + else + content.sub!('{ifduedate}', '') + end + content.sub!('{endduedate}', '') + content.gsub!('{duedate1}', duedate1) + content.gsub!('{duedate2}', duedate2) + else + content.gsub!(/({ifduedate})(.*)({endduedate})/, '') + end + + return receiver&.mail, title, content + rescue => e + Rails.logger.info("MessageTemplate::IssueChanged.get_email_message_content [ERROR] #{e}") + return '', '', '' + end end diff --git a/app/models/message_template/issue_deleted.rb b/app/models/message_template/issue_deleted.rb index 8c4145716..c08ee0439 100644 --- a/app/models/message_template/issue_deleted.rb +++ b/app/models/message_template/issue_deleted.rb @@ -17,10 +17,35 @@ class MessageTemplate::IssueDeleted < MessageTemplate # MessageTemplate::IssueDeleted.get_message_content(User.where(login: 'yystopf'), User.last, "hahah") def self.get_message_content(receivers, operator, issue_title) + receivers.each do |receiver| + if receiver.user_template_message_setting.present? + receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["CreateOrAssign::IssueChanged"] + end + end + return '', '', '' if receivers.blank? content = sys_notice.gsub('{nickname}', operator&.real_name).gsub('{title}', issue_title) return receivers_string(receivers), content, notification_url rescue => e - Rails.logger.info("MessageTemplate::IssueAtme.get_message_content [ERROR] #{e}") + Rails.logger.info("MessageTemplate::IssueDeleted.get_message_content [ERROR] #{e}") + return '', '', '' + end + + def self.get_email_message_content(receiver, operator, issue_title) + if receiver.user_template_message_setting.present? + return '', '', '' unless receiver.user_template_message_setting.email_body["CreateOrAssign::IssueChanged"] + end + title = email_title + title.gsub!('{title}', issue_title) + content = email + content.gsub!('{receiver}', receiver&.real_name) + content.gsub!('{nickname}', operator&.real_name) + content.gsub!('{login}', operator&.login) + content.gsub!('{baseurl}', base_url) + content.gsub!('{title}', issue_title) + + return receiver&.mail, title, content + rescue => e + Rails.logger.info("MessageTemplate::IssueDeleted.get_email_message_content [ERROR] #{e}") return '', '', '' end end diff --git a/app/models/message_template/project_role.rb b/app/models/message_template/project_role.rb index 6cb88ab89..e1ced084a 100644 --- a/app/models/message_template/project_role.rb +++ b/app/models/message_template/project_role.rb @@ -38,10 +38,12 @@ class MessageTemplate::ProjectRole < MessageTemplate title = email_title title.gsub!('{repository}', project&.name) title.gsub!('{role}', role) + title.gsub!('{nickname}', project&.owner&.real_name) content = email content.gsub!('{receiver}', receiver&.real_name) content.gsub!('{baseurl}', base_url) content.gsub!('{login}', project&.owner&.login) + content.gsub!('{nickname}', project&.owner&.real_name) content.gsub!('{identifier}', project&.identifier) content.gsub!('{repository}', project&.name) content.gsub!('{role}', role) diff --git a/app/models/message_template/pull_request_changed.rb b/app/models/message_template/pull_request_changed.rb index 099607fbe..729e12060 100644 --- a/app/models/message_template/pull_request_changed.rb +++ b/app/models/message_template/pull_request_changed.rb @@ -17,6 +17,12 @@ class MessageTemplate::PullRequestChanged < MessageTemplate # MessageTemplate::PullRequestChanged.get_message_content(User.where(login: 'yystopf'), User.last, PullRequest.last, {assigned_to_id: [nil, 203], priority_id: [2, 4], fixed_version_id: [nil, 5], issue_tags_value: ["", "7"]}) def self.get_message_content(receivers, operator, pull_request, change_params) + receivers.each do |receiver| + if receiver.user_template_message_setting.present? + receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["CreateOrAssign::PullRequestChanged"] + end + end + return '', '', '' if receivers.blank? return '', '', '' if change_params.blank? project = pull_request&.project owner = project&.owner @@ -92,4 +98,95 @@ class MessageTemplate::PullRequestChanged < MessageTemplate Rails.logger.info("MessageTemplate::PullRequestChanged.get_message_content [ERROR] #{e}") return '', '', '' end + + def self.get_email_message_content(receiver, operator, pull_request, change_params) + if receiver.user_template_message_setting.present? + return '', '', '' unless receiver.user_template_message_setting.email_body["CreateOrAssign::PullRequestChanged"] + end + project = pull_request&.project + owner = project&.owner + title = email_title + title.gsub!('{title}', pull_request&.title) + content = email + content.gsub!('{receiver}', receiver&.real_name) + content.gsub!('{nickname1}', operator&.real_name) + content.gsub!('{login1}', operator&.login) + content.gsub!('{nickname2}', owner&.real_name) + content.gsub!('{login2}', owner&.login) + content.gsub!('{identifier}', project&.identifier) + content.gsub!('{repository}', project&.name) + content.gsub!('{baseurl}', base_url) + content.gsub!('{title}', pull_request&.title) + content.gsub!('{id}', pull_request&.id.to_s) + + change_count = change_params.keys.size + # 合并请求审查成员修改 + if change_params[:assigned_to_id].present? + assigner1 = User.find_by_id(change_params[:assigned_to_id][0]) + assigner2 = User.find_by_id(change_params[:assigned_to_id][1]) + if change_count > 1 + content.sub!('{ifassigner}', '
') + else + content.sub!('{ifassigner}', '') + end + content.sub!('{endassigner}', '') + content.gsub!('{assigner1}', assigner1.present? ? assigner1&.real_name : '未指派成员') + content.gsub!('{assigner2}', assigner2.present? ? assigner2&.real_name : '未指派成员') + else + content.gsub!(/({ifassigner})(.*)({endassigner})/, '') + end + # 合并请求里程碑修改 + if change_params[:fixed_version_id].present? + fix_version1 = Version.find_by_id(change_params[:fixed_version_id][0]) + fix_version2 = Version.find_by_id(change_params[:fixed_version_id][1]) + if change_count > 1 + content.sub!('{ifmilestone}', '
') + else + content.sub!('{ifmilestone}', '') + end + content.sub!('{endmilestone}', '') + content.gsub!('{milestone1}', fix_version1.present? ? fix_version1&.name : '未选择里程碑') + content.gsub!('{milestone2}', fix_version2.present? ? fix_version2&.name : '未选择里程碑') + else + content.gsub!(/({ifmilestone})(.*)({endmilestone})/, '') + end + # 合并请求标记修改 + if change_params[:issue_tags_value].present? + issue_tags1 = IssueTag.where(id: change_params[:issue_tags_value][0]).distinct + issue_tags2 = IssueTag.where(id: change_params[:issue_tags_value][1]).distinct + tag1 = issue_tags1.pluck(:name).join(",").blank? ? '未选择标记' : issue_tags1.pluck(:name).join(",") + tag2 = issue_tags2.pluck(:name).join(",").blank? ? '未选择标记' : issue_tags2.pluck(:name).join(",") + if change_count > 1 + content.sub!('{iftag}', '
') + else + content.sub!('{iftag}', '') + end + content.sub!('{endtag}', '') + content.gsub!('{tag1}', tag1) + content.gsub!('{tag2}', tag2) + else + content.gsub!(/({iftag})(.*)({endtag})()/, '') + end + # 合并请求优先级修改 + if change_params[:priority_id].present? + priority1 = IssuePriority.find_by_id(change_params[:priority_id][0]) + priority2 = IssuePriority.find_by_id(change_params[:priority_id][1]) + if change_count > 1 + content.sub!('{ifpriority}', '
') + else + content.sub!('{ifpriority}', '') + end + content.sub!('{ifpriority}', '') + content.sub!('{endpriority}', '') + content.gsub!('{priority1}', priority1&.name) + content.gsub!('{priority2}', priority2&.name) + else + content.gsub!(/({ifpriority})(.*)({endpriority})/, '') + end + + return receiver&.mail, title, content + rescue => e + Rails.logger.info("MessageTemplate::PullRequestChanged.get_email_message_content [ERROR] #{e}") + return '', '', '' + end end diff --git a/app/models/message_template/pull_request_closed.rb b/app/models/message_template/pull_request_closed.rb index 6ebb23a63..f160ebf20 100644 --- a/app/models/message_template/pull_request_closed.rb +++ b/app/models/message_template/pull_request_closed.rb @@ -17,6 +17,12 @@ class MessageTemplate::PullRequestClosed < MessageTemplate # MessageTemplate::PullRequestClosed.get_message_content(User.where(login: 'yystopf'), User.last, PullRequest.last) def self.get_message_content(receivers, operator, pull_request) + receivers.each do |receiver| + if receiver.user_template_message_setting.present? + receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["CreateOrAssign::PullRequestChanged"] + end + end + return '', '', '' if receivers.blank? project = pull_request&.project owner = project&.owner content = sys_notice.gsub('{title}', pull_request&.title) @@ -26,4 +32,30 @@ class MessageTemplate::PullRequestClosed < MessageTemplate Rails.logger.info("MessageTemplate::PullRequestClosed.get_message_content [ERROR] #{e}") return '', '', '' end + + def self.get_email_message_content(receiver, operator, pull_request) + if receiver.user_template_message_setting.present? + return '', '', '' unless receiver.user_template_message_setting.email_body["CreateOrAssign::PullRequestChanged"] + end + project = pull_request&.project + owner = project&.owner + title = email_title + title.gsub!('{title}', pull_request&.title) + content = email + content.gsub!('{receiver}', receiver&.real_name) + content.gsub!('{nickname1}', operator&.real_name) + content.gsub!('{login1}', operator&.login) + content.gsub!('{nickname2}', owner&.real_name) + content.gsub!('{login2}', owner&.login) + content.gsub!('{identifier}', project&.identifier) + content.gsub!('{repository}', project&.name) + content.gsub!('{baseurl}', base_url) + content.gsub!('{title}', pull_request&.title) + content.gsub!('{id}', pull_request&.id.to_s) + + return receiver&.mail, title, content + rescue => e + Rails.logger.info("MessageTemplate::PullRequestClosed.get_email_message_content [ERROR] #{e}") + return '', '', '' + end end diff --git a/app/models/message_template/pull_request_merged.rb b/app/models/message_template/pull_request_merged.rb index 8df4255a0..3dccffdd7 100644 --- a/app/models/message_template/pull_request_merged.rb +++ b/app/models/message_template/pull_request_merged.rb @@ -17,6 +17,12 @@ class MessageTemplate::PullRequestMerged < MessageTemplate # MessageTemplate::PullRequestMerged.get_message_content(User.where(login: 'yystopf'), User.last, PullRequest.last) def self.get_message_content(receivers, operator, pull_request) + receivers.each do |receiver| + if receiver.user_template_message_setting.present? + receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["CreateOrAssign::PullRequestChanged"] + end + end + return '', '', '' if receivers.blank? project = pull_request&.project owner = project&.owner content = sys_notice.gsub('{title}', pull_request&.title) @@ -26,4 +32,30 @@ class MessageTemplate::PullRequestMerged < MessageTemplate Rails.logger.info("MessageTemplate::PullRequestMerged.get_message_content [ERROR] #{e}") return '', '', '' end + + def self.get_email_message_content(receiver, operator, pull_request) + if receiver.user_template_message_setting.present? + return '', '', '' unless receiver.user_template_message_setting.email_body["CreateOrAssign::PullRequestChanged"] + end + project = pull_request&.project + owner = project&.owner + title = email_title + title.gsub!('{title}', pull_request&.title) + content = email + content.gsub!('{receiver}', receiver&.real_name) + content.gsub!('{nickname1}', operator&.real_name) + content.gsub!('{login1}', operator&.login) + content.gsub!('{nickname2}', owner&.real_name) + content.gsub!('{login2}', owner&.login) + content.gsub!('{identifier}', project&.identifier) + content.gsub!('{repository}', project&.name) + content.gsub!('{baseurl}', base_url) + content.gsub!('{title}', pull_request&.title) + content.gsub!('{id}', pull_request&.id.to_s) + + return receiver&.mail, title, content + rescue => e + Rails.logger.info("MessageTemplate::PullRequestMerged.get_email_message_content [ERROR] #{e}") + return '', '', '' + end end diff --git a/app/models/template_message_setting/create_or_assign.rb b/app/models/template_message_setting/create_or_assign.rb index 54f842409..2c9fa2076 100644 --- a/app/models/template_message_setting/create_or_assign.rb +++ b/app/models/template_message_setting/create_or_assign.rb @@ -25,6 +25,7 @@ class TemplateMessageSetting::CreateOrAssign < TemplateMessageSetting end def self.build_init_data - + self.find_or_create_by(name: "易修状态变更", key: "IssueChanged") + self.find_or_create_by(name: "合并请求状态变更", key: "PullRequestChanged") end end diff --git a/app/models/template_message_setting/normal.rb b/app/models/template_message_setting/normal.rb index 44ed35617..9090196d5 100644 --- a/app/models/template_message_setting/normal.rb +++ b/app/models/template_message_setting/normal.rb @@ -24,7 +24,7 @@ class TemplateMessageSetting::Normal < TemplateMessageSetting end def self.build_init_data - # self.find_or_create_by(name: "账号有权限变更", key: "Permission") + self.find_or_create_by(name: "账号有权限变更", key: "Permission") self.find_or_create_by(name: "被拉入或移出组织", key: "Organization") self.find_or_create_by(name: "被拉入或移出项目", key: "Project") self.find_or_create_by(name: "有新的易修指派给我", key: "IssueAssigned") diff --git a/app/models/user_template_message_setting.rb b/app/models/user_template_message_setting.rb index 7b7f8cb8c..c581e626e 100644 --- a/app/models/user_template_message_setting.rb +++ b/app/models/user_template_message_setting.rb @@ -28,11 +28,13 @@ class UserTemplateMessageSetting < ApplicationRecord def self.init_notification_body { - # "Normal::Permission": true, + "Normal::Permission": true, "Normal::Project": true, "Normal::Organization": true, "Normal::IssueAssigned": true, "Normal::PullRequestAssigned": true, + "CreateOrAssign::IssueChanged": true, + "CreateOrAssign::PullRequestChanged": true, "ManageProject::Issue": true, "ManageProject::PullRequest": true, "ManageProject::Member": true, @@ -42,11 +44,13 @@ class UserTemplateMessageSetting < ApplicationRecord def self.init_email_body { - # "Normal::Permission": true, + "Normal::Permission": true, "Normal::Project": true, "Normal::Organization": true, "Normal::IssueAssigned": true, "Normal::PullRequestAssigned": true, + "CreateOrAssign::IssueChanged": true, + "CreateOrAssign::PullRequestChanged": true, "ManageProject::Issue": true, "ManageProject::PullRequest": true, "ManageProject::Member": true, diff --git a/public/message_template/issue_changed.html b/public/message_template/issue_changed.html new file mode 100755 index 000000000..ed3bbbe54 --- /dev/null +++ b/public/message_template/issue_changed.html @@ -0,0 +1,62 @@ + + + 有新的易修指派给我 + + + + +
+
+
+ +

确实让创新更美好

+
+
+
+

+ {receiver},您好!
+ 在项目 {nickname2}/{repository} 的易修 {title} 中: + {ifassigner}{nickname1}将负责人从 {assigner1} 修改为 {assigner2}{endassigner} + {ifstatus}{nickname1}将状态从 {status1} 修改为 {status2}{endstatus} + {iftracker}{nickname1}将类型从 {tracker1} 修改为 {tracker2}{endtracker} + {ifpriority}{nickname1}将优先级从 {priority1} 修改为 {priority2}{endpriority} + {ifmilestone}{nickname1}将里程碑从 {milestone1} 修改为 {milestone2}{endmilestone} + {iftag}{nickname1}将标记从 {tag1} 修改为 {tag2}{endtag} + {ifdoneratio}{nickname1}将完成度从 {doneratio1} 修改为 {doneratio2}{enddoneratio} + {ifbranch}{nickname1}将指定分支从 {branch1} 修改为 {branch2}{endbranch} + {ifstartdate}{nickname1}将开始日期从 {startdate1} 修改为 {startdate2}{endstartdate} + {ifduedate}{nickname1}将结束日期从 {duedate1} 修改为 {duedate2}{endduedate} +

+
+ +

+ 扫一扫,关注trustie微信公众号,更方便获取平台动态,消息推送等提醒
+ 想了解更多信息,请访问 www.trustie.net +

+
+
+

如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693

+

Trustie团队

+
+
+
+
+ + \ No newline at end of file diff --git a/public/message_template/issue_deleted.html b/public/message_template/issue_deleted.html new file mode 100755 index 000000000..1eb40c81c --- /dev/null +++ b/public/message_template/issue_deleted.html @@ -0,0 +1,52 @@ + + + 易修状态改变 + + + + +
+
+
+ +

确实让创新更美好

+
+
+
+

+ {receiver},您好!
+ {nickname}已将易修 {title} 删除 +

+
+ +

+ 扫一扫,关注trustie微信公众号,更方便获取平台动态,消息推送等提醒
+ 想了解更多信息,请访问 www.trustie.net +

+
+
+

如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693

+

Trustie团队

+
+
+
+
+ + \ No newline at end of file diff --git a/public/message_template/organization_role.html b/public/message_template/organization_role.html new file mode 100755 index 000000000..661698b8a --- /dev/null +++ b/public/message_template/organization_role.html @@ -0,0 +1,52 @@ + + + 组织权限被更改 + + + + +
+
+
+ +

确实让创新更美好

+
+
+
+

+ {receiver},您好!
+ 组织 {organization} 已把你的角色修改为 {role} +

+
+ +

+ 扫一扫,关注trustie微信公众号,更方便获取平台动态,消息推送等提醒
+ 想了解更多信息,请访问 www.trustie.net +

+
+
+

如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693

+

Trustie团队

+
+
+
+
+ + \ No newline at end of file diff --git a/public/message_template/project_pull_request.html b/public/message_template/project_pull_request.html index 0f75e0b8c..c342894b0 100755 --- a/public/message_template/project_pull_request.html +++ b/public/message_template/project_pull_request.html @@ -31,7 +31,7 @@

{receiver},您好!
- {nickname1}在 {nickname2}/{repository} 提交了一个合并请求:{title}
+ {nickname1}在 {nickname2}/{repository} 提交了一个合并请求:{title}

diff --git a/public/message_template/project_role.html b/public/message_template/project_role.html new file mode 100755 index 000000000..db64a4f76 --- /dev/null +++ b/public/message_template/project_role.html @@ -0,0 +1,52 @@ + + + 移出项目 + + + + +
+
+
+ +

确实让创新更美好

+
+
+
+

+ {receiver},您好!
+ 项目 {nickname}/{repository} 已把你的角色修改为 {role} +

+
+ +

+ 扫一扫,关注trustie微信公众号,更方便获取平台动态,消息推送等提醒
+ 想了解更多信息,请访问 www.trustie.net +

+
+
+

如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693

+

Trustie团队

+
+
+
+
+ + \ No newline at end of file diff --git a/public/message_template/pull_request_assigned.html b/public/message_template/pull_request_assigned.html index 3898336e4..fe139ec1b 100755 --- a/public/message_template/pull_request_assigned.html +++ b/public/message_template/pull_request_assigned.html @@ -31,7 +31,7 @@

{receiver},您好!
- {nickname1}在 {nickname2}/{repository} 指派给你一个合并请求:{title}
+ {nickname1}在 {nickname2}/{repository} 指派给你一个合并请求:{title}

diff --git a/public/message_template/pull_request_changed.html b/public/message_template/pull_request_changed.html new file mode 100755 index 000000000..4e6e4eac7 --- /dev/null +++ b/public/message_template/pull_request_changed.html @@ -0,0 +1,56 @@ + + + 合并请求被更改 + + + + +
+
+
+ +

确实让创新更美好

+
+
+
+

+ {receiver},您好!
+ 在项目 {nickname2}/{repository} 的合并请求 {title} 中: + {ifassigner}{nickname1}将负责人从 {assigner1} 修改为 {assigner2}{endassigner} + {ifmilestone}{nickname1}将里程碑从 {milestone1} 修改为 {milestone2}{endmilestone} + {iftag}{nickname1}将标记从 {tag1} 修改为 {tag2}{endtag} + {ifpriority}{nickname1}将优先级从 {priority1} 修改为 {priority2}{endpriority} +

+
+ +

+ 扫一扫,关注trustie微信公众号,更方便获取平台动态,消息推送等提醒
+ 想了解更多信息,请访问 www.trustie.net +

+
+
+

如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693

+

Trustie团队

+
+
+
+
+ + \ No newline at end of file diff --git a/public/message_template/pull_request_closed.html b/public/message_template/pull_request_closed.html new file mode 100755 index 000000000..d0828c19a --- /dev/null +++ b/public/message_template/pull_request_closed.html @@ -0,0 +1,52 @@ + + + 合并请求被关闭 + + + + +
+
+
+ +

确实让创新更美好

+
+
+
+

+ {receiver},您好!
+ 你提交的合并请求:{title} 被拒绝; +

+
+ +

+ 扫一扫,关注trustie微信公众号,更方便获取平台动态,消息推送等提醒
+ 想了解更多信息,请访问 www.trustie.net +

+
+
+

如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693

+

Trustie团队

+
+
+
+
+ + \ No newline at end of file diff --git a/public/message_template/pull_request_merged.html b/public/message_template/pull_request_merged.html new file mode 100755 index 000000000..e1f028a7e --- /dev/null +++ b/public/message_template/pull_request_merged.html @@ -0,0 +1,52 @@ + + + 合并请求被合并 + + + + +
+
+
+ +

确实让创新更美好

+
+
+
+

+ {receiver},您好!
+ 你提交的合并请求:{title} 已通过; +

+
+ +

+ 扫一扫,关注trustie微信公众号,更方便获取平台动态,消息推送等提醒
+ 想了解更多信息,请访问 www.trustie.net +

+
+
+

如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693

+

Trustie团队

+
+
+
+
+ + \ No newline at end of file