Skip to content
Snippets Groups Projects
Commit 5439aaf2 authored by Marc Saleiko's avatar Marc Saleiko Committed by Siddharth Dungarwal
Browse files

Adds system note when external participants have been added from CC

Also adds an abstraction IssueEmailParticipants::CreateService
and refactors the /invite_email quick action to use this.
parent 985f3eee
No related branches found
No related tags found
1 merge request!137147Adds system note when external participants have been added from CC
# frozen_string_literal: true
module IssueEmailParticipants
class CreateService < ::BaseProjectService
MAX_NUMBER_OF_EMAILS = 6
attr_reader :target, :emails
def initialize(target:, current_user:, emails:)
super(project: target.project, current_user: current_user)
@target = target
@emails = emails
end
def execute
return error_feature_flag unless Feature.enabled?(:issue_email_participants, target.project)
return error_underprivileged unless current_user.can?(:"admin_#{target.to_ability_name}", target)
return error_no_participants unless emails.present?
added_emails = add_participants(deduplicate_and_limit_emails)
if added_emails.any?
message = add_system_note(added_emails)
ServiceResponse.success(message: message.upcase_first << ".")
else
error_no_participants
end
end
private
def deduplicate_and_limit_emails
existing_emails = target.email_participants_emails_downcase
# Compare downcase versions, but use the original email
emails.index_by { |email| [email.downcase, email] }.excluding(*existing_emails).each_value
.first(MAX_NUMBER_OF_EMAILS)
end
def add_participants(emails_to_add)
added_emails = []
emails_to_add.each do |email|
new_participant = target.issue_email_participants.create(email: email)
added_emails << email if new_participant.persisted?
end
added_emails
end
def add_system_note(added_emails)
message = format(_("added %{emails}"), emails: added_emails.to_sentence)
::SystemNoteService.add_email_participants(target, project, current_user, message)
message
end
def error(message)
ServiceResponse.error(message: message)
end
def error_feature_flag
# Don't translate feature flag error because it's temporary.
error("Feature flag issue_email_participants is not enabled for this project.")
end
def error_underprivileged
error(_("You don't have permission to add email participants."))
end
def error_no_participants
error(_("No email participants were added. Either none were provided, or they already exist."))
end
end
end
......@@ -230,6 +230,9 @@ def author
def add_email_participants
return if reply_email? && !Feature.enabled?(:issue_email_participants, @issue.project)
# Migrate this to ::IssueEmailParticipants::CreateService once the
# feature flag issue_email_participants has been enabled globally
# or removed: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/137147#note_1652104416
@issue.issue_email_participants.create(email: from_address)
add_external_participants_from_cc
......@@ -239,11 +242,11 @@ def add_external_participants_from_cc
return if project.service_desk_setting.nil?
return unless project.service_desk_setting.add_external_participants_from_cc?
cc_addresses.each do |email|
next if service_desk_addresses.include?(email)
@issue.issue_email_participants.create!(email: email)
end
::IssueEmailParticipants::CreateService.new(
target: @issue,
current_user: Users::Internal.support_bot,
emails: cc_addresses.excluding(service_desk_addresses)
).execute
end
def service_desk_addresses
......
......@@ -230,24 +230,13 @@ module IssueActions
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target)
end
command :invite_email do |emails = ""|
MAX_NUMBER_OF_EMAILS = 6
response = ::IssueEmailParticipants::CreateService.new(
target: quick_action_target,
current_user: current_user,
emails: emails.split(' ')
).execute
existing_emails = quick_action_target.email_participants_emails_downcase
emails_to_add = emails.split(' ').index_by { |email| [email.downcase, email] }.except(*existing_emails).each_value.first(MAX_NUMBER_OF_EMAILS)
added_emails = []
emails_to_add.each do |email|
new_participant = quick_action_target.issue_email_participants.create(email: email)
added_emails << email if new_participant.persisted?
end
if added_emails.any?
message = _("added %{emails}") % { emails: added_emails.to_sentence }
SystemNoteService.add_email_participants(quick_action_target, quick_action_target.project, current_user, message)
@execution_message[:invite_email] = message.upcase_first << "."
else
@execution_message[:invite_email] = _("No email participants were added. Either none were provided, or they already exist.")
end
@execution_message[:invite_email] = response.message
end
desc { _('Promote issue to incident') }
......
......@@ -55554,6 +55554,9 @@ msgstr ""
msgid "You don't have any recent searches"
msgstr ""
 
msgid "You don't have permission to add email participants."
msgstr ""
msgid "You don't have permission to approve this deployment. Contact the project or group owner for help."
msgstr ""
 
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe IssueEmailParticipants::CreateService, feature_category: :service_desk do
shared_examples 'a successful service execution' do
it 'creates new participants', :aggregate_failures do
expect(response).to be_success
issue.reset
note = issue.notes.last
expect(note.system?).to be true
expect(note.author).to eq(user)
participants_emails = issue.email_participants_emails_downcase
expected_emails.each do |email|
expect(participants_emails).to include(email)
expect(response.message).to include(email)
expect(note.note).to include(email)
end
end
end
shared_examples 'a failed service execution' do
it 'returns error ServiceResponse with message', :aggregate_failures do
expect(response).to be_error
expect(response.message).to eq(error_message)
end
end
describe '#execute' do
let_it_be_with_reload(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:issue) { create(:issue, project: project) }
let(:emails) { nil }
let(:service) { described_class.new(target: issue, current_user: user, emails: emails) }
let(:expected_emails) { emails }
let(:error_feature_flag) { "Feature flag issue_email_participants is not enabled for this project." }
let(:error_underprivileged) { _("You don't have permission to add email participants.") }
let(:error_no_participants) do
_("No email participants were added. Either none were provided, or they already exist.")
end
subject(:response) { service.execute }
context 'when the user is not a project member' do
let(:error_message) { error_underprivileged }
it_behaves_like 'a failed service execution'
end
context 'when user has reporter role in project' do
before_all do
project.add_reporter(user)
end
context 'when no emails are provided' do
let(:error_message) { error_no_participants }
it_behaves_like 'a failed service execution'
end
context 'when one email is provided' do
let(:emails) { ['user@example.com'] }
it_behaves_like 'a successful service execution'
context 'when email is already a participant of the issue' do
let(:error_message) { error_no_participants }
before do
issue.issue_email_participants.create!(email: emails.first)
end
it_behaves_like 'a failed service execution'
context 'when email is formatted in a different case' do
let(:emails) { ['USER@example.com'] }
it_behaves_like 'a failed service execution'
end
end
end
context 'when multiple emails are provided' do
let(:emails) { ['user@example.com', 'user2@example.com'] }
it_behaves_like 'a successful service execution'
context 'when duplicate email provided' do
let(:emails) { ['user@example.com', 'user@example.com'] }
let(:expected_emails) { emails[...-1] }
it_behaves_like 'a successful service execution'
end
context 'when an email is already a participant of the issue' do
let(:expected_emails) { emails[1...] }
before do
issue.issue_email_participants.create!(email: emails.first)
end
it_behaves_like 'a successful service execution'
end
end
context 'when more than the allowed number of emails a re provided' do
let(:emails) { (1..7).map { |i| "user#{i}@example.com" } }
let(:expected_emails) { emails[...-1] }
it_behaves_like 'a successful service execution'
end
end
context 'when feature flag issue_email_participants is disabled' do
let(:error_message) { error_feature_flag }
before do
stub_feature_flags(issue_email_participants: false)
end
it_behaves_like 'a failed service execution'
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment