mirror of
https://github.com/bitwarden/server.git
synced 2025-05-22 20:11:04 -05:00

* [NO LOGIC] Organize Billing provider code * Run dotnet format * Run dotnet format' * Fixed using after merge * Fixed test usings after merge
186 lines
6.0 KiB
C#
186 lines
6.0 KiB
C#
using Bit.Api.Billing.Controllers;
|
|
using Bit.Api.Billing.Models.Requests;
|
|
using Bit.Core.AdminConsole.Repositories;
|
|
using Bit.Core.AdminConsole.Services;
|
|
using Bit.Core.Billing.Providers.Services;
|
|
using Bit.Core.Context;
|
|
using Bit.Core.Enums;
|
|
using Bit.Core.Models.Business;
|
|
using Bit.Core.Repositories;
|
|
using Bit.Core.Services;
|
|
using Bit.Core.Utilities;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
namespace Bit.Api.AdminConsole.Controllers;
|
|
|
|
[Route("providers/{providerId:guid}/clients")]
|
|
public class ProviderClientsController(
|
|
ICurrentContext currentContext,
|
|
ILogger<BaseProviderController> logger,
|
|
IOrganizationRepository organizationRepository,
|
|
IProviderBillingService providerBillingService,
|
|
IProviderOrganizationRepository providerOrganizationRepository,
|
|
IProviderRepository providerRepository,
|
|
IProviderService providerService,
|
|
IUserService userService) : BaseProviderController(currentContext, logger, providerRepository, userService)
|
|
{
|
|
private readonly ICurrentContext _currentContext = currentContext;
|
|
|
|
[HttpPost]
|
|
[SelfHosted(NotSelfHostedOnly = true)]
|
|
public async Task<IResult> CreateAsync(
|
|
[FromRoute] Guid providerId,
|
|
[FromBody] CreateClientOrganizationRequestBody requestBody)
|
|
{
|
|
var (provider, result) = await TryGetBillableProviderForAdminOperation(providerId);
|
|
|
|
if (provider == null)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
var user = await UserService.GetUserByPrincipalAsync(User);
|
|
|
|
if (user == null)
|
|
{
|
|
return Error.Unauthorized();
|
|
}
|
|
|
|
var organizationSignup = new OrganizationSignup
|
|
{
|
|
Name = requestBody.Name,
|
|
Plan = requestBody.PlanType,
|
|
AdditionalSeats = requestBody.Seats,
|
|
Owner = user,
|
|
BillingEmail = provider.BillingEmail,
|
|
OwnerKey = requestBody.Key,
|
|
PublicKey = requestBody.KeyPair.PublicKey,
|
|
PrivateKey = requestBody.KeyPair.EncryptedPrivateKey,
|
|
CollectionName = requestBody.CollectionName,
|
|
IsFromProvider = true
|
|
};
|
|
|
|
var providerOrganization = await providerService.CreateOrganizationAsync(
|
|
providerId,
|
|
organizationSignup,
|
|
requestBody.OwnerEmail,
|
|
user);
|
|
|
|
var clientOrganization = await organizationRepository.GetByIdAsync(providerOrganization.OrganizationId);
|
|
|
|
await providerBillingService.ScaleSeats(
|
|
provider,
|
|
requestBody.PlanType,
|
|
requestBody.Seats);
|
|
|
|
await providerBillingService.CreateCustomerForClientOrganization(
|
|
provider,
|
|
clientOrganization);
|
|
|
|
clientOrganization.Status = OrganizationStatusType.Managed;
|
|
|
|
await organizationRepository.ReplaceAsync(clientOrganization);
|
|
|
|
return TypedResults.Ok();
|
|
}
|
|
|
|
[HttpPut("{providerOrganizationId:guid}")]
|
|
[SelfHosted(NotSelfHostedOnly = true)]
|
|
public async Task<IResult> UpdateAsync(
|
|
[FromRoute] Guid providerId,
|
|
[FromRoute] Guid providerOrganizationId,
|
|
[FromBody] UpdateClientOrganizationRequestBody requestBody)
|
|
{
|
|
var (provider, result) = await TryGetBillableProviderForServiceUserOperation(providerId);
|
|
|
|
if (provider == null)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
var providerOrganization = await providerOrganizationRepository.GetByIdAsync(providerOrganizationId);
|
|
|
|
if (providerOrganization == null)
|
|
{
|
|
return Error.NotFound();
|
|
}
|
|
|
|
var clientOrganization = await organizationRepository.GetByIdAsync(providerOrganization.OrganizationId);
|
|
|
|
if (clientOrganization is not { Status: OrganizationStatusType.Managed })
|
|
{
|
|
return Error.ServerError();
|
|
}
|
|
|
|
var seatAdjustment = requestBody.AssignedSeats - (clientOrganization.Seats ?? 0);
|
|
|
|
var seatAdjustmentResultsInPurchase = await providerBillingService.SeatAdjustmentResultsInPurchase(
|
|
provider,
|
|
clientOrganization.PlanType,
|
|
seatAdjustment);
|
|
|
|
if (seatAdjustmentResultsInPurchase && !_currentContext.ProviderProviderAdmin(provider.Id))
|
|
{
|
|
return Error.Unauthorized("Service users cannot purchase additional seats.");
|
|
}
|
|
|
|
await providerBillingService.ScaleSeats(provider, clientOrganization.PlanType, seatAdjustment);
|
|
|
|
clientOrganization.Name = requestBody.Name;
|
|
clientOrganization.Seats = requestBody.AssignedSeats;
|
|
|
|
await organizationRepository.ReplaceAsync(clientOrganization);
|
|
|
|
return TypedResults.Ok();
|
|
}
|
|
|
|
[HttpGet("addable")]
|
|
[SelfHosted(NotSelfHostedOnly = true)]
|
|
public async Task<IResult> GetAddableOrganizationsAsync([FromRoute] Guid providerId)
|
|
{
|
|
var (provider, result) = await TryGetBillableProviderForServiceUserOperation(providerId);
|
|
|
|
if (provider == null)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
var userId = _currentContext.UserId;
|
|
|
|
if (!userId.HasValue)
|
|
{
|
|
return Error.Unauthorized();
|
|
}
|
|
|
|
var addable =
|
|
await providerBillingService.GetAddableOrganizations(provider, userId.Value);
|
|
|
|
return TypedResults.Ok(addable);
|
|
}
|
|
|
|
[HttpPost("existing")]
|
|
[SelfHosted(NotSelfHostedOnly = true)]
|
|
public async Task<IResult> AddExistingOrganizationAsync(
|
|
[FromRoute] Guid providerId,
|
|
[FromBody] AddExistingOrganizationRequestBody requestBody)
|
|
{
|
|
var (provider, result) = await TryGetBillableProviderForServiceUserOperation(providerId);
|
|
|
|
if (provider == null)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
var organization = await organizationRepository.GetByIdAsync(requestBody.OrganizationId);
|
|
|
|
if (organization == null)
|
|
{
|
|
return Error.BadRequest("The organization being added to the provider does not exist.");
|
|
}
|
|
|
|
await providerBillingService.AddExistingOrganization(provider, organization, requestBody.Key);
|
|
|
|
return TypedResults.Ok();
|
|
}
|
|
}
|