diff --git a/moneymgr_backend/src/controllers/accounts_controller.rs b/moneymgr_backend/src/controllers/accounts_controller.rs index c6b1787..dc64400 100644 --- a/moneymgr_backend/src/controllers/accounts_controller.rs +++ b/moneymgr_backend/src/controllers/accounts_controller.rs @@ -1,5 +1,6 @@ use crate::controllers::HttpResult; use crate::controllers::server_controller::ServerConstraints; +use crate::extractors::account_extractor::AccountInPath; use crate::extractors::auth_extractor::AuthExtractor; use crate::services::accounts_service; use crate::services::accounts_service::UpdateAccountQuery; @@ -33,3 +34,8 @@ pub async fn create(auth: AuthExtractor, req: web::Json) - pub async fn get_list(auth: AuthExtractor) -> HttpResult { Ok(HttpResponse::Ok().json(accounts_service::get_list_user(auth.user_id()).await?)) } + +/// Get a single account +pub async fn get_single(account: AccountInPath) -> HttpResult { + Ok(HttpResponse::Ok().json(account.as_ref())) +} diff --git a/moneymgr_backend/src/extractors/account_extractor.rs b/moneymgr_backend/src/extractors/account_extractor.rs new file mode 100644 index 0000000..3cc4575 --- /dev/null +++ b/moneymgr_backend/src/extractors/account_extractor.rs @@ -0,0 +1,64 @@ +use crate::extractors::auth_extractor::AuthExtractor; +use crate::models::accounts::{Account, AccountID}; +use crate::services::accounts_service; +use actix_web::dev::Payload; +use actix_web::{FromRequest, HttpRequest}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct AccountIdInPath { + account_id: AccountID, +} + +#[derive(thiserror::Error, Debug)] +enum AccountExtractorError { + #[error("Current user does not own the account!")] + UserDoesNotOwnAccount, +} + +pub struct AccountInPath(Account); + +impl AccountInPath { + pub async fn load_account_from_path( + auth: &AuthExtractor, + id: AccountID, + ) -> anyhow::Result { + let account = accounts_service::get_by_id(id).await?; + + if account.user_id() != auth.user_id() { + return Err(AccountExtractorError::UserDoesNotOwnAccount.into()); + } + + Ok(Self(account)) + } +} + +impl FromRequest for AccountInPath { + 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? + .account_id; + + Self::load_account_from_path(&auth, account_id) + .await + .map_err(|e| { + log::error!("Failed to extract account ID from URL! {}", e); + actix_web::error::ErrorNotFound("Could not fetch account information!") + }) + }) + } +} + +impl AsRef for AccountInPath { + fn as_ref(&self) -> &Account { + &self.0 + } +} diff --git a/moneymgr_backend/src/extractors/mod.rs b/moneymgr_backend/src/extractors/mod.rs index 216d78a..f219368 100644 --- a/moneymgr_backend/src/extractors/mod.rs +++ b/moneymgr_backend/src/extractors/mod.rs @@ -1,2 +1,3 @@ +pub mod account_extractor; pub mod auth_extractor; pub mod money_session; diff --git a/moneymgr_backend/src/main.rs b/moneymgr_backend/src/main.rs index e79167c..0954f21 100644 --- a/moneymgr_backend/src/main.rs +++ b/moneymgr_backend/src/main.rs @@ -91,25 +91,26 @@ async fn main() -> std::io::Result<()> { web::get().to(auth_controller::sign_out), ) // Tokens controller - .route("/api/tokens", web::post().to(tokens_controller::create)) + .route("/api/token", web::post().to(tokens_controller::create)) + .route("/api/tokens", web::get().to(tokens_controller::get_list)) .route( - "/api/tokens/list", - web::get().to(tokens_controller::get_list), - ) - .route( - "/api/tokens/{id}", + "/api/token/{id}", web::delete().to(tokens_controller::delete), ) // Accounts controller - .route("/api/accounts", web::post().to(accounts_controller::create)) + .route("/api/account", web::post().to(accounts_controller::create)) .route( - "/api/accounts/list", + "/api/accounts", web::get().to(accounts_controller::get_list), ) + .route( + "/api/account/{account_id}", + web::get().to(accounts_controller::get_single), + ) // TODO : update account //TODO /*.route( - "/api/accounts/{id}", + "/api/accounts/{account_id}", web::delete().to(accounts_controller::delete), )*/ // TODO : set as default diff --git a/moneymgr_web/src/api/TokensApi.ts b/moneymgr_web/src/api/TokensApi.ts index d7705a0..bd1b0cb 100644 --- a/moneymgr_web/src/api/TokensApi.ts +++ b/moneymgr_web/src/api/TokensApi.ts @@ -39,7 +39,7 @@ export class TokensApi { static async GetList(): Promise { return ( await APIClient.exec({ - uri: "/tokens/list", + uri: "/tokens", method: "GET", }) ).data; @@ -51,7 +51,7 @@ export class TokensApi { static async Create(t: NewToken): Promise { return ( await APIClient.exec({ - uri: "/tokens", + uri: "/token", method: "POST", jsonData: t, }) @@ -63,7 +63,7 @@ export class TokensApi { */ static async Delete(t: Token): Promise { await APIClient.exec({ - uri: `/tokens/${t.id}`, + uri: `/token/${t.id}`, method: "DELETE", }); }