diff options
Diffstat (limited to 'app/services/issues')
-rw-r--r-- | app/services/issues/base_service.rb | 9 | ||||
-rw-r--r-- | app/services/issues/build_service.rb | 2 | ||||
-rw-r--r-- | app/services/issues/close_service.rb | 9 | ||||
-rw-r--r-- | app/services/issues/create_service.rb | 6 | ||||
-rw-r--r-- | app/services/issues/set_crm_contacts_service.rb | 90 | ||||
-rw-r--r-- | app/services/issues/update_service.rb | 2 |
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 |