diff --git a/app/controllers/api/v1/issues_controller.rb b/app/controllers/api/v1/issues_controller.rb index 1decf3421..3f61259e5 100644 --- a/app/controllers/api/v1/issues_controller.rb +++ b/app/controllers/api/v1/issues_controller.rb @@ -1,12 +1,25 @@ class Api::V1::IssuesController < Api::V1::BaseController - before_action :require_public_and_member_above, only: [:index] + before_action :require_public_and_member_above, only: [:index, :show, :create, :update, :destroy] def index @object_results = Api::V1::Issues::ListService.call(@project, query_params, current_user) @issues = kaminari_paginate(@object_results) end + def create + @object_result = Api::V1::Issues::CreateService.call(@project, issue_params, current_user) + end + + before_action :load_issue, only: [:show, :update, :destroy] + + def show + end + + def update + @object_result = Api::V1::Issues::EditService.call(@project, issue_params, current_user) + end + private def query_params @@ -20,4 +33,23 @@ class Api::V1::IssuesController < Api::V1::BaseController :issue_tag_ids => []) end + def issue_params + params.permit( + :status_id, :priority_id, :milestone_id, + :branch_name, :start_date, :due_date, + :subject, :description, + :issue_tag_ids => [], + :assigner_ids => [], + :attachment_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 + end \ No newline at end of file diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index ddb0facdf..2f779f418 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -111,7 +111,9 @@ class IssuesController < ApplicationController issue_params = issue_send_params(params) Issues::CreateForm.new({subject: issue_params[:subject], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate! @issue = Issue.new(issue_params) + @issue.project_issues_index = @project.get_last_project_issues_index + 1 if @issue.save! + @project.del_project_issue_cache_delete_count SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('ProjectIssue', current_user.id, @issue&.id) if Site.has_notice_menu? if params[:attachment_ids].present? @@ -302,6 +304,7 @@ class IssuesController < ApplicationController login = @issue.user.try(:login) SendTemplateMessageJob.perform_later('IssueDeleted', current_user.id, @issue&.subject, @issue.assigned_to_id, @issue.author_id) if Site.has_notice_menu? if @issue.destroy + @project.incre_project_issue_cache_delete_count if issue_type == "2" && status_id != 5 post_to_chain("add", token, login) end diff --git a/app/models/issue.rb b/app/models/issue.rb index 03e33c666..be759d2b4 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -73,6 +73,7 @@ class Issue < ApplicationRecord has_many :issue_participants has_many :participants, through: :issue_participants has_many :comment_journals, -> {where.not(notes: nil)}, class_name: "Journal", :as => :journalized + has_many :operate_journals, -> {where(notes: nil)}, class_name: "Journal", :as => :journalized scope :issue_includes, ->{includes(:user)} scope :issue_many_includes, ->{includes(journals: :user)} diff --git a/app/models/project.rb b/app/models/project.rb index 840661ee7..310d3009e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -424,4 +424,19 @@ class Project < ApplicationRecord raise("项目名称包含敏感词汇,请重新输入") if name && !HarmoniousDictionary.clean?(name) raise("项目描述包含敏感词汇,请重新输入") if description && !HarmoniousDictionary.clean?(description) end + + def get_last_project_issues_index + last_issue = self.issues.last + deleted_issue_count = ($redis_cache.hget("issue_cache_delete_count", self.id) || 0).to_i + + last_issue.project_issues_index.present? ? last_issue.project_issues_index + deleted_issue_count : 1 + end + + def incre_project_issue_cache_delete_count + $redis_cache.hincrby("issue_cache_delete_count", self.id, 1) + end + + def del_project_issue_cache_delete_count + $redis_cache.hdel("issue_cache_delete_count", self.id) + end end diff --git a/app/services/api/v1/issues/create_service.rb b/app/services/api/v1/issues/create_service.rb new file mode 100644 index 000000000..6b3e9685a --- /dev/null +++ b/app/services/api/v1/issues/create_service.rb @@ -0,0 +1,107 @@ +class Api::V1::Issues::CreateService < ApplicationService + include ActiveModel::Model + + attr_reader :project, :created_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 + + validates :subject, presence: true + validates :status_id, :priority_id, presence: true + validates :current_user, presence: true + + def initialize(project, params, current_user = nil) + @project = project + @current_user = current_user + @status_id = params[:status_id] + @priority_id = params[:priority_id] + @milestone_id = params[:milestone_id] + @branch_name = params[:branch_name] + @start_date = params[:start_date] + @due_date = params[:due_date] + @subject = params[:subject] + @description = params[:description] + @issue_tag_ids = params[:issue_tag_ids] + @assigner_ids = params[:assigner_ids] + @attachment_ids = params[:attachment_ids] + end + + def call + raise Error, errors.full_messages.join(", ") unless valid? + begin + ActiveRecord::Base.transaction do + check_issue_status + check_issue_priority + check_milestone if milestone_id.present? + load_assigners unless assigner_ids.blank? + load_attachments unless attachment_ids.blank? + load_issue_tags unless issue_tag_ids.blank? + load_participants + + @created_issue = Issue.new(issue_attributes) + @created_issue.assigners = @assigners unless assigner_ids.blank? + @created_issue.attachments = @attachments unless attachment_ids.blank? + @created_issue.issue_tags = @issue_tags unless issue_tag_ids.blank? + @created_issue.participants = @participants + + @created_issue.save! + + project.del_project_issue_cache_delete_count # 把缓存里存储项目删除issue的个数清除掉 + end + + return @created_issue + rescue + raise Error, "服务器错误,请联系系统管理员!" + end + end + + private + def check_issue_status + raise Error, "IssueStatus不存在!" unless IssueStatus.find_by_id(status_id).present? + end + + def check_issue_priority + raise Error, "IssuePriority不存在!" unless IssuePriority.find_by_id(priority_id).present? + end + + def check_milestone + raise Error, "Milestone不存在!" unless Version.find_by_id(milestone_id).present? + end + + def load_assigners + @assigners = User.where(id: assigner_ids) + end + + def load_issue_tags + @issue_tags = IssueTag.where(id: issue_tag_ids) + end + + def load_attachments + @attachments = Attachment.where(id: attachment_ids) + end + + def load_participants + @participants = User.where(id: assigner_ids).or(User.where(id: current_user.id)) + end + + def issue_attributes + issue_attributes = { + subject: subject, + project_id: project.id, + author_id: current_user.id, + tracker_id: Tracker.first.id, + status_id: status_id, + priority_id: priority_id, + project_issues_index: (project.get_last_project_issues_index + 1), + issue_type: "1", + issue_classify: "Issue" + } + + issue_attributes.merge!({description: description}) if description.present? + issue_attributes.merge!({fixed_version_id: milestone_id}) if milestone_id.present? + issue_attributes.merge!({start_date: start_date}) if start_date.present? + issue_attributes.merge!({due_date: due_date}) if due_date.present? + issue_attributes.merge!({branch_name: branch_name}) if branch_name.present? + + issue_attributes + 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 39ff2eca8..a5609bb62 100644 --- a/app/services/api/v1/issues/list_service.rb +++ b/app/services/api/v1/issues/list_service.rb @@ -6,14 +6,15 @@ class Api::V1::Issues::ListService < ApplicationService attr_accessor :queried_issues validates :category, inclusion: {in: %w(all opened closed), message: "请输入正确的Category"} + validates :participant_category, inclusion: {in: %w(all aboutme authoredme assignedme atme), message: "请输入正确的ParticipantCategory"} validates :sort_by, inclusion: {in: Issue.column_names, message: '请输入正确的SortBy'}, allow_blank: true validates :sort_direction, inclusion: {in: %w(asc desc), message: '请输入正确的SortDirection'}, allow_blank: true + validates :current_user, presence: true def initialize(project, params, current_user=nil) - puts params @project = project @category = params[:category] || 'all' - @participant_category = params[:participant_category] + @participant_category = params[:participant_category] || 'all' @keyword = params[:keyword] @author_id = params[:author_id] @issue_tag_ids = params[:issue_tag_ids] diff --git a/app/views/api/v1/issues/_detail.json.jbuilder b/app/views/api/v1/issues/_detail.json.jbuilder new file mode 100644 index 000000000..e2e1bde8d --- /dev/null +++ b/app/views/api/v1/issues/_detail.json.jbuilder @@ -0,0 +1,42 @@ +json.(issue, :id, :subject, :project_issues_index, :description, :branch_name, :start_date, :due_date) +json.created_at issue.created_on.strftime("%Y-%m-%d %H:%M") +json.updated_at issue.updated_on.strftime("%Y-%m-%d %H:%M") +json.tags issue.issue_tags.each do |tag| + json.partial! "api/v1/issues/issue_tags/simple_detail", locals: {tag: tag} +end +json.status do + if issue.issue_status.present? + json.partial! "api/v1/issues/statues/simple_detail", locals: {status: issue.issue_status} + else + json.nil! + end +end +json.priority do + if issue.priority.present? + json.partial! "api/v1/issues/issue_priorities/simple_detail", locals: {priority: issue.priority} + else + json.nil! + end +end +json.milestone do + if issue.version.present? + json.partial! "api/v1/issues/milestones/simple_detail", locals: {milestone: issue.version} + else + json.nil! + end +end +json.author do + if issue.user.present? + json.partial! "api/v1/users/simple_user", locals: {user: issue.user} + else + json.nil! + end +end +json.assigners issue.assigners.each do |assigner| + json.partial! "api/v1/users/simple_user", locals: {user: assigner} +end +json.participants issue.participants.each do |participant| + json.partial! "api/v1/users/simple_user", locals: {user: participant} +end +json.comment_journals_count issue.comment_journals.size +json.operate_journals_count issue.operate_journals.size \ No newline at end of file diff --git a/app/views/api/v1/issues/_simple_detail.json.jbuilder b/app/views/api/v1/issues/_simple_detail.json.jbuilder index a33cde4cf..bfc2693cf 100644 --- a/app/views/api/v1/issues/_simple_detail.json.jbuilder +++ b/app/views/api/v1/issues/_simple_detail.json.jbuilder @@ -1,6 +1,6 @@ json.(issue, :id, :subject, :project_issues_index) -json.created_at issue.created_on.strftime("%Y/%m/%d %H:%M") -json.updated_at issue.updated_on.strftime("%Y/%m/%d %H:%M") +json.created_at issue.created_on.strftime("%Y-%m-%d %H:%M") +json.updated_at issue.updated_on.strftime("%Y-%m-%d %H:%M") json.tags issue.issue_tags.each do |tag| json.partial! "api/v1/issues/issue_tags/simple_detail", locals: {tag: tag} end diff --git a/app/views/api/v1/issues/create.json.jbuilder b/app/views/api/v1/issues/create.json.jbuilder new file mode 100644 index 000000000..f45ef5b2f --- /dev/null +++ b/app/views/api/v1/issues/create.json.jbuilder @@ -0,0 +1 @@ +json.partial! "api/v1/issues/detail", locals: {issue: @object_result} diff --git a/app/views/api/v1/issues/index.json.jbuilder b/app/views/api/v1/issues/index.json.jbuilder index 920e7d68d..3e820f6f4 100644 --- a/app/views/api/v1/issues/index.json.jbuilder +++ b/app/views/api/v1/issues/index.json.jbuilder @@ -1,4 +1,6 @@ json.total_count @issues.total_count +json.opened_count @issues.opened.size +json.closed_count @issues.closed.size 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/issue_priorities/_simple_detail.json.jbuilder b/app/views/api/v1/issues/issue_priorities/_simple_detail.json.jbuilder new file mode 100644 index 000000000..b7c37147a --- /dev/null +++ b/app/views/api/v1/issues/issue_priorities/_simple_detail.json.jbuilder @@ -0,0 +1 @@ +json.(priority, :id, :name) diff --git a/app/views/api/v1/issues/issue_priorities/index.json.jbuilder b/app/views/api/v1/issues/issue_priorities/index.json.jbuilder index 41499d456..c1b8ebb25 100644 --- a/app/views/api/v1/issues/issue_priorities/index.json.jbuilder +++ b/app/views/api/v1/issues/issue_priorities/index.json.jbuilder @@ -1,4 +1,4 @@ json.total_count @priorities.total_count json.priorities @priorities.each do |priority| - json.(priority, :id, :name) + json.partial! "simple_detail", locals: {priority: priority} end \ No newline at end of file diff --git a/app/views/api/v1/issues/show.json.jbuilder b/app/views/api/v1/issues/show.json.jbuilder new file mode 100644 index 000000000..8746417b5 --- /dev/null +++ b/app/views/api/v1/issues/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "api/v1/issues/detail", locals: {issue: @issue} diff --git a/app/views/api/v1/issues/statues/_simple_detail.json.jbuilder b/app/views/api/v1/issues/statues/_simple_detail.json.jbuilder new file mode 100644 index 000000000..f66b6c95a --- /dev/null +++ b/app/views/api/v1/issues/statues/_simple_detail.json.jbuilder @@ -0,0 +1 @@ +json.(status, :id, :name) diff --git a/app/views/api/v1/issues/statues/index.json.jbuilder b/app/views/api/v1/issues/statues/index.json.jbuilder index 2cc91fb52..9fb60acc2 100644 --- a/app/views/api/v1/issues/statues/index.json.jbuilder +++ b/app/views/api/v1/issues/statues/index.json.jbuilder @@ -1,4 +1,4 @@ json.total_count @statues.total_count json.statues @statues.each do |status| - json.(status, :id, :name) + json.partial! "simple_detail", locals: {status: status} end \ No newline at end of file diff --git a/lib/tasks/fix_issue_project_issues_index.rake b/lib/tasks/fix_issue_project_issues_index.rake new file mode 100644 index 000000000..010df5f4b --- /dev/null +++ b/lib/tasks/fix_issue_project_issues_index.rake @@ -0,0 +1,22 @@ +# 执行示例 bundle exec rake sync_version_issues:update_issues +# 线上环境执行示例 RAILS_ENV=production bundle exec rake sync_version_issues:update_issues + +namespace :fix_issue_project_issues_index do + desc "update issue project_issues_index" + + task update_issues: :environment do + puts "____________fix start________________" + + Issue.update_all(project_issues_index: nil) + + Issue.where(project_issues_index: nil).group(:project_id).count.each do |pid, count| + p = Project.find_by_id(pid) + issues = p.issues.order(created_on: :asc) + issues.find_each.with_index do |issue, index| + issue.update_column(:project_issues_index, index+1) + end + end + puts "____________fix end________________" + end + +end \ No newline at end of file