From 54cf3de11bf72c80cce979395dd3a1c5e0f3aff4 Mon Sep 17 00:00:00 2001 From: Jake Fink Date: Wed, 13 Jul 2022 09:21:28 -0400 Subject: [PATCH] [EC-284] Prevent duplicate organization invites (#2113) * prevent duplicate organization invites with test * formatting --- .../Accounts/UpdateProfileRequestModel.cs | 3 +-- .../Implementations/OrganizationService.cs | 3 ++- .../Services/OrganizationServiceTests.cs | 22 +++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/Api/Models/Request/Accounts/UpdateProfileRequestModel.cs b/src/Api/Models/Request/Accounts/UpdateProfileRequestModel.cs index 0ab9b89be2..9f8506dfc9 100644 --- a/src/Api/Models/Request/Accounts/UpdateProfileRequestModel.cs +++ b/src/Api/Models/Request/Accounts/UpdateProfileRequestModel.cs @@ -1,5 +1,4 @@ -using System; -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; using Bit.Core.Entities; namespace Bit.Api.Models.Request.Accounts diff --git a/src/Core/Services/Implementations/OrganizationService.cs b/src/Core/Services/Implementations/OrganizationService.cs index 197cdd4d4a..f7314d0e73 100644 --- a/src/Core/Services/Implementations/OrganizationService.cs +++ b/src/Core/Services/Implementations/OrganizationService.cs @@ -1135,7 +1135,8 @@ namespace Bit.Core.Services var events = new List<(OrganizationUser, EventType, DateTime?)>(); foreach (var (invite, externalId) in invites) { - foreach (var email in invite.Emails) + // Prevent duplicate invitations + foreach (var email in invite.Emails.Distinct()) { try { diff --git a/test/Core.Test/Services/OrganizationServiceTests.cs b/test/Core.Test/Services/OrganizationServiceTests.cs index a4f978c3dc..acf2b7f170 100644 --- a/test/Core.Test/Services/OrganizationServiceTests.cs +++ b/test/Core.Test/Services/OrganizationServiceTests.cs @@ -195,6 +195,28 @@ namespace Bit.Core.Test.Services () => sutProvider.Sut.InviteUsersAsync(organization.Id, invitor.UserId, new (OrganizationUserInvite, string)[] { (invite, null) })); } + [Theory] + [OrganizationInviteAutoData] + public async Task InviteUser_DuplicateEmails_PassesWithoutDuplicates(Organization organization, OrganizationUser invitor, + [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner, + OrganizationUserInvite invite, SutProvider sutProvider) + { + invite.Emails = invite.Emails.Append(invite.Emails.First()); + + sutProvider.GetDependency().GetByIdAsync(organization.Id).Returns(organization); + sutProvider.GetDependency().OrganizationOwner(organization.Id).Returns(true); + sutProvider.GetDependency().ManageUsers(organization.Id).Returns(true); + var organizationUserRepository = sutProvider.GetDependency(); + organizationUserRepository.GetManyByOrganizationAsync(organization.Id, OrganizationUserType.Owner) + .Returns(new[] { owner }); + + await sutProvider.Sut.InviteUsersAsync(organization.Id, invitor.UserId, new (OrganizationUserInvite, string)[] { (invite, null) }); + + await sutProvider.GetDependency().Received(1) + .BulkSendOrganizationInviteEmailAsync(organization.Name, + Arg.Is>(v => v.Count() == invite.Emails.Distinct().Count())); + } + [Theory] [OrganizationInviteAutoData( inviteeUserType: (int)OrganizationUserType.Admin,