mirror of
https://git.dirksys.ovh/dirk/bankserver.git
synced 2025-12-20 02:59:20 +01:00
implement custom data
This commit is contained in:
parent
efa8332f33
commit
975fc1d567
6
migrations/000002_user_data.sql
Normal file
6
migrations/000002_user_data.sql
Normal file
@ -0,0 +1,6 @@
|
||||
create table user_data(
|
||||
owner uuid not null references users(id) on delete cascade,
|
||||
"user" uuid not null references users(id) on delete cascade,
|
||||
data jsonb not null,
|
||||
primary key (owner, "user")
|
||||
);
|
||||
@ -125,6 +125,42 @@ paths:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
default:
|
||||
$ref: '#/components/responses/Default'
|
||||
/api/users/@me/data:
|
||||
get:
|
||||
operationId: self-get-data
|
||||
summary: User data
|
||||
tags:
|
||||
- Users
|
||||
security:
|
||||
- bearer: []
|
||||
responses:
|
||||
200:
|
||||
description: Ok
|
||||
content:
|
||||
application/json:
|
||||
schema: {}
|
||||
401:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
default:
|
||||
$ref: '#/components/responses/Default'
|
||||
post:
|
||||
operationId: self-set-data
|
||||
summary: Set User data
|
||||
tags:
|
||||
- Users
|
||||
security:
|
||||
- bearer: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema: {}
|
||||
responses:
|
||||
200:
|
||||
description: Ok
|
||||
401:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
default:
|
||||
$ref: '#/components/responses/Default'
|
||||
/api/users/@me/balance:
|
||||
get:
|
||||
operationId: self-get-balance
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::{
|
||||
Router,
|
||||
|
||||
@ -21,6 +21,7 @@ pub(super) fn router() -> Router<Arc<AppState>> {
|
||||
Router::new()
|
||||
.route("/{target}", get(user_info))
|
||||
.route("/@me/balance", get(user_balance))
|
||||
.route("/@me/data", get(get_user_data).post(set_user_data))
|
||||
.route("/@me/accounts", get(user_accounts))
|
||||
.route("/@me/transactions", get(me_transaction_history))
|
||||
.route("/", get(list_users))
|
||||
@ -100,6 +101,32 @@ pub async fn user_accounts(EState(state): State, auth: Auth) -> Result<Json<User
|
||||
Ok(Json(UserAccounts { result }))
|
||||
}
|
||||
|
||||
#[instrument(skip(state))]
|
||||
pub async fn get_user_data(
|
||||
EState(state): State,
|
||||
auth: Auth,
|
||||
) -> Result<Json<Option<serde_json::Value>>, Error> {
|
||||
let user = auth.user_id();
|
||||
let conn = state.conn().await?;
|
||||
let data = Users::get_data(&conn, user).await?;
|
||||
Ok(Json(data))
|
||||
}
|
||||
|
||||
#[instrument(skip(state))]
|
||||
pub async fn set_user_data(
|
||||
EState(state): State,
|
||||
auth: Auth,
|
||||
Json(body): Json<Option<serde_json::Value>>,
|
||||
) -> Result<(), Error> {
|
||||
let user = auth.user_id();
|
||||
let mut conn = state.conn().await?;
|
||||
match body {
|
||||
Some(data) => Users::set_data(&mut conn, user, data).await?,
|
||||
None => Users::delete_data(&mut conn, user).await?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use uuid::Uuid;
|
||||
|
||||
@ -120,4 +120,38 @@ impl Users {
|
||||
let info = client.query_opt(&stmt, &[&id]).await?.map(user_from_row);
|
||||
Ok(info)
|
||||
}
|
||||
|
||||
pub async fn get_data(
|
||||
client: &impl GenericClient,
|
||||
user: Uuid,
|
||||
) -> Result<Option<serde_json::Value>, tokio_postgres::Error> {
|
||||
let stmt = client
|
||||
.prepare_cached("select data from user_data where owner = $1 and \"user\" = $1")
|
||||
.await?;
|
||||
let res = client.query_opt(&stmt, &[&user]).await?;
|
||||
Ok(res.map(|row| row.get(0)))
|
||||
}
|
||||
|
||||
pub async fn set_data(
|
||||
client: &mut impl GenericClient,
|
||||
user: Uuid,
|
||||
data: serde_json::Value,
|
||||
) -> Result<(), tokio_postgres::Error> {
|
||||
let stmt = client
|
||||
.prepare_cached("insert into user_data(owner, \"user\", data) values ($1, $1, $2) on conflict (owner, \"user\") do update set data = $2")
|
||||
.await?;
|
||||
client.execute(&stmt, &[&user, &data]).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_data(
|
||||
client: &mut impl GenericClient,
|
||||
user: Uuid,
|
||||
) -> Result<(), tokio_postgres::Error> {
|
||||
let stmt = client
|
||||
.prepare_cached("delete from user_data where \"owner\" = $1 and user = $2")
|
||||
.await?;
|
||||
client.execute(&stmt, &[&user]).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
23
tests/integration/user_data.hurl
Normal file
23
tests/integration/user_data.hurl
Normal file
@ -0,0 +1,23 @@
|
||||
POST {{host}}/api/login
|
||||
{
|
||||
"name": "user1",
|
||||
"password": "this-is-a-password"
|
||||
}
|
||||
HTTP 200
|
||||
|
||||
[Captures]
|
||||
token: jsonpath "$.token"
|
||||
|
||||
POST {{host}}/api/users/@me/data
|
||||
Authorization: Bearer {{token}}
|
||||
{
|
||||
"hello": "world"
|
||||
}
|
||||
HTTP 200
|
||||
|
||||
GET {{host}}/api/users/@me/data
|
||||
Authorization: Bearer {{token}}
|
||||
HTTP 200
|
||||
|
||||
[Asserts]
|
||||
jsonpath "$.hello" == "world"
|
||||
Loading…
x
Reference in New Issue
Block a user