From 9b9318caac66aca26e3c1ec9d2a462fe3429b7b6 Mon Sep 17 00:00:00 2001 From: Alex Morask <144709477+amorask-bitwarden@users.noreply.github.com> Date: Tue, 14 May 2024 09:16:24 -0400 Subject: [PATCH] [AC-2313] Add Gateway fields to Provider edit in Admin (#4057) * Formatting * Add Gateway fields to provider edit * Remove unnecessary usings * Thomas' feedback * Removing unnecessary using for linter * Removing unused file * Removing unused file --- .../Providers/CreateProviderCommand.cs | 9 +- .../Controllers/ProvidersController.cs | 39 ++-- .../Models/CreateProviderModel.cs | 16 +- .../AdminConsole/Models/ProviderEditModel.cs | 61 +++-- .../Views/Providers/Create.cshtml | 8 +- .../AdminConsole/Views/Providers/Edit.cshtml | 209 +++++++++++------- 6 files changed, 196 insertions(+), 146 deletions(-) diff --git a/bitwarden_license/src/Commercial.Core/AdminConsole/Providers/CreateProviderCommand.cs b/bitwarden_license/src/Commercial.Core/AdminConsole/Providers/CreateProviderCommand.cs index 1f96202d86..16d62d69c3 100644 --- a/bitwarden_license/src/Commercial.Core/AdminConsole/Providers/CreateProviderCommand.cs +++ b/bitwarden_license/src/Commercial.Core/AdminConsole/Providers/CreateProviderCommand.cs @@ -46,6 +46,13 @@ public class CreateProviderCommand : ICreateProviderCommand throw new BadRequestException("Invalid owner. Owner must be an existing Bitwarden user."); } + var isConsolidatedBillingEnabled = _featureService.IsEnabled(FeatureFlagKeys.EnableConsolidatedBilling); + + if (isConsolidatedBillingEnabled) + { + provider.Gateway = GatewayType.Stripe; + } + await ProviderRepositoryCreateAsync(provider, ProviderStatusType.Pending); var providerUser = new ProviderUser @@ -56,8 +63,6 @@ public class CreateProviderCommand : ICreateProviderCommand Status = ProviderUserStatusType.Confirmed, }; - var isConsolidatedBillingEnabled = _featureService.IsEnabled(FeatureFlagKeys.EnableConsolidatedBilling); - if (isConsolidatedBillingEnabled) { var providerPlans = new List diff --git a/src/Admin/AdminConsole/Controllers/ProvidersController.cs b/src/Admin/AdminConsole/Controllers/ProvidersController.cs index 0d3f7f996a..d58d132bbc 100644 --- a/src/Admin/AdminConsole/Controllers/ProvidersController.cs +++ b/src/Admin/AdminConsole/Controllers/ProvidersController.cs @@ -17,7 +17,6 @@ using Bit.Core.Exceptions; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Core.Settings; -using Bit.Core.Tools.Services; using Bit.Core.Utilities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -36,7 +35,6 @@ public class ProvidersController : Controller private readonly GlobalSettings _globalSettings; private readonly IApplicationCacheService _applicationCacheService; private readonly IProviderService _providerService; - private readonly IReferenceEventService _referenceEventService; private readonly IUserService _userService; private readonly ICreateProviderCommand _createProviderCommand; private readonly IFeatureService _featureService; @@ -51,7 +49,6 @@ public class ProvidersController : Controller IProviderService providerService, GlobalSettings globalSettings, IApplicationCacheService applicationCacheService, - IReferenceEventService referenceEventService, IUserService userService, ICreateProviderCommand createProviderCommand, IFeatureService featureService, @@ -65,7 +62,6 @@ public class ProvidersController : Controller _providerService = providerService; _globalSettings = globalSettings; _applicationCacheService = applicationCacheService; - _referenceEventService = referenceEventService; _userService = userService; _createProviderCommand = createProviderCommand; _featureService = featureService; @@ -104,8 +100,8 @@ public class ProvidersController : Controller return View(new CreateProviderModel { OwnerEmail = ownerEmail, - TeamsMinimumSeats = teamsMinimumSeats, - EnterpriseMinimumSeats = enterpriseMinimumSeats + TeamsMonthlySeatMinimum = teamsMinimumSeats, + EnterpriseMonthlySeatMinimum = enterpriseMinimumSeats }); } @@ -123,8 +119,11 @@ public class ProvidersController : Controller switch (provider.Type) { case ProviderType.Msp: - await _createProviderCommand.CreateMspAsync(provider, model.OwnerEmail, model.TeamsMinimumSeats, - model.EnterpriseMinimumSeats); + await _createProviderCommand.CreateMspAsync( + provider, + model.OwnerEmail, + model.TeamsMonthlySeatMinimum, + model.EnterpriseMonthlySeatMinimum); break; case ProviderType.Reseller: await _createProviderCommand.CreateResellerAsync(provider); @@ -167,8 +166,9 @@ public class ProvidersController : Controller return View(new ProviderEditModel(provider, users, providerOrganizations, new List())); } - var providerPlan = await _providerPlanRepository.GetByProviderId(id); - return View(new ProviderEditModel(provider, users, providerOrganizations, providerPlan)); + var providerPlans = await _providerPlanRepository.GetByProviderId(id); + + return View(new ProviderEditModel(provider, users, providerOrganizations, providerPlans.ToList())); } [HttpPost] @@ -177,14 +177,15 @@ public class ProvidersController : Controller [RequirePermission(Permission.Provider_Edit)] public async Task Edit(Guid id, ProviderEditModel model) { - var providerPlans = await _providerPlanRepository.GetByProviderId(id); var provider = await _providerRepository.GetByIdAsync(id); + if (provider == null) { return RedirectToAction("Index"); } model.ToProvider(provider); + await _providerRepository.ReplaceAsync(provider); await _applicationCacheService.UpsertProviderAbilityAsync(provider); @@ -195,13 +196,14 @@ public class ProvidersController : Controller return RedirectToAction("Edit", new { id }); } - model.ToProviderPlan(providerPlans); + var providerPlans = await _providerPlanRepository.GetByProviderId(id); + if (providerPlans.Count == 0) { var newProviderPlans = new List { - new() {ProviderId = provider.Id, PlanType = PlanType.TeamsMonthly, SeatMinimum= model.TeamsMinimumSeats, PurchasedSeats = 0, AllocatedSeats = 0}, - new() {ProviderId = provider.Id, PlanType = PlanType.EnterpriseMonthly, SeatMinimum= model.EnterpriseMinimumSeats, PurchasedSeats = 0, AllocatedSeats = 0} + new () { ProviderId = provider.Id, PlanType = PlanType.TeamsMonthly, SeatMinimum = model.TeamsMonthlySeatMinimum, PurchasedSeats = 0, AllocatedSeats = 0 }, + new () { ProviderId = provider.Id, PlanType = PlanType.EnterpriseMonthly, SeatMinimum = model.EnterpriseMonthlySeatMinimum, PurchasedSeats = 0, AllocatedSeats = 0 } }; foreach (var newProviderPlan in newProviderPlans) @@ -213,6 +215,15 @@ public class ProvidersController : Controller { foreach (var providerPlan in providerPlans) { + if (providerPlan.PlanType == PlanType.EnterpriseMonthly) + { + providerPlan.SeatMinimum = model.EnterpriseMonthlySeatMinimum; + } + else if (providerPlan.PlanType == PlanType.TeamsMonthly) + { + providerPlan.SeatMinimum = model.TeamsMonthlySeatMinimum; + } + await _providerPlanRepository.ReplaceAsync(providerPlan); } } diff --git a/src/Admin/AdminConsole/Models/CreateProviderModel.cs b/src/Admin/AdminConsole/Models/CreateProviderModel.cs index 2efbbb54f6..07bb1b6e4c 100644 --- a/src/Admin/AdminConsole/Models/CreateProviderModel.cs +++ b/src/Admin/AdminConsole/Models/CreateProviderModel.cs @@ -24,11 +24,11 @@ public class CreateProviderModel : IValidatableObject [Display(Name = "Primary Billing Email")] public string BillingEmail { get; set; } - [Display(Name = "Teams minimum seats")] - public int TeamsMinimumSeats { get; set; } + [Display(Name = "Teams (Monthly) Seat Minimum")] + public int TeamsMonthlySeatMinimum { get; set; } - [Display(Name = "Enterprise minimum seats")] - public int EnterpriseMinimumSeats { get; set; } + [Display(Name = "Enterprise (Monthly) Seat Minimum")] + public int EnterpriseMonthlySeatMinimum { get; set; } public virtual Provider ToProvider() { @@ -51,14 +51,14 @@ public class CreateProviderModel : IValidatableObject var ownerEmailDisplayName = nameof(OwnerEmail).GetDisplayAttribute()?.GetName() ?? nameof(OwnerEmail); yield return new ValidationResult($"The {ownerEmailDisplayName} field is required."); } - if (TeamsMinimumSeats < 0) + if (TeamsMonthlySeatMinimum < 0) { - var teamsMinimumSeatsDisplayName = nameof(TeamsMinimumSeats).GetDisplayAttribute()?.GetName() ?? nameof(TeamsMinimumSeats); + var teamsMinimumSeatsDisplayName = nameof(TeamsMonthlySeatMinimum).GetDisplayAttribute()?.GetName() ?? nameof(TeamsMonthlySeatMinimum); yield return new ValidationResult($"The {teamsMinimumSeatsDisplayName} field can not be negative."); } - if (EnterpriseMinimumSeats < 0) + if (EnterpriseMonthlySeatMinimum < 0) { - var enterpriseMinimumSeatsDisplayName = nameof(EnterpriseMinimumSeats).GetDisplayAttribute()?.GetName() ?? nameof(EnterpriseMinimumSeats); + var enterpriseMinimumSeatsDisplayName = nameof(EnterpriseMonthlySeatMinimum).GetDisplayAttribute()?.GetName() ?? nameof(EnterpriseMonthlySeatMinimum); yield return new ValidationResult($"The {enterpriseMinimumSeatsDisplayName} field can not be negative."); } break; diff --git a/src/Admin/AdminConsole/Models/ProviderEditModel.cs b/src/Admin/AdminConsole/Models/ProviderEditModel.cs index 1055d0cba4..078731aaa7 100644 --- a/src/Admin/AdminConsole/Models/ProviderEditModel.cs +++ b/src/Admin/AdminConsole/Models/ProviderEditModel.cs @@ -10,16 +10,21 @@ public class ProviderEditModel : ProviderViewModel { public ProviderEditModel() { } - public ProviderEditModel(Provider provider, IEnumerable providerUsers, - IEnumerable organizations, IEnumerable providerPlans) - : base(provider, providerUsers, organizations) + public ProviderEditModel( + Provider provider, + IEnumerable providerUsers, + IEnumerable organizations, + IReadOnlyCollection providerPlans) : base(provider, providerUsers, organizations) { Name = provider.DisplayName(); BusinessName = provider.DisplayBusinessName(); BillingEmail = provider.BillingEmail; BillingPhone = provider.BillingPhone; - TeamsMinimumSeats = GetMinimumSeats(providerPlans, PlanType.TeamsMonthly); - EnterpriseMinimumSeats = GetMinimumSeats(providerPlans, PlanType.EnterpriseMonthly); + TeamsMonthlySeatMinimum = GetSeatMinimum(providerPlans, PlanType.TeamsMonthly); + EnterpriseMonthlySeatMinimum = GetSeatMinimum(providerPlans, PlanType.EnterpriseMonthly); + Gateway = provider.Gateway; + GatewayCustomerId = provider.GatewayCustomerId; + GatewaySubscriptionId = provider.GatewaySubscriptionId; } [Display(Name = "Billing Email")] @@ -29,38 +34,28 @@ public class ProviderEditModel : ProviderViewModel [Display(Name = "Business Name")] public string BusinessName { get; set; } public string Name { get; set; } - [Display(Name = "Teams minimum seats")] - public int TeamsMinimumSeats { get; set; } + [Display(Name = "Teams (Monthly) Seat Minimum")] + public int TeamsMonthlySeatMinimum { get; set; } - [Display(Name = "Enterprise minimum seats")] - public int EnterpriseMinimumSeats { get; set; } - [Display(Name = "Events")] + [Display(Name = "Enterprise (Monthly) Seat Minimum")] + public int EnterpriseMonthlySeatMinimum { get; set; } + [Display(Name = "Gateway")] + public GatewayType? Gateway { get; set; } + [Display(Name = "Gateway Customer Id")] + public string GatewayCustomerId { get; set; } + [Display(Name = "Gateway Subscription Id")] + public string GatewaySubscriptionId { get; set; } - public IEnumerable ToProviderPlan(IEnumerable existingProviderPlans) + public virtual Provider ToProvider(Provider existingProvider) { - var providerPlans = existingProviderPlans.ToList(); - foreach (var existingProviderPlan in providerPlans) - { - existingProviderPlan.SeatMinimum = existingProviderPlan.PlanType switch - { - PlanType.TeamsMonthly => TeamsMinimumSeats, - PlanType.EnterpriseMonthly => EnterpriseMinimumSeats, - _ => existingProviderPlan.SeatMinimum - }; - } - return providerPlans; - } - - public Provider ToProvider(Provider existingProvider) - { - existingProvider.BillingEmail = BillingEmail?.ToLowerInvariant()?.Trim(); - existingProvider.BillingPhone = BillingPhone?.ToLowerInvariant()?.Trim(); + existingProvider.BillingEmail = BillingEmail?.ToLowerInvariant().Trim(); + existingProvider.BillingPhone = BillingPhone?.ToLowerInvariant().Trim(); + existingProvider.Gateway = Gateway; + existingProvider.GatewayCustomerId = GatewayCustomerId; + existingProvider.GatewaySubscriptionId = GatewaySubscriptionId; return existingProvider; } - - private int GetMinimumSeats(IEnumerable providerPlans, PlanType planType) - { - return (from providerPlan in providerPlans where providerPlan.PlanType == planType select (int)providerPlan.SeatMinimum).FirstOrDefault(); - } + private static int GetSeatMinimum(IEnumerable providerPlans, PlanType planType) + => providerPlans.FirstOrDefault(providerPlan => providerPlan.PlanType == planType)?.SeatMinimum ?? 0; } diff --git a/src/Admin/AdminConsole/Views/Providers/Create.cshtml b/src/Admin/AdminConsole/Views/Providers/Create.cshtml index 7b10de3724..41855895e1 100644 --- a/src/Admin/AdminConsole/Views/Providers/Create.cshtml +++ b/src/Admin/AdminConsole/Views/Providers/Create.cshtml @@ -46,14 +46,14 @@
- - + +
- - + +
diff --git a/src/Admin/AdminConsole/Views/Providers/Edit.cshtml b/src/Admin/AdminConsole/Views/Providers/Edit.cshtml index b9348d3474..1d58a16a29 100644 --- a/src/Admin/AdminConsole/Views/Providers/Edit.cshtml +++ b/src/Admin/AdminConsole/Views/Providers/Edit.cshtml @@ -48,103 +48,142 @@
- - + +
- - + + +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
} @await Html.PartialAsync("Organizations", Model) - @if (canEdit) - { - - - - +@if (canEdit) +{ + + + + - + -
- - @if (FeatureService.IsEnabled(FeatureFlagKeys.EnableDeleteProvider)) - { -
- - +
+ + @if (FeatureService.IsEnabled(FeatureFlagKeys.EnableDeleteProvider)) + { +
+ + - - + + - + -
- } -
- - } +
+ } +
+}