mirror of
https://github.com/bitwarden/server.git
synced 2025-04-05 21:18:13 -05:00
[AC-85] Set Max Seats Autoscale and Current Seats via Public API (#3389)
* Add new public models and controllers * Resolve pr comments * Fix the failing test * Change the controller name * resolve pr comments * add the IValidatableObject * resolve pr comment * resolve pr comments * resolve pr comments * resolve * removing the whitespaces * code refactoring
This commit is contained in:
parent
3bffd09472
commit
cedbea4a60
81
src/Api/Billing/Public/Controllers/OrganizationController.cs
Normal file
81
src/Api/Billing/Public/Controllers/OrganizationController.cs
Normal file
@ -0,0 +1,81 @@
|
||||
using System.Net;
|
||||
using Bit.Api.Models.Public.Response;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using OrganizationSubscriptionUpdateRequestModel = Bit.Api.Billing.Public.Models.OrganizationSubscriptionUpdateRequestModel;
|
||||
|
||||
namespace Bit.Api.Billing.Public.Controllers;
|
||||
|
||||
[Route("public/organization")]
|
||||
[Authorize("Organization")]
|
||||
public class OrganizationController : Controller
|
||||
{
|
||||
private readonly IOrganizationService _organizationService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IUpdateSecretsManagerSubscriptionCommand _updateSecretsManagerSubscriptionCommand;
|
||||
|
||||
public OrganizationController(
|
||||
IOrganizationService organizationService,
|
||||
ICurrentContext currentContext,
|
||||
IOrganizationRepository organizationRepository,
|
||||
IUpdateSecretsManagerSubscriptionCommand updateSecretsManagerSubscriptionCommand)
|
||||
{
|
||||
_organizationService = organizationService;
|
||||
_currentContext = currentContext;
|
||||
_organizationRepository = organizationRepository;
|
||||
_updateSecretsManagerSubscriptionCommand = updateSecretsManagerSubscriptionCommand;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the organization's current subscription for Password Manager and/or Secrets Manager.
|
||||
/// </summary>
|
||||
/// <param name="model">The request model containing the updated subscription information.</param>
|
||||
[HttpPut("subscription")]
|
||||
[SelfHosted(NotSelfHostedOnly = true)]
|
||||
[ProducesResponseType((int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.BadRequest)]
|
||||
[ProducesResponseType((int)HttpStatusCode.NotFound)]
|
||||
public async Task<IActionResult> PostSubscriptionAsync([FromBody] OrganizationSubscriptionUpdateRequestModel model)
|
||||
{
|
||||
|
||||
await UpdatePasswordManagerAsync(model, _currentContext.OrganizationId.Value);
|
||||
|
||||
await UpdateSecretsManagerAsync(model, _currentContext.OrganizationId.Value);
|
||||
|
||||
return new OkResult();
|
||||
}
|
||||
|
||||
private async Task UpdatePasswordManagerAsync(OrganizationSubscriptionUpdateRequestModel model, Guid organizationId)
|
||||
{
|
||||
if (model.PasswordManager != null)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
|
||||
model.PasswordManager.ToPasswordManagerSubscriptionUpdate(organization);
|
||||
await _organizationService.UpdateSubscription(organization.Id, (int)model.PasswordManager.Seats,
|
||||
model.PasswordManager.MaxAutoScaleSeats);
|
||||
if (model.PasswordManager.Storage.HasValue)
|
||||
{
|
||||
await _organizationService.AdjustStorageAsync(organization.Id, (short)model.PasswordManager.Storage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateSecretsManagerAsync(OrganizationSubscriptionUpdateRequestModel model, Guid organizationId)
|
||||
{
|
||||
if (model.SecretsManager != null)
|
||||
{
|
||||
var organization =
|
||||
await _organizationRepository.GetByIdAsync(organizationId);
|
||||
|
||||
var organizationUpdate = model.SecretsManager.ToSecretsManagerSubscriptionUpdate(organization);
|
||||
await _updateSecretsManagerSubscriptionCommand.UpdateSubscriptionAsync(organizationUpdate);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Models.Business;
|
||||
|
||||
namespace Bit.Api.Billing.Public.Models;
|
||||
|
||||
public class OrganizationSubscriptionUpdateRequestModel : IValidatableObject
|
||||
{
|
||||
public PasswordManagerSubscriptionUpdateModel PasswordManager { get; set; }
|
||||
public SecretsManagerSubscriptionUpdateModel SecretsManager { get; set; }
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (PasswordManager == null && SecretsManager == null)
|
||||
{
|
||||
yield return new ValidationResult("At least one of PasswordManager or SecretsManager must be provided.");
|
||||
}
|
||||
|
||||
yield return ValidationResult.Success;
|
||||
}
|
||||
}
|
||||
|
||||
public class PasswordManagerSubscriptionUpdateModel
|
||||
{
|
||||
public int? Seats { get; set; }
|
||||
public int? Storage { get; set; }
|
||||
private int? _maxAutoScaleSeats;
|
||||
public int? MaxAutoScaleSeats
|
||||
{
|
||||
get { return _maxAutoScaleSeats; }
|
||||
set { _maxAutoScaleSeats = value < 0 ? null : value; }
|
||||
}
|
||||
|
||||
public virtual void ToPasswordManagerSubscriptionUpdate(Organization organization)
|
||||
{
|
||||
UpdateMaxAutoScaleSeats(organization);
|
||||
|
||||
UpdateSeats(organization);
|
||||
|
||||
UpdateStorage(organization);
|
||||
}
|
||||
|
||||
private void UpdateMaxAutoScaleSeats(Organization organization)
|
||||
{
|
||||
MaxAutoScaleSeats ??= organization.MaxAutoscaleSeats;
|
||||
}
|
||||
|
||||
private void UpdateSeats(Organization organization)
|
||||
{
|
||||
if (Seats is > 0)
|
||||
{
|
||||
if (organization.Seats.HasValue)
|
||||
{
|
||||
Seats = Seats.Value - organization.Seats.Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Seats = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateStorage(Organization organization)
|
||||
{
|
||||
if (Storage is > 0)
|
||||
{
|
||||
if (organization.MaxStorageGb.HasValue)
|
||||
{
|
||||
Storage = (short?)(Storage - organization.MaxStorageGb.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Storage = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SecretsManagerSubscriptionUpdateModel
|
||||
{
|
||||
public int? Seats { get; set; }
|
||||
private int? _maxAutoScaleSeats;
|
||||
public int? MaxAutoScaleSeats
|
||||
{
|
||||
get { return _maxAutoScaleSeats; }
|
||||
set { _maxAutoScaleSeats = value < 0 ? null : value; }
|
||||
}
|
||||
public int? ServiceAccounts { get; set; }
|
||||
private int? _maxAutoScaleServiceAccounts;
|
||||
public int? MaxAutoScaleServiceAccounts
|
||||
{
|
||||
get { return _maxAutoScaleServiceAccounts; }
|
||||
set { _maxAutoScaleServiceAccounts = value < 0 ? null : value; }
|
||||
}
|
||||
|
||||
public virtual SecretsManagerSubscriptionUpdate ToSecretsManagerSubscriptionUpdate(Organization organization)
|
||||
{
|
||||
var update = UpdateUpdateMaxAutoScale(organization);
|
||||
UpdateSeats(organization, update);
|
||||
UpdateServiceAccounts(organization, update);
|
||||
return update;
|
||||
}
|
||||
|
||||
private SecretsManagerSubscriptionUpdate UpdateUpdateMaxAutoScale(Organization organization)
|
||||
{
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false)
|
||||
{
|
||||
MaxAutoscaleSmSeats = MaxAutoScaleSeats ?? organization.MaxAutoscaleSmSeats,
|
||||
MaxAutoscaleSmServiceAccounts = MaxAutoScaleServiceAccounts ?? organization.MaxAutoscaleSmServiceAccounts
|
||||
};
|
||||
return update;
|
||||
}
|
||||
|
||||
private void UpdateSeats(Organization organization, SecretsManagerSubscriptionUpdate update)
|
||||
{
|
||||
if (Seats is > 0)
|
||||
{
|
||||
if (organization.SmSeats.HasValue)
|
||||
{
|
||||
Seats = Seats.Value - organization.SmSeats.Value;
|
||||
|
||||
}
|
||||
update.AdjustSeats(Seats.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateServiceAccounts(Organization organization, SecretsManagerSubscriptionUpdate update)
|
||||
{
|
||||
if (ServiceAccounts is > 0)
|
||||
{
|
||||
if (organization.SmServiceAccounts.HasValue)
|
||||
{
|
||||
ServiceAccounts = ServiceAccounts.Value - organization.SmServiceAccounts.Value;
|
||||
}
|
||||
update.AdjustServiceAccounts(ServiceAccounts.Value);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user