Commit 195c9e17 authored by Pavel Shutsin's avatar Pavel Shutsin

Merge branch '2256-cascade-crm-objects' into 'master'

Allow issue contacts from parent groups

See merge request gitlab-org/gitlab!77352
parents e938dde4 380cc55a
...@@ -26,10 +26,10 @@ class CustomerRelations::Contact < ApplicationRecord ...@@ -26,10 +26,10 @@ class CustomerRelations::Contact < ApplicationRecord
validate :validate_email_format validate :validate_email_format
validate :unique_email_for_group_hierarchy validate :unique_email_for_group_hierarchy
def self.find_ids_by_emails(group_id, emails) def self.find_ids_by_emails(group, emails)
raise ArgumentError, "Cannot lookup more than #{MAX_PLUCK} emails" if emails.length > MAX_PLUCK raise ArgumentError, "Cannot lookup more than #{MAX_PLUCK} emails" if emails.length > MAX_PLUCK
where(group_id: group_id, email: emails) where(group_id: group.self_and_ancestor_ids, email: emails)
.pluck(:id) .pluck(:id)
end end
......
...@@ -6,7 +6,7 @@ class CustomerRelations::IssueContact < ApplicationRecord ...@@ -6,7 +6,7 @@ class CustomerRelations::IssueContact < ApplicationRecord
belongs_to :issue, optional: false, inverse_of: :customer_relations_contacts belongs_to :issue, optional: false, inverse_of: :customer_relations_contacts
belongs_to :contact, optional: false, inverse_of: :issue_contacts belongs_to :contact, optional: false, inverse_of: :issue_contacts
validate :contact_belongs_to_issue_group validate :contact_belongs_to_issue_group_or_ancestor
def self.find_contact_ids_by_emails(issue_id, emails) def self.find_contact_ids_by_emails(issue_id, emails)
raise ArgumentError, "Cannot lookup more than #{MAX_PLUCK} emails" if emails.length > MAX_PLUCK raise ArgumentError, "Cannot lookup more than #{MAX_PLUCK} emails" if emails.length > MAX_PLUCK
...@@ -18,11 +18,11 @@ class CustomerRelations::IssueContact < ApplicationRecord ...@@ -18,11 +18,11 @@ class CustomerRelations::IssueContact < ApplicationRecord
private private
def contact_belongs_to_issue_group def contact_belongs_to_issue_group_or_ancestor
return unless contact&.group_id return unless contact&.group_id
return unless issue&.project&.namespace_id return unless issue&.project&.namespace_id
return if contact.group_id == issue.project.namespace_id return if issue.project.group&.self_and_ancestor_ids&.include?(contact.group_id)
errors.add(:base, _('The contact does not belong to the same group as the issue')) errors.add(:base, _('The contact does not belong to the issue group or an ancestor'))
end end
end end
...@@ -48,7 +48,7 @@ module Issues ...@@ -48,7 +48,7 @@ module Issues
end end
def add_by_email def add_by_email
contact_ids = ::CustomerRelations::Contact.find_ids_by_emails(project_group.id, params[:add_emails]) contact_ids = ::CustomerRelations::Contact.find_ids_by_emails(project_group, params[:add_emails])
add_by_id(contact_ids) add_by_id(contact_ids)
end end
......
...@@ -35367,7 +35367,7 @@ msgstr "" ...@@ -35367,7 +35367,7 @@ msgstr ""
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination." msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "" msgstr ""
msgid "The contact does not belong to the same group as the issue" msgid "The contact does not belong to the issue group or an ancestor"
msgstr "" msgstr ""
msgid "The content editor may change the markdown formatting style of the document, which may not match your original markdown style." msgid "The content editor may change the markdown formatting style of the document, which may not match your original markdown style."
......
...@@ -75,20 +75,27 @@ RSpec.describe CustomerRelations::Contact, type: :model do ...@@ -75,20 +75,27 @@ RSpec.describe CustomerRelations::Contact, type: :model do
let_it_be(:other_contacts) { create_list(:contact, 2) } let_it_be(:other_contacts) { create_list(:contact, 2) }
it 'returns ids of contacts from group' do it 'returns ids of contacts from group' do
contact_ids = described_class.find_ids_by_emails(group.id, group_contacts.pluck(:email)) contact_ids = described_class.find_ids_by_emails(group, group_contacts.pluck(:email))
expect(contact_ids).to match_array(group_contacts.pluck(:id))
end
it 'returns ids of contacts from parent group' do
subgroup = create(:group, parent: group)
contact_ids = described_class.find_ids_by_emails(subgroup, group_contacts.pluck(:email))
expect(contact_ids).to match_array(group_contacts.pluck(:id)) expect(contact_ids).to match_array(group_contacts.pluck(:id))
end end
it 'does not return ids of contacts from other groups' do it 'does not return ids of contacts from other groups' do
contact_ids = described_class.find_ids_by_emails(group.id, other_contacts.pluck(:email)) contact_ids = described_class.find_ids_by_emails(group, other_contacts.pluck(:email))
expect(contact_ids).to be_empty expect(contact_ids).to be_empty
end end
it 'raises ArgumentError when called with too many emails' do it 'raises ArgumentError when called with too many emails' do
too_many_emails = described_class::MAX_PLUCK + 1 too_many_emails = described_class::MAX_PLUCK + 1
expect { described_class.find_ids_by_emails(group.id, Array(0..too_many_emails)) }.to raise_error(ArgumentError) expect { described_class.find_ids_by_emails(group, Array(0..too_many_emails)) }.to raise_error(ArgumentError)
end end
end end
end end
...@@ -5,7 +5,8 @@ require 'spec_helper' ...@@ -5,7 +5,8 @@ require 'spec_helper'
RSpec.describe CustomerRelations::IssueContact do RSpec.describe CustomerRelations::IssueContact do
let_it_be(:issue_contact, reload: true) { create(:issue_customer_relations_contact) } let_it_be(:issue_contact, reload: true) { create(:issue_customer_relations_contact) }
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) } let_it_be(:subgroup) { create(:group, parent: group) }
let_it_be(:project) { create(:project, group: subgroup) }
let_it_be(:issue) { create(:issue, project: project) } let_it_be(:issue) { create(:issue, project: project) }
subject { issue_contact } subject { issue_contact }
...@@ -33,17 +34,29 @@ RSpec.describe CustomerRelations::IssueContact do ...@@ -33,17 +34,29 @@ RSpec.describe CustomerRelations::IssueContact do
end end
it 'builds using the same group', :aggregate_failures do it 'builds using the same group', :aggregate_failures do
expect(for_issue.contact.group).to eq(group) expect(for_issue.contact.group).to eq(subgroup)
expect(for_contact.issue.project.group).to eq(group) expect(for_contact.issue.project.group).to eq(group)
end end
end end
describe 'validation' do describe 'validation' do
let(:built) { build(:issue_customer_relations_contact, issue: create(:issue), contact: create(:contact)) } it 'fails when the contact group does not belong to the issue group or ancestors' do
built = build(:issue_customer_relations_contact, issue: create(:issue), contact: create(:contact))
it 'fails when the contact group does not match the issue group' do
expect(built).not_to be_valid expect(built).not_to be_valid
end end
it 'succeeds when the contact group is the same as the issue group' do
built = build(:issue_customer_relations_contact, issue: create(:issue, project: project), contact: create(:contact, group: subgroup))
expect(built).to be_valid
end
it 'succeeds when the contact group is an ancestor of the issue group' do
built = build(:issue_customer_relations_contact, issue: create(:issue, project: project), contact: create(:contact, group: group))
expect(built).to be_valid
end
end end
describe '#self.find_contact_ids_by_emails' do describe '#self.find_contact_ids_by_emails' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment