mirror of
https://github.com/bitwarden/server
synced 2025-12-21 02:33:30 +00:00
[AC-2888] Improve consolidated billing error handling (#4548)
* Fix error handling in provider setup process This update ensures that when 'enable-consolidated-billing' is on, any exception thrown during the Stripe customer or subscription setup process for the provider will block the remainder of the setup process so the provider does not enter an invalid state * Refactor the way BillingException is thrown Made it simpler to just use the exception constructor and also ensured it was added to the exception handling middleware so it could provide a simple response to the client * Handle all Stripe exceptions in exception handling middleware * Fixed error response output for billing's provider controllers * Cleaned up billing owned provider controllers Changes were made based on feature updates by product and stuff that's no longer needed. No need to expose sensitive endpoints when they're not being used. * Reafctored get invoices Removed unnecssarily bloated method from SubscriberService * Updated error handling for generating the client invoice report * Moved get provider subscription to controller This is only used once and the service layer doesn't seem like the correct choice anymore when thinking about error handling with retrieval * Handled bad request for update tax information * Split out Stripe configuration from unauthorization * Run dotnet format * Addison's feedback
This commit is contained in:
@@ -3,7 +3,9 @@ using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Extensions;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Bit.Api.Billing.Controllers;
|
||||
@@ -11,8 +13,25 @@ namespace Bit.Api.Billing.Controllers;
|
||||
public abstract class BaseProviderController(
|
||||
ICurrentContext currentContext,
|
||||
IFeatureService featureService,
|
||||
IProviderRepository providerRepository) : Controller
|
||||
ILogger<BaseProviderController> logger,
|
||||
IProviderRepository providerRepository,
|
||||
IUserService userService) : Controller
|
||||
{
|
||||
protected readonly IUserService UserService = userService;
|
||||
|
||||
protected static NotFound<ErrorResponseModel> NotFoundResponse() =>
|
||||
TypedResults.NotFound(new ErrorResponseModel("Resource not found."));
|
||||
|
||||
protected static JsonHttpResult<ErrorResponseModel> ServerErrorResponse(string errorMessage) =>
|
||||
TypedResults.Json(
|
||||
new ErrorResponseModel(errorMessage),
|
||||
statusCode: StatusCodes.Status500InternalServerError);
|
||||
|
||||
protected static JsonHttpResult<ErrorResponseModel> UnauthorizedResponse() =>
|
||||
TypedResults.Json(
|
||||
new ErrorResponseModel("Unauthorized."),
|
||||
statusCode: StatusCodes.Status401Unauthorized);
|
||||
|
||||
protected Task<(Provider, IResult)> TryGetBillableProviderForAdminOperation(
|
||||
Guid providerId) => TryGetBillableProviderAsync(providerId, currentContext.ProviderProviderAdmin);
|
||||
|
||||
@@ -25,26 +44,53 @@ public abstract class BaseProviderController(
|
||||
{
|
||||
if (!featureService.IsEnabled(FeatureFlagKeys.EnableConsolidatedBilling))
|
||||
{
|
||||
return (null, TypedResults.NotFound());
|
||||
logger.LogError(
|
||||
"Cannot run Consolidated Billing operation for provider ({ProviderID}) while feature flag is disabled",
|
||||
providerId);
|
||||
|
||||
return (null, NotFoundResponse());
|
||||
}
|
||||
|
||||
var provider = await providerRepository.GetByIdAsync(providerId);
|
||||
|
||||
if (provider == null)
|
||||
{
|
||||
return (null, TypedResults.NotFound());
|
||||
logger.LogError(
|
||||
"Cannot find provider ({ProviderID}) for Consolidated Billing operation",
|
||||
providerId);
|
||||
|
||||
return (null, NotFoundResponse());
|
||||
}
|
||||
|
||||
if (!checkAuthorization(providerId))
|
||||
{
|
||||
return (null, TypedResults.Unauthorized());
|
||||
var user = await UserService.GetUserByPrincipalAsync(User);
|
||||
|
||||
logger.LogError(
|
||||
"User ({UserID}) is not authorized to perform Consolidated Billing operation for provider ({ProviderID})",
|
||||
user?.Id, providerId);
|
||||
|
||||
return (null, UnauthorizedResponse());
|
||||
}
|
||||
|
||||
if (!provider.IsBillable())
|
||||
{
|
||||
return (null, TypedResults.Unauthorized());
|
||||
logger.LogError(
|
||||
"Cannot run Consolidated Billing operation for provider ({ProviderID}) that is not billable",
|
||||
providerId);
|
||||
|
||||
return (null, UnauthorizedResponse());
|
||||
}
|
||||
|
||||
return (provider, null);
|
||||
if (provider.IsStripeEnabled())
|
||||
{
|
||||
return (provider, null);
|
||||
}
|
||||
|
||||
logger.LogError(
|
||||
"Cannot run Consolidated Billing operation for provider ({ProviderID}) that is missing Stripe configuration",
|
||||
providerId);
|
||||
|
||||
return (null, ServerErrorResponse("Something went wrong with your request. Please contact support."));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user