| @@ -111,6 +111,7 @@ class IssuesController < ApplicationController | |||
| Issues::CreateForm.new({subject:issue_params[:subject]}).validate! | |||
| @issue = Issue.new(issue_params) | |||
| if @issue.save! | |||
| SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) | |||
| if params[:attachment_ids].present? | |||
| params[:attachment_ids].each do |id| | |||
| attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id) | |||
| @@ -202,6 +203,20 @@ class IssuesController < ApplicationController | |||
| issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id) | |||
| Issues::UpdateForm.new({subject:issue_params[:subject]}).validate! | |||
| if @issue.update_attributes(issue_params) | |||
| if @issue&.pull_request.present? | |||
| SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @issue&.pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) | |||
| SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @issue&.pull_request&.id ) if @issue.previous_changes[:assigned_to_id].present? | |||
| else | |||
| previous_changes = @issue.previous_changes.slice(:status_id, :assigned_to_id, :tracker_id, :priority_id, :fixed_version_id, :done_ratio, :issue_tags_value, :branch_name) | |||
| if @issue.previous_changes[:start_date].present? | |||
| previous_changes.merge!(start_date: [@issue.previous_changes[:start_date][0].to_s, @issue.previous_changes[:start_date][1].to_s]) | |||
| end | |||
| if @issue.previous_changes[:due_date].present? | |||
| previous_changes.merge!(due_date: [@issue.previous_changes[:due_date][0].to_s, @issue.previous_changes[:due_date][1].to_s]) | |||
| end | |||
| SendTemplateMessageJob.perform_later('IssueChanged', current_user.id, @issue&.id, previous_changes) | |||
| SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if @issue.previous_changes[:assigned_to_id].present? | |||
| end | |||
| if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时 | |||
| @issue.issue_times.update_all(end_time: Time.now) | |||
| @issue.update_closed_issues_count_in_project! | |||
| @@ -253,6 +268,7 @@ class IssuesController < ApplicationController | |||
| status_id = @issue.status_id | |||
| token = @issue.token | |||
| login = @issue.user.try(:login) | |||
| SendTemplateMessageJob.perform_later('IssueDeleted', current_user.id, @issue&.subject, @issue.assigned_to_id, @issue.author_id) | |||
| if @issue.destroy | |||
| if issue_type == "2" && status_id != 5 | |||
| post_to_chain("add", token, login) | |||
| @@ -9,6 +9,7 @@ class MembersController < ApplicationController | |||
| def create | |||
| interactor = Projects::AddMemberInteractor.call(@project.owner, @project, @user) | |||
| SendTemplateMessageJob.perform_later('ProjectJoined', @user.id, @project.id) | |||
| render_response(interactor) | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| @@ -28,6 +29,7 @@ class MembersController < ApplicationController | |||
| def remove | |||
| interactor = Projects::DeleteMemberInteractor.call(@project.owner, @project, @user) | |||
| SendTemplateMessageJob.perform_later('ProjectLeft', @user.id, @project.id) | |||
| render_response(interactor) | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| @@ -36,6 +38,7 @@ class MembersController < ApplicationController | |||
| def change_role | |||
| interactor = Projects::ChangeMemberRoleInteractor.call(@project.owner, @project, @user, params[:role]) | |||
| SendTemplateMessageJob.perform_later('ProjectRole', @user.id, @project.id, message_role_name) | |||
| render_response(interactor) | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| @@ -66,4 +69,14 @@ class MembersController < ApplicationController | |||
| def check_user_profile_completed | |||
| require_user_profile_completed(@user) | |||
| end | |||
| def message_role_name | |||
| case params[:role] | |||
| when 'Manager' then '管理员' | |||
| when 'Developer' then '开发者' | |||
| when 'Reporter' then '报告者' | |||
| else | |||
| '' | |||
| end | |||
| end | |||
| end | |||
| @@ -18,6 +18,7 @@ class Organizations::TeamUsersController < Organizations::BaseController | |||
| ActiveRecord::Base.transaction do | |||
| @team_user = TeamUser.build(@organization.id, @operate_user.id, @team.id) | |||
| @organization_user = OrganizationUser.build(@organization.id, @operate_user.id) | |||
| SendTemplateMessageJob.perform_later('OrganizationRole', @operate_user.id, @organization.id, @team.authorize_name) | |||
| Gitea::Organization::TeamUser::CreateService.call(@organization.gitea_token, @team.gtid, @operate_user.login) | |||
| end | |||
| rescue Exception => e | |||
| @@ -6,7 +6,8 @@ class Projects::ProjectUnitsController < Projects::BaseController | |||
| def create | |||
| if current_user.admin? || @project.manager?(current_user) | |||
| ActiveRecord::Base.transaction do | |||
| ProjectUnit.update_by_unit_types!(@project, unit_types) | |||
| before_units, after_units = ProjectUnit.update_by_unit_types!(@project, unit_types) | |||
| SendTemplateMessageJob.perform_later('ProjectSettingChanged', current_user.id, @project&.id, {navbar: true}) unless before_units.eql?(after_units) | |||
| render_ok | |||
| end | |||
| else | |||
| @@ -139,6 +139,7 @@ class ProjectsController < ApplicationController | |||
| @project.repository.update_column(:hidden, private) | |||
| end | |||
| end | |||
| SendTemplateMessageJob.perform_later('ProjectSettingChanged', current_user.id, @project&.id, @project.previous_changes.slice(:name, :description, :project_category_id, :project_language_id, :is_public)) | |||
| end | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| @@ -59,6 +59,7 @@ class PullRequestsController < ApplicationController | |||
| @pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params) | |||
| if @gitea_pull_request[:status] == :success | |||
| @pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"]) | |||
| SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @pull_request&.id) | |||
| render_ok | |||
| else | |||
| render_error("create pull request error: #{@gitea_pull_request[:status]}") | |||
| @@ -91,6 +92,8 @@ class PullRequestsController < ApplicationController | |||
| end | |||
| if @issue.update_attributes(@issue_params) | |||
| SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) | |||
| SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @pull_request&.id ) if @issue.previous_changes[:assigned_to_id].present? | |||
| if @pull_request.update_attributes(@local_params.compact) | |||
| gitea_pull = Gitea::PullRequest::UpdateService.call(@owner.login, @repository.identifier, | |||
| @pull_request.gitea_number, @requests_params, current_user.gitea_token) | |||
| @@ -125,7 +128,12 @@ class PullRequestsController < ApplicationController | |||
| ActiveRecord::Base.transaction do | |||
| begin | |||
| colsed = PullRequests::CloseService.call(@owner, @repository, @pull_request, current_user) | |||
| colsed === true ? normal_status(1, "已拒绝") : normal_status(-1, '合并失败') | |||
| if colsed === true | |||
| SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, @pull_request.id) | |||
| normal_status(1, "已拒绝") | |||
| else | |||
| normal_status(-1, '合并失败') | |||
| end | |||
| rescue => e | |||
| normal_status(-1, e.message) | |||
| raise ActiveRecord::Rollback | |||
| @@ -164,6 +172,7 @@ class PullRequestsController < ApplicationController | |||
| if success_condition && @pull_request.merge! | |||
| @pull_request.project_trend_status! | |||
| @issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id) | |||
| SendTemplateMessageJob.perform_later('PullRequestMerged', current_user.id, @pull_request.id) | |||
| normal_status(1, "合并成功") | |||
| else | |||
| normal_status(-1, result.message) | |||
| @@ -16,8 +16,21 @@ class Users::MessagesController < Users::BaseController | |||
| case params[:type] | |||
| when 'atme' | |||
| Notice::Write::CreateAtmeForm.new(atme_params).validate! | |||
| result = Notice::Write::CreateService.call(@receivers.pluck(:id), '发送了一个@我消息', base_url, "IssueAtme", 2, {}, current_user.id) | |||
| return render_error if result.nil? | |||
| case atme_params[:atmeable_type] | |||
| when 'Issue' | |||
| SendTemplateMessageJob.perform_now('IssueAtme', @receivers, current_user.id, atme_params[:atmeable_id]) | |||
| when 'PullRequest' | |||
| SendTemplateMessageJob.perform_now('PullRequestAtme', @receivers, current_user.id, atme_params[:atmeable_id]) | |||
| when 'Journal' | |||
| journal = Journal.find_by_id(atme_params[:atmeable_id]) | |||
| if journal.present? | |||
| if journal&.issue&.pull_request.present? | |||
| SendTemplateMessageJob.perform_now('PullRequestAtme', @receivers, current_user.id, atme_params[:atmeable_id]) | |||
| else | |||
| SendTemplateMessageJob.perform_now('IssueAtme', @receivers, current_user.id, atme_params[:atmeable_id]) | |||
| end | |||
| end | |||
| end | |||
| end | |||
| render_ok | |||
| rescue Exception => e | |||
| @@ -1,7 +1,7 @@ | |||
| <!-- | |||
| * @Date: 2021-03-01 10:35:21 | |||
| * @LastEditors: viletyy | |||
| * @LastEditTime: 2021-09-14 17:34:40 | |||
| * @LastEditTime: 2021-09-15 18:00:10 | |||
| * @FilePath: /forgeplus/app/docs/slate/source/includes/_users.md | |||
| --> | |||
| # Users | |||
| @@ -219,8 +219,8 @@ await octokit.request('POST /api/users/:login/messages.json') | |||
| 参数 | 类型 | 字段说明 | |||
| --------- | ----------- | ----------- | |||
| |type | string | 消息类型 | | |||
| |recervers_login | array | 需要发送消息的用户名数组| | |||
| |atmeable_type | string | atme消息对象,是从哪里@我的,比如评论:Journal | | |||
| |receivers_login | array | 需要发送消息的用户名数组| | |||
| |atmeable_type | string | atme消息对象,是从哪里@我的,比如评论:Journal、易修:Issue、合并请求:PullRequest | | |||
| |atmeable_id | integer | atme消息对象id | | |||
| > 请求的JSON示例: | |||
| @@ -5,8 +5,152 @@ class SendTemplateMessageJob < ApplicationJob | |||
| Rails.logger.info "SendTemplateMessageJob [args] #{args}" | |||
| case source | |||
| when 'FollowTip' | |||
| receivers, followeder = args | |||
| Rails.logger.info "#{receivers} #{followeder}" | |||
| watcher_id = args[0] | |||
| watcher = Watcher.find_by_id(watcher_id) | |||
| return unless watcher.present? | |||
| receivers = User.where(id: watcher.watchable_id) | |||
| followeder = User.find_by_id(watcher.user_id) | |||
| receivers_string, content, notification_url = MessageTemplate::FollowedTip.get_message_content(receivers, followeder) | |||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {watcher_id: watcher.id}) | |||
| when 'IssueAssigned' | |||
| 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&.assigned_to_id) | |||
| receivers_string, content, notification_url = MessageTemplate::IssueAssigned.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 'IssueAssignerExpire' | |||
| issue_id = args[0] | |||
| issue = Issue.find_by_id(issue_id) | |||
| return unless issue.present? | |||
| receivers = User.where(id: issue&.assigned_to_id) | |||
| receivers_string, content, notification_url = MessageTemplate::IssueAssignerExpire.get_message_content(receivers, issue) | |||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {issue_id: issue.id}) | |||
| when 'IssueAtme' | |||
| receivers, operator_id, issue_id = args[0], args[1], args[2] | |||
| operator = User.find_by_id(operator_id) | |||
| issue = Issue.find_by_id(issue_id) | |||
| return unless operator.present? && issue.present? | |||
| receivers_string, content, notification_url = MessageTemplate::IssueAtme.get_message_content(receivers, operator, issue) | |||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_id: issue.id}, 2) | |||
| when 'IssueChanged' | |||
| operator_id, issue_id, change_params = args[0], args[1], args[2] | |||
| 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&.assigned_to_id, issue&.author_id]) | |||
| receivers_string, content, notification_url = MessageTemplate::IssueChanged.get_message_content(receivers, operator, issue, change_params) | |||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_id: issue.id, change_params: change_params.symbolize_keys}) | |||
| when 'IssueCreatorExpire' | |||
| issue_id = args[0] | |||
| issue = Issue.find_by_id(issue_id) | |||
| return unless issue.present? | |||
| receivers = User.where(id: issue&.author_id) | |||
| receivers_string, content, notification_url = MessageTemplate::IssueCreatorExpire.get_message_content(receivers, issue) | |||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {issue_id: issue.id}) | |||
| when 'IssueDeleted' | |||
| operator_id, issue_title, issue_assigned_to_id, issue_author_id = args[0], args[1], args[2], args[3] | |||
| operator = User.find_by_id(operator_id) | |||
| return unless operator.present? | |||
| receivers = User.where(id: [issue_assigned_to_id, issue_author_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}) | |||
| when 'OrganizationJoined' | |||
| user_id, organization_id = args[0], args[1] | |||
| user = User.find_by_id(user_id) | |||
| organization = Organization.find_by_id(organization_id) | |||
| return unless user.present? && organization.present? | |||
| receivers = User.where(id: user.id) | |||
| receivers_string, content, notification_url = MessageTemplate::OrganizationJoined.get_message_content(receivers, organization) | |||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user.id, organization_id: organization.id}) | |||
| when 'OrganizationLeft' | |||
| user_id, organization_id = args[0], args[1] | |||
| user = User.find_by_id(user_id) | |||
| organization = Organization.find_by_id(organization_id) | |||
| return unless user.present? && organization.present? | |||
| receivers = User.where(id: user.id) | |||
| receivers_string, content, notification_url = MessageTemplate::OrganizationLeft.get_message_content(receivers, organization) | |||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user.id, organization_id: organization.id}) | |||
| when 'OrganizationRole' | |||
| user_id, organization_id, role = args[0], args[1], args[2] | |||
| user = User.find_by_id(user_id) | |||
| organization = Organization.find_by_id(organization_id) | |||
| return unless user.present? && organization.present? | |||
| receivers = User.where(id: user.id) | |||
| receivers_string, content, notification_url = MessageTemplate::OrganizationRole.get_message_content(receivers, organization, role) | |||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user.id, organization_id: organization.id, role: role}) | |||
| when 'ProjectJoined' | |||
| user_id, project_id = args[0], args[1] | |||
| user = User.find_by_id(user_id) | |||
| project = Project.find_by_id(project_id) | |||
| return unless user.present? && project.present? | |||
| receivers = User.where(id: user.user_id) | |||
| receivers_string, content, notification_url = MessageTemplate::ProjectJoined.get_message_content(receivers, project) | |||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user.id, project_id: project.id}) | |||
| when 'ProjectLeft' | |||
| user_id, project_id = args[0], args[1] | |||
| user = User.find_by_id(user_id) | |||
| project = Project.find_by_id(project_id) | |||
| return unless user.present? && project.present? | |||
| receivers = User.where(id: user.user_id) | |||
| receivers_string, content, notification_url = MessageTemplate::ProjectJoined.get_message_content(receivers, project) | |||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user.id, project_id: project.id}) | |||
| when 'ProjectRole' | |||
| user_id, project_id, role = args[0], args[1], args[2] | |||
| user = User.find_by_id(user_id) | |||
| project = Project.find_by_id(project_id) | |||
| return unless user.present? && project.present? | |||
| receivers = User.where(id: user.user_id) | |||
| receivers_string, content, notification_url = MessageTemplate::ProjectRole.get_message_content(receivers, project, role) | |||
| Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user.id, project_id: project.id, role: role}) | |||
| when 'ProjectSettingChanged' | |||
| operator_id, project_id, change_params = args[0], args[1], args[2] | |||
| operator = User.find_by_id(operator_id) | |||
| project = Project.find_by_id(project_id) | |||
| return unless operator.present? && project.present? | |||
| receivers = project.all_managers | |||
| 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}) | |||
| when 'PullRequestAssigned' | |||
| operator_id, pull_request_id = args[0], args[1] | |||
| operator = User.find_by_id(operator_id) | |||
| pull_request = PullRequest.find_by_id(pull_request_id) | |||
| return unless operator.present? && pull_request.present? | |||
| receivers = User.where(id: pull_request&.issue&.assigned_to_id) | |||
| receivers_string, content, notification_url = MessageTemplate::PullRequestAssigned.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}) | |||
| when 'PullRequestAtme' | |||
| receivers, operator_id, pull_request_id = args[0], args[1], args[2] | |||
| operator = User.find_by_id(operator_id) | |||
| pull_request = PullRequest.find_by_id(pull_request_id) | |||
| return unless operator.present? && pull_request.present? | |||
| receivers_string, content, notification_url = MessageTemplate::PullRequestAtme.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}, 2) | |||
| when 'PullRequestChanged' | |||
| operator_id, pull_request_id, change_params = args[0], args[1], args[2] | |||
| operator = User.find_by_id(operator_id) | |||
| pull_request = PullRequest.find_by_id(pull_request_id) | |||
| return unless operator.present? && pull_request.present? | |||
| receivers = User.where(id: [pull_request&.issue&.assigned_to_id, pull_request&.user_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}) | |||
| when 'PullRequestClosed' | |||
| operator_id, pull_request_id = args[0], args[1] | |||
| operator = User.find_by_id(operator_id) | |||
| pull_request = PullRequest.find_by_id(pull_request_id) | |||
| return unless operator.present? && pull_request.present? | |||
| receivers = User.where(id: [pull_request&.issue&.assigned_to_id, pull_request&.user_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}) | |||
| when 'PullRequestMerged' | |||
| operator_id, pull_request_id = args[0], args[1] | |||
| operator = User.find_by_id(operator_id) | |||
| pull_request = PullRequest.find_by_id(pull_request_id) | |||
| return unless operator.present? && pull_request.present? | |||
| receivers = User.where(id: [pull_request&.issue&.assigned_to_id, pull_request&.user_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}) | |||
| end | |||
| end | |||
| end | |||
| @@ -19,7 +19,7 @@ class MessageTemplate::IssueAtme < MessageTemplate | |||
| project = issue&.project | |||
| owner = project&.owner | |||
| content = sys_notice.gsub('{nickname}', operator&.nickname).gsub('{title}', issue&.subject) | |||
| url = notification_url.gsub('{owner}', owner&.login).gsub('{identifer}', project&.identifier).gsub('{id}', issue&.id.to_s) | |||
| url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', issue&.id.to_s) | |||
| return receivers_string(receivers), content, url | |||
| rescue => e | |||
| Rails.logger.info("MessageTemplate::IssueAtme.get_message_content [ERROR] #{e}") | |||
| @@ -14,116 +14,132 @@ | |||
| # 我创建或负责的易修状态变更 | |||
| class MessageTemplate::IssueChanged < MessageTemplate | |||
| # MessageTemplate::IssueChanged.get_message_content(User.where(login: 'yystopf'), User.last, Issue.last, {assigner: 'testforge2', milestone: '里程碑', tag: '标签', priority: '低', tracker: '支持', doneratio: '70', branch: 'master', startdate: Date.today, duedate: Date.today + 1.days}) | |||
| # 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) | |||
| return '', '', '' if change_params.blank? | |||
| project = issue&.project | |||
| owner = project&.owner | |||
| content = MessageTemplate::IssueChanged.sys_notice.gsub('{nickname1}', operator&.nickname).gsub('{nickname2}', owner&.nickname).gsub('{repository}', project&.name).gsub('{title}', issue&.subject) | |||
| url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', issue&.id.to_s) | |||
| # 易修负责人修改 | |||
| if change_params[:assigner].present? | |||
| assigner = issue&.get_assign_user&.nickname || '未指派成员' | |||
| 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]) | |||
| content.sub!('{ifassigner}', '') | |||
| content.sub!('{endassigner}', '') | |||
| content.gsub!('{assigner1}', assigner) | |||
| content.gsub!('{assigner2}', change_params[:assigner]) | |||
| content.gsub!('{assigner1}', assigner1.present? ? assigner1&.nickname || assigner1.login : '未指派成员') | |||
| content.gsub!('{assigner2}', assigner2.present? ? assigner2&.nickname || assigner2.login : '未指派成员') | |||
| else | |||
| content.gsub!(/({ifassigner})(.*)({endassigner})/, '') | |||
| end | |||
| # 易修状态修改 | |||
| if change_params[:status].present? | |||
| status = issue&.issue_status&.name | |||
| 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]) | |||
| content.sub!('{ifstatus}', '') | |||
| content.sub!('{endstatus}', '') | |||
| content.gsub!('{status1}', status) | |||
| content.gsub!('{status2}', change_params[:status]) | |||
| content.gsub!('{status1}', status1&.name) | |||
| content.gsub!('{status2}', status2&.name) | |||
| else | |||
| content.gsub!(/({ifstatus})(.*)({endstatus})/, '') | |||
| end | |||
| # 易修类型修改 | |||
| if change_params[:tracker].present? | |||
| tracker = issue&.tracker&.name | |||
| 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]) | |||
| content.sub!('{iftracker}', '') | |||
| content.sub!('{endtracker}', '') | |||
| content.gsub!('{tracker1}', tracker) | |||
| content.gsub!('{tracker2}', change_params[:tracker]) | |||
| content.gsub!('{tracker1}', tracker1&.name) | |||
| content.gsub!('{tracker2}', tracker2&.name) | |||
| else | |||
| content.gsub!(/({iftracker})(.*)({endtracker})/, '') | |||
| end | |||
| # 合并请求里程碑修改 | |||
| if change_params[:milestone].present? | |||
| milestone = issue&.version&.name || '未选择里程碑' | |||
| # 易修里程碑修改 | |||
| 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]) | |||
| content.sub!('{ifmilestone}', '') | |||
| content.sub!('{endmilestone}', '') | |||
| content.gsub!('{milestone1}', milestone) | |||
| content.gsub!('{milestone2}', change_params[:milestone]) | |||
| 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[:tag].present? | |||
| tag = issue&.issue_tags.distinct.pluck(:name).join(",") | |||
| tag = '未选择标签' if tag == '' | |||
| # 易修标签修改 | |||
| 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(",") | |||
| content.sub!('{iftag}', '') | |||
| content.sub!('{endtag}', '') | |||
| content.gsub!('{tag1}', tag) | |||
| content.gsub!('{tag2}', change_params[:tag]) | |||
| content.gsub!('{tag1}', tag1) | |||
| content.gsub!('{tag2}', tag2) | |||
| else | |||
| content.gsub!(/({iftag})(.*)({endtag})()/, '') | |||
| end | |||
| # 合并请求优先级修改 | |||
| if change_params[:priority].present? | |||
| priority = issue&.priority&.name | |||
| # 易修优先级修改 | |||
| 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]) | |||
| content.sub!('{ifpriority}', '') | |||
| content.sub!('{endpriority}', '') | |||
| content.gsub!('{priority1}', priority) | |||
| content.gsub!('{priority2}', change_params[:priority]) | |||
| content.gsub!('{priority1}', priority1&.name) | |||
| content.gsub!('{priority2}', priority2&.name) | |||
| else | |||
| content.gsub!(/({ifpriority})(.*)({endpriority})/, '') | |||
| end | |||
| # 易修完成度修改 | |||
| if change_params[:doneratio].present? | |||
| doneratio = issue&.done_ratio | |||
| if change_params[:done_ratio].present? | |||
| doneratio1 = change_params[:done_ratio][0] | |||
| doneratio2 = change_params[:done_ratio][1] | |||
| content.sub!('{ifdoneratio}', '') | |||
| content.sub!('{enddoneratio}', '') | |||
| content.gsub!('{doneratio1}', "#{doneratio}%") | |||
| content.gsub!('{doneratio2}', "#{change_params[:doneratio]}%") | |||
| content.gsub!('{doneratio1}', "#{doneratio1}%") | |||
| content.gsub!('{doneratio2}', "#{doneratio2}%") | |||
| else | |||
| content.gsub!(/({ifdoneratio})(.*)({enddoneratio})/, '') | |||
| end | |||
| # 易修指定分支修改 | |||
| if change_params[:branch].present? | |||
| branch = issue&.branch_name || '分支未指定' | |||
| 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] | |||
| content.sub!('{ifbranch}', '') | |||
| content.sub!('{endbranch}', '') | |||
| content.gsub!('{branch1}', branch ) | |||
| content.gsub!('{branch2}', change_params[:branch]) | |||
| content.gsub!('{branch1}', branch1) | |||
| content.gsub!('{branch2}', branch2) | |||
| else | |||
| content.gsub!(/({ifbranch})(.*)({endbranch})/, '') | |||
| end | |||
| # 易修开始日期修改 | |||
| if change_params[:startdate].present? | |||
| startdate = issue&.start_date || "未选择开始日期" | |||
| 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] | |||
| content.sub!('{ifstartdate}', '') | |||
| content.sub!('{endstartdate}', '') | |||
| content.gsub!('{startdate1}', startdate.to_s ) | |||
| content.gsub!('{startdate2}', change_params[:startdate].to_s) | |||
| content.gsub!('{startdate1}', startdate1 ) | |||
| content.gsub!('{startdate2}', startdate2) | |||
| else | |||
| content.gsub!(/({ifstartdate})(.*)({endstartdate})/, '') | |||
| end | |||
| # 易修结束日期修改 | |||
| if change_params[:duedate].present? | |||
| duedate = issue&.due_date || '未选择结束日期' | |||
| 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] | |||
| content.sub!('{ifduedate}', '') | |||
| content.sub!('{endduedate}', '') | |||
| content.gsub!('{duedate1}', duedate.to_s) | |||
| content.gsub!('{duedate2}', change_params[:duedate].to_s) | |||
| content.gsub!('{duedate1}', duedate1) | |||
| content.gsub!('{duedate2}', duedate2) | |||
| else | |||
| content.gsub!(/({ifduedate})(.*)({endduedate})/, '') | |||
| end | |||
| return receivers_string(receivers), content, url | |||
| # rescue => e | |||
| # Rails.logger.info("MessageTemplate::IssueAssigned.get_message_content [ERROR] #{e}") | |||
| # return '', '', '' | |||
| rescue => e | |||
| Rails.logger.info("MessageTemplate::IssueAssigned.get_message_content [ERROR] #{e}") | |||
| return '', '', '' | |||
| end | |||
| end | |||
| @@ -14,11 +14,9 @@ | |||
| # 我创建或负责的易修删除 | |||
| class MessageTemplate::IssueDeleted < MessageTemplate | |||
| # MessageTemplate::IssueDeleted.get_message_content(User.where(login: 'yystopf'), User.last, Issue.last) | |||
| def self.get_message_content(receivers, operator, issue) | |||
| project = issue&.project | |||
| owner = project&.owner | |||
| content = sys_notice.gsub('{nickname}', operator&.nickname).gsub('{title}', issue&.subject) | |||
| # MessageTemplate::IssueDeleted.get_message_content(User.where(login: 'yystopf'), User.last, "hahah") | |||
| def self.get_message_content(receivers, operator, issue_title) | |||
| content = sys_notice.gsub('{nickname}', operator&.nickname).gsub('{title}', issue_title) | |||
| return receivers_string(receivers), content, notification_url | |||
| rescue => e | |||
| Rails.logger.info("MessageTemplate::IssueAtme.get_message_content [ERROR] #{e}") | |||
| @@ -16,6 +16,7 @@ class MessageTemplate::ProjectSettingChanged < MessageTemplate | |||
| # MessageTemplate::ProjectSettingChanged.get_message_content(User.where(login: 'yystopf'), User.last, Project.last, {description: '测试修改项目简介', category: '大数据', language: 'Ruby', permission: '公有', navbar: '易修, 合并请求'}) | |||
| def self.get_message_content(receivers, operator, project, change_params) | |||
| return '', '', '' if change_params.blank? | |||
| owner = project&.owner | |||
| content = sys_notice.gsub('{nickname1}', operator&.nickname).gsub('{nickname2}', owner&.nickname).gsub('{repository}', project&.name) | |||
| url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier) | |||
| @@ -23,7 +24,7 @@ class MessageTemplate::ProjectSettingChanged < MessageTemplate | |||
| if change_params[:name].present? | |||
| content.sub!('{ifname}', '') | |||
| content.sub!('{endname}', '') | |||
| content.gsub!('{name}', change_params[:name]) | |||
| content.gsub!('{name}', change_params[:name][1]) | |||
| else | |||
| content.gsub!(/({ifname})(.*)({endname})/, '') | |||
| end | |||
| @@ -31,46 +32,57 @@ class MessageTemplate::ProjectSettingChanged < MessageTemplate | |||
| if change_params[:description].present? | |||
| content.sub!('{ifdescription}', '') | |||
| content.sub!('{enddescription}', '') | |||
| content.gsub!('{description}', change_params[:description]) | |||
| content.gsub!('{description}', change_params[:description][1]) | |||
| else | |||
| content.gsub!(/({ifdescription})(.*)({enddescription})/, '') | |||
| end | |||
| # 项目类别更改 | |||
| if change_params[:category].present? | |||
| if change_params[:project_category_id].present? | |||
| category = ProjectCategory.find_by_id(change_params[:project_category_id][1]) | |||
| content.sub!('{ifcategory}', '') | |||
| content.sub!('{endcategory}', '') | |||
| content.gsub!('{category}', change_params[:category]) | |||
| content.gsub!('{category}', category&.name) | |||
| else | |||
| content.gsub!(/({ifcategory})(.*)({endcategory})/, '') | |||
| end | |||
| # 项目语言更改 | |||
| if change_params[:language].present? | |||
| if change_params[:project_language_id].present? | |||
| language = ProjectLanguage.find_by_id(change_params[:project_language_id][1]) | |||
| content.sub!('{iflanguage}', '') | |||
| content.sub!('{endlanguage}', '') | |||
| content.gsub!('{language}', change_params[:language]) | |||
| content.gsub!('{language}', language&.name) | |||
| else | |||
| content.gsub!(/({iflanguage})(.*)({endlanguage})/, '') | |||
| end | |||
| # 项目公私有更改 | |||
| if change_params[:permission].present? | |||
| if change_params[:is_public].present? | |||
| permission = change_params[:is_public][1] ? '公有' : '私有' | |||
| content.sub!('{ifpermission}', '') | |||
| content.sub!('{endpermission}', '') | |||
| content.gsub!('{permission}', change_params[:permission]) | |||
| content.gsub!('{permission}', permission) | |||
| else | |||
| content.gsub!(/({ifpermission})(.*)({endpermission})/, '') | |||
| end | |||
| # 项目导航更改 | |||
| if change_params[:navbar].present? | |||
| if change_params[:navbar].present? || navbar_is_changed_by_time | |||
| navbar = project.project_units.order(unit_type: :asc).pluck(:unit_type).join(',') | |||
| navbar.gsub!('code,', '') | |||
| navbar.gsub!('issues', '易修') | |||
| navbar.gsub!('pulls', '合并请求') | |||
| navbar.gsub!('wiki', 'Wiki') | |||
| navbar.gsub!('devops', '工作流') | |||
| navbar.gsub!('versions', '里程碑') | |||
| navbar.gsub!('resources', '资源库') | |||
| content.sub!('{ifnavbar}', '') | |||
| content.sub!('{endnavbar}', '') | |||
| content.gsub!('{navbar}', change_params[:navbar]) | |||
| content.gsub!('{navbar}', navbar) | |||
| else | |||
| content.gsub!(/({ifnavbar})(.*)({endnavbar})/, '') | |||
| end | |||
| return receivers_string(receivers.where.not(id: operator.id)), content, url | |||
| rescue => e | |||
| Rails.logger.info("MessageTemplate::ProjectSettingChanged.get_message_content [ERROR] #{e}") | |||
| return '', '', '' | |||
| # rescue => e | |||
| # Rails.logger.info("MessageTemplate::ProjectSettingChanged.get_message_content [ERROR] #{e}") | |||
| # return '', '', '' | |||
| end | |||
| end | |||
| @@ -14,51 +14,57 @@ | |||
| # 我创建或负责的合并请求状态变更 | |||
| class MessageTemplate::PullRequestChanged < MessageTemplate | |||
| # MessageTemplate::PullRequestChanged.get_message_content(User.where(login: 'yystopf'), User.last, PullRequest.last, {assigner: 'testforge2', tag: '标签', priority: '低'}) | |||
| # 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) | |||
| return '', '', '' if change_params.blank? | |||
| project = pull_request&.project | |||
| owner = project&.owner | |||
| issue = pull_request&.issue | |||
| content = sys_notice.gsub('{nickname1}', operator&.nickname).gsub('{nickname2}', owner&.nickname).gsub('{repository}', project&.name) | |||
| content = sys_notice.gsub('{nickname1}', operator&.nickname).gsub('{nickname2}', owner&.nickname).gsub('{repository}', project&.name).gsub("{title}", pull_request&.title) | |||
| url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', pull_request&.id.to_s) | |||
| # 合并请求审查成员修改 | |||
| if change_params[:assigner].present? | |||
| assigner = issue&.get_assign_user&.nickname || '未指派成员' | |||
| 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]) | |||
| content.sub!('{ifassigner}', '') | |||
| content.sub!('{endassigner}', '') | |||
| content.gsub!('{assigner1}', assigner) | |||
| content.gsub!('{assigner2}', change_params[:assigner]) | |||
| content.gsub!('{assigner1}', assigner1.present? ? assigner1&.nickname || assigner1.login : '未指派成员') | |||
| content.gsub!('{assigner2}', assigner2.present? ? assigner2&.nickname || assigner2.login : '未指派成员') | |||
| else | |||
| content.gsub!(/({ifassigner})(.*)({endassigner})/, '') | |||
| end | |||
| # 合并请求里程碑修改 | |||
| if change_params[:milestone].present? | |||
| milestone = issue&.version&.name || '未选择里程碑' | |||
| 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]) | |||
| content.sub!('{ifmilestone}', '') | |||
| content.sub!('{endmilestone}', '') | |||
| content.gsub!('{milestone1}', milestone) | |||
| content.gsub!('{milestone2}', change_params[:milestone]) | |||
| 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[:tag].present? | |||
| tag = issue&.issue_tags.distinct.pluck(:name).join(",") | |||
| tag = '未选择标签' if tag == '' | |||
| 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(",") | |||
| content.sub!('{iftag}', '') | |||
| content.sub!('{endtag}', '') | |||
| content.gsub!('{tag1}', tag) | |||
| content.gsub!('{tag2}', change_params[:tag]) | |||
| content.gsub!('{tag1}', tag1) | |||
| content.gsub!('{tag2}', tag2) | |||
| else | |||
| content.gsub!(/({iftag})(.*)({endtag})()/, '') | |||
| end | |||
| # 合并请求优先级修改 | |||
| if change_params[:priority].present? | |||
| priority = issue&.priority&.name | |||
| 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]) | |||
| content.sub!('{ifpriority}', '') | |||
| content.sub!('{endpriority}', '') | |||
| content.gsub!('{priority1}', priority) | |||
| content.gsub!('{priority2}', change_params[:priority]) | |||
| content.gsub!('{priority1}', priority1&.name) | |||
| content.gsub!('{priority2}', priority2&.name) | |||
| else | |||
| content.gsub!(/({ifpriority})(.*)({endpriority})/, '') | |||
| end | |||
| @@ -22,6 +22,9 @@ class OrganizationUser < ApplicationRecord | |||
| validates :user_id, uniqueness: {scope: :organization_id} | |||
| after_create :send_create_message_to_notice_system | |||
| after_destroy :send_destroy_message_to_notice_system | |||
| def self.build(organization_id, user_id) | |||
| org_user = self.find_by(organization_id: organization_id, user_id: user_id) | |||
| return org_user unless org_user.nil? | |||
| @@ -31,4 +34,12 @@ class OrganizationUser < ApplicationRecord | |||
| def teams | |||
| organization.teams.joins(:team_users).where(team_users: {user_id: user_id}) | |||
| end | |||
| def send_create_message_to_notice_system | |||
| SendTemplateMessageJob.perform_later('OrganizationJoined', self.user_id, self.organization_id) | |||
| end | |||
| def send_destroy_message_to_notice_system | |||
| SendTemplateMessageJob.perform_later('OrganizationLeft', self.user_id, self.organization_id) | |||
| end | |||
| end | |||
| @@ -32,9 +32,13 @@ class ProjectUnit < ApplicationRecord | |||
| types.delete("pulls") if project.sync_mirror? | |||
| # 默认code类型自动创建 | |||
| types << "code" | |||
| before_units = project.project_units.pluck(:unit_type).sort | |||
| project.project_units.where.not(unit_type: types).each(&:destroy!) | |||
| types.each do |type| | |||
| project.project_units.find_or_create_by!(unit_type: type) | |||
| end | |||
| after_units = project.project_units.pluck(:unit_type).sort | |||
| return before_units, after_units | |||
| end | |||
| end | |||
| @@ -54,4 +54,15 @@ class Team < ApplicationRecord | |||
| team_users.where(user_id: user_id).present? | |||
| end | |||
| def authorize_name | |||
| case self.authorize | |||
| when 'read' then '报告者' | |||
| when 'write' then '开发者' | |||
| when 'admin' then '管理员' | |||
| when 'owner' then '管理员' | |||
| else | |||
| '' | |||
| end | |||
| end | |||
| end | |||
| @@ -24,6 +24,7 @@ class Watcher < ApplicationRecord | |||
| after_save :reset_cache_data | |||
| after_destroy :reset_cache_data | |||
| after_create :send_create_message_to_notice_system | |||
| def reset_cache_data | |||
| if self.watchable.is_a?(User) | |||
| @@ -35,4 +36,8 @@ class Watcher < ApplicationRecord | |||
| self.reset_platform_cache_async_job | |||
| end | |||
| def send_create_message_to_notice_system | |||
| SendTemplateMessageJob.perform_later('FollowTip', self.id) if self.watchable.is_a?(User) | |||
| end | |||
| end | |||
| @@ -1,7 +1,7 @@ | |||
| class Notice::Write::CreateService < Notice::Write::ClientService | |||
| attr_accessor :receivers, :sender, :content, :notification_url, :source, :extra, :type | |||
| def initialize(receivers, content, notification_url, source, type=1, extra={},sender=-1) | |||
| def initialize(receivers, content, notification_url, source, extra={}, type=1, sender=-1) | |||
| @receivers = receivers | |||
| @sender = sender | |||
| @content = content | |||
| @@ -12,6 +12,7 @@ class Notice::Write::CreateService < Notice::Write::ClientService | |||
| end | |||
| def call | |||
| return nil if request_receivers.blank? | |||
| result = post("", request_params) | |||
| response = render_response(result) | |||
| end | |||
| @@ -19,7 +20,7 @@ class Notice::Write::CreateService < Notice::Write::ClientService | |||
| private | |||
| def request_receivers | |||
| receivers.join(",") | |||
| receivers.is_a?(Array) ? receivers.join(",") : receivers | |||
| end | |||
| def request_params | |||
| @@ -921,7 +921,7 @@ Success — a happy kitten is an authenticated kitten! | |||
| <!-- | |||
| * @Date: 2021-03-01 10:35:21 | |||
| * @LastEditors: viletyy | |||
| * @LastEditTime: 2021-09-14 17:34:40 | |||
| * @LastEditTime: 2021-09-15 18:00:10 | |||
| * @FilePath: /forgeplus/app/docs/slate/source/includes/_users.md | |||
| --> | |||
| <h1 id='users'>Users</h1><h2 id='1ae74893b1'>获取当前登陆用户信息</h2> | |||
| @@ -1326,14 +1326,14 @@ Success — a happy kitten is an authenticated kitten! | |||
| <td>消息类型</td> | |||
| </tr> | |||
| <tr> | |||
| <td>recervers_login</td> | |||
| <td>receivers_login</td> | |||
| <td>array</td> | |||
| <td>需要发送消息的用户名数组</td> | |||
| </tr> | |||
| <tr> | |||
| <td>atmeable_type</td> | |||
| <td>string</td> | |||
| <td>atme消息对象,是从哪里@我的,比如评论:Journal</td> | |||
| <td>atme消息对象,是从哪里@我的,比如评论:Journal、易修:Issue、合并请求:PullRequest</td> | |||
| </tr> | |||
| <tr> | |||
| <td>atmeable_id</td> | |||