diff --git a/app/controllers/admins/message_templates_controller.rb b/app/controllers/admins/message_templates_controller.rb
new file mode 100644
index 000000000..23c94e784
--- /dev/null
+++ b/app/controllers/admins/message_templates_controller.rb
@@ -0,0 +1,44 @@
+class Admins::MessageTemplatesController < Admins::BaseController
+ before_action :get_template, only: [:edit, :update, :destroy]
+
+ def index
+ message_templates = MessageTemplate.group(:type).count.keys
+ @message_templates = kaminari_array_paginate(message_templates)
+ end
+
+ def edit
+ end
+
+ def update
+ if @message_template.update_attributes(message_template_params)
+ redirect_to admins_message_templates_path
+ flash[:success] = '消息模版更新成功'
+ else
+ redirect_to admins_message_templates_path
+ flash[:danger] = @message_template.errors.full_messages.join(",")
+ end
+ end
+
+ def init_data
+ if MessageTemplate.build_init_data
+ redirect_to admins_message_templates_path
+ flash[:success] = '消息模版初始化成功'
+ else
+ redirect_to admins_message_templates_path
+ flash[:danger] = '消息模版初始化失败'
+ end
+ end
+
+ private
+ def message_template_params
+ params.require(@message_template.type.split("::").join("_").underscore.to_sym).permit!
+ end
+
+ def get_template
+ @message_template = MessageTemplate.find_by(id: params[:id])
+ unless @message_template.present?
+ redirect_to admins_message_templates_path
+ flash[:danger] = "消息模版不存在"
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb
index 266d746d7..7b90e3108 100644
--- a/app/controllers/issues_controller.rb
+++ b/app/controllers/issues_controller.rb
@@ -111,6 +111,8 @@ 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)
+ SendTemplateMessageJob.perform_later('ProjectIssue', 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)
@@ -158,6 +160,7 @@ class IssuesController < ApplicationController
def update
last_token = @issue.token
last_status_id = @issue.status_id
+ @issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank?
if params[:issue_tag_ids].present? && !@issue&.issue_tags_relates.where(issue_tag_id: params[:issue_tag_ids]).exists?
@issue&.issue_tags_relates&.destroy_all
params[:issue_tag_ids].each do |tag|
@@ -202,6 +205,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 +270,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)
@@ -272,8 +290,12 @@ class IssuesController < ApplicationController
def clean
#批量删除,暂时只能删除未悬赏的
issue_ids = params[:ids]
- if issue_ids.present?
- if Issue.where(id: issue_ids, issue_type: "1").destroy_all
+ issues = Issue.where(id: issue_ids, issue_type: "1")
+ if issues.present?
+ issues.find_each do |i|
+ SendTemplateMessageJob.perform_later('IssueDeleted', current_user.id, i&.subject, i.assigned_to_id, i.author_id)
+ end
+ if issues.destroy_all
normal_status(0, "删除成功")
else
normal_status(-1, "删除失败")
@@ -307,7 +329,18 @@ class IssuesController < ApplicationController
if update_hash.blank?
normal_status(-1, "请选择批量更新内容")
elsif issues&.update(update_hash)
- issues.map{|i| i.create_journal_detail(false, [], [], current_user&.id) if i.previous_changes.present?}
+ issues.each do |i|
+ i.create_journal_detail(false, [], [], current_user&.id) if i.previous_changes.present?
+ previous_changes = i.previous_changes.slice(:status_id, :assigned_to_id, :tracker_id, :priority_id, :fixed_version_id, :done_ratio, :issue_tags_value, :branch_name)
+ if i.previous_changes[:start_date].present?
+ previous_changes.merge!(start_date: [i.previous_changes[:start_date][0].to_s, i.previous_changes[:start_date][1].to_s])
+ end
+ if i.previous_changes[:due_date].present?
+ previous_changes.merge!(due_date: [i.previous_changes[:due_date][0].to_s, i.previous_changes[:due_date][1].to_s])
+ end
+ SendTemplateMessageJob.perform_later('IssueChanged', current_user.id, i&.id, previous_changes)
+ SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, i&.id) if i.previous_changes[:assigned_to_id].present?
+ end
normal_status(0, "批量更新成功")
else
normal_status(-1, "批量更新失败")
@@ -321,6 +354,8 @@ class IssuesController < ApplicationController
@new_issue = @issue.dup
@new_issue.author_id = current_user.id
if @new_issue.save
+ SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @new_issue&.id)
+ SendTemplateMessageJob.perform_later('ProjectIssue', current_user.id, @new_issue&.id)
issue_tags = @issue.issue_tags.pluck(:id)
if issue_tags.present?
issue_tags.each do |tag|
@@ -398,22 +433,22 @@ class IssuesController < ApplicationController
def check_project_public
unless @project.is_public || @project.member?(current_user) || current_user.admin? || (@project.user_id == current_user.id)
- normal_status(-1, "您没有权限")
+ return render_forbidden
end
end
def set_issue
@issue = Issue.find_by_id(params[:id])
if @issue.blank?
- normal_status(-1, "标签不存在")
- elsif @issue.is_lock &&!(@project.member?(current_user) || current_user.admin?)
- normal_status(-1, "您没有权限")
+ return render_not_found
+ elsif !(@project.is_public || (current_user.present? && (@project.member?(current_user) || current_user&.admin? || (@project.user_id == current_user&.id))))
+ return render_forbidden
end
end
def check_issue_permission
unless @project.is_public || (current_user.present? && (@project.member?(current_user) || current_user&.admin? || (@project.user_id == current_user&.id)))
- normal_status(-1, "您没有权限")
+ return render_forbidden
end
end
diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb
index 7fb211e38..0af4898fc 100644
--- a/app/controllers/members_controller.rb
+++ b/app/controllers/members_controller.rb
@@ -9,6 +9,8 @@ class MembersController < ApplicationController
def create
interactor = Projects::AddMemberInteractor.call(@project.owner, @project, @user)
+ SendTemplateMessageJob.perform_later('ProjectJoined', current_user.id, @user.id, @project.id)
+ SendTemplateMessageJob.perform_later('ProjectMemberJoined', current_user.id, @user.id, @project.id)
render_response(interactor)
rescue Exception => e
uid_logger_error(e.message)
@@ -28,6 +30,8 @@ class MembersController < ApplicationController
def remove
interactor = Projects::DeleteMemberInteractor.call(@project.owner, @project, @user)
+ SendTemplateMessageJob.perform_later('ProjectLeft', current_user.id, @user.id, @project.id)
+ SendTemplateMessageJob.perform_later('ProjectMemberLeft', current_user.id, @user.id, @project.id)
render_response(interactor)
rescue Exception => e
uid_logger_error(e.message)
@@ -36,6 +40,7 @@ class MembersController < ApplicationController
def change_role
interactor = Projects::ChangeMemberRoleInteractor.call(@project.owner, @project, @user, params[:role])
+ SendTemplateMessageJob.perform_later('ProjectRole', current_user.id, @user.id, @project.id, message_role_name)
render_response(interactor)
rescue Exception => e
uid_logger_error(e.message)
@@ -66,4 +71,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
diff --git a/app/controllers/organizations/team_users_controller.rb b/app/controllers/organizations/team_users_controller.rb
index 43ed10708..c63005260 100644
--- a/app/controllers/organizations/team_users_controller.rb
+++ b/app/controllers/organizations/team_users_controller.rb
@@ -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
diff --git a/app/controllers/projects/project_units_controller.rb b/app/controllers/projects/project_units_controller.rb
index e21fa388f..e8b8f67a1 100644
--- a/app/controllers/projects/project_units_controller.rb
+++ b/app/controllers/projects/project_units_controller.rb
@@ -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
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 325d76ccb..78056beed 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -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)
diff --git a/app/controllers/pull_requests_controller.rb b/app/controllers/pull_requests_controller.rb
index 161810474..585230015 100644
--- a/app/controllers/pull_requests_controller.rb
+++ b/app/controllers/pull_requests_controller.rb
@@ -59,6 +59,8 @@ 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"], @gitea_pull_request[:body]["id"])
+ SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @pull_request&.id)
+ SendTemplateMessageJob.perform_later('ProjectPullRequest', current_user.id, @pull_request&.id)
render_ok
else
render_error("create pull request error: #{@gitea_pull_request[:status]}")
@@ -77,12 +79,13 @@ class PullRequestsController < ApplicationController
if params[:title].nil?
normal_status(-1, "名称不能为空")
elsif params[:issue_tag_ids].nil?
- normal_status(-1, "标签不能为空")
+ normal_status(-1, "标记不能为空")
else
ActiveRecord::Base.transaction do
begin
merge_params
+ @issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank?
if params[:issue_tag_ids].present? && !@issue&.issue_tags_relates.where(issue_tag_id: params[:issue_tag_ids]).exists?
@issue&.issue_tags_relates&.destroy_all
params[:issue_tag_ids].each do |tag|
@@ -116,6 +119,8 @@ class PullRequestsController < ApplicationController
normal_status(-1, e.message)
raise ActiveRecord::Rollback
end
+ 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?
end
end
@@ -125,7 +130,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 +174,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)
diff --git a/app/controllers/users/messages_controller.rb b/app/controllers/users/messages_controller.rb
new file mode 100644
index 000000000..035441ccb
--- /dev/null
+++ b/app/controllers/users/messages_controller.rb
@@ -0,0 +1,96 @@
+class Users::MessagesController < Users::BaseController
+ before_action :private_user_resources!
+ before_action :find_receivers, only: [:create]
+
+ def index
+ limit = params[:limit] || params[:per_page]
+ limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i
+ page = params[:page].to_i.zero? ? 1 : params[:page].to_i
+ result = Notice::Read::ListService.call(observed_user.id, message_type, message_status, page, limit)
+ return render_error if result.nil?
+ @data = result[2]
+ end
+
+ def create
+ return render_forbidden unless %w(atme).include?(params[:type])
+ case params[:type]
+ when 'atme'
+ Notice::Write::CreateAtmeForm.new(atme_params).validate!
+ 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
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+
+ def delete
+ return render_forbidden unless %w(atme).include?(params[:type])
+ result = Notice::Write::DeleteService.call(params[:ids], observed_user.id, message_type)
+ return render_error if result.nil?
+
+ render_ok
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+
+ def read
+ return render_forbidden unless %w(notification atme).include?(params[:type])
+ result = Notice::Write::ChangeStatusService.call(params[:ids], observed_user.id, message_type)
+ if result.nil?
+ render_error
+ else
+ render_ok
+ end
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+
+ private
+ def message_type
+ @message_type = begin
+ case params[:type]
+ when "notification" then 1
+ when "atme" then 2
+ else
+ -1
+ end
+ end
+ end
+
+ def message_status
+ @message_status = begin
+ case params[:status]
+ when "1" then 1
+ when "2" then 2
+ else
+ -1
+ end
+ end
+ end
+
+ def atme_params
+ params.permit(:atmeable_type, :atmeable_id, receivers_login: [])
+ end
+
+ def find_receivers
+ @receivers = User.where(login: params[:receivers_login])
+ return render_not_found if @receivers.size == 0
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index c9161a42a..7890ee864 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -91,6 +91,12 @@ class UsersController < ApplicationController
def get_user_info
begin
@user = current_user
+ begin
+ result = Notice::Read::CountService.call(current_user.id)
+ @message_unread_total = result.nil? ? 0 : result[2]["unread_notification"]
+ rescue
+ @message_unread_total = 0
+ end
# TODO 等消息上线再打开注释
#@tidding_count = unviewed_tiddings(current_user) if current_user.present?
rescue Exception => e
diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md
index bb4fd2b66..9d6b80927 100644
--- a/app/docs/slate/source/includes/_users.md
+++ b/app/docs/slate/source/includes/_users.md
@@ -1,7 +1,7 @@
# Users
@@ -47,6 +47,275 @@ await octokit.request('GET /api/users/me.json')
Success Data.
+## 用户消息列表
+获取用户消息列表
+
+> 示例:
+
+```shell
+curl -X GET http://localhost:3000/api/users/:login/messages.json
+```
+
+```javascript
+await octokit.request('GET /api/users/:login/messages.json')
+```
+
+### HTTP 请求
+`GET api/users/yystopf/messages.json`
+
+### 请求字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|type | string | 消息类型,不传为所有消息,notification为系统消息,atme为@我消息|
+|status | integer | 是否已读,不传为所有消息,1为未读,2为已读 |
+|limit | integer | 每页个数 |
+|page | integer | 页码 |
+
+### 返回字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|total_count | integer | 消息总数 |
+|type | string | 消息类型 |
+|unread_notification | integer | 未读系统通知数量 |
+|unread_atme | integer | 未读@我数量 |
+|messages.id | integer | 消息id |
+|messages.status | integer | 消息是否已读,1为未读,2为已读 |
+|messages.content | string | 消息内容 |
+|messages.notification_url | string | 消息跳转地址 |
+|messages.source | string | 消息来源 |
+|messages.timeago | string | 消息时间 |
+|messages.type | string | 消息类型,notification为系统消息,atme为@我消息|
+|sender | object | 消息发送者 |
+
+#### 消息来源source字段说明
+类型|说明
+--------- | -----------
+|IssueAssigned | 有新指派给我的易修 |
+|IssueAssignerExpire | 我负责的易修截止日期到达最后一天 |
+|IssueAtme | 在易修中@我 |
+|IssueChanged | 我创建或负责的易修状态变更 |
+|IssueCreatorExpire | 我创建的易修截止日期到达最后一天 |
+|IssueDeleted | 我创建或负责的易修删除 |
+|IssueJournal | 我创建或负责的易修有新的评论 |
+|LoginIpTip | 登录异常提示 |
+|OrganizationJoined | 账号被拉入组织 |
+|OrganizationLeft | 账号被移出组织 |
+|OrganizationRole | 账号组织权限变更 |
+|ProjectDeleted | 我关注的仓库被删除 |
+|ProjectFollowed | 我管理的仓库被关注 |
+|ProjectForked | 我管理的仓库被复刻 |
+|ProjectIssue | 我管理/关注的仓库有新的易修 |
+|ProjectJoined | 账号被拉入项目 |
+|ProjectLeft | 账号被移出项目 |
+|ProjectMemberJoined | 我管理的仓库有成员加入 |
+|ProjectMemberLeft | 我管理的仓库有成员移出 |
+|ProjectMilestone | 我管理的仓库有新的里程碑 |
+|ProjectPraised | 我管理的仓库被点赞 |
+|ProjectPullRequest | 我管理/关注的仓库有新的合并请求 |
+|ProjectRole | 账号仓库权限变更 |
+|ProjectSettingChanged | 我管理的仓库项目设置被更改 |
+|ProjectTransfer | 我关注的仓库被转移 |
+|ProjectVersion | 我关注的仓库有新的发行版 |
+|PullRequestAssigned | 有新指派给我的合并请求 |
+|PullReuqestAtme | 在合并请求中@我 |
+|PullRequestChanged | 我创建或负责的合并请求状态变更 |
+|PullRequestClosed | 我创建或负责的合并请求被关闭 |
+|PullRequestJournal | 我创建或负责的合并请求有新的评论 |
+|PullRequestMerged | 我创建或负责的合并请求被合并 |
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "total_count": 5,
+ "type": "",
+ "unread_notification": 3,
+ "unread_atme": 2,
+ "messages": [
+ {
+ "id": 1,
+ "status": 1,
+ "content": "Atme Message Content 1",
+ "notification_url": "http://www.baidu.com",
+ "source": "PullRequestAtme",
+ "time_ago": "1天前",
+ "type": "atme",
+ "sender": {
+ "id": 5,
+ "type": "User",
+ "name": "testforge2",
+ "login": "testforge2",
+ "image_url": "system/lets/letter_avatars/2/T/236_177_85/120.png"
+ }
+ },
+ {
+ "id": 2,
+ "status": 0,
+ "content": "Atme Message Content 2",
+ "notification_url": "http://www.baidu.com",
+ "source": "IssueAtme",
+ "time_ago": "1天前",
+ "type": "atme",
+ "sender": {
+ "id": 4,
+ "type": "User",
+ "name": "testforge1",
+ "login": "testforge1",
+ "image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png"
+ }
+ },
+ {
+ "id": 3,
+ "status": 1,
+ "content": "Notification Message Content 1",
+ "notification_url": "http://www.baidu.com",
+ "source": "IssueDelete",
+ "time_ago": "1天前",
+ "type": "notification"
+ },
+ {
+ "id": 4,
+ "status": 0,
+ "content": "Notification Message Content 2",
+ "notification_url": "http://www.baidu.com",
+ "source": "IssueChanged",
+ "time_ago": "1天前",
+ "type": "notification"
+ },
+ {
+ "id": 5,
+ "status": 0,
+ "content": "Notification Message Content 3",
+ "notification_url": "http://www.baidu.com",
+ "source": "ProjectJoined",
+ "time_ago": "1天前",
+ "type": "notification"
+ }
+ ]
+}
+```
+
+
+## 发送消息
+发送消息, 目前只支持atme
+
+> 示例:
+
+```shell
+curl -X POST http://localhost:3000/api/users/:login/messages.json
+```
+
+```javascript
+await octokit.request('POST /api/users/:login/messages.json')
+```
+
+### HTTP 请求
+`POST api/users/yystopf/messages.json`
+
+### 请求字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|type | string | 消息类型 |
+|receivers_login | array | 需要发送消息的用户名数组|
+|atmeable_type | string | atme消息对象,是从哪里@我的,比如评论:Journal、易修:Issue、合并请求:PullRequest |
+|atmeable_id | integer | atme消息对象id |
+
+> 请求的JSON示例:
+
+```json
+{
+ "type": "atme",
+ "receivers_login": ["yystopf", "testforge1"],
+ "atmeable_type": "Journal",
+ "atmeable_id": 67
+}
+```
+
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "success"
+}
+```
+
+
+## 阅读消息
+阅读消息
+
+> 示例:
+
+```shell
+curl -X POST http://localhost:3000/api/users/:login/messages/read.json
+```
+
+```javascript
+await octokit.request('POST /api/users/:login/messages/read.json')
+```
+
+### HTTP 请求
+`POST api/users/yystopf/messages/read.json`
+
+### 请求字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|type | string | 消息类型,不传为所有消息,notification为系统消息,atme为@我消息|
+|ids | array | 消息id数组,包含-1则把所有未读消息标记为已读|
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "success"
+}
+```
+
+
+## 删除消息
+删除消息
+
+> 示例:
+
+```shell
+curl -X DELETE http://localhost:3000/api/users/:login/messages.json
+```
+
+```javascript
+await octokit.request('DELETE /api/users/:login/messages.json')
+```
+
+### HTTP 请求
+`DELETE api/users/yystopf/messages.json`
+
+### 请求字段说明:
+参数 | 类型 | 字段说明
+--------- | ----------- | -----------
+|type | string | 消息类型,atme为@我消息|
+|ids | array | 消息id数组,包含-1则把所有消息删除|
+
+> 返回的JSON示例:
+
+```json
+{
+ "status": 0,
+ "message": "success"
+}
+```
+
+
+
## 更改用户信息
更改用户信息
diff --git a/app/forms/base_form.rb b/app/forms/base_form.rb
index c41a12993..71eaee174 100644
--- a/app/forms/base_form.rb
+++ b/app/forms/base_form.rb
@@ -2,11 +2,15 @@ class BaseForm
include ActiveModel::Model
def check_project_category(project_category_id)
- raise "project_category_id参数值无效." if project_category_id && !ProjectCategory.exists?(project_category_id)
+ unless project_category_id == ''
+ raise "project_category_id参数值无效." if project_category_id && !ProjectCategory.exists?(project_category_id)
+ end
end
def check_project_language(project_language_id)
- raise "project_language_id参数值无效." if project_language_id && !ProjectLanguage.exists?(project_language_id)
+ unless project_language_id == ''
+ raise "project_language_id参数值无效." if project_language_id && !ProjectLanguage.exists?(project_language_id)
+ end
end
def check_repository_name(user_id, repository_name)
diff --git a/app/forms/notice/write/create_atme_form.rb b/app/forms/notice/write/create_atme_form.rb
new file mode 100644
index 000000000..5ac3acc25
--- /dev/null
+++ b/app/forms/notice/write/create_atme_form.rb
@@ -0,0 +1,23 @@
+class Notice::Write::CreateAtmeForm
+ include ActiveModel::Model
+
+ attr_accessor :receivers_login, :atmeable_type, :atmeable_id
+
+ validate :check_receivers
+
+ def check_receivers
+ receivers_login.each do |login|
+ receiver = User.find_by(login: login) || User.find_by_id(login)
+ raise 'receivers_login值无效.' unless receiver.present?
+ end
+ end
+
+ def check_atmeable
+ begin
+ raise 'atmeable对象无效.' unless atmeable_type.constantize.find_by_id(atmeable_id).present?
+ rescue => exception
+ raise 'atmeable对象无效.'
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/app/forms/projects/update_form.rb b/app/forms/projects/update_form.rb
index 65810a820..0cd2c9459 100644
--- a/app/forms/projects/update_form.rb
+++ b/app/forms/projects/update_form.rb
@@ -1,6 +1,6 @@
class Projects::UpdateForm < BaseForm
attr_accessor :name, :description, :project_category_id, :project_language_id, :private
- validates :name, :description, :project_category_id, :project_language_id, presence: true
+ validates :name, presence: true
validates :name, length: { maximum: 50 }
validates :description, length: { maximum: 200 }
validate do
diff --git a/app/jobs/broadcast_mirror_repo_msg_job.rb b/app/jobs/broadcast_mirror_repo_msg_job.rb
index 6372ae2e3..4dee6894a 100644
--- a/app/jobs/broadcast_mirror_repo_msg_job.rb
+++ b/app/jobs/broadcast_mirror_repo_msg_job.rb
@@ -18,12 +18,30 @@ class BroadcastMirrorRepoMsgJob < ApplicationJob
id: project.id,
type: project.numerical_for_project_type
}
+ # 新增失败重试机制, 重试三次
+ result = broadcast(project, json_data)
+
+ if result == 0
+ count = 3
+ while count > 0
+ sleep 3.seconds
+ result = broadcast(project, json_data)
+ if result > 0
+ break
+ end
+ count -= 1
+ end
+ end
+ end
+
+ def broadcast(project, json_data)
puts "############ broadcast start.......... "
puts "############ broadcast channel_name: channel_room_#{project.id}"
puts "############ broadcast project data: #{json_data} "
cable_result = ActionCable.server.broadcast "channel_room_#{project.id}", project: json_data
- puts "############ broadcast result: #{cable_result == 1 ? 'successed' : 'failed'} "
+ puts "############ broadcast result: #{cable_result > 0 ? 'successed' : 'failed'} "
+ return cable_result
end
end
diff --git a/app/jobs/delay_expired_issue_job.rb b/app/jobs/delay_expired_issue_job.rb
new file mode 100644
index 000000000..4633a953d
--- /dev/null
+++ b/app/jobs/delay_expired_issue_job.rb
@@ -0,0 +1,11 @@
+class DelayExpiredIssueJob < ApplicationJob
+ queue_as :message
+
+ def perform
+ Issue.where(due_date: Date.today + 1.days).find_each do |issue|
+ SendTemplateMessageJob.perform_later('IssueAssignerExpire', issue.id)
+ SendTemplateMessageJob.perform_later('IssueCreatorExpire', issue.id)
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/app/jobs/migrate_remote_repository_job.rb b/app/jobs/migrate_remote_repository_job.rb
index 340e006ea..e54eaf2bc 100644
--- a/app/jobs/migrate_remote_repository_job.rb
+++ b/app/jobs/migrate_remote_repository_job.rb
@@ -16,5 +16,6 @@ class MigrateRemoteRepositoryJob < ApplicationJob
else
repo&.mirror&.failed!
end
+ BroadcastMirrorRepoMsgJob.perform_later(repo.id) unless repo&.mirror.waiting?
end
end
diff --git a/app/jobs/send_template_message_job.rb b/app/jobs/send_template_message_job.rb
new file mode 100644
index 000000000..2c463d705
--- /dev/null
+++ b/app/jobs/send_template_message_job.rb
@@ -0,0 +1,259 @@
+class SendTemplateMessageJob < ApplicationJob
+ queue_as :message
+
+ def perform(source, *args)
+ Rails.logger.info "SendTemplateMessageJob [args] #{args}"
+ case source
+ when 'FollowTip'
+ 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).where.not(id: operator&.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})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::IssueAssigned.get_email_message_content(receiver, operator, issue)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ 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 = receivers.where.not(id: operator&.id)
+ 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]).where.not(id: operator&.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]).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})
+ 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})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::OrganizationJoined.get_email_message_content(receiver, organization)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ 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})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::OrganizationLeft.get_email_message_content(receiver, organization)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ 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})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::OrganizationRole.get_email_message_content(receiver, organization, role)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectIssue'
+ 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? && issue&.project.present?
+ managers = issue&.project&.all_managers.where.not(id: operator&.id)
+ followers = User.none # TODO
+ receivers_string, content, notification_url = MessageTemplate::ProjectIssue.get_message_content(managers, followers, operator, issue)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_id: issue.id})
+ managers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectIssue.get_email_message_content(receiver, true, operator, issue)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ followers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectIssue.get_email_message_content(receiver, false, operator, issue)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectJoined'
+ operator_id, user_id, project_id = args[0], args[1], args[2]
+ operator = User.find_by_id(operator_id)
+ user = User.find_by_id(user_id)
+ project = Project.find_by_id(project_id)
+ return unless operator.present? && user.present? && project.present?
+ receivers = User.where(id: user.id).where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::ProjectJoined.get_message_content(receivers, project)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, user_id: user.id, project_id: project.id})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectJoined.get_email_message_content(receiver, project)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectLeft'
+ operator_id, user_id, project_id = args[0], args[1], args[2]
+ operator = User.find_by_id(operator_id)
+ user = User.find_by_id(user_id)
+ project = Project.find_by_id(project_id)
+ return unless operator.present? && user.present? && project.present?
+ receivers = User.where(id: user.id).where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::ProjectLeft.get_message_content(receivers, project)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, user_id: user.id, project_id: project.id})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectLeft.get_email_message_content(receiver, project)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectMemberJoined'
+ operator_id, user_id, project_id = args[0], args[1], args[2]
+ operator = User.find_by_id(operator_id)
+ user = User.find_by_id(user_id)
+ project = Project.find_by_id(project_id)
+ return unless operator.present? && user.present? && project.present?
+ receivers = project&.all_managers.where.not(id: [operator&.id, user&.id])
+ receivers_string, content, notification_url = MessageTemplate::ProjectMemberJoined.get_message_content(receivers, user, project)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, user_id: user.id, project_id: project.id})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectMemberJoined.get_email_message_content(receiver, user, project)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectMemberLeft'
+ operator_id, user_id, project_id = args[0], args[1], args[2]
+ operator = User.find_by_id(operator_id)
+ user = User.find_by_id(user_id)
+ project = Project.find_by_id(project_id)
+ return unless operator.present? && user.present? && project.present?
+ receivers = project&.all_managers.where.not(id: [operator&.id, user&.id])
+ receivers_string, content, notification_url = MessageTemplate::ProjectMemberLeft.get_message_content(receivers, user, project)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, user_id: user.id, project_id: project.id})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectMemberLeft.get_email_message_content(receiver, user, project)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectPullRequest'
+ 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? && pull_request&.project.present?
+ managers = pull_request&.project&.all_managers.where.not(id: operator&.id)
+ followers = User.none # TODO
+ receivers_string, content, notification_url = MessageTemplate::ProjectPullRequest.get_message_content(managers, followers, operator, pull_request)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, pull_request_id: pull_request.id})
+ managers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectPullRequest.get_email_message_content(receiver, true, operator, pull_request)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ followers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectPullRequest.get_email_message_content(receiver, false, operator, pull_request)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ when 'ProjectRole'
+ operator_id, user_id, project_id, role = args[0], args[1], args[2], args[3]
+ operator = User.find_by_id(operator_id)
+ user = User.find_by_id(user_id)
+ project = Project.find_by_id(project_id)
+ return unless operator.present? && user.present? && project.present?
+ receivers = User.where(id: user.id).where.not(id: operator&.id)
+ receivers_string, content, notification_url = MessageTemplate::ProjectRole.get_message_content(receivers, project, role)
+ Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, user_id: user.id, project_id: project.id, role: role})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::ProjectRole.get_email_message_content(receivers, project, role)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ 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.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})
+ 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)
+ end
+ 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)
+ issue = Issue.find_by_id(pull_request&.issue_id)
+ return unless operator.present? && pull_request.present? && issue.present?
+ receivers = User.where(id: issue&.assigned_to_id).where.not(id: operator&.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})
+ receivers.find_each do |receiver|
+ receivers_email_string, email_title, email_content = MessageTemplate::PullRequestAssigned.get_email_message_content(receiver, operator, pull_request)
+ Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
+ end
+ 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 = receivers.where.not(id: operator&.id)
+ 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)
+ issue = Issue.find_by_id(pull_request&.issue_id)
+ return unless operator.present? && pull_request.present? && issue.present?
+ 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})
+ 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]).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})
+ 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]).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})
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/jobs/sync_mirrored_repository_job.rb b/app/jobs/sync_mirrored_repository_job.rb
index a1408153f..63abbfd80 100644
--- a/app/jobs/sync_mirrored_repository_job.rb
+++ b/app/jobs/sync_mirrored_repository_job.rb
@@ -26,6 +26,7 @@ class SyncMirroredRepositoryJob < ApplicationJob
result = Gitea::Repository::SyncMirroredService.call(repo.owner.login,
repo.identifier, token: user.gitea_token)
repo&.mirror.set_status! if result[:status] === 200
+ BroadcastMirrorRepoMsgJob.perform_later(repo.id) unless repo&.mirror.waiting?
end
end
diff --git a/app/libs/notice.rb b/app/libs/notice.rb
new file mode 100644
index 000000000..93d5cb42d
--- /dev/null
+++ b/app/libs/notice.rb
@@ -0,0 +1,21 @@
+module Notice
+ class << self
+ def notice_config
+ notice_config = {}
+
+ begin
+ config = Rails.application.config_for(:configuration).symbolize_keys!
+ notice_config = config[:notice].symbolize_keys!
+ raise 'notice config missing' if notice_config.blank?
+ rescue => exception
+ raise ex if Rails.env.production?
+
+ puts %Q{\033[33m [warning] gitea config or configuration.yml missing,
+ please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m}
+ notice_config = {}
+ end
+
+ notice_config
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/models/message_template.rb b/app/models/message_template.rb
new file mode 100644
index 000000000..2c8c96869
--- /dev/null
+++ b/app/models/message_template.rb
@@ -0,0 +1,99 @@
+# == 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 < ApplicationRecord
+
+ def self.build_init_data
+ self.create(type: 'MessageTemplate::FollowedTip', sys_notice: '{nickname} 关注了你', notification_url: '{baseurl}/{login}')
+ email_html = File.read("#{email_template_html_dir}/issue_assigned.html")
+ 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}')
+ 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: '')
+ 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}')
+ 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}')
+ email_html = File.read("#{email_template_html_dir}/project_issue.html")
+ self.create(type: 'MessageTemplate::ProjectIssue', sys_notice: '{nickname1}在 {nickname2}/{repository} 新建易修:{title}', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: '{nickname1} 在 {nickname2}/{repository} 新建了一个易修')
+ email_html = File.read("#{email_template_html_dir}/project_joined.html")
+ self.create(type: 'MessageTemplate::ProjectJoined', sys_notice: '你已加入 {repository} 项目', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: '你已加入 {repository} 项目')
+ email_html = File.read("#{email_template_html_dir}/project_left.html")
+ self.create(type: 'MessageTemplate::ProjectLeft', sys_notice: '你已被移出 {repository} 项目', notification_url: '', email: email_html, email_title: '你已被移出 {repository} 项目')
+ email_html = File.read("#{email_template_html_dir}/project_member_joined.html")
+ self.create(type: 'MessageTemplate::ProjectMemberJoined', sys_notice: '{nickname1} 已加入项目 {nickname2}/{repository}', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: '{nickname1} 已加入项目 {nickname2}/{repository}')
+ email_html = File.read("#{email_template_html_dir}/project_member_left.html")
+ self.create(type: 'MessageTemplate::ProjectMemberLeft', sys_notice: '{nickname1} 已被移出项目 {nickname2}/{repository}', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: '{nickname1} 已被移出项目 {nickname2}/{repository}')
+ 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}')
+ 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')
+ end
+
+ def self.sys_notice
+ self.last&.sys_notice
+ end
+
+ def self.email
+ self.last&.email
+ end
+
+ def self.email_title
+ self.last&.email_title
+ end
+
+ def self.notification_url
+ self.last&.notification_url.gsub('{baseurl}', base_url)
+ end
+
+ def self.base_url
+ Rails.application.config_for(:configuration)['platform_url']
+ end
+
+ def self.receivers_string(receivers)
+ receivers.pluck(:id).join(",")
+ end
+
+ def self.receivers_email_string(receivers)
+ receivers.pluck(:mail).join(",")
+ end
+
+ def self.email_template_html_dir
+ "#{Rails.root}/public/message_template"
+ end
+
+ def simple_type
+ self.type.split("::")[-1]
+ end
+end
diff --git a/app/models/message_template/followed_tip.rb b/app/models/message_template/followed_tip.rb
new file mode 100644
index 000000000..6231db595
--- /dev/null
+++ b/app/models/message_template/followed_tip.rb
@@ -0,0 +1,24 @@
+# == 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::FollowedTip < MessageTemplate
+
+ # MessageTemplate::FollowedTip.get_message_content(User.where(login: 'yystopf'), User.last)
+ def self.get_message_content(receivers, followeder)
+ return receivers_string(receivers), sys_notice.gsub('{nickname}', followeder&.real_name), notification_url.gsub('{login}', followeder.login)
+ rescue
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/issue_assigned.rb b/app/models/message_template/issue_assigned.rb
new file mode 100644
index 000000000..91daa8dcc
--- /dev/null
+++ b/app/models/message_template/issue_assigned.rb
@@ -0,0 +1,54 @@
+# == 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::IssueAssigned < MessageTemplate
+
+ # MessageTemplate::IssueAssigned.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('{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&.id.to_s)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::IssueAssigned.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, operator, issue)
+ project = issue&.project
+ owner = project&.owner
+ title = email_title
+ title.gsub!('{nickname1}', operator&.real_name)
+ title.gsub!('{nickname2}', owner&.real_name)
+ title.gsub!('{repository}', project&.name)
+ 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}', issue&.subject)
+ content.gsub!('{id}', issue&.id.to_s)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::IssueAssigned.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/issue_assigner_expire.rb b/app/models/message_template/issue_assigner_expire.rb
new file mode 100644
index 000000000..405d44bb4
--- /dev/null
+++ b/app/models/message_template/issue_assigner_expire.rb
@@ -0,0 +1,29 @@
+# == 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::IssueAssignerExpire < MessageTemplate
+
+ # MessageTemplate::IssueAssignerExpire.get_message_content(User.where(login: 'yystopf'), Issue.last)
+ def self.get_message_content(receivers, issue)
+ project = issue&.project
+ owner = project&.owner
+ content = sys_notice.gsub('{title}', issue&.subject)
+ 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::IssueAssignerExpire.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/issue_atme.rb b/app/models/message_template/issue_atme.rb
new file mode 100644
index 000000000..d9dfd1957
--- /dev/null
+++ b/app/models/message_template/issue_atme.rb
@@ -0,0 +1,29 @@
+# == 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::IssueAtme < MessageTemplate
+
+ # MessageTemplate::IssueAtme.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&.real_name).gsub('{title}', issue&.subject)
+ 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}")
+ return 0, '', ''
+ end
+end
diff --git a/app/models/message_template/issue_changed.rb b/app/models/message_template/issue_changed.rb
new file mode 100644
index 000000000..6b9e79763
--- /dev/null
+++ b/app/models/message_template/issue_changed.rb
@@ -0,0 +1,183 @@
+# == 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::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)
+ return '', '', '' if change_params.blank?
+ project = issue&.project
+ owner = project&.owner
+ content = MessageTemplate::IssueChanged.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&.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 receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::IssueAssigned.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/issue_creator_expire.rb b/app/models/message_template/issue_creator_expire.rb
new file mode 100644
index 000000000..38ef2fe29
--- /dev/null
+++ b/app/models/message_template/issue_creator_expire.rb
@@ -0,0 +1,29 @@
+# == 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::IssueCreatorExpire < MessageTemplate
+
+ # MessageTemplate::IssueCreatorExpire.get_message_content(User.where(login: 'yystopf'), Issue.last)
+ def self.get_message_content(receivers, issue)
+ project = issue&.project
+ owner = project&.owner
+ content = sys_notice.gsub('{title}', issue&.subject)
+ 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::IssueAssignerExpire.get_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
new file mode 100644
index 000000000..8c4145716
--- /dev/null
+++ b/app/models/message_template/issue_deleted.rb
@@ -0,0 +1,26 @@
+# == 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::IssueDeleted < MessageTemplate
+
+ # 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&.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}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/issue_journal.rb b/app/models/message_template/issue_journal.rb
new file mode 100644
index 000000000..0b3851475
--- /dev/null
+++ b/app/models/message_template/issue_journal.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我创建或负责的易修有新的评论
+class MessageTemplate::IssueJournal < MessageTemplate
+
+ # MessageTemplate::IssueJournal.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::IssueJournal.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/login_ip_tip.rb b/app/models/message_template/login_ip_tip.rb
new file mode 100644
index 000000000..5c7caa936
--- /dev/null
+++ b/app/models/message_template/login_ip_tip.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 登录异常提示
+class MessageTemplate::LoginIpTip < MessageTemplate
+
+ # MessageTemplate::LoginIpTip.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::LoginIpTip.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/organization_joined.rb b/app/models/message_template/organization_joined.rb
new file mode 100644
index 000000000..9045ac424
--- /dev/null
+++ b/app/models/message_template/organization_joined.rb
@@ -0,0 +1,42 @@
+# == 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::OrganizationJoined < MessageTemplate
+
+ # MessageTemplate::OrganizationJoined.get_message_content(User.where(login: 'yystopf'), Organization.last)
+ def self.get_message_content(receivers, organization)
+ content = sys_notice.gsub('{organization}', organization&.real_name)
+ url = notification_url.gsub('{login}', organization&.name)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::OrganizationJoined.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, organization)
+ title = email_title
+ title.gsub!('{organization}', organization&.real_name)
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login}', organization&.login)
+ content.gsub!('{organization}', organization&.real_name)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::OrganizationJoined.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/organization_left.rb b/app/models/message_template/organization_left.rb
new file mode 100644
index 000000000..edf8b32ec
--- /dev/null
+++ b/app/models/message_template/organization_left.rb
@@ -0,0 +1,42 @@
+# == 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::OrganizationLeft < MessageTemplate
+
+ # MessageTemplate::OrganizationLeft.get_message_content(User.where(login: 'yystopf'), Organization.last)
+ def self.get_message_content(receivers, organization)
+ content = sys_notice.gsub('{organization}', organization&.real_name)
+ url = notification_url.gsub('{login}', organization&.name)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::OrganizationLeft.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, organization)
+ title = email_title
+ title.gsub!('{organization}', organization&.real_name)
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login}', organization&.login)
+ content.gsub!('{organization}', organization&.real_name)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::OrganizationLeft.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/organization_role.rb b/app/models/message_template/organization_role.rb
new file mode 100644
index 000000000..4bc96a63e
--- /dev/null
+++ b/app/models/message_template/organization_role.rb
@@ -0,0 +1,44 @@
+# == 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::OrganizationRole < MessageTemplate
+
+ # MessageTemplate::OrganizationRole.get_message_content(User.where(login: 'yystopf'), Organization.last, '管理员')
+ def self.get_message_content(receivers, organization, role)
+ content = sys_notice.gsub('{organization}', organization&.real_name).gsub('{role}', role)
+ url = notification_url.gsub('{login}', organization&.login)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::OrganizationRole.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, organization, role)
+ title = email_title
+ title.gsub!('{organization}', organization&.real_name)
+ title.gsub!('{role}', role)
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login}', organization&.login)
+ content.gsub!('{organization}', organization&.real_name)
+ content.gsub!('{role}', role)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::OrganizationRole.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_deleted.rb b/app/models/message_template/project_deleted.rb
new file mode 100644
index 000000000..aa45e818e
--- /dev/null
+++ b/app/models/message_template/project_deleted.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我关注的仓库被删除
+class MessageTemplate::ProjectDeleted < MessageTemplate
+
+ # MessageTemplate::ProjectDeleted.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectDeleted.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_followed.rb b/app/models/message_template/project_followed.rb
new file mode 100644
index 000000000..e9dd9a2a8
--- /dev/null
+++ b/app/models/message_template/project_followed.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我管理的仓库被关注
+class MessageTemplate::ProjectFollowed < MessageTemplate
+
+ # MessageTemplate::ProjectFollowed.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectFollowed.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_forked.rb b/app/models/message_template/project_forked.rb
new file mode 100644
index 000000000..7cd17222d
--- /dev/null
+++ b/app/models/message_template/project_forked.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我管理的仓库被复刻
+class MessageTemplate::ProjectForked < MessageTemplate
+
+ # MessageTemplate::ProjectForked.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectForked.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_issue.rb b/app/models/message_template/project_issue.rb
new file mode 100644
index 000000000..8e319bf3b
--- /dev/null
+++ b/app/models/message_template/project_issue.rb
@@ -0,0 +1,57 @@
+# == 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)
+#
+
+# TODO 我管理/关注的仓库有新的易修
+class MessageTemplate::ProjectIssue < MessageTemplate
+
+ # MessageTemplate::ProjectIssue.get_message_content(User.where(login: 'yystopf'), User.where(login: 'forgetest1'), User.last, Issue.last)
+ def self.get_message_content(managers, followers, operator, issue)
+ project = issue&.project
+ owner = project&.owner
+ receivers = managers + followers
+ 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&.id.to_s)
+
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectIssue.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, is_manager, operator, issue)
+ project = issue&.project
+ owner = project&.owner
+ title = email_title
+ title.gsub!('{nickname1}', operator&.real_name)
+ title.gsub!('{nickname2}', owner&.real_name)
+ title.gsub!('{repository}', project&.name)
+
+ 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!('{nickname2}', owner&.real_name)
+ content.gsub!('{repository}', project&.name)
+ content.gsub!('{login2}', owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{id}', issue&.id.to_s)
+ content.gsub!('{title}', issue&.subject)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectIssue.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_joined.rb b/app/models/message_template/project_joined.rb
new file mode 100644
index 000000000..3ff1d23d7
--- /dev/null
+++ b/app/models/message_template/project_joined.rb
@@ -0,0 +1,45 @@
+# == 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::ProjectJoined < MessageTemplate
+
+ # MessageTemplate::ProjectJoined.get_message_content(User.where(login: 'yystopf'), Project.last)
+ def self.get_message_content(receivers, project)
+ content = sys_notice.gsub('{repository}', project&.name)
+ url = notification_url.gsub('{owner}', project&.owner&.login).gsub('{identifier}', project&.identifier)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectJoined.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, project)
+ title = email_title
+ title.gsub!('{repository}', project&.name)
+
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login}', project&.owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{nickname}', project&.owner&.real_name)
+ content.gsub!('{repository}', project&.name)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectJoined.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_left.rb b/app/models/message_template/project_left.rb
new file mode 100644
index 000000000..3244e59a0
--- /dev/null
+++ b/app/models/message_template/project_left.rb
@@ -0,0 +1,45 @@
+# == 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::ProjectLeft < MessageTemplate
+
+ # MessageTemplate::ProjectLeft.get_message_content(User.where(login: 'yystopf'), Project.last)
+ def self.get_message_content(receivers, project)
+ content = sys_notice.gsub('{repository}', project&.name)
+ url = notification_url.gsub('{owner}', project&.owner&.login).gsub('{identifier}', project&.identifier)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectLeft.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, project)
+ title = email_title
+ title.gsub!('{repository}', project&.name)
+
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login}', project&.owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{nickname}', project&.owner&.real_name)
+ content.gsub!('{repository}', project&.name)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectLeft.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_member_joined.rb b/app/models/message_template/project_member_joined.rb
new file mode 100644
index 000000000..e2ab7d610
--- /dev/null
+++ b/app/models/message_template/project_member_joined.rb
@@ -0,0 +1,49 @@
+# == 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::ProjectMemberJoined < MessageTemplate
+
+ # MessageTemplate::ProjectMemberJoined.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers, user, project)
+ content = sys_notice.gsub('{nickname1}', user&.real_name).gsub('{nickname2}', project&.owner&.real_name).gsub('{repository}', project&.name)
+ url = notification_url.gsub('{owner}', project&.owner&.login).gsub('{identifier}', project&.identifier)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectMemberJoined.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, user, project)
+ title = email_title
+ title.gsub!('{nickname1}', user&.real_name)
+ title.gsub!('{nickname2}', project&.owner&.real_name)
+ title.gsub!('{repository}', project&.name)
+
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login1}', user&.login)
+ content.gsub!('{login2}', project&.owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{nickname1}', user&.real_name)
+ content.gsub!('{nickname2}', project&.owner&.real_name)
+ content.gsub!('{repository}', project&.name)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectMemberJoined.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_member_left.rb b/app/models/message_template/project_member_left.rb
new file mode 100644
index 000000000..a7d9911d6
--- /dev/null
+++ b/app/models/message_template/project_member_left.rb
@@ -0,0 +1,49 @@
+# == 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::ProjectMemberLeft < MessageTemplate
+
+ # MessageTemplate::ProjectMemberLeft.get_message_content(User.where(login: 'yystopf'), User.last, Project.last)
+ def self.get_message_content(receivers, user, project)
+ content = sys_notice.gsub('{nickname1}', user&.real_name).gsub('{nickname2}', project&.owner&.real_name).gsub('{repository}', project&.name)
+ url = notification_url.gsub('{owner}', project&.owner&.login).gsub('{identifier}', project&.identifier)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectMemberLeft.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, user, project)
+ title = email_title
+ title.gsub!('{nickname1}', user&.real_name)
+ title.gsub!('{nickname2}', project&.owner&.real_name)
+ title.gsub!('{repository}', project&.name)
+
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login1}', user&.login)
+ content.gsub!('{login2}', project&.owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{nickname1}', user&.real_name)
+ content.gsub!('{nickname2}', project&.owner&.real_name)
+ content.gsub!('{repository}', project&.name)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectMemberLeft.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_milestone.rb b/app/models/message_template/project_milestone.rb
new file mode 100644
index 000000000..14f992cdd
--- /dev/null
+++ b/app/models/message_template/project_milestone.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我管理的仓库有新的里程碑
+class MessageTemplate::ProjectMilestone < MessageTemplate
+
+ # MessageTemplate::ProjectMilestone.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectMilestone.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_praised.rb b/app/models/message_template/project_praised.rb
new file mode 100644
index 000000000..e6acee6f5
--- /dev/null
+++ b/app/models/message_template/project_praised.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我管理的仓库被点赞
+class MessageTemplate::ProjectPraised < MessageTemplate
+
+ # MessageTemplate::ProjectPraised.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectPraised.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_pull_request.rb b/app/models/message_template/project_pull_request.rb
new file mode 100644
index 000000000..704936f54
--- /dev/null
+++ b/app/models/message_template/project_pull_request.rb
@@ -0,0 +1,57 @@
+# == 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)
+#
+
+# TODO 我管理/关注的仓库有新的合并请求
+class MessageTemplate::ProjectPullRequest < MessageTemplate
+
+ # MessageTemplate::ProjectPullRequest.get_message_content(User.where(login: 'yystopf'), User.where(login: 'testforge2'), User.last, PullRequest.last)
+ def self.get_message_content(managers, followers, operator, pull_request)
+ project = pull_request&.project
+ owner = project&.owner
+ receivers = managers + followers
+ content = sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).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)
+
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectPullRequest.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, is_manager, operator, pull_request)
+ project = pull_request&.project
+ owner = project&.owner
+ title = email_title
+ title.gsub!('{nickname1}', operator&.real_name)
+ title.gsub!('{nickname2}', owner&.real_name)
+ title.gsub!('{repository}', project&.name)
+
+ 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!('{nickname2}', owner&.real_name)
+ content.gsub!('{repository}', project&.name)
+ content.gsub!('{login2}', owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{id}', pull_request&.id.to_s)
+ content.gsub!('{title}', pull_request&.title)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectPullRequest.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
new file mode 100644
index 000000000..4db81ab47
--- /dev/null
+++ b/app/models/message_template/project_role.rb
@@ -0,0 +1,45 @@
+# == 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::ProjectRole < MessageTemplate
+
+ # MessageTemplate::ProjectRole.get_message_content(User.where(login: 'yystopf'), Project.last, '管理员')
+ def self.get_message_content(receivers, project, role)
+ content = sys_notice.gsub('{repository}', project&.name).gsub('{role}', role)
+ url = notification_url.gsub('{owner}', project&.owner&.login).gsub('{identifier}', project&.identifier)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectRole.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receivers, project, role)
+ title = email_title
+ title.gsub!('{repository}', project&.name)
+ title.gsub!('{role}', role)
+ content = email
+ content.gsub!('{receiver}', receiver&.real_name)
+ content.gsub!('{baseurl}', base_url)
+ content.gsub!('{login}', project&.owner&.login)
+ content.gsub!('{identifier}', project&.identifier)
+ content.gsub!('{repository}', project&.name)
+ content.gsub!('{role}', role)
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectRole.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_setting_changed.rb b/app/models/message_template/project_setting_changed.rb
new file mode 100644
index 000000000..3a8df5ffc
--- /dev/null
+++ b/app/models/message_template/project_setting_changed.rb
@@ -0,0 +1,277 @@
+# == 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::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&.real_name).gsub('{nickname2}', owner&.real_name).gsub('{repository}', project&.name)
+ url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier)
+ change_count = change_params.keys.size
+ # 项目名称更改
+ if change_params[:name].present?
+ if change_count > 1
+ content.sub!('{ifname}', '
')
+ else
+ content.sub!('{ifname}', '')
+ end
+ content.sub!('{endname}', '')
+ content.gsub!('{name}', change_params[:name][1])
+ else
+ content.gsub!(/({ifname})(.*)({endname})/, '')
+ end
+ # 项目简介更改
+ if change_params[:description].present?
+ if change_params[:description][1].blank?
+ if change_count > 1
+ content.gsub!(/({ifdescription})(.*)({enddescription})/, '
删除了项目简介')
+ else
+ content.gsub!(/({ifdescription})(.*)({enddescription})/, '删除了项目简介')
+ end
+ else
+ if change_count > 1
+ content.sub!('{ifdescription}', '
')
+ else
+ content.sub!('{ifdescription}', '')
+ end
+ content.sub!('{enddescription}', '')
+ content.gsub!('{description}', change_params[:description][1])
+ end
+ else
+ content.gsub!(/({ifdescription})(.*)({enddescription})/, '')
+ end
+ # 项目类别更改
+ if change_params[:project_category_id].present?
+ category = ProjectCategory.find_by_id(change_params[:project_category_id][1])
+ if category.present?
+ if change_count > 1
+ content.sub!('{ifcategory}', '
')
+ else
+ content.sub!('{ifcategory}', '')
+ end
+ content.sub!('{endcategory}', '')
+ content.gsub!('{category}', category&.name)
+ else
+ if change_count > 1
+ content.gsub!(/({ifcategory})(.*)({endcategory})/, '
删除了项目类别')
+ else
+ content.gsub!(/({ifcategory})(.*)({endcategory})/, '删除了项目类别')
+ end
+ end
+ else
+ content.gsub!(/({ifcategory})(.*)({endcategory})/, '')
+ end
+ # 项目语言更改
+ if change_params[:project_language_id].present?
+ language = ProjectLanguage.find_by_id(change_params[:project_language_id][1])
+ if language.present?
+ if change_count > 1
+ content.sub!('{iflanguage}', '
')
+ else
+ content.sub!('{iflanguage}', '')
+ end
+ content.sub!('{endlanguage}', '')
+ content.gsub!('{language}', language&.name)
+ else
+ if change_count > 1
+ content.gsub!(/({iflanguage})(.*)({endlanguage})/, '
删除了项目语言')
+ else
+ content.gsub!(/({iflanguage})(.*)({endlanguage})/, '删除了项目语言')
+ end
+ end
+ else
+ content.gsub!(/({iflanguage})(.*)({endlanguage})/, '')
+ end
+ # 项目公私有更改
+ if change_params[:is_public].present?
+ permission = change_params[:is_public][1] ? '公有' : '私有'
+ if change_count > 1
+ content.sub!('{ifpermission}', '
')
+ else
+ content.sub!('{ifpermission}', '')
+ end
+ content.sub!('{endpermission}', '')
+ content.gsub!('{permission}', permission)
+ else
+ content.gsub!(/({ifpermission})(.*)({endpermission})/, '')
+ end
+ # 项目导航更改
+ if change_params[:navbar].present?
+ unit_types = project.project_units.order(unit_type: :asc).pluck(:unit_type)
+ unit_types.delete('code')
+ unit_types.unshift('代码库')
+ unit_types.unshift('主页')
+ unit_types.append('动态')
+ navbar = unit_types.join(',')
+ navbar.gsub!('issues', '易修')
+ navbar.gsub!('pulls', '合并请求')
+ navbar.gsub!('wiki', 'Wiki')
+ navbar.gsub!('devops', '工作流')
+ navbar.gsub!('versions', '里程碑')
+ navbar.gsub!('resources', '资源库')
+ if change_count > 1
+ content.sub!('{ifnavbar}', '
')
+ else
+ content.sub!('{ifnavbar}', '')
+ end
+ content.sub!('{endnavbar}', '')
+ content.gsub!('{navbar}', navbar)
+ else
+ content.gsub!(/({ifnavbar})(.*)({endnavbar})/, '')
+ end
+
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectSettingChanged.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, operator, project, change_params)
+ return '', '', '' if change_params.blank?
+ owner = project&.owner
+ title = email_title
+ title.gsub!('{nickname2}', owner&.real_name)
+ title.gsub!('{repository}', project&.name)
+
+ 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)
+ change_count = change_params.keys.size
+ # 项目名称更改
+ if change_params[:name].present?
+ if change_count > 1
+ content.sub!('{ifname}', '
')
+ else
+ content.sub!('{ifname}', '')
+ end
+ content.sub!('{endname}', '')
+ content.gsub!('{name}', change_params[:name][1])
+ else
+ content.gsub!(/({ifname})(.*)({endname})/, '')
+ end
+ # 项目简介更改
+ if change_params[:description].present?
+ if change_params[:description][1].blank?
+ if change_count > 1
+ content.gsub!(/({ifdescription})(.*)({enddescription})/, '
删除了项目简介')
+ else
+ content.gsub!(/({ifdescription})(.*)({enddescription})/, '删除了项目简介')
+ end
+ else
+ if change_count > 1
+ content.sub!('{ifdescription}', '
')
+ else
+ content.sub!('{ifdescription}', '')
+ end
+ content.sub!('{enddescription}', '')
+ content.gsub!('{description}', change_params[:description][1])
+ end
+ else
+ content.gsub!(/({ifdescription})(.*)({enddescription})/, '')
+ end
+ # 项目类别更改
+ if change_params[:project_category_id].present?
+ category = ProjectCategory.find_by_id(change_params[:project_category_id][1])
+ if category.present?
+ if change_count > 1
+ content.sub!('{ifcategory}', '
')
+ else
+ content.sub!('{ifcategory}', '')
+ end
+ content.sub!('{endcategory}', '')
+ content.gsub!('{category}', category&.name)
+ else
+ if change_count > 1
+ content.gsub!(/({ifcategory})(.*)({endcategory})/, '
删除了项目类别')
+ else
+ content.gsub!(/({ifcategory})(.*)({endcategory})/, '删除了项目类别')
+ end
+ end
+ else
+ content.gsub!(/({ifcategory})(.*)({endcategory})/, '')
+ end
+ # 项目语言更改
+ if change_params[:project_language_id].present?
+ language = ProjectLanguage.find_by_id(change_params[:project_language_id][1])
+ if language.present?
+ if change_count > 1
+ content.sub!('{iflanguage}', '
')
+ else
+ content.sub!('{iflanguage}', '')
+ end
+ content.sub!('{endlanguage}', '')
+ content.gsub!('{language}', language&.name)
+ else
+ if change_count > 1
+ content.gsub!(/({iflanguage})(.*)({endlanguage})/, '
删除了项目语言')
+ else
+ content.gsub!(/({iflanguage})(.*)({endlanguage})/, '删除了项目语言')
+ end
+ end
+ else
+ content.gsub!(/({iflanguage})(.*)({endlanguage})/, '')
+ end
+ # 项目公私有更改
+ if change_params[:is_public].present?
+ permission = change_params[:is_public][1] ? '公有' : '私有'
+ if change_count > 1
+ content.sub!('{ifpermission}', '
')
+ else
+ content.sub!('{ifpermission}', '')
+ end
+ content.sub!('{endpermission}', '')
+ content.gsub!('{permission}', permission)
+ else
+ content.gsub!(/({ifpermission})(.*)({endpermission})/, '')
+ end
+ # 项目导航更改
+ if change_params[:navbar].present?
+ unit_types = project.project_units.order(unit_type: :asc).pluck(:unit_type)
+ unit_types.delete('code')
+ unit_types.unshift('代码库')
+ unit_types.unshift('主页')
+ unit_types.append('动态')
+ navbar = unit_types.join(',')
+ navbar.gsub!('issues', '易修')
+ navbar.gsub!('pulls', '合并请求')
+ navbar.gsub!('wiki', 'Wiki')
+ navbar.gsub!('devops', '工作流')
+ navbar.gsub!('versions', '里程碑')
+ navbar.gsub!('resources', '资源库')
+ if change_count > 1
+ content.sub!('{ifnavbar}', '
')
+ else
+ content.sub!('{ifnavbar}', '')
+ end
+ content.sub!('{endnavbar}', '')
+ content.gsub!('{navbar}', navbar)
+ else
+ content.gsub!(/({ifnavbar})(.*)({endnavbar})/, '')
+ end
+
+ return receiver&.mail, title, content
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectSettingChanged.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_transfer.rb b/app/models/message_template/project_transfer.rb
new file mode 100644
index 000000000..7a99276ba
--- /dev/null
+++ b/app/models/message_template/project_transfer.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我关注的仓库被转移
+class MessageTemplate::ProjectTransfer < MessageTemplate
+
+ # MessageTemplate::ProjectTransfer.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectTransfer.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/project_version.rb b/app/models/message_template/project_version.rb
new file mode 100644
index 000000000..14ae46306
--- /dev/null
+++ b/app/models/message_template/project_version.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我关注的仓库有新的发行版
+class MessageTemplate::ProjectVersion < MessageTemplate
+
+ # MessageTemplate::ProjectVersion.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::ProjectVersion.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/pull_request_assigned.rb b/app/models/message_template/pull_request_assigned.rb
new file mode 100644
index 000000000..54d51f3f3
--- /dev/null
+++ b/app/models/message_template/pull_request_assigned.rb
@@ -0,0 +1,54 @@
+# == 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::PullRequestAssigned < MessageTemplate
+
+ # MessageTemplate::PullRequestAssigned.get_message_content(User.where(login: 'yystopf'), User.last, PullRequest.last)
+ def self.get_message_content(receivers, operator, pull_request)
+ project = pull_request&.project
+ owner = project&.owner
+ content = sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).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)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestAssigned.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+
+ def self.get_email_message_content(receiver, operator, pull_request)
+ project = pull_request&.project
+ owner = project&.owner
+ title = email_title
+ title.gsub!('{nickname1}', operator&.real_name)
+ title.gsub!('{nickname2}', owner&.real_name)
+ title.gsub!('{repository}', project&.name)
+ 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::PullRequestAssigned.get_email_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/pull_request_atme.rb b/app/models/message_template/pull_request_atme.rb
new file mode 100644
index 000000000..54f8c9585
--- /dev/null
+++ b/app/models/message_template/pull_request_atme.rb
@@ -0,0 +1,29 @@
+# == 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::PullRequestAtme < MessageTemplate
+
+ # MessageTemplate::PullRequestAtme.get_message_content(User.where(login: 'yystopf'), User.last, PullRequest.last)
+ def self.get_message_content(receivers, operator, pull_request)
+ project = pull_request&.project
+ owner = project&.owner
+ content = sys_notice.gsub('{nickname}', operator&.real_name).gsub('{title}', pull_request&.title)
+ url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', pull_request&.id.to_s)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestAtme.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/pull_request_changed.rb b/app/models/message_template/pull_request_changed.rb
new file mode 100644
index 000000000..099607fbe
--- /dev/null
+++ b/app/models/message_template/pull_request_changed.rb
@@ -0,0 +1,95 @@
+# == 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::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)
+ return '', '', '' if change_params.blank?
+ project = pull_request&.project
+ owner = project&.owner
+ issue = pull_request&.issue
+ content = sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).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)
+ 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 receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestChanged.get_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
new file mode 100644
index 000000000..6ebb23a63
--- /dev/null
+++ b/app/models/message_template/pull_request_closed.rb
@@ -0,0 +1,29 @@
+# == 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::PullRequestClosed < MessageTemplate
+
+ # MessageTemplate::PullRequestClosed.get_message_content(User.where(login: 'yystopf'), User.last, PullRequest.last)
+ def self.get_message_content(receivers, operator, pull_request)
+ project = pull_request&.project
+ owner = project&.owner
+ content = sys_notice.gsub('{title}', pull_request&.title)
+ url = notification_url
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestClosed.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/message_template/pull_request_journal.rb b/app/models/message_template/pull_request_journal.rb
new file mode 100644
index 000000000..9b2fae949
--- /dev/null
+++ b/app/models/message_template/pull_request_journal.rb
@@ -0,0 +1,25 @@
+# == 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)
+#
+
+# TODO 我创建或负责的合并请求有新的评论
+class MessageTemplate::PullRequestJournal < MessageTemplate
+
+ # MessageTemplate::PullRequestJournal.get_message_content(User.where(login: 'yystopf'))
+ def self.get_message_content(receivers)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestJournal.get_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
new file mode 100644
index 000000000..8df4255a0
--- /dev/null
+++ b/app/models/message_template/pull_request_merged.rb
@@ -0,0 +1,29 @@
+# == 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::PullRequestMerged < MessageTemplate
+
+ # MessageTemplate::PullRequestMerged.get_message_content(User.where(login: 'yystopf'), User.last, PullRequest.last)
+ def self.get_message_content(receivers, operator, pull_request)
+ project = pull_request&.project
+ owner = project&.owner
+ content = sys_notice.gsub('{title}', pull_request&.title)
+ url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', pull_request&.id.to_s)
+ return receivers_string(receivers), content, url
+ rescue => e
+ Rails.logger.info("MessageTemplate::PullRequestMerged.get_message_content [ERROR] #{e}")
+ return '', '', ''
+ end
+end
diff --git a/app/models/mirror.rb b/app/models/mirror.rb
index 67ef73775..b71dce3fb 100644
--- a/app/models/mirror.rb
+++ b/app/models/mirror.rb
@@ -18,7 +18,7 @@ class Mirror < ApplicationRecord
# 0: 同步镜像成功;1: 正在同步镜像;2: 同步失败; 默认值为0
enum status: { succeeded: 0, waiting: 1, failed: 2 }
- after_update :websocket_boardcast, if: :saved_change_to_status?
+ # after_update :websocket_boardcast, if: :saved_change_to_status?
belongs_to :repository, foreign_key: :repo_id
diff --git a/app/models/organization_user.rb b/app/models/organization_user.rb
index cf9e22371..1ad2abd9a 100644
--- a/app/models/organization_user.rb
+++ b/app/models/organization_user.rb
@@ -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
diff --git a/app/models/project_unit.rb b/app/models/project_unit.rb
index 5c519e1d5..cc35a6b28 100644
--- a/app/models/project_unit.rb
+++ b/app/models/project_unit.rb
@@ -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
diff --git a/app/models/team.rb b/app/models/team.rb
index 72df05097..19d05c77a 100644
--- a/app/models/team.rb
+++ b/app/models/team.rb
@@ -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
diff --git a/app/models/user.rb b/app/models/user.rb
index fb8849443..e2b82e6df 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -187,7 +187,7 @@ class User < Owner
:show_email, :show_location, :show_department,
:technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true
- before_save :update_hashed_password, :set_lastname, :set_profile_completed
+ before_save :update_hashed_password, :set_lastname
after_create do
SyncTrustieJob.perform_later("user", 1) if allow_sync_to_trustie?
end
@@ -770,6 +770,10 @@ class User < Owner
laboratory_id.present? && laboratory_id != 1
end
+ def profile_is_completed?
+ self.nickname.present? && self.gender.present? && self.mail.present? && self.custom_department.present?
+ end
+
protected
def validate_password_length
# 管理员的初始密码是5位
@@ -796,10 +800,6 @@ class User < Owner
def set_lastname
self.lastname = self.nickname if changes[:nickname].present?
end
-
- def set_profile_completed
- self.profile_completed = self.nickname.present? && self.gender.present? && self.mail.present? && self.custom_department.present?
- end
end
diff --git a/app/models/watcher.rb b/app/models/watcher.rb
index ccc8eefaa..7ff20943e 100644
--- a/app/models/watcher.rb
+++ b/app/models/watcher.rb
@@ -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
diff --git a/app/queries/projects/list_query.rb b/app/queries/projects/list_query.rb
index 771d4c927..4658408d2 100644
--- a/app/queries/projects/list_query.rb
+++ b/app/queries/projects/list_query.rb
@@ -11,7 +11,7 @@ class Projects::ListQuery < ApplicationQuery
end
def call
- q = Project.all_visible(current_user_id).by_name_or_identifier(params[:search])
+ q = Project.visible.by_name_or_identifier(params[:search])
scope = q
.with_project_type(params[:project_type])
diff --git a/app/services/notice/read/client_service.rb b/app/services/notice/read/client_service.rb
new file mode 100644
index 000000000..95ab8159e
--- /dev/null
+++ b/app/services/notice/read/client_service.rb
@@ -0,0 +1,108 @@
+class Notice::Read::ClientService < ApplicationService
+ attr_reader :url, :params
+
+ def initialize(options={})
+ @url = options[:url]
+ @params = options[:params]
+ end
+
+ def post(url, params={})
+ puts "[notice][read][POST] request params: #{params}"
+ conn.post do |req|
+ req.url = full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def get(url, params={})
+ puts "[notice][read][GET] request params: #{params}"
+ conn.get do |req|
+ req.url full_url(url, 'get')
+ params.each_pair do |key, value|
+ req.params["#{key}"] = value
+ end
+ end
+ end
+
+ def delete(url, params={})
+ puts "[notice][read][DELETE] request params: #{params}"
+ conn.delete do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def patch(url, params={})
+ puts "[notice][read][PATCH] request params: #{params}"
+ conn.patch do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def put(url, params={})
+ puts "[notice][read][PUT] request params: #{params}"
+ conn.put do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def platform
+ Notice.notice_config[:platform]
+ end
+
+ private
+ def conn
+ @client ||= begin
+ Faraday.new(url: domain) do |req|
+ req.request :url_encoded
+ req.headers['Content-Type'] = 'application/json'
+ req.adapter Faraday.default_adapter
+ end
+ end
+
+ @client
+ end
+
+ def base_url
+ Notice.notice_config[:base_url]
+ end
+
+ def domain
+ Notice.notice_config[:read_domain]
+ end
+
+ def api_url
+ [domain, base_url].join('')
+ end
+
+ def full_url(api_rest, action='post')
+ url = [api_url, api_rest].join('').freeze
+ url = action === 'get' ? url : URI.escape(url)
+ url = URI.escape(url) unless url.ascii_only?
+ puts "[notice][read] request url: #{url}"
+ return url
+ end
+
+ def log_error(status, body)
+ puts "[notice][read] status: #{status}"
+ puts "[notice][read] body: #{body}"
+ end
+
+ def render_response(response)
+ status = response.status
+ body = JSON.parse(response&.body)
+
+ log_error(status, body)
+
+ if status == 200
+ if body["code"] == 1
+ return [body["code"], body["message"], body["data"]]
+ else
+ puts "[notice][read][ERROR] code: #{body["code"]}"
+ puts "[notice][read][ERROR] message: #{body["message"]}"
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/services/notice/read/count_service.rb b/app/services/notice/read/count_service.rb
new file mode 100644
index 000000000..fade12278
--- /dev/null
+++ b/app/services/notice/read/count_service.rb
@@ -0,0 +1,25 @@
+class Notice::Read::CountService < Notice::Read::ClientService
+ attr_accessor :receiver, :type
+
+ def initialize(receiver, type=-1)
+ @receiver = receiver
+ @type = type
+ end
+
+ def call
+ result = get(url, request_params)
+ response = render_response(result)
+ end
+
+ private
+ def request_params
+ {
+ receiver: receiver,
+ type: type
+ }.stringify_keys
+ end
+
+ def url
+ "/notification/#{platform}/count".freeze
+ end
+end
\ No newline at end of file
diff --git a/app/services/notice/read/list_service.rb b/app/services/notice/read/list_service.rb
new file mode 100644
index 000000000..3f6645d77
--- /dev/null
+++ b/app/services/notice/read/list_service.rb
@@ -0,0 +1,32 @@
+class Notice::Read::ListService < Notice::Read::ClientService
+ attr_accessor :receiver, :type, :status, :page, :size
+
+ def initialize(receiver, type=-1, status=2, page=1, size=15)
+ @receiver = receiver
+ @type = type
+ @status = status
+ @page = page
+ @size = size
+ end
+
+ def call
+ result = get(url, request_params)
+ response = render_response(result)
+ end
+
+ private
+
+ def request_params
+ {
+ receiver: receiver,
+ page: page,
+ status: status,
+ size: size,
+ type: type
+ }.stringify_keys
+ end
+
+ def url
+ "/notification/#{platform}/list".freeze
+ end
+end
\ No newline at end of file
diff --git a/app/services/notice/write/change_status_service.rb b/app/services/notice/write/change_status_service.rb
new file mode 100644
index 000000000..de2c89815
--- /dev/null
+++ b/app/services/notice/write/change_status_service.rb
@@ -0,0 +1,35 @@
+class Notice::Write::ChangeStatusService < Notice::Write::ClientService
+ attr_accessor :notification_ids, :receiver, :type, :status
+
+ def initialize(notification_ids, receiver, type=-1, status=2)
+ @notification_ids = notification_ids
+ @receiver = receiver
+ @type = type
+ @status = status
+ end
+
+ def call
+ result = put(url, request_params)
+ response = render_response(result)
+ end
+
+ private
+
+ def request_notification_ids
+ notification_ids.join(",")
+ end
+
+ def request_params
+ Hash.new.merge(data: {
+ notificationIds: request_notification_ids,
+ receiver: receiver,
+ type: type,
+ status: status
+ }.stringify_keys)
+ end
+
+ def url
+ "/notification/#{platform}".freeze
+ end
+
+end
\ No newline at end of file
diff --git a/app/services/notice/write/client_service.rb b/app/services/notice/write/client_service.rb
new file mode 100644
index 000000000..c76691cfb
--- /dev/null
+++ b/app/services/notice/write/client_service.rb
@@ -0,0 +1,108 @@
+class Notice::Write::ClientService < ApplicationService
+ attr_reader :url, :params
+
+ def initialize(options={})
+ @url = options[:url]
+ @params = options[:params]
+ end
+
+ def post(url, params={})
+ puts "[notice][write][POST] request params: #{params}"
+ conn.post do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def get(url, params={})
+ puts "[notice][write][GET] request params: #{params}"
+ conn.get do |req|
+ req.url full_url(url, 'get')
+ params.each_pair do |key, value|
+ req.params["#{key}"] = value
+ end
+ end
+ end
+
+ def delete(url, params={})
+ puts "[notice][write][DELETE] request params: #{params}"
+ conn.delete do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def patch(url, params={})
+ puts "[notice][write][PATCH] request params: #{params}"
+ conn.patch do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def put(url, params={})
+ puts "[notice][write][PUT] request params: #{params}"
+ conn.put do |req|
+ req.url full_url(url)
+ req.body = params[:data].to_json
+ end
+ end
+
+ def platform
+ Notice.notice_config[:platform]
+ end
+
+ private
+ def conn
+ @client ||= begin
+ Faraday.new(url: domain) do |req|
+ req.request :url_encoded
+ req.headers['Content-Type'] = 'application/json'
+ req.adapter Faraday.default_adapter
+ end
+ end
+
+ @client
+ end
+
+ def base_url
+ Notice.notice_config[:base_url]
+ end
+
+ def domain
+ Notice.notice_config[:write_domain]
+ end
+
+ def api_url
+ [domain, base_url].join('')
+ end
+
+ def full_url(api_rest, action='post')
+ url = [api_url, api_rest].join('').freeze
+ url = action === 'get' ? url : URI.escape(url)
+ url = URI.escape(url) unless url.ascii_only?
+ puts "[notice][write] request url: #{url}"
+ return url
+ end
+
+ def log_error(status, body)
+ puts "[notice][write] status: #{status}"
+ puts "[notice][write] body: #{body}"
+ end
+
+ def render_response(response)
+ status = response.status
+ body = JSON.parse(response&.body)
+
+ log_error(status, body)
+
+ if status == 200
+ if body["code"] == 1
+ return [body["code"], body["message"], body["data"]]
+ else
+ puts "[notice][write][ERROR] code: #{body["code"]}"
+ puts "[notice][write][ERROR] message: #{body["message"]}"
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/services/notice/write/create_service.rb b/app/services/notice/write/create_service.rb
new file mode 100644
index 000000000..8dfc88483
--- /dev/null
+++ b/app/services/notice/write/create_service.rb
@@ -0,0 +1,42 @@
+class Notice::Write::CreateService < Notice::Write::ClientService
+ attr_accessor :receivers, :sender, :content, :notification_url, :source, :extra, :type
+
+ def initialize(receivers, content, notification_url, source, extra={}, type=1, sender=-1)
+ @receivers = receivers
+ @sender = sender
+ @content = content
+ @notification_url = notification_url
+ @source = source
+ @extra = extra
+ @type = type
+ end
+
+ def call
+ return nil if request_receivers.blank?
+ result = post(url, request_params)
+ response = render_response(result)
+ end
+
+ private
+
+ def request_receivers
+ receivers.is_a?(Array) ? receivers.join(",") : receivers
+ end
+
+ def request_params
+ Hash.new.merge(data: {
+ receivers: request_receivers,
+ sender: sender,
+ content: content,
+ notification_url: notification_url,
+ source: source,
+ extra: extra.to_json.to_s,
+ type: type
+ }.stringify_keys)
+ end
+
+ def url
+ "/notification/#{platform}".freeze
+ end
+
+end
\ No newline at end of file
diff --git a/app/services/notice/write/delete_service.rb b/app/services/notice/write/delete_service.rb
new file mode 100644
index 000000000..f63584819
--- /dev/null
+++ b/app/services/notice/write/delete_service.rb
@@ -0,0 +1,33 @@
+class Notice::Write::DeleteService < Notice::Write::ClientService
+ attr_accessor :notification_ids, :receiver, :type
+
+ def initialize(notification_ids, receiver, type=-1)
+ @notification_ids = notification_ids
+ @receiver = receiver
+ @type = type
+ end
+
+ def call
+ result = delete(url, request_params)
+ response = render_response(result)
+ end
+
+ private
+
+ def request_notification_ids
+ notification_ids.join(",")
+ end
+
+ def request_params
+ Hash.new.merge(data: {
+ notificationIds: request_notification_ids,
+ receiver: receiver,
+ type: type
+ }.stringify_keys)
+ end
+
+ def url
+ "/notification/#{platform}".freeze
+ end
+
+end
\ No newline at end of file
diff --git a/app/services/notice/write/email_create_service.rb b/app/services/notice/write/email_create_service.rb
new file mode 100644
index 000000000..070b42689
--- /dev/null
+++ b/app/services/notice/write/email_create_service.rb
@@ -0,0 +1,40 @@
+class Notice::Write::EmailCreateService < Notice::Write::ClientService
+ attr_accessor :receivers, :sender, :content, :subject
+
+ def initialize(receivers, subject, content, sender=-1)
+ @receivers = receivers
+ @sender = sender
+ @content = content
+ @subject = subject
+ end
+
+ def call
+ return nil if request_receivers.blank?
+ result = post(url, request_params)
+ response = render_response(result)
+ end
+
+ private
+
+ def request_receivers
+ receivers.is_a?(Array) ? receivers.join(",") : receivers
+ end
+
+ def request_subject
+ "Trustie: #{subject}"
+ end
+
+ def request_params
+ Hash.new.merge(data: {
+ emails: request_receivers,
+ sender: sender,
+ content: content,
+ subject: request_subject
+ }.stringify_keys)
+ end
+
+ def url
+ "/email/#{platform}".freeze
+ end
+
+end
\ No newline at end of file
diff --git a/app/services/projects/accept_join_service.rb b/app/services/projects/accept_join_service.rb
index 69cb97603..b1a996fd8 100644
--- a/app/services/projects/accept_join_service.rb
+++ b/app/services/projects/accept_join_service.rb
@@ -53,6 +53,8 @@ class Projects::AcceptJoinService < ApplicationService
def operate_project_member
Projects::AddMemberInteractor.call(@project.owner, @project, @applied_project.user, permission)
+ SendTemplateMessageJob.perform_later('ProjectJoined', @user.id, @applied_project.user_id, @project.id)
+ SendTemplateMessageJob.perform_later('ProjectMemberJoined', @user.id, @applied_project.user_id, @project.id)
end
def send_apply_message
diff --git a/app/views/admins/message_templates/_form.html.erb b/app/views/admins/message_templates/_form.html.erb
new file mode 100644
index 000000000..4b2a6c767
--- /dev/null
+++ b/app/views/admins/message_templates/_form.html.erb
@@ -0,0 +1,65 @@
+
+
+
+ <%= form_for @message_template, url: {controller: "message_templates", action: "#{type}"} do |f| %>
+
+
+
+
+
+
+
+ <%= f.submit "确认", class: "btn btn-primary submit-btn" %>
+
+ <% end %>
+
\ No newline at end of file
diff --git a/app/views/admins/message_templates/_list.html.erb b/app/views/admins/message_templates/_list.html.erb
new file mode 100644
index 000000000..4082735f5
--- /dev/null
+++ b/app/views/admins/message_templates/_list.html.erb
@@ -0,0 +1,39 @@
+
+
+
+ 序号 |
+ 类型 |
+ 系统消息模版 |
+ 邮件模版 |
+ 通知地址 |
+ 操作 |
+
+
+
+ <% if message_templates.present? %>
+ <% message_templates.each_with_index do |message_template_type, index| %>
+ <% message_template = message_template_type.constantize.last%>
+
+ <%= list_index_no((params[:page] || 1).to_i, index) %> |
+ <%= message_template.simple_type %> |
+
+ <%= message_template.sys_notice.to_s.truncate(200) %>
+ |
+
+ <%= message_template.email.to_s.truncate(100) %>
+ |
+
+ <%= message_template.notification_url.to_s.truncate(200) %>
+ |
+
+ <%= link_to "编辑", edit_admins_message_template_path(message_template),remote: true, class: "action" %>
+ |
+
+ <% end %>
+ <% else %>
+ <%= render 'admins/shared/no_data_for_table' %>
+ <% end %>
+
+
+
+<%= render partial: 'admins/shared/paginate', locals: { objects: message_templates } %>
\ No newline at end of file
diff --git a/app/views/admins/message_templates/edit.js.erb b/app/views/admins/message_templates/edit.js.erb
new file mode 100644
index 000000000..5d797af2f
--- /dev/null
+++ b/app/views/admins/message_templates/edit.js.erb
@@ -0,0 +1,2 @@
+$("#admins-message-templates-content").html("<%= j render partial: 'admins/message_templates/form', locals:{type: 'update'} %>")
+createMDEditor('message-template-email-editor', { height: 500, placeholder: '请输入邮件模版' });
diff --git a/app/views/admins/message_templates/index.html.erb b/app/views/admins/message_templates/index.html.erb
new file mode 100644
index 000000000..54d273332
--- /dev/null
+++ b/app/views/admins/message_templates/index.html.erb
@@ -0,0 +1,12 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('消息模版') %>
+<% end %>
+
+
+ <%= link_to "初始化数据", init_data_admins_message_templates_path, class: "btn btn-primary pull-right", "data-disabled-with":"...初始化数据" %>
+
+
+ <%= render partial: 'admins/message_templates/list', locals: { message_templates: @message_templates } %>
+
+
+
diff --git a/app/views/admins/message_templates/index.js.erb b/app/views/admins/message_templates/index.js.erb
new file mode 100644
index 000000000..d8e0fdd26
--- /dev/null
+++ b/app/views/admins/message_templates/index.js.erb
@@ -0,0 +1 @@
+$('.message-templates-list-container').html("<%= j( render partial: 'admins/message_templates/list', locals: { message_templates: @message_templates } ) %>");
\ No newline at end of file
diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb
index e58337c18..402449b3b 100644
--- a/app/views/admins/shared/_sidebar.html.erb
+++ b/app/views/admins/shared/_sidebar.html.erb
@@ -30,6 +30,7 @@
<%= sidebar_item(admins_reversed_keywords_path, '系统保留关键词', icon: 'key', controller: 'admins-reversed_keywords') %>
+ <%= sidebar_item(admins_message_templates_path, '消息模版', icon: 'folder', controller: 'admins-message_templates') %>
<%= sidebar_item(admins_laboratories_path, '云上实验室', icon: 'cloud', controller: 'admins-laboratories') %>
diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder
index 29fbbd2d2..c02a3160f 100644
--- a/app/views/users/get_user_info.json.jbuilder
+++ b/app/views/users/get_user_info.json.jbuilder
@@ -12,8 +12,8 @@ json.tidding_count 0
json.user_phone_binded @user.phone.present?
json.need_edit_info @user.need_edit_info?
# json.phone @user.phone
-json.email @user.mail
-json.profile_completed @user.profile_completed?
+# json.email @user.mail
+json.profile_completed @user.profile_is_completed?
json.professional_certification @user.professional_certification
json.devops_step @user.devops_step
json.ci_certification @user.ci_certification?
@@ -22,4 +22,5 @@ json.province @user.province
json.city @user.city
json.custom_department @user.custom_department
json.description @user.description
-json.(@user, :show_email, :show_department, :show_location)
\ No newline at end of file
+json.(@user, :show_email, :show_department, :show_location)
+json.message_unread_total @message_unread_total
diff --git a/app/views/users/messages/_message.json.jbuilder b/app/views/users/messages/_message.json.jbuilder
new file mode 100644
index 000000000..9f6f0c504
--- /dev/null
+++ b/app/views/users/messages/_message.json.jbuilder
@@ -0,0 +1,24 @@
+json.id message["id"]
+# json.receiver do
+# json.partial! '/users/user_simple', locals: {user: current_user}
+# end
+json.status message["status"]
+json.content message["content"]
+json.notification_url message["notification_url"]
+json.source message["source"]
+json.time_ago time_from_now(message["created_at"].to_time)
+
+case message["type"]
+when 1
+ json.type "notification"
+when 2
+ json.type "atme"
+ json.sender do
+ sender = User.find_by_id(message["sender"])
+ if sender.present?
+ json.partial! '/users/user_simple', locals: {user: sender}
+ else
+ json.nil
+ end
+ end
+end
diff --git a/app/views/users/messages/index.json.jbuilder b/app/views/users/messages/index.json.jbuilder
new file mode 100644
index 000000000..b16d806b7
--- /dev/null
+++ b/app/views/users/messages/index.json.jbuilder
@@ -0,0 +1,7 @@
+json.total_count @data["records_count"]
+json.type %w(notification atme).include?(params[:type]) ? params[:type] : ""
+json.unread_notification @data["unread_notification"]
+json.unread_atme @data["unread_atme"]
+json.messages @data["records"].each do |message|
+ json.partial! "message", message: message.stringify_keys
+end
\ No newline at end of file
diff --git a/config/configuration.yml.example b/config/configuration.yml.example
index 9b012277a..4c9683e12 100644
--- a/config/configuration.yml.example
+++ b/config/configuration.yml.example
@@ -62,6 +62,11 @@ default: &default
domain: 'https://testgit.trustie.net'
base_url: '/api/v1'
+ notice:
+ platform: ''
+ write_domain: ''
+ read_domain: ''
+ base_url: ''
production:
<<: *default
diff --git a/config/database.yml.example b/config/database.yml.example
index b0f1f2bef..52f6538e1 100644
--- a/config/database.yml.example
+++ b/config/database.yml.example
@@ -18,7 +18,7 @@ default: &default
password: 123456
# socket: /var/run/mysqld/mysqld.sock
gitea_server:
- aadapter: mysql2
+ adapter: mysql2
database: gitea_development
host: 127.0.0.1
username: root
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index db1030163..f6f478625 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -31,7 +31,7 @@ zh-CN:
branch_name: 分支
close_pr: 合并
merge: 合并
- issue_tags_value: 标签
+ issue_tags_value: 标记
lock_issue: 锁定工单
unlock_issue: 解锁工单
destroy_issue_depend: 删除依赖
@@ -55,7 +55,7 @@ zh-CN:
f: 否
true: 是
false: 否
- issue_tag_ids: 标签
+ issue_tag_ids: 标记
issue_type: 分类
token: 悬赏金额
close_issue: 工单
diff --git a/config/routes.rb b/config/routes.rb
index dc8892081..9c6dda1b0 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -300,6 +300,15 @@ Rails.application.routes.draw do
# resources :recent_contacts, only: [:index]
# resource :private_message_details, only: [:show]
# resource :unread_message_info, only: [:show]
+
+ # 通知中心
+ resources :messages, only: [:index, :create] do
+ collection do
+ post :read
+
+ end
+ end
+ delete 'messages', to: 'messages#delete'
end
resources :tidings, only: [:index]
@@ -659,6 +668,11 @@ Rails.application.routes.draw do
resources :project_licenses
resources :project_ignores
resources :reversed_keywords
+ resources :message_templates, only: [:index, :edit, :update] do
+ collection do
+ get :init_data
+ end
+ end
resources :major_informations, only: [:index]
resources :ec_templates, only: [:index, :destroy] do
collection do
diff --git a/config/sidekiq.yml b/config/sidekiq.yml
index a50c1c1aa..f8981a8b1 100644
--- a/config/sidekiq.yml
+++ b/config/sidekiq.yml
@@ -8,3 +8,4 @@
- [notify, 100]
- [mailers, 101]
- [cache, 10]
+ - [message, 20]
diff --git a/config/sidekiq_cron.yml b/config/sidekiq_cron.yml
index 3e807fa10..448e9c945 100644
--- a/config/sidekiq_cron.yml
+++ b/config/sidekiq_cron.yml
@@ -2,3 +2,8 @@ sync_gitea_repo_update_time:
cron: "0 0 * * *"
class: "SyncRepoUpdateTimeJob"
queue: default
+
+delay_expired_issue:
+ cron: "0 0 * * *"
+ class: "DelayExpiredIssueJob"
+ queue: message
diff --git a/db/migrate/20210909030759_create_message_templates.rb b/db/migrate/20210909030759_create_message_templates.rb
new file mode 100644
index 000000000..dbae7f55d
--- /dev/null
+++ b/db/migrate/20210909030759_create_message_templates.rb
@@ -0,0 +1,11 @@
+class CreateMessageTemplates < ActiveRecord::Migration[5.2]
+ def change
+ create_table :message_templates do |t|
+ t.string :type
+ t.text :sys_notice
+ t.text :email
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20210914064456_add_notification_url_to_message_templates.rb b/db/migrate/20210914064456_add_notification_url_to_message_templates.rb
new file mode 100644
index 000000000..2adb842c8
--- /dev/null
+++ b/db/migrate/20210914064456_add_notification_url_to_message_templates.rb
@@ -0,0 +1,5 @@
+class AddNotificationUrlToMessageTemplates < ActiveRecord::Migration[5.2]
+ def change
+ add_column :message_templates, :notification_url, :string
+ end
+end
diff --git a/db/migrate/20210924021337_add_email_title_to_message_templates.rb b/db/migrate/20210924021337_add_email_title_to_message_templates.rb
new file mode 100644
index 000000000..33d84b243
--- /dev/null
+++ b/db/migrate/20210924021337_add_email_title_to_message_templates.rb
@@ -0,0 +1,5 @@
+class AddEmailTitleToMessageTemplates < ActiveRecord::Migration[5.2]
+ def change
+ add_column :message_templates, :email_title, :string
+ end
+end
diff --git a/public/docs/api.html b/public/docs/api.html
index 35099a4e8..c77c08988 100644
--- a/public/docs/api.html
+++ b/public/docs/api.html
@@ -345,6 +345,18 @@
获取当前登陆用户信息
+
+ 用户消息列表
+
+
+ 发送消息
+
+
+ 阅读消息
+
+
+ 删除消息
+
更改用户信息
@@ -909,7 +921,7 @@ Success — a happy kitten is an authenticated kitten!
Users
获取当前登陆用户信息
@@ -971,6 +983,468 @@ Success — a happy kitten is an authenticated kitten!
+用户消息列表
+
获取用户消息列表
+
+
+示例:
+
+curl -X GET http://localhost:3000/api/users/:login/messages.json
+
await octokit.request('GET /api/users/:login/messages.json')
+
HTTP 请求
+GET api/users/yystopf/messages.json
+请求字段说明:
+
+
+参数 |
+类型 |
+字段说明 |
+
+
+
+type |
+string |
+消息类型,不传为所有消息,notification为系统消息,atme为@我消息 |
+
+
+status |
+integer |
+是否已读,不传为所有消息,1为未读,2为已读 |
+
+
+limit |
+integer |
+每页个数 |
+
+
+page |
+integer |
+页码 |
+
+
+返回字段说明:
+
+
+参数 |
+类型 |
+字段说明 |
+
+
+
+total_count |
+integer |
+消息总数 |
+
+
+type |
+string |
+消息类型 |
+
+
+unread_notification |
+integer |
+未读系统通知数量 |
+
+
+unread_atme |
+integer |
+未读@我数量 |
+
+
+messages.id |
+integer |
+消息id |
+
+
+messages.status |
+integer |
+消息是否已读,1为未读,2为已读 |
+
+
+messages.content |
+string |
+消息内容 |
+
+
+messages.notification_url |
+string |
+消息跳转地址 |
+
+
+messages.source |
+string |
+消息来源 |
+
+
+messages.timeago |
+string |
+消息时间 |
+
+
+messages.type |
+string |
+消息类型,notification为系统消息,atme为@我消息 |
+
+
+sender |
+object |
+消息发送者 |
+
+
+消息来源source字段说明
+
+
+类型 |
+说明 |
+
+
+
+IssueAssigned |
+有新指派给我的易修 |
+
+
+IssueAssignerExpire |
+我负责的易修截止日期到达最后一天 |
+
+
+IssueAtme |
+在易修中@我 |
+
+
+IssueChanged |
+我创建或负责的易修状态变更 |
+
+
+IssueCreatorExpire |
+我创建的易修截止日期到达最后一天 |
+
+
+IssueDeleted |
+我创建或负责的易修删除 |
+
+
+IssueJournal |
+我创建或负责的易修有新的评论 |
+
+
+LoginIpTip |
+登录异常提示 |
+
+
+OrganizationJoined |
+账号被拉入组织 |
+
+
+OrganizationLeft |
+账号被移出组织 |
+
+
+OrganizationRole |
+账号组织权限变更 |
+
+
+ProjectDeleted |
+我关注的仓库被删除 |
+
+
+ProjectFollowed |
+我管理的仓库被关注 |
+
+
+ProjectForked |
+我管理的仓库被复刻 |
+
+
+ProjectIssue |
+我管理/关注的仓库有新的易修 |
+
+
+ProjectJoined |
+账号被拉入项目 |
+
+
+ProjectLeft |
+账号被移出项目 |
+
+
+ProjectMemberJoined |
+我管理的仓库有成员加入 |
+
+
+ProjectMemberLeft |
+我管理的仓库有成员移出 |
+
+
+ProjectMilestone |
+我管理的仓库有新的里程碑 |
+
+
+ProjectPraised |
+我管理的仓库被点赞 |
+
+
+ProjectPullRequest |
+我管理/关注的仓库有新的合并请求 |
+
+
+ProjectRole |
+账号仓库权限变更 |
+
+
+ProjectSettingChanged |
+我管理的仓库项目设置被更改 |
+
+
+ProjectTransfer |
+我关注的仓库被转移 |
+
+
+ProjectVersion |
+我关注的仓库有新的发行版 |
+
+
+PullRequestAssigned |
+有新指派给我的合并请求 |
+
+
+PullReuqestAtme |
+在合并请求中@我 |
+
+
+PullRequestChanged |
+我创建或负责的合并请求状态变更 |
+
+
+PullRequestClosed |
+我创建或负责的合并请求被关闭 |
+
+
+PullRequestJournal |
+我创建或负责的合并请求有新的评论 |
+
+
+PullRequestMerged |
+我创建或负责的合并请求被合并 |
+
+
+
+
+返回的JSON示例:
+
+{
+ "total_count": 5,
+ "type": "",
+ "unread_notification": 3,
+ "unread_atme": 2,
+ "messages": [
+ {
+ "id": 1,
+ "status": 1,
+ "content": "Atme Message Content 1",
+ "notification_url": "http://www.baidu.com",
+ "source": "PullRequestAtme",
+ "time_ago": "1天前",
+ "type": "atme",
+ "sender": {
+ "id": 5,
+ "type": "User",
+ "name": "testforge2",
+ "login": "testforge2",
+ "image_url": "system/lets/letter_avatars/2/T/236_177_85/120.png"
+ }
+ },
+ {
+ "id": 2,
+ "status": 0,
+ "content": "Atme Message Content 2",
+ "notification_url": "http://www.baidu.com",
+ "source": "IssueAtme",
+ "time_ago": "1天前",
+ "type": "atme",
+ "sender": {
+ "id": 4,
+ "type": "User",
+ "name": "testforge1",
+ "login": "testforge1",
+ "image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png"
+ }
+ },
+ {
+ "id": 3,
+ "status": 1,
+ "content": "Notification Message Content 1",
+ "notification_url": "http://www.baidu.com",
+ "source": "IssueDelete",
+ "time_ago": "1天前",
+ "type": "notification"
+ },
+ {
+ "id": 4,
+ "status": 0,
+ "content": "Notification Message Content 2",
+ "notification_url": "http://www.baidu.com",
+ "source": "IssueChanged",
+ "time_ago": "1天前",
+ "type": "notification"
+ },
+ {
+ "id": 5,
+ "status": 0,
+ "content": "Notification Message Content 3",
+ "notification_url": "http://www.baidu.com",
+ "source": "ProjectJoined",
+ "time_ago": "1天前",
+ "type": "notification"
+ }
+ ]
+}
+
+
+发送消息
+发送消息, 目前只支持atme
+
+
+示例:
+
+curl -X POST http://localhost:3000/api/users/:login/messages.json
+
await octokit.request('POST /api/users/:login/messages.json')
+
HTTP 请求
+POST api/users/yystopf/messages.json
+请求字段说明:
+
+
+参数 |
+类型 |
+字段说明 |
+
+
+
+type |
+string |
+消息类型 |
+
+
+receivers_login |
+array |
+需要发送消息的用户名数组 |
+
+
+atmeable_type |
+string |
+atme消息对象,是从哪里@我的,比如评论:Journal、易修:Issue、合并请求:PullRequest |
+
+
+atmeable_id |
+integer |
+atme消息对象id |
+
+
+
+
+请求的JSON示例:
+
+{
+ "type": "atme",
+ "receivers_login": ["yystopf", "testforge1"],
+ "atmeable_type": "Journal",
+ "atmeable_id": 67
+}
+
+
+返回的JSON示例:
+
+{
+ "status": 0,
+ "message": "success"
+}
+
+
+阅读消息
+阅读消息
+
+
+示例:
+
+curl -X POST http://localhost:3000/api/users/:login/messages/read.json
+
await octokit.request('POST /api/users/:login/messages/read.json')
+
HTTP 请求
+POST api/users/yystopf/messages/read.json
+请求字段说明:
+
+
+参数 |
+类型 |
+字段说明 |
+
+
+
+type |
+string |
+消息类型,不传为所有消息,notification为系统消息,atme为@我消息 |
+
+
+ids |
+array |
+消息id数组,包含-1则把所有未读消息标记为已读 |
+
+
+
+
+返回的JSON示例:
+
+{
+ "status": 0,
+ "message": "success"
+}
+
+
+删除消息
+删除消息
+
+
+示例:
+
+curl -X DELETE http://localhost:3000/api/users/:login/messages.json
+
await octokit.request('DELETE /api/users/:login/messages.json')
+
HTTP 请求
+DELETE api/users/yystopf/messages.json
+请求字段说明:
+
+
+参数 |
+类型 |
+字段说明 |
+
+
+
+type |
+string |
+消息类型,atme为@我消息 |
+
+
+ids |
+array |
+消息id数组,包含-1则把所有消息删除 |
+
+
+
+
+返回的JSON示例:
+
+{
+ "status": 0,
+ "message": "success"
+}
+
+
更改用户信息
更改用户信息
@@ -979,9 +1453,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X PATCH/PUT http://localhost:3000/api/users/yystopf.json
await octokit.request('PATCH/PUT /api/users/:login.json')
-
HTTP 请求
+HTTP 请求
PATCH/PUT /api/users/:login.json
-请求字段说明:
+请求字段说明:
参数 |
@@ -1077,9 +1551,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X GET http://localhost:3000/api/users/yystopf/is_pinned_projects.json
await octokit.request('GET /api/users/:login/is_pinned_projects.json')
-
HTTP 请求
+HTTP 请求
GET api/users/:login/is_pinned_projects.json
-返回字段说明:
+返回字段说明:
参数 |
@@ -1264,9 +1738,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X POST http://localhost:3000/api/users/yystopf/is_pinned_projects/pin.json
await octokit.request('GET /api/users/:login/is_pinned_projects/pin.json')
-
HTTP 请求
+HTTP 请求
POST /api/users/:login/is_pinned_projects/pin.json
-请求字段说明:
同时设定多个星标项目
+请求字段说明:
同时设定多个星标项目
参数 |
@@ -1310,9 +1784,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X PATCH http://localhost:3000/api/users/yystopf/is_pinned_projects/11.json
await octokit.request('PATCH/PUT /api/users/:login/is_pinned_projects/:id.json')
-
HTTP 请求
+HTTP 请求
PATCH/PUT /api/users/:login/is_pinned_projects/:id.json
-请求字段说明:
+请求字段说明:
参数 |
@@ -1351,9 +1825,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X GET http://localhost:3000/api/users/yystopf/statistics/activity.json
await octokit.request('GET /api/users/:login/statistics/activity.json')
-
HTTP 请求
+HTTP 请求
GET /api/users/:login/statistics/activity.json
-返回字段说明:
+返回字段说明:
参数 |
@@ -1440,9 +1914,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json
await octokit.request('GET /api/users/:login/headmaps.json')
-
HTTP 请求
+HTTP 请求
GET api/users/:login/headmaps.json
-请求字段说明:
+请求字段说明:
参数 |
@@ -1456,7 +1930,7 @@ Success — a happy kitten is an authenticated kitten!
年份 |
-返回字段说明:
+返回字段说明:
参数 |
@@ -1585,9 +2059,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X GET http://localhost:3000/api/users/yystopf/project_trends.json
await octokit.request('GET /api/users/:login/project_trends.json')
-
HTTP 请求
+HTTP 请求
GET api/users/:login/project_trends.json
-请求字段说明:
+请求字段说明:
参数 |
@@ -1601,7 +2075,7 @@ Success — a happy kitten is an authenticated kitten!
日期,格式: 2021-05-28 |
-返回字段说明:
+返回字段说明:
参数 |
@@ -1902,9 +2376,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X GET http://localhost:3000/api/users/yystopf/statistics/develop.json
await octokit.request('GET /api/users/:login/statistics/develop.json')
-
HTTP 请求
+HTTP 请求
GET /api/users/:login/statistics/develop.json
-请求字段说明:
+请求字段说明:
参数 |
@@ -1923,7 +2397,7 @@ Success — a happy kitten is an authenticated kitten!
时间戳,结束时间,格式:1622131200 |
-返回字段说明:
+返回字段说明:
参数 |
@@ -2045,9 +2519,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X GET http://localhost:3000/api/users/yystopf/statistics/role.json
await octokit.request('GET /api/users/:login/statistics/role.json')
-
HTTP 请求
+HTTP 请求
GET /api/users/:login/statistics/role.json
-请求字段说明:
+请求字段说明:
参数 |
@@ -2066,7 +2540,7 @@ Success — a happy kitten is an authenticated kitten!
时间戳,结束时间,格式:1622131200 |
-返回字段说明:
+返回字段说明:
参数 |
@@ -2127,9 +2601,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X GET http://localhost:3000/api/users/yystopf/statistics/major.json
await octokit.request('GET /api/users/:login/statistics/major.json')
-
HTTP 请求
+HTTP 请求
GET /api/users/:login/statistics/major.json
-请求字段说明:
+请求字段说明:
参数 |
@@ -2148,7 +2622,7 @@ Success — a happy kitten is an authenticated kitten!
时间戳,结束时间,格式:1622131200 |
-返回字段说明:
+返回字段说明:
参数 |
@@ -2188,9 +2662,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X GET http://localhost:3000/api/users/yystopf/applied_messages.json
await octokit.request('GET /api/users/:login/applied_messages.json')
-
HTTP 请求
+HTTP 请求
GET /api/users/:login/applied_messages.json
-请求字段说明:
+请求字段说明:
参数 |
@@ -2204,7 +2678,7 @@ Success — a happy kitten is an authenticated kitten!
用户标识 |
-返回字段说明:
+返回字段说明:
参数 |
@@ -2467,9 +2941,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X GET http://localhost:3000/api/users/yystopf/applied_transfer_projects.json
await octokit.request('GET /api/users/:login/applied_transfer_projects.json')
-
HTTP 请求
+HTTP 请求
GET /api/users/:login/applied_transfer_projects.json
-请求字段说明:
+请求字段说明:
参数 |
@@ -2483,7 +2957,7 @@ Success — a happy kitten is an authenticated kitten!
用户标识 |
-返回字段说明:
+返回字段说明:
参数 |
@@ -2659,200 +3133,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/accept.json
await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/accept.json')
-
HTTP 请求
+HTTP 请求
GET /api/users/:login/applied_transfer_projects/:id/accept.json
-请求字段说明:
-
-
-参数 |
-类型 |
-字段说明 |
-
-
-
-login |
-string |
-用户标识 |
-
-
-id |
-int |
-迁移id |
-
-
-返回字段说明:
-
-
-参数 |
-类型 |
-字段说明 |
-
-
-
-id |
-int |
-迁移id |
-
-
-status |
-string |
-迁移状态,canceled:取消,common:正在迁移, accept:已接受,refuse:已拒绝 |
-
-
-time_ago |
-string |
-迁移创建的时间 |
-
-
-project.id |
-int |
-迁移项目的id |
-
-
-project.identifier |
-string |
-迁移项目的标识 |
-
-
-project.name |
-string |
-迁移项目的名称 |
-
-
-project.description |
-string |
-迁移项目的描述 |
-
-
-project.is_public |
-bool |
-迁移项目是否公开 |
-
-
-project.owner.id |
-bool |
-迁移项目拥有者id |
-
-
-project.owner.type |
-string |
-迁移项目拥有者类型 |
-
-
-project.owner.name |
-string |
-迁移项目拥有者昵称 |
-
-
-project.owner.login |
-string |
-迁移项目拥有者标识 |
-
-
-project.owner.image_url |
-string |
-迁移项目拥有者头像 |
-
-
-user.id |
-int |
-迁移创建者的id |
-
-
-user.type |
-string |
-迁移创建者的类型 |
-
-
-user.name |
-string |
-迁移创建者的名称 |
-
-
-user.login |
-string |
-迁移创建者的标识 |
-
-
-user.image_url |
-string |
-迁移创建者头像 |
-
-
-owner.id |
-int |
-迁移接受者的id |
-
-
-owner.type |
-string |
-迁移接受者的类型 |
-
-
-owner.name |
-string |
-迁移接受者的名称 |
-
-
-owner.login |
-string |
-迁移接受者的标识 |
-
-
-owner.image_url |
-string |
-迁移接受者头像 |
-
-
-
-
-返回的JSON示例:
-
-{
- "project": {
- "id": 86,
- "identifier": "ceshi_repo1",
- "name": "测试项目啊1",
- "description": "二十多",
- "is_public": true,
- "owner": {
- "id": 52,
- "type": "Organization",
- "name": "身份卡手动阀",
- "login": "ceshi1",
- "image_url": "images/avatars/Organization/52?t=1618805056"
- }
- },
- "user": {
- "id": 6,
- "type": "User",
- "name": "yystopf",
- "login": "yystopf",
- "image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
- },
- "owner": {
- "id": 52,
- "type": "Organization",
- "name": "身份卡手动阀",
- "login": "ceshi1",
- "image_url": "images/avatars/Organization/52?t=1618805056"
- },
- "id": 1,
- "status": "canceled",
- "created_at": "2021-04-25 18:06",
- "time_ago": "16小时前"
-}
-
用户拒绝迁移
-用户拒绝迁移
-
-
-示例:
-
-curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.json
-
await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refuse.json')
-
HTTP 请求
-GET /api/users/:login/applied_transfer_projects/:id/refuse.json
-请求字段说明:
+请求字段说明:
参数 |
@@ -2996,6 +3279,197 @@ Success — a happy kitten is an authenticated kitten!
+
+返回的JSON示例:
+
+{
+ "project": {
+ "id": 86,
+ "identifier": "ceshi_repo1",
+ "name": "测试项目啊1",
+ "description": "二十多",
+ "is_public": true,
+ "owner": {
+ "id": 52,
+ "type": "Organization",
+ "name": "身份卡手动阀",
+ "login": "ceshi1",
+ "image_url": "images/avatars/Organization/52?t=1618805056"
+ }
+ },
+ "user": {
+ "id": 6,
+ "type": "User",
+ "name": "yystopf",
+ "login": "yystopf",
+ "image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
+ },
+ "owner": {
+ "id": 52,
+ "type": "Organization",
+ "name": "身份卡手动阀",
+ "login": "ceshi1",
+ "image_url": "images/avatars/Organization/52?t=1618805056"
+ },
+ "id": 1,
+ "status": "canceled",
+ "created_at": "2021-04-25 18:06",
+ "time_ago": "16小时前"
+}
+
用户拒绝迁移
+用户拒绝迁移
+
+
+示例:
+
+curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.json
+
await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refuse.json')
+
HTTP 请求
+GET /api/users/:login/applied_transfer_projects/:id/refuse.json
+请求字段说明:
+
+
+参数 |
+类型 |
+字段说明 |
+
+
+
+login |
+string |
+用户标识 |
+
+
+id |
+int |
+迁移id |
+
+
+返回字段说明:
+
+
+参数 |
+类型 |
+字段说明 |
+
+
+
+id |
+int |
+迁移id |
+
+
+status |
+string |
+迁移状态,canceled:取消,common:正在迁移, accept:已接受,refuse:已拒绝 |
+
+
+time_ago |
+string |
+迁移创建的时间 |
+
+
+project.id |
+int |
+迁移项目的id |
+
+
+project.identifier |
+string |
+迁移项目的标识 |
+
+
+project.name |
+string |
+迁移项目的名称 |
+
+
+project.description |
+string |
+迁移项目的描述 |
+
+
+project.is_public |
+bool |
+迁移项目是否公开 |
+
+
+project.owner.id |
+bool |
+迁移项目拥有者id |
+
+
+project.owner.type |
+string |
+迁移项目拥有者类型 |
+
+
+project.owner.name |
+string |
+迁移项目拥有者昵称 |
+
+
+project.owner.login |
+string |
+迁移项目拥有者标识 |
+
+
+project.owner.image_url |
+string |
+迁移项目拥有者头像 |
+
+
+user.id |
+int |
+迁移创建者的id |
+
+
+user.type |
+string |
+迁移创建者的类型 |
+
+
+user.name |
+string |
+迁移创建者的名称 |
+
+
+user.login |
+string |
+迁移创建者的标识 |
+
+
+user.image_url |
+string |
+迁移创建者头像 |
+
+
+owner.id |
+int |
+迁移接受者的id |
+
+
+owner.type |
+string |
+迁移接受者的类型 |
+
+
+owner.name |
+string |
+迁移接受者的名称 |
+
+
+owner.login |
+string |
+迁移接受者的标识 |
+
+
+owner.image_url |
+string |
+迁移接受者头像 |
+
+
+
返回的JSON示例:
@@ -3041,9 +3515,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X GET http://localhost:3000/api/users/yystopf/applied_projects.json
await octokit.request('GET /api/users/:login/applied_projects.json')
-
HTTP 请求
+HTTP 请求
GET /api/users/:login/applied_projects.json
-请求字段说明:
+请求字段说明:
参数 |
@@ -3057,7 +3531,7 @@ Success — a happy kitten is an authenticated kitten!
用户标识 |
-返回字段说明:
+返回字段说明:
参数 |
@@ -3201,9 +3675,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X POST http://localhost:3000/api/users/yystopf/applied_projects/2/accept.json
await octokit.request('GET /api/users/:login/applied_projects/:id/accept.json')
-
HTTP 请求
+HTTP 请求
GET /api/users/:login/applied_projects/:id/accept.json
-请求字段说明:
+请求字段说明:
参数 |
@@ -3222,7 +3696,7 @@ Success — a happy kitten is an authenticated kitten!
申请id |
-返回字段说明:
+返回字段说明:
参数 |
@@ -3360,9 +3834,9 @@ Success — a happy kitten is an authenticated kitten!
curl -X POST http://localhost:3000/api/users/yystopf/applied_projects/2/refuse.json
await octokit.request('GET /api/users/:login/applied_projects/:id/refuse.json')
-
HTTP 请求
+HTTP 请求
GET /api/users/:login/applied_projects/:id/refuse.json
-请求字段说明:
+请求字段说明:
参数 |
@@ -3381,7 +3855,7 @@ Success — a happy kitten is an authenticated kitten!
申请id |
-返回字段说明:
+返回字段说明:
参数 |
diff --git a/public/message_template/issue_assigned.html b/public/message_template/issue_assigned.html
new file mode 100755
index 000000000..8b78dbdaf
--- /dev/null
+++ b/public/message_template/issue_assigned.html
@@ -0,0 +1,52 @@
+
+
+ 有新的易修指派给我
+
+
+
+
+
+
+
+

+
确实让创新更美好
+
+
+
+
+
如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693
+
Trustie团队
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/message_template/organization_joined.html b/public/message_template/organization_joined.html
new file mode 100755
index 000000000..cc0c68ed2
--- /dev/null
+++ b/public/message_template/organization_joined.html
@@ -0,0 +1,52 @@
+
+
+ 加入组织
+
+
+
+
+
+
+
+

+
确实让创新更美好
+
+
+
+
+
如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693
+
Trustie团队
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/message_template/organization_left.html b/public/message_template/organization_left.html
new file mode 100755
index 000000000..5355129fd
--- /dev/null
+++ b/public/message_template/organization_left.html
@@ -0,0 +1,52 @@
+
+
+ 移出组织
+
+
+
+
+
+
+
+

+
确实让创新更美好
+
+
+
+
+
如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693
+
Trustie团队
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/message_template/project_issue.html b/public/message_template/project_issue.html
new file mode 100755
index 000000000..d9999e70c
--- /dev/null
+++ b/public/message_template/project_issue.html
@@ -0,0 +1,52 @@
+
+
+ 管理的仓库有新的易修
+
+
+
+
+
+
+
+

+
确实让创新更美好
+
+
+
+
+
如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693
+
Trustie团队
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/message_template/project_joined.html b/public/message_template/project_joined.html
new file mode 100755
index 000000000..c144da01a
--- /dev/null
+++ b/public/message_template/project_joined.html
@@ -0,0 +1,52 @@
+
+
+ 加入项目
+
+
+
+
+
+
+
+

+
确实让创新更美好
+
+
+
+
+
如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693
+
Trustie团队
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/message_template/project_left.html b/public/message_template/project_left.html
new file mode 100755
index 000000000..5a87e8ba4
--- /dev/null
+++ b/public/message_template/project_left.html
@@ -0,0 +1,52 @@
+
+
+ 移出项目
+
+
+
+
+
+
+
+

+
确实让创新更美好
+
+
+
+
+
如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693
+
Trustie团队
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/message_template/project_member_joined.html b/public/message_template/project_member_joined.html
new file mode 100755
index 000000000..9f376d4f3
--- /dev/null
+++ b/public/message_template/project_member_joined.html
@@ -0,0 +1,52 @@
+
+
+ 管理的仓库有成员变更
+
+
+
+
+
+
+
+

+
确实让创新更美好
+
+
+
+
+
如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693
+
Trustie团队
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/message_template/project_member_left.html b/public/message_template/project_member_left.html
new file mode 100755
index 000000000..f1c6b6d95
--- /dev/null
+++ b/public/message_template/project_member_left.html
@@ -0,0 +1,52 @@
+
+
+ 管理的仓库有成员变更
+
+
+
+
+
+
+
+

+
确实让创新更美好
+
+
+
+
+
如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ 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
new file mode 100755
index 000000000..0f75e0b8c
--- /dev/null
+++ b/public/message_template/project_pull_request.html
@@ -0,0 +1,52 @@
+
+
+ 管理的仓库有新的合并请求
+
+
+
+
+
+
+
+

+
确实让创新更美好
+
+
+
+
+
如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693
+
Trustie团队
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/message_template/project_setting_changed.html b/public/message_template/project_setting_changed.html
new file mode 100755
index 000000000..ca51e262c
--- /dev/null
+++ b/public/message_template/project_setting_changed.html
@@ -0,0 +1,58 @@
+
+
+ 管理的仓库设置被更改
+
+
+
+
+
+
+
+

+
确实让创新更美好
+
+
+
+
+ {receiver},您好!
+ {nickname1} 更改 {nickname2}/{repository} 的仓库设置:
+ {ifname}更改项目名称为"{name}"{endname}
+ {ifdescription}更改项目简介为"{description}"{enddescription}
+ {ifcategory}更改项目类别为"{category}"{endcategory}
+ {iflanguage}更改项目语言为"{language}"{endlanguage}
+ {ifpermission}将仓库设为"{permission}"{endpermission}
+ {ifnavbar}将项目导航更改为"{navbar}"{endnavbar}
+
+
+

+
+ 扫一扫,关注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
new file mode 100755
index 000000000..3898336e4
--- /dev/null
+++ b/public/message_template/pull_request_assigned.html
@@ -0,0 +1,52 @@
+
+
+ 有新的合并请求指派给我
+
+
+
+
+
+
+
+

+
确实让创新更美好
+
+
+
+
+
如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见
+ QQ群:1071514693
+
Trustie团队
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spec/models/message_template_spec.rb b/spec/models/message_template_spec.rb
new file mode 100644
index 000000000..8f1d26fcd
--- /dev/null
+++ b/spec/models/message_template_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe MessageTemplate, type: :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end