mirror of
https://git.dirksys.ovh/dirk/bankserver.git
synced 2025-12-20 02:59:20 +01:00
add tests and fix account and user list endpoints
This commit is contained in:
parent
456c507c10
commit
6e04bb561c
@ -2,6 +2,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use axum::{Router, extract::Path, http::StatusCode, routing::get};
|
use axum::{Router, extract::Path, http::StatusCode, routing::get};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use tracing::instrument;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -29,7 +30,10 @@ pub struct ListAccounts {
|
|||||||
accounts: Vec<AccountInfo>,
|
accounts: Vec<AccountInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(state))]
|
||||||
pub async fn account_info(EState(state): State, _: Auth, Path(id): Path<Uuid>) {}
|
pub async fn account_info(EState(state): State, _: Auth, Path(id): Path<Uuid>) {}
|
||||||
|
|
||||||
|
#[instrument(skip(state))]
|
||||||
pub async fn account_transactions(
|
pub async fn account_transactions(
|
||||||
EState(state): State,
|
EState(state): State,
|
||||||
auth: Auth,
|
auth: Auth,
|
||||||
@ -53,6 +57,8 @@ pub async fn account_transactions(
|
|||||||
|
|
||||||
Ok(Json(result))
|
Ok(Json(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(state))]
|
||||||
pub async fn list_accounts(
|
pub async fn list_accounts(
|
||||||
EState(state): State,
|
EState(state): State,
|
||||||
_: Auth,
|
_: Auth,
|
||||||
|
|||||||
@ -404,7 +404,7 @@ impl RequestPagination {
|
|||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn offset(&self) -> i64 {
|
pub const fn offset(&self) -> i64 {
|
||||||
self.limit as i64
|
self.offset as i64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -333,7 +333,7 @@ impl MakePayment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct TransactionQuery {
|
pub struct TransactionQuery {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub pagination: RequestPagination,
|
pub pagination: RequestPagination,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use axum::{Router, extract::Path, http::StatusCode, routing::get};
|
use axum::{Router, extract::Path, http::StatusCode, routing::get};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tracing::instrument;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -69,12 +70,16 @@ pub async fn user_info(
|
|||||||
}
|
}
|
||||||
Err(ApiError::NOT_FOUND.into())
|
Err(ApiError::NOT_FOUND.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(state))]
|
||||||
pub async fn user_balance(EState(state): State, auth: Auth) -> Result<Json<UserBalance>, Error> {
|
pub async fn user_balance(EState(state): State, auth: Auth) -> Result<Json<UserBalance>, Error> {
|
||||||
let conn = state.conn().await?;
|
let conn = state.conn().await?;
|
||||||
let info = Account::list_for_user(&conn, auth.user_id()).await?;
|
let info = Account::list_for_user(&conn, auth.user_id()).await?;
|
||||||
let balance = info.iter().map(|info| info.balance).sum();
|
let balance = info.iter().map(|info| info.balance).sum();
|
||||||
Ok(Json(UserBalance { balance }))
|
Ok(Json(UserBalance { balance }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(state))]
|
||||||
pub async fn list_users(
|
pub async fn list_users(
|
||||||
EState(state): State,
|
EState(state): State,
|
||||||
_: Auth,
|
_: Auth,
|
||||||
@ -84,6 +89,8 @@ pub async fn list_users(
|
|||||||
let users = User::list(&conn, pagination).await?;
|
let users = User::list(&conn, pagination).await?;
|
||||||
Ok(Json(users))
|
Ok(Json(users))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(state))]
|
||||||
pub async fn me_transaction_history(
|
pub async fn me_transaction_history(
|
||||||
EState(state): State,
|
EState(state): State,
|
||||||
auth: Auth,
|
auth: Auth,
|
||||||
@ -97,6 +104,7 @@ pub async fn me_transaction_history(
|
|||||||
Ok(Json(result))
|
Ok(Json(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(state))]
|
||||||
pub async fn user_accounts(EState(state): State, auth: Auth) -> Result<Json<UserAccounts>, Error> {
|
pub async fn user_accounts(EState(state): State, auth: Auth) -> Result<Json<UserAccounts>, Error> {
|
||||||
let user = auth.user_id();
|
let user = auth.user_id();
|
||||||
let conn = state.conn().await?;
|
let conn = state.conn().await?;
|
||||||
|
|||||||
@ -96,7 +96,7 @@ impl Account {
|
|||||||
.prepare_cached("select id,\"user\",name from accounts limit $1 offset $2")
|
.prepare_cached("select id,\"user\",name from accounts limit $1 offset $2")
|
||||||
.await?;
|
.await?;
|
||||||
let stmt_count = client
|
let stmt_count = client
|
||||||
.prepare_cached("select count(*) from accounts limit $1 offset $2")
|
.prepare_cached("select count(*) from accounts")
|
||||||
.await?;
|
.await?;
|
||||||
let users = client
|
let users = client
|
||||||
.query(&stmt, &[&pagination.limit(), &pagination.offset()])
|
.query(&stmt, &[&pagination.limit(), &pagination.offset()])
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use garde::Validate;
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio_postgres::{ToStatement, types::ToSql};
|
use tokio_postgres::{ToStatement, types::ToSql};
|
||||||
|
use tracing::{info, instrument};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
mod account;
|
mod account;
|
||||||
@ -50,7 +51,8 @@ pub struct IdWithName {
|
|||||||
pub name: Name,
|
pub name: Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn count<T: ?Sized + ToStatement + Sync + Send>(
|
#[instrument(skip(client))]
|
||||||
|
async fn count<T: ?Sized + ToStatement + Sync + Send + std::fmt::Debug>(
|
||||||
client: &impl GenericClient,
|
client: &impl GenericClient,
|
||||||
statement: &T,
|
statement: &T,
|
||||||
params: &[&(dyn ToSql + Sync)],
|
params: &[&(dyn ToSql + Sync)],
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use crate::api::{Pagination, RequestPagination};
|
|||||||
|
|
||||||
use super::{User, account::ReducedAccountInfo};
|
use super::{User, account::ReducedAccountInfo};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[cfg_attr(feature = "schemas", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemas", derive(schemars::JsonSchema))]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
|
|||||||
@ -100,21 +100,14 @@ impl User {
|
|||||||
let stmt = client
|
let stmt = client
|
||||||
.prepare_cached("select id,name from users limit $1 offset $2")
|
.prepare_cached("select id,name from users limit $1 offset $2")
|
||||||
.await?;
|
.await?;
|
||||||
let stmt_count = client
|
let stmt_count = client.prepare_cached("select count(*) from users").await?;
|
||||||
.prepare_cached("select count(*) from users limit $1 offset $2")
|
|
||||||
.await?;
|
|
||||||
let users = client
|
let users = client
|
||||||
.query(&stmt, &[&pagination.limit(), &pagination.offset()])
|
.query(&stmt, &[&pagination.limit(), &pagination.offset()])
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(User::from)
|
.map(User::from)
|
||||||
.collect();
|
.collect();
|
||||||
let count = count(
|
let count = count(client, &stmt_count, &[]).await?;
|
||||||
client,
|
|
||||||
&stmt_count,
|
|
||||||
&[&pagination.limit(), &pagination.offset()],
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
Ok(Pagination::new(users, count, pagination))
|
Ok(Pagination::new(users, count, pagination))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
tests/integration/account-list.hurl
Normal file
25
tests/integration/account-list.hurl
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
POST {{host}}/api/login
|
||||||
|
{
|
||||||
|
"name": "user1",
|
||||||
|
"password": "this-is-a-password"
|
||||||
|
}
|
||||||
|
HTTP 200
|
||||||
|
|
||||||
|
[Captures]
|
||||||
|
token: jsonpath "$.token"
|
||||||
|
|
||||||
|
GET {{host}}/api/accounts?limit=50
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
HTTP 200
|
||||||
|
[Asserts]
|
||||||
|
jsonpath "$.pagination.total" == 7
|
||||||
|
jsonpath "$.pagination.limit" == 50
|
||||||
|
jsonpath "$.pagination.offset" == 0
|
||||||
|
jsonpath "$.result" isCollection
|
||||||
|
jsonpath "$.result[0].name" == "user1"
|
||||||
|
jsonpath "$.result[1].name" == "user2"
|
||||||
|
jsonpath "$.result[2].name" == "user3"
|
||||||
|
jsonpath "$.result[3].name" == "user4"
|
||||||
|
jsonpath "$.result[4].name" == "user5"
|
||||||
|
jsonpath "$.result[5].name" == "user6"
|
||||||
|
jsonpath "$.result[6].name" == "test-user"
|
||||||
@ -18,3 +18,10 @@ POST {{host}}/api/login
|
|||||||
"password": "this-is-a-test"
|
"password": "this-is-a-test"
|
||||||
}
|
}
|
||||||
HTTP 200
|
HTTP 200
|
||||||
|
|
||||||
|
[Captures]
|
||||||
|
token: jsonpath "$.token"
|
||||||
|
|
||||||
|
GET {{host}}/api/users/@me
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
HTTP 200
|
||||||
|
|||||||
25
tests/integration/user-list.hurl
Normal file
25
tests/integration/user-list.hurl
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
POST {{host}}/api/login
|
||||||
|
{
|
||||||
|
"name": "user1",
|
||||||
|
"password": "this-is-a-password"
|
||||||
|
}
|
||||||
|
HTTP 200
|
||||||
|
|
||||||
|
[Captures]
|
||||||
|
token: jsonpath "$.token"
|
||||||
|
|
||||||
|
GET {{host}}/api/users?limit=50
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
HTTP 200
|
||||||
|
[Asserts]
|
||||||
|
jsonpath "$.pagination.total" == 7
|
||||||
|
jsonpath "$.pagination.limit" == 50
|
||||||
|
jsonpath "$.pagination.offset" == 0
|
||||||
|
jsonpath "$.result" isCollection
|
||||||
|
jsonpath "$.result[0].name" == "user1"
|
||||||
|
jsonpath "$.result[1].name" == "user2"
|
||||||
|
jsonpath "$.result[2].name" == "user3"
|
||||||
|
jsonpath "$.result[3].name" == "user4"
|
||||||
|
jsonpath "$.result[4].name" == "user5"
|
||||||
|
jsonpath "$.result[5].name" == "user6"
|
||||||
|
jsonpath "$.result[6].name" == "test-user"
|
||||||
Loading…
x
Reference in New Issue
Block a user