Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PM-7004] Org Admin Initiate Delete #3905

Merged
merged 28 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3f967e7
org delete
kspearrin Mar 15, 2024
877ad24
Merge branch 'main' into orgdelete
kspearrin Mar 15, 2024
c31a35c
move org id to URL path
kspearrin Mar 22, 2024
9ab2986
tweaks
kspearrin Mar 22, 2024
b86484f
Merge branch 'main' into orgdelete
kspearrin Mar 22, 2024
e636056
lint fixes
kspearrin Mar 22, 2024
1cc554b
Merge branch 'orgdelete' of github.com:bitwarden/server into orgdelete
kspearrin Mar 22, 2024
8bd450e
Update src/Core/Services/Implementations/HandlebarsMailService.cs
kspearrin Mar 29, 2024
fae1138
Update src/Core/Services/Implementations/HandlebarsMailService.cs
kspearrin Mar 29, 2024
fcc69a7
Apply suggestions from code review
kspearrin Mar 29, 2024
2817802
Apply suggestions from code review
kspearrin Apr 1, 2024
be95456
PR feedback
kspearrin Apr 1, 2024
2014bf9
fix id
kspearrin Apr 9, 2024
2f3e3cd
Merge branch 'main' into orgdelete
kspearrin Apr 9, 2024
03e6a03
[PM-7004] Move OrgDeleteTokenable to AdminConsole ownership
r-tome Apr 23, 2024
0a7ea40
Merge branch 'main' into orgdelete
r-tome Apr 23, 2024
5edecc4
[PM-7004] Add consolidated billing logic into organization delete req…
r-tome Apr 24, 2024
cb0eba4
[PM-7004] Delete unused IOrganizationService.DeleteAsync(Organization…
r-tome Apr 24, 2024
84c2782
[PM-7004] Fix unit tests
r-tome Apr 24, 2024
5c12bc1
[PM-7004] Update delete organization request email templates
r-tome Apr 25, 2024
404f306
Merge branch 'main' into orgdelete
r-tome May 8, 2024
aa7e748
Merge branch 'main' into orgdelete
r-tome May 16, 2024
95fe9c0
Add success message when initiating organization deletion
r-tome May 17, 2024
1a0ce74
Merge branch 'main' into orgdelete
r-tome May 17, 2024
e4a4da0
Refactor OrganizationsController request delete initiation action to …
r-tome May 17, 2024
74ac919
Merge branch 'main' into orgdelete
r-tome May 17, 2024
ff9ef05
Merge branch 'main' into orgdelete
r-tome May 22, 2024
460a1b0
Merge branch 'main' into orgdelete
r-tome May 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/Admin/AdminConsole/Controllers/OrganizationsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,25 @@
return RedirectToAction("Index");
}

[HttpPost]
[ValidateAntiForgeryToken]
[RequirePermission(Permission.Org_Delete)]
public async Task<IActionResult> DeleteInitiation(Guid id, OrganizationInitiateDeleteModel model)
{

Check warning on line 276 in src/Admin/AdminConsole/Controllers/OrganizationsController.cs

View check run for this annotation

Codecov / codecov/patch

src/Admin/AdminConsole/Controllers/OrganizationsController.cs#L276

Added line #L276 was not covered by tests
if (!ModelState.IsValid)
{
return RedirectToAction("Edit", new { id });

Check warning on line 279 in src/Admin/AdminConsole/Controllers/OrganizationsController.cs

View check run for this annotation

Codecov / codecov/patch

src/Admin/AdminConsole/Controllers/OrganizationsController.cs#L278-L279

Added lines #L278 - L279 were not covered by tests
}

var organization = await _organizationRepository.GetByIdAsync(id);

Check warning on line 282 in src/Admin/AdminConsole/Controllers/OrganizationsController.cs

View check run for this annotation

Codecov / codecov/patch

src/Admin/AdminConsole/Controllers/OrganizationsController.cs#L282

Added line #L282 was not covered by tests
kspearrin marked this conversation as resolved.
Show resolved Hide resolved
if (organization != null)
{
await _organizationService.InitiateDeleteAsync(organization, model.AdminEmail);
}

Check warning on line 286 in src/Admin/AdminConsole/Controllers/OrganizationsController.cs

View check run for this annotation

Codecov / codecov/patch

src/Admin/AdminConsole/Controllers/OrganizationsController.cs#L284-L286

Added lines #L284 - L286 were not covered by tests

return RedirectToAction("Edit", new { id });
}

Check warning on line 289 in src/Admin/AdminConsole/Controllers/OrganizationsController.cs

View check run for this annotation

Codecov / codecov/patch

src/Admin/AdminConsole/Controllers/OrganizationsController.cs#L288-L289

Added lines #L288 - L289 were not covered by tests

public async Task<IActionResult> TriggerBillingSync(Guid id)
{
var organization = await _organizationRepository.GetByIdAsync(id);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations;

namespace Bit.Admin.AdminConsole.Models;

public class OrganizationInitiateDeleteModel
{
[Required]
[EmailAddress]
[StringLength(256)]
[Display(Name = "Admin Email")]
kspearrin marked this conversation as resolved.
Show resolved Hide resolved
public string AdminEmail { get; set; }

Check warning on line 11 in src/Admin/AdminConsole/Models/OrganizationInitiateDeleteModel.cs

View check run for this annotation

Codecov / codecov/patch

src/Admin/AdminConsole/Models/OrganizationInitiateDeleteModel.cs#L11

Added line #L11 was not covered by tests
}
73 changes: 47 additions & 26 deletions src/Admin/AdminConsole/Views/Organizations/Edit.cshtml
r-tome marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@using Bit.Admin.Enums;
@using Bit.Admin.Enums;
@using Bit.Admin.Models
@using Bit.Core.Enums
@inject Bit.Admin.Services.IAccessControlService AccessControlService
Expand All @@ -18,24 +18,43 @@

<script>
(() => {
document.getElementById('teams-trial').addEventListener('click', () => {
if (document.getElementById('@(nameof(Model.PlanType))').value !== '@((byte)PlanType.Free)') {
alert('Organization is not on a free plan.');
return;
}
setTrialDefaults('@((byte)PlanType.TeamsAnnually)');
togglePlanFeatures('@((byte)PlanType.TeamsAnnually)');
document.getElementById('@(nameof(Model.Plan))').value = 'Teams (Trial)';
});
document.getElementById('enterprise-trial').addEventListener('click', () => {
if (document.getElementById('@(nameof(Model.PlanType))').value !== '@((byte)PlanType.Free)') {
alert('Organization is not on a free plan.');
return;
}
setTrialDefaults('@((byte)PlanType.EnterpriseAnnually)');
togglePlanFeatures('@((byte)PlanType.EnterpriseAnnually)');
document.getElementById('@(nameof(Model.Plan))').value = 'Enterprise (Trial)';
});
const treamsTrialButton = document.getElementById('teams-trial');
if (treamsTrialButton != null) {
treamsTrialButton.addEventListener('click', () => {
if (document.getElementById('@(nameof(Model.PlanType))').value !== '@((byte)PlanType.Free)') {

Check warning on line 24 in src/Admin/AdminConsole/Views/Organizations/Edit.cshtml

View check run for this annotation

Codecov / codecov/patch

src/Admin/AdminConsole/Views/Organizations/Edit.cshtml#L24

Added line #L24 was not covered by tests
alert('Organization is not on a free plan.');
return;
}
setTrialDefaults('@((byte)PlanType.TeamsAnnually)');
togglePlanFeatures('@((byte)PlanType.TeamsAnnually)');
document.getElementById('@(nameof(Model.Plan))').value = 'Teams (Trial)';

Check warning on line 30 in src/Admin/AdminConsole/Views/Organizations/Edit.cshtml

View check run for this annotation

Codecov / codecov/patch

src/Admin/AdminConsole/Views/Organizations/Edit.cshtml#L28-L30

Added lines #L28 - L30 were not covered by tests
});
}

const entTrialButton = document.getElementById('enterprise-trial');
if (entTrialButton != null) {
entTrialButton.addEventListener('click', () => {
if (document.getElementById('@(nameof(Model.PlanType))').value !== '@((byte)PlanType.Free)') {

Check warning on line 37 in src/Admin/AdminConsole/Views/Organizations/Edit.cshtml

View check run for this annotation

Codecov / codecov/patch

src/Admin/AdminConsole/Views/Organizations/Edit.cshtml#L37

Added line #L37 was not covered by tests
alert('Organization is not on a free plan.');
return;
}
setTrialDefaults('@((byte)PlanType.EnterpriseAnnually)');
togglePlanFeatures('@((byte)PlanType.EnterpriseAnnually)');
document.getElementById('@(nameof(Model.Plan))').value = 'Enterprise (Trial)';

Check warning on line 43 in src/Admin/AdminConsole/Views/Organizations/Edit.cshtml

View check run for this annotation

Codecov / codecov/patch

src/Admin/AdminConsole/Views/Organizations/Edit.cshtml#L41-L43

Added lines #L41 - L43 were not covered by tests
});
}

const initDeleteButton = document.getElementById('initiate-delete-form');
if (initDeleteButton != null) {
initDeleteButton.addEventListener('submit', (e) => {
const email = prompt('Enter the email address of the owner/admin that your want to ' +
'request the organization delete verification process with.');
document.getElementById('AdminEmail').value = email;
if (email == null || email === '') {
e.preventDefault();
}
});
}

function setTrialDefaults(planType) {
// Plan
Expand Down Expand Up @@ -76,7 +95,7 @@
{
<h2>Billing Information</h2>
@await Html.PartialAsync("_BillingInformation",
new BillingInformationModel { BillingInfo = Model.BillingInfo, OrganizationId = Model.Organization.Id, Entity = "Organization" })
new BillingInformationModel { BillingInfo = Model.BillingInfo, OrganizationId = Model.Organization.Id, Entity = "Organization" })

Check warning on line 98 in src/Admin/AdminConsole/Views/Organizations/Edit.cshtml

View check run for this annotation

Codecov / codecov/patch

src/Admin/AdminConsole/Views/Organizations/Edit.cshtml#L98

Added line #L98 was not covered by tests
}

@await Html.PartialAsync("~/AdminConsole/Views/Shared/_OrganizationForm.cshtml", Model)
Expand All @@ -95,18 +114,20 @@
}
@if (canUnlinkFromProvider && Model.Provider is not null)
{
<button
class="btn btn-outline-danger mr-2"
onclick="return unlinkProvider('@Model.Organization.Id');"
>
<button class="btn btn-outline-danger mr-2"
onclick="return unlinkProvider('@Model.Organization.Id');">

Check warning on line 118 in src/Admin/AdminConsole/Views/Organizations/Edit.cshtml

View check run for this annotation

Codecov / codecov/patch

src/Admin/AdminConsole/Views/Organizations/Edit.cshtml#L118

Added line #L118 was not covered by tests
Unlink provider
</button>
}
@if (canDelete)
{
<form asp-action="DeleteInitiation" asp-route-id="@Model.Organization.Id" id="initiate-delete-form">
<input type="hidden" name="AdminEmail" id="AdminEmail" />
<button class="btn btn-danger mr-2" type="submit">Request Delete</button>
</form>
<form asp-action="Delete" asp-route-id="@Model.Organization.Id"
onsubmit="return confirm('Are you sure you want to delete this organization?')">
<button class="btn btn-danger" type="submit">Delete</button>
onsubmit="return confirm('Are you sure you want to hard delete this organization?')">
<button class="btn btn-outline-danger" type="submit">Delete</button>
</form>
}
</div>
Expand Down
38 changes: 37 additions & 1 deletion src/Api/AdminConsole/Controllers/OrganizationsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
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;
Expand All @@ -32,6 +33,7 @@
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings;
using Bit.Core.Tokens;
using Bit.Core.Tools.Enums;
using Bit.Core.Tools.Models.Business;
using Bit.Core.Tools.Services;
Expand Down Expand Up @@ -72,6 +74,7 @@
private readonly IOrganizationEnableCollectionEnhancementsCommand _organizationEnableCollectionEnhancementsCommand;
private readonly IProviderRepository _providerRepository;
private readonly IScaleSeatsCommand _scaleSeatsCommand;
private readonly IDataProtectorTokenFactory<OrgDeleteTokenable> _orgDeleteTokenDataFactory;

public OrganizationsController(
IOrganizationRepository organizationRepository,
Expand Down Expand Up @@ -100,7 +103,8 @@
IReferenceEventService referenceEventService,
IOrganizationEnableCollectionEnhancementsCommand organizationEnableCollectionEnhancementsCommand,
IProviderRepository providerRepository,
IScaleSeatsCommand scaleSeatsCommand)
IScaleSeatsCommand scaleSeatsCommand,
IDataProtectorTokenFactory<OrgDeleteTokenable> orgDeleteTokenDataFactory)
{
_organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository;
Expand Down Expand Up @@ -129,6 +133,7 @@
_organizationEnableCollectionEnhancementsCommand = organizationEnableCollectionEnhancementsCommand;
_providerRepository = providerRepository;
_scaleSeatsCommand = scaleSeatsCommand;
_orgDeleteTokenDataFactory = orgDeleteTokenDataFactory;
}

[HttpGet("{id}")]
Expand Down Expand Up @@ -586,6 +591,37 @@
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);

Check warning on line 598 in src/Api/AdminConsole/Controllers/OrganizationsController.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/AdminConsole/Controllers/OrganizationsController.cs#L597-L598

Added lines #L597 - L598 were not covered by tests
if (organization == null)
{
throw new NotFoundException();

Check warning on line 601 in src/Api/AdminConsole/Controllers/OrganizationsController.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/AdminConsole/Controllers/OrganizationsController.cs#L600-L601

Added lines #L600 - L601 were not covered by tests
}

if (!_orgDeleteTokenDataFactory.TryUnprotect(model.Token, out var data) || !data.IsValid(organization))
{
throw new BadRequestException("Invalid token.");

Check warning on line 606 in src/Api/AdminConsole/Controllers/OrganizationsController.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/AdminConsole/Controllers/OrganizationsController.cs#L605-L606

Added lines #L605 - L606 were not covered by tests
}

var consolidatedBillingEnabled = _featureService.IsEnabled(FeatureFlagKeys.EnableConsolidatedBilling);

Check warning on line 609 in src/Api/AdminConsole/Controllers/OrganizationsController.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/AdminConsole/Controllers/OrganizationsController.cs#L609

Added line #L609 was not covered by tests
if (consolidatedBillingEnabled && organization.IsValidClient())
{
var provider = await _providerRepository.GetByOrganizationIdAsync(organization.Id);

Check warning on line 612 in src/Api/AdminConsole/Controllers/OrganizationsController.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/AdminConsole/Controllers/OrganizationsController.cs#L611-L612

Added lines #L611 - L612 were not covered by tests
if (provider.IsBillable())
{

Check warning on line 614 in src/Api/AdminConsole/Controllers/OrganizationsController.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/AdminConsole/Controllers/OrganizationsController.cs#L614

Added line #L614 was not covered by tests
await _scaleSeatsCommand.ScalePasswordManagerSeats(
provider,
organization.PlanType,
-organization.Seats ?? 0);
}
}

Check warning on line 620 in src/Api/AdminConsole/Controllers/OrganizationsController.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/AdminConsole/Controllers/OrganizationsController.cs#L616-L620

Added lines #L616 - L620 were not covered by tests

await _organizationService.DeleteAsync(organization);
}

Check warning on line 623 in src/Api/AdminConsole/Controllers/OrganizationsController.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/AdminConsole/Controllers/OrganizationsController.cs#L622-L623

Added lines #L622 - L623 were not covered by tests

[HttpPost("{id}/import")]
public async Task Import(string id, [FromBody] ImportOrganizationUsersRequestModel model)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.ComponentModel.DataAnnotations;

namespace Bit.Api.AdminConsole.Models.Request.Organizations;

public class OrganizationVerifyDeleteRecoverRequestModel
{
[Required]
public string Token { get; set; }

Check warning on line 8 in src/Api/AdminConsole/Models/Request/Organizations/OrganizationVerifyDeleteRecoverRequestModel.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/AdminConsole/Models/Request/Organizations/OrganizationVerifyDeleteRecoverRequestModel.cs#L8

Added line #L8 was not covered by tests
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Text.Json.Serialization;
using Bit.Core.AdminConsole.Entities;

namespace Bit.Core.AdminConsole.Models.Business.Tokenables;

public class OrgDeleteTokenable : Tokens.ExpiringTokenable
{
public const string ClearTextPrefix = "";
public const string DataProtectorPurpose = "OrgDeleteDataProtector";
public const string TokenIdentifier = "OrgDelete";
public string Identifier { get; set; } = TokenIdentifier;
public Guid Id { get; set; }

Check warning on line 12 in src/Core/AdminConsole/Models/Business/Tokenables/OrgDeleteTokenable.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/AdminConsole/Models/Business/Tokenables/OrgDeleteTokenable.cs#L11-L12

Added lines #L11 - L12 were not covered by tests

[JsonConstructor]
public OrgDeleteTokenable(DateTime expirationDate)
{
ExpirationDate = expirationDate;
}

Check warning on line 18 in src/Core/AdminConsole/Models/Business/Tokenables/OrgDeleteTokenable.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/AdminConsole/Models/Business/Tokenables/OrgDeleteTokenable.cs#L15-L18

Added lines #L15 - L18 were not covered by tests

public OrgDeleteTokenable(Organization organization, int hoursTillExpiration)
{
Id = organization.Id;
ExpirationDate = DateTime.UtcNow.AddHours(hoursTillExpiration);
}

Check warning on line 24 in src/Core/AdminConsole/Models/Business/Tokenables/OrgDeleteTokenable.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/AdminConsole/Models/Business/Tokenables/OrgDeleteTokenable.cs#L20-L24

Added lines #L20 - L24 were not covered by tests

public bool IsValid(Organization organization)
{
return Id == organization.Id;
}

Check warning on line 29 in src/Core/AdminConsole/Models/Business/Tokenables/OrgDeleteTokenable.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/AdminConsole/Models/Business/Tokenables/OrgDeleteTokenable.cs#L27-L29

Added lines #L27 - L29 were not covered by tests

protected override bool TokenIsValid() => Identifier == TokenIdentifier && Id != default;
}
1 change: 1 addition & 0 deletions src/Core/AdminConsole/Services/IOrganizationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public interface IOrganizationService
/// </summary>
Task<(Organization organization, OrganizationUser organizationUser)> SignUpAsync(OrganizationLicense license, User owner,
string ownerKey, string collectionName, string publicKey, string privateKey);
Task InitiateDeleteAsync(Organization organization, string orgAdminEmail);
Task DeleteAsync(Organization organization);
Task EnableAsync(Guid organizationId, DateTime? expirationDate);
Task DisableAsync(Guid organizationId, DateTime? expirationDate);
Expand Down
kspearrin marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Enums.Provider;
using Bit.Core.AdminConsole.Models.Business;
using Bit.Core.AdminConsole.Models.Business.Tokenables;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.AdminConsole.Repositories;
Expand Down Expand Up @@ -60,6 +61,7 @@
private readonly IProviderUserRepository _providerUserRepository;
private readonly ICountNewSmSeatsRequiredQuery _countNewSmSeatsRequiredQuery;
private readonly IUpdateSecretsManagerSubscriptionCommand _updateSecretsManagerSubscriptionCommand;
private readonly IDataProtectorTokenFactory<OrgDeleteTokenable> _orgDeleteTokenDataFactory;
private readonly IProviderRepository _providerRepository;
private readonly IOrgUserInviteTokenableFactory _orgUserInviteTokenableFactory;
private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory;
Expand Down Expand Up @@ -94,6 +96,7 @@
IOrgUserInviteTokenableFactory orgUserInviteTokenableFactory,
IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory,
IUpdateSecretsManagerSubscriptionCommand updateSecretsManagerSubscriptionCommand,
IDataProtectorTokenFactory<OrgDeleteTokenable> orgDeleteTokenDataFactory,
IProviderRepository providerRepository,
IFeatureService featureService)
{
Expand Down Expand Up @@ -123,6 +126,7 @@
_providerUserRepository = providerUserRepository;
_countNewSmSeatsRequiredQuery = countNewSmSeatsRequiredQuery;
_updateSecretsManagerSubscriptionCommand = updateSecretsManagerSubscriptionCommand;
_orgDeleteTokenDataFactory = orgDeleteTokenDataFactory;
_providerRepository = providerRepository;
_orgUserInviteTokenableFactory = orgUserInviteTokenableFactory;
_orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory;
Expand Down Expand Up @@ -811,6 +815,23 @@
}
}

public async Task InitiateDeleteAsync(Organization organization, string orgAdminEmail)
{
var orgAdmin = await _userRepository.GetByEmailAsync(orgAdminEmail);

Check warning on line 820 in src/Core/AdminConsole/Services/Implementations/OrganizationService.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/AdminConsole/Services/Implementations/OrganizationService.cs#L819-L820

Added lines #L819 - L820 were not covered by tests
if (orgAdmin == null)
{
throw new BadRequestException("Org admin not found.");

Check warning on line 823 in src/Core/AdminConsole/Services/Implementations/OrganizationService.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/AdminConsole/Services/Implementations/OrganizationService.cs#L822-L823

Added lines #L822 - L823 were not covered by tests
}
var orgAdminOrgUser = await _organizationUserRepository.GetDetailsByUserAsync(orgAdmin.Id, organization.Id);

Check warning on line 825 in src/Core/AdminConsole/Services/Implementations/OrganizationService.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/AdminConsole/Services/Implementations/OrganizationService.cs#L825

Added line #L825 was not covered by tests
if (orgAdminOrgUser == null || orgAdminOrgUser.Status != OrganizationUserStatusType.Confirmed ||
(orgAdminOrgUser.Type != OrganizationUserType.Admin && orgAdminOrgUser.Type != OrganizationUserType.Owner))
kspearrin marked this conversation as resolved.
Show resolved Hide resolved
{
throw new BadRequestException("Org admin not found.");

Check warning on line 829 in src/Core/AdminConsole/Services/Implementations/OrganizationService.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/AdminConsole/Services/Implementations/OrganizationService.cs#L827-L829

Added lines #L827 - L829 were not covered by tests
}
var token = _orgDeleteTokenDataFactory.Protect(new OrgDeleteTokenable(organization, 1));
await _mailService.SendInitiateDeleteOrganzationEmailAsync(orgAdminEmail, organization, token);
}

Check warning on line 833 in src/Core/AdminConsole/Services/Implementations/OrganizationService.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/AdminConsole/Services/Implementations/OrganizationService.cs#L831-L833

Added lines #L831 - L833 were not covered by tests

public async Task DeleteAsync(Organization organization)
{
await ValidateDeleteOrganizationAsync(organization);
Expand Down