forked from Gitlink/forgeplus
Merge branch 'standalone_develop' into dev_osredm_server
This commit is contained in:
commit
50cb870c34
5
Gemfile
5
Gemfile
|
@ -70,6 +70,7 @@ group :development do
|
|||
gem 'web-console', '>= 3.3.0'
|
||||
gem 'listen', '>= 3.0.5', '< 3.2'
|
||||
gem 'spring'
|
||||
gem 'pry-rails'
|
||||
gem 'spring-watcher-listen', '~> 2.0.0'
|
||||
gem "annotate", "~> 2.6.0"
|
||||
end
|
||||
|
@ -140,4 +141,6 @@ gem 'doorkeeper'
|
|||
|
||||
gem 'doorkeeper-jwt'
|
||||
|
||||
gem 'gitea-client', '~> 1.5.7'
|
||||
gem 'gitea-client', '~> 1.5.8'
|
||||
|
||||
gem 'loofah', '~> 2.20.0'
|
|
@ -0,0 +1,2 @@
|
|||
// Place all the behaviors and hooks related to the matching controller here.
|
||||
// All this logic will automatically be available in application.js.
|
|
@ -40,6 +40,13 @@ body {
|
|||
}
|
||||
}
|
||||
}
|
||||
.editormd .CodeMirror{
|
||||
margin-top: 35px!important;
|
||||
}
|
||||
|
||||
.CodeMirror-gutter .CodeMirror-linenumbers {
|
||||
width: 28px!important;
|
||||
}
|
||||
|
||||
input.form-control {
|
||||
font-size: 14px;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
// Place all the styles related to the api/v1/sonarqubes controller here.
|
||||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -23,10 +23,23 @@ class Admins::BaseController < ApplicationController
|
|||
def require_admin!
|
||||
return if current_user.blank? || !current_user.logged?
|
||||
return if current_user.admin_or_business?
|
||||
return if current_user.admin_or_glcc_admin?
|
||||
|
||||
render_forbidden
|
||||
end
|
||||
|
||||
def require_admin
|
||||
render_forbidden unless User.current.admin?
|
||||
end
|
||||
|
||||
def require_business
|
||||
render_forbidden unless admin_or_business?
|
||||
end
|
||||
|
||||
def require_glcc_admin
|
||||
render_forbidden unless admin_or_glcc_admin?
|
||||
end
|
||||
|
||||
# 触发after ajax render partial hooks,执行一些因为局部刷新后失效的绑定事件
|
||||
def rebind_event_if_ajax_render_partial
|
||||
return if request.format.symbol != :js
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::EduSettingsController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :find_setting, only: [:edit,:update, :destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::FaqsController < Admins::BaseController
|
||||
before_action :require_business
|
||||
before_action :find_faq, only: [:edit,:update, :destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::FeedbacksController < Admins::BaseController
|
||||
before_action :require_business
|
||||
before_action :get_feedback, only: [:new_history, :create_history, :destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
class Admins::GlccPrCheckController < Admins::BaseController
|
||||
before_action :require_glcc_admin
|
||||
|
||||
def index
|
||||
params[:sort_by] = params[:sort_by].presence || 'created_on'
|
||||
params[:sort_direction] = params[:sort_direction].presence || 'desc'
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::IdentityVerificationsController < Admins::BaseController
|
||||
before_action :require_business
|
||||
before_action :finder_identity_verification, except: [:index]
|
||||
def index
|
||||
params[:sort_by] = params[:sort_by].presence || 'created_at'
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::IssuesRankController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
|
||||
def index
|
||||
@statistics = DailyProjectStatistic.where('date >= ? AND date <= ?', begin_date, end_date)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::LaboratoriesController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
def index
|
||||
default_sort('id', 'desc')
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::MessageTemplatesController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :get_template, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
|
@ -7,12 +8,12 @@ class Admins::MessageTemplatesController < Admins::BaseController
|
|||
end
|
||||
|
||||
def new
|
||||
@message_template = MessageTemplate.new
|
||||
@message_template = MessageTemplate::CustomTip.new
|
||||
end
|
||||
|
||||
def create
|
||||
@message_template = MessageTemplate::CustomTip.new(message_template_params)
|
||||
@message_template.type = "MessageTemplate::CustomTip"
|
||||
def create
|
||||
@message_template = MessageTemplate::CustomTip.new
|
||||
@message_template.attributes = message_template_params
|
||||
if @message_template.save!
|
||||
redirect_to admins_message_templates_path
|
||||
flash[:success] = "创建消息模板成功"
|
||||
|
@ -47,9 +48,7 @@ class Admins::MessageTemplatesController < Admins::BaseController
|
|||
|
||||
private
|
||||
def message_template_params
|
||||
# type = @message_template.present? ? @message_template.type : "MessageTemplate::CustomTip"
|
||||
# params.require(type.split("::").join("_").underscore.to_sym).permit!
|
||||
params.require(:message_template_custom_tip).permit!
|
||||
params.require(@message_template.type.split("::").join("_").underscore.to_sym).permit!
|
||||
end
|
||||
|
||||
def get_template
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::NpsController < Admins::BaseController
|
||||
before_action :require_business
|
||||
def index
|
||||
@on_off_switch = EduSetting.get("nps-on-off-switch").to_s == 'true'
|
||||
@user_nps = UserNp.joins(:user).order(created_at: :desc)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
class Admins::OrganizationsController < Admins::BaseController
|
||||
before_action :finder_org, except: [:index]
|
||||
before_action :require_admin
|
||||
before_action :finder_org, except: [:index]
|
||||
|
||||
def index
|
||||
params[:sort_by] = params[:sort_by].presence || 'created_on'
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::PageThemesController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :finder_page_theme, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::ProjectCategoriesController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :get_category, only: [:edit,:update, :destroy]
|
||||
before_action :validate_names, only: [:create, :update]
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::ProjectIgnoresController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :set_ignore, only: [:edit,:update, :destroy,:show]
|
||||
# before_action :validate_params, only: [:create, :update]
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::ProjectLanguagesController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :get_language, only: [:edit,:update, :destroy]
|
||||
before_action :validate_names, only: [:create, :update]
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::ProjectLicensesController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :set_license, only: [:edit,:update, :destroy,:show]
|
||||
# before_action :validate_params, only: [:create, :update]
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::ProjectsController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :find_project, only: [:edit, :update, :sync_phenglei_user]
|
||||
|
||||
def index
|
||||
|
@ -42,8 +43,12 @@ class Admins::ProjectsController < Admins::BaseController
|
|||
def destroy
|
||||
project = Project.find_by!(id: params[:id])
|
||||
ActiveRecord::Base.transaction do
|
||||
Gitea::Repository::DeleteService.new(project.owner, project.identifier).call
|
||||
close_fork_pull_requests_by(project)
|
||||
Gitea::Repository::DeleteService.new(project.owner, project.identifier, current_user.gitea_token).call
|
||||
project.destroy!
|
||||
project.forked_projects.update_all(forked_from_project_id: nil)
|
||||
# 如果该项目有所属的项目分类以及为私有项目,需要更新对应数量
|
||||
project.project_category.decrement!(:private_projects_count, 1) if project.project_category.present? && !project.is_public
|
||||
# render_delete_success
|
||||
UserAction.create(action_id: project.id, action_type: "DestroyProject", user_id: current_user.id, :ip => request.remote_ip, data_bank: project.attributes.to_json)
|
||||
redirect_to admins_projects_path
|
||||
|
@ -84,4 +89,19 @@ class Admins::ProjectsController < Admins::BaseController
|
|||
def project_update_params
|
||||
params.require(:project).permit(:is_pinned, :recommend, :recommend_index)
|
||||
end
|
||||
|
||||
def close_fork_pull_requests_by(project)
|
||||
open_pull_requests = PullRequest.where(fork_project_id: project.id)
|
||||
if open_pull_requests.present?
|
||||
open_pull_requests.each do |pull_request|
|
||||
closed = PullRequests::CloseService.call(pull_request&.project.owner, pull_request&.project.repository, pull_request, current_user)
|
||||
if closed === true
|
||||
pull_request.project_trends.create!(user: current_user, project: pull_request&.project,action_type: ProjectTrend::CLOSE)
|
||||
# 合并请求下issue处理为关闭
|
||||
pull_request.issue&.update_attributes!({status_id:5})
|
||||
SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, pull_request.id) if Site.has_notice_menu?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,4 +1,6 @@
|
|||
class Admins::ProjectsRankController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
|
||||
def index
|
||||
@statistics = DailyProjectStatistic.where("date >= ? AND date <= ?", begin_date, end_date)
|
||||
@statistics = @statistics.group(:project_id).select("project_id,
|
||||
|
@ -10,7 +12,7 @@ class Admins::ProjectsRankController < Admins::BaseController
|
|||
sum(issues) as issues,
|
||||
sum(pullrequests) as pullrequests,
|
||||
sum(commits) as commits").includes(:project)
|
||||
@statistics = @statistics.order("#{sort_by} #{sort_direction}")
|
||||
@statistics = paginate @statistics.order("#{sort_by} #{sort_direction}")
|
||||
export_excel(@statistics.limit(50))
|
||||
end
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::ReversedKeywordsController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :get_keyword, only: [:edit,:update, :destroy]
|
||||
# before_action :validate_identifer, only: [:create, :update]
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::SitePagesController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :finder_site_page, except: [:index]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::SitesController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :find_site, only: [:edit,:update, :destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::SystemNotificationsController < Admins::BaseController
|
||||
before_action :require_business
|
||||
before_action :get_notification, only: [:history, :edit,:update, :destroy]
|
||||
# before_action :validate_identifer, only: [:create, :update]
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::Topic::ActivityForumsController < Admins::Topic::BaseController
|
||||
before_action :require_business
|
||||
before_action :find_activity_forum, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::Topic::BannersController < Admins::Topic::BaseController
|
||||
before_action :require_business
|
||||
before_action :find_banner, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::Topic::CardsController < Admins::Topic::BaseController
|
||||
before_action :require_business
|
||||
before_action :find_card, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::Topic::CooperatorsController < Admins::Topic::BaseController
|
||||
before_action :require_business
|
||||
before_action :find_cooperator, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::Topic::ExcellentProjectsController < Admins::Topic::BaseController
|
||||
before_action :require_business
|
||||
before_action :find_excellent_project, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::Topic::ExperienceForumsController < Admins::Topic::BaseController
|
||||
before_action :require_business
|
||||
before_action :find_experience_forum, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::Topic::GlccNewsController < Admins::Topic::BaseController
|
||||
before_action :require_glcc_admin
|
||||
before_action :find_glcc, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::Topic::PinnedForumsController < Admins::Topic::BaseController
|
||||
before_action :require_business
|
||||
before_action :find_pinned_forum, only: [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
class Admins::UsersController < Admins::BaseController
|
||||
before_action :finder_user, except: [:index, :export]
|
||||
before_action :require_admin
|
||||
before_action :finder_user, except: [:index, :export]
|
||||
|
||||
def index
|
||||
params[:sort_by] = params[:sort_by].presence || 'created_on'
|
||||
|
@ -134,6 +135,8 @@ class Admins::UsersController < Admins::BaseController
|
|||
end
|
||||
|
||||
def validate_create_params
|
||||
create_params.slice(:phone, :password)
|
||||
params.require(:user).permit(%i[lastname nickname gender technical_title is_shixun_marker
|
||||
mail phone location location_city school_id department_id admin
|
||||
password login website_permission business glcc_admin])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::UsersRankController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
|
||||
def index
|
||||
@rank_date = rank_date
|
||||
|
|
|
@ -2,19 +2,44 @@ class Api::Pm::IssueLinksController < Api::Pm::BaseController
|
|||
before_action :load_project
|
||||
before_action :load_issue
|
||||
def index
|
||||
@links = @issue.pm_links.where(be_linkable_type: 'Issue')
|
||||
@links = PmLink.where(be_linkable_id: @issue.id,be_linkable_type: 'Issue').or(PmLink.where(linkable_id: @issue.id,linkable_type: 'Issue'))
|
||||
end
|
||||
|
||||
def create
|
||||
params[:link_ids].map { |e| @issue.pm_links.find_or_create_by(be_linkable_type: 'Issue', be_linkable_id: e) }
|
||||
render_ok
|
||||
begin
|
||||
ActiveRecord::Base.transaction do
|
||||
params[:link_ids].each do |e|
|
||||
@issue.pm_links.find_or_create_by!(be_linkable_type: 'Issue', be_linkable_id: e)
|
||||
tag_issue = Issue.find_by_id(e)
|
||||
next unless tag_issue.present?
|
||||
journal = tag_issue.journals.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: "tag_link_issue", prop_key: "1", value: @issue.id.to_s})
|
||||
end
|
||||
journal = @issue.journals.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: "tag_link_issue", prop_key: "#{params[:link_ids].size}", value: params[:link_ids].join(",")})
|
||||
end
|
||||
render_ok
|
||||
rescue
|
||||
render_error('创建失败!')
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@link = @issue.pm_links.find_by(be_linkable_type: 'Issue', be_linkable_id: params[:id])
|
||||
if @link.try(:destroy)
|
||||
begin
|
||||
ActiveRecord::Base.transaction do
|
||||
@links = PmLink.where(be_linkable_id: @issue.id, be_linkable_type: 'Issue', linkable_id: params[:id], linkable_type: 'Issue').or(PmLink.where(linkable_id: @issue.id, linkable_type: 'Issue', be_linkable_id: params[:id], be_linkable_type: 'Issue'))
|
||||
journal = @issue.journals.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: "tag_link_issue", prop_key: "1", old_value: params[:id].to_s})
|
||||
another_issue = Issue.find_by_id(params[:id])
|
||||
if another_issue.present?
|
||||
journal = another_issue.journals.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: "tag_link_issue", prop_key: "1", old_value: @issue.id.to_s})
|
||||
end
|
||||
@link = @links.last
|
||||
@link.destroy!
|
||||
end
|
||||
render_ok
|
||||
else
|
||||
rescue
|
||||
render_error('删除失败!')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -62,17 +62,17 @@ class Api::Pm::IssuesController < Api::Pm::BaseController
|
|||
end
|
||||
|
||||
def create
|
||||
@object_result = Api::V1::Issues::CreateService.call(@project, issue_params, current_user)
|
||||
@object_result = Api::Pm::Issues::CreateService.call(@project, issue_params, current_user)
|
||||
render 'api/v1/issues/create'
|
||||
end
|
||||
|
||||
def update
|
||||
@object_result = Api::V1::Issues::UpdateService.call(@project, @issue, issue_params, current_user)
|
||||
@object_result = Api::Pm::Issues::UpdateService.call(@project, @issue, issue_params, current_user)
|
||||
render 'api/v1/issues/update'
|
||||
end
|
||||
|
||||
def batch_update
|
||||
@object_result = Api::V1::Issues::BatchUpdateService.call(@project, @issues, batch_issue_params, current_user)
|
||||
@object_result = Api::Pm::Issues::BatchUpdateService.call(@project, @issues, batch_issue_params, current_user)
|
||||
if @object_result
|
||||
render_ok
|
||||
else
|
||||
|
@ -82,7 +82,7 @@ class Api::Pm::IssuesController < Api::Pm::BaseController
|
|||
|
||||
def batch_destroy
|
||||
return render_ok if params[:ids].is_a?(Array) && params[:ids].blank?
|
||||
@object_result = Api::V1::Issues::BatchDeleteService.call(@project, @issues, current_user)
|
||||
@object_result = Api::Pm::Issues::BatchDeleteService.call(@project, @issues, current_user)
|
||||
if @object_result
|
||||
render_ok
|
||||
else
|
||||
|
@ -116,7 +116,7 @@ class Api::Pm::IssuesController < Api::Pm::BaseController
|
|||
|
||||
|
||||
def destroy
|
||||
@object_result = Api::V1::Issues::DeleteService.call(@project, @issue, current_user)
|
||||
@object_result = Api::Pm::Issues::DeleteService.call(@project, @issue, current_user)
|
||||
if @object_result
|
||||
render_ok
|
||||
else
|
||||
|
@ -124,6 +124,119 @@ class Api::Pm::IssuesController < Api::Pm::BaseController
|
|||
end
|
||||
end
|
||||
|
||||
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", "标题*", "正文", "创建者*", "创建时间", "修改者", "更新时间", "状态", "负责人", "优先级", "标记", "开始时间","结束时间", "预估工时"]
|
||||
@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]
|
||||
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]})
|
||||
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
|
||||
p.serialize('public/导出工作项.xlsx')
|
||||
end
|
||||
|
||||
send_file('public/导出工作项.xlsx', :type => 'application/octet-stream;charset=utf-8')
|
||||
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]
|
||||
author = User.find_by(login: row[3])
|
||||
issue.user = author
|
||||
issue.created_on = row[4]
|
||||
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?
|
||||
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)
|
||||
end
|
||||
else
|
||||
return render_error('导入失败,请上传正确格式的excel文件')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
render_ok
|
||||
rescue
|
||||
return render_error('导入失败,请上传正确格式的excel文件')
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def check_issue_operate_permission
|
||||
return if params[:project_id].to_i.zero?
|
||||
|
|
|
@ -10,7 +10,7 @@ class Api::Pm::JournalsController < Api::Pm::BaseController
|
|||
@total_operate_journals_count = @object_result[:total_operate_journals_count]
|
||||
@total_comment_journals_count = @object_result[:total_comment_journals_count]
|
||||
@journals = kaminary_select_paginate(@object_result[:data])
|
||||
render 'api/v1/issues/journals/index'
|
||||
render 'api/pm/issues/journals/index'
|
||||
end
|
||||
|
||||
def create
|
||||
|
|
|
@ -55,11 +55,12 @@ class Api::Pm::ProjectsController < Api::Pm::BaseController
|
|||
|
||||
def statistics
|
||||
return tip_exception '参数错误' if params[:pm_project_id].blank?
|
||||
@issues = Issue.where(pm_project_id: params[:pm_project_id])
|
||||
@issues = Issue.where(pm_project_id: params[:pm_project_id], pm_issue_type:[1, 2, 3])
|
||||
type_count_data = @issues.group(:pm_issue_type).count
|
||||
type_status = @issues.group(:pm_issue_type,:status_id).count
|
||||
type_status_data = {}
|
||||
IssueStatus.all.map do |e|
|
||||
# next if e.id == 5
|
||||
[1,2,3].map{ |type|
|
||||
type_status_data[type] = {} if type_status_data[type].nil?
|
||||
if type_status[[type,e.id]].nil?
|
||||
|
|
|
@ -17,7 +17,8 @@ class Api::Pm::SprintIssuesController < Api::Pm::BaseController
|
|||
data = []
|
||||
curren_issues = @issues.group(:status_id, :due_date).count
|
||||
total_count = @issues.count
|
||||
cardinality = BigDecimal.new(total_count) / BigDecimal.new(time_count)
|
||||
cardinality = (total_count.zero? || time_count.zero?) ? 0 : total_count.to_f / time_count.to_f
|
||||
# cardinality = BigDecimal.new(total_count) / BigDecimal.new(time_count)
|
||||
time_count.times do |x|
|
||||
e_time = start_time + x
|
||||
completed = curren_issues[[5, e_time]].to_i + curren_issues[[3, e_time]].to_i - @issues.where(pm_issue_type: 3, status_id: 3).size
|
||||
|
|
|
@ -5,6 +5,17 @@ class Api::V1::Projects::Actions::RunsController < Api::V1::Projects::Actions::B
|
|||
puts @result_object
|
||||
end
|
||||
|
||||
def create
|
||||
return render_error("请输入正确的流水线文件!") if params[:workflow].blank?
|
||||
return render_error("请输入正确的分支!") if params[:ref].blank?
|
||||
gitea_result = $gitea_hat_client.post_repos_actions_runs_by_owner_repo(@project&.owner&.login, @project&.identifier, {query: {workflow: params[:workflow], ref: params[:ref]}})
|
||||
if gitea_result
|
||||
render_ok
|
||||
else
|
||||
ender_error("启动流水线任务失败")
|
||||
end
|
||||
end
|
||||
|
||||
def rerun
|
||||
return render_error("请输入正确的流水线记录ID!") if params[:run_id].blank?
|
||||
gitea_result = $gitea_hat_client.post_repos_actions_runs_rerun_by_owner_repo_run(@project&.owner&.login, @project&.identifier, params[:run_id]) rescue nil
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
class Api::V1::Projects::PortraitController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above
|
||||
|
||||
def index
|
||||
platform_statistic = $redis_cache.hgetall("v2-platform-statistic")
|
||||
|
||||
# 社区影响力
|
||||
praise_count = PraiseTread.where(praise_tread_object_type: "Project", praise_tread_object_id: @project.id).count
|
||||
watcher_count = Watcher.where(watchable_type:"Project", watchable_id: @project.id).count
|
||||
fork_count = ForkUser.where(project_id: @project.id).count
|
||||
community_impact_praise = platform_statistic['max-praise-count'].to_i == 0 ? 0 : 30*(praise_count.to_f/platform_statistic['max-praise-count'].to_i)
|
||||
community_impact_watcher = platform_statistic['max-watcher-count'].to_i == 0 ? 0 : 30*(watcher_count.to_f/platform_statistic['max-watcher-count'].to_i)
|
||||
community_impact_fork = platform_statistic['max-fork-count'].to_i == 0 ? 0 : 40*(fork_count.to_f/platform_statistic['max-fork-count'].to_i)
|
||||
community_impact = format("%.2f", community_impact_praise + community_impact_watcher + community_impact_fork)
|
||||
|
||||
# 项目成熟度
|
||||
pullrequest_count = PullRequest.where(project_id: @project.id).count
|
||||
issue_count = Issue.issue_issue.where(project_id: @project.id).count
|
||||
commit_count = CommitLog.joins(:project).merge(Project.common).where(project_id: @project.id).count
|
||||
project_maturity_pullrequest = platform_statistic['max-pullrequest-count'].to_i == 0 ? 0 : 30*(pullrequest_count.to_f/platform_statistic['max-pullrequest-count'].to_i)
|
||||
project_maturity_issue = platform_statistic['max-issue-count'].to_i == 0 ? 0 : 30*(issue_count.to_f/platform_statistic['max-issue-count'].to_i)
|
||||
project_maturity_commit = platform_statistic['max-commit-count'].to_i == 0 ? 0 : 40*(commit_count.to_f/platform_statistic['max-commit-count'].to_i)
|
||||
project_maturity = format("%.2f", project_maturity_pullrequest + project_maturity_issue + project_maturity_commit)
|
||||
|
||||
# 项目健康度
|
||||
closed_pullrequest_count = PullRequest.where(project_id: @project.id).merged_and_closed.count
|
||||
closed_issue_count = Issue.issue_issue.where(project_id: @project.id).closed.count
|
||||
has_license = @project.license.present? ? 1 : 0
|
||||
project_health_issue = (issue_count < 10 || closed_issue_count < 10) ? 0 : 40*(closed_issue_count-10).to_f/(issue_count-10)
|
||||
project_health_pullrequest = (pullrequest_count < 5 || closed_pullrequest_count < 5) ? 0 : 30*(closed_pullrequest_count-5).to_f/(pullrequest_count-5)
|
||||
project_health_license = 20*has_license
|
||||
project_health = format("%.2f", project_health_issue + project_health_pullrequest + project_health_license)
|
||||
|
||||
# 团队影响度
|
||||
member_count = Member.where(project_id: @project.id).count
|
||||
recent_one_month_member_count = Member.where(project_id:@project.id).where("created_on > ?", Time.now - 30.days).count
|
||||
team_impact_member = platform_statistic['max-member-count'].to_i == 0 ? 0 : 40*(member_count.to_f/platform_statistic['max-member-count'].to_i)
|
||||
team_impact_recent_member = platform_statistic['max-recent-one-month-member-count'].to_i == 0 ? 0 : 60*(recent_one_month_member_count.to_f/platform_statistic['max-recent-one-month-member-count'].to_i)
|
||||
team_impact = format("%.2f", team_impact_member + team_impact_recent_member)
|
||||
|
||||
# 开发活跃度
|
||||
recent_one_month_pullrequest_count = PullRequest.where(project_id: @project.id).where("created_at > ?", Time.now - 30.days).count
|
||||
recent_one_month_issue_count = Issue.issue_issue.where(project_id: @project.id).where("created_on > ?", Time.now - 30.days).count
|
||||
recent_one_month_commit_count = CommitLog.joins(:project).merge(Project.common).where(project_id: @project.id).where("created_at > ?", Time.now - 30.days).count
|
||||
develop_activity_pullrequest = platform_statistic['max-recent-one-month-pullrequest-count'].to_i == 0 ? 0 : 20*(recent_one_month_pullrequest_count.to_f/platform_statistic['max-recent-one-month-pullrequest-count'].to_i)
|
||||
develop_activity_issue = platform_statistic['max-recent-one-month-issue-count'].to_i == 0 ? 0 : 20*(recent_one_month_issue_count.to_f/platform_statistic['max-recent-one-month-issue-count'].to_i)
|
||||
develop_activity_commit = platform_statistic['max-recent-one-month-commit-count'].to_i == 0 ? 0 : 40*(recent_one_month_commit_count.to_f/platform_statistic['max-recent-one-month-commit-count'].to_i)
|
||||
develop_activity = format("%.2f", 20 + develop_activity_pullrequest + develop_activity_issue + develop_activity_commit)
|
||||
|
||||
render :json => {community_impact: community_impact, project_maturity: project_maturity, project_health: project_health, team_impact: team_impact, develop_activity: develop_activity}
|
||||
end
|
||||
end
|
|
@ -1,5 +1,5 @@
|
|||
class Api::V1::ProjectsController < Api::V1::BaseController
|
||||
before_action :require_public_and_member_above, only: [:show, :compare, :blame]
|
||||
before_action :require_public_and_member_above, only: [:show, :compare, :blame, :sonar_search]
|
||||
|
||||
def index
|
||||
render_ok
|
||||
|
@ -9,6 +9,7 @@ class Api::V1::ProjectsController < Api::V1::BaseController
|
|||
@result_object = Api::V1::Projects::GetService.call(@project, current_user.gitea_token)
|
||||
end
|
||||
|
||||
|
||||
def compare
|
||||
@result_object = Api::V1::Projects::CompareService.call(@project, params[:from], params[:to], current_user&.gitea_token)
|
||||
end
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
class Api::V1::Sonarqubes::IssuesController < ApplicationController
|
||||
def index
|
||||
data = Sonarqube.client.get("/api/issues/search",params)
|
||||
render_ok data
|
||||
end
|
||||
end
|
|
@ -0,0 +1,171 @@
|
|||
class Api::V1::SonarqubesController < Api::V1::BaseController
|
||||
before_action :load_repository
|
||||
def sonar_initialize
|
||||
gitea_params = { has_actions: params[:has_actions] == 'true' ? true :false }
|
||||
gitea_setting = Gitea::Repository::UpdateService.call(@owner, @project.identifier, gitea_params)
|
||||
if gitea_setting['has_actions'] == true
|
||||
Gitea::Repository::ActionSecretsService.new(@owner, @project.identifier, 'SONAR_HOST_URL', Rails.application.config_for(:configuration)['sonarqube']['url'] ).call
|
||||
Gitea::Repository::ActionSecretsService.new(@owner, @project.identifier, 'SONAR_TOKEN', Rails.application.config_for(:configuration)['sonarqube']['secret'] ).call
|
||||
else
|
||||
Gitea::Repository::ActionSecretsService.new(@owner, @project.identifier, 'SONAR_HOST_URL', Rails.application.config_for(:configuration)['sonarqube']['url'] ).destroy
|
||||
Gitea::Repository::ActionSecretsService.new(@owner, @project.identifier, 'SONAR_TOKEN', Rails.application.config_for(:configuration)['sonarqube']['secret'] ).destroy
|
||||
end
|
||||
@project.update(gitea_params)
|
||||
render_ok
|
||||
end
|
||||
|
||||
def insert_file
|
||||
checkout_url = 'https://gitlink.org.cn/KingChan/checkout@v4'
|
||||
scanner_url = 'https://gitlink.org.cn/KingChan/sonarqube-scan-action@master'
|
||||
begin
|
||||
config = Rails.application.config_for(:configuration)
|
||||
sonarqube_config = config.dig('sonarqube')
|
||||
|
||||
if sonarqube_config.present? && sonarqube_config['checkout'].present?
|
||||
checkout_url = sonarqube_config['checkout']
|
||||
end
|
||||
if sonarqube_config.present? && sonarqube_config['scanner'].present?
|
||||
scanner_url = sonarqube_config['scanner']
|
||||
end
|
||||
|
||||
raise 'sonar config missing' if sonarqube_config.blank?
|
||||
rescue => ex
|
||||
raise ex if Rails.env.production?
|
||||
|
||||
puts %Q{\033[33m [warning] soanrqube config or configuration.yml missing,
|
||||
please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m}
|
||||
end
|
||||
|
||||
sonar_scanner_content = {
|
||||
filepath: '.gitea/workflows/SonarScanner.yaml',
|
||||
branch: params[:branch],
|
||||
new_branch: nil,
|
||||
content: "
|
||||
on:
|
||||
# Trigger analysis when pushing to your main branches, and when creating a pull request.
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
- develop
|
||||
- 'releases/**'
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
name: Main Workflow
|
||||
jobs:
|
||||
sonarqube:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: #{checkout_url}
|
||||
with:
|
||||
# Disabling shallow clones is recommended for improving the relevancy of reporting
|
||||
fetch-depth: 0
|
||||
- name: SonarQube Scan
|
||||
uses: #{scanner_url}
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
||||
",
|
||||
message: 'Add .gitea/workflows/SonarScanner.yaml',
|
||||
committer: {
|
||||
email: @owner.mail,
|
||||
name: @owner.login
|
||||
},
|
||||
identifier: @project.identifier
|
||||
}
|
||||
@path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{params[:branch]}/"
|
||||
sonar_scanner_exit = Repositories::EntriesInteractor.call(@owner, @project.identifier, '.gitea/workflows/SonarScanner.yaml', ref: params[:branch])
|
||||
if sonar_scanner_exit.success?
|
||||
Gitea::UpdateFileInteractor.call(@owner.gitea_token, @owner.login, sonar_scanner_content.merge(sha:sonar_scanner_exit.result['sha']))
|
||||
else
|
||||
sonar_scanner_content[:content] = Base64.strict_encode64(sonar_scanner_content[:content])
|
||||
Gitea::CreateFileInteractor.call(@owner.gitea_token, @owner.login, sonar_scanner_content)
|
||||
end
|
||||
|
||||
sonar_project_content = {
|
||||
filepath: 'sonar-project.properties',
|
||||
branch: params[:branch],
|
||||
new_branch: nil,
|
||||
"content": "sonar.projectKey=#{params[:owner]}-#{@project.id}\nsonar.sources=.\nsonar.java.binaries=.",
|
||||
"message": 'Add sonar-project.properties',
|
||||
committer: {
|
||||
email: @owner.mail,
|
||||
name: @owner.login
|
||||
},
|
||||
identifier: @project.identifier
|
||||
}
|
||||
sonar_project_exit = Repositories::EntriesInteractor.call(@owner, @project.identifier, 'sonar-project.properties', ref: params[:branch])
|
||||
if sonar_project_exit.success?
|
||||
Gitea::UpdateFileInteractor.call(@owner.gitea_token, @owner.login, sonar_project_content.merge(sha:sonar_project_exit.result['sha']))
|
||||
else
|
||||
sonar_project_content[:content] = Base64.strict_encode64(sonar_project_content[:content])
|
||||
Gitea::CreateFileInteractor.call(@owner.gitea_token, @owner.login, sonar_project_content)
|
||||
end
|
||||
render_ok
|
||||
end
|
||||
|
||||
def issues_search
|
||||
params_data = {
|
||||
components: "#{params[:owner]}-#{@project.id}",
|
||||
s: params[:s],
|
||||
impactSoftwareQualities: params[:impactSoftwareQualities],
|
||||
issueStatuses: params[:issueStatuses],
|
||||
ps: params[:ps],
|
||||
p: params[:p],
|
||||
facets: params[:facets],
|
||||
additionalFields: params[:additionalFields],
|
||||
timeZone: params[:timeZone],
|
||||
types: params[:types],
|
||||
impactSeverities: params[:impactSeverities],
|
||||
tags: params[:tags]
|
||||
}
|
||||
data = Sonarqube.client.get('/api/issues/search', query: params_data)
|
||||
render_ok data
|
||||
end
|
||||
|
||||
def ce_component
|
||||
params_data = {
|
||||
components: "#{params[:owner]}-#{@project.id}",
|
||||
}
|
||||
data = Sonarqube.client.get('/api/ce/component', query: params_data)
|
||||
render_ok data
|
||||
end
|
||||
|
||||
def sources_issue_snippet
|
||||
params_data = {
|
||||
issueKey: params[:issueKey]
|
||||
}
|
||||
data = Sonarqube.client.get('/api/sources/issue_snippets', query: params_data)
|
||||
render_ok data
|
||||
end
|
||||
|
||||
def rules_show
|
||||
params_data = {
|
||||
key: params[:key]
|
||||
}
|
||||
data = Sonarqube.client.get('/api/rules/show', query: params_data)
|
||||
render_ok data
|
||||
end
|
||||
|
||||
def measures_search_history
|
||||
params_data = {
|
||||
from: params[:form],
|
||||
component: "#{params[:owner]}-#{@project.id}",
|
||||
metrics: params[:metrics],
|
||||
ps: params[:ps]
|
||||
}
|
||||
data = Sonarqube.client.get('/api/measures/search_history', query: params_data)
|
||||
render_ok data
|
||||
end
|
||||
|
||||
def measures_component
|
||||
params_data = {
|
||||
component: "#{params[:owner]}-#{@project.id}",
|
||||
additionalFields: params[:additionalFields],
|
||||
metricKeys: params[:metricKeys]
|
||||
}
|
||||
data = Sonarqube.client.get('/api/measures/component', query: params_data)
|
||||
render_ok data
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
class Api::V1::Users::HomeTopSettingsController < Api::V1::BaseController
|
||||
|
||||
before_action :load_observe_user
|
||||
before_action :check_auth_for_observe_user
|
||||
|
||||
def create
|
||||
@result = Api::V1::Users::HomeTopSettings::CreateService.call(@observe_user, home_top_setting_params)
|
||||
return render_error("置顶失败.") if @result.nil?
|
||||
return render_ok
|
||||
end
|
||||
|
||||
def cancel
|
||||
@result = Api::V1::Users::HomeTopSettings::DeleteService.call(@observe_user, home_top_setting_params)
|
||||
return render_error("取消置顶失败.") if @result.nil?
|
||||
return render_ok
|
||||
end
|
||||
|
||||
private
|
||||
def home_top_setting_params
|
||||
params.permit(:top_type, :top_id)
|
||||
end
|
||||
|
||||
end
|
|
@ -72,7 +72,11 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
|
||||
def admin_or_business?
|
||||
User.current.admin? || User.current.business?
|
||||
User.current.admin? || User.current.business?
|
||||
end
|
||||
|
||||
def admin_or_glcc_admin?
|
||||
User.current.admin? || User.current.glcc_admin?
|
||||
end
|
||||
|
||||
# 判断用户的邮箱或者手机是否可用
|
||||
|
@ -164,6 +168,10 @@ class ApplicationController < ActionController::Base
|
|||
normal_status(403, "") unless admin_or_business?
|
||||
end
|
||||
|
||||
def require_glcc_admin
|
||||
normal_status(403, "") unless admin_or_glcc_admin?
|
||||
end
|
||||
|
||||
# 前端会捕捉401,弹登录弹框
|
||||
# 未授权的捕捉407,弹试用申请弹框
|
||||
def require_login
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
class Oauth::AcgeController < Oauth::BaseController
|
||||
include RegisterHelper
|
||||
|
||||
def refer
|
||||
uid = params['uid'].to_s.strip
|
||||
tip_exception("uid不能为空") if uid.blank?
|
||||
|
||||
open_user = OpenUsers::Acge.find_by(uid: uid)
|
||||
if open_user.present? && open_user.user.present?
|
||||
render :json => {login: open_user.user.login}
|
||||
else
|
||||
render_not_found
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
begin
|
||||
uid = params['uid'].to_s.strip
|
||||
|
|
|
@ -14,8 +14,11 @@ class Organizations::ProjectsController < Organizations::BaseController
|
|||
else
|
||||
@projects = Project.from("( #{ public_projects_sql} UNION #{ private_projects_sql } ) AS projects")
|
||||
end
|
||||
|
||||
@projects = @projects.ransack(name_or_identifier_cont: params[:search]).result if params[:search].present?
|
||||
keywords = params[:search].to_s.each_char.select { |c| c.bytes.first < 240 }.join('')
|
||||
@projects = @projects.where(id: params[:pm_project_repository_ids].split(',')) if params[:pm_project_repository_ids].present?
|
||||
@projects = @projects.where.not(id: params[:exclude_ids].to_s.split(",")) if params[:exclude_ids].present?
|
||||
@projects = @projects.where("gpid is not null") if params[:actived].present?
|
||||
@projects = @projects.ransack(name_or_identifier_cont: keywords).result if params[:search].present?
|
||||
@projects = @projects.includes(:owner)
|
||||
if params[:choosed].present? && params[:choosed].is_a?(Array)
|
||||
@projects = @projects.order("FIELD(projects.id, #{params[:choosed].reverse.join(",")}) desc")
|
||||
|
|
|
@ -43,11 +43,11 @@ class ProjectsController < ApplicationController
|
|||
@rand_projects = @projects
|
||||
category_id = params[:category_id]
|
||||
@total_count =
|
||||
if category_id.blank? && params[:search].blank? && params[:topic_id].blank?
|
||||
if category_id.blank? && params[:search].blank? && params[:topic_id].blank? && params[:topic_name].blank?
|
||||
# 默认查询时count性能问题处理
|
||||
not_category_count = Project.where(project_category_id: nil).count
|
||||
ProjectCategory.sum("projects_count") - Project.visible.joins("left join organization_extensions on organization_extensions.organization_id = projects.user_id").where("organization_extensions.visibility =2").count + not_category_count
|
||||
elsif params[:search].present? || params[:topic_id].present?
|
||||
elsif params[:search].present? || params[:topic_id].present? || params[:topic_name].present?
|
||||
@projects.total_count
|
||||
elsif params[:topic_id].present?
|
||||
topic = ProjectTopic.find_by(id: params[:topic_id])
|
||||
|
@ -67,7 +67,8 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
rescue Gitea::Api::ServerError => ex
|
||||
uid_logger_error(ex.message)
|
||||
tip_exception(ex.http_code, ex.message)
|
||||
# tip_exception(ex.http_code, ex.message)
|
||||
tip_exception(ex.message)
|
||||
rescue ApplicationService::Error => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
|
@ -210,7 +211,11 @@ class ProjectsController < ApplicationController
|
|||
|
||||
new_project_params = project_params.except(:private).merge(is_public: !private)
|
||||
@project.update_attributes!(new_project_params)
|
||||
@project.forked_projects.update_all(is_public: @project.is_public)
|
||||
fork_pull_requests = PullRequest.where(fork_project_id: @project.id)
|
||||
if fork_pull_requests.present?
|
||||
fork_pull_requests.update_all(fork_project_identifier: @project.identifier)
|
||||
end
|
||||
@project.forked_projects.map{|p| p.update!(is_public: @project.is_public)}
|
||||
gitea_params = {
|
||||
private: private,
|
||||
default_branch: @project.default_branch,
|
||||
|
@ -242,7 +247,8 @@ class ProjectsController < ApplicationController
|
|||
def destroy
|
||||
if current_user.admin? || @project.manager?(current_user)
|
||||
ActiveRecord::Base.transaction do
|
||||
Gitea::Repository::DeleteService.new(@project.owner, @project.identifier).call
|
||||
close_fork_pull_requests_by(@project)
|
||||
Gitea::Repository::DeleteService.new(@project.owner, @project.identifier,current_user.gitea_token).call
|
||||
@project.destroy!
|
||||
@project.forked_projects.update_all(forked_from_project_id: nil)
|
||||
# 如果该项目有所属的项目分类以及为私有项目,需要更新对应数量
|
||||
|
@ -298,6 +304,30 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
|
||||
def simple
|
||||
if !@project.common? && @project&.repository&.mirror&.waiting?
|
||||
gitea_result = $gitea_client.get_repos_by_owner_repo(@project&.owner&.login, @project&.identifier) rescue nil
|
||||
if gitea_result.present? && !gitea_result["empty"]
|
||||
@project&.update_columns(gpid: gitea_result["id"])
|
||||
@project&.repository&.mirror&.succeeded!
|
||||
project_id = @project&.id
|
||||
user_id = @project&.owner&.id
|
||||
Rails.logger.info "############ mirror project_id,user_id: #{project_id},#{user_id} ############"
|
||||
OpenProjectDevOpsJob.set(wait: 5.seconds).perform_later(project_id, user_id) if project_id.present? && user_id.present?
|
||||
UpdateProjectTopicJob.set(wait: 1.seconds).perform_later(project_id) if project_id.present?
|
||||
Rails.logger.info "############ mirror status: #{@project&.repository&.mirror&.status} ############"
|
||||
end
|
||||
elsif !@project.common? && @project&.repository&.mirror&.failed?
|
||||
# 导入失败的项目标记 project.status=0, 在列表中不显示
|
||||
@project&.update_columns(status: 0) if @project&.status == 1
|
||||
|
||||
# Rails.logger.info "############ mirror status: #{@project&.repository&.mirror&.status}"
|
||||
# Gitea::Repository::DeleteService.new(@project.owner, @project.identifier,current_user.gitea_token).call
|
||||
# @project.destroy!
|
||||
# @project.forked_projects.update_all(forked_from_project_id: nil)
|
||||
# # 如果该项目有所属的项目分类以及为私有项目,需要更新对应数量
|
||||
# @project.project_category.decrement!(:private_projects_count, 1) if @project.project_category.present? && !@project.is_public
|
||||
# return render_error("导入失败,请重试!")
|
||||
end
|
||||
# 为了缓存活跃项目的基本信息,后续删除
|
||||
Cache::V2::ProjectCommonService.new(@project.id).read
|
||||
# 项目名称,标识,所有者变化时重置缓存
|
||||
|
@ -356,7 +386,7 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
|
||||
def mirror_params
|
||||
params.permit(:user_id, :name, :description, :repository_name, :is_mirror, :auth_username, :auth_token,
|
||||
params.permit(:user_id, :name, :description, :repository_name, :is_mirror, :auth_username, :auth_token, :service,
|
||||
:auth_password, :project_category_id, :project_language_id, :clone_addr, :private)
|
||||
end
|
||||
|
||||
|
@ -374,4 +404,19 @@ class ProjectsController < ApplicationController
|
|||
render_unauthorized('你还未登录.')
|
||||
end
|
||||
end
|
||||
|
||||
def close_fork_pull_requests_by(project)
|
||||
open_pull_requests = PullRequest.where(fork_project_id: project.id)
|
||||
if open_pull_requests.present?
|
||||
open_pull_requests.each do |pull_request|
|
||||
closed = PullRequests::CloseService.call(pull_request&.project.owner, pull_request&.project.repository, pull_request, current_user)
|
||||
if closed === true
|
||||
pull_request.project_trends.create!(user: current_user, project: pull_request&.project,action_type: ProjectTrend::CLOSE)
|
||||
# 合并请求下issue处理为关闭
|
||||
pull_request.issue&.update_attributes!({status_id:5})
|
||||
SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, pull_request.id) if Site.has_notice_menu?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,6 +7,7 @@ class RepositoriesController < ApplicationController
|
|||
before_action :require_login, only: %i[edit update create_file update_file delete_file sync_mirror]
|
||||
before_action :require_profile_completed, only: [:create_file]
|
||||
before_action :load_repository
|
||||
before_action :require_operate_above, only: %i[create_file update_file replace_file delete_file]
|
||||
before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive]
|
||||
before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror]
|
||||
before_action :get_ref, only: %i[entries sub_entries top_counts files archive]
|
||||
|
@ -438,4 +439,8 @@ class RepositoriesController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def require_operate_above
|
||||
return render_forbidden if !current_user.admin? && !@project.operator?(current_user)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -10,7 +10,15 @@ class Users::OrganizationsController < Users::BaseController
|
|||
end
|
||||
|
||||
@organizations = @organizations.ransack(login_cont: params[:search]).result if params[:search].present?
|
||||
@organizations = @organizations.includes(:organization_extension).order("organization_extensions.#{sort_by} #{sort_direction}")
|
||||
|
||||
@home_top_ids = @organizations.joins(:home_top_settings).where(home_top_settings: {user_id: observed_user.id}).order("home_top_settings.created_at asc").pluck(:id)
|
||||
|
||||
if @home_top_ids.present?
|
||||
@organizations = @organizations.joins(:organization_extension).order("FIELD(users.id, #{@home_top_ids.join(",")}) desc, organization_extensions.#{sort_by} #{sort_direction}")
|
||||
else
|
||||
@organizations = @organizations.joins(:organization_extension).order("organization_extensions.#{sort_by} #{sort_direction}")
|
||||
end
|
||||
|
||||
@organizations = kaminari_paginate(@organizations)
|
||||
end
|
||||
|
||||
|
|
|
@ -20,6 +20,6 @@ class Users::ProjectsController < Users::BaseController
|
|||
private
|
||||
|
||||
def query_params
|
||||
params.permit(:category, :status, :sort_direction)
|
||||
params.permit(:category, :status, :sort_direction, :topic_name)
|
||||
end
|
||||
end
|
|
@ -408,7 +408,7 @@ class UsersController < ApplicationController
|
|||
|
||||
def projects
|
||||
is_current_admin_user = User.current.logged? && (current_user&.admin? || current_user.id == @user.id)
|
||||
scope = Projects::ListMyQuery.call(params, @user,is_current_admin_user)
|
||||
scope, @home_top_ids = Projects::ListMyQuery.call(params, @user,is_current_admin_user)
|
||||
@total_count = scope.size
|
||||
@projects = kaminari_unlimit_paginate(scope)
|
||||
end
|
||||
|
@ -706,6 +706,15 @@ class UsersController < ApplicationController
|
|||
json="{\"result\":\"success\",\"rsltcode\":\"0\",\"rsltmsg\":\"操作成功\",\"account\":\"moucz#{rand(200)}\",\"ca\":\"xicz-testca\",\"delete\":false,\"enddate\":\"\",\"failedLoginCount\":0,\"fullname\":\"某处长\",\"ip\":\"\",\"isManager\":0,\"loginMode\":\"\",\"manageLevel\":\"\",\"mobile\":\"13355561202\",\"nodeType\":\"\",\"orderId\":27,\"orgName\":\"XX 二处\",\"organId\":\"231ac070-0884-46c0-975e-5d213f0eb630\",\"password\":\"ndnSLQgelXKh/NbNtjax3s81ldW/bnCVxFkP+WQNbhE=\",\"secLevel\":\"2\",\"sex\":\"0\",\"sn\":\"\",\"spid\":\"\",\"startdate\":\"\",\"timestamp\":1521628264,\"tokenId\":\"\",\"type\":1,\"userId\":\"5b933469-3e32-422d-ac3c-7c3ffd60a3ea\",\"useremail\":\"\",\"useruuid\":\"5b933469-3e32-422\"}"
|
||||
render plain: json
|
||||
end
|
||||
|
||||
#根据login获取用户信息
|
||||
def get_user_info_by_login
|
||||
private_token = "hriEn3UwXfJs3PmyXnSH"
|
||||
sign = Digest::MD5.hexdigest("#{private_token}:#{params[:login]}")
|
||||
tip_exception(401, '401 Unauthorized') unless params[:sign].to_s == sign
|
||||
user = User.find_by_login params[:login]
|
||||
render_ok(data: {username: user.real_name, school: user.custom_department, login: user.login, phone: user.phone, mail: user.mail})
|
||||
end
|
||||
|
||||
private
|
||||
def load_user
|
||||
|
|
|
@ -2,7 +2,7 @@ class VersionReleasesController < ApplicationController
|
|||
include ApplicationHelper
|
||||
before_action :load_repository
|
||||
before_action :set_user
|
||||
before_action :require_login, except: [:index, :show]
|
||||
before_action :require_login, except: [:index, :show, :download]
|
||||
before_action :check_release_authorize, except: [:index, :show, :download]
|
||||
before_action :find_version , only: [:show, :edit, :update, :destroy]
|
||||
|
||||
|
|
|
@ -26,6 +26,16 @@ class BaseForm
|
|||
raise "项目标识已被使用." if Repository.where(user_id: user_id, identifier: repository_name.strip).exists?
|
||||
end
|
||||
|
||||
def check_gitea_repository_name(user_id, repository_name)
|
||||
user_login = User.find_by_id(user_id)&.login
|
||||
begin
|
||||
gitea_result = $gitea_client.get_repos_by_owner_repo(user_login, repository_name)
|
||||
raise "项目标识已被使用." if gitea_result["id"].present?
|
||||
rescue Gitea::Api::ServerError => e
|
||||
raise "服务器错误,请联系系统管理员!" unless e.http_code.to_i == 404
|
||||
end
|
||||
end
|
||||
|
||||
def check_project_name(user_id, project_name)
|
||||
raise "项目名称已被使用." if Project.where(user_id: user_id, name: project_name.strip).exists?
|
||||
end
|
||||
|
|
|
@ -16,6 +16,7 @@ class Projects::CreateForm < BaseForm
|
|||
check_project_language(project_language_id)
|
||||
check_project_name(user_id, name) unless name.blank?
|
||||
check_repository_name(user_id, repository_name) unless repository_name.blank?
|
||||
# check_gitea_repository_name(user_id, repository_name) unless repository_name.blank?
|
||||
check_blockchain_token_all(blockchain_token_all) unless blockchain_token_all.blank?
|
||||
check_blockchain_init_token(blockchain_init_token) unless blockchain_init_token.blank?
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Projects::MigrateForm < BaseForm
|
||||
attr_accessor :user_id, :name, :repository_name, :project_category_id, :description, :auth_token,
|
||||
attr_accessor :user_id, :name, :repository_name, :project_category_id, :description, :auth_token, :service,
|
||||
:project_language_id, :clone_addr, :private, :is_mirror, :auth_username, :auth_password, :owner
|
||||
|
||||
validates :user_id, :name, :repository_name, :clone_addr, presence: true
|
||||
|
@ -11,6 +11,7 @@ class Projects::MigrateForm < BaseForm
|
|||
validate do
|
||||
check_project_name(user_id, name) unless name.blank?
|
||||
check_repository_name(user_id, repository_name) unless repository_name.blank?
|
||||
# check_gitea_repository_name(user_id, repository_name) unless repository_name.blank?
|
||||
check_project_category(project_category_id)
|
||||
check_project_language(project_language_id)
|
||||
check_owner
|
||||
|
|
|
@ -10,6 +10,7 @@ class Projects::UpdateForm < BaseForm
|
|||
check_project_language(project_language_id)
|
||||
|
||||
check_repository_name(user_id, identifier) unless identifier.blank? || identifier == project_identifier
|
||||
# check_gitea_repository_name(user_id, identifier) unless identifier.blank? || identifier == project_identifier
|
||||
check_project_name(user_id, name) unless name.blank? || name == project_name
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
module Api::V1::SonarqubesHelper
|
||||
end
|
|
@ -485,7 +485,7 @@ module ApplicationHelper
|
|||
|
||||
return if url.blank?
|
||||
content_tag(:li) do
|
||||
sidebar_item(url, "数据统计", icon: 'bar-chart', controller: 'root')
|
||||
sidebar_item(url, "数据统计", icon: 'bar-chart', controller: 'root', has_permission: true)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,29 +2,33 @@ module ManageBackHelper
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
def sidebar_item_group(url, text, **opts)
|
||||
link_opts = url.start_with?('/') ? {} : { 'data-toggle': 'collapse', 'aria-expanded': false }
|
||||
content =
|
||||
link_to url, link_opts do
|
||||
content_tag(:i, '', class: "fa fa-#{opts[:icon]}", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) +
|
||||
content_tag(:span, text)
|
||||
end
|
||||
if opts[:has_permission]
|
||||
link_opts = url.start_with?('/') ? {} : { 'data-toggle': 'collapse', 'aria-expanded': false }
|
||||
content =
|
||||
link_to url, link_opts do
|
||||
content_tag(:i, '', class: "fa fa-#{opts[:icon]}", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) +
|
||||
content_tag(:span, text)
|
||||
end
|
||||
|
||||
content +=
|
||||
content_tag(:ul, id: url[1..-1], class: 'collapse list-unstyled', "data-parent": '#sidebar') do
|
||||
yield
|
||||
end
|
||||
content +=
|
||||
content_tag(:ul, id: url[1..-1], class: 'collapse list-unstyled', "data-parent": '#sidebar') do
|
||||
yield
|
||||
end
|
||||
|
||||
raw content
|
||||
raw content
|
||||
end
|
||||
end
|
||||
|
||||
def sidebar_item(url, text, **opts)
|
||||
content =
|
||||
link_to url, 'data-controller': opts[:controller] do
|
||||
content_tag(:i, '', class: "fa fa-#{opts[:icon]} fa-fw", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) +
|
||||
content_tag(:span, text)
|
||||
end
|
||||
if opts[:has_permission]
|
||||
content =
|
||||
link_to url, 'data-controller': opts[:controller] do
|
||||
content_tag(:i, '', class: "fa fa-#{opts[:icon]} fa-fw", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) +
|
||||
content_tag(:span, text)
|
||||
end
|
||||
|
||||
raw content
|
||||
raw content
|
||||
end
|
||||
end
|
||||
|
||||
def admin_sidebar_controller
|
||||
|
|
|
@ -73,6 +73,7 @@ module ProjectsHelper
|
|||
cloud_ide_saas_url: cloud_ide_saas_url(user),
|
||||
open_blockchain: Site.has_blockchain? && project.use_blockchain,
|
||||
has_dataset: project.project_dataset.present?,
|
||||
open_portrait: project.open_portrait,
|
||||
ignore_id: project.ignore_id
|
||||
}).compact
|
||||
|
||||
|
|
|
@ -147,7 +147,8 @@ module RepositoriesHelper
|
|||
ss_href = content.to_s.scan(href_regex)
|
||||
ss_href_1 = content.to_s.scan(href_regex_1)
|
||||
total_sources = {ss_c: ss_c,ss: ss, ss_1: ss_1, ss_2: ss_2, ss_src: ss_src, ss_src_1: ss_src_1, ss_src_2: ss_src_2, ss_src_3: ss_src_3, ss_src_4: ss_src_4, ss_src_5: ss_src_5, ss_href: ss_href, ss_href_1: ss_href_1}
|
||||
# total_sources.uniq!
|
||||
puts total_sources
|
||||
# total_sources.uniq!
|
||||
total_sources.except(:ss, :ss_c).each do |k, sources|
|
||||
sources.each do |s|
|
||||
begin
|
||||
|
@ -212,10 +213,12 @@ module RepositoriesHelper
|
|||
|
||||
after_ss_souces = content.to_s.scan(s_regex)
|
||||
after_ss_souces.each_with_index do |s, index|
|
||||
next if total_sources[:ss][index].nil?
|
||||
content = content.gsub("#{s[0]}","#{total_sources[:ss][index][0]}")
|
||||
end
|
||||
after_ss_c_souces = content.to_s.scan(s_regex_c)
|
||||
after_ss_c_souces.each_with_index do |s, index|
|
||||
next if total_sources[:ss_c][index].nil?
|
||||
content = content.gsub("#{s[0]}","#{total_sources[:ss_c][index][0]}")
|
||||
end
|
||||
return content
|
||||
|
|
|
@ -2,6 +2,7 @@ class CacheAsyncClearJob < ApplicationJob
|
|||
queue_as :cache
|
||||
|
||||
def perform(type, id=nil)
|
||||
return if id.nil?
|
||||
case type
|
||||
when "project_common_service"
|
||||
Cache::V2::ProjectCommonService.new(id).clear
|
||||
|
|
|
@ -11,7 +11,7 @@ class CheckMirrorJob < ApplicationJob
|
|||
unless response.present?
|
||||
SyncLog.sync_log("==========check_project_error_id:#{project.id}============")
|
||||
ActiveRecord::Base.transaction do
|
||||
delete_gitea = Gitea::Repository::DeleteService.new(project.owner, project.identifier).call
|
||||
delete_gitea = Gitea::Repository::DeleteService.new(project.owner, project.identifier, project.owner.gitea_token).call
|
||||
if delete_gitea.status == 204 || delete_gitea.status == 404 #删除成功或者仓库不存在,都重新创建
|
||||
repository_params= {
|
||||
name: project.identifier,
|
||||
|
|
|
@ -10,7 +10,7 @@ class MigrateRemoteRepositoryJob < ApplicationJob
|
|||
gitea_repository = Gitea::Repository::MigrateService.new(token, params).call
|
||||
puts "#gitea_repository#{gitea_repository}"
|
||||
if gitea_repository[0]==201
|
||||
repo&.project&.update_columns(gpid: gitea_repository[2]["id"])
|
||||
repo&.project&.update_columns(gpid: gitea_repository[2]["id"], default_branch: gitea_repository[2]["default_branch"])
|
||||
repo&.mirror&.succeeded!
|
||||
## open jianmu devops
|
||||
project_id = repo&.project&.id
|
||||
|
@ -19,9 +19,21 @@ class MigrateRemoteRepositoryJob < ApplicationJob
|
|||
UpdateProjectTopicJob.set(wait: 1.seconds).perform_later(project_id) if project_id.present?
|
||||
puts "############ mirror status: #{repo.mirror.status} ############"
|
||||
else
|
||||
repo&.mirror&.failed!
|
||||
gitea_result = $gitea_client.get_repos_by_owner_repo(repo&.project&.owner&.login, repo&.project&.identifier)
|
||||
if gitea_result["empty"]
|
||||
repo&.mirror&.failed!
|
||||
repo&.project&.update_columns(status: 0)
|
||||
else
|
||||
repo&.project&.update_columns(gpid: gitea_repository[2]["id"], default_branch: gitea_repository[2]["default_branch"])
|
||||
repo&.mirror&.succeeded!
|
||||
project_id = repo&.project&.id
|
||||
puts "############ mirror project_id,user_id: #{project_id},#{user_id} ############"
|
||||
OpenProjectDevOpsJob.set(wait: 5.seconds).perform_later(project_id, user_id) if project_id.present? && user_id.present?
|
||||
UpdateProjectTopicJob.set(wait: 1.seconds).perform_later(project_id) if project_id.present?
|
||||
puts "############ mirror status: #{repo.mirror.status} ############"
|
||||
end
|
||||
end
|
||||
# UpdateProjectTopicJob 中语言要延迟1S才能获取
|
||||
BroadcastMirrorRepoMsgJob.set(wait: 1.seconds).perform_later(repo.id) unless repo&.mirror.waiting?
|
||||
BroadcastMirrorRepoMsgJob.set(wait: 10.seconds).perform_later(repo.id) unless repo&.mirror.waiting?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
# user_id :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# label :string(255)
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# by_name (name)
|
||||
# index_action_nodes_on_action_types_id (action_node_types_id)
|
||||
# index_action_nodes_on_user_id (user_id)
|
||||
# index_action_nodes_on_action_node_types_id (action_node_types_id)
|
||||
# index_action_nodes_on_user_id (user_id)
|
||||
#
|
||||
|
||||
class Action::Node < ApplicationRecord
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
# input_type :string(255)
|
||||
# description :string(255)
|
||||
# is_required :boolean default("0")
|
||||
# sort_no :string(255) default("0")
|
||||
# sort_no :integer default("0")
|
||||
# user_id :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
# id :integer not null, primary key
|
||||
# name :string(255)
|
||||
# description :string(255)
|
||||
# sort_no :integer
|
||||
# sort_no :integer default("0")
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# name :string(255)
|
||||
# description :string(255)
|
||||
# img :string(255)
|
||||
# sort_no :string(255) default("0")
|
||||
# sort_no :integer default("0")
|
||||
# json :text(65535)
|
||||
# yaml :text(65535)
|
||||
# created_at :datetime not null
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
# cloud_url :string(255) default("")
|
||||
# course_second_category_id :integer default("0")
|
||||
# delay_publish :boolean default("0")
|
||||
# memo_image :boolean default("0")
|
||||
# extra_type :integer default("0")
|
||||
# uuid :string(255)
|
||||
#
|
||||
# Indexes
|
||||
|
@ -77,6 +75,42 @@ class Attachment < ApplicationRecord
|
|||
|
||||
DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z)
|
||||
|
||||
def self.build_from_remote_url(user, name, url, container=nil)
|
||||
ext = name.split('.')[-1]
|
||||
tmp_path = "#{Rails.root}/#{name}"
|
||||
uri = URI(url)
|
||||
size = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
||||
response = http.get(uri.path)
|
||||
File.open(tmp_path, 'wb') do |file|
|
||||
file.write(response.body)
|
||||
end
|
||||
end
|
||||
digest = "#{Digest::MD5.file(tmp_path).hexdigest}_#{(Time.now.to_f * 1000).to_i}.#{ext}"
|
||||
month_folder = "#{Time.now.year}/#{Time.now.month.to_s.rjust(2, '0')}"
|
||||
save_path = "#{Rails.root}#{EduSetting.get("attachment_folder")}#{month_folder}"
|
||||
unless Dir.exists?(save_path)
|
||||
FileUtils.mkdir_p(save_path) ##不成功这里会抛异常
|
||||
end
|
||||
path = File.join(save_path, digest)
|
||||
FileUtils.mv(tmp_path, path)
|
||||
attachment = Attachment.new
|
||||
attachment.filename = name
|
||||
attachment.disk_filename = path[save_path.size+1, path.size]
|
||||
attachment.filesize = size
|
||||
attachment.content_type = 'application/octet-stream'
|
||||
attachment.digest = digest.split('.')[0]
|
||||
attachment.author_id = user.id
|
||||
attachment.disk_directory = month_folder
|
||||
attachment.cloud_url = url
|
||||
attachment.uuid = SecureRandom.uuid
|
||||
attachment.container = container
|
||||
attachment.save!
|
||||
|
||||
return attachment
|
||||
rescue
|
||||
return nil
|
||||
end
|
||||
|
||||
def diskfile
|
||||
File.join(File.join(Rails.root, "files"), disk_directory.to_s, disk_filename.to_s)
|
||||
end
|
||||
|
@ -206,4 +240,4 @@ class Attachment < ApplicationRecord
|
|||
attachment.content_type self.content_type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -6,7 +6,8 @@ module Matchable
|
|||
scope :with_project_language, ->(language_id) { where(project_language_id: language_id) unless language_id.blank? }
|
||||
scope :with_project_type, ->(project_type) { where(project_type: project_type) if Project.project_types.include?(project_type) }
|
||||
scope :by_name_or_identifier, ->(search) { where("projects.name like :search or projects.identifier LIKE :search", :search => "%#{search.split(" ").join('|')}%") unless search.blank? }
|
||||
scope :with_project_topic, ->(topic_id) {joins(:project_topics).where(project_topics: {id: topic_id}) unless topic_id.blank?}
|
||||
scope :with_project_topic, ->(topic_id) {left_outer_joins(:project_topics).where(project_topics: {id: topic_id}) unless topic_id.blank?}
|
||||
scope :with_project_topic_name, ->(topic_name) {left_outer_joins(:project_topics).where(project_topics: {name: topic_name}) unless topic_name.blank?}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: home_top_settings
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer
|
||||
# top_type :string(255)
|
||||
# top_id :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_home_top_settings_on_top_type_and_top_id (top_type,top_id)
|
||||
# index_home_top_settings_on_user_id (user_id)
|
||||
#
|
||||
|
||||
class HomeTopSetting < ApplicationRecord
|
||||
|
||||
belongs_to :user
|
||||
|
||||
belongs_to :top, polymorphic: true
|
||||
end
|
|
@ -110,6 +110,20 @@ class Issue < ApplicationRecord
|
|||
after_save :incre_or_decre_closed_issues_count, :change_versions_count, :send_update_message_to_notice_system, :associate_attachment_container, :generate_uuid
|
||||
after_destroy :update_closed_issues_count_in_project!, :decre_project_common, :decre_user_statistic, :decre_platform_statistic, :destroy_be_pm_links
|
||||
|
||||
|
||||
def pm_issue_type_string
|
||||
case pm_issue_type
|
||||
when 1
|
||||
"requirement"
|
||||
when 2
|
||||
"task"
|
||||
when 3
|
||||
"bug"
|
||||
else
|
||||
"issue"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_be_pm_links
|
||||
PmLink.where(be_linkable_type:"Issue",be_linkable_id:self.id).map(&:destroy)
|
||||
end
|
||||
|
|
|
@ -83,7 +83,424 @@ class Journal < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def operate_content
|
||||
def pm_operate_category
|
||||
detail = self.journal_details.take
|
||||
if %w(requirement task bug).include?(detail.property) && detail.prop_key.to_s == "1"
|
||||
return "issue"
|
||||
else
|
||||
return %w(requirement task bug attr).include?(detail.property) ? detail.prop_key : detail.property
|
||||
end
|
||||
end
|
||||
|
||||
def pm_operate_content
|
||||
content = ""
|
||||
detail = self.journal_details.take
|
||||
case detail.property
|
||||
when 'requirement'
|
||||
case detail.prop_key
|
||||
when 'status_id'
|
||||
old_value = IssueStatus.find_by_id(detail.old_value)&.name
|
||||
new_value = IssueStatus.find_by_id(detail.value)&.name
|
||||
content += "将状态"
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "设置为<b>#{new_value}</b>"
|
||||
else
|
||||
new_value = "未设置" if detail.value.blank?
|
||||
content += "由<b>#{old_value}</b>更改为<b>#{new_value}</b>"
|
||||
end
|
||||
content.gsub!('新增', '待评审')
|
||||
content.gsub!('正在解决', '进行中')
|
||||
content.gsub!('已解决', '已完成')
|
||||
content.gsub!('关闭', '已关闭')
|
||||
content.gsub!('拒绝', '已拒绝')
|
||||
return content
|
||||
when 'root_id'
|
||||
old_value = "<b><#{Issue.find_by_id(detail.old_value)&.subject}></b>"
|
||||
new_value = "<b><#{Issue.find_by_id(detail.value)&.subject}></b>"
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "关联了父需求#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "取消了关联的父需求#{old_value}"
|
||||
else
|
||||
content += "将关联的父需求由#{old_value}更改为#{new_value}"
|
||||
end
|
||||
end
|
||||
return content
|
||||
when 'leaf_issue'
|
||||
old_value = Issue.where(id: detail.old_value.to_s.split(",")).map{|i| "<b><#{i.subject}></b>"}.join("、")
|
||||
new_value = Issue.where(id: detail.value.to_s.split(",")).map{|i| "<b><#{i.subject}></b>"}.join("、")
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "新建了子需求#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "删除了关联的子需求#{old_value}"
|
||||
else
|
||||
content += "新建了子需求#{new_value}"
|
||||
end
|
||||
end
|
||||
return content
|
||||
when 'tag_leaf_issue'
|
||||
old_value = Issue.where(id: detail.old_value.to_s.split(",")).map{|i| "<b><#{i.subject}></b>"}.join("、")
|
||||
new_value = Issue.where(id: detail.value.to_s.split(",")).map{|i| "<b><#{i.subject}></b>"}.join("、")
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "关联了子需求#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "取消了关联的子需求#{old_value}"
|
||||
else
|
||||
content += "关联了子需求#{new_value}"
|
||||
end
|
||||
end
|
||||
return content
|
||||
else
|
||||
return "创建了需求"
|
||||
end
|
||||
when 'task'
|
||||
case detail.prop_key
|
||||
when 'status_id'
|
||||
old_value = IssueStatus.find_by_id(detail.old_value)&.name
|
||||
new_value = IssueStatus.find_by_id(detail.value)&.name
|
||||
content += "将状态"
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "设置为<b>#{new_value}</b>"
|
||||
else
|
||||
new_value = "未设置" if detail.value.blank?
|
||||
content += "由<b>#{old_value}</b>更改为<b>#{new_value}</b>"
|
||||
end
|
||||
content.gsub!('新增', '待处理')
|
||||
content.gsub!('正在解决', '进行中')
|
||||
content.gsub!('已解决', '已完成')
|
||||
content.gsub!('关闭', '已关闭')
|
||||
content.gsub!('拒绝', '已拒绝')
|
||||
return content
|
||||
when 'root_id'
|
||||
old_value = "<b><#{Issue.find_by_id(detail.old_value)&.subject}></b>"
|
||||
new_value = "<b><#{Issue.find_by_id(detail.value)&.subject}></b>"
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "关联了父任务#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "取消了关联的父任务#{old_value}"
|
||||
else
|
||||
content += "将关联的父任务由#{old_value}>更改为#{new_value}"
|
||||
end
|
||||
end
|
||||
return content
|
||||
when 'leaf_issue'
|
||||
old_value = Issue.where(id: detail.old_value.to_s.split(",")).map{|i| "<b><#{i.subject}></b>"}.join("、")
|
||||
new_value = Issue.where(id: detail.value.to_s.split(",")).map{|i| "<b><#{i.subject}></b>"}.join("、")
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "新建了子任务#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "删除了关联的子任务#{old_value}"
|
||||
else
|
||||
content += "新建了子任务#{new_value}"
|
||||
end
|
||||
end
|
||||
return content
|
||||
when 'tag_leaf_issue'
|
||||
old_value = Issue.where(id: detail.old_value.to_s.split(",")).map{|i| "<b><#{i.subject}></b>"}.join("、")
|
||||
new_value = Issue.where(id: detail.value.to_s.split(",")).map{|i| "<b><#{i.subject}></b>"}.join("、")
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "关联了子任务#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "取消了关联的子任务#{old_value}"
|
||||
else
|
||||
content += "关联了子任务#{new_value}"
|
||||
end
|
||||
end
|
||||
return content
|
||||
else
|
||||
return "创建了任务"
|
||||
end
|
||||
when 'bug'
|
||||
case detail.prop_key
|
||||
when 'status_id'
|
||||
old_value = IssueStatus.find_by_id(detail.old_value)&.name
|
||||
new_value = IssueStatus.find_by_id(detail.value)&.name
|
||||
content += "将状态"
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "设置为<b>#{new_value}</b>"
|
||||
else
|
||||
new_value = "未设置" if detail.value.blank?
|
||||
content += "由<b>#{old_value}</b>更改为<b>#{new_value}</b>"
|
||||
end
|
||||
content.gsub!('新增', '待修复')
|
||||
content.gsub!('正在解决', '修复中')
|
||||
content.gsub!('已解决', '已修复')
|
||||
content.gsub!('关闭', '已关闭')
|
||||
content.gsub!('拒绝', '已拒绝')
|
||||
return content
|
||||
when 'root_id'
|
||||
old_value = "<b><#{Issue.find_by_id(detail.old_value)&.subject}></b>"
|
||||
new_value = "<b><#{Issue.find_by_id(detail.value)&.subject}></b>"
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "关联了父缺陷#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "取消了关联的父缺陷#{old_value}"
|
||||
else
|
||||
content += "将关联的父缺陷由#{old_value}更改为#{new_value}"
|
||||
end
|
||||
end
|
||||
return content
|
||||
when 'leaf_issue'
|
||||
old_value = Issue.where(id: detail.old_value.to_s.split(",")).map{|i| "<b><#{i.subject}></b>"}.join("、")
|
||||
new_value = Issue.where(id: detail.value.to_s.split(",")).map{|i| "<b><#{i.subject}></b>"}.join("、")
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "新建了子缺陷#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "删除了关联的子缺陷#{old_value}"
|
||||
else
|
||||
content += "新建了子缺陷#{new_value}"
|
||||
end
|
||||
end
|
||||
return content
|
||||
when 'tag_leaf_issue'
|
||||
old_value = Issue.where(id: detail.old_value.to_s.split(",")).map{|i| "<b><#{i.subject}></b>"}.join("、")
|
||||
new_value = Issue.where(id: detail.value.to_s.split(",")).map{|i| "<b><#{i.subject}></b>"}.join("、")
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "关联了子缺陷#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "取消了关联的子缺陷#{old_value}"
|
||||
else
|
||||
content += "关联了子缺陷#{new_value}"
|
||||
end
|
||||
end
|
||||
return content
|
||||
else
|
||||
return "创建了缺陷"
|
||||
end
|
||||
when 'attr'
|
||||
case detail.prop_key
|
||||
when 'subject'
|
||||
return "修改了<b>标题</b>"
|
||||
when 'description'
|
||||
return "修改了<b>正文</b>"
|
||||
when 'priority_id'
|
||||
old_value = IssuePriority.find_by_id(detail.old_value)&.name
|
||||
new_value = IssuePriority.find_by_id(detail.value)&.name
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "将优先级设置为<b>#{new_value}</b>"
|
||||
else
|
||||
new_value = "未设置" if detail.value.blank?
|
||||
content += "将优先级由<b>#{old_value}</b>更改为<b>#{new_value}</b>"
|
||||
end
|
||||
return content
|
||||
when 'status_id'
|
||||
old_value = IssueStatus.find_by_id(detail.old_value)&.name
|
||||
new_value = IssueStatus.find_by_id(detail.value)&.name
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "将状态设置为<b>#{new_value}</b>"
|
||||
else
|
||||
new_value = "未设置" if detail.value.blank?
|
||||
content += "将状态由<b>#{old_value}</b>更改为<b>#{new_value}</b>"
|
||||
end
|
||||
case self.issue.pm_issue_type.to_i
|
||||
when 1
|
||||
content.gsub!('新增', '待评审')
|
||||
content.gsub!('正在解决', '进行中')
|
||||
content.gsub!('已解决', '已完成')
|
||||
content.gsub!('关闭', '已关闭')
|
||||
content.gsub!('拒绝', '已拒绝')
|
||||
when 2
|
||||
content.gsub!('新增', '待处理')
|
||||
content.gsub!('正在解决', '进行中')
|
||||
content.gsub!('已解决', '已完成')
|
||||
content.gsub!('关闭', '已关闭')
|
||||
content.gsub!('拒绝', '已拒绝')
|
||||
when 3
|
||||
content.gsub!('新增', '待修复')
|
||||
content.gsub!('正在解决', '修复中')
|
||||
content.gsub!('已解决', '已修复')
|
||||
content.gsub!('关闭', '已关闭')
|
||||
content.gsub!('拒绝', '已拒绝')
|
||||
end
|
||||
return content
|
||||
when 'pm_issue_type'
|
||||
old_value = detail.old_value
|
||||
new_value = detail.value
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "将工作项类型设置为<b>#{new_value}</b>"
|
||||
else
|
||||
new_value = "未设置" if detail.value.blank?
|
||||
content += "将工作项类型由<b>#{old_value}</b>更改为<b>#{new_value}</b>"
|
||||
end
|
||||
content.gsub!('1', '需求')
|
||||
content.gsub!('2', '任务')
|
||||
content.gsub!('3', '缺陷')
|
||||
return content
|
||||
when 'pm_sprint_id'
|
||||
old_value = detail.old_value
|
||||
new_value = detail.value
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "添加了关联迭代"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "将关联迭代更改为<b>未设置</b>"
|
||||
else
|
||||
content += "变更了关联迭代"
|
||||
end
|
||||
end
|
||||
return content
|
||||
when 'project_id'
|
||||
old_value = Project.find_by_id(detail.old_value)&.name
|
||||
new_value = Project.find_by_id(detail.value)&.name
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "添加关联代码库<b>#{new_value}</b>"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "将关联代码库更改为<b>未设置</b>"
|
||||
else
|
||||
content += "将关联代码库由<b>#{old_value}</b>改为<b>#{new_value}</b>"
|
||||
end
|
||||
end
|
||||
return content
|
||||
when 'branch_name'
|
||||
old_value = detail.old_value
|
||||
new_value = detail.value
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "添加关联分支<b>#{new_value}</b>"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "将关联分支更改为<b>未设置</b>"
|
||||
else
|
||||
content += "将关联分支由<b>#{old_value}</b>改为<b>#{new_value}</b>"
|
||||
end
|
||||
end
|
||||
return content
|
||||
|
||||
when 'start_date'
|
||||
old_value = detail.old_value
|
||||
new_value = detail.value
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "添加开始时间<b>#{new_value}</b>"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "将开始时间更改为<b>未设置</b>"
|
||||
else
|
||||
content += "将开始时间由<b>#{old_value}</b>改为<b>#{new_value}</b>"
|
||||
end
|
||||
end
|
||||
return content
|
||||
|
||||
when 'due_date'
|
||||
old_value = detail.old_value
|
||||
new_value = detail.value
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "添加结束时间<b>#{new_value}</b>"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "将结束时间更改为<b>未设置</b>"
|
||||
else
|
||||
content += "将结束时间由<b>#{old_value}</b>改为<b>#{new_value}</b>"
|
||||
end
|
||||
end
|
||||
return content
|
||||
when 'time_scale'
|
||||
old_value = detail.old_value
|
||||
new_value = detail.value
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "添加预估工时<b>#{new_value}</b>"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "将预估工时更改为<b>未设置</b>"
|
||||
else
|
||||
content += "将预估工时由<b>#{old_value}</b>改为<b>#{new_value}</b>"
|
||||
end
|
||||
end
|
||||
return content
|
||||
end
|
||||
when 'attachment'
|
||||
old_value = detail.old_value.to_s
|
||||
new_value = detail.value.to_s
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "上传了附件"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "删除了附件"
|
||||
else
|
||||
content += "上传了附件"
|
||||
end
|
||||
end
|
||||
return content
|
||||
when 'assigner'
|
||||
old_value = User.where(id: detail.old_value.split(",")).map{|u| "<b>#{u.real_name}</b>"}.join("、")
|
||||
new_value = User.where(id: detail.value.split(",")).map{|u| "<b>#{u.real_name}</b>"}.join("、")
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "添加负责人#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "将负责人更改为<b>未设置</b>"
|
||||
else
|
||||
content += "将负责人由#{old_value}更改为#{new_value}"
|
||||
end
|
||||
end
|
||||
return content
|
||||
when 'issue_tag'
|
||||
old_value = IssueTag.where(id: detail.old_value.split(",")).map{|t| "<b>#{t.name}</b>"}.join("、")
|
||||
new_value = IssueTag.where(id: detail.value.split(",")).map{|t| "<b>#{t.name}</b>"}.join("、")
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "添加标记#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "将标记更改为<b>未设置</b>"
|
||||
else
|
||||
content += "将标记由#{old_value}更改为#{new_value}"
|
||||
end
|
||||
end
|
||||
return content
|
||||
when 'link_issue'
|
||||
old_value = Issue.where(id: detail.old_value.to_s.split(",")).map{|i| "<b>[#{i.pm_issue_type}]-<#{i.subject}></b>"}.join("、")
|
||||
new_value = Issue.where(id: detail.value.to_s.split(",")).map{|i| "<b>[#{i.pm_issue_type}]-<#{i.subject}></b>"}.join("、")
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "新建了关联的工作项#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "删除了关联的工作项#{old_value}"
|
||||
else
|
||||
content += "新建了关联的工作项#{new_value}"
|
||||
end
|
||||
end
|
||||
content.gsub!('1', "需求")
|
||||
content.gsub!('2', "任务")
|
||||
content.gsub!('3', "缺陷")
|
||||
return content
|
||||
when 'tag_link_issue'
|
||||
old_value = Issue.where(id: detail.old_value.to_s.split(",")).map{|i| "<b>[#{i.pm_issue_type}]-<#{i.subject}></b>"}.join("、")
|
||||
new_value = Issue.where(id: detail.value.to_s.split(",")).map{|i| "<b>[#{i.pm_issue_type}]-<#{i.subject}></b>"}.join("、")
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "关联了工作项#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "取消了关联的工作项#{old_value}"
|
||||
else
|
||||
content += "关联了工作项#{new_value}"
|
||||
end
|
||||
end
|
||||
content.gsub!('1', "需求")
|
||||
content.gsub!('2', "任务")
|
||||
content.gsub!('3', "缺陷")
|
||||
return content
|
||||
when 'issue'
|
||||
issue = self.issue
|
||||
case issue.pm_issue_type
|
||||
when 1
|
||||
return "创建了需求"
|
||||
when 2
|
||||
return "创建了任务"
|
||||
when 3
|
||||
return "创建了缺陷"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def operate_content
|
||||
content = ""
|
||||
detail = self.journal_details.take
|
||||
case detail.property
|
||||
|
|
|
@ -82,6 +82,7 @@ class Organization < Owner
|
|||
has_many :team_users, dependent: :destroy
|
||||
has_many :pinned_projects, class_name: 'PinnedProject', foreign_key: :user_id, dependent: :destroy
|
||||
has_many :is_pinned_projects, through: :pinned_projects, source: :project, validate: false
|
||||
has_many :home_top_settings, as: :top, dependent: :destroy
|
||||
|
||||
validates :login, presence: true
|
||||
validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, case_sensitive: false
|
||||
|
@ -222,4 +223,9 @@ class Organization < Owner
|
|||
ids.uniq.size
|
||||
end
|
||||
|
||||
# user容错处理
|
||||
def get_letter_avatar_url
|
||||
""
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
|
||||
class PmLink < ApplicationRecord
|
||||
belongs_to :linkable, polymorphic: true
|
||||
belongs_to :be_linkable, polymorphic: true
|
||||
# belongs_to :linkable_issue, -> {where(pm_links: {linkable_type: 'Issue'})}, foreign_key: 'linkable_id', class_name: 'Issue'
|
||||
# belongs_to :be_linkable_issue, -> {where(pm_links: {be_linkable_type: 'Issue'})}, foreign_key: 'be_linkable_id', class_name: 'Issue'
|
||||
|
||||
def be_linkable
|
||||
be_linkable_type.constantize.find be_linkable_id
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
# is_pinned :boolean default("0")
|
||||
# recommend_index :integer default("0")
|
||||
# pr_view_admin :boolean default("0")
|
||||
# has_actions :boolean default("0")
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
@ -140,6 +141,7 @@ class Project < ApplicationRecord
|
|||
has_many :daily_project_statistics, dependent: :destroy
|
||||
has_one :project_dataset, dependent: :destroy
|
||||
has_many :sync_repositories, dependent: :destroy
|
||||
has_many :home_top_settings, as: :top, dependent: :destroy
|
||||
after_create :incre_user_statistic, :incre_platform_statistic
|
||||
after_save :check_project_members
|
||||
before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data
|
||||
|
@ -159,6 +161,12 @@ class Project < ApplicationRecord
|
|||
|
||||
delegate :is_secret, to: :license, allow_nil: true
|
||||
|
||||
scope :like, lambda { |keywords|
|
||||
# 表情处理
|
||||
keywords = keywords.to_s.each_char.select { |c| c.bytes.first < 240 }.join('')
|
||||
sql = "name LIKE :search OR identifier LIKE :search"
|
||||
where(sql, :search => "%#{keywords.strip}%") unless keywords.blank?
|
||||
}
|
||||
delegate :content, to: :project_detail, allow_nil: true
|
||||
delegate :name, to: :license, prefix: true, allow_nil: true
|
||||
|
||||
|
@ -192,14 +200,14 @@ class Project < ApplicationRecord
|
|||
end
|
||||
if changes[:is_public].present?
|
||||
if changes[:is_public][0] && !changes[:is_public][1]
|
||||
CacheAsyncClearJob.perform_later('project_rank_service', self.id)
|
||||
CacheAsyncClearJob.set(wait: 5.seconds).perform_later('project_rank_service', self.id)
|
||||
end
|
||||
if !changes[:is_public][0] && changes[:is_public][1]
|
||||
$redis_cache.srem("v2-project-rank-deleted", self.id)
|
||||
end
|
||||
end
|
||||
if !self.common?
|
||||
CacheAsyncClearJob.perform_later('project_rank_service', self.id)
|
||||
CacheAsyncClearJob.set(wait: 5.seconds).perform_later('project_rank_service', self.id)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -470,11 +478,24 @@ class Project < ApplicationRecord
|
|||
$redis_cache.hdel("issue_cache_delete_count", self.id)
|
||||
end
|
||||
|
||||
def open_portrait
|
||||
EduSetting.get("open_portrait_projects").present? ? EduSetting.get("open_portrait_projects").split(",").include?(self.id.to_s) : false
|
||||
end
|
||||
|
||||
def actionable
|
||||
return false if EduSetting.get("project_user_actionable").nil?
|
||||
return EduSetting.get("project_user_actionable").split(",").include?(self.owner&.login)
|
||||
end
|
||||
|
||||
def has_pull_request(branch_name)
|
||||
return true if self.pull_requests.opening.where(head: branch_name).present? || self.pull_requests.opening.where(base: branch_name).present?
|
||||
if self.forked_from_project_id.present?
|
||||
return true if self.fork_project.pull_requests.opening.where(head: branch_name).present? || self.fork_project.pull_requests.opening.where(base: branch_name).present?
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
def is_need_apply
|
||||
return false if EduSetting.get("project_need_apply").nil?
|
||||
return EduSetting.get("project_need_apply").split(",").include?(self.id.to_s)
|
||||
|
|
|
@ -2,25 +2,27 @@
|
|||
#
|
||||
# Table name: pull_requests
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# gitea_id :integer
|
||||
# gitea_number :integer
|
||||
# user_id :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# status :integer default("0")
|
||||
# project_id :integer
|
||||
# title :string(255)
|
||||
# milestone :integer
|
||||
# body :text(4294967295)
|
||||
# head :string(255)
|
||||
# base :string(255)
|
||||
# issue_id :integer
|
||||
# fork_project_id :integer
|
||||
# is_original :boolean default("0")
|
||||
# comments_count :integer default("0")
|
||||
# commits_count :integer default("0")
|
||||
# files_count :integer default("0")
|
||||
# id :integer not null, primary key
|
||||
# gitea_id :integer
|
||||
# gitea_number :integer
|
||||
# user_id :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# status :integer default("0")
|
||||
# project_id :integer
|
||||
# title :string(255)
|
||||
# milestone :integer
|
||||
# body :text(4294967295)
|
||||
# head :string(255)
|
||||
# base :string(255)
|
||||
# issue_id :integer
|
||||
# fork_project_id :integer
|
||||
# is_original :boolean default("0")
|
||||
# comments_count :integer default("0")
|
||||
# commits_count :integer default("0")
|
||||
# files_count :integer default("0")
|
||||
# fork_project_owner :string(255)
|
||||
# fork_project_identifier :string(255)
|
||||
#
|
||||
|
||||
class PullRequest < ApplicationRecord
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_name (project_id)
|
||||
# index_repositories_on_identifier (identifier)
|
||||
# index_repositories_on_project_id (project_id)
|
||||
# index_repositories_on_user_id (user_id)
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
# sync_direction :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# external_token :string(255)
|
||||
# webhook_gid :integer
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
# sync_direction :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# external_token :string(255)
|
||||
# webhook_gid :integer
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#
|
||||
|
||||
|
||||
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
@ -44,7 +45,7 @@ class Token < ActiveRecord::Base
|
|||
|
||||
def self.get_or_create_permanent_login_token(user, type)
|
||||
token = Token.get_token_from_user(user, type)
|
||||
Rails.logger.info "###### Token.get_token_from_user result: #{token&.value}"
|
||||
Rails.logger.info "###### Token.get_token_from_user time:#{Time.new.to_i}, result: #{token&.value}"
|
||||
unless token
|
||||
token = Token.create(:user => user, :action => type)
|
||||
Rails.logger.info "###### Token.get_token_from_user is nul and agine create token: #{token&.value}"
|
||||
|
|
|
@ -191,7 +191,8 @@ class User < Owner
|
|||
has_many :clas, through: :user_clas
|
||||
|
||||
has_one :page, :dependent => :destroy
|
||||
|
||||
has_many :home_top_settings, dependent: :destroy
|
||||
|
||||
# Groups and active users
|
||||
scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) }
|
||||
scope :like, lambda { |keywords|
|
||||
|
@ -861,7 +862,11 @@ class User < Owner
|
|||
end
|
||||
|
||||
def admin_or_business?
|
||||
admin? || business?
|
||||
admin? || business?
|
||||
end
|
||||
|
||||
def admin_or_glcc_admin?
|
||||
admin? || glcc_admin?
|
||||
end
|
||||
|
||||
def self.generate_login(prefix)
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
# province :text(65535)
|
||||
# custom_department :string(255)
|
||||
# city :string(255)
|
||||
# custom_department :string(255)
|
||||
# show_email :boolean default("0")
|
||||
# show_location :boolean default("0")
|
||||
# show_department :boolean default("0")
|
||||
|
|
|
@ -17,7 +17,7 @@ class Admins::GlccExamineMaterial < ApplicationQuery
|
|||
if term.present?
|
||||
materials = materials.where(term: term)
|
||||
end
|
||||
#year
|
||||
#year
|
||||
year = if params[:date]
|
||||
params[:date][:year]
|
||||
end
|
||||
|
|
|
@ -20,11 +20,11 @@ class Projects::ListMyQuery < ApplicationQuery
|
|||
if params[:category].blank?
|
||||
normal_projects = projects.members_projects(user.id).to_sql
|
||||
org_projects = projects.joins(team_projects: [team: :team_users]).where(team_users: {user_id: user.id}).to_sql
|
||||
projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
|
||||
projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects")#.distinct
|
||||
elsif params[:category].to_s == "join"
|
||||
normal_projects = projects.where.not(user_id: user.id).members_projects(user.id).to_sql
|
||||
org_projects = projects.joins(team_projects: [team: :team_users]).where(team_users: {user_id: user.id}).to_sql
|
||||
projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
|
||||
projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects")#.distinct
|
||||
elsif params[:category].to_s == "manage"
|
||||
projects = projects.where(user_id: user.id)
|
||||
elsif params[:category].to_s == "watched" #我关注的
|
||||
|
@ -37,8 +37,8 @@ class Projects::ListMyQuery < ApplicationQuery
|
|||
elsif params[:category].to_s == "admin"
|
||||
normal_projects = projects.joins(members: :roles).where(members: {user_id: user.id}, roles: {name: %w(Manager)}).to_sql
|
||||
org_projects = projects.joins(team_projects: [team: :team_users]).where(teams: {authorize: %w(owner admin)},team_users: {user_id: user.id}).to_sql
|
||||
projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
|
||||
# elsif params[:category].to_s == "public"
|
||||
projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects")#.distinct
|
||||
# elsif params[:category].to_s == "public"
|
||||
# projects = projects.visible.joins(:members).where(members: { user_id: user.id })
|
||||
# elsif params[:category].to_s == "private"
|
||||
# projects = projects.is_private.joins(:members).where(members: { user_id: user.id })
|
||||
|
@ -63,6 +63,15 @@ class Projects::ListMyQuery < ApplicationQuery
|
|||
projects = projects.sync_mirror
|
||||
end
|
||||
|
||||
if params[:topic_name].present?
|
||||
projects = projects.with_project_topic_name(params[:topic_name].to_s.split(","))
|
||||
end
|
||||
|
||||
if params[:topic_id].present?
|
||||
projects = projects.with_project_topic(params[:topic_id])
|
||||
end
|
||||
|
||||
|
||||
# 表情处理
|
||||
keywords = params[:search].to_s.each_char.select { |c| c.bytes.first < 240 }.join('')
|
||||
q = projects.ransack(name_or_identifier_cont: keywords)
|
||||
|
@ -71,11 +80,21 @@ class Projects::ListMyQuery < ApplicationQuery
|
|||
|
||||
sort = Project.column_names.include?(params[:sort_by]) ? params[:sort_by] : "updated_on"
|
||||
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : "desc"
|
||||
|
||||
|
||||
@home_top_ids = scope.joins(:home_top_settings).where(home_top_settings: {user_id: user.id}).order("home_top_settings.created_at asc").pluck(:id)
|
||||
|
||||
if params[:choosed].present? && params[:choosed].is_a?(Array)
|
||||
scope.order("FIELD(id, #{params[:choosed].reverse.join(",")}) desc")
|
||||
scope = scope.distinct.order("FIELD(projects.id, #{params[:choosed].reverse.join(",")}) desc")
|
||||
else
|
||||
scope.order("projects.#{sort} #{sort_direction}")
|
||||
if @home_top_ids.present?
|
||||
scope = scope.distinct.order("FIELD(projects.id, #{@home_top_ids.join(",")}) desc, projects.#{sort} #{sort_direction}")
|
||||
elsif params[:topic_name].present?
|
||||
scope = scope.distinct.order("project_topics.id asc, projects.#{sort} #{sort_direction}")
|
||||
else
|
||||
scope = scope.distinct.order("projects.#{sort} #{sort_direction}")
|
||||
end
|
||||
end
|
||||
|
||||
return scope, @home_top_ids
|
||||
end
|
||||
end
|
||||
|
|
|
@ -42,7 +42,7 @@ class Projects::ListQuery < ApplicationQuery
|
|||
end
|
||||
|
||||
def main_collection
|
||||
collection = Project.visible
|
||||
collection = Project.visible.where(status: 1)
|
||||
# 增加私有组织中项目过滤
|
||||
collection = collection.joins("left join organization_extensions on organization_extensions.organization_id = projects.user_id")
|
||||
.where("organization_extensions.visibility is null or organization_extensions.visibility in (0,1)")
|
||||
|
@ -71,7 +71,11 @@ class Projects::ListQuery < ApplicationQuery
|
|||
end
|
||||
|
||||
def by_project_topic(items)
|
||||
items.with_project_topic(params[:topic_id])
|
||||
if params[:topic_name].present?
|
||||
items.with_project_topic_name(params[:topic_name].to_s.split(","))
|
||||
else
|
||||
items.with_project_topic(params[:topic_id])
|
||||
end
|
||||
end
|
||||
|
||||
# 优化排序
|
||||
|
|
|
@ -31,7 +31,7 @@ class Admins::UpdateUserService < ApplicationService
|
|||
private
|
||||
|
||||
def user_attributes
|
||||
params.slice(*%i[lastname nickname mail phone admin business is_test login
|
||||
params.slice(*%i[lastname nickname mail phone admin business glcc_admin is_test login
|
||||
professional_certification authentication is_shixun_marker website_permission bank_certification enterprise_certification])
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
class Api::Pm::Issues::BatchDeleteService < ApplicationService
|
||||
include ActiveModel::Model
|
||||
|
||||
attr_reader :project, :issues, :current_user
|
||||
|
||||
validates :project, :issues, :current_user, presence: true
|
||||
|
||||
def initialize(project, issues, current_user = nil)
|
||||
@project = project
|
||||
@issues = issues.includes(:assigners)
|
||||
@current_user = current_user
|
||||
end
|
||||
|
||||
def call
|
||||
raise Error, errors.full_messages.join(", ") unless valid?
|
||||
try_lock("Api::V1::Issues::DeleteService:#{project.id}") # 开始写数据,加锁
|
||||
|
||||
delete_issues
|
||||
|
||||
project.incre_project_issue_cache_delete_count(@issues.size)
|
||||
|
||||
if Site.has_notice_menu? && !project.id.zero?
|
||||
@issues.each do |issue|
|
||||
SendTemplateMessageJob.perform_later('IssueDeleted', current_user.id, @issue&.subject, @issue.assigners.pluck(:id), @issue.author_id)
|
||||
end
|
||||
end
|
||||
|
||||
unlock("Api::V1::Issues::DeleteService:#{project.id}")
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def delete_issues
|
||||
raise Error, "批量删除疑修失败!" unless @issues.destroy_all
|
||||
end
|
||||
end
|
|
@ -0,0 +1,33 @@
|
|||
class Api::Pm::Issues::BatchUpdateService < ApplicationService
|
||||
include ActiveModel::Model
|
||||
include Api::V1::Issues::Concerns::Checkable
|
||||
include Api::V1::Issues::Concerns::Loadable
|
||||
|
||||
attr_reader :project, :issues, :params, :current_user
|
||||
attr_reader :status_id, :priority_id, :milestone_id, :project_id
|
||||
attr_reader :issue_tag_ids, :assigner_ids
|
||||
|
||||
validates :project, :issues, :current_user, presence: true
|
||||
|
||||
def initialize(project, issues, params, current_user = nil)
|
||||
@project = project
|
||||
@issues = issues
|
||||
@params = params
|
||||
@current_user = current_user
|
||||
end
|
||||
|
||||
def call
|
||||
raise Error, errors.full_messages.join(", ") unless valid?
|
||||
ActiveRecord::Base.transaction do
|
||||
@issues.each do |issue|
|
||||
if issue.issue_classify == "issue"
|
||||
Api::Pm::Issues::UpdateService.call(project, issue, params, current_user)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
|
@ -0,0 +1,181 @@
|
|||
class Api::Pm::Issues::CreateService < ApplicationService
|
||||
include ActiveModel::Model
|
||||
include Api::V1::Issues::Concerns::Checkable
|
||||
include Api::V1::Issues::Concerns::Loadable
|
||||
|
||||
attr_reader :project, :current_user
|
||||
attr_reader :status_id, :priority_id, :milestone_id, :branch_name, :start_date, :due_date, :subject, :description, :blockchain_token_num, :root_subject
|
||||
attr_reader :issue_tag_ids, :assigner_ids, :attachment_ids, :receivers_login
|
||||
attr_accessor :created_issue
|
||||
|
||||
validates :subject, presence: true
|
||||
validates :status_id, :priority_id, presence: true
|
||||
validates :project, :current_user, presence: true
|
||||
validates :blockchain_token_num, numericality: {greater_than: 0}, allow_blank: 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]
|
||||
@blockchain_token_num = params[:blockchain_token_num]
|
||||
@issue_tag_ids = params[:issue_tag_ids]
|
||||
@assigner_ids = params[:assigner_ids]
|
||||
@attachment_ids = params[:attachment_ids]
|
||||
@receivers_login = params[:receivers_login]
|
||||
@pm_project_id = params[:pm_project_id]
|
||||
@pm_sprint_id = params[:pm_sprint_id]
|
||||
@pm_issue_type = params[:pm_issue_type]
|
||||
@root_id = params[:root_id]
|
||||
@time_scale = params[:time_scale]
|
||||
@linkable_id = params[:link_able_id]
|
||||
@root_subject = params[:root_subject]
|
||||
end
|
||||
|
||||
def call
|
||||
raise Error, errors.full_messages.join(', ') unless valid?
|
||||
ActiveRecord::Base.transaction do
|
||||
check_issue_status(status_id)
|
||||
check_issue_priority(priority_id)
|
||||
check_milestone(milestone_id) if milestone_id.present?
|
||||
check_issue_tags(issue_tag_ids) unless issue_tag_ids.blank?
|
||||
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?
|
||||
check_blockchain_token_num(current_user.id, project.id, blockchain_token_num) if blockchain_token_num.present?
|
||||
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_atme_receivers(receivers_login) unless receivers_login.blank?
|
||||
try_lock("Api::Pm::Issues::CreateService:#{project.id}") # 开始写数据,加锁
|
||||
@created_issue = Issue.new(issue_attributes)
|
||||
@created_issue.pm_issue_type = @pm_issue_type
|
||||
if @root_subject.present? && @pm_issue_type.to_i == 4
|
||||
@root_issue = Issue.find_by(subject: @root_subject, pm_issue_type: 4, pm_project_id: @pm_project_id)
|
||||
unless @root_issue.present?
|
||||
@root_issue = Issue.create(subject: @root_subject, pm_issue_type: 4, pm_project_id: @pm_project_id, status_id: 1, priority_id: 1, tracker_id: Tracker.first.id, project_id: @project.id, author_id: current_user.id)
|
||||
end
|
||||
@created_issue.root_id = @root_issue.id
|
||||
else
|
||||
@created_issue.root_id = @root_id
|
||||
end
|
||||
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.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.pm_project_id = @pm_project_id
|
||||
@created_issue.pm_sprint_id = @pm_sprint_id
|
||||
@created_issue.time_scale = @time_scale
|
||||
@created_issue.issue_tags_value = @issue_tags.order('id asc').pluck(:id).join(',') unless issue_tag_ids.blank?
|
||||
@created_issue.changer_id = @current_user.id
|
||||
@created_issue.save!
|
||||
if @created_issue.parent_issue.present?
|
||||
parent_issue = @created_issue.parent_issue
|
||||
if @created_issue.root_id.present? && parent_issue.present?
|
||||
journal = parent_issue.journals.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: @created_issue.pm_issue_type_string, prop_key: 'leaf_issue', value: @created_issue.id.to_s})
|
||||
end
|
||||
end
|
||||
if @linkable_id.present?
|
||||
PmLink.create(be_linkable_type: 'Issue', be_linkable_id: @created_issue.id, linkable_type: 'Issue', linkable_id: @linkable_id)
|
||||
another_issue = Issue.find_by_id(@linkable_id)
|
||||
if another_issue.present?
|
||||
journal = another_issue.journals.create!({user_id: @current_user.id})
|
||||
journal.journal_details.create!({property: 'link_issue', prop_key: "1", value: @created_issue.id.to_s})
|
||||
end
|
||||
end
|
||||
if Site.has_blockchain? && @project.use_blockchain
|
||||
if @created_issue.blockchain_token_num.present? && @created_issue.blockchain_token_num > 0
|
||||
Blockchain::CreateIssue.call({user_id: current_user.id, project_id: @created_issue.project_id, token_num: @created_issue.blockchain_token_num})
|
||||
end
|
||||
|
||||
push_activity_2_blockchain('issue_create', @created_issue)
|
||||
end
|
||||
|
||||
project.del_project_issue_cache_delete_count # 把缓存里存储项目删除issue的个数清除掉
|
||||
unless @project.id.zero?
|
||||
# 新增时向grimoirelab推送事件
|
||||
IssueWebhookJob.set(wait: 5.seconds).perform_later(@created_issue.id)
|
||||
|
||||
# @信息发送
|
||||
AtmeService.call(current_user, @atme_receivers, @created_issue) unless receivers_login.blank?
|
||||
|
||||
# 发消息
|
||||
if Site.has_notice_menu?
|
||||
SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @created_issue&.id, assigner_ids) unless assigner_ids.blank?
|
||||
SendTemplateMessageJob.perform_later('ProjectIssue', current_user.id, @created_issue&.id)
|
||||
end
|
||||
|
||||
# 触发webhook
|
||||
TouchWebhookJob.set(wait: 5.seconds).perform_later('IssueCreate', @created_issue&.id, current_user.id)
|
||||
TouchWebhookJob.set(wait: 5.seconds).perform_later('IssueLabel', @created_issue&.id, current_user.id, {issue_tag_ids: [[], issue_tag_ids]}) unless issue_tag_ids.blank?
|
||||
TouchWebhookJob.set(wait: 5.seconds).perform_later('IssueAssign', @created_issue&.id, current_user.id, {assigner_ids: [[], assigner_ids]}) unless assigner_ids.blank?
|
||||
end
|
||||
unlock("Api::Pm::Issues::CreateService:#{project.id}") # 结束写数据,解锁
|
||||
end
|
||||
|
||||
return @created_issue
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
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.merge!({blockchain_token_num: blockchain_token_num}) if blockchain_token_num.present?
|
||||
|
||||
issue_attributes
|
||||
end
|
||||
|
||||
def build_author_participants
|
||||
@created_issue.issue_participants.new({participant_type: 'authored', participant_id: current_user.id})
|
||||
end
|
||||
|
||||
def build_assigner_participants
|
||||
assigner_ids.each do |aid|
|
||||
@created_issue.issue_participants.new({participant_type: 'assigned', participant_id: aid})
|
||||
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
|
||||
return if @project.id == 0
|
||||
@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
|
||||
end
|
||||
|
||||
def build_issue_journal_details
|
||||
journal = @created_issue.journals.new({user_id: current_user.id})
|
||||
journal.journal_details.new({property: @created_issue.pm_issue_type_string, prop_key: 1, old_value: '', value: ''})
|
||||
end
|
||||
end
|
|
@ -0,0 +1,48 @@
|
|||
class Api::Pm::Issues::DeleteService < ApplicationService
|
||||
include ActiveModel::Model
|
||||
|
||||
attr_reader :project, :issue, :current_user
|
||||
|
||||
validates :project, :issue, :current_user, presence: true
|
||||
|
||||
def initialize(project, issue, current_user = nil)
|
||||
@project = project
|
||||
@issue = issue
|
||||
@current_user = current_user
|
||||
end
|
||||
|
||||
def call
|
||||
raise Error, errors.full_messages.join(", ") unless valid?
|
||||
try_lock("Api::V1::Issues::DeleteService:#{project.id}") # 开始写数据,加锁
|
||||
ActiveRecord::Base.transaction do
|
||||
parent_issue = @issue.parent_issue
|
||||
if @issue.root_id.present? && parent_issue.present?
|
||||
journal = parent_issue.journals.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: @issue.pm_issue_type_string, prop_key: 'leaf_issue', old_value: @issue.id.to_s})
|
||||
end
|
||||
|
||||
delete_issue
|
||||
#删除双向关联
|
||||
PmLink.where(be_linkable_id: @issue.id, be_linkable_type: 'Issue').or(PmLink.where(linkable_id: @issue.id, linkable_type: 'Issue')).map(&:destroy)
|
||||
|
||||
project.incre_project_issue_cache_delete_count
|
||||
|
||||
if Site.has_blockchain? && @project.use_blockchain && !project.id.zero?
|
||||
unlock_balance_on_blockchain(@issue.author_id.to_s, @project.id.to_s, @issue.blockchain_token_num.to_i) if @issue.blockchain_token_num.present?
|
||||
end
|
||||
|
||||
if Site.has_notice_menu? && !project.id.zero?
|
||||
SendTemplateMessageJob.perform_later('IssueDeleted', current_user.id, @issue&.subject, @issue.assigners.pluck(:id), @issue.author_id)
|
||||
end
|
||||
end
|
||||
unlock("Api::V1::Issues::DeleteService:#{project.id}")
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def delete_issue
|
||||
raise Error, "删除疑修失败!" unless issue.destroy!
|
||||
end
|
||||
end
|
|
@ -0,0 +1,326 @@
|
|||
class Api::Pm::Issues::UpdateService < ApplicationService
|
||||
include ActiveModel::Model
|
||||
include Api::V1::Issues::Concerns::Checkable
|
||||
include Api::V1::Issues::Concerns::Loadable
|
||||
|
||||
attr_reader :project, :issue, :current_user
|
||||
attr_reader :status_id, :priority_id, :milestone_id, :branch_name, :start_date, :due_date, :subject, :description, :blockchain_token_num
|
||||
attr_reader :target_pm_project_id, :pm_sprint_id, :pm_issue_type, :root_id, :time_scale
|
||||
attr_reader :issue_tag_ids, :assigner_ids, :attachment_ids, :receivers_login, :before_issue_tag_ids, :before_assigner_ids, :project_id
|
||||
attr_accessor :add_assigner_ids, :previous_issue_changes, :updated_issue, :atme_receivers
|
||||
|
||||
validates :project, :issue, :current_user, presence: true
|
||||
validates :blockchain_token_num, numericality: {greater_than: 0}, allow_blank: true
|
||||
|
||||
def initialize(project, issue, params, current_user = nil)
|
||||
@project = project
|
||||
@issue = issue
|
||||
@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]
|
||||
@blockchain_token_num = params[:blockchain_token_num]
|
||||
@issue_tag_ids = params[:issue_tag_ids]
|
||||
@assigner_ids = params[:assigner_ids]
|
||||
@before_issue_tag_ids = issue.issue_tags.pluck(:id)
|
||||
@before_assigner_ids = issue.assigners.pluck(:id)
|
||||
@attachment_ids = params[:attachment_ids]
|
||||
@receivers_login = params[:receivers_login]
|
||||
@target_pm_project_id = params[:target_pm_project_id]
|
||||
@pm_sprint_id = params[:pm_sprint_id]
|
||||
@pm_issue_type = params[:pm_issue_type]
|
||||
@root_id = params[:root_id]
|
||||
@time_scale = params[:time_scale]
|
||||
@project_id = params[:project_id]
|
||||
@add_assigner_ids = []
|
||||
@previous_issue_changes = {}
|
||||
end
|
||||
|
||||
def call
|
||||
raise Error, errors.full_messages.join(", ") unless valid?
|
||||
ActiveRecord::Base.transaction do
|
||||
check_issue_status(status_id) if status_id.present?
|
||||
check_issue_priority(priority_id) if priority_id.present?
|
||||
check_milestone(milestone_id) if milestone_id.present?
|
||||
check_root_issue(issue, root_id) if root_id.present?
|
||||
check_issue_tags(issue_tag_ids) unless issue_tag_ids.nil?
|
||||
check_assigners(assigner_ids) unless assigner_ids.nil?
|
||||
check_attachments(attachment_ids) unless attachment_ids.nil?
|
||||
check_atme_receivers(receivers_login) unless receivers_login.nil?
|
||||
check_blockchain_token_num(issue.author_id, project.id, blockchain_token_num, (@issue.blockchain_token_num || 0)) if blockchain_token_num.present? && current_user.id == @issue.author_id && !PullAttachedIssue.exists?(issue_id: @issue, fixed: true)
|
||||
load_assigners(assigner_ids)
|
||||
load_attachments(attachment_ids)
|
||||
load_issue_tags(issue_tag_ids)
|
||||
load_atme_receivers(receivers_login) unless receivers_login.nil?
|
||||
|
||||
try_lock("Api::Pm::Issues::UpdateService:#{project.id}:#{issue.id}")
|
||||
@updated_issue = @issue
|
||||
issue_load_attributes
|
||||
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.nil? # 负责人
|
||||
build_edit_participants
|
||||
build_atme_participants if @atme_receivers.present?
|
||||
unless assigner_ids.nil?
|
||||
@previous_issue_changes.merge!(assigned_to_id: [@updated_issue.assigners.pluck(:id), @assigners.pluck(:id)])
|
||||
@updated_issue.assigners = @assigners || User.none
|
||||
end
|
||||
@updated_issue.attachments = @attachments || Attachment.none unless attachment_ids.nil?
|
||||
@updated_issue.issue_tags_relates.destroy_all & @updated_issue.issue_tags = @issue_tags || IssueTag.none unless issue_tag_ids.nil?
|
||||
@updated_issue.issue_tags_value = @issue_tags.order("id asc").pluck(:id).join(",") unless issue_tag_ids.nil?
|
||||
|
||||
#Pm相关
|
||||
@updated_issue.pm_project_id = @target_pm_project_id unless @target_pm_project_id.nil?
|
||||
@updated_issue.pm_sprint_id = @pm_sprint_id unless @pm_sprint_id.nil?
|
||||
if @updated_issue.children_issues.count == 0 && @updated_issue.parent_id.nil?
|
||||
@updated_issue.pm_issue_type = @pm_issue_type unless @pm_issue_type.nil?
|
||||
end
|
||||
@updated_issue.root_id = @root_id unless @root_id.nil? #不为 nil的时候更新
|
||||
@updated_issue.root_id = nil if @root_id.try(:zero?) #为 0 的时候设置为 nil
|
||||
@updated_issue.time_scale = @time_scale unless @time_scale.nil?
|
||||
@updated_issue.project_id = @project_id unless @project_id.nil?
|
||||
@updated_issue.updated_on = Time.now
|
||||
@updated_issue.changer_id = @current_user.id
|
||||
@updated_issue.save!
|
||||
|
||||
build_after_issue_journal_details if @updated_issue.previous_changes.present? # 操作记录
|
||||
build_previous_issue_changes
|
||||
build_cirle_blockchain_token if blockchain_token_num.present?
|
||||
unless @project.id.zero?
|
||||
# @信息发送
|
||||
AtmeService.call(current_user, @atme_receivers, @issue) unless receivers_login.blank?
|
||||
# 消息发送
|
||||
if Site.has_notice_menu?
|
||||
SendTemplateMessageJob.perform_later('IssueChanged', current_user.id, @issue&.id, previous_issue_changes) unless previous_issue_changes.blank?
|
||||
SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id, add_assigner_ids) unless add_assigner_ids.blank?
|
||||
end
|
||||
# 触发webhook
|
||||
Rails.logger.info "################### 触发webhook"
|
||||
TouchWebhookJob.set(wait: 5.seconds).perform_later('IssueUpdate', @updated_issue&.id, current_user.id, previous_issue_changes.except(:issue_tags_value, :assigned_to_id))
|
||||
TouchWebhookJob.set(wait: 5.seconds).perform_later('IssueLabel', @issue&.id, current_user.id, {issue_tag_ids: [before_issue_tag_ids, issue_tag_ids]}) unless issue_tag_ids.nil?
|
||||
TouchWebhookJob.set(wait: 5.seconds).perform_later('IssueAssign', @issue&.id, current_user.id, {assigner_ids: [before_assigner_ids, assigner_ids]}) unless assigner_ids.nil?
|
||||
end
|
||||
|
||||
unlock("Api::Pm::Issues::UpdateService:#{project.id}:#{issue.id}")
|
||||
return @updated_issue
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def issue_load_attributes
|
||||
if current_user.id == @updated_issue.author_id && !PullAttachedIssue.exists?(issue_id: @updated_issue, fixed: true)
|
||||
@updated_issue.blockchain_token_num = blockchain_token_num unless blockchain_token_num.nil?
|
||||
end
|
||||
@updated_issue.status_id = status_id if status_id.present?
|
||||
@updated_issue.priority_id = priority_id if priority_id.present?
|
||||
@updated_issue.fixed_version_id = milestone_id unless milestone_id.nil?
|
||||
@updated_issue.branch_name = branch_name unless branch_name.nil?
|
||||
@updated_issue.start_date = start_date unless start_date.nil?
|
||||
@updated_issue.due_date = due_date unless due_date.nil?
|
||||
@updated_issue.subject = subject if subject.present?
|
||||
@updated_issue.description = description unless description.nil?
|
||||
end
|
||||
|
||||
def build_assigner_participants
|
||||
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.merge!(@updated_issue.previous_changes.slice("status_id", "priority_id", "fixed_version_id", "issue_tags_value", "branch_name", "subject").symbolize_keys)
|
||||
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])
|
||||
end
|
||||
end
|
||||
|
||||
def build_cirle_blockchain_token
|
||||
if @updated_issue.previous_changes["blockchain_token_num"].present?
|
||||
unlock_balance_on_blockchain(@updated_issue&.author_id.to_s, @updated_issue.project_id.to_s, @updated_issue.previous_changes["blockchain_token_num"][0].to_i) if @updated_issue.previous_changes["blockchain_token_num"][0].present?
|
||||
lock_balance_on_blockchain(@updated_issue&.author_id.to_s, @updated_issue.project_id.to_s, @updated_issue.previous_changes["blockchain_token_num"][1].to_i) if @updated_issue.previous_changes["blockchain_token_num"][1].present?
|
||||
end
|
||||
end
|
||||
|
||||
def build_issue_project_trends
|
||||
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
|
||||
@updated_issue.project_trends.where(action_type: ProjectTrend::CLOSE).each(&:destroy!)
|
||||
end
|
||||
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.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.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: @updated_issue.pm_issue_type_string, 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.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["pm_issue_type"].present?
|
||||
journal = @updated_issue.journals.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: "attr", prop_key: "pm_issue_type", old_value: @updated_issue.previous_changes["pm_issue_type"][0], value: @updated_issue.previous_changes["pm_issue_type"][1]})
|
||||
end
|
||||
|
||||
# 修改迭代
|
||||
if @updated_issue.previous_changes["pm_sprint_id"].present?
|
||||
journal = @updated_issue.journals.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: "attr", prop_key: "pm_sprint_id", old_value: @updated_issue.previous_changes["pm_sprint_id"][0], value: @updated_issue.previous_changes["pm_sprint_id"][1]})
|
||||
end
|
||||
|
||||
# 修改代码库
|
||||
if @updated_issue.previous_changes["project_id"].present?
|
||||
journal = @updated_issue.journals.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: "attr", prop_key: "project_id", old_value: @updated_issue.previous_changes["project_id"][0], value: @updated_issue.previous_changes["project_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.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.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.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
|
||||
|
||||
# 更改预估工时
|
||||
if @updated_issue.previous_changes["time_scale"].present?
|
||||
journal = @updated_issue.journals.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: "attr", prop_key: "time_scale", old_value: @updated_issue.previous_changes["time_scale"][0], value: @updated_issue.previous_changes["time_scale"][1]})
|
||||
end
|
||||
|
||||
# 更改父工作项
|
||||
if @updated_issue.previous_changes["root_id"].present?
|
||||
journal = @updated_issue.journals.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: @updated_issue.pm_issue_type_string, prop_key: "root_id", old_value: @updated_issue.previous_changes["root_id"][0], value: @updated_issue.previous_changes["root_id"][1]})
|
||||
|
||||
# 更改子工作项
|
||||
before_parent_issue = Issue.find_by_id(@updated_issue.previous_changes["root_id"][0])
|
||||
if before_parent_issue.present?
|
||||
journal = before_parent_issue.journals.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: @updated_issue.pm_issue_type_string, prop_key: "tag_leaf_issue", old_value: @updated_issue.id.to_s})
|
||||
end
|
||||
|
||||
after_parent_issue = Issue.find_by_id(@updated_issue.previous_changes["root_id"][1])
|
||||
if after_parent_issue.present?
|
||||
journal = after_parent_issue.journals.create!({user_id: current_user.id})
|
||||
journal.journal_details.create!({property: @updated_issue.pm_issue_type_string, prop_key: "tag_leaf_issue", value: @updated_issue.id.to_s})
|
||||
end
|
||||
end
|
||||
rescue
|
||||
raise Error, "创建操作记录失败!"
|
||||
end
|
||||
end
|
||||
|
||||
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.sort == new_assigner_ids.sort)
|
||||
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 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.sort == new_issue_tag_ids.sort)
|
||||
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.sort == new_attachment_ids.sort)
|
||||
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
|
|
@ -8,7 +8,7 @@ class Api::Pm::SprintIssues::ListService < ApplicationService
|
|||
attr_accessor :queried_issues
|
||||
|
||||
validates :category, inclusion: { in: %w[linked unlink], message: '请输入正确的Category'}
|
||||
validates :sort_by, inclusion: { in: %w[issues.created_on issues.updated_on issue_priorities.position] , message: '请输入正确的SortBy'}, allow_blank: true
|
||||
validates :sort_by, inclusion: { in: %w[issues.status_id issues.created_on issues.updated_on issue_priorities.position] , message: '请输入正确的SortBy'}, allow_blank: true
|
||||
validates :sort_direction, inclusion: { in: %w[asc desc], message: '请输入正确的SortDirection'}, allow_blank: true
|
||||
|
||||
validates :pm_project_id, :current_user, presence: true
|
||||
|
|
|
@ -16,6 +16,8 @@ class Api::V1::Issues::DeleteService < ApplicationService
|
|||
try_lock("Api::V1::Issues::DeleteService:#{project.id}") # 开始写数据,加锁
|
||||
|
||||
delete_issue
|
||||
#删除双向关联
|
||||
PmLink.where(be_linkable_id: @issue.id, be_linkable_type: 'Issue').or(PmLink.where(linkable_id: @issue.id, linkable_type: 'Issue')).map(&:destroy)
|
||||
|
||||
project.incre_project_issue_cache_delete_count
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ class Api::V1::Issues::ListService < ApplicationService
|
|||
|
||||
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: %w[issues.created_on issues.updated_on issues.blockchain_token_num issue_priorities.position issues.start_date issues.due_date] , message: '请输入正确的SortBy'}, allow_blank: true
|
||||
validates :sort_by, inclusion: { in: %w[issues.created_on issues.updated_on issues.blockchain_token_num issue_priorities.position issues.start_date issues.due_date issues.status_id] , message: '请输入正确的SortBy'}, allow_blank: true
|
||||
validates :sort_direction, inclusion: { in: %w[asc desc], message: '请输入正确的SortDirection'}, allow_blank: true
|
||||
validates :current_user, presence: true
|
||||
|
||||
|
@ -64,7 +64,7 @@ class Api::V1::Issues::ListService < ApplicationService
|
|||
private
|
||||
def issue_query_data
|
||||
issues = @project&.id.zero? ? Issue.issue_issue : @project.issues.issue_issue
|
||||
@total_issues_count = issues.distinct.size
|
||||
@total_issues_count = pm_project_id.present? ? issues.where(pm_issue_type:[1, 2, 3]).count : issues.count
|
||||
case participant_category
|
||||
when 'aboutme' # 关于我的
|
||||
issues = issues.joins(:issue_participants).where(issue_participants: {participant_type: %w[authored assigned atme], participant_id: participator&.id})
|
||||
|
|
|
@ -79,7 +79,9 @@ class Api::V1::Issues::UpdateService < ApplicationService
|
|||
#Pm相关
|
||||
@updated_issue.pm_project_id = @target_pm_project_id unless @target_pm_project_id.nil?
|
||||
@updated_issue.pm_sprint_id = @pm_sprint_id unless @pm_sprint_id.nil?
|
||||
@updated_issue.pm_issue_type = @pm_issue_type unless @pm_issue_type.nil?
|
||||
if @updated_issue.children_issues.count == 0 && @updated_issue.parent_id.nil?
|
||||
@updated_issue.pm_issue_type = @pm_issue_type unless @pm_issue_type.nil?
|
||||
end
|
||||
@updated_issue.root_id = @root_id unless @root_id.nil? #不为 nil的时候更新
|
||||
@updated_issue.root_id = nil if @root_id.try(:zero?) #为 0 的时候设置为 nil
|
||||
@updated_issue.time_scale = @time_scale unless @time_scale.nil?
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue