From 89ffb558ac228f8c65de8bcc6ba3b93af848c738 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Sat, 19 Apr 2025 21:57:19 +0200 Subject: [PATCH] Can get a single movement information --- .../src/controllers/movement_controller.rs | 6 ++ moneymgr_backend/src/extractors/mod.rs | 1 + .../src/extractors/movement_extractor.rs | 71 +++++++++++++++++++ moneymgr_backend/src/main.rs | 4 ++ 4 files changed, 82 insertions(+) create mode 100644 moneymgr_backend/src/extractors/movement_extractor.rs diff --git a/moneymgr_backend/src/controllers/movement_controller.rs b/moneymgr_backend/src/controllers/movement_controller.rs index 4f5663c..21cd309 100644 --- a/moneymgr_backend/src/controllers/movement_controller.rs +++ b/moneymgr_backend/src/controllers/movement_controller.rs @@ -1,6 +1,7 @@ use crate::controllers::HttpResult; use crate::extractors::account_extractor::AccountInPath; use crate::extractors::auth_extractor::AuthExtractor; +use crate::extractors::movement_extractor::MovementInPath; use crate::services::movements_service; use crate::services::movements_service::UpdateMovementQuery; use actix_web::{HttpResponse, web}; @@ -21,3 +22,8 @@ pub async fn get_list_of_account(account_id: AccountInPath) -> HttpResult { Ok(HttpResponse::Ok() .json(movements_service::get_list_account(account_id.as_ref().id()).await?)) } + +/// Get a single movement information +pub async fn get_single(movement: MovementInPath) -> HttpResult { + Ok(HttpResponse::Ok().json(movement.movement())) +} diff --git a/moneymgr_backend/src/extractors/mod.rs b/moneymgr_backend/src/extractors/mod.rs index 1f63609..f584e3a 100644 --- a/moneymgr_backend/src/extractors/mod.rs +++ b/moneymgr_backend/src/extractors/mod.rs @@ -3,3 +3,4 @@ pub mod auth_extractor; pub mod file_extractor; pub mod file_id_extractor; pub mod money_session; +pub mod movement_extractor; diff --git a/moneymgr_backend/src/extractors/movement_extractor.rs b/moneymgr_backend/src/extractors/movement_extractor.rs new file mode 100644 index 0000000..c2decab --- /dev/null +++ b/moneymgr_backend/src/extractors/movement_extractor.rs @@ -0,0 +1,71 @@ +use crate::extractors::auth_extractor::AuthExtractor; +use crate::models::accounts::Account; +use crate::models::movements::{Movement, MovementID}; +use crate::services::{accounts_service, movements_service}; +use actix_web::dev::Payload; +use actix_web::{FromRequest, HttpRequest}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct MovementIdInPath { + movement_id: MovementID, +} + +#[derive(thiserror::Error, Debug)] +enum AccountExtractorError { + #[error("Current user does not own the account associated to this movement!")] + UserDoesNotOwnAccount, +} + +pub struct MovementInPath(Account, Movement); + +impl MovementInPath { + async fn load_movement_from_path(auth: &AuthExtractor, id: MovementID) -> anyhow::Result { + let movement = movements_service::get_by_id(id).await?; + + let account = accounts_service::get_by_id(movement.account_id()).await?; + + if account.user_id() != auth.user_id() { + return Err(AccountExtractorError::UserDoesNotOwnAccount.into()); + } + + Ok(Self(account, movement)) + } + + pub fn account(&self) -> &Account { + &self.0 + } + pub fn movement(&self) -> &Movement { + &self.1 + } +} + +impl FromRequest for MovementInPath { + type Error = actix_web::Error; + type Future = futures_util::future::LocalBoxFuture<'static, Result>; + + fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future { + let req = req.clone(); + Box::pin(async move { + let auth = AuthExtractor::extract(&req).await?; + + let account_id = + actix_web::web::Path::::from_request(&req, &mut Payload::None) + .await? + .movement_id; + + Self::load_movement_from_path(&auth, account_id) + .await + .map_err(|e| { + log::error!("Failed to extract movement ID from URL! {}", e); + actix_web::error::ErrorNotFound("Could not fetch movement information!") + }) + }) + } +} + +impl AsRef for MovementInPath { + fn as_ref(&self) -> &Movement { + &self.1 + } +} diff --git a/moneymgr_backend/src/main.rs b/moneymgr_backend/src/main.rs index f5279ef..542c21b 100644 --- a/moneymgr_backend/src/main.rs +++ b/moneymgr_backend/src/main.rs @@ -135,6 +135,10 @@ async fn main() -> std::io::Result<()> { "/api/account/{account_id}/movements", web::get().to(movement_controller::get_list_of_account), ) + .route( + "/api/movement/{movement_id}", + web::get().to(movement_controller::get_single), + ) // Static assets .route("/", web::get().to(static_controller::root_index)) .route(