From ecbfc056830e41822e4567721be0a8bc51fc0436 Mon Sep 17 00:00:00 2001
From: aj-bw <81774843+aj-bw@users.noreply.github.com>
Date: Tue, 17 Dec 2024 08:32:37 -0500
Subject: [PATCH] QA-689/BEEEP-public-api-GET-subscription-details (#5041)
* added GET operation to org subscription endpoint
* adding back removed using statement
* addressing unused import and lint warnings
* whitespace lint fix
* successful local format
* add NotSelfHostOnly attribute
* add endpoint summary and return details
---
.../Controllers/OrganizationController.cs | 44 +++++++++++++++++++
...anizationSubscriptionUpdateRequestModel.cs | 0
...izationSubscriptionDetailsResponseModel.cs | 32 ++++++++++++++
3 files changed, 76 insertions(+)
rename src/Api/Billing/Public/Models/{ => Request}/OrganizationSubscriptionUpdateRequestModel.cs (100%)
create mode 100644 src/Api/Billing/Public/Models/Response/OrganizationSubscriptionDetailsResponseModel.cs
diff --git a/src/Api/Billing/Public/Controllers/OrganizationController.cs b/src/Api/Billing/Public/Controllers/OrganizationController.cs
index c696f2af5..7fcd94acd 100644
--- a/src/Api/Billing/Public/Controllers/OrganizationController.cs
+++ b/src/Api/Billing/Public/Controllers/OrganizationController.cs
@@ -1,4 +1,5 @@
using System.Net;
+using Bit.Api.Billing.Public.Models;
using Bit.Api.Models.Public.Response;
using Bit.Core.Context;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
@@ -35,6 +36,49 @@ public class OrganizationController : Controller
_logger = logger;
}
+ ///
+ /// Retrieves the subscription details for the current organization.
+ ///
+ ///
+ /// Returns an object containing the subscription details if successful.
+ ///
+ [HttpGet("subscription")]
+ [SelfHosted(NotSelfHostedOnly = true)]
+ [ProducesResponseType(typeof(OrganizationSubscriptionDetailsResponseModel), (int)HttpStatusCode.OK)]
+ [ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.NotFound)]
+ public async Task GetSubscriptionAsync()
+ {
+ try
+ {
+ var organizationId = _currentContext.OrganizationId.Value;
+ var organization = await _organizationRepository.GetByIdAsync(organizationId);
+
+ var subscriptionDetails = new OrganizationSubscriptionDetailsResponseModel
+ {
+ PasswordManager = new PasswordManagerSubscriptionDetails
+ {
+ Seats = organization.Seats,
+ MaxAutoScaleSeats = organization.MaxAutoscaleSeats,
+ Storage = organization.MaxStorageGb
+ },
+ SecretsManager = new SecretsManagerSubscriptionDetails
+ {
+ Seats = organization.SmSeats,
+ MaxAutoScaleSeats = organization.MaxAutoscaleSmSeats,
+ ServiceAccounts = organization.SmServiceAccounts,
+ MaxAutoScaleServiceAccounts = organization.MaxAutoscaleSmServiceAccounts
+ }
+ };
+
+ return Ok(subscriptionDetails);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Unhandled error while retrieving the subscription details");
+ return StatusCode(500, new { Message = "An error occurred while retrieving the subscription details." });
+ }
+ }
+
///
/// Update the organization's current subscription for Password Manager and/or Secrets Manager.
///
diff --git a/src/Api/Billing/Public/Models/OrganizationSubscriptionUpdateRequestModel.cs b/src/Api/Billing/Public/Models/Request/OrganizationSubscriptionUpdateRequestModel.cs
similarity index 100%
rename from src/Api/Billing/Public/Models/OrganizationSubscriptionUpdateRequestModel.cs
rename to src/Api/Billing/Public/Models/Request/OrganizationSubscriptionUpdateRequestModel.cs
diff --git a/src/Api/Billing/Public/Models/Response/OrganizationSubscriptionDetailsResponseModel.cs b/src/Api/Billing/Public/Models/Response/OrganizationSubscriptionDetailsResponseModel.cs
new file mode 100644
index 000000000..09aa7decc
--- /dev/null
+++ b/src/Api/Billing/Public/Models/Response/OrganizationSubscriptionDetailsResponseModel.cs
@@ -0,0 +1,32 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Bit.Api.Billing.Public.Models;
+
+public class OrganizationSubscriptionDetailsResponseModel : IValidatableObject
+{
+ public PasswordManagerSubscriptionDetails PasswordManager { get; set; }
+ public SecretsManagerSubscriptionDetails SecretsManager { get; set; }
+ public IEnumerable 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 PasswordManagerSubscriptionDetails
+{
+ public int? Seats { get; set; }
+ public int? MaxAutoScaleSeats { get; set; }
+ public short? Storage { get; set; }
+}
+
+public class SecretsManagerSubscriptionDetails
+{
+ public int? Seats { get; set; }
+ public int? MaxAutoScaleSeats { get; set; }
+ public int? ServiceAccounts { get; set; }
+ public int? MaxAutoScaleServiceAccounts { get; set; }
+}