mirror of
https://github.com/bitwarden/server.git
synced 2026-02-07 17:33:11 +08:00
* Remove gRPC and convert PricingClient to HttpClient wrapper * Add PlanType.GetProductTier extension Many instances of StaticStore use are just to get the ProductTierType of a PlanType, but this can be derived from the PlanType itself without having to fetch the entire plan. * Remove invocations of the StaticStore in non-Test code * Deprecate StaticStore entry points * Run dotnet format * Matt's feedback * Run dotnet format * Rui's feedback * Run dotnet format * Replacements since approval * Run dotnet format
135 lines
4.4 KiB
C#
135 lines
4.4 KiB
C#
using System.Net;
|
|
using System.Net.Http.Json;
|
|
using Bit.Core.Billing.Enums;
|
|
using Bit.Core.Billing.Pricing.Models;
|
|
using Bit.Core.Exceptions;
|
|
using Bit.Core.Services;
|
|
using Bit.Core.Settings;
|
|
using Bit.Core.Utilities;
|
|
using Microsoft.Extensions.Logging;
|
|
using Plan = Bit.Core.Models.StaticStore.Plan;
|
|
|
|
#nullable enable
|
|
|
|
namespace Bit.Core.Billing.Pricing;
|
|
|
|
public class PricingClient(
|
|
IFeatureService featureService,
|
|
GlobalSettings globalSettings,
|
|
HttpClient httpClient,
|
|
ILogger<PricingClient> logger) : IPricingClient
|
|
{
|
|
public async Task<Plan?> GetPlan(PlanType planType)
|
|
{
|
|
if (globalSettings.SelfHosted)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var usePricingService = featureService.IsEnabled(FeatureFlagKeys.UsePricingService);
|
|
|
|
if (!usePricingService)
|
|
{
|
|
return StaticStore.GetPlan(planType);
|
|
}
|
|
|
|
var lookupKey = GetLookupKey(planType);
|
|
|
|
if (lookupKey == null)
|
|
{
|
|
logger.LogError("Could not find Pricing Service lookup key for PlanType {PlanType}", planType);
|
|
return null;
|
|
}
|
|
|
|
var response = await httpClient.GetAsync($"plans/lookup/{lookupKey}");
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var plan = await response.Content.ReadFromJsonAsync<PlanDTO>();
|
|
if (plan == null)
|
|
{
|
|
throw new BillingException(message: "Deserialization of Pricing Service response resulted in null");
|
|
}
|
|
return new PlanAdapter(plan);
|
|
}
|
|
|
|
if (response.StatusCode == HttpStatusCode.NotFound)
|
|
{
|
|
logger.LogError("Pricing Service plan for PlanType {PlanType} was not found", planType);
|
|
return null;
|
|
}
|
|
|
|
throw new BillingException(
|
|
message: $"Request to the Pricing Service failed with status code {response.StatusCode}");
|
|
}
|
|
|
|
public async Task<Plan> GetPlanOrThrow(PlanType planType)
|
|
{
|
|
var plan = await GetPlan(planType);
|
|
|
|
if (plan == null)
|
|
{
|
|
throw new NotFoundException();
|
|
}
|
|
|
|
return plan;
|
|
}
|
|
|
|
public async Task<List<Plan>> ListPlans()
|
|
{
|
|
if (globalSettings.SelfHosted)
|
|
{
|
|
return [];
|
|
}
|
|
|
|
var usePricingService = featureService.IsEnabled(FeatureFlagKeys.UsePricingService);
|
|
|
|
if (!usePricingService)
|
|
{
|
|
return StaticStore.Plans.ToList();
|
|
}
|
|
|
|
var response = await httpClient.GetAsync("plans");
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var plans = await response.Content.ReadFromJsonAsync<List<PlanDTO>>();
|
|
if (plans == null)
|
|
{
|
|
throw new BillingException(message: "Deserialization of Pricing Service response resulted in null");
|
|
}
|
|
return plans.Select(Plan (plan) => new PlanAdapter(plan)).ToList();
|
|
}
|
|
|
|
throw new BillingException(
|
|
message: $"Request to the Pricing Service failed with status {response.StatusCode}");
|
|
}
|
|
|
|
private static string? GetLookupKey(PlanType planType)
|
|
=> planType switch
|
|
{
|
|
PlanType.EnterpriseAnnually => "enterprise-annually",
|
|
PlanType.EnterpriseAnnually2019 => "enterprise-annually-2019",
|
|
PlanType.EnterpriseAnnually2020 => "enterprise-annually-2020",
|
|
PlanType.EnterpriseAnnually2023 => "enterprise-annually-2023",
|
|
PlanType.EnterpriseMonthly => "enterprise-monthly",
|
|
PlanType.EnterpriseMonthly2019 => "enterprise-monthly-2019",
|
|
PlanType.EnterpriseMonthly2020 => "enterprise-monthly-2020",
|
|
PlanType.EnterpriseMonthly2023 => "enterprise-monthly-2023",
|
|
PlanType.FamiliesAnnually => "families",
|
|
PlanType.FamiliesAnnually2019 => "families-2019",
|
|
PlanType.Free => "free",
|
|
PlanType.TeamsAnnually => "teams-annually",
|
|
PlanType.TeamsAnnually2019 => "teams-annually-2019",
|
|
PlanType.TeamsAnnually2020 => "teams-annually-2020",
|
|
PlanType.TeamsAnnually2023 => "teams-annually-2023",
|
|
PlanType.TeamsMonthly => "teams-monthly",
|
|
PlanType.TeamsMonthly2019 => "teams-monthly-2019",
|
|
PlanType.TeamsMonthly2020 => "teams-monthly-2020",
|
|
PlanType.TeamsMonthly2023 => "teams-monthly-2023",
|
|
PlanType.TeamsStarter => "teams-starter",
|
|
PlanType.TeamsStarter2023 => "teams-starter-2023",
|
|
_ => null
|
|
};
|
|
}
|