mirror of
https://git.dirksys.ovh/dirk/bankserver.git
synced 2025-12-20 02:59:20 +01:00
117 lines
3.2 KiB
Rust
117 lines
3.2 KiB
Rust
use std::sync::Arc;
|
|
|
|
use axum::{Router, extract::Path, routing::get};
|
|
use bank_core::{
|
|
pagination::Pagination,
|
|
transaction::{FullTransaction, TransactionQuery},
|
|
user::{User, UserAccounts, UserBalance},
|
|
};
|
|
use serde::{Deserialize, Serialize};
|
|
use tracing::instrument;
|
|
use uuid::Uuid;
|
|
|
|
use crate::{
|
|
api::ApiError,
|
|
model::{Accounts, Transactions, Users},
|
|
};
|
|
|
|
use super::{AppState, EState, Error, Json, PaginationQuery, Query, State, auth::Auth};
|
|
|
|
pub(super) fn router() -> Router<Arc<AppState>> {
|
|
Router::new()
|
|
.route("/{target}", get(user_info))
|
|
.route("/@me/balance", get(user_balance))
|
|
.route("/@me/accounts", get(user_accounts))
|
|
.route("/@me/transactions", get(me_transaction_history))
|
|
.route("/", get(list_users))
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize)]
|
|
pub enum UserTarget {
|
|
#[serde(rename = "@me")]
|
|
Me,
|
|
Id(Uuid),
|
|
}
|
|
|
|
impl UserTarget {
|
|
pub fn user_id(&self, auth: &Auth) -> Uuid {
|
|
match self {
|
|
UserTarget::Me => auth.user_id(),
|
|
UserTarget::Id(uuid) => *uuid,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn user_info(
|
|
EState(state): State,
|
|
auth: Auth,
|
|
Path(target): Path<UserTarget>,
|
|
) -> Result<Json<User>, Error> {
|
|
let user = target.user_id(&auth);
|
|
let conn = state.conn().await?;
|
|
let info = Users::info(&conn, user).await?;
|
|
if let Some(info) = info {
|
|
return Ok(Json(info));
|
|
}
|
|
if matches!(target, UserTarget::Me) {
|
|
return Err(ApiError::INTERNAL_SERVER_ERROR.into());
|
|
}
|
|
Err(ApiError::NOT_FOUND.into())
|
|
}
|
|
|
|
#[instrument(skip(state))]
|
|
pub async fn user_balance(EState(state): State, auth: Auth) -> Result<Json<UserBalance>, Error> {
|
|
let conn = state.conn().await?;
|
|
let info = Accounts::list_for_user(&conn, auth.user_id()).await?;
|
|
let balance = info.iter().map(|info| info.balance).sum();
|
|
Ok(Json(UserBalance { balance }))
|
|
}
|
|
|
|
#[instrument(skip(state))]
|
|
pub async fn list_users(
|
|
EState(state): State,
|
|
_: Auth,
|
|
PaginationQuery(pagination): PaginationQuery,
|
|
) -> Result<Json<Pagination<User>>, Error> {
|
|
let conn = state.conn().await?;
|
|
let users = Users::list(&conn, pagination).await?;
|
|
Ok(Json(users))
|
|
}
|
|
|
|
#[instrument(skip(state))]
|
|
pub async fn me_transaction_history(
|
|
EState(state): State,
|
|
auth: Auth,
|
|
Query(TransactionQuery {
|
|
direction,
|
|
pagination,
|
|
}): Query<TransactionQuery>,
|
|
) -> Result<Json<Pagination<FullTransaction>>, Error> {
|
|
let conn = state.conn().await?;
|
|
let result = Transactions::user_history(&conn, auth.user_id(), direction, pagination).await?;
|
|
Ok(Json(result))
|
|
}
|
|
|
|
#[instrument(skip(state))]
|
|
pub async fn user_accounts(EState(state): State, auth: Auth) -> Result<Json<UserAccounts>, Error> {
|
|
let user = auth.user_id();
|
|
let conn = state.conn().await?;
|
|
let result = Accounts::list_for_user(&conn, user).await?;
|
|
Ok(Json(UserAccounts { result }))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use uuid::Uuid;
|
|
|
|
use super::UserTarget;
|
|
|
|
#[test]
|
|
fn user_target() {
|
|
let json = serde_json::to_string(&UserTarget::Me).unwrap();
|
|
assert_eq!(json, r#""@me""#);
|
|
let json = serde_json::to_string(&Uuid::nil()).unwrap();
|
|
assert_eq!(json, r#""00000000-0000-0000-0000-000000000000""#);
|
|
}
|
|
}
|