collab: Add endpoint for initiating a billing subscription (#15452)
This PR adds a new `POST /billing/subscriptions` endpoint that can be used to initiate a billing subscription. The endpoint will use the provided `github_user_id` to look up a user, generate a Stripe Checkout session, and then return the URL. The caller would then redirect the user to the URL to initiate the checkout flow. Here's an example of how to call it: ```sh curl -X POST "http://localhost:8080/billing/subscriptions" \ -H "Authorization: <ADMIN_TOKEN>" \ -H "Content-Type: application/json" \ -d '{"github_user_id": 12345}' ``` Release Notes: - N/A
This commit is contained in:
parent
8bb34fd93e
commit
e15d59c445
9 changed files with 258 additions and 0 deletions
|
@ -26,6 +26,7 @@ pub enum Error {
|
|||
Http(StatusCode, String),
|
||||
Database(sea_orm::error::DbErr),
|
||||
Internal(anyhow::Error),
|
||||
Stripe(stripe::StripeError),
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for Error {
|
||||
|
@ -40,6 +41,12 @@ impl From<sea_orm::error::DbErr> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<stripe::StripeError> for Error {
|
||||
fn from(error: stripe::StripeError) -> Self {
|
||||
Self::Stripe(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<axum::Error> for Error {
|
||||
fn from(error: axum::Error) -> Self {
|
||||
Self::Internal(error.into())
|
||||
|
@ -81,6 +88,14 @@ impl IntoResponse for Error {
|
|||
);
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, format!("{}", &error)).into_response()
|
||||
}
|
||||
Error::Stripe(error) => {
|
||||
log::error!(
|
||||
"HTTP error {}: {:?}",
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
&error
|
||||
);
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, format!("{}", &error)).into_response()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -91,6 +106,7 @@ impl std::fmt::Debug for Error {
|
|||
Error::Http(code, message) => (code, message).fmt(f),
|
||||
Error::Database(error) => error.fmt(f),
|
||||
Error::Internal(error) => error.fmt(f),
|
||||
Error::Stripe(error) => error.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,6 +117,7 @@ impl std::fmt::Display for Error {
|
|||
Error::Http(code, message) => write!(f, "{code}: {message}"),
|
||||
Error::Database(error) => error.fmt(f),
|
||||
Error::Internal(error) => error.fmt(f),
|
||||
Error::Stripe(error) => error.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,6 +154,8 @@ pub struct Config {
|
|||
pub zed_client_checksum_seed: Option<String>,
|
||||
pub slack_panics_webhook: Option<String>,
|
||||
pub auto_join_channel_id: Option<ChannelId>,
|
||||
pub stripe_api_key: Option<String>,
|
||||
pub stripe_price_id: Option<Arc<str>>,
|
||||
pub supermaven_admin_api_key: Option<Arc<str>>,
|
||||
}
|
||||
|
||||
|
@ -150,6 +169,7 @@ pub struct AppState {
|
|||
pub db: Arc<Database>,
|
||||
pub live_kit_client: Option<Arc<dyn live_kit_server::api::Client>>,
|
||||
pub blob_store_client: Option<aws_sdk_s3::Client>,
|
||||
pub stripe_client: Option<Arc<stripe::Client>>,
|
||||
pub rate_limiter: Arc<RateLimiter>,
|
||||
pub executor: Executor,
|
||||
pub clickhouse_client: Option<clickhouse::Client>,
|
||||
|
@ -183,6 +203,10 @@ impl AppState {
|
|||
db: db.clone(),
|
||||
live_kit_client,
|
||||
blob_store_client: build_blob_store_client(&config).await.log_err(),
|
||||
stripe_client: build_stripe_client(&config)
|
||||
.await
|
||||
.map(|client| Arc::new(client))
|
||||
.log_err(),
|
||||
rate_limiter: Arc::new(RateLimiter::new(db)),
|
||||
executor,
|
||||
clickhouse_client: config
|
||||
|
@ -195,6 +219,15 @@ impl AppState {
|
|||
}
|
||||
}
|
||||
|
||||
async fn build_stripe_client(config: &Config) -> anyhow::Result<stripe::Client> {
|
||||
let api_key = config
|
||||
.stripe_api_key
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("missing stripe_api_key"))?;
|
||||
|
||||
Ok(stripe::Client::new(api_key))
|
||||
}
|
||||
|
||||
async fn build_blob_store_client(config: &Config) -> anyhow::Result<aws_sdk_s3::Client> {
|
||||
let keys = aws_sdk_s3::config::Credentials::new(
|
||||
config
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue