From b53159b0a4017739f480a4bbdc90f7429e12de28 Mon Sep 17 00:00:00 2001 From: 0xZensh Date: Wed, 13 Sep 2023 16:43:02 +0800 Subject: [PATCH] 1. Add list_credits api; 2. Improve code. --- Cargo.lock | 86 +++++++++++------------ Cargo.toml | 2 +- src/api/transaction.rs | 19 +++-- src/api/wallet.rs | 63 ++++++++++++++++- src/db/model_charge.rs | 47 ++++++------- src/db/model_credit.rs | 53 ++++++-------- src/db/model_transaction.rs | 135 ++++++++++++------------------------ src/router.rs | 1 + 8 files changed, 206 insertions(+), 200 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 01cabb9..9acb55d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,9 +107,9 @@ checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" [[package]] name = "async-compression" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d495b6dc0184693324491a5ac05f559acc97bf937ab31d7a1c33dd0016be6d2b" +checksum = "bb42b2197bf15ccb092b62c74515dbd8b86d0effd934795f6687c93b6e679a2c" dependencies = [ "flate2", "futures-core", @@ -128,7 +128,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -197,7 +197,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -207,7 +207,7 @@ dependencies = [ "anyhow", "async-trait", "axum", - "base64 0.21.3", + "base64 0.21.4", "bytes", "ciborium", "ciborium-io", @@ -249,9 +249,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.3" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "base64ct" @@ -314,9 +314,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" @@ -336,9 +336,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87d9d13be47a5b7c3907137f1290b0459a7f80efb26be8c52afb11963bccb02" +checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" dependencies = [ "android-tzdata", "iana-time-zone", @@ -463,9 +463,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f711ade317dd348950a9910f81c5947e3d8907ebd2b83f76203ff1807e6a2bc2" +checksum = "622178105f911d937a42cdb140730ba4a3ed2becd8ae6ce39c7d28b5d75d4588" dependencies = [ "cfg-if", "cpufeatures", @@ -486,7 +486,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -581,9 +581,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.1.20" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" +checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" [[package]] name = "flate2" @@ -666,7 +666,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -782,7 +782,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ - "base64 0.21.3", + "base64 0.21.4", "bytes", "headers-core", "http", @@ -1249,7 +1249,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -1355,7 +1355,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -1424,7 +1424,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -1729,7 +1729,7 @@ dependencies = [ "scylla-macros", "smallvec", "snap", - "socket2 0.5.3", + "socket2 0.5.4", "strum 0.23.0", "strum_macros 0.23.1", "thiserror", @@ -1792,7 +1792,7 @@ dependencies = [ "proc-macro2", "quote", "scylla-orm", - "syn 2.0.31", + "syn 2.0.32", "xid", ] @@ -1819,7 +1819,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -1833,9 +1833,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2" dependencies = [ "indexmap 2.0.0", "itoa", @@ -1951,9 +1951,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" dependencies = [ "libc", "windows-sys", @@ -2023,7 +2023,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -2113,9 +2113,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.31" +version = "2.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" dependencies = [ "proc-macro2", "quote", @@ -2158,7 +2158,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -2190,7 +2190,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.3", + "socket2 0.5.4", "tokio-macros", "windows-sys", ] @@ -2203,7 +2203,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -2237,9 +2237,9 @@ checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.0.0", "toml_datetime", @@ -2317,7 +2317,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", ] [[package]] @@ -2365,9 +2365,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -2512,14 +2512,14 @@ dependencies = [ [[package]] name = "walletbase" -version = "0.4.0" +version = "0.4.1" dependencies = [ "aes-gcm", "anyhow", "async-trait", "axum", "axum-web", - "base64 0.21.3", + "base64 0.21.4", "base64ct", "bytes", "ciborium", @@ -2591,7 +2591,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", "wasm-bindgen-shared", ] @@ -2613,7 +2613,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.32", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 78a4e46..669400c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "walletbase" -version = "0.4.0" +version = "0.4.1" edition = "2021" rust-version = "1.64" description = "" diff --git a/src/api/transaction.rs b/src/api/transaction.rs index 351dd2d..921f740 100644 --- a/src/api/transaction.rs +++ b/src/api/transaction.rs @@ -10,10 +10,11 @@ use axum_web::context::ReqContext; use axum_web::erring::{HTTPError, SuccessResponse}; use axum_web::object::PackObject; -use crate::api::{ - get_fields, token_from_xid, token_to_xid, AppState, Pagination, QueryUidId, -}; use crate::db; +use crate::{ + api::{get_fields, token_from_xid, token_to_xid, AppState, Pagination, QueryUidId}, + db::TransactionKind, +}; #[derive(Debug, Default, Deserialize, Serialize)] pub struct TransactionOutput { @@ -22,6 +23,8 @@ pub struct TransactionOutput { pub payee: PackObject, #[serde(skip_serializing_if = "Option::is_none")] pub sub_payee: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub payer: Option>, pub status: i8, pub kind: String, pub amount: i64, @@ -40,13 +43,21 @@ impl TransactionOutput { sequence: val.sequence, payee: to.with(val.payee), status: val.status, - kind: val.kind, + kind: val.kind.clone(), amount: val.amount, sys_fee: val.sys_fee, sub_shares: val.sub_shares, ..Default::default() }; + match TransactionKind::from_str(&val.kind) { + Ok(TransactionKind::Award) + | Ok(TransactionKind::Topup) + | Ok(TransactionKind::Sponsor) + | Ok(TransactionKind::Subscribe) => rt.payer = to.with_option(Some(val.uid)), + _ => {} + } + for v in val._fields { match v.as_str() { "sub_payee" => rt.sub_payee = to.with_option(val.sub_payee), diff --git a/src/api/wallet.rs b/src/api/wallet.rs index c56d079..76935c8 100644 --- a/src/api/wallet.rs +++ b/src/api/wallet.rs @@ -12,7 +12,7 @@ use axum_web::object::PackObject; use crate::db; use crate::{ - api::{AppState, QueryUid}, + api::{token_from_xid, token_to_xid, AppState, Pagination, QueryUid}, db::SYS_ID, }; @@ -60,6 +60,67 @@ pub async fn get( Ok(to.with(SuccessResponse::new(WalletOutput::from(doc, &to)))) } +#[derive(Debug, Default, Deserialize, Serialize)] +pub struct CreditOutput { + pub txn: PackObject, + pub kind: String, + pub amount: i64, + pub description: String, +} + +impl CreditOutput { + pub fn from(val: db::Credit, to: &PackObject) -> Self { + Self { + txn: to.with(val.txn), + kind: val.kind, + amount: val.amount, + description: val.description, + } + } +} + +pub async fn list_credits( + State(app): State>, + Extension(ctx): Extension>, + to: PackObject, +) -> Result>>, HTTPError> { + let (to, input) = to.unpack(); + input.validate()?; + + let page_size = input.page_size.unwrap_or(10); + ctx.set_kvs(vec![ + ("action", "list_credit".into()), + ("uid", input.uid.to_string().into()), + ("page_size", page_size.into()), + ]) + .await; + + let fields = input.fields.unwrap_or_default(); + let res = db::Credit::list( + &app.scylla, + input.uid.unwrap(), + fields, + page_size, + token_to_xid(&input.page_token), + None, + ) + .await?; + let next_page_token = if res.len() >= page_size as usize { + to.with_option(token_from_xid(res.last().unwrap().txn)) + } else { + None + }; + + Ok(to.with(SuccessResponse { + total_size: None, + next_page_token, + result: res + .iter() + .map(|r| CreditOutput::from(r.to_owned(), &to)) + .collect(), + })) +} + #[derive(Debug, Deserialize, Validate)] pub struct AwardInput { pub payee: PackObject, diff --git a/src/db/model_charge.rs b/src/db/model_charge.rs index 2de8a2a..6bb4a9f 100644 --- a/src/db/model_charge.rs +++ b/src/db/model_charge.rs @@ -2,6 +2,7 @@ use axum_web::{context::unix_ms, erring::HTTPError}; use scylla_orm::{ColumnsMap, CqlValue, ToCqlVal}; use scylla_orm_macros::CqlOrm; +use super::MAX_ID; use crate::db::scylladb::{self, extract_applied}; #[derive(Debug, Default, Clone, CqlOrm)] @@ -233,36 +234,28 @@ impl Charge { ) -> anyhow::Result> { let fields = Self::select_fields(select_fields, true)?; - let rows = if let Some(id) = page_token { - if status.is_none() { - let query = format!( - "SELECT {} FROM charge WHERE uid=? AND id id, + None => MAX_ID, + }; + + let rows = if status.is_none() { + let query = format!( + "SELECT {} FROM charge WHERE uid=? AND id anyhow::Result> { let fields = Self::select_fields(select_fields, true)?; - let rows = if let Some(id) = page_token { - if kind.is_none() { - let query = format!( - "SELECT {} FROM credit WHERE uid=? AND txn id, + None => MAX_ID, + }; + + let rows = if kind.is_none() { + let query = format!( + "SELECT {} FROM credit WHERE uid=? AND txn anyhow::Result> { let fields = Self::select_fields(select_fields, true)?; - let rows = if let Some(id) = page_token { - if kind.is_none() { - let query = format!( + let token = match page_token { + Some(id) => id, + None => MAX_ID, + }; + + let rows = if kind.is_none() { + let query = format!( "SELECT {} FROM transaction WHERE uid=? AND id anyhow::Result> { let fields = Self::select_fields(select_fields, true)?; - let rows = if let Some(id) = page_token { - if kind.is_none() { - let query = format!( + let token = match page_token { + Some(id) => id, + None => MAX_ID, + }; + + let rows = if kind.is_none() { + let query = format!( "SELECT {} FROM transaction WHERE payee=? AND id anyhow::Result> { let fields = Self::select_fields(select_fields, true)?; - let rows = if let Some(id) = page_token { - if kind.is_none() { - let query = format!( + let token = match page_token { + Some(id) => id, + None => MAX_ID, + }; + + let rows = if kind.is_none() { + let query = format!( "SELECT {} FROM transaction WHERE sub_payee=? AND id anyhow::Result<(Arc, Router) "/v1/wallet", Router::new() .route("/", routing::get(api::wallet::get)) + .route("/list_credits", routing::post(api::wallet::list_credits)) .route("/award", routing::post(api::wallet::award)) .route("/spend", routing::post(api::wallet::spend)) .route("/sponsor", routing::post(api::wallet::sponsor))