forgeplus/app/controllers/api/pm/issues_controller.rb

377 lines
16 KiB
Ruby
Raw Normal View History

2023-11-01 16:49:00 +08:00
class Api::Pm::IssuesController < Api::Pm::BaseController
2023-11-01 10:42:27 +08:00
before_action :require_login, except: [:index]
2023-11-01 16:49:00 +08:00
before_action :load_project
before_action :load_issue, only: %i[show update destroy link_index link_issues parent_issues]
2023-11-02 11:38:52 +08:00
before_action :load_issues, only: %i[batch_update batch_destroy]
before_action :check_issue_operate_permission, only: %i[update destroy]
2023-11-01 16:49:00 +08:00
2023-11-01 10:42:27 +08:00
def index
@object_result = Api::V1::Issues::ListService.call(@project, query_params, current_user)
@total_issues_count = @object_result[:total_issues_count]
@opened_issues_count = @object_result[:opened_issues_count]
@closed_issues_count = @object_result[:closed_issues_count]
@complete_issues_count = @object_result[:complete_issues_count]
2023-11-01 10:42:27 +08:00
if params[:only_name].present?
@issues = kaminary_select_paginate(
@object_result[:data].select(:id, :subject, :project_issues_index, :updated_on, :created_on))
else
@issues = kaminari_paginate(@object_result[:data])
end
2023-11-01 16:49:00 +08:00
render 'api/v1/issues/index'
2023-11-01 10:42:27 +08:00
end
2023-11-07 17:16:25 +08:00
def link_index
2023-11-08 14:45:40 +08:00
pm_issue_type = params[:pm_issue_type] || [1, 2, 3]
2023-11-15 14:18:36 +08:00
not_join_id = case params[:issue_filter_type]
when 'leaf_issue'
Issue.where(root_id: @issue.id).pluck(:id)
2023-11-16 15:30:16 +08:00
when 'link_issue'
@issue.pm_links.pluck(:be_linkable_id)
2023-11-15 14:18:36 +08:00
end
2023-11-07 17:16:25 +08:00
2023-11-15 11:47:17 +08:00
not_join_id << @issue.id
object_issues = Issue.where(
pm_project_id: params[:pm_project_id],
pm_issue_type: pm_issue_type
2023-11-16 15:13:45 +08:00
).where.not(id: not_join_id).order(updated_on: :desc)
object_issues = object_issues.where(root_id: nil, child_count: 0) if params[:issue_filter_type] == 'leaf_issue'
2023-11-15 11:47:17 +08:00
@issues = kaminari_paginate(object_issues)
render 'api/v1/issues/index'
end
def parent_issues
@issues = Issue.where(pm_project_id: params[:pm_project_id])
.where.not(id: @issue.id)
.where.not(id: Issue.full_children_issues(@issue).map{|i|i.id})
@issues = @issues.where(pm_issue_type: params[:pm_issue_type]) if params[:pm_issue_type].present?
2023-12-13 11:05:16 +08:00
@issues = @issues.ransack(id_or_project_issues_index_eq: params[:keyword]).result.or(@issues.ransack(subject_or_description_cont: params[:keyword]).result) if params[:keyword].present?
@issues = @issues.reorder("#{issue_sort_by} #{issue_sort_direction}")
if params[:only_name].present?
@issues = kaminary_select_paginate(
@issues.select(:id, :subject, :project_issues_index, :updated_on, :created_on))
else
@issues = @issues.includes(:priority, :issue_status, :user, :show_assigners, :show_issue_tags, :version, :comment_journals)
@issues = kaminari_paginate(@issues)
end
end
2023-11-01 10:42:27 +08:00
def show
@issue.associate_attachment_container
2023-11-01 16:49:00 +08:00
render 'api/v1/issues/show'
2023-11-01 10:42:27 +08:00
end
def create
2024-08-20 15:56:40 +08:00
@object_result = Api::Pm::Issues::CreateService.call(@project, issue_params, current_user)
2023-11-01 16:49:00 +08:00
render 'api/v1/issues/create'
2023-11-01 10:42:27 +08:00
end
def update
2024-08-20 15:56:40 +08:00
@object_result = Api::Pm::Issues::UpdateService.call(@project, @issue, issue_params, current_user)
2023-11-01 16:49:00 +08:00
render 'api/v1/issues/update'
end
def batch_update
2024-08-20 15:56:40 +08:00
@object_result = Api::Pm::Issues::BatchUpdateService.call(@project, @issues, batch_issue_params, current_user)
2023-11-01 16:49:00 +08:00
if @object_result
render_ok
else
render_error('批量更新疑修失败!')
end
end
def batch_destroy
return render_ok if params[:ids].is_a?(Array) && params[:ids].blank?
2024-08-20 15:56:40 +08:00
@object_result = Api::Pm::Issues::BatchDeleteService.call(@project, @issues, current_user)
2023-11-01 16:49:00 +08:00
if @object_result
render_ok
else
render_error('批量删除疑修失败!')
end
end
def priorities
@priorities = IssuePriority.order(position: :asc)
@priorities = @priorities.ransack(name_cont: params[:keyword]).result if params[:keyword]
@priorities = kaminary_select_paginate(@priorities)
render "api/v1/issues/issue_priorities/index"
end
def tags
# IssueTag.pm_init_data(params[:pm_project_id]) unless $redis_cache.hget("pm_project_init_issue_tags", params[:pm_project_id])
2023-11-02 09:17:32 +08:00
@issue_tags = IssueTag.where(pm_project_id: params[:pm_project_id]).reorder("#{tag_sort_by} #{tag_sort_direction}")
@issue_tags = @issue_tags.ransack(name_cont: params[:keyword]).result if params[:keyword].present?
params[:only_name] = true #强制渲染 不走project
@issue_tags = kaminary_select_paginate(@issue_tags.select(:id, :name, :color))
render "api/v1/issues/issue_tags/index"
2023-11-01 16:49:00 +08:00
end
def statues
2023-12-06 13:59:28 +08:00
@statues = IssueStatus.order("position asc")
2023-11-01 16:49:00 +08:00
@statues = @statues.ransack(name_cont: params[:keyword]).result if params[:keyword].present?
@statues = kaminary_select_paginate(@statues)
render "api/v1/issues/statues/index"
end
2023-11-07 09:54:50 +08:00
2023-11-01 10:42:27 +08:00
def destroy
2024-08-20 15:56:40 +08:00
@object_result = Api::Pm::Issues::DeleteService.call(@project, @issue, current_user)
2023-11-01 10:42:27 +08:00
if @object_result
render_ok
else
render_error('删除疑修失败!')
end
end
2023-11-01 16:49:00 +08:00
2024-08-07 11:01:24 +08:00
def export
return render_error('请输入正确的项目ID.') if params[:pm_project_id].blank?
Axlsx::Package.new do |p|
[['requirement', 1], ['task', 2], ['bug', 3]].each do |type|
p.workbook.add_worksheet(:name => type[0]) do |sheet|
@issues = Issue.where(pm_project_id: params[:pm_project_id], pm_issue_type: type[1])
sheet.add_row ["ID", "标题*", "正文", "创建者*", "创建时间", "修改者", "更新时间", "状态", "负责人", "优先级", "标记", "开始时间","结束时间", "预估工时"]
2024-08-07 11:01:24 +08:00
@issues.each do |issue|
sheet.add_row [issue.id, issue.subject, issue.description, issue.user.try(:login), issue.created_on.strftime("%Y-%m-%d %H:%M:%S"), issue.changer.try(:login), issue.updated_on.strftime("%Y-%m-%d %H:%M:%S"), issue.status_id, issue.assigners.pluck(:login).join(","), issue.priority_id, issue.issue_tags.pluck(:name, :color).join(","), issue.start_date.present? ? issue.start_date.strftime("%Y-%m-%d") : "", issue.due_date.present? ? issue.due_date.strftime("%Y-%m-%d") : "", issue.time_scale]
2024-08-07 11:01:24 +08:00
end
end
end
p.workbook.add_worksheet(:name => 'leaf_relations') do |sheet|
leaf_issues = Issue.where(pm_project_id: params[:pm_project_id]).where.not(root_id: nil)
sheet.add_row ["ID", "父工作项ID"]
leaf_issues.each do |issue|
sheet.add_row [issue.id, issue.root_id]
end
end
p.workbook.add_worksheet(:name => 'link_relations') do |sheet|
# links = PmLink.joins(:linkable_issue).where(issues: {pm_project_id: params[:pm_project_id]})
2024-09-14 14:18:51 +08:00
links = PmLink.find_by_sql("SELECT `pm_links`.* FROM `pm_links` INNER JOIN `issues` ON `issues`.`id` = `pm_links`.`linkable_id` AND `pm_links`.`linkable_type` = 'Issue' WHERE `issues`.`pm_project_id` = #{params[:pm_project_id]}")
sheet.add_row ["ID", "被关联工作项ID"]
links.each do |link|
sheet.add_row [link.linkable_id, link.be_linkable_id]
end
end
2024-08-07 11:01:24 +08:00
p.serialize('public/导出工作项.xlsx')
end
2024-08-28 11:55:35 +08:00
send_file('public/导出工作项.xlsx', :type => 'application/octet-stream;charset=utf-8')
2024-08-07 11:01:24 +08:00
end
def import
begin
return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile)
return render_error('请输入正确的项目ID.') if params[:pm_project_id].blank?
return render_error('请输入正确的组织ID.') if params[:organization_id].blank?
ActiveRecord::Base.transaction do
types = {requirement: 1, task: 2, bug: 3}
doc = SimpleXlsxReader.open(params[:file].tempfile)
doc.sheets.each do |sheet|
case sheet.name
when 'requirement', 'task', 'bug'
type = types["#{sheet.name}".to_sym]
sheet.rows.each.with_index do |row, index|
next if index == 0
issue = Issue.new(issue_classify: "issue", project_id: 0, pm_project_id: params[:pm_project_id], pm_issue_type: type, tracker_id: Tracker.first.id)
issue.fake_id = row[0]
issue.subject = row[1]
issue.description = row[2]
2024-09-04 09:46:39 +08:00
author = User.find_by(login: row[3])
issue.user = author
issue.created_on = row[4]
2024-09-04 09:46:39 +08:00
changer = User.find_by(login: row[5])
issue.changer = changer
issue.updated_on = row[6]
issue.status_id = row[7].to_i
if row[8].present?
row[8].split(',').each do |a|
u = User.find_by(login: a)
next unless u.present?
issue.assigners << u
end
end
issue.priority_id = row[9]
if row[10].present?
row[10].split(',').each_slice(2).to_a.each do |t|
tag = IssueTag.find_by(project_id: 0, organization_id: params[:organization_id], name: t[0])
if tag.present?
issue.issue_tags << tag
else
tag = IssueTag.create(project_id: 0,organization_id: params[:organization_id], name: t[0], color: t[1])
issue.issue_tags << tag
end
end
end
issue.start_date = row[11]
issue.due_date = row[12]
issue.time_scale = row[13]
issue.save!
end
when 'leaf_relations'
sheet.rows.each.with_index do |row, index|
next if index == 0
children_issue = Issue.where(fake_id: row[0]).last
parent_issue = Issue.where(fake_id: row[1]).last
next if children_issue.blank? || parent_issue.blank?
2024-08-27 14:20:35 +08:00
children_issue.root_id = parent_issue.id
children_issue.save(touch: false)
end
when 'link_relations'
sheet.rows.each.with_index do |row, index|
next if index == 0
link_issue = Issue.where(fake_id: row[0]).last
be_link_issue = Issue.where(fake_id: row[1]).last
next if link_issue.blank? || be_link_issue.blank?
PmLink.create!(linkable_type: 'Issue', linkable_id: link_issue.id, be_linkable_type: 'Issue', be_linkable_id: be_link_issue.id)
2024-08-07 11:27:14 +08:00
end
2024-09-04 09:46:39 +08:00
else
return render_error('导入失败请上传正确格式的excel文件')
2024-08-07 11:01:24 +08:00
end
2024-08-07 11:01:24 +08:00
end
end
2024-08-27 13:58:35 +08:00
render_ok
rescue
return render_error('导入失败请上传正确格式的excel文件')
2024-08-07 11:01:24 +08:00
end
end
def link_issues
children_issues = @issue.pm_issue_type == 1 ? @issue.child_count > 0 ? Issue.where(id: @issue.id) : Issue.none : Issue.where(root_id: @issue.id)
2024-12-06 10:59:10 +08:00
linkable_issues = Issue.where(id: PmLink.where(linkable_type: "Issue", linkable_id: @issue.id).pluck(:be_linkable_id))
belinkable_issues = Issue.where(id: PmLink.where(be_linkable_type: "Issue", be_linkable_id: @issue.id).pluck(:linkable_id))
full_link_issues_ids = children_issues.pluck(:id) | linkable_issues.pluck(:id) | belinkable_issues.pluck(:id)
2024-12-06 11:31:58 +08:00
compare_link_issues_ids = children_issues.pluck(:id) | linkable_issues.pluck(:id) | belinkable_issues.pluck(:id)
i = compare_link_issues_ids.count
while i > 0 do
2024-12-11 17:22:27 +08:00
children_issues = Issue.where(root_id: compare_link_issues_ids)
2024-12-06 10:59:10 +08:00
linkable_issues = Issue.where(id: PmLink.where(linkable_type: "Issue", linkable_id: compare_link_issues_ids).pluck(:be_linkable_id))
belinkable_issues = Issue.where(id: PmLink.where(be_linkable_type: "Issue", be_linkable_id: compare_link_issues_ids).pluck(:linkable_id))
2024-12-06 11:20:53 +08:00
compare_link_issues_ids = (children_issues.pluck(:id) | linkable_issues.pluck(:id) | belinkable_issues.pluck(:id)) - full_link_issues_ids
full_link_issues_ids = full_link_issues_ids | compare_link_issues_ids
i = compare_link_issues_ids.count
end
2024-12-12 09:10:09 +08:00
exclude_issues_ids = []
exclude_issues = Issue.where(id: full_link_issues_ids).where.not(root_id: nil)
exclude_issues.each do |i|
exclude_issues_ids << i.id if i.pm_issue_type == 1 && full_link_issues_ids.include?(i.root_id)
2024-12-11 17:22:27 +08:00
end
2024-12-12 09:10:09 +08:00
full_link_issues_ids = full_link_issues_ids - exclude_issues_ids
@requirement_issues = Issue.where(id:full_link_issues_ids, pm_issue_type:1, root_id: nil).pm_includes
@task_issues = Issue.where(id:full_link_issues_ids, pm_issue_type:2).pm_includes
@bug_issues = Issue.where(id:full_link_issues_ids, pm_issue_type:3).pm_includes
end
2023-11-01 10:42:27 +08:00
private
def circle_link_issues(issue_ids)
if issue_ids.present?
children_issues = Issue.joins(:parent_issue).where(issues: {id: issue_ids})
linkable_issues = Issue.where(id: PmLink.where(linkable_type: "Issue", linkable_id: issue_ids))
belinkable_issues = Issue.where(id: PmLink.where(be_linkable_type: "Issue", be_linkable_id: issue_ids))
return circle_link_issues(children_issues.pluck(:id))
else
return []
end
end
2023-11-01 16:49:00 +08:00
def check_issue_operate_permission
2023-11-02 14:41:33 +08:00
return if params[:project_id].to_i.zero?
2023-11-01 16:49:00 +08:00
render_forbidden('您没有操作权限!') unless @project.member?(current_user) || current_user.admin? || @issue.user == current_user
end
2023-11-07 17:16:25 +08:00
def load_issue
2025-05-22 14:11:09 +08:00
# return render_parameter_missing if params[:pm_project_id].blank?
2025-05-22 14:13:50 +08:00
@issue = Issue.issue_issue.find_by_id(params[:id])
2023-11-07 17:16:25 +08:00
render_not_found('疑修不存在!') if @issue.blank?
end
2025-05-21 09:33:00 +08:00
# def load_issue_by_index
# return render_parameter_missing if params[:pm_project_id].blank? || params[:pm_issue_type].blank? || params[:enterprise_identifier].blank?
# @issue = Issue.find_issues_by_pm(params[:enterprise_identifier], params[:pm_issue_type])
# .find_by(pm_issue_type_index3: params[:index])
# render_not_found('疑修不存在!') if @issue.blank?
# end
2023-11-01 16:49:00 +08:00
def load_issues
return render_error('请输入正确的ID数组') unless params[:ids].is_a?(Array)
params[:ids].each do |id|
@issue = Issue.find_by(id: id, pm_project_id: params[:pm_project_id])
return render_not_found("ID为#{id}的疑修不存在!") if @issue.blank?
2023-11-01 10:42:27 +08:00
end
if params[:ids].blank?
@issues = Issue.where(pm_project_id: params[:pm_project_id])
else
@issues = Issue.where(id: params[:ids], pm_project_id: params[:pm_project_id])
end
2023-11-01 10:42:27 +08:00
end
2023-11-01 16:49:00 +08:00
2023-11-01 10:42:27 +08:00
def query_params
params.permit(
:only_name,
:category,
:participant_category,
:keyword, :author_id,
:milestone_id, :assigner_id,
:status_id, :priority_id,
2023-11-01 10:42:27 +08:00
:begin_date, :end_date,
2024-03-26 17:31:47 +08:00
:update_begin_date, :update_end_date,
2023-11-07 14:30:28 +08:00
:sort_by, :sort_direction, :root_id,
2024-01-25 15:49:03 +08:00
:issue_tag_ids, :pm_project_id, :pm_sprint_id, :pm_issue_type, :pm_project_ids,
:status_ids, :ids, :exclude_ids, :pm_issue_types, :participator_id, :enterprise_identifier
2023-11-01 10:42:27 +08:00
)
end
def issue_params
params.permit(
:status_id, :priority_id, :milestone_id,
2023-11-07 09:40:50 +08:00
:branch_name, :start_date, :due_date, :time_scale,
2024-05-27 11:51:51 +08:00
:subject, :description, :blockchain_token_num, :root_subject,
2023-11-17 17:18:34 +08:00
:pm_project_id, :pm_sprint_id, :pm_issue_type, :root_id, :link_able_id, :project_id,
2025-05-21 09:33:00 +08:00
:status_msg, :enterprise_identifier,
2023-11-01 10:42:27 +08:00
issue_tag_ids: [],
assigner_ids: [],
attachment_ids: [],
receivers_login: []
)
end
2023-11-02 09:17:32 +08:00
2023-11-09 14:20:34 +08:00
def batch_issue_params
params.permit(
2024-01-31 08:43:10 +08:00
:status_id, :priority_id, :milestone_id, :pm_sprint_id, :due_date, :pm_issue_type, :root_id, :target_pm_project_id, :project_id,
2023-11-09 14:20:34 +08:00
:issue_tag_ids => [],
:assigner_ids => [] )
end
2023-12-13 11:05:16 +08:00
def issue_sort_by
sort_by = params.fetch(:sort_by, "updated_on")
sort_by = Issue.column_names.include?(sort_by) ? sort_by : "updated_on"
sort_by
end
def issue_sort_direction
sort_direction = params.fetch(:sort_direction, "desc").downcase
sort_direction = %w(desc asc).include?(sort_direction) ? sort_direction : "desc"
sort_direction
end
2023-11-02 09:17:32 +08:00
def tag_sort_by
sort_by = params.fetch(:sort_by, "created_at")
sort_by = IssueTag.column_names.include?(sort_by) ? sort_by : "created_at"
sort_by
end
def tag_sort_direction
sort_direction = params.fetch(:sort_direction, "desc").downcase
sort_direction = %w(desc asc).include?(sort_direction) ? sort_direction : "desc"
sort_direction
end
2023-11-01 10:42:27 +08:00
end