Create endpoint to fetch all accounts for a user
This commit is contained in:
parent
8005bb6800
commit
2bdb3ff67a
8 changed files with 177 additions and 9 deletions
|
@ -4,7 +4,7 @@ use tracing::error;
|
|||
use crate::models::AppError;
|
||||
|
||||
use super::{
|
||||
associate_account_with_user_as_owner, AccountType, DbPool, PermissionEntity, StatusType,
|
||||
AccountType, DbPool, PermissionEntity, StatusType, associate_account_with_user_as_owner,
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
@ -27,6 +27,18 @@ pub struct AccountEntity {
|
|||
pub status: StatusType,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Default, FromRow)]
|
||||
pub struct AccountWithPermissionValueEntity {
|
||||
pub id: i32,
|
||||
pub account_type: AccountType,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub currency_code: String,
|
||||
pub permission_name: String,
|
||||
pub permission_value: i32,
|
||||
}
|
||||
|
||||
pub async fn insert_new_account_for_user(
|
||||
pool: &DbPool,
|
||||
new_account: NewAccountEntity,
|
||||
|
@ -53,3 +65,63 @@ pub async fn insert_new_account_for_user(
|
|||
|
||||
Ok((new_account, account_permissions))
|
||||
}
|
||||
|
||||
pub async fn get_all_accounts_for_user(
|
||||
pool: &DbPool,
|
||||
user_id: i32,
|
||||
) -> Result<Vec<AccountWithPermissionValueEntity>, AppError> {
|
||||
sqlx::query_as::<_, AccountWithPermissionValueEntity>(
|
||||
"SELECT
|
||||
a.id AS id,
|
||||
a.account_type AS account_type,
|
||||
a.name AS name,
|
||||
a.description AS description,
|
||||
a.currency_code AS currency_code,
|
||||
p.name AS permission_name,
|
||||
p.value AS permission_value
|
||||
FROM
|
||||
public.account a
|
||||
INNER JOIN public.user_account_permission uap ON a.id = uap.account_id
|
||||
INNER JOIN public.permission p ON uap.permission_id = p.id
|
||||
WHERE
|
||||
uap.user_id = $1
|
||||
ORDER BY
|
||||
a.id,
|
||||
p.value;",
|
||||
)
|
||||
.bind(user_id)
|
||||
.fetch_all(pool)
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
error!(
|
||||
?err,
|
||||
user_id, "Cannot fetch permission values for the user's accounts"
|
||||
)
|
||||
})
|
||||
.map_err(AppError::from)
|
||||
.map(|all_accounts| {
|
||||
all_accounts
|
||||
.chunk_by(|a, b| a.id == b.id)
|
||||
.map(|accounts| {
|
||||
accounts.into_iter().fold(
|
||||
AccountWithPermissionValueEntity::default(),
|
||||
|acc, entity| AccountWithPermissionValueEntity {
|
||||
id: entity.id,
|
||||
account_type: entity.account_type,
|
||||
name: entity.name.clone(),
|
||||
description: entity.description.clone(),
|
||||
currency_code: entity.currency_code.clone(),
|
||||
permission_name: acc
|
||||
.permission_name
|
||||
.split('|')
|
||||
.filter(|name| !name.is_empty())
|
||||
.chain([entity.permission_name.as_str()])
|
||||
.collect::<Vec<_>>()
|
||||
.join("|"),
|
||||
permission_value: acc.permission_value + entity.permission_value,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, sqlx::Type,
|
||||
Clone, Copy, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, sqlx::Type,
|
||||
)]
|
||||
#[sqlx(type_name = "account_type", rename_all = "PascalCase")]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AccountType {
|
||||
#[default]
|
||||
Asset,
|
||||
Equity,
|
||||
Expense,
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
use axum::{
|
||||
debug_handler,
|
||||
Json, debug_handler,
|
||||
extract::State,
|
||||
response::{IntoResponse, Response},
|
||||
Json,
|
||||
};
|
||||
use http::StatusCode;
|
||||
|
||||
use crate::{
|
||||
db::{insert_new_account_for_user, DbPool, NewAccountEntity},
|
||||
db::{DbPool, NewAccountEntity, insert_new_account_for_user},
|
||||
models::{AppError, Session},
|
||||
requests::AppState,
|
||||
};
|
||||
|
@ -23,13 +22,13 @@ pub async fn account_creation_post_handler(
|
|||
let pool = state.db_pool();
|
||||
let user_id = session.user_id;
|
||||
|
||||
account_creation_request(request, user_id, pool).await
|
||||
account_creation_request(pool, user_id, request).await
|
||||
}
|
||||
|
||||
async fn account_creation_request(
|
||||
request: AccountCreationRequest,
|
||||
user_id: i32,
|
||||
pool: &DbPool,
|
||||
user_id: i32,
|
||||
request: AccountCreationRequest,
|
||||
) -> Result<Response, AppError> {
|
||||
let AccountCreationRequest {
|
||||
r#type: account_type,
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
mod create;
|
||||
mod read;
|
||||
|
||||
use axum::{routing::post, Router};
|
||||
use axum::{
|
||||
Router,
|
||||
routing::{get, post},
|
||||
};
|
||||
use create::account_creation_post_handler;
|
||||
use read::account_read_all_get_request;
|
||||
|
||||
use super::AppState;
|
||||
|
||||
|
@ -10,6 +15,7 @@ pub fn requests(state: AppState) -> Router {
|
|||
"/account",
|
||||
Router::new()
|
||||
.route("/", post(account_creation_post_handler))
|
||||
.route("/", get(account_read_all_get_request))
|
||||
.with_state(state),
|
||||
)
|
||||
}
|
||||
|
|
45
api/src/requests/account/read/handler.rs
Normal file
45
api/src/requests/account/read/handler.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use axum::{
|
||||
Json, debug_handler,
|
||||
extract::State,
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use http::StatusCode;
|
||||
|
||||
use crate::{
|
||||
db::{DbPool, get_all_accounts_for_user},
|
||||
models::{ApiResponse, AppError, Session},
|
||||
requests::AppState,
|
||||
};
|
||||
|
||||
use super::models::AccountsReadAllResponse;
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn account_read_all_get_request(
|
||||
State(state): State<AppState>,
|
||||
session: Session,
|
||||
) -> Result<Response, AppError> {
|
||||
let pool = state.db_pool();
|
||||
let user_id = session.user_id;
|
||||
|
||||
account_read_all_request(pool, user_id)
|
||||
.await
|
||||
.map(|(status_code, response)| {
|
||||
(status_code, Json(ApiResponse::new(response))).into_response()
|
||||
})
|
||||
}
|
||||
|
||||
async fn account_read_all_request(
|
||||
pool: &DbPool,
|
||||
user_id: i32,
|
||||
) -> Result<(StatusCode, Vec<AccountsReadAllResponse>), AppError> {
|
||||
let accounts = get_all_accounts_for_user(pool, user_id)
|
||||
.await
|
||||
.map(|accounts| {
|
||||
accounts
|
||||
.into_iter()
|
||||
.map(AccountsReadAllResponse::from)
|
||||
.collect::<Vec<_>>()
|
||||
})?;
|
||||
|
||||
Ok((StatusCode::OK, accounts))
|
||||
}
|
4
api/src/requests/account/read/mod.rs
Normal file
4
api/src/requests/account/read/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
mod handler;
|
||||
mod models;
|
||||
|
||||
pub use handler::*;
|
3
api/src/requests/account/read/models/mod.rs
Normal file
3
api/src/requests/account/read/models/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
mod response;
|
||||
|
||||
pub use response::*;
|
38
api/src/requests/account/read/models/response.rs
Normal file
38
api/src/requests/account/read/models/response.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::db::{AccountType, AccountWithPermissionValueEntity};
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct AccountsReadAllResponse {
|
||||
pub id: i32,
|
||||
pub account_type: AccountType,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub currency_code: String,
|
||||
pub permission_name: String,
|
||||
pub permission_value: i32,
|
||||
}
|
||||
|
||||
impl From<AccountWithPermissionValueEntity> for AccountsReadAllResponse {
|
||||
fn from(other: AccountWithPermissionValueEntity) -> Self {
|
||||
let AccountWithPermissionValueEntity {
|
||||
id,
|
||||
account_type,
|
||||
name,
|
||||
description,
|
||||
currency_code,
|
||||
permission_name,
|
||||
permission_value,
|
||||
} = other;
|
||||
|
||||
Self {
|
||||
id,
|
||||
account_type,
|
||||
name,
|
||||
description,
|
||||
currency_code,
|
||||
permission_name,
|
||||
permission_value,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue