list wallet ledger entries for support

This commit is contained in:
Brandon Thomas committed 2026-03-05 09:12:01 -05:00
1 parent d0fe9e1676
commit 5167feb0d4
11 files changed
+329 -1

No files matched your search

@@ -0,0 +1,146 @@
{
"db_name": "MySQL",
"query": "\nSELECT\n token as `token: tokens::tokens::wallet_ledger_entries::WalletLedgerEntryToken`,\n wallet_token as `wallet_token: tokens::tokens::wallets::WalletToken`,\n entry_type as `entry_type: enums::by_table::wallet_ledger_entries::wallet_ledger_entry_type::WalletLedgerEntryType`,\n maybe_entity_ref,\n credits_delta,\n banked_credits_before as `banked_credits_before: u32`,\n banked_credits_after as `banked_credits_after: u32`,\n monthly_credits_before as `monthly_credits_before: u32`,\n monthly_credits_after as `monthly_credits_after: u32`,\n created_at as `created_at: DateTime<Utc>`,\n is_refunded as `is_refunded: bool`,\n maybe_linked_refund_ledger_token as `maybe_linked_refund_ledger_token: tokens::tokens::wallet_ledger_entries::WalletLedgerEntryToken`\nFROM wallet_ledger_entries\nWHERE wallet_token = ?\nORDER BY id DESC\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token: tokens::tokens::wallet_ledger_entries::WalletLedgerEntryToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 1,
"name": "wallet_token: tokens::tokens::wallets::WalletToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 2,
"name": "entry_type: enums::by_table::wallet_ledger_entries::wallet_ledger_entry_type::WalletLedgerEntryType",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 3,
"name": "maybe_entity_ref",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 1020
}
},
{
"ordinal": 4,
"name": "credits_delta",
"type_info": {
"type": "Long",
"flags": "NOT_NULL",
"char_set": 63,
"max_size": 11
}
},
{
"ordinal": 5,
"name": "banked_credits_before: u32",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 6,
"name": "banked_credits_after: u32",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 7,
"name": "monthly_credits_before: u32",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 8,
"name": "monthly_credits_after: u32",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 9,
"name": "created_at: DateTime<Utc>",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 10,
"name": "is_refunded: bool",
"type_info": {
"type": "Tiny",
"flags": "NOT_NULL",
"char_set": 63,
"max_size": 1
}
},
{
"ordinal": 11,
"name": "maybe_linked_refund_ledger_token: tokens::tokens::wallet_ledger_entries::WalletLedgerEntryToken",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 128
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
true,
false,
false,
false,
false,
false,
false,
false,
true
]
},
"hash": "7f874f4ac43d8c66e3ea8cb2fb56f57b93047355dd9faee4df48799f6d1be00a"
}
@@ -1,3 +1,4 @@
pub mod jobs;
pub mod user;
pub mod wallet_ledger_entries;
pub mod wallets;
@@ -0,0 +1,35 @@
use chrono::{DateTime, Utc};
use enums::by_table::wallet_ledger_entries::wallet_ledger_entry_type::WalletLedgerEntryType;
use serde_derive::{Deserialize, Serialize};
use tokens::tokens::wallet_ledger_entries::WalletLedgerEntryToken;
use tokens::tokens::wallets::WalletToken;
use utoipa::ToSchema;
pub const LIST_WALLET_LEDGER_ENTRIES_BY_WALLET_PATH: &str = "/v1/moderation/wallet_ledger_entries/wallet/{wallet_token}/list";
#[derive(Deserialize, ToSchema)]
pub struct ListWalletLedgerEntriesByWalletPathInfo {
pub wallet_token: WalletToken,
}
#[derive(Serialize, ToSchema)]
pub struct ListWalletLedgerEntriesByWalletResponse {
pub success: bool,
pub entries: Vec<ListWalletLedgerEntriesByWalletEntry>,
}
#[derive(Serialize, ToSchema)]
pub struct ListWalletLedgerEntriesByWalletEntry {
pub token: WalletLedgerEntryToken,
pub wallet_token: WalletToken,
pub entry_type: WalletLedgerEntryType,
pub maybe_entity_ref: Option<String>,
pub credits_delta: i32,
pub banked_credits_before: u32,
pub banked_credits_after: u32,
pub monthly_credits_before: u32,
pub monthly_credits_after: u32,
pub created_at: DateTime<Utc>,
pub is_refunded: bool,
pub maybe_linked_refund_ledger_token: Option<WalletLedgerEntryToken>,
}
@@ -0,0 +1 @@
pub mod list_wallet_ledger_entries_by_wallet;
@@ -0,0 +1,62 @@
use anyhow::anyhow;
use log::warn;
use sqlx::MySqlPool;
use chrono::{DateTime, Utc};
use enums::by_table::wallet_ledger_entries::wallet_ledger_entry_type::WalletLedgerEntryType;
use errors::AnyhowResult;
use tokens::tokens::wallet_ledger_entries::WalletLedgerEntryToken;
use tokens::tokens::wallets::WalletToken;
pub struct WalletLedgerEntryForModerationResult {
pub token: WalletLedgerEntryToken,
pub wallet_token: WalletToken,
pub entry_type: WalletLedgerEntryType,
pub maybe_entity_ref: Option<String>,
pub credits_delta: i32,
pub banked_credits_before: u32,
pub banked_credits_after: u32,
pub monthly_credits_before: u32,
pub monthly_credits_after: u32,
pub created_at: DateTime<Utc>,
pub is_refunded: bool,
pub maybe_linked_refund_ledger_token: Option<WalletLedgerEntryToken>,
}
pub async fn list_wallet_ledger_entries_by_wallet(
wallet_token: &WalletToken,
mysql_pool: &MySqlPool,
) -> AnyhowResult<Vec<WalletLedgerEntryForModerationResult>> {
let results = sqlx::query_as!(
WalletLedgerEntryForModerationResult,
r#"
SELECT
token as `token: tokens::tokens::wallet_ledger_entries::WalletLedgerEntryToken`,
wallet_token as `wallet_token: tokens::tokens::wallets::WalletToken`,
entry_type as `entry_type: enums::by_table::wallet_ledger_entries::wallet_ledger_entry_type::WalletLedgerEntryType`,
maybe_entity_ref,
credits_delta,
banked_credits_before as `banked_credits_before: u32`,
banked_credits_after as `banked_credits_after: u32`,
monthly_credits_before as `monthly_credits_before: u32`,
monthly_credits_after as `monthly_credits_after: u32`,
created_at as `created_at: DateTime<Utc>`,
is_refunded as `is_refunded: bool`,
maybe_linked_refund_ledger_token as `maybe_linked_refund_ledger_token: tokens::tokens::wallet_ledger_entries::WalletLedgerEntryToken`
FROM wallet_ledger_entries
WHERE wallet_token = ?
ORDER BY id DESC
"#,
wallet_token,
)
.fetch_all(mysql_pool)
.await;
match results {
Ok(records) => Ok(records),
Err(err) => {
warn!("list_wallet_ledger_entries_by_wallet query error: {:?}", err);
Err(anyhow!("query error"))
}
}
}
@@ -1,2 +1,3 @@
pub (crate) mod internal_insert_wallet_ledger_entry;
pub mod internal_insert_wallet_created_ledger_entry;
pub mod internal_insert_wallet_created_ledger_entry;
pub mod list_wallet_ledger_entries_by_wallet;
@@ -268,6 +268,7 @@ use crate::http_server::endpoints::moderation::info::moderator_token_info_handle
use artcraft_api_defs::moderation::user::user_lookup::*;
use artcraft_api_defs::moderation::user::user_lookup_by_stripe_customer_id::*;
use artcraft_api_defs::moderation::jobs::user::list_user_jobs::*;
use artcraft_api_defs::moderation::wallet_ledger_entries::list_wallet_ledger_entries_by_wallet::*;
use artcraft_api_defs::moderation::wallets::list_user_wallets::*;
use crate::http_server::endpoints::webhooks::fal_webhook_handler::*;
use crate::http_server::endpoints::image_studio::update_gpt_image_job_status_handler::*;
@@ -441,6 +442,7 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux
crate::http_server::endpoints::moderation::user::moderator_user_lookup_handler::moderator_user_lookup_handler,
crate::http_server::endpoints::moderation::user::moderator_user_lookup_by_stripe_customer_id_handler::moderator_user_lookup_by_stripe_customer_id_handler,
crate::http_server::endpoints::moderation::jobs::user::list_user_jobs_handler::list_user_jobs_handler,
crate::http_server::endpoints::moderation::wallet_ledger_entries::list_wallet_ledger_entries_by_wallet_handler::list_wallet_ledger_entries_by_wallet_handler,
crate::http_server::endpoints::moderation::wallets::list_user_wallets_handler::list_user_wallets_handler,
// Credits
crate::http_server::endpoints::credits::get_session_credits_handler::get_session_credits_handler,
@@ -631,6 +633,9 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux
ListUserWalletsPathInfo,
ListUserWalletsResponse,
ListUserWalletsEntry,
ListWalletLedgerEntriesByWalletPathInfo,
ListWalletLedgerEntriesByWalletResponse,
ListWalletLedgerEntriesByWalletEntry,
GptImage1EditImageRequest,
GptImage1EditImageImageSize,
GptImage1EditImageNumImages,
@@ -4,4 +4,5 @@ pub mod jobs;
pub mod user;
pub mod user_bans;
pub mod user_feature_flags;
pub mod wallet_ledger_entries;
pub mod wallets;
@@ -0,0 +1,68 @@
use std::sync::Arc;
use actix_web::web::{Json, Path};
use actix_web::{web, HttpRequest};
use log::warn;
use artcraft_api_defs::moderation::wallet_ledger_entries::list_wallet_ledger_entries_by_wallet::{
ListWalletLedgerEntriesByWalletEntry,
ListWalletLedgerEntriesByWalletPathInfo,
ListWalletLedgerEntriesByWalletResponse,
};
use mysql_queries::queries::wallet_ledger_entries::list_wallet_ledger_entries_by_wallet::list_wallet_ledger_entries_by_wallet;
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;
/// List wallet ledger entries by wallet token (moderation)
#[utoipa::path(
get,
tag = "Moderation",
path = "/v1/moderation/wallet_ledger_entries/wallet/{wallet_token}/list",
responses(
(status = 200, description = "Success", body = ListWalletLedgerEntriesByWalletResponse),
(status = 401, description = "Unauthorized"),
(status = 500, description = "Server error"),
),
params(
("wallet_token" = WalletToken, Path, description = "Wallet token to look up ledger entries for"),
)
)]
pub async fn list_wallet_ledger_entries_by_wallet_handler(
http_request: HttpRequest,
path: Path<ListWalletLedgerEntriesByWalletPathInfo>,
server_state: web::Data<Arc<ServerState>>,
) -> Result<Json<ListWalletLedgerEntriesByWalletResponse>, CommonWebError> {
let _user_session = require_moderator(&http_request, &server_state, UseDatabase::Implicit)
.await
.map_err(|_| CommonWebError::NotAuthorized)?;
let results = list_wallet_ledger_entries_by_wallet(&path.wallet_token, &server_state.mysql_pool)
.await
.map_err(|err| {
warn!("list_wallet_ledger_entries_by_wallet error: {:?}", err);
CommonWebError::ServerError
})?;
let entries = results.into_iter().map(|row| ListWalletLedgerEntriesByWalletEntry {
token: row.token,
wallet_token: row.wallet_token,
entry_type: row.entry_type,
maybe_entity_ref: row.maybe_entity_ref,
credits_delta: row.credits_delta,
banked_credits_before: row.banked_credits_before,
banked_credits_after: row.banked_credits_after,
monthly_credits_before: row.monthly_credits_before,
monthly_credits_after: row.monthly_credits_after,
created_at: row.created_at,
is_refunded: row.is_refunded,
maybe_linked_refund_ledger_token: row.maybe_linked_refund_ledger_token,
}).collect();
Ok(Json(ListWalletLedgerEntriesByWalletResponse {
success: true,
entries,
}))
}
@@ -0,0 +1 @@
pub mod list_wallet_ledger_entries_by_wallet_handler;
@@ -20,6 +20,7 @@ use crate::http_server::endpoints::moderation::ip_bans::delete_ip_ban::delete_ip
use crate::http_server::endpoints::moderation::ip_bans::get_ip_ban::get_ip_ban_handler;
use crate::http_server::endpoints::moderation::ip_bans::list_ip_bans::list_ip_bans_handler;
use crate::http_server::endpoints::moderation::jobs::user::list_user_jobs_handler::list_user_jobs_handler;
use crate::http_server::endpoints::moderation::wallet_ledger_entries::list_wallet_ledger_entries_by_wallet_handler::list_wallet_ledger_entries_by_wallet_handler;
use crate::http_server::endpoints::moderation::wallets::list_user_wallets_handler::list_user_wallets_handler;
use crate::http_server::endpoints::moderation::jobs::get_tts_inference_queue_count::get_tts_inference_queue_count_handler;
use crate::http_server::endpoints::moderation::jobs::get_w2l_inference_queue_count::get_w2l_inference_queue_count_handler;
@@ -68,6 +69,12 @@ pub fn add_moderator_routes<T, B> (app: App<T>) -> App<T>
.route(web::head().to(|| HttpResponse::Ok()))
)
)
.service(web::scope("/wallet_ledger_entries")
.service(web::resource("/wallet/{wallet_token}/list")
.route(web::get().to(list_wallet_ledger_entries_by_wallet_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
)
)
// NB: Old paths are not under /v1 -
.service(web::scope("/moderation")