summaryrefslogtreecommitdiff
path: root/app/services/issues
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/issues')
-rw-r--r--app/services/issues/base_service.rb9
-rw-r--r--app/services/issues/build_service.rb2
-rw-r--r--app/services/issues/close_service.rb9
-rw-r--r--app/services/issues/create_service.rb6
-rw-r--r--app/services/issues/set_crm_contacts_service.rb90
-rw-r--r--app/services/issues/update_service.rb2
6 files changed, 108 insertions, 10 deletions
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index 6dce9fd6e73..efb5de5b17c 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -3,6 +3,7 @@
module Issues
class BaseService < ::IssuableBaseService
include IncidentManagement::UsageData
+ include IssueTypeHelpers
def hook_data(issue, action, old_associations: {})
hook_data = issue.to_hook_data(current_user, old_associations: old_associations)
@@ -44,7 +45,7 @@ module Issues
def filter_params(issue)
super
- params.delete(:issue_type) unless issue_type_allowed?(issue)
+ params.delete(:issue_type) unless create_issue_type_allowed?(issue, params[:issue_type])
filter_incident_label(issue) if params[:issue_type]
moved_issue = params.delete(:moved_issue)
@@ -89,12 +90,6 @@ module Issues
Milestones::IssuesCountService.new(milestone).delete_cache
end
- # @param object [Issue, Project]
- def issue_type_allowed?(object)
- WorkItem::Type.base_types.key?(params[:issue_type]) &&
- can?(current_user, :"create_#{params[:issue_type]}", object)
- end
-
# @param issue [Issue]
def filter_incident_label(issue)
return unless add_incident_label?(issue) || remove_incident_label?(issue)
diff --git a/app/services/issues/build_service.rb b/app/services/issues/build_service.rb
index 7fdc8daf15c..8fd844c4886 100644
--- a/app/services/issues/build_service.rb
+++ b/app/services/issues/build_service.rb
@@ -80,7 +80,7 @@ module Issues
]
allowed_params << :milestone_id if can?(current_user, :admin_issue, project)
- allowed_params << :issue_type if issue_type_allowed?(project)
+ allowed_params << :issue_type if create_issue_type_allowed?(project, params[:issue_type])
params.slice(*allowed_params)
end
diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb
index ac846c769a3..65f143d0b21 100644
--- a/app/services/issues/close_service.rb
+++ b/app/services/issues/close_service.rb
@@ -62,6 +62,7 @@ module Issues
def perform_incident_management_actions(issue)
resolve_alert(issue)
+ resolve_incident(issue)
end
def close_external_issue(issue, closed_via)
@@ -91,6 +92,14 @@ module Issues
end
end
+ def resolve_incident(issue)
+ return unless issue.incident?
+
+ status = issue.incident_management_issuable_escalation_status || issue.build_incident_management_issuable_escalation_status
+
+ SystemNoteService.resolve_incident_status(issue, current_user) if status.resolve
+ end
+
def store_first_mentioned_in_commit_at(issue, merge_request, max_commit_lookup: 100)
metrics = issue.metrics
return if metrics.nil? || metrics.first_mentioned_in_commit_at
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index fcedd1c1c8d..fa8d380404b 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -6,7 +6,7 @@ module Issues
prepend RateLimitedService
rate_limit key: :issues_create,
- opts: { scope: [:project, :current_user], users_allowlist: -> { [User.support_bot.username] } }
+ opts: { scope: [:project, :current_user, :external_author] }
# NOTE: For Issues::CreateService, we require the spam_params and do not default it to nil, because
# spam_checking is likely to be necessary. However, if there is not a request available in scope
@@ -25,6 +25,10 @@ module Issues
create(@issue, skip_system_notes: skip_system_notes)
end
+ def external_author
+ params[:external_author] # present when creating an issue using service desk (email: from)
+ end
+
def before_create(issue)
Spam::SpamActionService.new(
spammable: issue,
diff --git a/app/services/issues/set_crm_contacts_service.rb b/app/services/issues/set_crm_contacts_service.rb
new file mode 100644
index 00000000000..13fe30b5ac8
--- /dev/null
+++ b/app/services/issues/set_crm_contacts_service.rb
@@ -0,0 +1,90 @@
+# frozen_string_literal: true
+
+module Issues
+ class SetCrmContactsService < ::BaseProjectService
+ attr_accessor :issue, :errors
+
+ MAX_ADDITIONAL_CONTACTS = 6
+
+ def execute(issue)
+ @issue = issue
+ @errors = []
+
+ return error_no_permissions unless allowed?
+ return error_invalid_params unless valid_params?
+
+ determine_changes if params[:crm_contact_ids]
+
+ return error_too_many if too_many?
+
+ add_contacts if params[:add_crm_contact_ids]
+ remove_contacts if params[:remove_crm_contact_ids]
+
+ if issue.valid?
+ ServiceResponse.success(payload: issue)
+ else
+ # The default error isn't very helpful: "Issue customer relations contacts is invalid"
+ issue.errors.delete(:issue_customer_relations_contacts)
+ issue.errors.add(:issue_customer_relations_contacts, errors.to_sentence)
+ ServiceResponse.error(payload: issue, message: issue.errors.full_messages)
+ end
+ end
+
+ private
+
+ def determine_changes
+ existing_contact_ids = issue.issue_customer_relations_contacts.map(&:contact_id)
+ params[:add_crm_contact_ids] = params[:crm_contact_ids] - existing_contact_ids
+ params[:remove_crm_contact_ids] = existing_contact_ids - params[:crm_contact_ids]
+ end
+
+ def add_contacts
+ params[:add_crm_contact_ids].uniq.each do |contact_id|
+ issue_contact = issue.issue_customer_relations_contacts.create(contact_id: contact_id)
+
+ unless issue_contact.persisted?
+ # The validation ensures that the id exists and the user has permission
+ errors << "#{contact_id}: The resource that you are attempting to access does not exist or you don't have permission to perform this action"
+ end
+ end
+ end
+
+ def remove_contacts
+ issue.issue_customer_relations_contacts
+ .where(contact_id: params[:remove_crm_contact_ids]) # rubocop: disable CodeReuse/ActiveRecord
+ .delete_all
+ end
+
+ def allowed?
+ current_user&.can?(:set_issue_crm_contacts, issue)
+ end
+
+ def valid_params?
+ set_present? ^ add_or_remove_present?
+ end
+
+ def set_present?
+ params[:crm_contact_ids].present?
+ end
+
+ def add_or_remove_present?
+ params[:add_crm_contact_ids].present? || params[:remove_crm_contact_ids].present?
+ end
+
+ def too_many?
+ params[:add_crm_contact_ids] && params[:add_crm_contact_ids].length > MAX_ADDITIONAL_CONTACTS
+ end
+
+ def error_no_permissions
+ ServiceResponse.error(message: ['You have insufficient permissions to set customer relations contacts for this issue'])
+ end
+
+ def error_invalid_params
+ ServiceResponse.error(message: ['You cannot combine crm_contact_ids with add_crm_contact_ids or remove_crm_contact_ids'])
+ end
+
+ def error_too_many
+ ServiceResponse.error(payload: issue, message: ["You can only add up to #{MAX_ADDITIONAL_CONTACTS} contacts at one time"])
+ end
+ end
+end
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index d120b007af2..824a609dfb9 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -80,7 +80,7 @@ module Issues
todo_service.reassigned_assignable(issue, current_user, old_assignees)
track_incident_action(current_user, issue, :incident_assigned)
- if Gitlab::ActionCable::Config.in_app? || Feature.enabled?(:broadcast_issue_updates, issue.project)
+ if Feature.enabled?(:broadcast_issue_updates, issue.project, default_enabled: :yaml)
GraphqlTriggers.issuable_assignees_updated(issue)
end
end