-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Expand file tree
/
Copy pathOrganizationDeleteCommand.cs
More file actions
123 lines (114 loc) · 5.08 KB
/
OrganizationDeleteCommand.cs
File metadata and controls
123 lines (114 loc) · 5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
using System.Text.Json;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Repositories;
using Bit.Core.Billing;
using Bit.Core.Billing.Services;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Tools.Enums;
using Bit.Core.Tools.Models.Data;
using Bit.Core.Tools.Repositories;
using Bit.Core.Tools.Services;
using Bit.Core.Vault.Services;
using Microsoft.Extensions.Logging;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
public class OrganizationDeleteCommand : IOrganizationDeleteCommand
{
private readonly IApplicationCacheService _applicationCacheService;
private readonly IOrganizationRepository _organizationRepository;
private readonly IStripePaymentService _paymentService;
private readonly ISsoConfigRepository _ssoConfigRepository;
private readonly ICipherService _cipherService;
private readonly ISubscriberService _subscriberService;
private readonly IFeatureService _featureService;
private readonly ISendRepository _sendRepository;
private readonly ISendFileStorageService _sendFileStorageService;
private readonly ILogger<OrganizationDeleteCommand> _logger;
public OrganizationDeleteCommand(
IApplicationCacheService applicationCacheService,
IOrganizationRepository organizationRepository,
IStripePaymentService paymentService,
ISsoConfigRepository ssoConfigRepository,
ICipherService cipherService,
ISubscriberService subscriberService,
IFeatureService featureService,
ISendRepository sendRepository,
ISendFileStorageService sendFileStorageService,
ILogger<OrganizationDeleteCommand> logger)
{
_applicationCacheService = applicationCacheService;
_organizationRepository = organizationRepository;
_paymentService = paymentService;
_ssoConfigRepository = ssoConfigRepository;
_cipherService = cipherService;
_subscriberService = subscriberService;
_featureService = featureService;
_sendRepository = sendRepository;
_sendFileStorageService = sendFileStorageService;
_logger = logger;
}
public async Task DeleteAsync(Organization organization)
{
await ValidateDeleteOrganizationAsync(organization);
if (!string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId))
{
try
{
var eop = !organization.ExpirationDate.HasValue ||
organization.ExpirationDate.Value >= DateTime.UtcNow;
if (_featureService.IsEnabled(FeatureFlagKeys.PM32645_DeferPriceMigrationToRenewal))
{
// In cases where the subscription is not active, the cancellation will fail and be logged.
await _subscriberService.CancelSubscription(organization, cancelImmediately: !eop);
}
else
{
await _paymentService.CancelSubscriptionAsync(organization, eop);
}
}
catch (Exception exception) when (exception is GatewayException or BillingException)
{
_logger.LogWarning(exception, "Failed to cancel subscription for organization {OrganizationId}", organization.Id);
}
}
await DeleteOrganizationOwnedSendFilesAsync(organization);
await _cipherService.DeleteAttachmentsForOrganizationAsync(organization.Id);
await _organizationRepository.DeleteAsync(organization);
await _applicationCacheService.DeleteOrganizationAbilityAsync(organization.Id);
}
private async Task ValidateDeleteOrganizationAsync(Organization organization)
{
var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(organization.Id);
if (ssoConfig?.GetData()?.MemberDecryptionType == MemberDecryptionType.KeyConnector)
{
throw new BadRequestException("You cannot delete an Organization that is using Key Connector.");
}
}
/// <summary>
/// Deletes Send files from storage. Send objects are deleted via
/// IOrganizationRepository.DeleteAsync.
/// </summary>
/// <param name="organization">The organization whose Send files will be deleted.</param>
private async Task DeleteOrganizationOwnedSendFilesAsync(Organization organization)
{
var sends = await _sendRepository.GetManyByOrganizationIdAsync(organization.Id);
foreach (var send in sends.Where(s => s.Type == SendType.File))
{
try
{
var data = send.Data != null ? JsonSerializer.Deserialize<SendFileData>(send.Data) : null;
if (data?.Id != null)
{
await _sendFileStorageService.DeleteFileAsync(send, data.Id);
}
}
catch (JsonException ex)
{
_logger.LogWarning(ex, "Failed to deserialize Send {SendId} data; blob may be orphaned.", send.Id);
}
}
}
}