mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 07:36:14 -05:00
[PM-12489] Extract OrganizationService.DeleteAsync and OrganizationService.InitiateDeleteAsync into commands (#5279)
* Create organization deletion command with logic extracted from OrganizationService * Add unit tests for OrganizationDeleteCommand * Register OrganizationDeleteCommand for dependency injection * Refactor organization deletion logic to use IOrganizationDeleteCommand and remove legacy IOrganizationService.DeleteAsync method * Add organization deletion initiation command and refactor service usage * Enhance organization deletion commands with detailed XML documentation * Refactor organization command registration to include sign-up and deletion methods
This commit is contained in:
@ -0,0 +1,53 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
|
||||
using Bit.Core.Auth.Entities;
|
||||
using Bit.Core.Auth.Enums;
|
||||
using Bit.Core.Auth.Models.Data;
|
||||
using Bit.Core.Auth.Repositories;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Test.AutoFixture.OrganizationFixtures;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Organizations;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationDeleteCommandTests
|
||||
{
|
||||
[Theory, PaidOrganizationCustomize, BitAutoData]
|
||||
public async Task Delete_Success(Organization organization, SutProvider<OrganizationDeleteCommand> sutProvider)
|
||||
{
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
var applicationCacheService = sutProvider.GetDependency<IApplicationCacheService>();
|
||||
|
||||
await sutProvider.Sut.DeleteAsync(organization);
|
||||
|
||||
await organizationRepository.Received().DeleteAsync(organization);
|
||||
await applicationCacheService.Received().DeleteOrganizationAbilityAsync(organization.Id);
|
||||
}
|
||||
|
||||
[Theory, PaidOrganizationCustomize, BitAutoData]
|
||||
public async Task Delete_Fails_KeyConnector(Organization organization, SutProvider<OrganizationDeleteCommand> sutProvider,
|
||||
SsoConfig ssoConfig)
|
||||
{
|
||||
ssoConfig.Enabled = true;
|
||||
ssoConfig.SetData(new SsoConfigurationData { MemberDecryptionType = MemberDecryptionType.KeyConnector });
|
||||
var ssoConfigRepository = sutProvider.GetDependency<ISsoConfigRepository>();
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
var applicationCacheService = sutProvider.GetDependency<IApplicationCacheService>();
|
||||
|
||||
ssoConfigRepository.GetByOrganizationIdAsync(organization.Id).Returns(ssoConfig);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.DeleteAsync(organization));
|
||||
|
||||
Assert.Contains("You cannot delete an Organization that is using Key Connector.", exception.Message);
|
||||
|
||||
await organizationRepository.DidNotReceiveWithAnyArgs().DeleteAsync(default);
|
||||
await applicationCacheService.DidNotReceiveWithAnyArgs().DeleteOrganizationAbilityAsync(default);
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Business.Tokenables;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Tokens;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Organizations;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationInitiateDeleteCommandTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData(OrganizationUserType.Admin)]
|
||||
[BitAutoData(OrganizationUserType.Owner)]
|
||||
public async Task InitiateDeleteAsync_ValidAdminUser_Success(OrganizationUserType organizationUserType,
|
||||
Organization organization, User orgAdmin, OrganizationUserOrganizationDetails orgAdminUser,
|
||||
string token, SutProvider<OrganizationInitiateDeleteCommand> sutProvider)
|
||||
{
|
||||
orgAdminUser.Type = organizationUserType;
|
||||
orgAdminUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
|
||||
sutProvider.GetDependency<IUserRepository>()
|
||||
.GetByEmailAsync(orgAdmin.Email)
|
||||
.Returns(orgAdmin);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetDetailsByUserAsync(orgAdmin.Id, organization.Id)
|
||||
.Returns(orgAdminUser);
|
||||
|
||||
sutProvider.GetDependency<IDataProtectorTokenFactory<OrgDeleteTokenable>>()
|
||||
.Protect(Arg.Any<OrgDeleteTokenable>())
|
||||
.Returns(token);
|
||||
|
||||
await sutProvider.Sut.InitiateDeleteAsync(organization, orgAdmin.Email);
|
||||
|
||||
await sutProvider.GetDependency<IMailService>().Received(1)
|
||||
.SendInitiateDeleteOrganzationEmailAsync(orgAdmin.Email, organization, token);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task InitiateDeleteAsync_UserNotFound_ThrowsBadRequest(
|
||||
Organization organization, string email, SutProvider<OrganizationInitiateDeleteCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IUserRepository>()
|
||||
.GetByEmailAsync(email)
|
||||
.Returns((User)null);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.InitiateDeleteAsync(organization, email));
|
||||
|
||||
Assert.Equal(OrganizationInitiateDeleteCommand.OrganizationAdminNotFoundErrorMessage, exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(OrganizationUserType.User)]
|
||||
[BitAutoData(OrganizationUserType.Custom)]
|
||||
public async Task InitiateDeleteAsync_UserNotOrgAdmin_ThrowsBadRequest(OrganizationUserType organizationUserType,
|
||||
Organization organization, User user, OrganizationUserOrganizationDetails orgUser,
|
||||
SutProvider<OrganizationInitiateDeleteCommand> sutProvider)
|
||||
{
|
||||
orgUser.Type = organizationUserType;
|
||||
orgUser.Status = OrganizationUserStatusType.Confirmed;
|
||||
|
||||
sutProvider.GetDependency<IUserRepository>()
|
||||
.GetByEmailAsync(user.Email)
|
||||
.Returns(user);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetDetailsByUserAsync(user.Id, organization.Id)
|
||||
.Returns(orgUser);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.InitiateDeleteAsync(organization, user.Email));
|
||||
|
||||
Assert.Equal(OrganizationInitiateDeleteCommand.OrganizationAdminNotFoundErrorMessage, exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(OrganizationUserStatusType.Invited)]
|
||||
[BitAutoData(OrganizationUserStatusType.Revoked)]
|
||||
[BitAutoData(OrganizationUserStatusType.Accepted)]
|
||||
public async Task InitiateDeleteAsync_UserNotConfirmed_ThrowsBadRequest(
|
||||
OrganizationUserStatusType organizationUserStatusType,
|
||||
Organization organization, User user, OrganizationUserOrganizationDetails orgUser,
|
||||
SutProvider<OrganizationInitiateDeleteCommand> sutProvider)
|
||||
{
|
||||
orgUser.Type = OrganizationUserType.Admin;
|
||||
orgUser.Status = organizationUserStatusType;
|
||||
|
||||
sutProvider.GetDependency<IUserRepository>()
|
||||
.GetByEmailAsync(user.Email)
|
||||
.Returns(user);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetDetailsByUserAsync(user.Id, organization.Id)
|
||||
.Returns(orgUser);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.InitiateDeleteAsync(organization, user.Email));
|
||||
|
||||
Assert.Equal(OrganizationInitiateDeleteCommand.OrganizationAdminNotFoundErrorMessage, exception.Message);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user