stripe info admin endpoint (#1623)
This commit is contained in:
1 parent
a7c59f7c9b
commit
1c654bfafa
22 files changed
+439
-2
No files matched your search
+36
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT DISTINCT\n subscription_namespace as `subscription_namespace: enums::common::payments_namespace::PaymentsNamespace`,\n maybe_stripe_customer_id as `stripe_customer_id!`\n\nFROM user_subscriptions\n\nWHERE\n user_token = ?\n AND maybe_stripe_customer_id IS NOT NULL\n AND deleted_at IS NULL\nORDER BY subscription_namespace ASC, maybe_stripe_customer_id ASC\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "subscription_namespace: enums::common::payments_namespace::PaymentsNamespace",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "stripe_customer_id!",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "516db34b6a642a2f7d7107f186905a79ad694c3c86f3078efc77bcaae7f39f3d"
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n user_token as `user_token: tokens::tokens::users::UserToken`,\n payments_namespace as `payments_namespace: enums::common::payments_namespace::PaymentsNamespace`,\n stripe_customer_id\n\nFROM user_stripe_customer_links\n\nWHERE user_token = ?\nORDER BY id ASC\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "payments_namespace: enums::common::payments_namespace::PaymentsNamespace",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "stripe_customer_id",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "ffb5717340f21f21693bfcade201bc055fb3fb8a26da8d0574e3de44b033586c"
|
||||
}
|
||||
@@ -2,5 +2,6 @@ pub mod alerts;
|
||||
pub mod jobs;
|
||||
pub mod user;
|
||||
pub mod user_referrals;
|
||||
pub mod user_stripe_data;
|
||||
pub mod wallet_ledger_entries;
|
||||
pub mod wallets;
|
||||
@@ -0,0 +1 @@
|
||||
pub mod moderator_get_user_stripe_customer_ids;
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
use enums::common::payments_namespace::PaymentsNamespace;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tokens::tokens::users::UserToken;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub const MODERATOR_GET_USER_STRIPE_CUSTOMER_IDS_PATH: &str =
|
||||
"/v1/moderation/user_stripe_data/{user_token}/customer_ids";
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct ModeratorGetUserStripeCustomerIdsPathInfo {
|
||||
pub user_token: UserToken,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ModeratorGetUserStripeCustomerIdsResponse {
|
||||
pub success: bool,
|
||||
|
||||
/// All stripe customer ids we have on file for the user, across payments
|
||||
/// namespaces. A user may have zero or several: a customer link and/or
|
||||
/// subscriptions per namespace (eg. artcraft), plus legacy fakeyou
|
||||
/// subscriptions. The same customer id can appear once per source.
|
||||
pub customer_ids: Vec<ModeratorUserStripeCustomerIdEntry>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ModeratorUserStripeCustomerIdEntry {
|
||||
pub stripe_customer_id: String,
|
||||
pub payments_namespace: PaymentsNamespace,
|
||||
pub source: ModeratorStripeCustomerIdSource,
|
||||
}
|
||||
|
||||
/// Which table the customer id was found in.
|
||||
#[derive(Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ModeratorStripeCustomerIdSource {
|
||||
/// From the `user_stripe_customer_links` table (1:1 per namespace).
|
||||
CustomerLink,
|
||||
/// From the user's rows in the `user_subscriptions` table.
|
||||
Subscription,
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"type": "image",
|
||||
"blob": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCATgA0ADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDpBThTRThTJHinimCn0hjhS00U6kMKWkoqQFpRSUtAx1LTaWgB1LTaXNAxaSiigANNpTQaZIlJS0UxCUUuKSmAUtAooGFFFFIYYopaKAEpKWimJjTSU40lBI2ilxRikIQU8UgFKKBjhTxTBTxSGLS0lFMYtNNLSGgBppppxpKAGGkxTqKBCYoFLiigBRThSCnCmAtLSUtMYtFFFABRRRSASig0lJjCkNFJUgJSUppppAFJS0UCEpaKUUigpRRSigYopaQUopgLTqbS00SxRSikopiFzRmkozQAZpKM0maQAabS5pKBiGkNBpKYCUUUlMBaM0lGaBDqKSloAWlpKKAFptLSUxCUhpaQ0ANNJS0lACUlLijFIY2inYpMUgDFGKXFLipYxKdRilFJgUxTxTRTxWpI4U4U0U4UhjhS0gpaQwpaSjNIBaWkooAWlpKKYDqWm0tAC0tJRQAUUUYpkhikpcUUwEooooAKKKKQwpaSloGFLikFLQAlFLSUCEpMU6kpiG4oxTsUYpCsJSgUYpRQMUU4UgpaAFooooGFJS0lIBDTadSUANopaKAExS4oxS0AGKWilFMApaSloAKWiimAUlKaSkMSiikpAIaTNBpKACkoopAFFFFIApaKWgApaQUtIYtKKSlpgLS02lqhC0UlFMQtJmikoAWkopKQBSUUlAAaaaU0hoGJSZpaSmAUUUUALRSUtAC0uaSimAZooooEJSUtJQMSkpaKQCUUtLQA3FLilxS4pANxS4pcUYqRiYpaMUtICpilFLilxWhICnCkFLikMWloFLSGFFFFABRRRTELS02loAdS0gpaBBmlpKWmAtFFFMQUUYooASilooAbRS0UhiUtFFIYtFFFAgopaKYCYpKdikoASilooCwlLS0UAFLRS0gCilooASg0tJQA2ilopANxRilooGJS0UUAFLSUtMAFLQKBQAtFFFAAaaaWkNACGmmnGmmgBKSlNJSGFFFFAgpRSUtAgpaSlpDFFFJRQMWlpKKYDqKSlpiFzRmkopiCkoooAKSikoAKSlpKBiUhpaSkAlFLSUAFFFFMYUtFFABS0YooAKSlpKAENFKaSgAxRiiigApaKWgAxRS0UhhiilxRSASiiikBXxS4p2KMVZIgFGKdiikMSloooAKKKKQBRRRTAKWkpaBCinU0U4UAFKKBRTELS0lKKYgooooAMUlLRQMSkpaKQxKWiikAUtJS0AFFFFMAooooAKKKKACloooAWlpKUUgFopKKBBQaKDQAlJS0lAwNJRRSAKKSgUALS0lLTAWiiigBaSiigApKWkpAIaaadSUANoxS0UhiUUtGKYhKKXFFAhKKWkoAXNGaSigYtLTaWgBaWkpaYC5pKKKYBQaKQ0AFJSmkoASiiigBKSlopAJRRiigAooooAKWiimAUuKKKQxMUUtFADaKXFFMBMUUuKKACgUUtACiikpaBhRRRSGFFFJSAbikxTsUVRA2ilooASilpMUhhSUtFACUUtFACUtFLigApRSUtAhaWkpaBC0tNpaYC0UlLQAUUUtACUUtFAxKKXFGKQCUUtFACUUt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 truncated
|
||||
"job_id": "4123b4ec-ea71-49f4-b7e2-ad86d622b947",
|
||||
"grid_index": 0,
|
||||
"is_alteration": false,
|
||||
"order": 2,
|
||||
"section_id": 0,
|
||||
"request_id": "fc39cefd-fcf9-4775-b490-7e17ce670060",
|
||||
"url": "https://imagine-public.x.ai/imagine-public/images/7693b927-1c34-488c-8ccc-6750367c66b1.png",
|
||||
"id": "7693b927-1c34-488c-8ccc-6750367c66b1",
|
||||
"prompt": "a dog typing on a keyboard",
|
||||
"full_prompt": "a dog typing on a keyboard",
|
||||
"percentage_complete": 50,
|
||||
"model_name": "imagine_h_1",
|
||||
"suggested_moderation_rule": null,
|
||||
"r_rated": false
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"type": "json",
|
||||
"current_status": "completed",
|
||||
"percentage_complete": 100,
|
||||
"job_id": "c1bed796-3f05-4716-8ef0-a4d4900dfc6e",
|
||||
"elapsed": null,
|
||||
"prompt": "a dog typing on a keyboard",
|
||||
"confirmation": "Drew a dog typing",
|
||||
"full_prompt": "a dog typing on a keyboard",
|
||||
"flags": null,
|
||||
"is_alteration": false,
|
||||
"section_id": 0,
|
||||
"input_type": "text",
|
||||
"request_id": "fc39cefd-fcf9-4775-b490-7e17ce670060",
|
||||
"asr_transcript": null,
|
||||
"asr_accepted": null,
|
||||
"seed": null,
|
||||
"image_reference": null,
|
||||
"is_image_edit": null,
|
||||
"moderated": false,
|
||||
"r_rated": false,
|
||||
"order": 1,
|
||||
"model_name": "imagine_h_1",
|
||||
"image_id": "78b3e6ef-defc-41a6-a9ac-b7a370d26ce5"
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"type": "json",
|
||||
"current_status": "start_stage",
|
||||
"percentage_complete": 0,
|
||||
"job_id": "57baeffe-d5cf-483b-a5bb-7794899f905c",
|
||||
"elapsed": null,
|
||||
"prompt": "a dog typing on a keyboard",
|
||||
"confirmation": "Drew a dog typing",
|
||||
"full_prompt": "a dog typing on a keyboard",
|
||||
"flags": null,
|
||||
"is_alteration": true,
|
||||
"section_id": 0,
|
||||
"input_type": "text",
|
||||
"request_id": "fc39cefd-fcf9-4775-b490-7e17ce670060",
|
||||
"asr_transcript": null,
|
||||
"asr_accepted": null,
|
||||
"seed": null,
|
||||
"image_reference": null,
|
||||
"is_image_edit": null,
|
||||
"moderated": false,
|
||||
"r_rated": null,
|
||||
"order": 7,
|
||||
"model_name": "imagine_h_1",
|
||||
"image_id": null
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"type": "conversation.item.create",
|
||||
"timestamp": 1761010203630,
|
||||
"item": {
|
||||
"type": "message",
|
||||
"content": [
|
||||
{
|
||||
"requestId": "fc39cefd-fcf9-4775-b490-7e17ce670060",
|
||||
"text": "a dog typing on a keyboard",
|
||||
"type": "input_text",
|
||||
"properties": {
|
||||
"section_count": 0,
|
||||
"is_kids_mode": false,
|
||||
"enable_nsfw": true,
|
||||
"skip_upsampler": false,
|
||||
"is_initial": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"type": "other_type",
|
||||
"foo": "bar"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"json","current_status":"start_stage","percentage_complete":0.0,"job_id":"0080eaac-f7f7-4369-90a2-346491939c1b","elapsed":null,"prompt":"a dog riding a motorcycle","confirmation":"Drew a dog riding a motorcycle","full_prompt":"a dog riding a motorcycle","flags":null,"is_alteration":false,"section_id":0,"input_type":"text","request_id":"bbc15402-3257-4415-922e-b156c151f3c2","asr_transcript":null,"asr_accepted":null,"seed":null,"image_reference":null,"is_image_edit":null,"moderated":false,"r_rated":null,"order":0,"model_name":"imagine_h_1","image_id":null}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"type": "json",
|
||||
"current_status": "start_stage",
|
||||
"percentage_complete": 0,
|
||||
"job_id": "0080eaac-f7f7-4369-90a2-346491939c1b",
|
||||
"elapsed": null,
|
||||
"prompt": "a dog riding a motorcycle",
|
||||
"confirmation": "Drew a dog riding a motorcycle",
|
||||
"full_prompt": "a dog riding a motorcycle",
|
||||
"flags": null,
|
||||
"is_alteration": false,
|
||||
"section_id": 0,
|
||||
"input_type": "text",
|
||||
"request_id": "bbc15402-3257-4415-922e-b156c151f3c2",
|
||||
"asr_transcript": null,
|
||||
"asr_accepted": null,
|
||||
"seed": null,
|
||||
"image_reference": null,
|
||||
"is_image_edit": null,
|
||||
"moderated": false,
|
||||
"r_rated": null,
|
||||
"order": 0,
|
||||
"model_name": "imagine_h_1",
|
||||
"image_id": null
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::MySql;
|
||||
|
||||
use enums::common::payments_namespace::PaymentsNamespace;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::queries::users::user_stripe_customer_links::find_user_stripe_customer_link::UserStripeCustomerLink;
|
||||
|
||||
/// List every stripe customer link for a user, across all payments namespaces.
|
||||
/// Users have at most one link per namespace.
|
||||
pub async fn list_user_stripe_customer_links_for_user(
|
||||
user_token: &UserToken,
|
||||
connection: &mut PoolConnection<MySql>,
|
||||
) -> Result<Vec<UserStripeCustomerLink>, sqlx::Error> {
|
||||
let records = sqlx::query_as!(
|
||||
RawUserStripeCustomerLink,
|
||||
r#"
|
||||
SELECT
|
||||
user_token as `user_token: tokens::tokens::users::UserToken`,
|
||||
payments_namespace as `payments_namespace: enums::common::payments_namespace::PaymentsNamespace`,
|
||||
stripe_customer_id
|
||||
|
||||
FROM user_stripe_customer_links
|
||||
|
||||
WHERE user_token = ?
|
||||
ORDER BY id ASC
|
||||
"#,
|
||||
user_token.as_str(),
|
||||
)
|
||||
.fetch_all(&mut **connection)
|
||||
.await?;
|
||||
|
||||
let links = records
|
||||
.into_iter()
|
||||
.map(|record| UserStripeCustomerLink {
|
||||
user_token: record.user_token,
|
||||
payments_namespace: record.payments_namespace,
|
||||
stripe_customer_id: record.stripe_customer_id,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(links)
|
||||
}
|
||||
|
||||
#[derive(sqlx::FromRow)]
|
||||
struct RawUserStripeCustomerLink {
|
||||
user_token: UserToken,
|
||||
payments_namespace: PaymentsNamespace,
|
||||
stripe_customer_id: String,
|
||||
}
|
||||
+2
-1
@@ -1,2 +1,3 @@
|
||||
pub mod find_user_stripe_customer_link;
|
||||
pub mod upsert_user_stripe_customer_link;
|
||||
pub mod list_user_stripe_customer_links_for_user;
|
||||
pub mod upsert_user_stripe_customer_link;
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::MySql;
|
||||
|
||||
use enums::common::payments_namespace::PaymentsNamespace;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
/// A distinct stripe customer id attached to one of the user's subscriptions.
|
||||
pub struct UserSubscriptionStripeCustomerId {
|
||||
pub subscription_namespace: PaymentsNamespace,
|
||||
pub stripe_customer_id: String,
|
||||
}
|
||||
|
||||
/// List the distinct stripe customer ids across all of a user's subscriptions
|
||||
/// (current and historical), across all payments namespaces.
|
||||
pub async fn list_stripe_customer_ids_for_user_subscriptions(
|
||||
user_token: &UserToken,
|
||||
connection: &mut PoolConnection<MySql>,
|
||||
) -> Result<Vec<UserSubscriptionStripeCustomerId>, sqlx::Error> {
|
||||
let records = sqlx::query_as!(
|
||||
UserSubscriptionStripeCustomerId,
|
||||
r#"
|
||||
SELECT DISTINCT
|
||||
subscription_namespace as `subscription_namespace: enums::common::payments_namespace::PaymentsNamespace`,
|
||||
maybe_stripe_customer_id as `stripe_customer_id!`
|
||||
|
||||
FROM user_subscriptions
|
||||
|
||||
WHERE
|
||||
user_token = ?
|
||||
AND maybe_stripe_customer_id IS NOT NULL
|
||||
AND deleted_at IS NULL
|
||||
ORDER BY subscription_namespace ASC, maybe_stripe_customer_id ASC
|
||||
"#,
|
||||
user_token.as_str(),
|
||||
)
|
||||
.fetch_all(&mut **connection)
|
||||
.await?;
|
||||
|
||||
Ok(records)
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
pub mod find_possibly_inactive_first_subscription_for_owner_user;
|
||||
pub mod lookup_users_by_stripe_customer_id;
|
||||
pub mod find_subscription_for_owner_user;
|
||||
pub mod get_user_subscription_by_stripe_subscription_id;
|
||||
pub mod list_active_user_subscriptions;
|
||||
pub mod list_stripe_customer_ids_for_user_subscriptions;
|
||||
pub mod lookup_users_by_stripe_customer_id;
|
||||
pub mod upsert_user_subscription_by_stripe_id;
|
||||
pub mod upsert_user_subscription_with_invoice_paid_status_by_stripe_id;
|
||||
@@ -117,6 +117,7 @@ use artcraft_api_defs::folders::media_files::*;
|
||||
use artcraft_api_defs::folders::subfolder::*;
|
||||
use artcraft_api_defs::moderation::user_referrals::list_global_user_referrals::*;
|
||||
use artcraft_api_defs::moderation::user_referrals::list_user_referrals_for_user::*;
|
||||
use artcraft_api_defs::moderation::user_stripe_data::moderator_get_user_stripe_customer_ids::*;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_list_user_session_impersonation_requests_for_user_handler::*;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_list_user_session_impersonation_requests_handler::*;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_user_session_impersonation_request_handler::*;
|
||||
@@ -558,6 +559,7 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux
|
||||
crate::http_server::endpoints::moderation::user_bans::moderation_ban_user_handler::moderation_ban_user_handler,
|
||||
crate::http_server::endpoints::moderation::user_emails::moderator_change_user_email_handler::moderator_change_user_email_handler,
|
||||
crate::http_server::endpoints::moderation::user_emails::moderator_list_email_address_changes_for_user_handler::moderator_list_email_address_changes_for_user_handler,
|
||||
crate::http_server::endpoints::moderation::user_stripe_data::moderator_get_user_stripe_customer_ids_handler::moderator_get_user_stripe_customer_ids_handler,
|
||||
|
||||
// Folders
|
||||
crate::http_server::endpoints::folders::folder::create_folder_handler::create_folder_handler,
|
||||
@@ -816,6 +818,10 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux
|
||||
ModeratorGetWalletLedgerEntryPathInfo,
|
||||
ModeratorGetWalletLedgerEntryResponse,
|
||||
ModeratorGetWalletLedgerEntryDetails,
|
||||
ModeratorGetUserStripeCustomerIdsPathInfo,
|
||||
ModeratorGetUserStripeCustomerIdsResponse,
|
||||
ModeratorUserStripeCustomerIdEntry,
|
||||
ModeratorStripeCustomerIdSource,
|
||||
GptImage1EditImageRequest,
|
||||
GptImage1EditImageImageSize,
|
||||
GptImage1EditImageNumImages,
|
||||
|
||||
@@ -10,5 +10,6 @@ pub mod user_emails;
|
||||
pub mod user_feature_flags;
|
||||
pub mod user_referrals;
|
||||
pub mod user_sessions;
|
||||
pub mod user_stripe_data;
|
||||
pub mod wallet_ledger_entries;
|
||||
pub mod wallets;
|
||||
+1
@@ -0,0 +1 @@
|
||||
pub mod moderator_get_user_stripe_customer_ids_handler;
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::web::{Json, Path};
|
||||
use actix_web::{web, HttpRequest};
|
||||
use log::warn;
|
||||
|
||||
use artcraft_api_defs::moderation::user_stripe_data::moderator_get_user_stripe_customer_ids::{
|
||||
ModeratorGetUserStripeCustomerIdsPathInfo,
|
||||
ModeratorGetUserStripeCustomerIdsResponse,
|
||||
ModeratorStripeCustomerIdSource,
|
||||
ModeratorUserStripeCustomerIdEntry,
|
||||
};
|
||||
use mysql_queries::queries::users::user_stripe_customer_links::list_user_stripe_customer_links_for_user::list_user_stripe_customer_links_for_user;
|
||||
use mysql_queries::queries::users::user_subscriptions::list_stripe_customer_ids_for_user_subscriptions::list_stripe_customer_ids_for_user_subscriptions;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::http_server::common_responses::common_web_error::CommonWebError;
|
||||
use crate::http_server::web_utils::user_session::require_moderator::{require_moderator, UseDatabase};
|
||||
use crate::state::server_state::ServerState;
|
||||
|
||||
/// Get all stripe customer ids on file for a user (moderation)
|
||||
#[utoipa::path(
|
||||
get,
|
||||
tag = "Moderation",
|
||||
path = "/v1/moderation/user_stripe_data/{user_token}/customer_ids",
|
||||
responses(
|
||||
(status = 200, description = "Success", body = ModeratorGetUserStripeCustomerIdsResponse),
|
||||
(status = 401, description = "Unauthorized"),
|
||||
(status = 500, description = "Server error"),
|
||||
),
|
||||
params(
|
||||
("user_token" = UserToken, Path, description = "User token to look up"),
|
||||
)
|
||||
)]
|
||||
pub async fn moderator_get_user_stripe_customer_ids_handler(
|
||||
http_request: HttpRequest,
|
||||
path: Path<ModeratorGetUserStripeCustomerIdsPathInfo>,
|
||||
server_state: web::Data<Arc<ServerState>>,
|
||||
) -> Result<Json<ModeratorGetUserStripeCustomerIdsResponse>, CommonWebError> {
|
||||
|
||||
let mut mysql_connection = server_state.mysql_pool
|
||||
.acquire()
|
||||
.await?;
|
||||
|
||||
let _moderator_session = require_moderator(
|
||||
&http_request,
|
||||
&server_state,
|
||||
UseDatabase::FromPool(&mut mysql_connection),
|
||||
)
|
||||
.await
|
||||
.map_err(|_| CommonWebError::NotAuthorized)?;
|
||||
|
||||
let customer_links = list_user_stripe_customer_links_for_user(&path.user_token, &mut mysql_connection)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("moderator_get_user_stripe_customer_ids customer link query error: {:?}", err);
|
||||
CommonWebError::from_error(err)
|
||||
})?;
|
||||
|
||||
let subscription_customer_ids = list_stripe_customer_ids_for_user_subscriptions(&path.user_token, &mut mysql_connection)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("moderator_get_user_stripe_customer_ids subscription query error: {:?}", err);
|
||||
CommonWebError::from_error(err)
|
||||
})?;
|
||||
|
||||
let mut customer_ids = Vec::with_capacity(customer_links.len() + subscription_customer_ids.len());
|
||||
|
||||
customer_ids.extend(customer_links.into_iter().map(|link| ModeratorUserStripeCustomerIdEntry {
|
||||
stripe_customer_id: link.stripe_customer_id,
|
||||
payments_namespace: link.payments_namespace,
|
||||
source: ModeratorStripeCustomerIdSource::CustomerLink,
|
||||
}));
|
||||
|
||||
customer_ids.extend(subscription_customer_ids.into_iter().map(|subscription| ModeratorUserStripeCustomerIdEntry {
|
||||
stripe_customer_id: subscription.stripe_customer_id,
|
||||
payments_namespace: subscription.subscription_namespace,
|
||||
source: ModeratorStripeCustomerIdSource::Subscription,
|
||||
}));
|
||||
|
||||
Ok(Json(ModeratorGetUserStripeCustomerIdsResponse {
|
||||
success: true,
|
||||
customer_ids,
|
||||
}))
|
||||
}
|
||||
+7
@@ -46,6 +46,7 @@ use crate::http_server::endpoints::moderation::user_referrals::moderator_list_gl
|
||||
use crate::http_server::endpoints::moderation::user_referrals::moderator_list_user_referrals_for_user_handler::moderator_list_user_referrals_for_user_handler;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_list_user_session_impersonation_requests_handler::moderator_list_user_session_impersonation_requests_handler;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_user_session_impersonation_request_handler::moderator_user_session_impersonation_request_handler;
|
||||
use crate::http_server::endpoints::moderation::user_stripe_data::moderator_get_user_stripe_customer_ids_handler::moderator_get_user_stripe_customer_ids_handler;
|
||||
|
||||
pub fn add_moderator_routes<T, B> (app: App<T>) -> App<T>
|
||||
where
|
||||
@@ -171,6 +172,12 @@ pub fn add_moderator_routes<T, B> (app: App<T>) -> App<T>
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
)
|
||||
.service(web::scope("/user_stripe_data")
|
||||
.service(web::resource("/{user_token}/customer_ids")
|
||||
.route(web::get().to(moderator_get_user_stripe_customer_ids_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
)
|
||||
.service(web::resource("/wallet_ledger_entry/{wallet_ledger_entry_token}")
|
||||
.route(web::get().to(moderator_get_wallet_ledger_entry_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
|
||||
Reference in new issue
Block a user