1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-21 12:05:42 +01:00

PM-7999 | Reseller billing e-mail can be blank causing downstream errors for org creation (#4733)

This commit is contained in:
Jonas Hendrickx 2024-09-05 16:37:20 +02:00 committed by GitHub
parent d71916aee5
commit 64a7cba013
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 64 additions and 17 deletions

View File

@ -162,27 +162,13 @@ public class ProvidersController : Controller
[SelfHosted(NotSelfHostedOnly = true)]
public async Task<IActionResult> Edit(Guid id)
{
var provider = await _providerRepository.GetByIdAsync(id);
var provider = await GetEditModel(id);
if (provider == null)
{
return RedirectToAction("Index");
}
var users = await _providerUserRepository.GetManyDetailsByProviderAsync(id);
var providerOrganizations = await _providerOrganizationRepository.GetManyDetailsByProviderAsync(id);
var isConsolidatedBillingEnabled = _featureService.IsEnabled(FeatureFlagKeys.EnableConsolidatedBilling);
if (!isConsolidatedBillingEnabled || !provider.IsBillable())
{
return View(new ProviderEditModel(provider, users, providerOrganizations, new List<ProviderPlan>()));
}
var providerPlans = await _providerPlanRepository.GetByProviderId(id);
return View(new ProviderEditModel(
provider, users, providerOrganizations,
providerPlans.ToList(), GetGatewayCustomerUrl(provider), GetGatewaySubscriptionUrl(provider)));
return View(provider);
}
[HttpPost]
@ -198,6 +184,20 @@ public class ProvidersController : Controller
return RedirectToAction("Index");
}
if (provider.Type != model.Type)
{
var oldModel = await GetEditModel(id);
ModelState.AddModelError(nameof(model.Type), "Provider type cannot be changed.");
return View(oldModel);
}
if (!ModelState.IsValid)
{
var oldModel = await GetEditModel(id);
ModelState[nameof(ProviderEditModel.BillingEmail)]!.RawValue = oldModel.BillingEmail;
return View(oldModel);
}
model.ToProvider(provider);
await _providerRepository.ReplaceAsync(provider);
@ -236,6 +236,32 @@ public class ProvidersController : Controller
return RedirectToAction("Edit", new { id });
}
private async Task<ProviderEditModel> GetEditModel(Guid id)
{
var provider = await _providerRepository.GetByIdAsync(id);
if (provider == null)
{
return null;
}
var users = await _providerUserRepository.GetManyDetailsByProviderAsync(id);
var providerOrganizations = await _providerOrganizationRepository.GetManyDetailsByProviderAsync(id);
var isConsolidatedBillingEnabled = _featureService.IsEnabled(FeatureFlagKeys.EnableConsolidatedBilling);
if (!isConsolidatedBillingEnabled || !provider.IsBillable())
{
return new ProviderEditModel(provider, users, providerOrganizations, new List<ProviderPlan>());
}
var providerPlans = await _providerPlanRepository.GetByProviderId(id);
return new ProviderEditModel(
provider, users, providerOrganizations,
providerPlans.ToList(), GetGatewayCustomerUrl(provider), GetGatewaySubscriptionUrl(provider));
}
[RequirePermission(Permission.Provider_ResendEmailInvite)]
public async Task<IActionResult> ResendInvite(Guid ownerId, Guid providerId)
{

View File

@ -1,13 +1,15 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.AdminConsole.Enums.Provider;
using Bit.Core.AdminConsole.Models.Data.Provider;
using Bit.Core.Billing.Entities;
using Bit.Core.Billing.Enums;
using Bit.Core.Enums;
using Bit.SharedWeb.Utilities;
namespace Bit.Admin.AdminConsole.Models;
public class ProviderEditModel : ProviderViewModel
public class ProviderEditModel : ProviderViewModel, IValidatableObject
{
public ProviderEditModel() { }
@ -30,6 +32,7 @@ public class ProviderEditModel : ProviderViewModel
GatewaySubscriptionId = provider.GatewaySubscriptionId;
GatewayCustomerUrl = gatewayCustomerUrl;
GatewaySubscriptionUrl = gatewaySubscriptionUrl;
Type = provider.Type;
}
[Display(Name = "Billing Email")]
@ -52,6 +55,8 @@ public class ProviderEditModel : ProviderViewModel
public string GatewaySubscriptionId { get; set; }
public string GatewayCustomerUrl { get; }
public string GatewaySubscriptionUrl { get; }
[Display(Name = "Provider Type")]
public ProviderType Type { get; set; }
public virtual Provider ToProvider(Provider existingProvider)
{
@ -65,4 +70,18 @@ public class ProviderEditModel : ProviderViewModel
private static int GetSeatMinimum(IEnumerable<ProviderPlan> providerPlans, PlanType planType)
=> providerPlans.FirstOrDefault(providerPlan => providerPlan.PlanType == planType)?.SeatMinimum ?? 0;
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
switch (Type)
{
case ProviderType.Reseller:
if (string.IsNullOrWhiteSpace(BillingEmail))
{
var billingEmailDisplayName = nameof(BillingEmail).GetDisplayAttribute<CreateProviderModel>()?.GetName() ?? nameof(BillingEmail);
yield return new ValidationResult($"The {billingEmailDisplayName} field is required.");
}
break;
}
}
}

View File

@ -16,6 +16,8 @@
@await Html.PartialAsync("_ViewInformation", Model)
@await Html.PartialAsync("Admins", Model)
<form method="post" id="edit-form">
<div asp-validation-summary="All" class="alert alert-danger"></div>
<input type="hidden" asp-for="Type" readonly>
<h2>General</h2>
<dl class="row">
<dt class="col-sm-4 col-lg-3">Name</dt>