Commit 8997b8ab authored by Etienne Baqué's avatar Etienne Baqué

Merge branch 'vij-unique-pending-members' into 'master'

Adjusts pending members to be distinct

See merge request gitlab-org/gitlab!76864
parents 8bb0cff3 b988a40b
...@@ -30,11 +30,13 @@ module EE ...@@ -30,11 +30,13 @@ module EE
includes(:user, source: [:route, :parent]) includes(:user, source: [:route, :parent])
end end
scope :awaiting_or_invited_for_group, -> (group) do scope :distinct_awaiting_or_invited_for_group, -> (group) do
awaiting awaiting
.or(::Member.invite) .or(::Member.invite)
.in_hierarchy(group) .in_hierarchy(group)
.select('DISTINCT ON (members.user_id, members.invite_email) members.*')
.includes(:user) .includes(:user)
.order(:user_id, :invite_email)
end end
end end
......
...@@ -105,7 +105,7 @@ module EE ...@@ -105,7 +105,7 @@ module EE
bad_request! unless group.root? bad_request! unless group.root?
bad_request! unless can?(current_user, :admin_group_member, group) bad_request! unless can?(current_user, :admin_group_member, group)
members = ::Member.awaiting_or_invited_for_group(group) members = ::Member.distinct_awaiting_or_invited_for_group(group)
present paginate(members), with: ::API::Entities::PendingMember present paginate(members), with: ::API::Entities::PendingMember
end end
......
...@@ -246,22 +246,53 @@ RSpec.describe Member, type: :model do ...@@ -246,22 +246,53 @@ RSpec.describe Member, type: :model do
end end
end end
describe '.awaiting_or_invited_for_group' do describe '.distinct_awaiting_or_invited_for_group' do
let_it_be(:other_sub_group) { create(:group, parent: group) }
let_it_be(:active_group_member) { create(:group_member, group: group) } let_it_be(:active_group_member) { create(:group_member, group: group) }
let_it_be(:awaiting_group_member) { create(:group_member, :awaiting, group: group) } let_it_be(:awaiting_group_member) { create(:group_member, :awaiting, group: group) }
let_it_be(:awaiting_subgroup_member) { create(:group_member, :awaiting, group: sub_group) } let_it_be(:awaiting_subgroup_member) { create(:group_member, :awaiting, group: sub_group) }
let_it_be(:awaiting_other_subgroup_member) { create(:group_member, :awaiting, user: awaiting_subgroup_member.user, group: other_sub_group) }
let_it_be(:awaiting_project_member) { create(:project_member, :awaiting, project: project) } let_it_be(:awaiting_project_member) { create(:project_member, :awaiting, project: project) }
let_it_be(:awaiting_invited_member) { create(:group_member, :awaiting, :invited, group: group) } let_it_be(:awaiting_invited_member) { create(:group_member, :awaiting, :invited, group: group) }
let_it_be(:active_invited_member) { create(:group_member, :invited, group: group) } let_it_be(:active_invited_member) { create(:group_member, :invited, group: group) }
let_it_be(:awaiting_previously_invited_member) do
member = create(:group_member, :awaiting, :invited, group: group)
user = create(:user)
member.accept_invite!(user)
member
end
subject(:results) { described_class.distinct_awaiting_or_invited_for_group(group) }
it 'returns the correct members' do it 'returns the correct members' do
expect(described_class.awaiting_or_invited_for_group(group)).to match_array [ expect(results).to contain_exactly(
awaiting_group_member, awaiting_group_member,
awaiting_subgroup_member, awaiting_subgroup_member,
awaiting_project_member, awaiting_project_member,
awaiting_invited_member, awaiting_invited_member,
awaiting_previously_invited_member,
active_invited_member active_invited_member
] )
end
it 'does not return additional results for duplicates' do
create(:group_member, :awaiting, group: sub_group, user: awaiting_group_member.user)
create(:group_member, :invited, group: sub_group, invite_email: awaiting_invited_member.invite_email)
create(:group_member, :awaiting, group: sub_group, invite_email: awaiting_previously_invited_member.invite_email, user: awaiting_previously_invited_member.user)
expect(results.map(&:user_id).compact).to contain_exactly(
awaiting_group_member.user_id,
awaiting_subgroup_member.user_id,
awaiting_project_member.user_id,
awaiting_previously_invited_member.user_id
)
expect(results.map(&:invite_email).compact).to contain_exactly(
awaiting_invited_member.invite_email,
active_invited_member.invite_email,
awaiting_previously_invited_member.invite_email
)
end end
end end
end end
...@@ -1148,6 +1148,20 @@ RSpec.describe API::Members do ...@@ -1148,6 +1148,20 @@ RSpec.describe API::Members do
] ]
end end
it 'returns only one membership per user' do
create(:group_member, :awaiting, group: subgroup, user: pending_group_member.user)
create(:group_member, :awaiting, :invited, group: subgroup, invite_email: pending_invited_member.invite_email)
get api(url, owner)
expect(json_response.map { |m| m['id'] }).to match_array [
pending_group_member.id,
pending_subgroup_member.id,
pending_project_member.id,
pending_invited_member.id
]
end
it 'paginates the response' do it 'paginates the response' do
get api(url, owner) get api(url, owner)
......
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