mirror of
https://github.com/bitwarden/server.git
synced 2025-07-04 01:22:50 -05:00
[PM-7004] Org Admin Initiate Delete (#3905)
* org delete * move org id to URL path * tweaks * lint fixes * Update src/Core/Services/Implementations/HandlebarsMailService.cs Co-authored-by: Rui Tomé <108268980+r-tome@users.noreply.github.com> * Update src/Core/Services/Implementations/HandlebarsMailService.cs Co-authored-by: Rui Tomé <108268980+r-tome@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Rui Tomé <108268980+r-tome@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Rui Tomé <108268980+r-tome@users.noreply.github.com> * PR feedback * fix id * [PM-7004] Move OrgDeleteTokenable to AdminConsole ownership * [PM-7004] Add consolidated billing logic into organization delete request acceptance endpoint * [PM-7004] Delete unused IOrganizationService.DeleteAsync(Organization organization, string token) method * [PM-7004] Fix unit tests * [PM-7004] Update delete organization request email templates * Add success message when initiating organization deletion * Refactor OrganizationsController request delete initiation action to handle exceptions --------- Co-authored-by: Rui Tomé <108268980+r-tome@users.noreply.github.com> Co-authored-by: Rui Tome <rtome@bitwarden.com>
This commit is contained in:
@ -11,6 +11,7 @@ using Bit.Api.Models.Request.Organizations;
|
||||
using Bit.Api.Models.Response;
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Business.Tokenables;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys.Interfaces;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationCollectionEnhancements.Interfaces;
|
||||
@ -26,6 +27,7 @@ using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Tokens;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -54,6 +56,7 @@ public class OrganizationsController : Controller
|
||||
private readonly IOrganizationEnableCollectionEnhancementsCommand _organizationEnableCollectionEnhancementsCommand;
|
||||
private readonly IProviderRepository _providerRepository;
|
||||
private readonly IScaleSeatsCommand _scaleSeatsCommand;
|
||||
private readonly IDataProtectorTokenFactory<OrgDeleteTokenable> _orgDeleteTokenDataFactory;
|
||||
|
||||
public OrganizationsController(
|
||||
IOrganizationRepository organizationRepository,
|
||||
@ -73,7 +76,8 @@ public class OrganizationsController : Controller
|
||||
IPushNotificationService pushNotificationService,
|
||||
IOrganizationEnableCollectionEnhancementsCommand organizationEnableCollectionEnhancementsCommand,
|
||||
IProviderRepository providerRepository,
|
||||
IScaleSeatsCommand scaleSeatsCommand)
|
||||
IScaleSeatsCommand scaleSeatsCommand,
|
||||
IDataProtectorTokenFactory<OrgDeleteTokenable> orgDeleteTokenDataFactory)
|
||||
{
|
||||
_organizationRepository = organizationRepository;
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
@ -93,6 +97,7 @@ public class OrganizationsController : Controller
|
||||
_organizationEnableCollectionEnhancementsCommand = organizationEnableCollectionEnhancementsCommand;
|
||||
_providerRepository = providerRepository;
|
||||
_scaleSeatsCommand = scaleSeatsCommand;
|
||||
_orgDeleteTokenDataFactory = orgDeleteTokenDataFactory;
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
@ -279,6 +284,37 @@ public class OrganizationsController : Controller
|
||||
await _organizationService.DeleteAsync(organization);
|
||||
}
|
||||
|
||||
[HttpPost("{id}/delete-recover-token")]
|
||||
[AllowAnonymous]
|
||||
public async Task PostDeleteRecoverToken(Guid id, [FromBody] OrganizationVerifyDeleteRecoverRequestModel model)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(id);
|
||||
if (organization == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
if (!_orgDeleteTokenDataFactory.TryUnprotect(model.Token, out var data) || !data.IsValid(organization))
|
||||
{
|
||||
throw new BadRequestException("Invalid token.");
|
||||
}
|
||||
|
||||
var consolidatedBillingEnabled = _featureService.IsEnabled(FeatureFlagKeys.EnableConsolidatedBilling);
|
||||
if (consolidatedBillingEnabled && organization.IsValidClient())
|
||||
{
|
||||
var provider = await _providerRepository.GetByOrganizationIdAsync(organization.Id);
|
||||
if (provider.IsBillable())
|
||||
{
|
||||
await _scaleSeatsCommand.ScalePasswordManagerSeats(
|
||||
provider,
|
||||
organization.PlanType,
|
||||
-organization.Seats ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
await _organizationService.DeleteAsync(organization);
|
||||
}
|
||||
|
||||
[HttpPost("{id}/import")]
|
||||
public async Task Import(string id, [FromBody] ImportOrganizationUsersRequestModel model)
|
||||
{
|
||||
|
@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
|
||||
public class OrganizationVerifyDeleteRecoverRequestModel
|
||||
{
|
||||
[Required]
|
||||
public string Token { get; set; }
|
||||
}
|
Reference in New Issue
Block a user