mirror of
https://github.com/bitwarden/server
synced 2025-12-23 03:33:35 +00:00
[PM 21897]Add Manual Enable/Disable Override for Providers in Admin Portal (#6072)
* Add the changes for the enable provider * remove the wanted permission added * Added a unit testing for the updateAsync
This commit is contained in:
@@ -152,7 +152,15 @@ public class ProviderService : IProviderService
|
|||||||
throw new ArgumentException("Cannot create provider this way.");
|
throw new ArgumentException("Cannot create provider this way.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var existingProvider = await _providerRepository.GetByIdAsync(provider.Id);
|
||||||
|
var enabledStatusChanged = existingProvider != null && existingProvider.Enabled != provider.Enabled;
|
||||||
|
|
||||||
await _providerRepository.ReplaceAsync(provider);
|
await _providerRepository.ReplaceAsync(provider);
|
||||||
|
|
||||||
|
if (enabledStatusChanged && (provider.Type == ProviderType.Msp || provider.Type == ProviderType.BusinessUnit))
|
||||||
|
{
|
||||||
|
await UpdateClientOrganizationsEnabledStatusAsync(provider.Id, provider.Enabled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<ProviderUser>> InviteUserAsync(ProviderUserInvite<string> invite)
|
public async Task<List<ProviderUser>> InviteUserAsync(ProviderUserInvite<string> invite)
|
||||||
@@ -728,4 +736,20 @@ public class ProviderService : IProviderService
|
|||||||
throw new BadRequestException($"Unsupported provider type {providerType}.");
|
throw new BadRequestException($"Unsupported provider type {providerType}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task UpdateClientOrganizationsEnabledStatusAsync(Guid providerId, bool enabled)
|
||||||
|
{
|
||||||
|
var providerOrganizations = await _providerOrganizationRepository.GetManyDetailsByProviderAsync(providerId);
|
||||||
|
|
||||||
|
foreach (var providerOrganization in providerOrganizations)
|
||||||
|
{
|
||||||
|
var organization = await _organizationRepository.GetByIdAsync(providerOrganization.OrganizationId);
|
||||||
|
if (organization != null && organization.Enabled != enabled)
|
||||||
|
{
|
||||||
|
organization.Enabled = enabled;
|
||||||
|
await _organizationRepository.ReplaceAsync(organization);
|
||||||
|
await _applicationCacheService.UpsertOrganizationAbilityAsync(organization);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Bit.Core.AdminConsole.Entities.Provider;
|
|||||||
using Bit.Core.AdminConsole.Enums.Provider;
|
using Bit.Core.AdminConsole.Enums.Provider;
|
||||||
using Bit.Core.AdminConsole.Models.Business.Provider;
|
using Bit.Core.AdminConsole.Models.Business.Provider;
|
||||||
using Bit.Core.AdminConsole.Models.Business.Tokenables;
|
using Bit.Core.AdminConsole.Models.Business.Tokenables;
|
||||||
|
using Bit.Core.AdminConsole.Models.Data.Provider;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
|
||||||
using Bit.Core.AdminConsole.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Billing.Enums;
|
using Bit.Core.Billing.Enums;
|
||||||
@@ -188,6 +189,262 @@ public class ProviderServiceTests
|
|||||||
await sutProvider.Sut.UpdateAsync(provider);
|
await sutProvider.Sut.UpdateAsync(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task UpdateAsync_ExistingProviderIsNull_DoesNotCallUpdateClientOrganizationsEnabledStatus(
|
||||||
|
Provider provider, SutProvider<ProviderService> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var providerRepository = sutProvider.GetDependency<IProviderRepository>();
|
||||||
|
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||||
|
|
||||||
|
providerRepository.GetByIdAsync(provider.Id).Returns((Provider)null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await sutProvider.Sut.UpdateAsync(provider);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await providerRepository.Received(1).ReplaceAsync(provider);
|
||||||
|
await providerOrganizationRepository.DidNotReceive().GetManyDetailsByProviderAsync(Arg.Any<Guid>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task UpdateAsync_EnabledStatusNotChanged_DoesNotCallUpdateClientOrganizationsEnabledStatus(
|
||||||
|
Provider provider, Provider existingProvider, SutProvider<ProviderService> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var providerRepository = sutProvider.GetDependency<IProviderRepository>();
|
||||||
|
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||||
|
|
||||||
|
existingProvider.Id = provider.Id;
|
||||||
|
existingProvider.Enabled = provider.Enabled; // Same enabled status
|
||||||
|
provider.Type = ProviderType.Msp; // Set to a type that would trigger update if status changed
|
||||||
|
|
||||||
|
providerRepository.GetByIdAsync(provider.Id).Returns(existingProvider);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await sutProvider.Sut.UpdateAsync(provider);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await providerRepository.Received(1).ReplaceAsync(provider);
|
||||||
|
await providerOrganizationRepository.DidNotReceive().GetManyDetailsByProviderAsync(Arg.Any<Guid>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task UpdateAsync_EnabledStatusChangedButProviderTypeIsReseller_DoesNotCallUpdateClientOrganizationsEnabledStatus(
|
||||||
|
Provider provider, Provider existingProvider, SutProvider<ProviderService> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var providerRepository = sutProvider.GetDependency<IProviderRepository>();
|
||||||
|
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||||
|
|
||||||
|
existingProvider.Id = provider.Id;
|
||||||
|
existingProvider.Enabled = !provider.Enabled; // Different enabled status
|
||||||
|
provider.Type = ProviderType.Reseller; // Type that should not trigger update
|
||||||
|
|
||||||
|
providerRepository.GetByIdAsync(provider.Id).Returns(existingProvider);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await sutProvider.Sut.UpdateAsync(provider);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await providerRepository.Received(1).ReplaceAsync(provider);
|
||||||
|
await providerOrganizationRepository.DidNotReceive().GetManyDetailsByProviderAsync(Arg.Any<Guid>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task UpdateAsync_EnabledStatusChangedAndProviderTypeIsMsp_CallsUpdateClientOrganizationsEnabledStatus(
|
||||||
|
Provider provider, Provider existingProvider, SutProvider<ProviderService> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var providerRepository = sutProvider.GetDependency<IProviderRepository>();
|
||||||
|
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||||
|
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||||
|
var applicationCacheService = sutProvider.GetDependency<IApplicationCacheService>();
|
||||||
|
|
||||||
|
existingProvider.Id = provider.Id;
|
||||||
|
existingProvider.Enabled = !provider.Enabled; // Different enabled status
|
||||||
|
provider.Type = ProviderType.Msp; // Type that should trigger update
|
||||||
|
|
||||||
|
// Create test provider organization details
|
||||||
|
var providerOrganizationDetails = new List<ProviderOrganizationOrganizationDetails>
|
||||||
|
{
|
||||||
|
new ProviderOrganizationOrganizationDetails { Id = Guid.NewGuid(), ProviderId = provider.Id, OrganizationId = Guid.NewGuid() },
|
||||||
|
new ProviderOrganizationOrganizationDetails { Id = Guid.NewGuid(), ProviderId = provider.Id, OrganizationId = Guid.NewGuid() }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create test organizations with different enabled status than what we're setting
|
||||||
|
var organizations = providerOrganizationDetails.Select(po =>
|
||||||
|
{
|
||||||
|
var org = new Organization { Id = po.OrganizationId, Enabled = !provider.Enabled };
|
||||||
|
return org;
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
providerRepository.GetByIdAsync(provider.Id).Returns(existingProvider);
|
||||||
|
providerOrganizationRepository.GetManyDetailsByProviderAsync(provider.Id).Returns(providerOrganizationDetails);
|
||||||
|
|
||||||
|
foreach (var org in organizations)
|
||||||
|
{
|
||||||
|
organizationRepository.GetByIdAsync(org.Id).Returns(org);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await sutProvider.Sut.UpdateAsync(provider);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await providerRepository.Received(1).ReplaceAsync(provider);
|
||||||
|
await providerOrganizationRepository.Received(1).GetManyDetailsByProviderAsync(provider.Id);
|
||||||
|
|
||||||
|
foreach (var org in organizations)
|
||||||
|
{
|
||||||
|
await organizationRepository.Received(1).ReplaceAsync(Arg.Is<Organization>(o =>
|
||||||
|
o.Id == org.Id && o.Enabled == provider.Enabled));
|
||||||
|
await applicationCacheService.Received(1).UpsertOrganizationAbilityAsync(Arg.Is<Organization>(o =>
|
||||||
|
o.Id == org.Id && o.Enabled == provider.Enabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task UpdateAsync_EnabledStatusChangedAndProviderTypeIsBusinessUnit_CallsUpdateClientOrganizationsEnabledStatus(
|
||||||
|
Provider provider, Provider existingProvider, SutProvider<ProviderService> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var providerRepository = sutProvider.GetDependency<IProviderRepository>();
|
||||||
|
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||||
|
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||||
|
var applicationCacheService = sutProvider.GetDependency<IApplicationCacheService>();
|
||||||
|
|
||||||
|
existingProvider.Id = provider.Id;
|
||||||
|
existingProvider.Enabled = !provider.Enabled; // Different enabled status
|
||||||
|
provider.Type = ProviderType.BusinessUnit; // Type that should trigger update
|
||||||
|
|
||||||
|
// Create test provider organization details
|
||||||
|
var providerOrganizationDetails = new List<ProviderOrganizationOrganizationDetails>
|
||||||
|
{
|
||||||
|
new ProviderOrganizationOrganizationDetails { Id = Guid.NewGuid(), ProviderId = provider.Id, OrganizationId = Guid.NewGuid() },
|
||||||
|
new ProviderOrganizationOrganizationDetails { Id = Guid.NewGuid(), ProviderId = provider.Id, OrganizationId = Guid.NewGuid() }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create test organizations with different enabled status than what we're setting
|
||||||
|
var organizations = providerOrganizationDetails.Select(po =>
|
||||||
|
{
|
||||||
|
var org = new Organization { Id = po.OrganizationId, Enabled = !provider.Enabled };
|
||||||
|
return org;
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
providerRepository.GetByIdAsync(provider.Id).Returns(existingProvider);
|
||||||
|
providerOrganizationRepository.GetManyDetailsByProviderAsync(provider.Id).Returns(providerOrganizationDetails);
|
||||||
|
|
||||||
|
foreach (var org in organizations)
|
||||||
|
{
|
||||||
|
organizationRepository.GetByIdAsync(org.Id).Returns(org);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await sutProvider.Sut.UpdateAsync(provider);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await providerRepository.Received(1).ReplaceAsync(provider);
|
||||||
|
await providerOrganizationRepository.Received(1).GetManyDetailsByProviderAsync(provider.Id);
|
||||||
|
|
||||||
|
foreach (var org in organizations)
|
||||||
|
{
|
||||||
|
await organizationRepository.Received(1).ReplaceAsync(Arg.Is<Organization>(o =>
|
||||||
|
o.Id == org.Id && o.Enabled == provider.Enabled));
|
||||||
|
await applicationCacheService.Received(1).UpsertOrganizationAbilityAsync(Arg.Is<Organization>(o =>
|
||||||
|
o.Id == org.Id && o.Enabled == provider.Enabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task UpdateAsync_OrganizationEnabledStatusAlreadyMatches_DoesNotUpdateOrganization(
|
||||||
|
Provider provider, Provider existingProvider, SutProvider<ProviderService> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var providerRepository = sutProvider.GetDependency<IProviderRepository>();
|
||||||
|
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||||
|
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||||
|
var applicationCacheService = sutProvider.GetDependency<IApplicationCacheService>();
|
||||||
|
|
||||||
|
existingProvider.Id = provider.Id;
|
||||||
|
existingProvider.Enabled = !provider.Enabled; // Different enabled status
|
||||||
|
provider.Type = ProviderType.Msp; // Type that should trigger update
|
||||||
|
|
||||||
|
// Create test provider organization details
|
||||||
|
var providerOrganizationDetails = new List<ProviderOrganizationOrganizationDetails>
|
||||||
|
{
|
||||||
|
new ProviderOrganizationOrganizationDetails { Id = Guid.NewGuid(), ProviderId = provider.Id, OrganizationId = Guid.NewGuid() },
|
||||||
|
new ProviderOrganizationOrganizationDetails { Id = Guid.NewGuid(), ProviderId = provider.Id, OrganizationId = Guid.NewGuid() }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create test organizations with SAME enabled status as what we're setting
|
||||||
|
var organizations = providerOrganizationDetails.Select(po =>
|
||||||
|
{
|
||||||
|
var org = new Organization { Id = po.OrganizationId, Enabled = provider.Enabled };
|
||||||
|
return org;
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
providerRepository.GetByIdAsync(provider.Id).Returns(existingProvider);
|
||||||
|
providerOrganizationRepository.GetManyDetailsByProviderAsync(provider.Id).Returns(providerOrganizationDetails);
|
||||||
|
|
||||||
|
foreach (var org in organizations)
|
||||||
|
{
|
||||||
|
organizationRepository.GetByIdAsync(org.Id).Returns(org);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await sutProvider.Sut.UpdateAsync(provider);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await providerRepository.Received(1).ReplaceAsync(provider);
|
||||||
|
await providerOrganizationRepository.Received(1).GetManyDetailsByProviderAsync(provider.Id);
|
||||||
|
|
||||||
|
// Organizations should not be updated since their enabled status already matches
|
||||||
|
foreach (var org in organizations)
|
||||||
|
{
|
||||||
|
await organizationRepository.DidNotReceive().ReplaceAsync(Arg.Any<Organization>());
|
||||||
|
await applicationCacheService.DidNotReceive().UpsertOrganizationAbilityAsync(Arg.Any<Organization>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task UpdateAsync_OrganizationIsNull_SkipsNullOrganization(
|
||||||
|
Provider provider, Provider existingProvider, SutProvider<ProviderService> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var providerRepository = sutProvider.GetDependency<IProviderRepository>();
|
||||||
|
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||||
|
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||||
|
var applicationCacheService = sutProvider.GetDependency<IApplicationCacheService>();
|
||||||
|
|
||||||
|
existingProvider.Id = provider.Id;
|
||||||
|
existingProvider.Enabled = !provider.Enabled; // Different enabled status
|
||||||
|
provider.Type = ProviderType.Msp; // Type that should trigger update
|
||||||
|
|
||||||
|
// Create test provider organization details
|
||||||
|
var providerOrganizationDetails = new List<ProviderOrganizationOrganizationDetails>
|
||||||
|
{
|
||||||
|
new ProviderOrganizationOrganizationDetails { Id = Guid.NewGuid(), ProviderId = provider.Id, OrganizationId = Guid.NewGuid() },
|
||||||
|
new ProviderOrganizationOrganizationDetails { Id = Guid.NewGuid(), ProviderId = provider.Id, OrganizationId = Guid.NewGuid() }
|
||||||
|
};
|
||||||
|
|
||||||
|
providerRepository.GetByIdAsync(provider.Id).Returns(existingProvider);
|
||||||
|
providerOrganizationRepository.GetManyDetailsByProviderAsync(provider.Id).Returns(providerOrganizationDetails);
|
||||||
|
|
||||||
|
// Return null for all organizations
|
||||||
|
organizationRepository.GetByIdAsync(Arg.Any<Guid>()).Returns((Organization)null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await sutProvider.Sut.UpdateAsync(provider);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await providerRepository.Received(1).ReplaceAsync(provider);
|
||||||
|
await providerOrganizationRepository.Received(1).GetManyDetailsByProviderAsync(provider.Id);
|
||||||
|
|
||||||
|
// No organizations should be updated since they're all null
|
||||||
|
await organizationRepository.DidNotReceive().ReplaceAsync(Arg.Any<Organization>());
|
||||||
|
await applicationCacheService.DidNotReceive().UpsertOrganizationAbilityAsync(Arg.Any<Organization>());
|
||||||
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task InviteUserAsync_ProviderIdIsInvalid_Throws(ProviderUserInvite<string> invite, SutProvider<ProviderService> sutProvider)
|
public async Task InviteUserAsync_ProviderIdIsInvalid_Throws(ProviderUserInvite<string> invite, SutProvider<ProviderService> sutProvider)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using Bit.Admin.AdminConsole.Models;
|
using Bit.Admin.AdminConsole.Models;
|
||||||
using Bit.Admin.Enums;
|
using Bit.Admin.Enums;
|
||||||
|
using Bit.Admin.Services;
|
||||||
using Bit.Admin.Utilities;
|
using Bit.Admin.Utilities;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
using Bit.Core.AdminConsole.Entities.Provider;
|
using Bit.Core.AdminConsole.Entities.Provider;
|
||||||
@@ -51,6 +52,7 @@ public class ProvidersController : Controller
|
|||||||
private readonly IProviderBillingService _providerBillingService;
|
private readonly IProviderBillingService _providerBillingService;
|
||||||
private readonly IPricingClient _pricingClient;
|
private readonly IPricingClient _pricingClient;
|
||||||
private readonly IStripeAdapter _stripeAdapter;
|
private readonly IStripeAdapter _stripeAdapter;
|
||||||
|
private readonly IAccessControlService _accessControlService;
|
||||||
private readonly string _stripeUrl;
|
private readonly string _stripeUrl;
|
||||||
private readonly string _braintreeMerchantUrl;
|
private readonly string _braintreeMerchantUrl;
|
||||||
private readonly string _braintreeMerchantId;
|
private readonly string _braintreeMerchantId;
|
||||||
@@ -70,7 +72,8 @@ public class ProvidersController : Controller
|
|||||||
IProviderBillingService providerBillingService,
|
IProviderBillingService providerBillingService,
|
||||||
IWebHostEnvironment webHostEnvironment,
|
IWebHostEnvironment webHostEnvironment,
|
||||||
IPricingClient pricingClient,
|
IPricingClient pricingClient,
|
||||||
IStripeAdapter stripeAdapter)
|
IStripeAdapter stripeAdapter,
|
||||||
|
IAccessControlService accessControlService)
|
||||||
{
|
{
|
||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
_resellerClientOrganizationSignUpCommand = resellerClientOrganizationSignUpCommand;
|
_resellerClientOrganizationSignUpCommand = resellerClientOrganizationSignUpCommand;
|
||||||
@@ -89,6 +92,7 @@ public class ProvidersController : Controller
|
|||||||
_stripeUrl = webHostEnvironment.GetStripeUrl();
|
_stripeUrl = webHostEnvironment.GetStripeUrl();
|
||||||
_braintreeMerchantUrl = webHostEnvironment.GetBraintreeMerchantUrl();
|
_braintreeMerchantUrl = webHostEnvironment.GetBraintreeMerchantUrl();
|
||||||
_braintreeMerchantId = globalSettings.Braintree.MerchantId;
|
_braintreeMerchantId = globalSettings.Braintree.MerchantId;
|
||||||
|
_accessControlService = accessControlService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[RequirePermission(Permission.Provider_List_View)]
|
[RequirePermission(Permission.Provider_List_View)]
|
||||||
@@ -291,9 +295,14 @@ public class ProvidersController : Controller
|
|||||||
return View(oldModel);
|
return View(oldModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var originalProviderStatus = provider.Enabled;
|
||||||
|
|
||||||
model.ToProvider(provider);
|
model.ToProvider(provider);
|
||||||
|
|
||||||
await _providerRepository.ReplaceAsync(provider);
|
provider.Enabled = _accessControlService.UserHasPermission(Permission.Provider_CheckEnabledBox)
|
||||||
|
? model.Enabled : originalProviderStatus;
|
||||||
|
|
||||||
|
await _providerService.UpdateAsync(provider);
|
||||||
await _applicationCacheService.UpsertProviderAbilityAsync(provider);
|
await _applicationCacheService.UpsertProviderAbilityAsync(provider);
|
||||||
|
|
||||||
if (!provider.IsBillable())
|
if (!provider.IsBillable())
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public class ProviderEditModel : ProviderViewModel, IValidatableObject
|
|||||||
GatewaySubscriptionUrl = gatewaySubscriptionUrl;
|
GatewaySubscriptionUrl = gatewaySubscriptionUrl;
|
||||||
Type = provider.Type;
|
Type = provider.Type;
|
||||||
PayByInvoice = payByInvoice;
|
PayByInvoice = payByInvoice;
|
||||||
|
Enabled = provider.Enabled;
|
||||||
|
|
||||||
if (Type == ProviderType.BusinessUnit)
|
if (Type == ProviderType.BusinessUnit)
|
||||||
{
|
{
|
||||||
@@ -78,10 +79,14 @@ public class ProviderEditModel : ProviderViewModel, IValidatableObject
|
|||||||
[Display(Name = "Enterprise Seats Minimum")]
|
[Display(Name = "Enterprise Seats Minimum")]
|
||||||
public int? EnterpriseMinimumSeats { get; set; }
|
public int? EnterpriseMinimumSeats { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Enabled")]
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
|
||||||
public virtual Provider ToProvider(Provider existingProvider)
|
public virtual Provider ToProvider(Provider existingProvider)
|
||||||
{
|
{
|
||||||
existingProvider.BillingEmail = BillingEmail?.ToLowerInvariant().Trim();
|
existingProvider.BillingEmail = BillingEmail?.ToLowerInvariant().Trim();
|
||||||
existingProvider.BillingPhone = BillingPhone?.ToLowerInvariant().Trim();
|
existingProvider.BillingPhone = BillingPhone?.ToLowerInvariant().Trim();
|
||||||
|
existingProvider.Enabled = Enabled;
|
||||||
switch (Type)
|
switch (Type)
|
||||||
{
|
{
|
||||||
case ProviderType.Msp:
|
case ProviderType.Msp:
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Provider: " + Model.Provider.DisplayName();
|
ViewData["Title"] = "Provider: " + Model.Provider.DisplayName();
|
||||||
var canEdit = AccessControlService.UserHasPermission(Permission.Provider_Edit);
|
var canEdit = AccessControlService.UserHasPermission(Permission.Provider_Edit);
|
||||||
|
var canCheckEnabled = AccessControlService.UserHasPermission(Permission.Provider_CheckEnabledBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
<h1>Provider <small>@Model.Provider.DisplayName()</small></h1>
|
<h1>Provider <small>@Model.Provider.DisplayName()</small></h1>
|
||||||
@@ -30,6 +31,13 @@
|
|||||||
<dt class="col-sm-4 col-lg-3">Name</dt>
|
<dt class="col-sm-4 col-lg-3">Name</dt>
|
||||||
<dd class="col-sm-8 col-lg-9">@Model.Provider.DisplayName()</dd>
|
<dd class="col-sm-8 col-lg-9">@Model.Provider.DisplayName()</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
@if (canCheckEnabled && (Model.Provider.Type == ProviderType.Msp || Model.Provider.Type == ProviderType.BusinessUnit))
|
||||||
|
{
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input type="checkbox" class="form-check-input" asp-for="Enabled" disabled='@(canCheckEnabled ? null : "disabled")'>
|
||||||
|
<label class="form-check-label" asp-for="Enabled"></label>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<h2>Business Information</h2>
|
<h2>Business Information</h2>
|
||||||
<dl class="row">
|
<dl class="row">
|
||||||
<dt class="col-sm-4 col-lg-3">Business Name</dt>
|
<dt class="col-sm-4 col-lg-3">Business Name</dt>
|
||||||
|
|||||||
@@ -14,6 +14,12 @@
|
|||||||
<dt class="col-sm-4 col-lg-3">Provider Type</dt>
|
<dt class="col-sm-4 col-lg-3">Provider Type</dt>
|
||||||
<dd class="col-sm-8 col-lg-9">@(Model.Provider.Type.GetDisplayAttribute()?.GetName())</dd>
|
<dd class="col-sm-8 col-lg-9">@(Model.Provider.Type.GetDisplayAttribute()?.GetName())</dd>
|
||||||
|
|
||||||
|
@if (Model.Provider.Type == ProviderType.Msp || Model.Provider.Type == ProviderType.BusinessUnit)
|
||||||
|
{
|
||||||
|
<dt class="col-sm-4 col-lg-3">Enabled</dt>
|
||||||
|
<dd class="col-sm-8 col-lg-9">@(Model.Provider.Enabled ? "Yes" : "No")</dd>
|
||||||
|
}
|
||||||
|
|
||||||
<dt class="col-sm-4 col-lg-3">Created</dt>
|
<dt class="col-sm-4 col-lg-3">Created</dt>
|
||||||
<dd class="col-sm-8 col-lg-9">@Model.Provider.CreationDate.ToString()</dd>
|
<dd class="col-sm-8 col-lg-9">@Model.Provider.CreationDate.ToString()</dd>
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ public enum Permission
|
|||||||
Provider_Edit,
|
Provider_Edit,
|
||||||
Provider_View,
|
Provider_View,
|
||||||
Provider_ResendEmailInvite,
|
Provider_ResendEmailInvite,
|
||||||
|
Provider_CheckEnabledBox,
|
||||||
|
|
||||||
Tools_ChargeBrainTreeCustomer,
|
Tools_ChargeBrainTreeCustomer,
|
||||||
Tools_PromoteAdmin,
|
Tools_PromoteAdmin,
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ public static class RolePermissionMapping
|
|||||||
Permission.Provider_Create,
|
Permission.Provider_Create,
|
||||||
Permission.Provider_View,
|
Permission.Provider_View,
|
||||||
Permission.Provider_ResendEmailInvite,
|
Permission.Provider_ResendEmailInvite,
|
||||||
|
Permission.Provider_CheckEnabledBox,
|
||||||
Permission.Tools_ChargeBrainTreeCustomer,
|
Permission.Tools_ChargeBrainTreeCustomer,
|
||||||
Permission.Tools_PromoteAdmin,
|
Permission.Tools_PromoteAdmin,
|
||||||
Permission.Tools_PromoteProviderServiceUser,
|
Permission.Tools_PromoteProviderServiceUser,
|
||||||
@@ -98,6 +99,7 @@ public static class RolePermissionMapping
|
|||||||
Permission.Provider_View,
|
Permission.Provider_View,
|
||||||
Permission.Provider_Edit,
|
Permission.Provider_Edit,
|
||||||
Permission.Provider_ResendEmailInvite,
|
Permission.Provider_ResendEmailInvite,
|
||||||
|
Permission.Provider_CheckEnabledBox,
|
||||||
Permission.Tools_ChargeBrainTreeCustomer,
|
Permission.Tools_ChargeBrainTreeCustomer,
|
||||||
Permission.Tools_PromoteAdmin,
|
Permission.Tools_PromoteAdmin,
|
||||||
Permission.Tools_PromoteProviderServiceUser,
|
Permission.Tools_PromoteProviderServiceUser,
|
||||||
@@ -135,7 +137,8 @@ public static class RolePermissionMapping
|
|||||||
Permission.Org_Billing_LaunchGateway,
|
Permission.Org_Billing_LaunchGateway,
|
||||||
Permission.Org_RequestDelete,
|
Permission.Org_RequestDelete,
|
||||||
Permission.Provider_List_View,
|
Permission.Provider_List_View,
|
||||||
Permission.Provider_View
|
Permission.Provider_View,
|
||||||
|
Permission.Provider_CheckEnabledBox
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ "billing", new List<Permission>
|
{ "billing", new List<Permission>
|
||||||
@@ -173,6 +176,7 @@ public static class RolePermissionMapping
|
|||||||
Permission.Provider_Edit,
|
Permission.Provider_Edit,
|
||||||
Permission.Provider_View,
|
Permission.Provider_View,
|
||||||
Permission.Provider_List_View,
|
Permission.Provider_List_View,
|
||||||
|
Permission.Provider_CheckEnabledBox,
|
||||||
Permission.Tools_ChargeBrainTreeCustomer,
|
Permission.Tools_ChargeBrainTreeCustomer,
|
||||||
Permission.Tools_GenerateLicenseFile,
|
Permission.Tools_GenerateLicenseFile,
|
||||||
Permission.Tools_ManageTaxRates,
|
Permission.Tools_ManageTaxRates,
|
||||||
|
|||||||
Reference in New Issue
Block a user