Merge pull request '新增站内信以及里程碑完成度修复' (#299) from yystopf/forgeplus:develop into develop

This commit is contained in:
yystopf 2022-02-15 17:33:30 +08:00
commit b5acf2308a
24 changed files with 445 additions and 63 deletions

View File

@ -180,6 +180,7 @@ class IssuesController < ApplicationController
elsif params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size == 1 elsif params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size == 1
@issue&.issue_tags_relates&.destroy_all @issue&.issue_tags_relates&.destroy_all
params[:issue_tag_ids].each do |tag| params[:issue_tag_ids].each do |tag|
next if tag == [""]
IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag) IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag)
end end
else else
@ -246,7 +247,7 @@ class IssuesController < ApplicationController
end end
if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时 if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时
@issue.issue_times.update_all(end_time: Time.now) @issue.issue_times.update_all(end_time: Time.now)
@issue.update_closed_issues_count_in_project! # @issue.update_closed_issues_count_in_project!
if @issue.issue_type.to_s == "2" && last_status_id != 5 if @issue.issue_type.to_s == "2" && last_status_id != 5
if @issue.assigned_to_id.present? && last_status_id == 3 #只有当用户完成100%时才给token if @issue.assigned_to_id.present? && last_status_id == 3 #只有当用户完成100%时才给token
post_to_chain("add", @issue.token, @issue.get_assign_user.try(:login)) post_to_chain("add", @issue.token, @issue.get_assign_user.try(:login))

View File

@ -12,6 +12,7 @@ class PraiseTreadController < ApplicationController
begin begin
return normal_status(2, "你已点过赞了") if current_user.liked?(@project) return normal_status(2, "你已点过赞了") if current_user.liked?(@project)
current_user.like!(@project) current_user.like!(@project)
SendTemplateMessageJob.perform_later('ProjectPraised', current_user.id, @project.id) if Site.has_notice_menu?
render_ok({praises_count: @project.praises_count, praised: current_user.liked?(@project)}) render_ok({praises_count: @project.praises_count, praised: current_user.liked?(@project)})
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)

View File

@ -22,6 +22,8 @@ class Users::TemplateMessageSettingsController < Users::BaseController
def get_current_setting def get_current_setting
@current_setting = @_observed_user.user_template_message_setting @current_setting = @_observed_user.user_template_message_setting
@current_setting.notification_body.merge!(UserTemplateMessageSetting.init_notification_body.except(*@current_setting.notification_body.keys))
@current_setting.email_body.merge!(UserTemplateMessageSetting.init_email_body.except(*@current_setting.email_body.keys))
@current_setting = UserTemplateMessageSetting.build(@_observed_user.id) if @current_setting.nil? @current_setting = UserTemplateMessageSetting.build(@_observed_user.id) if @current_setting.nil?
end end

View File

@ -91,10 +91,9 @@ await octokit.request('GET /api/users/:login/messages.json')
类型|说明 类型|说明
--------- | ----------- --------- | -----------
|IssueAssigned | 有新指派给我的疑修 | |IssueAssigned | 有新指派给我的疑修 |
|IssueAssignerExpire | 我负责的疑修截止日期到达最后一天 | |IssueExpire | 我创建或负责的疑修截止日期到达最后一天 |
|IssueAtme | 在疑修中@我 | |IssueAtme | 在疑修中@我 |
|IssueChanged | 我创建或负责的疑修状态变更 | |IssueChanged | 我创建或负责的疑修状态变更 |
|IssueCreatorExpire | 我创建的疑修截止日期到达最后一天 |
|IssueDeleted | 我创建或负责的疑修删除 | |IssueDeleted | 我创建或负责的疑修删除 |
|IssueJournal | 我创建或负责的疑修有新的评论 | |IssueJournal | 我创建或负责的疑修有新的评论 |
|LoginIpTip | 登录异常提示 | |LoginIpTip | 登录异常提示 |
@ -109,6 +108,7 @@ await octokit.request('GET /api/users/:login/messages.json')
|ProjectLeft | 账号被移出项目 | |ProjectLeft | 账号被移出项目 |
|ProjectMemberJoined | 我管理的仓库有成员加入 | |ProjectMemberJoined | 我管理的仓库有成员加入 |
|ProjectMemberLeft | 我管理的仓库有成员移出 | |ProjectMemberLeft | 我管理的仓库有成员移出 |
|ProjectMilestoneCompleted | 我管理的仓库有里程碑完成度100% |
|ProjectMilestone | 我管理的仓库有新的里程碑 | |ProjectMilestone | 我管理的仓库有新的里程碑 |
|ProjectPraised | 我管理的仓库被点赞 | |ProjectPraised | 我管理的仓库被点赞 |
|ProjectPullRequest | 我管理/关注的仓库有新的合并请求 | |ProjectPullRequest | 我管理/关注的仓库有新的合并请求 |

View File

@ -3,8 +3,7 @@ class DelayExpiredIssueJob < ApplicationJob
def perform def perform
Issue.where(due_date: Date.today + 1.days).find_each do |issue| Issue.where(due_date: Date.today + 1.days).find_each do |issue|
SendTemplateMessageJob.perform_later('IssueAssignerExpire', issue.id) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('IssueExpire', issue.id) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('IssueCreatorExpire', issue.id) if Site.has_notice_menu?
end end
end end

View File

@ -24,13 +24,6 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::IssueAssigned.get_email_message_content(receiver, operator, issue) 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) Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end 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' when 'IssueAtme'
receivers, operator_id, issue_id = args[0], args[1], args[2] receivers, operator_id, issue_id = args[0], args[1], args[2]
operator = User.find_by_id(operator_id) operator = User.find_by_id(operator_id)
@ -52,12 +45,12 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::IssueChanged.get_email_message_content(receiver, operator, issue, change_params) receivers_email_string, email_title, email_content = MessageTemplate::IssueChanged.get_email_message_content(receiver, operator, issue, change_params)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end end
when 'IssueCreatorExpire' when 'IssueExpire'
issue_id = args[0] issue_id = args[0]
issue = Issue.find_by_id(issue_id) issue = Issue.find_by_id(issue_id)
return unless issue.present? return unless issue.present?
receivers = User.where(id: issue&.author_id) receivers = User.where(id: [issue&.assigned_to_id, issue&.author_id])
receivers_string, content, notification_url = MessageTemplate::IssueCreatorExpire.get_message_content(receivers, issue) receivers_string, content, notification_url = MessageTemplate::IssueExpire.get_message_content(receivers, issue)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {issue_id: issue.id}) Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {issue_id: issue.id})
when 'IssueDeleted' when 'IssueDeleted'
operator_id, issue_title, issue_assigned_to_id, issue_author_id = args[0], args[1], args[2], args[3] operator_id, issue_title, issue_assigned_to_id, issue_author_id = args[0], args[1], args[2], args[3]
@ -94,6 +87,14 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::OrganizationLeft.get_email_message_content(receiver, organization) 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) Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end end
when 'ProjectForked'
operator_id, project_id = args[0], args[1]
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::ProjectForked.get_message_content(receivers, operator, project)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id})
when 'ProjectIssue' when 'ProjectIssue'
operator_id, issue_id = args[0], args[1] operator_id, issue_id = args[0], args[1]
operator = User.find_by_id(operator_id) operator = User.find_by_id(operator_id)
@ -163,6 +164,37 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::ProjectMemberLeft.get_email_message_content(receiver, user, project) 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) Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end end
when 'ProjectMilestoneCompleted'
milestone_id = args[0]
milestone = Version.find_by_id(milestone_id)
return unless milestone.present? && milestone&.project.present?
receivers = milestone&.project&.all_managers
receivers_string, content, notification_url = MessageTemplate::ProjectMilestoneCompleted.get_message_content(receivers, milestone)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {milestone_id: milestone_id})
receivers.find_each do |receiver|
receivers_email_string, email_title, email_content = MessageTemplate::ProjectMilestoneCompleted.get_email_message_content(receiver, milestone)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'ProjectMilestone'
milestone_id, operator_id = args[0], args[1]
milestone = Version.find_by_id(milestone_id)
operator = User.find_by_id(operator_id)
return unless milestone.present? && milestone&.project.present? && operator.present?
receivers = milestone&.project&.all_managers.where.not(id: operator_id)
receivers_string, content, notification_url = MessageTemplate::ProjectMilestone.get_message_content(receivers, operator, milestone)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {milestone_id: milestone_id, operator_id: operator_id})
receivers.find_each do |receiver|
receivers_email_string, email_title, email_content = MessageTemplate::ProjectMilestone.get_email_message_content(receiver, operator, milestone)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'ProjectPraised'
operator_id, project_id = args[0], args[1]
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::ProjectPraised.get_message_content(receivers, operator, project)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id})
when 'ProjectPullRequest' when 'ProjectPullRequest'
operator_id, pull_request_id = args[0], args[1] operator_id, pull_request_id = args[0], args[1]
operator = User.find_by_id(operator_id) operator = User.find_by_id(operator_id)

View File

@ -75,7 +75,7 @@ class Issue < ApplicationRecord
scope :issue_index_includes, ->{includes(:tracker, :priority, :version, :issue_status, :journals,:issue_tags,user: :user_extension)} scope :issue_index_includes, ->{includes(:tracker, :priority, :version, :issue_status, :journals,:issue_tags,user: :user_extension)}
scope :closed, ->{where(status_id: 5)} scope :closed, ->{where(status_id: 5)}
after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic
after_update :change_versions_count after_save :change_versions_count
after_destroy :update_closed_issues_count_in_project!, :decre_project_common, :decre_user_statistic, :decre_platform_statistic after_destroy :update_closed_issues_count_in_project!, :decre_project_common, :decre_user_statistic, :decre_platform_statistic
def incre_project_common def incre_project_common
@ -170,11 +170,25 @@ class Issue < ApplicationRecord
end end
def change_versions_count def change_versions_count
if self.version.present? && self.saved_change_to_status_id? if self.saved_change_to_fixed_version_id?
before_version = Version.find_by_id(self.fixed_version_id_before_last_save)
Rails.logger.info self.fixed_version_id_before_last_save
if before_version.present?
Rails.logger.info self.status_id
Rails.logger.info self.status_id_before_last_save
# 更改前状态为完成 或者 更改前后都为完成状态
if self.status_id_before_last_save == 5
percent = before_version.issues_count == 0 ? 0.0 : ((before_version.closed_issues_count - 1).to_f / before_version.issues_count)
before_version.update_attributes(closed_issues_count: (before_version.closed_issues_count - 1), percent: percent)
end
end
end
if self.version.present? && (self.saved_change_to_status_id? || self.saved_change_to_fixed_version_id?)
if self.status_id == 5 if self.status_id == 5
percent = self.version.issues_count == 0 ? 0.0 : ((self.version.closed_issues_count + 1).to_f / self.version.issues_count) percent = self.version.issues_count == 0 ? 0.0 : ((self.version.closed_issues_count + 1).to_f / self.version.issues_count)
self.version.update_attributes(closed_issues_count: (self.version.closed_issues_count + 1), percent: percent) self.version.update_attributes(closed_issues_count: (self.version.closed_issues_count + 1), percent: percent)
elsif self.status_id_before_last_save == 5 elsif self.status_id_before_last_save == 5 && !self.saved_change_to_fixed_version_id?
percent = self.version.issues_count == 0 ? 0.0 : ((self.version.closed_issues_count - 1).to_f / self.version.issues_count) percent = self.version.issues_count == 0 ? 0.0 : ((self.version.closed_issues_count - 1).to_f / self.version.issues_count)
self.version.update_attributes(closed_issues_count: (self.version.closed_issues_count - 1), percent: percent) self.version.update_attributes(closed_issues_count: (self.version.closed_issues_count - 1), percent: percent)
end end
@ -182,7 +196,7 @@ class Issue < ApplicationRecord
end end
def update_closed_issues_count_in_project! def update_closed_issues_count_in_project!
self.project.decrement!(:closed_issues_count) self.project.decrement!(:closed_issues_count) if self.status_id == 5
end end
end end

View File

@ -15,14 +15,16 @@
class MessageTemplate < ApplicationRecord class MessageTemplate < ApplicationRecord
def self.build_init_data def self.build_init_data
MessageTemplate::IssueAssignerExpire.destroy_all
MessageTemplate::IssueCreatorExpire.destroy_all
self.create(type: 'MessageTemplate::FollowedTip', sys_notice: '<b>{nickname}</b> 关注了你', notification_url: '{baseurl}/{login}') self.create(type: 'MessageTemplate::FollowedTip', sys_notice: '<b>{nickname}</b> 关注了你', notification_url: '{baseurl}/{login}')
email_html = File.read("#{email_template_html_dir}/issue_assigned.html") email_html = File.read("#{email_template_html_dir}/issue_assigned.html")
self.create(type: 'MessageTemplate::IssueAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个疑修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 指派给你一个疑修') self.create(type: 'MessageTemplate::IssueAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个疑修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 指派给你一个疑修')
self.create(type: 'MessageTemplate::IssueAssignerExpire', sys_notice: '您负责的疑修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueAtme', sys_notice: '<b>{nickname}</b> 在疑修 <b>{title}</b> 中@我', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') self.create(type: 'MessageTemplate::IssueAtme', sys_notice: '<b>{nickname}</b> 在疑修 <b>{title}</b> 中@我', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
email_html = File.read("#{email_template_html_dir}/issue_changed.html") email_html = File.read("#{email_template_html_dir}/issue_changed.html")
self.create(type: 'MessageTemplate::IssueChanged', sys_notice: '在项目 <b>{nickname2}/{repository}</b> 的疑修 <b>{title}</b> 中:{ifassigner}{nickname1}将负责人从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifstatus}{nickname1}将状态从 <b>{status1}</b> 修改为 <b>{status2}</b> {endstatus}{iftracker}{nickname1}将类型从 <b>{tracker1}</b> 修改为 <b>{tracker2}</b> {endtracker}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifdoneratio}{nickname1}将完成度从 <b>{doneratio1}</b> 修改为 <b>{doneratio2}</b> {enddoneratio}{ifbranch}{nickname1}将指定分支从 <b>{branch1}</b> 修改为 <b>{branch2}</b> {endbranch}{ifstartdate}{nickname1}将开始日期从 <b>{startdate1}</b> 修改为 <b>{startdate2}</b> {endstartdate}{ifduedate}{nickname1}将结束日期从 <b>{duedate1}</b> 修改为 <b>{duedate2}</b> {endduedate}', email: email_html, email_title: 'GitLink: 疑修 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') self.create(type: 'MessageTemplate::IssueChanged', sys_notice: '在项目 <b>{nickname2}/{repository}</b> 的疑修 <b>{title}</b> 中:{ifassigner}{nickname1}将负责人从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifstatus}{nickname1}将状态从 <b>{status1}</b> 修改为 <b>{status2}</b> {endstatus}{iftracker}{nickname1}将类型从 <b>{tracker1}</b> 修改为 <b>{tracker2}</b> {endtracker}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifdoneratio}{nickname1}将完成度从 <b>{doneratio1}</b> 修改为 <b>{doneratio2}</b> {enddoneratio}{ifbranch}{nickname1}将指定分支从 <b>{branch1}</b> 修改为 <b>{branch2}</b> {endbranch}{ifstartdate}{nickname1}将开始日期从 <b>{startdate1}</b> 修改为 <b>{startdate2}</b> {endstartdate}{ifduedate}{nickname1}将结束日期从 <b>{duedate1}</b> 修改为 <b>{duedate2}</b> {endduedate}', email: email_html, email_title: 'GitLink: 疑修 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueCreatorExpire', sys_notice: '您发布的疑修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') email_html = File.read("#{email_template_html_dir}/issue_expire.html")
self.create(type: 'MessageTemplate::IssueExpire', sys_notice: '疑修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: 疑修截止日期到达最后一天')
email_html = File.read("#{email_template_html_dir}/issue_deleted.html") email_html = File.read("#{email_template_html_dir}/issue_deleted.html")
self.create(type: 'MessageTemplate::IssueDeleted', sys_notice: '{nickname}已将疑修 <b>{title}</b> 删除', email: email_html, email_title: 'GitLink: 疑修 {title} 有状态变更', notification_url: '') self.create(type: 'MessageTemplate::IssueDeleted', sys_notice: '{nickname}已将疑修 <b>{title}</b> 删除', email: email_html, email_title: 'GitLink: 疑修 {title} 有状态变更', notification_url: '')
self.create(type: 'MessageTemplate::IssueJournal', sys_notice: '{nickname}评论疑修{title}<b>{notes}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}') self.create(type: 'MessageTemplate::IssueJournal', sys_notice: '{nickname}评论疑修{title}<b>{notes}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
@ -33,7 +35,7 @@ class MessageTemplate < ApplicationRecord
self.create(type: 'MessageTemplate::OrganizationLeft', sys_notice: '你已被移出 <b>{organization}</b> 组织', notification_url: '', email: email_html, email_title: 'GitLink: 你已被移出 {organization} 组织') self.create(type: 'MessageTemplate::OrganizationLeft', sys_notice: '你已被移出 <b>{organization}</b> 组织', notification_url: '', email: email_html, email_title: 'GitLink: 你已被移出 {organization} 组织')
self.create(type: 'MessageTemplate::ProjectDeleted', sys_notice: '你关注的仓库{nickname}/{repository}已被删除', notification_url: '') self.create(type: 'MessageTemplate::ProjectDeleted', sys_notice: '你关注的仓库{nickname}/{repository}已被删除', notification_url: '')
self.create(type: 'MessageTemplate::ProjectFollowed', sys_notice: '<b>{nickname}</b> 关注了你管理的仓库', notification_url: '{baseurl}/{login}') self.create(type: 'MessageTemplate::ProjectFollowed', sys_notice: '<b>{nickname}</b> 关注了你管理的仓库', notification_url: '{baseurl}/{login}')
self.create(type: 'MessageTemplate::ProjectForked', sys_notice: '<b>{nickname1}</b> 复刻了你管理的仓库{nickname1}/{repository1}到{nickname2}/{repository2}', notification_url: '{baseurl}/{owner}/{identifier}') self.create(type: 'MessageTemplate::ProjectForked', sys_notice: '<b>{nickname1}</b> 复刻了你管理的仓库 <b>{nickname2}/{repository}</b> 到 <b>{nickname1}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}')
email_html = File.read("#{email_template_html_dir}/project_issue.html") email_html = File.read("#{email_template_html_dir}/project_issue.html")
self.create(type: 'MessageTemplate::ProjectIssue', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 新建疑修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 新建了一个疑修') self.create(type: 'MessageTemplate::ProjectIssue', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 新建疑修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 新建了一个疑修')
email_html = File.read("#{email_template_html_dir}/project_joined.html") email_html = File.read("#{email_template_html_dir}/project_joined.html")
@ -44,8 +46,11 @@ class MessageTemplate < ApplicationRecord
self.create(type: 'MessageTemplate::ProjectMemberJoined', sys_notice: '<b>{nickname1}</b> 已加入项目 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: {nickname1} 已加入项目 {nickname2}/{repository}') self.create(type: 'MessageTemplate::ProjectMemberJoined', sys_notice: '<b>{nickname1}</b> 已加入项目 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: {nickname1} 已加入项目 {nickname2}/{repository}')
email_html = File.read("#{email_template_html_dir}/project_member_left.html") email_html = File.read("#{email_template_html_dir}/project_member_left.html")
self.create(type: 'MessageTemplate::ProjectMemberLeft', sys_notice: '<b>{nickname1}</b> 已被移出项目 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: {nickname1} 已被移出项目 {nickname2}/{repository}') self.create(type: 'MessageTemplate::ProjectMemberLeft', sys_notice: '<b>{nickname1}</b> 已被移出项目 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: {nickname1} 已被移出项目 {nickname2}/{repository}')
self.create(type: 'MessageTemplate::ProjectMilestone', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 创建了一个里程碑:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}') email_html = File.read("#{email_template_html_dir}/project_milestone.html")
self.create(type: 'MessageTemplate::ProjectPraised', sys_notice: '<b>{nickname}</b> 点赞了你管理的仓库', notification_url: '{baseurl}/{login}') self.create(type: 'MessageTemplate::ProjectMilestone', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 创建了一个里程碑:<b>{name}</b>', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 新建了一个里程碑')
email_html = File.read("#{email_template_html_dir}/project_milestone_completed.html")
self.create(type: 'MessageTemplate::ProjectMilestoneCompleted', sys_notice: '在 <b>{nickname}/{repository}</b> 仓库,里程碑 <b>{name}</b> 的完成度已达到100%', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}', email: email_html, email_title: 'GitLink: 仓库 {nickname}/{repository} 有里程碑已完成')
self.create(type: 'MessageTemplate::ProjectPraised', sys_notice: '<b>{nickname1}</b> 点赞了你管理的仓库 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{login}')
email_html = File.read("#{email_template_html_dir}/project_pull_request.html") email_html = File.read("#{email_template_html_dir}/project_pull_request.html")
self.create(type: 'MessageTemplate::ProjectPullRequest', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 提交了一个合并请求:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 提交了一个合并请求') self.create(type: 'MessageTemplate::ProjectPullRequest', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 提交了一个合并请求:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 提交了一个合并请求')
email_html = File.read("#{email_template_html_dir}/project_role.html") email_html = File.read("#{email_template_html_dir}/project_role.html")

View File

@ -1,29 +1,3 @@
# == 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 class MessageTemplate::IssueCreatorExpire < MessageTemplate
# MessageTemplate::IssueCreatorExpire.get_message_content(User.where(login: 'yystopf'), Issue.last) end
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

View File

@ -0,0 +1,60 @@
# == 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::IssueExpire < MessageTemplate
# MessageTemplate::IssueCreatorExpire.get_message_content(User.where(login: 'yystopf'), Issue.last)
def self.get_message_content(receiver, issue)
if receiver.user_template_message_setting.present?
return '', '', '' unless receiver.user_template_message_setting.email_body["Normal::IssueExpire"]
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
else
return '', '', ''
end
rescue => e
Rails.logger.info("MessageTemplate::IssueExpire.get_message_content [ERROR] #{e}")
return '', '', ''
end
def self.get_email_message_content(receiver, issue)
if receiver.user_template_message_setting.present?
return '', '', '' unless receiver.user_template_message_setting.email_body["Normal::IssueExpire"]
project = issue&.project
owner = project&.owner
content = email
content.gsub!('{receiver}', receiver&.real_name)
content.gsub!('{nickname}', owner&.real_name)
content.gsub!('{login}', 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
else
return '', '', ''
end
rescue => e
Rails.logger.info("MessageTemplate::IssueExpire.get_email_message_content [ERROR] #{e}")
return '', '', ''
end
end

View File

@ -12,11 +12,19 @@
# email_title :string(255) # email_title :string(255)
# #
# TODO 我管理的仓库被复刻 # 我管理的仓库被复刻
class MessageTemplate::ProjectForked < MessageTemplate class MessageTemplate::ProjectForked < MessageTemplate
# MessageTemplate::ProjectForked.get_message_content(User.where(login: 'yystopf')) # MessageTemplate::ProjectForked.get_message_content(User.where(login: 'yystopf'))
def self.get_message_content(receivers) def self.get_message_content(receivers, user, project)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["ManageProject::Forked"]
end
end
return '', '', '' if receivers.blank?
content = sys_notice.gsub('{nickname1}', user&.real_name).gsub('{nickname2}', project&.owner&.real_name).gsub('{repository}', project&.name)
url = notification_url.gsub('{login}', user&.login).gsub('{identifier}', project&.identifier)
return receivers_string(receivers), content, url return receivers_string(receivers), content, url
rescue => e rescue => e
Rails.logger.info("MessageTemplate::ProjectForked.get_message_content [ERROR] #{e}") Rails.logger.info("MessageTemplate::ProjectForked.get_message_content [ERROR] #{e}")

View File

@ -12,14 +12,57 @@
# email_title :string(255) # email_title :string(255)
# #
# TODO 我管理的仓库有新的里程碑 # 我管理的仓库有新的里程碑
class MessageTemplate::ProjectMilestone < MessageTemplate class MessageTemplate::ProjectMilestone < MessageTemplate
# MessageTemplate::ProjectMilestone.get_message_content(User.where(login: 'yystopf')) # MessageTemplate::ProjectMilestone.get_message_content(User.where(login: 'yystopf'))
def self.get_message_content(receivers) def self.get_message_content(receivers, operator, milestone)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["ManageProject::Milestone"]
end
end
return '', '', '' if receivers.blank?
project = milestone&.project
owner = project&.owner
content = sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).gsub('{repository}', project&.name).gsub('{name}', milestone&.name)
url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', milestone&.id.to_s)
return receivers_string(receivers), content, url return receivers_string(receivers), content, url
rescue => e rescue => e
Rails.logger.info("MessageTemplate::ProjectMilestone.get_message_content [ERROR] #{e}") Rails.logger.info("MessageTemplate::ProjectMilestone.get_message_content [ERROR] #{e}")
return '', '', '' return '', '', ''
end end
def self.get_email_message_content(receiver, operator, milestone)
if receiver.user_template_message_setting.present?
return '', '', '' unless receiver.user_template_message_setting.email_body["ManageProject::Milestone"]
project = milestone&.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}', milestone&.id.to_s)
content.gsub!('{name}', milestone&.name)
return receiver&.mail, title, content
else
return '', '', ''
end
rescue => e
Rails.logger.info("MessageTemplate::ProjectMilestone.get_email_message_content [ERROR] #{e}")
return '', '', ''
end
end end

View File

@ -0,0 +1,65 @@
# == 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::ProjectMilestoneCompleted < MessageTemplate
# MessageTemplate::ProjectMilestoneCompleted.get_message_content(User.where(login: 'yystopf'))
def self.get_message_content(receivers, milestone)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["ManageProject::MilestoneCompleted"]
end
end
return '', '', '' if receivers.blank?
project = milestone&.project
owner = project&.owner
content = sys_notice.gsub('{nickname}', owner&.real_name).gsub('{repository}', project&.name).gsub('{name}', milestone&.name)
url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', milestone&.id.to_s)
return receivers_string(receivers), content, url
rescue => e
Rails.logger.info("MessageTemplate::ProjectMilestoneCompleted.get_message_content [ERROR] #{e}")
return '', '', ''
end
def self.get_email_message_content(receiver, milestone)
if receiver.user_template_message_setting.present?
return '', '', '' unless receiver.user_template_message_setting.email_body["ManageProject::MilestoneCompleted"]
project = milestone&.project
owner = project&.owner
title = email_title
title.gsub!('{nickname}', owner&.real_name)
title.gsub!('{repository}', project&.name)
content = email
content.gsub!('{receiver}', receiver&.real_name)
content.gsub!('{baseurl}', base_url)
content.gsub!('{nickname}', owner&.real_name)
content.gsub!('{repository}', project&.name)
content.gsub!('{login}', owner&.login)
content.gsub!('{identifier}', project&.identifier)
content.gsub!('{id}', milestone&.id.to_s)
content.gsub!('{name}', milestone&.name)
return receiver&.mail, title, content
else
return '', '', ''
end
rescue => e
Rails.logger.info("MessageTemplate::ProjectMilestoneCompleted.get_email_message_content [ERROR] #{e}")
return '', '', ''
end
end

View File

@ -12,11 +12,19 @@
# email_title :string(255) # email_title :string(255)
# #
# TODO 我管理的仓库被点赞 # 我管理的仓库被点赞
class MessageTemplate::ProjectPraised < MessageTemplate class MessageTemplate::ProjectPraised < MessageTemplate
# MessageTemplate::ProjectPraised.get_message_content(User.where(login: 'yystopf')) # MessageTemplate::ProjectPraised.get_message_content(User.where(login: 'yystopf'))
def self.get_message_content(receivers) def self.get_message_content(receivers, user, project)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["ManageProject::Praised"]
end
end
return '', '', '' if receivers.blank?
content = sys_notice.gsub('{nickname1}', user&.real_name).gsub('{nickname2}', project&.owner&.real_name).gsub('{repository}', project&.name)
url = notification_url.gsub('{login}', user&.login)
return receivers_string(receivers), content, url return receivers_string(receivers), content, url
rescue => e rescue => e
Rails.logger.info("MessageTemplate::ProjectPraised.get_message_content [ERROR] #{e}") Rails.logger.info("MessageTemplate::ProjectPraised.get_message_content [ERROR] #{e}")

View File

@ -22,6 +22,7 @@ class TemplateMessageSetting < ApplicationRecord
end end
def self.build_init_data def self.build_init_data
TemplateMessageSetting.destroy_all
TemplateMessageSetting::CreateOrAssign.build_init_data TemplateMessageSetting::CreateOrAssign.build_init_data
TemplateMessageSetting::ManageProject.build_init_data TemplateMessageSetting::ManageProject.build_init_data
TemplateMessageSetting::Normal.build_init_data TemplateMessageSetting::Normal.build_init_data

View File

@ -27,5 +27,6 @@ class TemplateMessageSetting::CreateOrAssign < TemplateMessageSetting
def self.build_init_data def self.build_init_data
self.find_or_create_by(name: "疑修状态变更", key: "IssueChanged") self.find_or_create_by(name: "疑修状态变更", key: "IssueChanged")
self.find_or_create_by(name: "合并请求状态变更", key: "PullRequestChanged") self.find_or_create_by(name: "合并请求状态变更", key: "PullRequestChanged")
self.find_or_create_by(name: "疑修截止日期到达最后一天", key: "IssueExpire", notification_disabled: false)
end end
end end

View File

@ -29,5 +29,9 @@ class TemplateMessageSetting::ManageProject < TemplateMessageSetting
self.find_or_create_by(name: "有新的合并请求", key: "PullRequest") self.find_or_create_by(name: "有新的合并请求", key: "PullRequest")
self.find_or_create_by(name: "有成员变动", key: "Member") self.find_or_create_by(name: "有成员变动", key: "Member")
self.find_or_create_by(name: "仓库设置被更改", key: "SettingChanged") self.find_or_create_by(name: "仓库设置被更改", key: "SettingChanged")
self.find_or_create_by(name: "被点赞", key: "Praised", notification_disabled: false, email_disabled: true)
self.find_or_create_by(name: "被fork", key: "Forked", notification_disabled: false, email_disabled: true)
self.find_or_create_by(name: "有新的里程碑", key: "Milestone", notification_disabled: false)
self.find_or_create_by(name: "有里程碑已完成", key: "MilestoneCompleted", notification_disabled: false)
end end
end end

View File

@ -35,10 +35,15 @@ class UserTemplateMessageSetting < ApplicationRecord
"Normal::PullRequestAssigned": true, "Normal::PullRequestAssigned": true,
"CreateOrAssign::IssueChanged": true, "CreateOrAssign::IssueChanged": true,
"CreateOrAssign::PullRequestChanged": true, "CreateOrAssign::PullRequestChanged": true,
"CreateOrAssign::IssueExpire": true,
"ManageProject::Issue": true, "ManageProject::Issue": true,
"ManageProject::PullRequest": true, "ManageProject::PullRequest": true,
"ManageProject::Member": true, "ManageProject::Member": true,
"ManageProject::SettingChanged": true, "ManageProject::SettingChanged": true,
"ManageProject::Praised": true,
"ManageProject::Forked": true,
"ManageProject::Milestone": true,
"ManageProject::MilestoneCompleted": true,
}.stringify_keys! }.stringify_keys!
end end
@ -51,10 +56,15 @@ class UserTemplateMessageSetting < ApplicationRecord
"Normal::PullRequestAssigned": false, "Normal::PullRequestAssigned": false,
"CreateOrAssign::IssueChanged": false, "CreateOrAssign::IssueChanged": false,
"CreateOrAssign::PullRequestChanged": false, "CreateOrAssign::PullRequestChanged": false,
"CreateOrAssign::IssueExpire": false,
"ManageProject::Issue": false, "ManageProject::Issue": false,
"ManageProject::PullRequest": false, "ManageProject::PullRequest": false,
"ManageProject::Member": false, "ManageProject::Member": false,
"ManageProject::SettingChanged": false, "ManageProject::SettingChanged": false,
"ManageProject::Praised": false,
"ManageProject::Forked": false,
"ManageProject::Milestone": false,
"ManageProject::MilestoneCompleted": false,
}.stringify_keys! }.stringify_keys!
end end

View File

@ -40,8 +40,19 @@ class Version < ApplicationRecord
# issues.select(:id,:status_id).where(status_id: 5).size # issues.select(:id,:status_id).where(status_id: 5).size
# end # end
after_create :send_create_message_to_notice_system
after_save :send_update_message_to_notice_system
def version_user def version_user
User.select(:login, :lastname,:firstname, :nickname)&.find_by_id(self.user_id) User.select(:login, :lastname,:firstname, :nickname)&.find_by_id(self.user_id)
end end
private
def send_create_message_to_notice_system
SendTemplateMessageJob.perform_later('ProjectMilestone', self.id, self.user_id) if Site.has_notice_menu?
end
def send_update_message_to_notice_system
SendTemplateMessageJob.perform_later('ProjectMilestoneCompleted', self.id) if Site.has_notice_menu? && self.percent == 1.0
end
end end

View File

@ -35,6 +35,8 @@ class Projects::ForkService < ApplicationService
ForkUser.create(project_id: @project.id, fork_project_id: clone_project.id, user_id: clone_project.user_id) ForkUser.create(project_id: @project.id, fork_project_id: clone_project.id, user_id: clone_project.user_id)
clone_project clone_project
SendTemplateMessageJob.perform_later('ProjectForked', @target_owner.id, @project.id) if Site.has_notice_menu?
end end
rescue => e rescue => e
puts "clone project service error: #{e.message}" puts "clone project service error: #{e.message}"

View File

@ -1141,8 +1141,8 @@ Success — a happy kitten is an authenticated kitten!
<td>有新指派给我的疑修</td> <td>有新指派给我的疑修</td>
</tr> </tr>
<tr> <tr>
<td>IssueAssignerExpire</td> <td>IssueExpire</td>
<td>我负责的疑修截止日期到达最后一天</td> <td>创建或负责的疑修截止日期到达最后一天</td>
</tr> </tr>
<tr> <tr>
<td>IssueAtme</td> <td>IssueAtme</td>
@ -1153,10 +1153,6 @@ Success — a happy kitten is an authenticated kitten!
<td>我创建或负责的疑修状态变更</td> <td>我创建或负责的疑修状态变更</td>
</tr> </tr>
<tr> <tr>
<td>IssueCreatorExpire</td>
<td>我创建的疑修截止日期到达最后一天</td>
</tr>
<tr>
<td>IssueDeleted</td> <td>IssueDeleted</td>
<td>我创建或负责的疑修删除</td> <td>我创建或负责的疑修删除</td>
</tr> </tr>
@ -1213,6 +1209,10 @@ Success — a happy kitten is an authenticated kitten!
<td>我管理的仓库有成员移出</td> <td>我管理的仓库有成员移出</td>
</tr> </tr>
<tr> <tr>
<td>ProjectMilestoneCompleted</td>
<td>我管理的仓库有里程碑完成度100%</td>
</tr>
<tr>
<td>ProjectMilestone</td> <td>ProjectMilestone</td>
<td>我管理的仓库有新的里程碑</td> <td>我管理的仓库有新的里程碑</td>
</tr> </tr>

View File

@ -0,0 +1,47 @@
<html>
<head>
<title>疑修截止日期到达最后一天</title>
<style type="text/css">
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{ margin:0; padding:0;}
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体"; font-size:12px;line-height:1.5; background:#eaebec;}
div,img,tr,td,table{ border:0;}
table,tr,td{border:0;}
ol,ul,li{ list-style-type:none}
.new_content{ background:#fff; width: 100%;}
.email-page-link{ }
.email-link-top{ }
.c_white{ color:#fff;}
.email-link-con{ }
.email-link-line{ }
.email-link-footer{ padding:15px; color:#333; line-height: 1.9; }
.c_grey02{ color: #888;}
.fb{ font-weight: normal;}
.f14{ }
</style>
</head>
<body style="background:#fff;">
<div class="new_content">
<div style="width: 598px; background:#fff; margin:20px auto;">
<div style="height:50px; width: 578px; background:#3b94d6; padding:9px 10px 6px;border:1px solid #ddd; border-bottom:none;">
<a href="{baseurl}"><img src="{baseurl}/images/email_logo.png" height="45" ></a>
<p style="color:#fff; float:right; margin-top:15px;">确实开源,协同创新</p>
<div style="clear:both; overflow:hidden;"></div>
</div>
<div style="width: 558px; border-left:1px solid #ddd;border-right:1px solid #ddd; background:#fff; padding:20px; color:#333; line-height: 1.9;">
<p style="font-size: 14px; color:#333;">
{receiver},您好!<br/>
疑修 <a href="{baseurl}/{login}/{identifier}/issues/{id}" style="font-weight:bold;color:#3b94d6;">{title}</a> 已临近截止日期,请尽快处理<br/>
</p>
<div style="width: 100%; border-top: 1px solid #ddd; margin:10px 0;"></div>
</div>
<div style="padding:20px; color:#333; line-height: 1.9;background: #eee;border:1px solid #ddd; border-top:none; width: 558px;">
<p style="color:#888; float:left;">如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见<br/>
QQ群1071514693</p>
<p style="color:#888; float:right;font-weight: bold;font-size: 16px;">GitLink团队</p>
<div style="clear:both; overflow:hidden;"></div>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,47 @@
<html>
<head>
<title>管理的仓库有新的里程碑</title>
<style type="text/css">
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{ margin:0; padding:0;}
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体"; font-size:12px;line-height:1.5; background:#eaebec;}
div,img,tr,td,table{ border:0;}
table,tr,td{border:0;}
ol,ul,li{ list-style-type:none}
.new_content{ background:#fff; width: 100%;}
.email-page-link{ }
.email-link-top{ }
.c_white{ color:#fff;}
.email-link-con{ }
.email-link-line{ }
.email-link-footer{ padding:15px; color:#333; line-height: 1.9; }
.c_grey02{ color: #888;}
.fb{ font-weight: normal;}
.f14{ }
</style>
</head>
<body style="background:#fff;">
<div class="new_content">
<div style="width: 598px; background:#fff; margin:20px auto;">
<div style="height:50px; width: 578px; background:#3b94d6; padding:9px 10px 6px;border:1px solid #ddd; border-bottom:none;">
<a href="{baseurl}"><img src="{baseurl}/images/email_logo.png" height="45" ></a>
<p style="color:#fff; float:right; margin-top:15px;">确实开源,协同创新</p>
<div style="clear:both; overflow:hidden;"></div>
</div>
<div style="width: 558px; border-left:1px solid #ddd;border-right:1px solid #ddd; background:#fff; padding:20px; color:#333; line-height: 1.9;">
<p style="font-size: 14px; color:#333;">
{receiver},您好!<br/>
{nickname1}在仓库 <a href="{baseurl}/{login}/{identifier}" style="font-weight:bold;color:#3b94d6;">{nickname2}/{repository}</a> 新建了一个里程碑:<a href="{baseurl}/{login}/{identifier}/milestones/{id}" style="font-weight:bold;color:#3b94d6;">{name}</a><br/>
</p>
<div style="width: 100%; border-top: 1px solid #ddd; margin:10px 0;"></div>
</div>
<div style="padding:20px; color:#333; line-height: 1.9;background: #eee;border:1px solid #ddd; border-top:none; width: 558px;">
<p style="color:#888; float:left;">如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见<br/>
QQ群1071514693</p>
<p style="color:#888; float:right;font-weight: bold;font-size: 16px;">GitLink团队</p>
<div style="clear:both; overflow:hidden;"></div>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,47 @@
<html>
<head>
<title>管理的仓库有里程碑已完成</title>
<style type="text/css">
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{ margin:0; padding:0;}
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体"; font-size:12px;line-height:1.5; background:#eaebec;}
div,img,tr,td,table{ border:0;}
table,tr,td{border:0;}
ol,ul,li{ list-style-type:none}
.new_content{ background:#fff; width: 100%;}
.email-page-link{ }
.email-link-top{ }
.c_white{ color:#fff;}
.email-link-con{ }
.email-link-line{ }
.email-link-footer{ padding:15px; color:#333; line-height: 1.9; }
.c_grey02{ color: #888;}
.fb{ font-weight: normal;}
.f14{ }
</style>
</head>
<body style="background:#fff;">
<div class="new_content">
<div style="width: 598px; background:#fff; margin:20px auto;">
<div style="height:50px; width: 578px; background:#3b94d6; padding:9px 10px 6px;border:1px solid #ddd; border-bottom:none;">
<a href="{baseurl}"><img src="{baseurl}/images/email_logo.png" height="45" ></a>
<p style="color:#fff; float:right; margin-top:15px;">确实开源,协同创新</p>
<div style="clear:both; overflow:hidden;"></div>
</div>
<div style="width: 558px; border-left:1px solid #ddd;border-right:1px solid #ddd; background:#fff; padding:20px; color:#333; line-height: 1.9;">
<p style="font-size: 14px; color:#333;">
{receiver},您好!<br/>
<a href="{baseurl}/{login}/{identifier}" style="font-weight:bold;color:#3b94d6;">{nickname}/{repository}</a> 里程碑<a href="{baseurl}/{login}/{identifier}/milestones/{id}" style="font-weight:bold;color:#3b94d6;">{name}</a>的完成度已达到100%<br/>
</p>
<div style="width: 100%; border-top: 1px solid #ddd; margin:10px 0;"></div>
</div>
<div style="padding:20px; color:#333; line-height: 1.9;background: #eee;border:1px solid #ddd; border-top:none; width: 558px;">
<p style="color:#888; float:left;">如果您在使用中有任何的疑问和建议,欢迎您给我们反馈意见<br/>
QQ群1071514693</p>
<p style="color:#888; float:right;font-weight: bold;font-size: 16px;">GitLink团队</p>
<div style="clear:both; overflow:hidden;"></div>
</div>
</div>
</div>
</body>
</html>