1
0
mirror of https://github.com/bitwarden/server synced 2025-12-10 05:13:48 +00:00
Files
server/src/Core/Billing/Organizations/Queries/GetOrganizationMetadataQuery.cs
Kyle Denney fedc6b865b [PM-25379] Refactor org metadata (#6441)
* ignore serena

* removing unused properties from org metadata

* removing further properties that can already be fetched on the client side using available data

* new vnext endpoint for org metadata plus caching metadata first pass

including new feature flag

# Conflicts:
#	src/Core/Constants.cs

* [PM-25379] decided against cache and new query shouldn't use the service

* pr feedback

removing unneeded response model

* run dotnet format
2025-10-13 10:49:55 -05:00

96 lines
2.8 KiB
C#

using Bit.Core.AdminConsole.Entities;
using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Organizations.Models;
using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Stripe;
namespace Bit.Core.Billing.Organizations.Queries;
public interface IGetOrganizationMetadataQuery
{
Task<OrganizationMetadata?> Run(Organization organization);
}
public class GetOrganizationMetadataQuery(
IGlobalSettings globalSettings,
IOrganizationRepository organizationRepository,
IPricingClient pricingClient,
ISubscriberService subscriberService) : IGetOrganizationMetadataQuery
{
public async Task<OrganizationMetadata?> Run(Organization organization)
{
if (organization == null)
{
return null;
}
if (globalSettings.SelfHosted)
{
return OrganizationMetadata.Default;
}
var orgOccupiedSeats = await organizationRepository.GetOccupiedSeatCountByOrganizationIdAsync(organization.Id);
if (string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId))
{
return OrganizationMetadata.Default with
{
OrganizationOccupiedSeats = orgOccupiedSeats.Total
};
}
var customer = await subscriberService.GetCustomer(organization,
new CustomerGetOptions { Expand = ["discount.coupon.applies_to"] });
var subscription = await subscriberService.GetSubscription(organization);
if (customer == null || subscription == null)
{
return OrganizationMetadata.Default with
{
OrganizationOccupiedSeats = orgOccupiedSeats.Total
};
}
var isOnSecretsManagerStandalone = await IsOnSecretsManagerStandalone(organization, customer, subscription);
return new OrganizationMetadata(
isOnSecretsManagerStandalone,
orgOccupiedSeats.Total);
}
private async Task<bool> IsOnSecretsManagerStandalone(
Organization organization,
Customer? customer,
Subscription? subscription)
{
if (customer == null || subscription == null)
{
return false;
}
var plan = await pricingClient.GetPlanOrThrow(organization.PlanType);
if (!plan.SupportsSecretsManager)
{
return false;
}
var hasCoupon = customer.Discount?.Coupon?.Id == StripeConstants.CouponIDs.SecretsManagerStandalone;
if (!hasCoupon)
{
return false;
}
var subscriptionProductIds = subscription.Items.Data.Select(item => item.Plan.ProductId);
var couponAppliesTo = customer.Discount?.Coupon?.AppliesTo?.Products;
return subscriptionProductIds.Intersect(couponAppliesTo ?? []).Any();
}
}