From b85913e4850b2e5fd5bf73444c8eca0de08f7361 Mon Sep 17 00:00:00 2001 From: yystopf Date: Fri, 17 Feb 2023 16:11:39 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E7=96=91=E4=BF=AE?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E8=AE=B0=E5=BD=95=E3=80=81=E8=AF=84=E8=AE=BA?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=8E=A5=E5=8F=A3=E4=BB=A5=E5=8F=8A=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E7=96=91=E4=BF=AE=E6=97=A0=E6=B3=95=E4=BA=A7=E7=94=9F?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E8=AE=B0=E5=BD=95=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/v1/issues/journals_controller.rb | 39 ++++ app/controllers/api/v1/issues_controller.rb | 51 +++-- app/models/journal.rb | 78 +++++++ .../api/v1/issues/batch_delete_service.rb | 13 +- app/services/api/v1/issues/create_service.rb | 19 +- app/services/api/v1/issues/delete_service.rb | 12 +- .../api/v1/issues/journals/create_service.rb | 48 ++++ .../api/v1/issues/journals/list_service.rb | 52 +++++ app/services/api/v1/issues/list_service.rb | 1 - app/services/api/v1/issues/update_service.rb | 213 +++++++++++------- app/services/application_service.rb | 9 + app/views/api/v1/issues/index.json.jbuilder | 4 +- .../journals/_children_detail.json.jbuilder | 17 ++ .../v1/issues/journals/_detail.json.jbuilder | 20 ++ .../v1/issues/journals/create.json.jbuilder | 1 + .../v1/issues/journals/index.json.jbuilder | 4 + config/routes/api.rb | 8 + 17 files changed, 448 insertions(+), 141 deletions(-) create mode 100644 app/controllers/api/v1/issues/journals_controller.rb create mode 100644 app/services/api/v1/issues/journals/create_service.rb create mode 100644 app/services/api/v1/issues/journals/list_service.rb create mode 100644 app/views/api/v1/issues/journals/_children_detail.json.jbuilder create mode 100644 app/views/api/v1/issues/journals/_detail.json.jbuilder create mode 100644 app/views/api/v1/issues/journals/create.json.jbuilder create mode 100644 app/views/api/v1/issues/journals/index.json.jbuilder diff --git a/app/controllers/api/v1/issues/journals_controller.rb b/app/controllers/api/v1/issues/journals_controller.rb new file mode 100644 index 000000000..c3185a755 --- /dev/null +++ b/app/controllers/api/v1/issues/journals_controller.rb @@ -0,0 +1,39 @@ +class Api::V1::Issues::JournalsController < Api::V1::IssuesController + + before_action :require_public_and_member_above, only: [:index, :create, :destroy] + before_action :load_issue, only: [:index, :create, :destroy] + before_action :load_journal, only: [:destroy] + + def index + @object_results = Api::V1::Issues::Journals::ListService.call(@issue, query_params, current_user) + @journals = kaminari_paginate(@object_results) + end + + def create + @object_result = Api::V1::Issues::Journals::CreateService.call(@issue, journal_params, current_user) + end + + def destroy + if @journal.destroy! + render_ok + else + render_error("删除评论失败!") + end + end + + private + + def query_params + params.permit(:category, :keyword, :sort_by, :sort_direction) + end + + def journal_params + params.permit(:notes, :parent_id, :attachment_ids => []) + end + + def load_journal + @journal = @issue.journals.find_by_id(params[:id]) + return render_not_found("评论不存在!") unless @journal.present? + end + +end \ No newline at end of file diff --git a/app/controllers/api/v1/issues_controller.rb b/app/controllers/api/v1/issues_controller.rb index 567ef6b3b..d1f8a83a1 100644 --- a/app/controllers/api/v1/issues_controller.rb +++ b/app/controllers/api/v1/issues_controller.rb @@ -4,6 +4,9 @@ class Api::V1::IssuesController < Api::V1::BaseController def index @object_results = Api::V1::Issues::ListService.call(@project, query_params, current_user) + @opened_issues_count = @object_results.opened.size + @closed_issues_count = @object_results.closed.size + @issues = kaminari_paginate(@object_results) end @@ -49,6 +52,31 @@ class Api::V1::IssuesController < Api::V1::BaseController end end + protected + + def load_issue + @issue = @project.issues.where(project_issues_index: params[:id]).where.not(id: params[:id]).take || Issue.find_by_id(params[:id]) + if @issue.blank? + render_not_found("疑修不存在!") + elsif @issue.present? && @issue.is_lock &&!(@project.member?(current_user) || current_user.admin?) + render_forbidden("您没有权限操作!") + end + end + + def load_issues + return render_error("请输入正确的ID数组!") unless params[:ids].is_a?(Array) + params[:ids].each do |id| + @issue = Issue.find_by_id(id) + if @issue.blank? + return render_not_found("ID为#{id}的疑修不存在!") + elsif @issue.present? && @issue.is_lock &&!(@project.member?(current_user) || current_user.admin?) + return render_forbidden("ID为#{id}的疑修您没有权限操作!") + end + end + @issues = Issue.where(id: params[:ids]) + end + + private def query_params @@ -79,27 +107,4 @@ class Api::V1::IssuesController < Api::V1::BaseController :issue_tag_ids => [], :assigner_ids => []) end - - def load_issue - @issue = @project.issues.where(project_issues_index: params[:id]).where.not(id: params[:id]).take || Issue.find_by_id(params[:id]) - if @issue.blank? - render_not_found("疑修不存在!") - elsif @issue.present? && @issue.is_lock &&!(@project.member?(current_user) || current_user.admin?) - render_forbidden("您没有权限操作!") - end - end - - def load_issues - return render_error("请输入正确的ID数组!") unless params[:ids].is_a?(Array) - params[:ids].each do |id| - @issue = Issue.find_by_id(id) - if @issue.blank? - return render_not_found("ID为#{id}的疑修不存在!") - elsif @issue.present? && @issue.is_lock &&!(@project.member?(current_user) || current_user.admin?) - return render_forbidden("ID为#{id}的疑修您没有权限操作!") - end - end - @issues = Issue.where(id: params[:ids]) - end - end \ No newline at end of file diff --git a/app/models/journal.rb b/app/models/journal.rb index 20297dd99..382ebd017 100644 --- a/app/models/journal.rb +++ b/app/models/journal.rb @@ -40,8 +40,11 @@ class Journal < ApplicationRecord belongs_to :journalized, polymorphic: true belongs_to :review, optional: true belongs_to :resolveer, class_name: 'User', foreign_key: :resolveer_id, optional: true + belongs_to :parent_journal, class_name: 'Journal', foreign_key: :parent_id, optional: true + belongs_to :reply_journal, class_name: 'Journal', foreign_key: :reply_id, optional: true has_many :journal_details, :dependent => :delete_all has_many :attachments, as: :container, dependent: :destroy + has_many :first_ten_children_journals, -> { order(created_on: :asc).limit(10)}, class_name: 'Journal', foreign_key: :parent_id has_many :children_journals, class_name: 'Journal', foreign_key: :parent_id scope :journal_includes, ->{includes(:user, :journal_details, :attachments)} @@ -54,6 +57,81 @@ class Journal < ApplicationRecord self.notes.blank? && self.journal_details.present? end + def operate_content + content = "" + detail = self.journal_details.take + case detail.property + when 'issue' + return "创建了疑修" + when 'attachment' + old_value = Attachment.where(id: detail.old_value.split(",")).pluck(:filename).join("、") + new_value = Attachment.where(id: detail.value.split(",")).pluck(:filename).join("、") + if old_value.nil? || old_value.blank? + content += "添加了#{new_value}附件" + else + new_value = "无" if new_value.blank? + content += "将附件由#{old_value}更改为#{new_value}" + end + when 'issue_tag' + old_value = IssueTag.where(id: detail.old_value.split(",")).pluck(:name, :color).map{|t| "#{t[0]}"}.join(" ") + new_value = IssueTag.where(id: detail.value.split(",")).pluck(:name, :color).map{|t| "#{t[0]}"}.join(" ") + if old_value.nil? || old_value.blank? + content += "添加了#{new_value}标记" + else + new_value = "无" if new_value.blank? + content += "将标记由#{old_value}更改为#{new_value}" + end + when 'assigner' + old_value = User.where(id: detail.old_value.split(",")).pluck(:nickname).join("、") + new_value = User.where(id: detail.value.split(",")).pluck(:nickname).join("、") + if old_value.nil? || old_value.blank? + content += "添加负责人#{new_value}" + else + new_value = "无" if new_value.blank? + content += "将负责人由#{old_value}更改为#{new_value}" + end + when 'attr' + content = "将" + case detail.prop_key + when 'subject' + return "修改了标题" + when 'description' + return "修改了描述" + when 'status_id' + old_value = IssueStatus.find_by_id(detail.old_value)&.name + new_value = IssueStatus.find_by_id(detail.value)&.name + content += "状态" + when 'priority_id' + old_value = IssuePriority.find_by_id(detail.old_value)&.name + new_value = IssuePriority.find_by_id(detail.value)&.name + content += "优先级" + when 'fixed_version_id' + old_value = Version.find_by_id(detail.old_value)&.name + new_value = Version.find_by_id(detail.value)&.name + content += "里程碑" + when 'branch_name' + old_value = detail.old_value + new_value = detail.value + content += "关联分支" + when 'start_date' + old_value = detail.old_value + new_value = detail.value + content += "开始日期" + when 'due_date' + old_value = detail.old_value + new_value = detail.value + content += "结束日期" + end + if old_value.nil? || old_value.blank? + content += "设置为#{new_value}" + else + new_value = "无" if new_value.blank? + content += "由#{old_value}更改为#{new_value}" + end + end + + end + def journal_content send_details = [] if self.is_journal_detail? diff --git a/app/services/api/v1/issues/batch_delete_service.rb b/app/services/api/v1/issues/batch_delete_service.rb index 133f098cd..45821b373 100644 --- a/app/services/api/v1/issues/batch_delete_service.rb +++ b/app/services/api/v1/issues/batch_delete_service.rb @@ -13,7 +13,7 @@ class Api::V1::Issues::BatchDeleteService < ApplicationService def call raise Error, errors.full_messages.join(", ") unless valid? - try_lock # 开始写数据,加锁 + try_lock("Api::V1::Issues::DeleteService:#{project.id}") # 开始写数据,加锁 delete_issues @@ -25,7 +25,7 @@ class Api::V1::Issues::BatchDeleteService < ApplicationService end end - unlock + unlock("Api::V1::Issues::DeleteService:#{project.id}") return true end @@ -35,13 +35,4 @@ class Api::V1::Issues::BatchDeleteService < ApplicationService def delete_issues raise Error, "批量删除疑修失败!" unless @issues.destroy_all end - - def try_lock - raise Error, "请稍后再试!" unless $redis_cache.set("Api::V1::Issues::BatchDeleteService:#{project.id}", 1, nx: true, ex: 60.seconds) - end - - def unlock - $redis_cache.del("Api::V1::Issues::BatchDeleteService:#{project.id}") - end - end \ No newline at end of file diff --git a/app/services/api/v1/issues/create_service.rb b/app/services/api/v1/issues/create_service.rb index e87745950..f5d9c7fa6 100644 --- a/app/services/api/v1/issues/create_service.rb +++ b/app/services/api/v1/issues/create_service.rb @@ -43,10 +43,11 @@ class Api::V1::Issues::CreateService < ApplicationService load_issue_tags(issue_tag_ids) unless issue_tag_ids.blank? load_atme_receivers(receivers_login) unless receivers_login.blank? - try_lock # 开始写数据,加锁 + try_lock("Api::V1::Issues::CreateService:#{project.id}") # 开始写数据,加锁 @created_issue = Issue.new(issue_attributes) build_author_participants build_assigner_participants unless assigner_ids.blank? + build_atme_participants if @atme_receivers.present? build_issue_journal_details build_issue_project_trends @created_issue.attachments = @attachments unless attachment_ids.blank? @@ -64,7 +65,7 @@ class Api::V1::Issues::CreateService < ApplicationService SendTemplateMessageJob.perform_later('ProjectIssue', current_user.id, @issue&.id) end - unlock # 结束写数据,解锁 + unlock("Api::V1::Issues::CreateService:#{project.id}") # 结束写数据,解锁 end return @created_issue @@ -104,6 +105,12 @@ class Api::V1::Issues::CreateService < ApplicationService end end + def build_atme_participants + atme_receivers.each do |receiver| + @created_issue.issue_participants.new({participant_type: "atme", participant_id: receiver.id}) + end + end + def build_issue_project_trends @created_issue.project_trends.new({user_id: current_user.id, project_id: @project.id, action_type: "create"}) @created_issue.project_trends.new({user_id: current_user.id, project_id: @project.id, action_type: ProjectTrend::CLOSE}) if status_id.to_i == 5 @@ -113,12 +120,4 @@ class Api::V1::Issues::CreateService < ApplicationService journal = @created_issue.journals.new({user_id: current_user.id}) journal.journal_details.new({property: "issue", prop_key: 1, old_value: '', value: ''}) end - - def try_lock - raise Error, "请稍后再试!" unless $redis_cache.set("Api::V1::Issues::CreateService:#{project.id}", 1, nx: true, ex: 60.seconds) - end - - def unlock - $redis_cache.del("Api::V1::Issues::CreateService:#{project.id}") - end end \ No newline at end of file diff --git a/app/services/api/v1/issues/delete_service.rb b/app/services/api/v1/issues/delete_service.rb index e6429390e..a34fdced6 100644 --- a/app/services/api/v1/issues/delete_service.rb +++ b/app/services/api/v1/issues/delete_service.rb @@ -13,7 +13,7 @@ class Api::V1::Issues::DeleteService < ApplicationService def call raise Error, errors.full_messages.join(", ") unless valid? - try_lock # 开始写数据,加锁 + try_lock("Api::V1::Issues::DeleteService:#{project.id}") # 开始写数据,加锁 delete_issue @@ -23,7 +23,7 @@ class Api::V1::Issues::DeleteService < ApplicationService SendTemplateMessageJob.perform_later('IssueDeleted', current_user.id, @issue&.subject, @issue.assigners.pluck(:id), @issue.author_id) end - unlock + unlock("Api::V1::Issues::DeleteService:#{project.id}") return true end @@ -34,12 +34,4 @@ class Api::V1::Issues::DeleteService < ApplicationService raise Error, "删除疑修失败!" unless issue.destroy! end - def try_lock - raise Error, "请稍后再试!" unless $redis_cache.set("Api::V1::Issues::DeleteService:#{project.id}", 1, nx: true, ex: 60.seconds) - end - - def unlock - $redis_cache.del("Api::V1::Issues::DeleteService:#{project.id}") - end - end \ No newline at end of file diff --git a/app/services/api/v1/issues/journals/create_service.rb b/app/services/api/v1/issues/journals/create_service.rb new file mode 100644 index 000000000..6fe096426 --- /dev/null +++ b/app/services/api/v1/issues/journals/create_service.rb @@ -0,0 +1,48 @@ +class Api::V1::Issues::Journals::CreateService < ApplicationService + include ActiveModel::Model + + attr_reader :issue, :current_user, :notes, :parent_id, :attachment_ids + + validates :issue, :current_user, presence: true + + def initialize(issue, params, current_user=nil) + @issue = issue + @notes = params[:notes] + @parent_id = params[:parent_id] + @attachment_ids = params[:attachment_ids] + @current_user = current_user + end + + def call + raise Error, errors.full_messages.join(", ") unless valid? + ActiveRecord::Base.transaction do + check_attachments(attachment_ids) unless attachment_ids.blank? + load_attachments(attachment_ids) unless attachment_ids.blank? + + try_lock("Api::V1::Issues::Journals::CreateService:#{@issue.id}") + @created_journal = Journal.new(journal_attributes) + + build_comment_participants + @created_journal.attachments = @attachments + + @created_journal.save! + unlock("Api::V1::Issues::Journals::CreateService:#{@issue.id}") + end + end + + private + + def journal_attributes + journal_attributes = { + notes: notes + } + + journal_attributes.merge!({parent_id: parent_id}) if parent_id.present? + + journal_attributes + end + + def build_comment_participants + @issue.issue_participants.new({participant_type: "commented", participant_id: current_user.id}) unless @issue.issue_participants.exists?(participant_type: "commented", participant_id: current_user.id) + end +end \ No newline at end of file diff --git a/app/services/api/v1/issues/journals/list_service.rb b/app/services/api/v1/issues/journals/list_service.rb new file mode 100644 index 000000000..02f709e55 --- /dev/null +++ b/app/services/api/v1/issues/journals/list_service.rb @@ -0,0 +1,52 @@ +class Api::V1::Issues::Journals::ListService < ApplicationService + + include ActiveModel::Model + + attr_reader :issue, :category, :keyword, :sort_by, :sort_direction + attr_accessor :queried_journals + + validates :category, inclusion: {in: %w(all comment operate), message: "请输入正确的Category"} + validates :sort_by, inclusion: {in: Journal.column_names, message: '请输入正确的SortBy'}, allow_blank: true + validates :sort_direction, inclusion: {in: %w(asc desc), message: '请输入正确的SortDirection'}, allow_blank: true + + def initialize(issue, params, current_user=nil) + @issue = issue + @keyword = params[:keyword] + @category = params[:category] || 'all' + @sort_by = params[:sort_by].present? ? params[:sort_by] : 'created_on' + @sort_direction = (params[:sort_direction].present? ? params[:sort_direction] : 'asc').downcase + end + + def call + raise Error, errors.full_messages.join(", ") unless valid? + begin + journal_query_data + + @queried_journals + rescue + raise Error, "服务器错误,请联系系统管理员!" + end + end + + private + def journal_query_data + + @queried_journals = issue.journals + + case category + when 'comment' + @queried_journals = issue.comment_journals + when 'operate' + @queried_journals = issue.operate_journals + end + + @queried_journals = @queried_journals.parent_journals + + @queried_journals = @queried_journals.ransack(notes_cont: keyword).result if keyword.present? + + @queried_journals = @queried_journals.includes(:journal_details, :user, :attachments, first_ten_children_journals: [:parent_journal, :reply_journal]) + @queried_journals = @queried_journals.reorder("journals.#{sort_by} #{sort_direction}").distinct + + @queried_journals + end +end \ No newline at end of file diff --git a/app/services/api/v1/issues/list_service.rb b/app/services/api/v1/issues/list_service.rb index a5609bb62..6383a6e12 100644 --- a/app/services/api/v1/issues/list_service.rb +++ b/app/services/api/v1/issues/list_service.rb @@ -79,7 +79,6 @@ class Api::V1::Issues::ListService < ApplicationService scope = q.result.includes(:priority, :issue_status, :user, :assigners, :version, :issue_tags, :comment_journals) - scope = scope.reorder("issues.#{sort_by} #{sort_direction}").distinct @queried_issues = scope diff --git a/app/services/api/v1/issues/update_service.rb b/app/services/api/v1/issues/update_service.rb index 3084e78a9..8abc6aae4 100644 --- a/app/services/api/v1/issues/update_service.rb +++ b/app/services/api/v1/issues/update_service.rb @@ -6,7 +6,7 @@ class Api::V1::Issues::UpdateService < ApplicationService attr_reader :project, :issue, :current_user attr_reader :status_id, :priority_id, :milestone_id, :branch_name, :start_date, :due_date, :subject, :description attr_reader :issue_tag_ids, :assigner_ids, :attachment_ids, :receivers_login - attr_accessor :add_assigner_ids, :previous_issue_changes, :updated_issue + attr_accessor :add_assigner_ids, :previous_issue_changes, :updated_issue, :atme_receivers validates :project, :issue, :current_user, presence: true @@ -40,23 +40,29 @@ class Api::V1::Issues::UpdateService < ApplicationService check_assigners(assigner_ids) unless assigner_ids.blank? check_attachments(attachment_ids) unless attachment_ids.blank? check_atme_receivers(receivers_login) unless receivers_login.blank? - load_assigners(assigner_ids) unless assigner_ids.blank? - load_attachments(attachment_ids) unless attachment_ids.blank? - load_issue_tags(issue_tag_ids) unless issue_tag_ids.blank? + load_assigners(assigner_ids) + load_attachments(attachment_ids) + load_issue_tags(issue_tag_ids) load_atme_receivers(receivers_login) unless receivers_login.blank? - try_lock + try_lock("Api::V1::Issues::UpdateService:#{project.id}:#{issue.id}") @updated_issue = @issue issue_load_attributes - build_issue_journal_details if @updated_issue.previous_changes.present? # 操作记录 + build_assigner_issue_journal_details unless assigner_ids.nil?# 操作记录 + build_attachment_issue_journal_details unless attachment_ids.nil? + build_issue_tag_issue_journal_details unless issue_tag_ids.nil? build_issue_project_trends if status_id.present? # 开关时间记录 - build_assigner_participants unless assigner_ids.blank? # 负责人 - @updated_issue.assigners = @assigners unless assigner_ids.blank? - @updated_issue.attachments = @attachments unless attachment_ids.blank? - @updated_issue.issue_tags = @issue_tags unless issue_tag_ids.blank? + build_assigner_participants unless assigner_ids.nil? # 负责人 + build_edit_participants + build_atme_participants if @atme_receivers.present? + @updated_issue.assigners = @assigners || User.none unless assigner_ids.nil? + @updated_issue.attachments = @attachments || Attachment.none unless attachment_ids.nil? + @updated_issue.issue_tags = @issue_tags || IssueTag.none unless issue_tag_ids.nil? + @updated_issue.updated_on = Time.now @updated_issue.save! + build_after_issue_journal_details if @updated_issue.previous_changes.present? # 操作记录 build_previous_issue_changes # @信息发送 @@ -67,7 +73,7 @@ class Api::V1::Issues::UpdateService < ApplicationService SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id, add_assigner_ids) unless add_assigner_ids.blank? end - unlock + unlock("Api::V1::Issues::UpdateService:#{project.id}:#{issue.id}") return @updated_issue end @@ -87,108 +93,147 @@ class Api::V1::Issues::UpdateService < ApplicationService end def build_assigner_participants - @updated_issue.issue_participants.where(participant_type: "assigned").where.not(participant_id: assigner_ids).each(&:destroy!) - assigner_ids.each do |aid| - next if @updated_issue.issue_participants.exists?(participant_type: "assigned", participant_id: aid) - @updated_issue.issue_participants.new({participant_type: "assigned", participant_id: aid}) - @add_assigner_ids << aid + if assigner_ids.blank? + @updated_issue.issue_participants.where(participant_type: "assigned").each(&:destroy!) + else + @updated_issue.issue_participants.where(participant_type: "assigned").where.not(participant_id: assigner_ids).each(&:destroy!) + assigner_ids.each do |aid| + next if @updated_issue.issue_participants.exists?(participant_type: "assigned", participant_id: aid) + @updated_issue.issue_participants.new({participant_type: "assigned", participant_id: aid}) + @add_assigner_ids << aid + end + end + end + + def build_edit_participants + @updated_issue.issue_participants.new({participant_type: "edited", participant_id: current_user.id}) unless @updated_issue.issue_participants.exists?(participant_type: "edited", participant_id: current_user.id) + end + + def build_atme_participants + atme_receivers.each do |receiver| + next if @updated_issue.issue_participants.exists?(participant_type: "atme", participant_id: receiver.id) + @updated_issue.issue_participants.new({participant_type: "atme", participant_id: receiver.id}) end end def build_previous_issue_changes @previous_issue_changes = @updated_issue.previous_changes.except("updated_on", "created_on") - if @updated_issue.previous_changes[:start_date].present? - @previous_issue_changes.merge!(start_date: [@updated_issue.previous_changes[:start_date][0].to_s, @updated_issue.previous_changes[:start_date][1].to_s]) + if @updated_issue.previous_changes["start_date"].present? + @previous_issue_changes.merge!(start_date: [@updated_issue.previous_changes["start_date"][0].to_s, @updated_issue.previous_changes["start_date"][1].to_s]) end - if @updated_issue.previous_changes[:due_date].present? - @previous_issue_changes.merge!(due_date: [@updated_issue.previous_changes[:due_date][0].to_s, @updated_issue.previous_changes[:due_date][1].to_s]) + if @updated_issue.previous_changes["due_date"].present? + @previous_issue_changes.merge!(due_date: [@updated_issue.previous_changes["due_date"][0].to_s, @updated_issue.previous_changes["due_date"][1].to_s]) end end def build_issue_project_trends - if @updated_issue.previous_changes[:status_id].present? && @updated_issue.previous_changes[:status_id][1] == 5 + if @updated_issue.previous_changes["status_id"].present? && @updated_issue.previous_changes["status_id"][1] == 5 @updated_issue.project_trends.new({user_id: current_user.id, project_id: @project.id, action_type: ProjectTrend::CLOSE}) end - if @updated_issue.previous_changes[:status_id].present? && @updated_issue.previous_changes[:status_id][0] == 5 + if @updated_issue.previous_changes["status_id"].present? && @updated_issue.previous_changes["status_id"][0] == 5 @updated_issue.project_trends.where(action_type: ProjectTrend::CLOSE).each(&:destroy!) end end - def build_issue_journal_details - # 更改标题 - if @updated_issue.previous_changes[:subject].present? - journal = @updated_issue.journals.new({user_id: current_user.id}) - journal.journal_details.new({property: "attr", prop_key: "subject", old_value: @updated_issue.previous_changes[:subject][0], value: @updated_issue.previous_changes[:subject][1]}) - end + def build_after_issue_journal_details + begin + # 更改标题 + if @updated_issue.previous_changes["subject"].present? + journal = @updated_issue.journals.create!({user_id: current_user.id}) + journal.journal_details.create!({property: "attr", prop_key: "subject", old_value: @updated_issue.previous_changes["subject"][0], value: @updated_issue.previous_changes["subject"][1]}) + end - # 更改描述 - if @updated_issue.previous_changes[:description].present? - journal = @updated_issue.journals.new({user_id: current_user.id}) - journal.journal_details.new({property: "attr", prop_key: "description", old_value: @updated_issue.previous_changes[:description][0], value: @updated_issue.previous_changes[:description][1]}) - end + # 更改描述 + if @updated_issue.previous_changes["description"].present? + journal = @updated_issue.journals.create!({user_id: current_user.id}) + journal.journal_details.create!({property: "attr", prop_key: "description", old_value: @updated_issue.previous_changes["description"][0], value: @updated_issue.previous_changes["description"][1]}) + end - # 修改状态 - if @updated_issue.previous_changes[:status_id].present? - journal = @updated_issue.journals.new({user_id: current_user.id}) - journal.journal_details.new({property: "attr", prop_key: "status_id", old_value: @updated_issue.previous_changes[:status_id][0], value: @updated_issue.previous_changes[:status_id][1]}) - end + # 修改状态 + if @updated_issue.previous_changes["status_id"].present? + journal = @updated_issue.journals.create!({user_id: current_user.id}) + journal.journal_details.create!({property: "attr", prop_key: "status_id", old_value: @updated_issue.previous_changes["status_id"][0], value: @updated_issue.previous_changes["status_id"][1]}) + end - # 修改优先级 - if @updated_issue.previous_changes[:priority_id].present? - journal = @updated_issue.journals.new({user_id: current_user.id}) - journal.journal_details.new({property: "attr", prop_key: "priority_id", old_value: @updated_issue.previous_changes[:priority_id][0], value: @updated_issue.previous_changes[:priority_id][1]}) - end + # 修改优先级 + if @updated_issue.previous_changes["priority_id"].present? + journal = @updated_issue.journals.create!({user_id: current_user.id}) + journal.journal_details.create!({property: "attr", prop_key: "priority_id", old_value: @updated_issue.previous_changes["priority_id"][0], value: @updated_issue.previous_changes["priority_id"][1]}) + end - # 修改里程碑 - if @updated_issue.previous_changes[:fixed_version_id].present? - journal = @updated_issue.journals.new({user_id: current_user.id}) - journal.journal_details.new({property: "attr", prop_key: "fixed_version_id", old_value: @updated_issue.previous_changes[:fixed_version_id][0], value: @updated_issue.previous_changes[:fixed_version_id][1]}) - end + # 修改里程碑 + if @updated_issue.previous_changes["fixed_version_id"].present? + journal = @updated_issue.journals.create!({user_id: current_user.id}) + journal.journal_details.create!({property: "attr", prop_key: "fixed_version_id", old_value: @updated_issue.previous_changes["fixed_version_id"][0], value: @updated_issue.previous_changes["fixed_version_id"][1]}) + end - # 更改分支 - if @updated_issue.previous_changes[:branch_name].present? - journal = @updated_issue.journals.new({user_id: current_user.id}) - journal.journal_details.new({property: "attr", prop_key: "branch_name", old_value: @updated_issue.previous_changes[:branch_name][0], value: @updated_issue.previous_changes[:branch_name][1]}) - end + # 更改分支 + if @updated_issue.previous_changes["branch_name"].present? + journal = @updated_issue.journals.create!({user_id: current_user.id}) + journal.journal_details.create!({property: "attr", prop_key: "branch_name", old_value: @updated_issue.previous_changes["branch_name"][0], value: @updated_issue.previous_changes["branch_name"][1]}) + end - # 更改开始时间 - if @updated_issue.previous_changes[:start_date].present? - journal = @updated_issue.journals.new({user_id: current_user.id}) - journal.journal_details.new({property: "attr", prop_key: "start_date", old_value: @updated_issue.previous_changes[:start_date][0], value: @updated_issue.previous_changes[:start_date][1]}) - end + # 更改开始时间 + if @updated_issue.previous_changes["start_date"].present? + journal = @updated_issue.journals.create!({user_id: current_user.id}) + journal.journal_details.create!({property: "attr", prop_key: "start_date", old_value: @updated_issue.previous_changes["start_date"][0], value: @updated_issue.previous_changes["start_date"][1]}) + end - # 更改结束时间 - if @updated_issue.previous_changes[:due_date].present? - journal = @updated_issue.journals.new({user_id: current_user.id}) - journal.journal_details.new({property: "attr", prop_key: "due_date", old_value: @updated_issue.previous_changes[:due_date][0], value: @updated_issue.previous_changes[:due_date][1]}) - end - - # 更改负责人 - if !@updated_issue.assigners.pluck(:id).sort! == assigner_ids.sort! - journal = @updated_issue.journals.new({user_id: current_user.id}) - journal.journal_details.new({property: "assigner", prop_key: "#{assigner_ids.size}", old_value: @updated_issue.assigners.pluck(:nickname).join(","), value: @assigners.pluck(:nickname).join(",")}) - end - - # 更改标记 - if !@updated_issue.issue_tags.pluck(:id).sort! == issue_tag_ids.sort! - journal = @updated_issue.journals.new({user_id: current_user.id}) - journal.journal_details.new({property: "issue_tag", prop_key: "#{issue_tag_ids.size}", old_value: @updated_issue.issue_tags.pluck(:name).join(","), value: @issue_tags.pluck(:name).join(",")}) - end - - # 更改附件 - if !@updated_issue.attachments.pluck(:id).sort! == attachment_ids.sort! - journal = @updated_issue.journals.new({user_id: current_user.id}) - journal.journal_details.new({property: "attachment", prop_key: "#{attachment_ids.size}", old_value: @updated_issue.attachments.pluck(:filename).join(","), value: @attachments.pluck(:filename).join(",")}) + # 更改结束时间 + if @updated_issue.previous_changes["due_date"].present? + journal = @updated_issue.journals.create!({user_id: current_user.id}) + journal.journal_details.create!({property: "attr", prop_key: "due_date", old_value: @updated_issue.previous_changes["due_date"][0], value: @updated_issue.previous_changes["due_date"][1]}) + end + rescue + raise Error, "创建操作记录失败!" end end - def try_lock - raise Error, "请稍后再试!" unless $redis_cache.set("Api::V1::Issues::UpdateService:#{project.id}:#{issue.id}", 1, nx: true, ex: 60.seconds) + def build_assigner_issue_journal_details + begin + # 更改负责人 + new_assigner_ids = @assigner_ids + new_assigner_ids = [] if @assigner_ids.nil? + now_assigner_ids = @updated_issue.assigners.pluck(:id) + if !(now_assigner_ids & assigner_ids).empty? || !(now_assigner_ids.empty? && new_assigner_ids.empty?) + journal = @updated_issue.journals.create!({user_id: current_user.id}) + journal.journal_details.create!({property: "assigner", prop_key: "#{new_assigner_ids.size}", old_value: now_assigner_ids.join(","), value: new_assigner_ids.join(",")}) + end + + rescue + raise Error, "创建操作记录失败!" + end end - def unlock - $redis_cache.del("Api::V1::Issues::UpdateService:#{project.id}:#{issue.id}") + def build_issue_tag_issue_journal_details + begin + # 更改标记 + new_issue_tag_ids = @issue_tag_ids + new_issue_tag_ids = [] if @issue_tag_ids.nil? + now_issue_tag_ids = @updated_issue.issue_tags.pluck(:id) + if !(now_issue_tag_ids & new_issue_tag_ids).empty? || !(now_issue_tag_ids.empty? && new_issue_tag_ids.empty?) + journal = @updated_issue.journals.create!({user_id: current_user.id}) + journal.journal_details.create!({property: "issue_tag", prop_key: "#{new_issue_tag_ids.size}", old_value: now_issue_tag_ids.join(","), value: new_issue_tag_ids.join(",")}) + end + rescue + raise Error, "创建操作记录失败!" + end end + + def build_attachment_issue_journal_details + begin + # 更改附件 + new_attachment_ids = @attachment_ids + new_attachment_ids = [] if @attachment_ids.nil? + now_attachment_ids = @updated_issue.attachments.pluck(:id) + if !(now_attachment_ids & new_attachment_ids).empty? || !(now_attachment_ids.empty? && new_attachment_ids.empty?) + journal = @updated_issue.journals.create!({user_id: current_user.id}) + journal.journal_details.create!({property: "attachment", prop_key: "#{new_attachment_ids.size}", old_value: now_attachment_ids.join(","), value: new_attachment_ids.join(",")}) + end + rescue + raise Error, "创建操作记录失败!" + end + end end \ No newline at end of file diff --git a/app/services/application_service.rb b/app/services/application_service.rb index 2fa59ed29..93f7ed48c 100644 --- a/app/services/application_service.rb +++ b/app/services/application_service.rb @@ -9,6 +9,15 @@ class ApplicationService content.gsub(regex, '') end + protected + def try_lock(key) + raise Error, "请稍后再试!" unless $redis_cache.set(key, 1, nx: true, ex: 60.seconds) + end + + def unlock(key) + $redis_cache.del(key) + end + private def strip(str) diff --git a/app/views/api/v1/issues/index.json.jbuilder b/app/views/api/v1/issues/index.json.jbuilder index 3e820f6f4..1a324eb27 100644 --- a/app/views/api/v1/issues/index.json.jbuilder +++ b/app/views/api/v1/issues/index.json.jbuilder @@ -1,6 +1,6 @@ json.total_count @issues.total_count -json.opened_count @issues.opened.size -json.closed_count @issues.closed.size +json.opened_count @opened_issues_count +json.closed_count @closed_issues_count json.issues @issues.each do |issue| json.partial! "simple_detail", locals: {issue: issue} end \ No newline at end of file diff --git a/app/views/api/v1/issues/journals/_children_detail.json.jbuilder b/app/views/api/v1/issues/journals/_children_detail.json.jbuilder new file mode 100644 index 000000000..38bbda404 --- /dev/null +++ b/app/views/api/v1/issues/journals/_children_detail.json.jbuilder @@ -0,0 +1,17 @@ +json.(journal, :id, :notes, :comments_count) +json.created_at journal.created_on.strftime("%Y-%m-%d %H:%M") +json.updated_at journal.updated_on.strftime("%Y-%m-%d %H:%M") +json.user do + if journal.user.present? + json.partial! "api/v1/users/simple_user", user: journal.user + else + json.nil! + end +end +json.reply_user do + if journal.reply_journal&.user&.present? + json.partial! "api/v1/users/simple_user", user: journal.reply_journal.user + else + json.nil! + end +end \ No newline at end of file diff --git a/app/views/api/v1/issues/journals/_detail.json.jbuilder b/app/views/api/v1/issues/journals/_detail.json.jbuilder new file mode 100644 index 000000000..418da24a8 --- /dev/null +++ b/app/views/api/v1/issues/journals/_detail.json.jbuilder @@ -0,0 +1,20 @@ +json.id journal.id +json.is_journal_detail journal.is_journal_detail? +json.created_at journal.created_on.strftime("%Y-%m-%d %H:%M") +json.updated_at journal.updated_on.strftime("%Y-%m-%d %H:%M") +json.user do + if journal.user.present? + json.partial! "api/v1/users/simple_user", user: journal.user + else + json.nil! + end +end +if journal.is_journal_detail? + json.operate_content journal.is_journal_detail? ? journal.operate_content : nil +else + json.notes journal.notes + json.comments_count journal.comments_count + json.children_journals journal.first_ten_children_journals.each do |journal| + json.partial! "children_detail", journal: journal + end +end diff --git a/app/views/api/v1/issues/journals/create.json.jbuilder b/app/views/api/v1/issues/journals/create.json.jbuilder new file mode 100644 index 000000000..91f3f3174 --- /dev/null +++ b/app/views/api/v1/issues/journals/create.json.jbuilder @@ -0,0 +1 @@ +json.partial! "detail", journal: @object_result \ No newline at end of file diff --git a/app/views/api/v1/issues/journals/index.json.jbuilder b/app/views/api/v1/issues/journals/index.json.jbuilder new file mode 100644 index 000000000..bea6746a6 --- /dev/null +++ b/app/views/api/v1/issues/journals/index.json.jbuilder @@ -0,0 +1,4 @@ +json.total_count @journals.total_count +json.journals @journals do |journal| + json.partial! "detail", journal: journal +end \ No newline at end of file diff --git a/config/routes/api.rb b/config/routes/api.rb index 15ebc44f1..6c9b3dcdf 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -30,6 +30,14 @@ defaults format: :json do patch :batch_update delete :batch_destroy end + + member do + resources :journals, module: :issues, only: [:index, :create, :update, :destroy] do + member do + get :children_journals + end + end + end end scope module: :issues do resources :issue_tags, except: [:new, :edit]