From 8e81b8c4e7e40ffb479dd80a051193a6704fa577 Mon Sep 17 00:00:00 2001 From: Ben White Date: Mon, 5 Feb 2024 17:39:39 +1100 Subject: [PATCH 1/8] mod: impl FromRequest for middleware --- Cargo.lock | 72 ++++++++++++++++++++--------------- Cargo.toml | 3 ++ src/guards.rs | 47 +++++++++++++++++++++++ src/main.rs | 29 ++++++++------ src/methods/common.rs | 18 ++++++++- src/methods/kiosk/handlers.rs | 40 +++++++------------ src/methods/mod.rs | 2 +- 7 files changed, 141 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a6e68c6..13d14df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,7 +192,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -203,7 +203,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -338,7 +338,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", "syn_derive", ] @@ -460,7 +460,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -724,7 +724,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics 0.10.0", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -802,7 +802,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -1003,7 +1003,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -1392,7 +1392,7 @@ checksum = "ce243b1bfa62ffc028f1cc3b6034ec63d649f3031bc8a4fbbb004e1ac17d1f68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -1544,6 +1544,15 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "macro_test" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1762,6 +1771,7 @@ dependencies = [ "futures", "geo", "lazy_static", + "macro_test", "okapi", "photon-geocoding", "rand", @@ -1806,7 +1816,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -1857,7 +1867,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -1915,7 +1925,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics 0.10.0", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -1961,7 +1971,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -2057,9 +2067,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -2085,7 +2095,7 @@ checksum = "606c4ba35817e2922a308af55ad51bab3645b59eae5c570d4a6cf07e36bd493b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", "version_check", "yansi 0.5.1", ] @@ -2112,9 +2122,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -2181,7 +2191,7 @@ checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -2360,7 +2370,7 @@ dependencies = [ "proc-macro2", "quote", "rocket_http", - "syn 2.0.32", + "syn 2.0.48", "unicode-xid", "version_check", ] @@ -2652,7 +2662,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -2710,7 +2720,7 @@ dependencies = [ "proc-macro2", "quote", "sea-bae", - "syn 2.0.32", + "syn 2.0.48", "unicode-ident", ] @@ -2873,7 +2883,7 @@ checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -3322,9 +3332,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.32" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -3340,7 +3350,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -3380,7 +3390,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -3461,7 +3471,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -3571,7 +3581,7 @@ checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] @@ -3854,7 +3864,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -3876,7 +3886,7 @@ checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4135,7 +4145,7 @@ checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.48", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a365fe9..7de032e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,6 +59,9 @@ okapi = { version = "0.7.0", features = ["impl_json_schema"] } rocket-validation = { version = "0.1.4", git = "https://github.com/bennjii/rocket-validation.git", branch = "main" } validator="0.16.1" +# Automations +macro_test = { path = "../../macro_test" } + [features] types = [] process = [ diff --git a/src/guards.rs b/src/guards.rs index 75a7a5b..93efa2b 100644 --- a/src/guards.rs +++ b/src/guards.rs @@ -1,10 +1,17 @@ +use futures::TryStreamExt; use rocket::{ data::{self, Data, FromData, Limits}, http::Status, request::{local_cache, Request}, }; +use rocket::request::{FromRequest, Outcome}; +use rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput}; +use rocket_db_pools::Connection; +use rocket_okapi::gen::OpenApiGenerator; use serde::{Deserialize, Serialize}; use uuid::Uuid; +use crate::methods::common::Error; +use crate::{cookie_status_wrapper, Db, ErrorResponse, Session}; #[derive(Copy, Clone, Debug)] pub struct RequestId(pub Option); @@ -55,4 +62,44 @@ impl<'r, T> FromData<'r> for JsonValidation } } } +} + +pub struct SessionReference(pub Session); + +impl<'r> OpenApiFromRequest<'r> for SessionReference { + fn from_request_input( + _gen: &mut OpenApiGenerator, + _name: String, + _required: bool, + ) -> rocket_okapi::Result { + Ok(RequestHeaderInput::None) + } +} + +#[rocket::async_trait] +impl<'r> FromRequest<'r> for SessionReference { // &'r + type Error = Error; + + async fn from_request(request: &'r Request<'_>) -> Outcome { + let cookies = request.cookies(); + + let db = match request.guard::>().await { + Outcome::Success(s) => s, + Outcome::Error(e) => { + let err = match e.1 { + Some(v) => ErrorResponse::db_err(v), + None => ErrorResponse::create_error("") + }; + + return Outcome::Error((e.0, err)) + }, + Outcome::Forward(f) => return Outcome::Forward(f) + }; + + match cookie_status_wrapper(&db, cookies).await { + Ok(session) => Outcome::Success(SessionReference(session)), + Err(error) => Outcome::Forward(Status::Unauthorized) + } + + } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e73a2ab..321333e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,18 +2,17 @@ #[cfg(feature = "sql")] use pool::Db; +use rocket::http::{Method, Status}; #[cfg(feature = "sql")] use rocket::{ fairing::{Fairing, Info, Kind}, http::Header, *, }; -use rocket::http::{Method, Status}; use rocket_db_pools::Database; use rocket_okapi::mount_endpoints_and_merged_docs; use rocket_okapi::swagger_ui::{make_swagger_ui, SwaggerUIConfig}; #[cfg(feature = "process")] - #[cfg(feature = "process")] pub mod entities; pub mod methods; @@ -22,12 +21,14 @@ pub mod migrator; #[cfg(feature = "process")] pub mod pool; +pub mod guards; + #[cfg(feature = "sql")] pub use entities::*; pub use methods::*; #[cfg(feature = "sql")] pub use migrator::*; -use open_stock::{catchers}; +use open_stock::catchers; #[cfg(feature = "sql")] extern crate argon2; @@ -58,7 +59,10 @@ impl Fairing for CORS { if request.method() == Method::Options { response.set_status(Status::Ok); - response.set_header(Header::new("Access-Control-Allow-Headers", "Content-Type, Referer, *")); + response.set_header(Header::new( + "Access-Control-Allow-Headers", + "Content-Type, Referer, *", + )); } } } @@ -70,13 +74,16 @@ fn rocket() -> _ { // All non-documented items attached here. let mut launcher = build() - .register("/", catchers![ - catchers::not_authorized, - catchers::internal_server_error, - catchers::not_found, - catchers::unprocessable_entry, - catchers::general_catcher, - ]) + .register( + "/", + catchers![ + catchers::not_authorized, + catchers::internal_server_error, + catchers::not_found, + catchers::unprocessable_entry, + catchers::general_catcher, + ], + ) .attach(Db::init()) .attach(CORS) .mount( diff --git a/src/methods/common.rs b/src/methods/common.rs index c1687d2..66b7a2c 100644 --- a/src/methods/common.rs +++ b/src/methods/common.rs @@ -229,7 +229,7 @@ pub enum SessionVariant { AccessToken, } -#[derive(Debug, Clone, JsonSchema, Validate)] +#[derive(Debug, Clone, JsonSchema, Validate, Serialize, Deserialize)] pub struct Session { pub id: String, pub key: String, @@ -450,6 +450,22 @@ impl From for Error { } } +impl> From> for Error { + fn from(value: Option) -> Self where T: Into { + match value { + Some(err) => err.into(), + None => ErrorResponse::create_error("Unable to retrieve database instance.") + } + } +} + +struct Wrapper(T); +impl Into> for Wrapper { + fn into(self) -> Json { + Json(self.0) + } +} + #[cfg(feature = "process")] #[derive(Debug, Responder)] pub enum Error { diff --git a/src/methods/kiosk/handlers.rs b/src/methods/kiosk/handlers.rs index 7a2ccba..69f22f6 100644 --- a/src/methods/kiosk/handlers.rs +++ b/src/methods/kiosk/handlers.rs @@ -1,14 +1,15 @@ -use okapi::openapi3::OpenApi; +use crate::catchers::Validated; use crate::methods::{Error, ErrorResponse}; use crate::pool::Db; use crate::{AuthenticationLog, Kiosk, KioskInit, KioskPreferences}; +use okapi::openapi3::OpenApi; +use crate::guards::SessionReference; use rocket::http::CookieJar; use rocket::serde::json::Json; use rocket::{get, post}; use rocket_db_pools::Connection; -use rocket_okapi::{openapi, openapi_get_routes_spec}; use rocket_okapi::settings::OpenApiSettings; -use crate::catchers::Validated; +use rocket_okapi::{openapi, openapi_get_routes_spec}; use crate::{ check_permissions, @@ -30,20 +31,12 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Kiosk")] #[get("/")] -pub async fn get( - conn: Connection, - id: &str, - cookies: &CookieJar<'_>, -) -> Result, Error> { +// #[guard(Action::FetchKiosk)] +pub async fn get(conn: Connection, id: &str, session: SessionReference) -> Result, Error> { let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; - check_permissions!(session.clone(), Action::FetchEmployee); - - match Kiosk::fetch_by_id(id, session, &db).await { - Ok(employee) => Ok(Json(employee)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Kiosk::fetch_by_id(id, session.0, &db).await + .map(|v| Json(v)) + .map_err(|v| ErrorResponse::db_err(v)) } #[openapi(tag = "Kiosk")] @@ -60,11 +53,10 @@ pub async fn initialize( check_permissions!(session.clone(), Action::AccessAdminPanel); match Kiosk::insert(input_data, session.clone(), &db, None).await { - Ok(kiosk) => - match Kiosk::fetch_by_id(&kiosk.last_insert_id, session, &db).await { - Ok(res) => Ok(Json(res)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - }, + Ok(kiosk) => match Kiosk::fetch_by_id(&kiosk.last_insert_id, session, &db).await { + Ok(res) => Ok(Json(res)), + Err(reason) => Err(ErrorResponse::db_err(reason)), + }, Err(err) => Err(ErrorResponse::db_err(err)), } } @@ -129,11 +121,7 @@ pub async fn update_online_status( #[openapi(tag = "Kiosk")] #[post("/delete/")] -pub async fn delete( - conn: Connection, - id: &str, - cookies: &CookieJar<'_>, -) -> Result<(), Error> { +pub async fn delete(conn: Connection, id: &str, cookies: &CookieJar<'_>) -> Result<(), Error> { let db = conn.into_inner(); let session = cookie_status_wrapper(&db, cookies).await?; diff --git a/src/methods/mod.rs b/src/methods/mod.rs index f31d4a5..a1ae14b 100644 --- a/src/methods/mod.rs +++ b/src/methods/mod.rs @@ -1,4 +1,4 @@ -mod common; +pub(crate) mod common; mod payment; mod stml; From 0b091603f379a8c66d062f01d319abb5372c05aa Mon Sep 17 00:00:00 2001 From: Ben White Date: Mon, 5 Feb 2024 21:31:37 +1100 Subject: [PATCH 2/8] mod: reformatted kiosk code --- src/catchers.rs | 6 ++ src/guards.rs | 49 +++++++++++---- src/methods/common.rs | 20 +++++++ src/methods/kiosk/handlers.rs | 110 +++++++++------------------------- src/methods/kiosk/structs.rs | 32 +++++----- src/methods/macros.rs | 2 +- src/pool.rs | 26 ++++---- 7 files changed, 124 insertions(+), 121 deletions(-) diff --git a/src/catchers.rs b/src/catchers.rs index 5aa4b86..d26ba51 100644 --- a/src/catchers.rs +++ b/src/catchers.rs @@ -27,6 +27,12 @@ use okapi::{ #[derive(Clone, Debug, JsonSchema)] pub struct Validated(pub T); +impl Validated> { + pub fn data(self) -> T { + self.clone().0.into_inner() + } +} + #[derive(Clone)] pub struct CachedValidationErrors(pub Option); diff --git a/src/guards.rs b/src/guards.rs index 93efa2b..31607b3 100644 --- a/src/guards.rs +++ b/src/guards.rs @@ -1,13 +1,13 @@ use futures::TryStreamExt; -use rocket::{ - data::{self, Data, FromData, Limits}, - http::Status, - request::{local_cache, Request}, -}; +use okapi::openapi3::Responses; +use rocket::{data::{self, Data, FromData, Limits}, http::Status, request::{local_cache, Request}, response}; use rocket::request::{FromRequest, Outcome}; +use rocket::response::Responder; +use rocket::serde::json::Json; use rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput}; use rocket_db_pools::Connection; use rocket_okapi::gen::OpenApiGenerator; +use rocket_okapi::response::OpenApiResponderInner; use serde::{Deserialize, Serialize}; use uuid::Uuid; use crate::methods::common::Error; @@ -64,9 +64,7 @@ impl<'r, T> FromData<'r> for JsonValidation } } -pub struct SessionReference(pub Session); - -impl<'r> OpenApiFromRequest<'r> for SessionReference { +impl<'r> OpenApiFromRequest<'r> for Session { fn from_request_input( _gen: &mut OpenApiGenerator, _name: String, @@ -77,7 +75,7 @@ impl<'r> OpenApiFromRequest<'r> for SessionReference { } #[rocket::async_trait] -impl<'r> FromRequest<'r> for SessionReference { // &'r +impl<'r> FromRequest<'r> for Session { // &'r type Error = Error; async fn from_request(request: &'r Request<'_>) -> Outcome { @@ -97,9 +95,38 @@ impl<'r> FromRequest<'r> for SessionReference { // &'r }; match cookie_status_wrapper(&db, cookies).await { - Ok(session) => Outcome::Success(SessionReference(session)), - Err(error) => Outcome::Forward(Status::Unauthorized) + Ok(session) => Outcome::Success(session), + Err(_) => Outcome::Forward(Status::Unauthorized) } + } +} + + +pub struct Convert(pub Result, Error>); + +impl From> for Convert { + fn from(value: Result) -> Self { + Convert(value.map(|v| Json(v))) + } +} +impl OpenApiResponderInner for Convert { + fn responses(_: &mut OpenApiGenerator) -> rocket_okapi::Result { + Ok(Responses::default()) + } +} + +impl<'r, 'o: 'r, K: Serialize> Responder<'r, 'o> for Convert { + fn respond_to(self, r: &'r Request<'_>) -> response::Result<'o> where K: Serialize { + Responder::respond_to(self.0, r) + } +} + +impl<'de, T: Deserialize<'de>> Into, Error>> for Convert { + fn into(self) -> Result, Error> { + match self.0 { + Ok(v) => Ok(v.into()), + Err(e) => Err(e.into()) + } } } \ No newline at end of file diff --git a/src/methods/common.rs b/src/methods/common.rs index 66b7a2c..75e94bb 100644 --- a/src/methods/common.rs +++ b/src/methods/common.rs @@ -486,3 +486,23 @@ impl OpenApiResponderInner for Error { Ok(Responses::default()) } } + +pub struct VoidableResult(pub Result); + +impl VoidableResult { + fn void(self) -> Result<(), Error> { + self.into() + } +} + +impl From> for VoidableResult { + fn from(value: Result) -> Self { + VoidableResult(value) + } +} + +impl Into> for VoidableResult { + fn into(self) -> Result<(), Error> { + self.0.map(|_| ()) + } +} \ No newline at end of file diff --git a/src/methods/kiosk/handlers.rs b/src/methods/kiosk/handlers.rs index 69f22f6..5f250c9 100644 --- a/src/methods/kiosk/handlers.rs +++ b/src/methods/kiosk/handlers.rs @@ -1,20 +1,17 @@ use crate::catchers::Validated; -use crate::methods::{Error, ErrorResponse}; -use crate::pool::Db; -use crate::{AuthenticationLog, Kiosk, KioskInit, KioskPreferences}; +use crate::methods::{Error}; +use crate::pool::{InternalDb}; +use crate::{AuthenticationLog, Kiosk, KioskInit, KioskPreferences, Session}; use okapi::openapi3::OpenApi; -use crate::guards::SessionReference; -use rocket::http::CookieJar; use rocket::serde::json::Json; use rocket::{get, post}; -use rocket_db_pools::Connection; use rocket_okapi::settings::OpenApiSettings; use rocket_okapi::{openapi, openapi_get_routes_spec}; - use crate::{ check_permissions, - methods::{cookie_status_wrapper, Action}, + methods::{Action}, }; +use crate::guards::Convert; pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, OpenApi) { openapi_get_routes_spec![ @@ -31,124 +28,75 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Kiosk")] #[get("/")] -// #[guard(Action::FetchKiosk)] -pub async fn get(conn: Connection, id: &str, session: SessionReference) -> Result, Error> { - let db = conn.into_inner(); - Kiosk::fetch_by_id(id, session.0, &db).await - .map(|v| Json(v)) - .map_err(|v| ErrorResponse::db_err(v)) +pub async fn get(db: InternalDb, id: &str, session: Session) -> Convert { + check_permissions!(session.clone(), Action::FetchKiosk); + Kiosk::fetch_by_id(id, session, &db.0).await.into() } #[openapi(tag = "Kiosk")] #[post("/", data = "")] pub async fn initialize( - conn: Connection, + db: InternalDb, input_data: Validated>, - cookies: &CookieJar<'_>, + session: Session, ) -> Result, Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::AccessAdminPanel); - match Kiosk::insert(input_data, session.clone(), &db, None).await { - Ok(kiosk) => match Kiosk::fetch_by_id(&kiosk.last_insert_id, session, &db).await { - Ok(res) => Ok(Json(res)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - }, - Err(err) => Err(ErrorResponse::db_err(err)), - } + let kiosk = Kiosk::insert(input_data.data(), session.clone(), &db.0, None).await?; + Kiosk::fetch_by_id(&kiosk.last_insert_id, session, &db.0).await.map(|v| Json(v)) } #[openapi(tag = "Kiosk")] #[post("/", data = "")] pub async fn update( - conn: Connection, + conn: InternalDb, id: &str, input_data: Validated>, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + session: Session, +) -> Convert { check_permissions!(session.clone(), Action::AccessAdminPanel); - match Kiosk::update(input_data, session, id, &db).await { - Ok(kiosk) => Ok(Json(kiosk)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Kiosk::update(input_data.data(), session, id, &conn.0).await.into() } #[openapi(tag = "Kiosk")] #[post("/preferences/", data = "")] pub async fn update_preferences( - conn: Connection, + db: InternalDb, id: &str, input_data: Validated>, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + session: Session, +) -> Convert { check_permissions!(session.clone(), Action::ModifyKioskPreferences); - - match Kiosk::update_preferences(id, session, input_data, &db).await { - Ok(kiosk) => Ok(Json(kiosk)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Kiosk::update_preferences(id, session, input_data.data(), &db.0).await.into() } #[openapi(tag = "Kiosk")] #[post("/online/")] pub async fn update_online_status( - conn: Connection, + db: InternalDb, id: &str, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + session: Session, +) -> Convert { check_permissions!(session.clone(), Action::FetchKiosk); - - match Kiosk::update_online_to_now(id, session, &db).await { - Ok(kiosk) => Ok(Json(kiosk)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Kiosk::update_online_to_now(id, session, &db.0).await.into() } #[openapi(tag = "Kiosk")] #[post("/delete/")] -pub async fn delete(conn: Connection, id: &str, cookies: &CookieJar<'_>) -> Result<(), Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +pub async fn delete(db: InternalDb, id: &str, session: Session) -> Result<(), Error> { check_permissions!(session.clone(), Action::AccessAdminPanel); - - match Kiosk::delete(id, session, &db).await { - Ok(_res) => Ok(()), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Kiosk::delete(id, session, &db.0).await.map(|_| ()) } #[openapi(tag = "Kiosk")] #[post("/log/", data = "")] pub async fn auth_log( - conn: Connection, + db: InternalDb, + session: Session, id: &str, input_data: Validated>, - cookies: &CookieJar<'_>, ) -> Result<(), Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::AccessAdminPanel); - - match Kiosk::auth_log(id, session, input_data, &db).await { - Ok(_res) => Ok(()), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Kiosk::auth_log(id, session, input_data.data(), &db.0).await.map(|_| ()) } diff --git a/src/methods/kiosk/structs.rs b/src/methods/kiosk/structs.rs index f3bbb2b..7907203 100644 --- a/src/methods/kiosk/structs.rs +++ b/src/methods/kiosk/structs.rs @@ -16,6 +16,7 @@ use serde_json::json; use uuid::Uuid; use validator::Validate; use crate::entities::kiosk::Model; +use crate::methods::Error; #[cfg(feature = "types")] #[derive(Serialize, Deserialize, Clone, JsonSchema, Validate)] @@ -64,7 +65,7 @@ pub struct KioskInit { #[cfg(feature = "methods")] impl Kiosk { - pub async fn generate(id: &str, session: Session, db: &DbConn) -> Result { + pub async fn generate(id: &str, session: Session, db: &DbConn) -> Result { let ksk: KioskInit = example_kiosk(); // Insert & Fetch Customer let result = Kiosk::insert(ksk, session.clone(), db, Some(id)) @@ -76,7 +77,7 @@ impl Kiosk { } } - pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { + pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { let kiosk = Ksk::find_by_id(id.to_string()) .filter(kiosk::Column::TenantId.eq(session.tenant_id)) .one(db) @@ -91,7 +92,7 @@ impl Kiosk { disabled: k.disabled != 0, last_online: DateTime::from_naive_utc_and_offset(k.last_online, Utc), }), - None => Err(DbErr::RecordNotFound(id.to_string())), + None => Err(DbErr::RecordNotFound(id.to_string()).into()), } } @@ -100,7 +101,7 @@ impl Kiosk { session: Session, db: &DbConn, id: Option<&str>, - ) -> Result, DbErr> { + ) -> Result, Error> { let id = match id { Some(id) => id.to_string(), None => Uuid::new_v4().to_string(), @@ -116,10 +117,7 @@ impl Kiosk { tenant_id: Set(session.tenant_id), }; - match Ksk::insert(insert_crud).exec(db).await { - Ok(res) => Ok(res), - Err(err) => Err(err), - } + Ksk::insert(insert_crud).exec(db).await.map_err(|v| v.into()) } pub async fn insert_raw( @@ -138,7 +136,7 @@ impl Kiosk { session: Session, id: &str, db: &DbConn, - ) -> Result { + ) -> Result { ActiveModel { id: Set(id.to_string()), name: Set(kiosk.name), @@ -154,15 +152,12 @@ impl Kiosk { Self::fetch_by_id(id, session, db).await } - pub async fn delete(id: &str, session: Session, db: &DbConn) -> Result { - match Ksk::delete_by_id(id) + pub async fn delete(id: &str, session: Session, db: &DbConn) -> Result { + Ksk::delete_by_id(id) .filter(kiosk::Column::TenantId.eq(session.tenant_id)) .exec(db) .await - { - Ok(res) => Ok(res), - Err(err) => Err(err), - } + .map_err(|v| v.into()) } pub async fn auth_log( @@ -170,7 +165,7 @@ impl Kiosk { session: Session, log: AuthenticationLog, db: &DbConn, - ) -> Result { + ) -> Result { let kiosk = Self::fetch_by_id(id, session.clone(), db).await?; AuthRecord { @@ -182,6 +177,7 @@ impl Kiosk { } .insert(db) .await + .map_err(|v| v.into()) } pub async fn update_preferences( @@ -189,7 +185,7 @@ impl Kiosk { session: Session, preferences: KioskPreferences, db: &DbConn, - ) -> Result { + ) -> Result { let kiosk = Self::fetch_by_id(id, session.clone(), db).await?; ActiveModel { @@ -211,7 +207,7 @@ impl Kiosk { id: &str, session: Session, db: &DbConn, - ) -> Result { + ) -> Result { let kiosk = Self::fetch_by_id(id, session.clone(), db).await?; ActiveModel { diff --git a/src/methods/macros.rs b/src/methods/macros.rs index 7dc63fa..9009a5d 100644 --- a/src/methods/macros.rs +++ b/src/methods/macros.rs @@ -4,7 +4,7 @@ macro_rules! check_permissions { if !$session.has_permission($permission) { return Err($crate::methods::ErrorResponse::custom_unauthorized( "User is unauthorized, may not have a valid session.", - )); + )).into(); } }; } diff --git a/src/pool.rs b/src/pool.rs index f8e52cc..92ea092 100644 --- a/src/pool.rs +++ b/src/pool.rs @@ -2,7 +2,7 @@ use crate::entities::{session, transactions}; #[cfg(feature = "process")] use crate::migrator::Migrator; -use crate::SessionVariant; +use crate::{SessionVariant}; use crate::{example_employee, Customer, Kiosk, Product, Session, Store, Transaction}; #[cfg(feature = "process")] use async_trait::async_trait; @@ -10,10 +10,10 @@ use chrono::{Days, Duration as ChronoDuration, Utc}; #[cfg(feature = "process")] use dotenv::dotenv; use rocket::request; -use rocket::request::FromRequest; +use rocket::request::{FromRequest, Outcome}; #[cfg(feature = "process")] use rocket::tokio; -use rocket_db_pools::Database; +use rocket_db_pools::{Connection, Database}; use rocket_okapi::gen::OpenApiGenerator; use rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput}; use sea_orm::DatabaseConnection; @@ -44,19 +44,25 @@ impl<'a> FromRequest<'a> for RocketDbPool { } } +#[derive(Debug)] +pub struct InternalDb(pub DbConn); + #[rocket::async_trait] -impl<'a> FromRequest<'a> for Db { - type Error = &'static str; +impl<'a> FromRequest<'a> for InternalDb { + type Error = Option; + async fn from_request( - _request: &'a request::Request<'_>, + request: &'a request::Request<'_>, ) -> request::Outcome { - request::Outcome::Success(Db(RocketDbPool { - conn: DatabaseConnection::Disconnected, - })) + match request.guard::>().await { + Outcome::Success(s) => Outcome::Success(InternalDb(s.into_inner())), + Outcome::Error(e) => Outcome::Error(e), + Outcome::Forward(f) => Outcome::Forward(f) + } } } -impl<'r> OpenApiFromRequest<'r> for Db { +impl<'r> OpenApiFromRequest<'r> for InternalDb { fn from_request_input( _gen: &mut OpenApiGenerator, _name: String, From 6992a3a7cb3576d9139d61bef22da8df54dde16f Mon Sep 17 00:00:00 2001 From: Ben White Date: Tue, 6 Feb 2024 14:27:36 +1100 Subject: [PATCH 3/8] mod: migrate employees and customers --- src/methods/common.rs | 17 +- src/methods/customer/handlers.rs | 220 ++++---------- src/methods/customer/structs.rs | 59 ++-- src/methods/employee/handlers.rs | 466 +++++++++-------------------- src/methods/employee/structs.rs | 99 +++--- src/methods/helpers/handlers.rs | 20 +- src/methods/transaction/structs.rs | 13 +- src/pool.rs | 7 +- 8 files changed, 297 insertions(+), 604 deletions(-) diff --git a/src/methods/common.rs b/src/methods/common.rs index 75e94bb..075fef7 100644 --- a/src/methods/common.rs +++ b/src/methods/common.rs @@ -6,7 +6,7 @@ use crate::entities::employee::Entity as Employee; #[cfg(feature = "process")] use crate::entities::session::Entity as SessionEntity; -use crate::{session, AccountType, Employee as EmployeeStruct, EmployeeInput}; +use crate::{session, AccountType, Employee as EmployeeStruct, EmployeeInput, example_employee}; #[cfg(feature = "process")] use crate::entities; @@ -239,6 +239,21 @@ pub struct Session { pub variant: SessionVariant, } +impl Session { + pub fn default_with_tenant(tenant_id: String) -> Self { + let default_employee = example_employee(); + + Session { + id: String::new(), + key: String::new(), + employee: default_employee.into(), + expiry: Utc::now().checked_add_days(Days::new(1)).unwrap(), + tenant_id, + variant: SessionVariant::AccessToken, + } + } +} + impl From for session::ActiveModel { fn from(val: Session) -> Self { ActiveModel { diff --git a/src/methods/customer/handlers.rs b/src/methods/customer/handlers.rs index 9252aad..5db4d07 100644 --- a/src/methods/customer/handlers.rs +++ b/src/methods/customer/handlers.rs @@ -1,21 +1,14 @@ use okapi::openapi3::OpenApi; -use crate::{check_permissions}; -use crate::methods::{ - cookie_status_wrapper, Action, ContactInformation, CustomerWithTransactionsOut, Error, - ErrorResponse, Transaction, -}; -use crate::pool::Db; - +use crate::{check_permissions, Session}; +use crate::methods::{Action, ContactInformation, CustomerWithTransactionsOut, Error, Transaction}; +use crate::pool::{InternalDb}; use rocket::get; -use rocket::http::CookieJar; use rocket::serde::json::Json; use rocket::{post}; - -use rocket_db_pools::Connection; use rocket_okapi::{openapi, openapi_get_routes_spec}; use rocket_okapi::settings::OpenApiSettings; use crate::catchers::Validated; - +use crate::guards::Convert; use super::{Customer, CustomerInput}; pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, OpenApi) { @@ -40,244 +33,147 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Customer")] #[get("/")] pub async fn get( - conn: Connection, + db: InternalDb, id: &str, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + session: Session, +) -> Convert { check_permissions!(session.clone(), Action::FetchCustomer); - - match Customer::fetch_by_id(id, session, &db).await { - Ok(customers) => Ok(Json(customers)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Customer::fetch_by_id(id, session, &db.0).await.into() } #[openapi(tag = "Customer")] #[post("/delete/")] pub async fn delete( - conn: Connection, + db: InternalDb, id: &str, - cookies: &CookieJar<'_>, + session: Session, ) -> Result<(), Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::AccessAdminPanel); - - match Customer::delete(id, session, &db).await { - Ok(_res) => Ok(()), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Customer::delete(id, session, &db.0).await.map(|_| ()) } #[openapi(tag = "Customer")] #[get("/recent")] pub async fn get_recent( - conn: Connection, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + db: InternalDb, + session: Session, +) -> Convert> { check_permissions!(session.clone(), Action::FetchCustomer); - - match Customer::fetch_recent(session, &db).await { - Ok(customers) => Ok(Json(customers)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Customer::fetch_recent(session, &db.0).await.into() } #[openapi(tag = "Customer")] #[get("/name/")] pub async fn get_by_name( - conn: Connection, + db: InternalDb, + session: Session, name: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchCustomer); - - match Customer::fetch_by_name(name, session, &db).await { - Ok(customers) => Ok(Json(customers)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Customer::fetch_by_name(name, session, &db.0).await.into() } /// Will search by both name, phone and email. #[openapi(tag = "Customer")] #[get("/search/")] pub async fn search_query( - conn: Connection, + db: InternalDb, + session: Session, query: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchCustomer); - - match Customer::search(query, session, &db).await { - Ok(customers) => Ok(Json(customers)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Customer::search(query, session, &db.0).await.into() } #[openapi(tag = "Customer")] #[get("/transactions/")] pub async fn find_related_transactions( - conn: Connection, + db: InternalDb, + session: Session, id: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchCustomer); - - Ok(Json( - Transaction::fetch_by_client_id(id, session, &db).await? - )) + Transaction::fetch_by_client_id(id, session, &db.0).await.into() } #[openapi(tag = "Customer")] #[get("/phone/")] pub async fn get_by_phone( - conn: Connection, + db: InternalDb, + session: Session, phone: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchCustomer); - - Ok(Json( - Customer::fetch_by_phone(phone, session, &db).await? - )) + Customer::fetch_by_phone(phone, session, &db.0).await.into() } #[openapi(tag = "Customer")] #[get("/addr/")] pub async fn get_by_addr( - conn: Connection, + db: InternalDb, + session: Session, addr: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchCustomer); - - Ok(Json( - Customer::fetch_by_addr(addr, session, &db).await? - )) + Customer::fetch_by_addr(addr, session, &db.0).await.into() } #[openapi(tag = "Customer")] #[post("/generate")] async fn generate( - conn: Connection, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + db: InternalDb, + session: Session, +) -> Convert { check_permissions!(session.clone(), Action::GenerateTemplateContent); - - Ok(Json( - Customer::generate(session, &db).await? - )) + Customer::generate(session, &db.0).await.into() } #[openapi(tag = "Customer")] #[post("/", data = "")] async fn update( - conn: Connection, - id: &str, - cookies: &CookieJar<'_>, + db: InternalDb, + session: Session, input_data: Validated>, -) -> Result, Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + id: &str, +) -> Convert { check_permissions!(session.clone(), Action::ModifyCustomer); - - Ok(Json( - Customer::update(input_data, session, id, &db).await? - )) + Customer::update(input_data.data(), session, id, &db.0).await.into() } #[openapi(tag = "Customer")] #[post("/input/", data = "")] async fn update_by_input( - conn: Connection, + db: InternalDb, id: &str, - cookies: &CookieJar<'_>, + session: Session, input_data: Validated>, -) -> Result, Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert { check_permissions!(session.clone(), Action::ModifyCustomer); - - Ok(Json( - Customer::update_by_input(input_data, session, id, &db).await? - )) + Customer::update_by_input(input_data.data(), session, id, &db.0).await.into() } #[openapi(tag = "Customer")] #[post("/contact/", data = "")] async fn update_contact_info( - conn: Connection, - id: &str, - cookies: &CookieJar<'_>, + db: InternalDb, + session: Session, input_data: Validated>, -) -> Result, Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - let session = cookie_status_wrapper(&db, cookies).await?; - + id: &str, +) -> Convert { check_permissions!(session.clone(), Action::ModifyCustomer); - - match Customer::update_contact_information(input_data, id, session, &db).await { - Ok(res) => Ok(Json(res)), - Err(error) => Err(ErrorResponse::db_err(error)), - } + Customer::update_contact_information(input_data.data(), id, session, &db.0).await.into() } #[openapi(tag = "Customer")] #[post("/", data = "")] pub async fn create( - conn: Connection, - cookies: &CookieJar<'_>, + db: InternalDb, + session: Session, input_data: Validated>, ) -> Result, Error> { - let new_transaction = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::CreateCustomer); - match Customer::insert(new_transaction, session.clone(), &db).await { - Ok(data) => - match Customer::fetch_by_id( - &data.last_insert_id, session, &db - ).await { - Ok(res) => Ok(Json(res)), - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::create_error(&format!( - "Fetch for customer failed, reason: {}", - reason - ))) - } - }, - Err(error) => Err(ErrorResponse::db_err(error)), - } + let data = Customer::insert(input_data.data(), session.clone(), &db.0).await?; + let converted: Convert = Customer::fetch_by_id(&data.last_insert_id, session, &db.0).await.into(); + converted.0 } diff --git a/src/methods/customer/structs.rs b/src/methods/customer/structs.rs index d1a2164..b4ee9b2 100644 --- a/src/methods/customer/structs.rs +++ b/src/methods/customer/structs.rs @@ -14,15 +14,15 @@ use sea_orm::QueryFilter; #[cfg(feature = "process")] use sea_orm::{ sea_query::{Expr, Func}, - ActiveModelTrait, ColumnTrait, DbBackend, DbConn, DbErr, EntityTrait, FromQueryResult, + ActiveModelTrait, ColumnTrait, DbBackend, DbConn, EntityTrait, FromQueryResult, InsertResult, JsonValue, QuerySelect, RuntimeErr, Set, Statement, }; -use sea_orm::{DeleteResult, QueryOrder}; +use sea_orm::{DbErr, DeleteResult, QueryOrder}; use serde::{Deserialize, Serialize}; use serde_json::json; use validator::Validate; use crate::entities::customer::ActiveModel; -use crate::{ContactInformationInput, Session}; +use crate::{ContactInformationInput, methods::Error, Session}; #[cfg(feature = "types")] #[derive(Serialize, Deserialize, Clone, JsonSchema, Validate)] @@ -99,33 +99,29 @@ impl Customer { cust: CustomerInput, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let insert_crud = cust.into_active(session.tenant_id); - - Cust::insert(insert_crud).exec(db).await + Cust::insert(insert_crud).exec(db).await.map_err(|v| v.into()) } pub async fn insert_raw( cust: Customer, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let insert_crud = cust.into_active(session.tenant_id); - - Cust::insert(insert_crud).exec(db).await + Cust::insert(insert_crud).exec(db).await.map_err(|v| v.into()) } - pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { - let cust = Cust::find_by_id(id.to_string()) + pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { + match Cust::find_by_id(id.to_string()) .filter(customer::Column::TenantId.eq(session.tenant_id)) .one(db) - .await?; - - match cust { + .await? { Some(c) => Ok(c.into()), None => Err(DbErr::RecordNotFound( "Unable to find customer record value".to_string(), - )), + ).into()), } } @@ -133,7 +129,7 @@ impl Customer { query: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let as_str: Vec = CustomerWithTransactions::find_by_statement(Statement::from_sql_and_values( DbBackend::MySql, &format!("SELECT Customer.*, GROUP_CONCAT(`Transactions`.`id`) as transactions @@ -173,7 +169,7 @@ impl Customer { name: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = customer::Entity::find() .filter(customer::Column::TenantId.eq(session.tenant_id)) .having( @@ -192,22 +188,19 @@ impl Customer { Ok(mapped) } - pub async fn delete(id: &str, session: Session, db: &DbConn) -> Result { - match crate::entities::customer::Entity::delete_by_id(id) + pub async fn delete(id: &str, session: Session, db: &DbConn) -> Result { + crate::entities::customer::Entity::delete_by_id(id) .filter(customer::Column::TenantId.eq(session.tenant_id)) .exec(db) .await - { - Ok(res) => Ok(res), - Err(err) => Err(err), - } + .map_err(|v| v.into()) } pub async fn fetch_containing_contact( value: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = customer::Entity::find() .filter(customer::Column::TenantId.eq(session.tenant_id)) .having(customer::Column::Contact.contains(value)) @@ -227,7 +220,7 @@ impl Customer { phone: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { Customer::fetch_containing_contact(phone, session, db).await } @@ -235,14 +228,14 @@ impl Customer { addr: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { Customer::fetch_containing_contact(addr, session, db).await } pub async fn fetch_recent( session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = customer::Entity::find() .filter(customer::Column::TenantId.eq(session.tenant_id)) .order_by_desc(customer::Column::UpdatedAt) @@ -259,7 +252,7 @@ impl Customer { } /// Generate and insert a default customer. - pub async fn generate(session: Session, db: &DbConn) -> Result { + pub async fn generate(session: Session, db: &DbConn) -> Result { let cust = example_customer(); // Insert & Fetch Customer let r = Customer::insert(cust, session.clone(), db).await.unwrap(); @@ -271,7 +264,7 @@ impl Customer { session: Session, id: &str, db: &DbConn, - ) -> Result { + ) -> Result { let old_customer = Self::fetch_by_id(id, session.clone(), db).await?; let customer = cust.from_existing(old_customer, session.tenant_id.clone()); @@ -285,7 +278,7 @@ impl Customer { session: Session, id: &str, db: &DbConn, - ) -> Result { + ) -> Result { let addr = convert_addr_to_geo(&format!( "{} {} {} {}", cust.contact.address.street, @@ -314,7 +307,7 @@ impl Customer { } Err(_) => Err(DbErr::Query(RuntimeErr::Internal( "Invalid address format".to_string(), - ))), + )).into()), } } @@ -323,7 +316,7 @@ impl Customer { id: &str, session: Session, db: &DbConn, - ) -> Result { + ) -> Result { let cust = Self::fetch_by_id(id, session.clone(), db).await?; // Get geo location for new contact information... @@ -354,7 +347,7 @@ impl Customer { } Err(_) => Err(DbErr::Query(RuntimeErr::Internal( "Invalid address format".to_string(), - ))), + )).into()), } } } diff --git a/src/methods/employee/handlers.rs b/src/methods/employee/handlers.rs index c6dca7d..146f4e9 100644 --- a/src/methods/employee/handlers.rs +++ b/src/methods/employee/handlers.rs @@ -1,7 +1,7 @@ use crate::catchers::Validated; use crate::entities::session; use crate::methods::{cookie_status_wrapper, Error, ErrorResponse, History, Name}; -use crate::pool::Db; +use crate::pool::{Db, InternalDb}; use crate::SessionVariant; use crate::{ check_permissions, create_cookie, example_employee, tenants, Auth, AuthenticationLog, Customer, @@ -19,6 +19,7 @@ use rocket_okapi::{openapi, openapi_get_routes_spec}; use sea_orm::{EntityTrait, Set}; use serde_json::json; use uuid::Uuid; +use crate::guards::Convert; use super::{Action, Attendance, Employee, EmployeeInput, TrackType}; @@ -46,370 +47,212 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Employee")] #[get("/")] pub async fn whoami( - conn: Connection, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + session: Session, +) -> Convert { check_permissions!(session.clone(), Action::FetchEmployee); - - Ok(Json(session.employee)) + Ok(session.employee).into() } #[openapi(tag = "Employee")] #[get("/")] pub async fn get( - conn: Connection, + db: InternalDb, id: &str, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + session: Session, +) -> Convert { check_permissions!(session.clone(), Action::FetchEmployee); if session.employee.id == id { - Ok(Json(session.employee)) + Ok(session.employee).into() } else { - match Employee::fetch_by_id(id, session, &db).await { - Ok(employee) => Ok(Json(employee)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Employee::fetch_by_id(id, session, &db.0).await.into() } } #[openapi(tag = "Employee")] #[get("/rid/")] pub async fn get_by_rid( - conn: Connection, + db: InternalDb, rid: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + session: Session, +) -> Convert> { check_permissions!(session.clone(), Action::FetchEmployee); - - match Employee::fetch_by_rid(rid, session, &db).await { - Ok(employee) => Ok(Json(employee)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Employee::fetch_by_rid(rid, session, &db.0).await.into() } #[openapi(tag = "Employee")] #[get("/recent")] pub async fn get_recent( - conn: Connection, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + db: InternalDb, + session: Session, +) -> Convert> { check_permissions!(session.clone(), Action::FetchCustomer); - - match Employee::fetch_recent(session, &db).await { - Ok(employees) => Ok(Json(employees)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Employee::fetch_recent(session, &db.0).await.into() } #[openapi(tag = "Employee")] #[get("/name/")] pub async fn get_by_name( - conn: Connection, + db: InternalDb, + session: Session, name: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchEmployee); - - match Employee::fetch_by_name(name, session, &db).await { - Ok(employees) => Ok(Json(employees)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Employee::fetch_by_name(name, session, &db.0).await.into() } #[openapi(tag = "Employee")] #[get("/!name", data = "")] pub async fn get_by_name_exact( - conn: Connection, + db: InternalDb, + session: Session, name: Json, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - let new_transaction = name.clone().into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchEmployee); - if session.employee.name == new_transaction { - Ok(Json(vec![session.employee])) + if session.employee.name == name.0 { + Ok(vec![session.employee]).into() } else { - match Employee::fetch_by_name_exact(json!(new_transaction), session, &db).await { - Ok(employees) => Ok(Json(employees)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Employee::fetch_by_name_exact(json!(name.0), session, &db.0).await.into() } } #[openapi(tag = "Employee")] #[get("/level/")] pub async fn get_by_level( - conn: Connection, + db: InternalDb, + session: Session, level: i32, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchEmployee); - - match Employee::fetch_by_level(level, session, &db).await { - Ok(employees) => Ok(Json(employees)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Employee::fetch_by_level(level, session, &db.0).await.into() } #[openapi(tag = "Employee")] #[post("/generate")] -async fn generate(conn: Connection, cookies: &CookieJar<'_>) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +async fn generate( + db: InternalDb, + session: Session, +) -> Convert { check_permissions!(session.clone(), Action::GenerateTemplateContent); - - match Employee::generate(&db, session).await { - Ok(res) => Ok(Json(res)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Employee::generate(&db.0, session).await.into() } #[openapi(tag = "Employee")] #[post("/", data = "")] async fn update( - conn: Connection, + db: InternalDb, + session: Session, id: &str, - cookies: &CookieJar<'_>, input_data: Validated>, -) -> Result, Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert { check_permissions!(session.clone(), Action::ModifyEmployee); - - if session - .clone() - .employee - .level - .into_iter() - .find(|x| x.action == Action::ModifyEmployee) - .unwrap() - .authority - >= 1 - { - Ok(Json(Employee::update(input_data, session, id, &db).await?)) - } else { - Err(ErrorResponse::unauthorized(Action::ModifyEmployee)) - } + Employee::update(input_data.data(), session, id, &db.0).await.into() } #[openapi(tag = "Employee")] #[post("/input/", data = "")] async fn update_by_input( - conn: Connection, + db: InternalDb, + session: Session, id: &str, - cookies: &CookieJar<'_>, input_data: Validated>, -) -> Result, Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert { check_permissions!(session.clone(), Action::ModifyEmployee); - - Ok(Json( - Employee::update_by_input(input_data, session, id, &db).await?, - )) + Employee::update_by_input(input_data.data(), session, id, &db.0).await.into() } #[openapi(tag = "Employee")] #[post("/auth/", data = "")] pub async fn auth( - id: &str, - conn: Connection, + db: InternalDb, input_data: Validated>, cookies: &CookieJar<'_>, + id: &str, ) -> Result, Error> { - let input = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let default_employee = example_employee(); - - match Employee::verify( - id, - Session { - id: String::new(), - key: String::new(), - employee: default_employee.into(), - expiry: Utc::now().checked_add_days(Days::new(1)).unwrap(), - tenant_id: input.tenant_id.clone(), - variant: SessionVariant::AccessToken, - }, - &input.pass, - &db, - ) - .await - { - Ok(data) => { - if !data { - Err(ErrorResponse::custom_unauthorized( - "Invalid password or id.", - )) - } else { - // User is authenticated, lets give them an API key to work with... - let api_key = Uuid::new_v4().to_string(); - let session_id = Uuid::new_v4().to_string(); - let exp = Utc::now() - .checked_add_signed(ChronoDuration::minutes(10)) - .unwrap(); - - let tenant_data = match tenants::Entity::find_by_id(input.tenant_id.clone()) - .one(&db) - .await - { - Ok(optional_data) => match optional_data { - Some(data) => data, - None => { - return Err(ErrorResponse::custom_unauthorized( - "Tenant ID does not exist.", - )) - } - }, - Err(error) => return Err(ErrorResponse::db_err(error)), - }; - - match session::Entity::insert(session::ActiveModel { - id: Set(session_id.to_string()), - key: Set(api_key.clone()), - employee_id: Set(id.to_string()), - expiry: Set(exp.naive_utc()), - tenant_id: Set(tenant_data.tenant_id), - variant: Set(json!(SessionVariant::AccessToken)), - }) - .exec(&db) - .await - { - Ok(_) => { - cookies.add(create_cookie(api_key.clone())); - Ok(Json(api_key)) - } - Err(reason) => Err(ErrorResponse::db_err(reason)), + let input = input_data.data(); + let default_session = Session::default_with_tenant(input.tenant_id.clone()); + + let verified = Employee::verify(id, default_session, &input.pass, &db.0).await?; + + match verified { + false => Err(ErrorResponse::custom_unauthorized("Invalid password or id.")), + true => { + // User is authenticated, lets give them an API key to work with... + let api_key = Uuid::new_v4().to_string(); + let session_id = Uuid::new_v4().to_string(); + let exp = Utc::now() + .checked_add_signed(ChronoDuration::minutes(10)) + .unwrap(); + + let tenant_data: Option = tenants::Entity::find_by_id(input.tenant_id.clone()).one(&db.0).await?; + + match tenant_data { + Some(data) => { + session::Entity::insert(session::ActiveModel { + id: Set(session_id.to_string()), + key: Set(api_key.clone()), + employee_id: Set(id.to_string()), + expiry: Set(exp.naive_utc()), + tenant_id: Set(data.tenant_id), + variant: Set(json!(SessionVariant::AccessToken)), + }).exec(&db.0).await?; + + cookies.add(create_cookie(api_key.clone())); + Ok(Json(api_key)) } + None => Err(ErrorResponse::create_error("Tenant does not exist.")) } } - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::db_err(reason)) - } } } #[openapi(tag = "Employee")] #[post("/auth/rid/", data = "")] pub async fn auth_rid( - rid: &str, - conn: Connection, + db: InternalDb, input_data: Validated>, cookies: &CookieJar<'_>, + rid: &str, ) -> Result, Error> { - let input = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let default_employee = example_employee(); - let session = Session { - id: String::new(), - key: String::new(), - employee: default_employee.into(), - expiry: Utc::now().checked_add_days(Days::new(1)).unwrap(), - tenant_id: input.tenant_id.clone(), - variant: SessionVariant::AccessToken, - }; + let input = input_data.data(); + let session = Session::default_with_tenant(input.tenant_id.clone()); - match Employee::verify_with_rid(rid, session.clone(), &input.pass, &db).await { + match Employee::verify_with_rid(rid, session.clone(), &input.pass, &db.0).await { Ok(data) => { - Kiosk::auth_log( - &input.kiosk_id, - session.clone(), - AuthenticationLog { - employee_id: data.id.to_string(), - successful: true, - }, - &db, - ) - .await - .map_err(ErrorResponse::db_err)?; + let auth_log = AuthenticationLog { employee_id: data.id.to_string(), successful: true }; + Kiosk::auth_log(&input.kiosk_id, session.clone(), auth_log, &db.0).await?; - // User is authenticated, lets give them an API key to work with... let api_key = Uuid::new_v4().to_string(); let session_id = Uuid::new_v4().to_string(); let exp = Utc::now() .checked_add_signed(ChronoDuration::minutes(10)) .unwrap(); - let tenant_data = match tenants::Entity::find_by_id(input.tenant_id.clone()) - .one(&db) - .await - { - Ok(optional_data) => match optional_data { - Some(data) => data, - None => { - return Err(ErrorResponse::custom_unauthorized( - "Tenant ID does not exist.", - )) - } - }, - Err(error) => return Err(ErrorResponse::db_err(error)), - }; - - match session::Entity::insert(session::ActiveModel { - id: Set(session_id.to_string()), - key: Set(api_key.clone()), - employee_id: Set(data.id.to_string()), - expiry: Set(exp.naive_utc()), - tenant_id: Set(tenant_data.tenant_id), - variant: Set(json!(SessionVariant::AccessToken)), - }) - .exec(&db) - .await - { - Ok(_) => { + let tenant_data: Option = tenants::Entity::find_by_id(input.tenant_id.clone()).one(&db.0).await?; + + match tenant_data { + Some(tenant) => { + session::Entity::insert(session::ActiveModel { + id: Set(session_id.to_string()), + key: Set(api_key.clone()), + employee_id: Set(data.id.to_string()), + expiry: Set(exp.naive_utc()), + tenant_id: Set(tenant.tenant_id), + variant: Set(json!(SessionVariant::AccessToken)), + }).exec(&db.0).await?; + cookies.add(create_cookie(api_key.clone())); Ok(Json(api_key)) } - Err(reason) => Err(ErrorResponse::db_err(reason)), + None => Err(ErrorResponse::create_error("Tenant does not exist.")) } } - Err(reason) => { - Kiosk::auth_log( - &input.kiosk_id, - session.clone(), - AuthenticationLog { - employee_id: rid.to_string(), - successful: false, - }, - &db, - ) - .await - .map_err(ErrorResponse::db_err)?; - - Err(ErrorResponse::custom_unauthorized(&format!( - "Invalid password or id. Reason: {}", - reason - ))) + Err(err) => { + let auth_log = AuthenticationLog { employee_id: rid.to_string(), successful: false }; + Kiosk::auth_log(&input.kiosk_id, session.clone(), auth_log, &db.0).await?; + + Err(ErrorResponse::custom_unauthorized(&format!("Invalid password or id. Reason: {:?}", err))) } } } @@ -417,45 +260,29 @@ pub async fn auth_rid( #[openapi(tag = "Employee")] #[post("/", data = "")] pub async fn create( - conn: Connection, + db: InternalDb, + session: Session, input_data: Validated>, - cookies: &CookieJar<'_>, ) -> Result, Error> { - let new_transaction = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::CreateEmployee); - match Employee::insert(new_transaction, &db, session.clone(), None, None).await { - Ok(data) => match Employee::fetch_by_id(&data.last_insert_id, session, &db).await { - Ok(res) => Ok(Json(res)), - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::db_err(reason)) - } - }, - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::input_error()) - } - } + let data = Employee::insert(input_data.data(), &db.0, session.clone(), None, None).await?; + let converted: Convert = Employee::fetch_by_id(&data.last_insert_id, session, &db.0).await.into(); + converted.0 } #[openapi(tag = "Employee")] #[post("/log/", data = "")] pub async fn log( - conn: Connection, + db: InternalDb, + session: Session, input_data: Validated>, id: &str, - cookies: &CookieJar<'_>, ) -> Result, Error> { - let db = conn.into_inner(); - let data = input_data.0.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::FetchEmployee); + let data = input_data.data(); + let track_type = if data.in_or_out.to_lowercase() == "in" { TrackType::In } else { @@ -467,63 +294,40 @@ pub async fn log( track_type, kiosk: data.kiosk, }, - reason: "".to_string(), + reason: "OpenStock - Log".to_string(), timestamp: Utc::now(), }; - match Employee::fetch_by_id(id, session.clone(), &db).await { - Ok(mut data) => { - data.clock_history.push(new_attendance); + let mut data = Employee::fetch_by_id(id, session.clone(), &db.0).await?; + data.clock_history.push(new_attendance); - match Employee::update_no_geom(data, session, id, &db).await { - Ok(data) => Ok(Json(data)), - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::db_err(reason)) - } - } - } - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::input_error()) - } - } + let converted: Convert = Employee::update_no_geom(data, session, id, &db.0).await.into(); + converted.0 } #[openapi(tag = "Employee")] #[get("/log/")] pub async fn get_status( - conn: Connection, + db: InternalDb, + session: Session, id: &str, - cookies: &CookieJar<'_>, ) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::FetchEmployee); - match Employee::fetch_by_id(id, session, &db).await { - Ok(mut data) => { - // First time employee is just considered "clocked out" - if data.clock_history.is_empty() { - return Ok(Json(History { - item: Attendance { - track_type: TrackType::Out, - kiosk: "new-employee".to_string(), - }, - reason: String::new(), - timestamp: Utc::now(), - })); - } - - data.clock_history - .sort_by(|a, b| b.timestamp.cmp(&a.timestamp)); - - Ok(Json(data.clock_history[0].clone())) - } - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::input_error()) - } + let mut data = Employee::fetch_by_id(id, session, &db.0).await?; + + // First time employee is just considered "clocked out" + if data.clock_history.is_empty() { + return Ok(Json(History { + item: Attendance { + track_type: TrackType::Out, + kiosk: "new-employee".to_string(), + }, + reason: "This employee has never clocked in.".to_string(), + timestamp: Utc::now(), + })); } + + data.clock_history.sort_by(|a, b| b.timestamp.cmp(&a.timestamp)); + Ok(Json(data.clock_history[0].clone())) } diff --git a/src/methods/employee/structs.rs b/src/methods/employee/structs.rs index 9f9013f..35388bd 100644 --- a/src/methods/employee/structs.rs +++ b/src/methods/employee/structs.rs @@ -187,6 +187,7 @@ use rand::Rng; use schemars::JsonSchema; use sea_orm::QueryOrder; use validator::Validate; +use crate::methods::Error; #[cfg(feature = "methods")] impl Employee { @@ -196,7 +197,7 @@ impl Employee { session: Session, static_rid: Option, static_id: Option, - ) -> Result, DbErr> { + ) -> Result, Error> { let id = static_id.map_or(Uuid::new_v4().to_string(), |x| x); let mut rid = rand::thread_rng().gen_range(0..9999); @@ -207,7 +208,7 @@ impl Employee { let password = empl.password.clone(); if password.is_none() { - return Err(DbErr::AttrNotSet("Field `password` must be present".to_string())) + return Err(DbErr::AttrNotSet("Field `password` must be present".to_string()).into()) } let salt = b"randomsalt"; @@ -216,10 +217,7 @@ impl Employee { let insert_crud = empl.into_active(id, rid, session.tenant_id, hash); - match Epl::insert(insert_crud).exec(db).await { - Ok(res) => Ok(res), - Err(err) => Err(err), - } + Epl::insert(insert_crud).exec(db).await.map_err(|e| e.into()) } pub async fn verify( @@ -227,7 +225,7 @@ impl Employee { session: Session, pass: &str, db: &DbConn, - ) -> Result { + ) -> Result { let employee = Self::fetch_by_id(id, session, db).await?; let is_valid = argon2::verify_encoded( @@ -242,7 +240,7 @@ impl Employee { session: Session, pass: &str, db: &DbConn, - ) -> Result { + ) -> Result { let employee = Self::fetch_by_rid(rid, session, db).await?; let mut valid_user: Option = None; @@ -268,14 +266,14 @@ impl Employee { } else { Err(DbErr::Query(RuntimeErr::Internal( "Unable to locate user. No user exists.".to_string(), - ))) + )).into()) } } pub async fn fetch_recent( session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = employee::Entity::find() .filter(employee::Column::TenantId.eq(session.tenant_id)) .order_by_desc(employee::Column::UpdatedAt) @@ -291,7 +289,7 @@ impl Employee { Ok(mapped) } - pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { + pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { let empl = Epl::find_by_id(id.to_string()) .filter(employee::Column::TenantId.eq(session.tenant_id)) .one(db) @@ -299,7 +297,7 @@ impl Employee { match empl { Some(e) => Ok(e.into()), - None => Err(DbErr::RecordNotFound(id.to_string())), + None => Err(DbErr::RecordNotFound(id.to_string()).into()), } } @@ -307,7 +305,7 @@ impl Employee { rid: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = employee::Entity::find() .having(employee::Column::Rid.contains(rid)) .filter(employee::Column::TenantId.eq(session.tenant_id)) @@ -327,7 +325,7 @@ impl Employee { name: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = employee::Entity::find() .having(employee::Column::Name.contains(name)) .filter(employee::Column::TenantId.eq(session.tenant_id)) @@ -347,7 +345,7 @@ impl Employee { name: serde_json::Value, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = employee::Entity::find() .having(employee::Column::Name.eq(name)) .filter(employee::Column::TenantId.eq(session.tenant_id)) @@ -367,7 +365,7 @@ impl Employee { level: i32, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = employee::Entity::find() .having(employee::Column::Level.eq(level)) .filter(employee::Column::TenantId.eq(session.tenant_id)) @@ -388,7 +386,7 @@ impl Employee { session: Session, id: &str, db: &DbConn, - ) -> Result { + ) -> Result { employee::ActiveModel { id: Set(id.to_string()), rid: Set(empl.rid), @@ -409,7 +407,7 @@ impl Employee { session: Session, id: &str, db: &DbConn, - ) -> Result { + ) -> Result { let old_employee = Self::fetch_by_id(id, session.clone(), db).await?; let as_model = employee.from_existing(old_employee, session.tenant_id.clone()); @@ -423,51 +421,44 @@ impl Employee { session: Session, id: &str, db: &DbConn, - ) -> Result { + ) -> Result { let addr = convert_addr_to_geo(&format!( "{} {} {} {}", empl.contact.address.street, empl.contact.address.street2, empl.contact.address.po_code, empl.contact.address.city - )); - - match addr { - Ok(ad) => { - let mut new_contact = empl.contact; - new_contact.address = ad; - - // A hand-written conversion is used here, - // as it is more explicit and less generalisable. - // - // When given time, re-write the track for the `update` API - // to remove this as a limitation as this may become future - // technical debt. - employee::ActiveModel { - id: Set(id.to_string()), - rid: Set(empl.rid), - name: Set(json!(empl.name)), - auth: Set(json!(empl.auth)), - contact: Set(json!(new_contact)), - clock_history: Set(json!(empl.clock_history)), - level: Set(json!(empl.level)), - tenant_id: Set(session.clone().tenant_id), - account_type: Set(json!(empl.account_type)), - created_at: Set(empl.created_at.naive_utc()), - updated_at: Set(empl.updated_at.naive_utc()) - } - .update(db) - .await?; - - Self::fetch_by_id(id, session, db).await - } - Err(_) => Err(DbErr::Query(RuntimeErr::Internal( - "Invalid address format".to_string(), - ))), + ))?; + + let mut new_contact = empl.contact; + new_contact.address = addr; + + // A hand-written conversion is used here, + // as it is more explicit and less generalisable. + // + // When given time, re-write the track for the `update` API + // to remove this as a limitation as this may become future + // technical debt. + employee::ActiveModel { + id: Set(id.to_string()), + rid: Set(empl.rid), + name: Set(json!(empl.name)), + auth: Set(json!(empl.auth)), + contact: Set(json!(new_contact)), + clock_history: Set(json!(empl.clock_history)), + level: Set(json!(empl.level)), + tenant_id: Set(session.clone().tenant_id), + account_type: Set(json!(empl.account_type)), + created_at: Set(empl.created_at.naive_utc()), + updated_at: Set(empl.updated_at.naive_utc()) } + .update(db) + .await?; + + Self::fetch_by_id(id, session, db).await } - pub async fn generate(db: &DbConn, session: Session) -> Result { + pub async fn generate(db: &DbConn, session: Session) -> Result { let empl = example_employee(); match Employee::insert(empl.clone(), db, session.clone(), Some(empl.rid), None).await { Ok(data) => match Employee::fetch_by_id(&data.last_insert_id, session, db).await { diff --git a/src/methods/helpers/handlers.rs b/src/methods/helpers/handlers.rs index 7e427e4..b031130 100644 --- a/src/methods/helpers/handlers.rs +++ b/src/methods/helpers/handlers.rs @@ -85,11 +85,9 @@ pub async fn generate_template(conn: Connection) -> Result, Error> // Add Employees let employee = Employee::generate(&db, session.clone()) - .await - .map_err(ErrorResponse::db_err)?; + .await?; let _employee2 = Employee::generate(&db, session2.clone()) - .await - .map_err(ErrorResponse::db_err)?; + .await?; // Add other items (aggregated) let stores = Store::generate(session.clone(), &db) @@ -99,21 +97,18 @@ pub async fn generate_template(conn: Connection) -> Result, Error> .await .map_err(ErrorResponse::db_err)?; let customer = Customer::generate(session.clone(), &db) - .await - .map_err(ErrorResponse::db_err)?; + .await?; // Add Kiosks let kiosk = Kiosk::generate("adbd48ab-f4ca-4204-9c88-3516f3133621", session.clone(), &db) - .await - .map_err(ErrorResponse::db_err)?; + .await?; let _kiosk2 = Kiosk::generate( "adbd48ab-f4ca-4204-9c88-3516f3133622", session2.clone(), &db, ) - .await - .map_err(ErrorResponse::db_err)?; + .await?; let transaction = Transaction::generate( &db, @@ -199,8 +194,7 @@ pub async fn new_tenant( let employee_insert_result = Employee::insert(employee, &db, session.clone(), None, Some(employee_id)) - .await - .map_err(ErrorResponse::db_err)?; + .await?; match session::Entity::insert::(session.clone().into()) .exec(&db) @@ -345,7 +339,7 @@ pub async fn distance_to_stores( let customer = match Customer::fetch_by_id(id, session.clone(), &db).await { Ok(c) => c, - Err(reason) => return Err(ErrorResponse::db_err(reason)), + Err(reason) => return Err(reason), }; let stores = match Store::fetch_all(session, &db).await { diff --git a/src/methods/transaction/structs.rs b/src/methods/transaction/structs.rs index bcf999a..1fa303f 100644 --- a/src/methods/transaction/structs.rs +++ b/src/methods/transaction/structs.rs @@ -20,13 +20,10 @@ use sea_orm::FromQueryResult; use crate::entities::{ prelude::Transactions, sea_orm_active_enums::TransactionType as SeaORMTType, transactions, }; -use crate::{ - methods::{ - History, Id, NoteList, Order, OrderList, OrderStatus, OrderStatusAssignment, Payment, - Product, Session, Stock, VariantInformation, - }, - PickStatus, ProductInstance, -}; +use crate::{methods::{ + History, Id, NoteList, Order, OrderList, OrderStatus, OrderStatusAssignment, Payment, + Product, Session, Stock, VariantInformation, Error +}, PickStatus, ProductInstance}; #[cfg(feature = "process")] use sea_orm::DbConn; use validator::Validate; @@ -332,7 +329,7 @@ impl Transaction { id: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let tsn = Transactions::find() .filter(transactions::Column::TenantId.eq(session.tenant_id)) .having(transactions::Column::Customer.contains(id)) diff --git a/src/pool.rs b/src/pool.rs index 92ea092..e942df6 100644 --- a/src/pool.rs +++ b/src/pool.rs @@ -49,13 +49,16 @@ pub struct InternalDb(pub DbConn); #[rocket::async_trait] impl<'a> FromRequest<'a> for InternalDb { - type Error = Option; + type Error = Option; async fn from_request( request: &'a request::Request<'_>, ) -> request::Outcome { match request.guard::>().await { - Outcome::Success(s) => Outcome::Success(InternalDb(s.into_inner())), + Outcome::Success(s) => { + let database = s.into_inner(); + Outcome::Success(InternalDb(database)) + }, Outcome::Error(e) => Outcome::Error(e), Outcome::Forward(f) => Outcome::Forward(f) } From 0ed77e33b3dd2ae144812d809560f39524e98cd9 Mon Sep 17 00:00:00 2001 From: Ben White Date: Tue, 6 Feb 2024 17:11:24 +1100 Subject: [PATCH 4/8] mod: product & format --- src/catchers.rs | 36 +-- src/entities/sea_orm_active_enums.rs | 12 +- src/entities/session.rs | 2 +- src/guards.rs | 63 +++--- src/lib.rs | 4 +- src/methods/common.rs | 11 +- src/methods/customer/conversions.rs | 6 +- src/methods/customer/handlers.rs | 76 +++---- src/methods/customer/mod.rs | 2 +- src/methods/customer/structs.rs | 85 ++++--- src/methods/employee/handlers.rs | 104 +++++---- src/methods/employee/mod.rs | 2 +- src/methods/employee/structs.rs | 79 +++---- src/methods/helpers/handlers.rs | 133 ++++------- src/methods/ingress/handlers.rs | 14 +- src/methods/kiosk/conversions.rs | 6 +- src/methods/kiosk/handlers.rs | 33 +-- src/methods/kiosk/mod.rs | 2 +- src/methods/kiosk/structs.rs | 15 +- src/methods/macros.rs | 3 +- src/methods/payment/discount.rs | 2 +- src/methods/product/conversions.rs | 9 +- src/methods/product/example.rs | 6 +- src/methods/product/handlers.rs | 256 ++++++---------------- src/methods/product/mod.rs | 4 +- src/methods/product/structs.rs | 70 +++--- src/methods/product/variant.rs | 27 +-- src/methods/stml/mod.rs | 2 +- src/methods/store/conversions.rs | 8 +- src/methods/store/example.rs | 2 +- src/methods/store/handlers.rs | 4 +- src/methods/store/mod.rs | 4 +- src/methods/store/structs.rs | 22 +- src/methods/supplier/conversions.rs | 14 +- src/methods/supplier/handlers.rs | 30 +-- src/methods/supplier/mod.rs | 4 +- src/methods/supplier/structs.rs | 34 +-- src/methods/tenant/conversions.rs | 6 +- src/methods/tenant/mod.rs | 2 +- src/methods/tenant/structs.rs | 3 +- src/methods/transaction/conversions.rs | 17 +- src/methods/transaction/example.rs | 7 +- src/methods/transaction/handlers.rs | 17 +- src/methods/transaction/mod.rs | 4 +- src/methods/transaction/structs.rs | 45 ++-- src/migrator/m20230730_000002_customer.rs | 6 +- src/migrator/m20230730_000006_session.rs | 2 +- src/pool.rs | 6 +- tests/client_test.rs | 4 +- 49 files changed, 541 insertions(+), 764 deletions(-) diff --git a/src/catchers.rs b/src/catchers.rs index d26ba51..f9409e5 100644 --- a/src/catchers.rs +++ b/src/catchers.rs @@ -1,19 +1,23 @@ -use crate::{guards::UserErrorMessage}; -use rocket::{serde::json::{json, Value}, Request, catch, Data, form}; +use crate::guards::UserErrorMessage; +use okapi::{ + openapi3::{MediaType, RequestBody}, + Map, +}; use rocket::data::{FromData, Outcome as DataOutcome}; use rocket::form::{DataField, FromForm, ValueField}; use rocket::http::Status; use rocket::outcome::Outcome; use rocket::request::FromRequest; use rocket::serde::json::Json; +use rocket::{ + catch, form, + serde::json::{json, Value}, + Data, Request, +}; use rocket_okapi::gen::OpenApiGenerator; use rocket_okapi::request::OpenApiFromData; use schemars::JsonSchema; use validator::{Validate, ValidationErrors}; -use okapi::{ - openapi3::{MediaType, RequestBody}, - Map, -}; /* The below code is a mix between json_validator @@ -23,7 +27,6 @@ use okapi::{ https://github.com/owlnext-fr/rust-microservice-skeleton/blob/main/src/core/validation.rs */ - #[derive(Clone, Debug, JsonSchema)] pub struct Validated(pub T); @@ -60,14 +63,18 @@ macro_rules! fn_request_body { }}; } -impl<'r, D: validator::Validate + rocket::serde::Deserialize<'r> + JsonSchema> OpenApiFromData<'r> for Validated> { +impl<'r, D: validator::Validate + rocket::serde::Deserialize<'r> + JsonSchema> OpenApiFromData<'r> + for Validated> +{ fn request_body(gen: &mut OpenApiGenerator) -> rocket_okapi::Result { fn_request_body!(gen, D, "application/json") } } #[rocket::async_trait] -impl<'r, D: validator::Validate + rocket::serde::Deserialize<'r> + JsonSchema> FromData<'r> for Validated> { +impl<'r, D: validator::Validate + rocket::serde::Deserialize<'r> + JsonSchema> FromData<'r> + for Validated> +{ type Error = Result>; async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> DataOutcome<'r, Self> { @@ -114,7 +121,6 @@ impl<'r, D: Validate + FromRequest<'r>> FromRequest<'r> for Validated { } } - #[rocket::async_trait] impl<'r, T: Validate + FromForm<'r>> FromForm<'r> for Validated { type Context = T::Context; @@ -179,14 +185,14 @@ pub fn unprocessable_entry(req: &Request) -> Value { let possible_parse_violation = req.local_cache(|| CachedParseErrors(None)).0.as_ref(); let validation_errors = req.local_cache(|| CachedValidationErrors(None)).0.as_ref(); - let mut message = "Failed to service request, structure parsing failed.".to_string(); + let mut message = "Failed to service request, structure parsing failed.".to_string(); if validation_errors.is_some() { message.clear(); let erros = validation_errors.unwrap().field_errors(); - for (_,val) in erros.iter() { + for (_, val) in erros.iter() { for error in val.iter() { message.push_str(error.message.as_ref().unwrap()); } @@ -201,8 +207,8 @@ pub fn unprocessable_entry(req: &Request) -> Value { #[catch(500)] pub fn internal_server_error(req: &Request) -> Value { - let error_message = req - .local_cache(|| Some(UserErrorMessage("Internal server error".to_owned()))); + let error_message = + req.local_cache(|| Some(UserErrorMessage("Internal server error".to_owned()))); json! [{"code": "error.internal", "message": error_message}] -} \ No newline at end of file +} diff --git a/src/entities/sea_orm_active_enums.rs b/src/entities/sea_orm_active_enums.rs index 95702e3..6ac70b9 100644 --- a/src/entities/sea_orm_active_enums.rs +++ b/src/entities/sea_orm_active_enums.rs @@ -2,9 +2,11 @@ use schemars::JsonSchema; use sea_orm::entity::prelude::*; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize, JsonSchema)] +#[derive( + Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize, JsonSchema, +)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "transaction_type")] pub enum TransactionType { /// For **finalized** incoming transactions - all items within suborders of this transaction will be considered as additive towards inventory (i.e. incoming shipment of goods) @@ -19,10 +21,10 @@ pub enum TransactionType { /// For **proposed** outgoing transactions - all items within suborders of this transaction will be considered as subtractive towards inventory upon finalization (i.e. reserved/allocated goods) #[sea_orm(string_value = "pending-out")] PendingOut, - /// For **saved** transactions - for all transactions saved temporarily. Acts identically to "Quote" but where quotes are retrieved by order number, saved will be time limited and culled. + /// For **saved** transactions - for all transactions saved temporarily. Acts identically to "Quote" but where quotes are retrieved by order number, saved will be time limited and culled. #[sea_orm(string_value = "saved")] Saved, /// For **quoted** transactions - to be given to customers as an promise of cost #[sea_orm(string_value = "quote")] - Quote -} \ No newline at end of file + Quote, +} diff --git a/src/entities/session.rs b/src/entities/session.rs index 0cd3ba2..289878a 100644 --- a/src/entities/session.rs +++ b/src/entities/session.rs @@ -12,7 +12,7 @@ pub struct Model { #[sea_orm(column_name = "employee_id")] pub employee_id: String, pub expiry: DateTime, - pub variant: Json + pub variant: Json, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/guards.rs b/src/guards.rs index 31607b3..9a60ed7 100644 --- a/src/guards.rs +++ b/src/guards.rs @@ -1,17 +1,22 @@ +use crate::methods::common::Error; +use crate::{cookie_status_wrapper, Db, ErrorResponse, Session}; use futures::TryStreamExt; use okapi::openapi3::Responses; -use rocket::{data::{self, Data, FromData, Limits}, http::Status, request::{local_cache, Request}, response}; use rocket::request::{FromRequest, Outcome}; use rocket::response::Responder; use rocket::serde::json::Json; -use rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput}; +use rocket::{ + data::{self, Data, FromData, Limits}, + http::Status, + request::{local_cache, Request}, + response, +}; use rocket_db_pools::Connection; use rocket_okapi::gen::OpenApiGenerator; +use rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput}; use rocket_okapi::response::OpenApiResponderInner; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::methods::common::Error; -use crate::{cookie_status_wrapper, Db, ErrorResponse, Session}; #[derive(Copy, Clone, Debug)] pub struct RequestId(pub Option); @@ -22,7 +27,7 @@ pub struct JsonValidation(pub T); #[derive(Debug)] pub enum JsonValidationError { ParseError(serde_json::Error), - ReadError + ReadError, } #[derive(Serialize, Debug)] @@ -33,32 +38,23 @@ pub struct UserErrorMessage(pub String); /// type have the `Validate` trait. #[rocket::async_trait] impl<'r, T> FromData<'r> for JsonValidation - where - T: Deserialize<'r>, +where + T: Deserialize<'r>, { type Error = JsonValidationError; - async fn from_data( - req: &'r Request<'_>, - data: Data<'r>, - ) -> data::Outcome<'r, Self> { + async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> { match data.open(Limits::JSON).into_string().await { Ok(value) => { let string = local_cache!(req, value.into_inner()); - match serde_json::from_str::(string) - .map_err(JsonValidationError::ParseError) - { - Ok(e) => - data::Outcome::Success(JsonValidation(e)), - Err(e) => - data::Outcome::Error((Status::InternalServerError, e)) + match serde_json::from_str::(string).map_err(JsonValidationError::ParseError) { + Ok(e) => data::Outcome::Success(JsonValidation(e)), + Err(e) => data::Outcome::Error((Status::InternalServerError, e)), } } Err(_) => { - data::Outcome::Error( - (Status::InternalServerError, JsonValidationError::ReadError) - ) + data::Outcome::Error((Status::InternalServerError, JsonValidationError::ReadError)) } } } @@ -75,7 +71,8 @@ impl<'r> OpenApiFromRequest<'r> for Session { } #[rocket::async_trait] -impl<'r> FromRequest<'r> for Session { // &'r +impl<'r> FromRequest<'r> for Session { + // &'r type Error = Error; async fn from_request(request: &'r Request<'_>) -> Outcome { @@ -84,24 +81,23 @@ impl<'r> FromRequest<'r> for Session { // &'r let db = match request.guard::>().await { Outcome::Success(s) => s, Outcome::Error(e) => { - let err = match e.1 { + let err = match e.1 { Some(v) => ErrorResponse::db_err(v), - None => ErrorResponse::create_error("") + None => ErrorResponse::create_error(""), }; - return Outcome::Error((e.0, err)) - }, - Outcome::Forward(f) => return Outcome::Forward(f) + return Outcome::Error((e.0, err)); + } + Outcome::Forward(f) => return Outcome::Forward(f), }; match cookie_status_wrapper(&db, cookies).await { Ok(session) => Outcome::Success(session), - Err(_) => Outcome::Forward(Status::Unauthorized) + Err(_) => Outcome::Forward(Status::Unauthorized), } } } - pub struct Convert(pub Result, Error>); impl From> for Convert { @@ -117,7 +113,10 @@ impl OpenApiResponderInner for Convert { } impl<'r, 'o: 'r, K: Serialize> Responder<'r, 'o> for Convert { - fn respond_to(self, r: &'r Request<'_>) -> response::Result<'o> where K: Serialize { + fn respond_to(self, r: &'r Request<'_>) -> response::Result<'o> + where + K: Serialize, + { Responder::respond_to(self.0, r) } } @@ -126,7 +125,7 @@ impl<'de, T: Deserialize<'de>> Into, Error>> for Convert { fn into(self) -> Result, Error> { match self.0 { Ok(v) => Ok(v.into()), - Err(e) => Err(e.into()) + Err(e) => Err(e.into()), } } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index bed810e..de36e6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,14 +5,14 @@ use std::sync::Arc; use std::sync::Mutex; use std::thread; +pub mod catchers; #[cfg(feature = "process")] pub mod entities; +pub mod guards; pub mod methods; #[cfg(feature = "process")] pub mod migrator; pub mod pool; -pub mod catchers; -pub mod guards; #[cfg(feature = "process")] pub use self::entities::*; diff --git a/src/methods/common.rs b/src/methods/common.rs index 075fef7..6c57993 100644 --- a/src/methods/common.rs +++ b/src/methods/common.rs @@ -6,7 +6,7 @@ use crate::entities::employee::Entity as Employee; #[cfg(feature = "process")] use crate::entities::session::Entity as SessionEntity; -use crate::{session, AccountType, Employee as EmployeeStruct, EmployeeInput, example_employee}; +use crate::{example_employee, session, AccountType, Employee as EmployeeStruct, EmployeeInput}; #[cfg(feature = "process")] use crate::entities; @@ -466,10 +466,13 @@ impl From for Error { } impl> From> for Error { - fn from(value: Option) -> Self where T: Into { + fn from(value: Option) -> Self + where + T: Into, + { match value { Some(err) => err.into(), - None => ErrorResponse::create_error("Unable to retrieve database instance.") + None => ErrorResponse::create_error("Unable to retrieve database instance."), } } } @@ -520,4 +523,4 @@ impl Into> for VoidableResult { fn into(self) -> Result<(), Error> { self.0.map(|_| ()) } -} \ No newline at end of file +} diff --git a/src/methods/customer/conversions.rs b/src/methods/customer/conversions.rs index 130541a..a034fb3 100644 --- a/src/methods/customer/conversions.rs +++ b/src/methods/customer/conversions.rs @@ -1,9 +1,9 @@ +use crate::entities::customer::ActiveModel; +use crate::{ContactInformation, Customer, CustomerInput, NoteList}; use chrono::{DateTime, Utc}; use sea_orm::ActiveValue::Set; use serde_json::json; use uuid::Uuid; -use crate::{ContactInformation, Customer, CustomerInput, NoteList}; -use crate::entities::customer::ActiveModel; #[cfg(feature = "process")] use crate::entities::customer; @@ -96,4 +96,4 @@ impl From<&customer::Model> for Customer { updated_at: DateTime::from_naive_utc_and_offset(val.updated_at, Utc), } } -} \ No newline at end of file +} diff --git a/src/methods/customer/handlers.rs b/src/methods/customer/handlers.rs index 5db4d07..8e50db9 100644 --- a/src/methods/customer/handlers.rs +++ b/src/methods/customer/handlers.rs @@ -1,15 +1,15 @@ -use okapi::openapi3::OpenApi; -use crate::{check_permissions, Session}; +use super::{Customer, CustomerInput}; +use crate::catchers::Validated; +use crate::guards::Convert; use crate::methods::{Action, ContactInformation, CustomerWithTransactionsOut, Error, Transaction}; -use crate::pool::{InternalDb}; +use crate::pool::InternalDb; +use crate::{check_permissions, Session}; +use okapi::openapi3::OpenApi; use rocket::get; +use rocket::post; use rocket::serde::json::Json; -use rocket::{post}; -use rocket_okapi::{openapi, openapi_get_routes_spec}; use rocket_okapi::settings::OpenApiSettings; -use crate::catchers::Validated; -use crate::guards::Convert; -use super::{Customer, CustomerInput}; +use rocket_okapi::{openapi, openapi_get_routes_spec}; pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, OpenApi) { openapi_get_routes_spec![ @@ -32,43 +32,28 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Customer")] #[get("/")] -pub async fn get( - db: InternalDb, - id: &str, - session: Session, -) -> Convert { +pub async fn get(db: InternalDb, id: &str, session: Session) -> Convert { check_permissions!(session.clone(), Action::FetchCustomer); Customer::fetch_by_id(id, session, &db.0).await.into() } #[openapi(tag = "Customer")] #[post("/delete/")] -pub async fn delete( - db: InternalDb, - id: &str, - session: Session, -) -> Result<(), Error> { +pub async fn delete(db: InternalDb, id: &str, session: Session) -> Result<(), Error> { check_permissions!(session.clone(), Action::AccessAdminPanel); Customer::delete(id, session, &db.0).await.map(|_| ()) } #[openapi(tag = "Customer")] #[get("/recent")] -pub async fn get_recent( - db: InternalDb, - session: Session, -) -> Convert> { +pub async fn get_recent(db: InternalDb, session: Session) -> Convert> { check_permissions!(session.clone(), Action::FetchCustomer); Customer::fetch_recent(session, &db.0).await.into() } #[openapi(tag = "Customer")] #[get("/name/")] -pub async fn get_by_name( - db: InternalDb, - session: Session, - name: &str, -) -> Convert> { +pub async fn get_by_name(db: InternalDb, session: Session, name: &str) -> Convert> { check_permissions!(session.clone(), Action::FetchCustomer); Customer::fetch_by_name(name, session, &db.0).await.into() } @@ -93,37 +78,28 @@ pub async fn find_related_transactions( id: &str, ) -> Convert> { check_permissions!(session.clone(), Action::FetchCustomer); - Transaction::fetch_by_client_id(id, session, &db.0).await.into() + Transaction::fetch_by_client_id(id, session, &db.0) + .await + .into() } #[openapi(tag = "Customer")] #[get("/phone/")] -pub async fn get_by_phone( - db: InternalDb, - session: Session, - phone: &str, -) -> Convert> { +pub async fn get_by_phone(db: InternalDb, session: Session, phone: &str) -> Convert> { check_permissions!(session.clone(), Action::FetchCustomer); Customer::fetch_by_phone(phone, session, &db.0).await.into() } #[openapi(tag = "Customer")] #[get("/addr/")] -pub async fn get_by_addr( - db: InternalDb, - session: Session, - addr: &str, -) -> Convert> { +pub async fn get_by_addr(db: InternalDb, session: Session, addr: &str) -> Convert> { check_permissions!(session.clone(), Action::FetchCustomer); Customer::fetch_by_addr(addr, session, &db.0).await.into() } #[openapi(tag = "Customer")] #[post("/generate")] -async fn generate( - db: InternalDb, - session: Session, -) -> Convert { +async fn generate(db: InternalDb, session: Session) -> Convert { check_permissions!(session.clone(), Action::GenerateTemplateContent); Customer::generate(session, &db.0).await.into() } @@ -137,7 +113,9 @@ async fn update( id: &str, ) -> Convert { check_permissions!(session.clone(), Action::ModifyCustomer); - Customer::update(input_data.data(), session, id, &db.0).await.into() + Customer::update(input_data.data(), session, id, &db.0) + .await + .into() } #[openapi(tag = "Customer")] @@ -149,7 +127,9 @@ async fn update_by_input( input_data: Validated>, ) -> Convert { check_permissions!(session.clone(), Action::ModifyCustomer); - Customer::update_by_input(input_data.data(), session, id, &db.0).await.into() + Customer::update_by_input(input_data.data(), session, id, &db.0) + .await + .into() } #[openapi(tag = "Customer")] @@ -161,7 +141,9 @@ async fn update_contact_info( id: &str, ) -> Convert { check_permissions!(session.clone(), Action::ModifyCustomer); - Customer::update_contact_information(input_data.data(), id, session, &db.0).await.into() + Customer::update_contact_information(input_data.data(), id, session, &db.0) + .await + .into() } #[openapi(tag = "Customer")] @@ -174,6 +156,8 @@ pub async fn create( check_permissions!(session.clone(), Action::CreateCustomer); let data = Customer::insert(input_data.data(), session.clone(), &db.0).await?; - let converted: Convert = Customer::fetch_by_id(&data.last_insert_id, session, &db.0).await.into(); + let converted: Convert = Customer::fetch_by_id(&data.last_insert_id, session, &db.0) + .await + .into(); converted.0 } diff --git a/src/methods/customer/mod.rs b/src/methods/customer/mod.rs index a2ca52d..f78b620 100644 --- a/src/methods/customer/mod.rs +++ b/src/methods/customer/mod.rs @@ -1,7 +1,7 @@ +mod conversions; #[cfg(feature = "process")] pub(crate) mod handlers; mod structs; -mod conversions; pub use self::structs::*; #[cfg(feature = "process")] diff --git a/src/methods/customer/structs.rs b/src/methods/customer/structs.rs index b4ee9b2..39ab935 100644 --- a/src/methods/customer/structs.rs +++ b/src/methods/customer/structs.rs @@ -1,28 +1,28 @@ -use std::fmt::Display; use chrono::{DateTime, Utc}; use schemars::JsonSchema; +use std::fmt::Display; #[cfg(feature = "process")] use crate::entities::customer; +use crate::entities::customer::ActiveModel; #[cfg(feature = "process")] use crate::entities::prelude::Customer as Cust; #[cfg(feature = "process")] use crate::methods::convert_addr_to_geo; use crate::methods::{Address, ContactInformation, Id, NoteList}; +use crate::{methods::Error, ContactInformationInput, Session}; #[cfg(feature = "process")] use sea_orm::QueryFilter; #[cfg(feature = "process")] use sea_orm::{ sea_query::{Expr, Func}, - ActiveModelTrait, ColumnTrait, DbBackend, DbConn, EntityTrait, FromQueryResult, - InsertResult, JsonValue, QuerySelect, RuntimeErr, Set, Statement, + ActiveModelTrait, ColumnTrait, DbBackend, DbConn, EntityTrait, FromQueryResult, InsertResult, + JsonValue, QuerySelect, RuntimeErr, Set, Statement, }; use sea_orm::{DbErr, DeleteResult, QueryOrder}; use serde::{Deserialize, Serialize}; use serde_json::json; use validator::Validate; -use crate::entities::customer::ActiveModel; -use crate::{ContactInformationInput, methods::Error, Session}; #[cfg(feature = "types")] #[derive(Serialize, Deserialize, Clone, JsonSchema, Validate)] @@ -38,7 +38,7 @@ pub struct Customer { pub accepts_marketing: bool, pub created_at: DateTime, - pub updated_at: DateTime + pub updated_at: DateTime, } #[cfg(feature = "process")] @@ -101,7 +101,10 @@ impl Customer { db: &DbConn, ) -> Result, Error> { let insert_crud = cust.into_active(session.tenant_id); - Cust::insert(insert_crud).exec(db).await.map_err(|v| v.into()) + Cust::insert(insert_crud) + .exec(db) + .await + .map_err(|v| v.into()) } pub async fn insert_raw( @@ -110,18 +113,22 @@ impl Customer { db: &DbConn, ) -> Result, Error> { let insert_crud = cust.into_active(session.tenant_id); - Cust::insert(insert_crud).exec(db).await.map_err(|v| v.into()) + Cust::insert(insert_crud) + .exec(db) + .await + .map_err(|v| v.into()) } pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { match Cust::find_by_id(id.to_string()) .filter(customer::Column::TenantId.eq(session.tenant_id)) .one(db) - .await? { + .await? + { Some(c) => Ok(c.into()), - None => Err(DbErr::RecordNotFound( - "Unable to find customer record value".to_string(), - ).into()), + None => Err( + DbErr::RecordNotFound("Unable to find customer record value".to_string()).into(), + ), } } @@ -158,7 +165,7 @@ impl Customer { transactions: c.transactions.clone(), accepts_marketing: c.accepts_marketing, created_at: c.created_at, - updated_at: c.updated_at + updated_at: c.updated_at, }) .collect(); @@ -180,10 +187,7 @@ impl Customer { .all(db) .await?; - let mapped: Vec = res - .iter() - .map(|c| c.into()) - .collect(); + let mapped: Vec = res.iter().map(|c| c.into()).collect(); Ok(mapped) } @@ -208,10 +212,7 @@ impl Customer { .all(db) .await?; - let mapped: Vec = res - .iter() - .map(|c| c.into()) - .collect(); + let mapped: Vec = res.iter().map(|c| c.into()).collect(); Ok(mapped) } @@ -232,10 +233,7 @@ impl Customer { Customer::fetch_containing_contact(addr, session, db).await } - pub async fn fetch_recent( - session: Session, - db: &DbConn, - ) -> Result, Error> { + pub async fn fetch_recent(session: Session, db: &DbConn) -> Result, Error> { let res = customer::Entity::find() .filter(customer::Column::TenantId.eq(session.tenant_id)) .order_by_desc(customer::Column::UpdatedAt) @@ -243,10 +241,7 @@ impl Customer { .all(db) .await?; - let mapped: Vec = res - .iter() - .map(|c| c.into()) - .collect(); + let mapped: Vec = res.iter().map(|c| c.into()).collect(); Ok(mapped) } @@ -292,12 +287,10 @@ impl Customer { // Derive the default from the provided customer let mut model = cust.clone().into_active(session.tenant_id.clone()); - model.contact = Set( - json!(ContactInformation { - address: ad, - ..cust.contact - }) - ); + model.contact = Set(json!(ContactInformation { + address: ad, + ..cust.contact + })); println!("Have active model: {:?}", model); @@ -305,9 +298,9 @@ impl Customer { Self::fetch_by_id(id, session, db).await } - Err(_) => Err(DbErr::Query(RuntimeErr::Internal( - "Invalid address format".to_string(), - )).into()), + Err(_) => { + Err(DbErr::Query(RuntimeErr::Internal("Invalid address format".to_string())).into()) + } } } @@ -332,12 +325,10 @@ impl Customer { Ok(ad) => { let mut model = cust.clone().into_active(session.tenant_id.clone()); - model.contact = Set( - json!(ContactInformation { - address: ad, - ..cust.contact - }) - ); + model.contact = Set(json!(ContactInformation { + address: ad, + ..cust.contact + })); println!("Have active model: {:?}", model); @@ -345,9 +336,9 @@ impl Customer { Self::fetch_by_id(id, session, db).await } - Err(_) => Err(DbErr::Query(RuntimeErr::Internal( - "Invalid address format".to_string(), - )).into()), + Err(_) => { + Err(DbErr::Query(RuntimeErr::Internal("Invalid address format".to_string())).into()) + } } } } diff --git a/src/methods/employee/handlers.rs b/src/methods/employee/handlers.rs index 146f4e9..6927a7d 100644 --- a/src/methods/employee/handlers.rs +++ b/src/methods/employee/handlers.rs @@ -1,5 +1,6 @@ use crate::catchers::Validated; use crate::entities::session; +use crate::guards::Convert; use crate::methods::{cookie_status_wrapper, Error, ErrorResponse, History, Name}; use crate::pool::{Db, InternalDb}; use crate::SessionVariant; @@ -19,7 +20,6 @@ use rocket_okapi::{openapi, openapi_get_routes_spec}; use sea_orm::{EntityTrait, Set}; use serde_json::json; use uuid::Uuid; -use crate::guards::Convert; use super::{Action, Attendance, Employee, EmployeeInput, TrackType}; @@ -46,20 +46,14 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Employee")] #[get("/")] -pub async fn whoami( - session: Session, -) -> Convert { +pub async fn whoami(session: Session) -> Convert { check_permissions!(session.clone(), Action::FetchEmployee); Ok(session.employee).into() } #[openapi(tag = "Employee")] #[get("/")] -pub async fn get( - db: InternalDb, - id: &str, - session: Session, -) -> Convert { +pub async fn get(db: InternalDb, id: &str, session: Session) -> Convert { check_permissions!(session.clone(), Action::FetchEmployee); if session.employee.id == id { @@ -71,32 +65,21 @@ pub async fn get( #[openapi(tag = "Employee")] #[get("/rid/")] -pub async fn get_by_rid( - db: InternalDb, - rid: &str, - session: Session, -) -> Convert> { +pub async fn get_by_rid(db: InternalDb, rid: &str, session: Session) -> Convert> { check_permissions!(session.clone(), Action::FetchEmployee); Employee::fetch_by_rid(rid, session, &db.0).await.into() } #[openapi(tag = "Employee")] #[get("/recent")] -pub async fn get_recent( - db: InternalDb, - session: Session, -) -> Convert> { +pub async fn get_recent(db: InternalDb, session: Session) -> Convert> { check_permissions!(session.clone(), Action::FetchCustomer); Employee::fetch_recent(session, &db.0).await.into() } #[openapi(tag = "Employee")] #[get("/name/")] -pub async fn get_by_name( - db: InternalDb, - session: Session, - name: &str, -) -> Convert> { +pub async fn get_by_name(db: InternalDb, session: Session, name: &str) -> Convert> { check_permissions!(session.clone(), Action::FetchEmployee); Employee::fetch_by_name(name, session, &db.0).await.into() } @@ -113,27 +96,22 @@ pub async fn get_by_name_exact( if session.employee.name == name.0 { Ok(vec![session.employee]).into() } else { - Employee::fetch_by_name_exact(json!(name.0), session, &db.0).await.into() + Employee::fetch_by_name_exact(json!(name.0), session, &db.0) + .await + .into() } } #[openapi(tag = "Employee")] #[get("/level/")] -pub async fn get_by_level( - db: InternalDb, - session: Session, - level: i32, -) -> Convert> { +pub async fn get_by_level(db: InternalDb, session: Session, level: i32) -> Convert> { check_permissions!(session.clone(), Action::FetchEmployee); Employee::fetch_by_level(level, session, &db.0).await.into() } #[openapi(tag = "Employee")] #[post("/generate")] -async fn generate( - db: InternalDb, - session: Session, -) -> Convert { +async fn generate(db: InternalDb, session: Session) -> Convert { check_permissions!(session.clone(), Action::GenerateTemplateContent); Employee::generate(&db.0, session).await.into() } @@ -147,7 +125,9 @@ async fn update( input_data: Validated>, ) -> Convert { check_permissions!(session.clone(), Action::ModifyEmployee); - Employee::update(input_data.data(), session, id, &db.0).await.into() + Employee::update(input_data.data(), session, id, &db.0) + .await + .into() } #[openapi(tag = "Employee")] @@ -159,7 +139,9 @@ async fn update_by_input( input_data: Validated>, ) -> Convert { check_permissions!(session.clone(), Action::ModifyEmployee); - Employee::update_by_input(input_data.data(), session, id, &db.0).await.into() + Employee::update_by_input(input_data.data(), session, id, &db.0) + .await + .into() } #[openapi(tag = "Employee")] @@ -176,7 +158,9 @@ pub async fn auth( let verified = Employee::verify(id, default_session, &input.pass, &db.0).await?; match verified { - false => Err(ErrorResponse::custom_unauthorized("Invalid password or id.")), + false => Err(ErrorResponse::custom_unauthorized( + "Invalid password or id.", + )), true => { // User is authenticated, lets give them an API key to work with... let api_key = Uuid::new_v4().to_string(); @@ -185,7 +169,10 @@ pub async fn auth( .checked_add_signed(ChronoDuration::minutes(10)) .unwrap(); - let tenant_data: Option = tenants::Entity::find_by_id(input.tenant_id.clone()).one(&db.0).await?; + let tenant_data: Option = + tenants::Entity::find_by_id(input.tenant_id.clone()) + .one(&db.0) + .await?; match tenant_data { Some(data) => { @@ -196,12 +183,14 @@ pub async fn auth( expiry: Set(exp.naive_utc()), tenant_id: Set(data.tenant_id), variant: Set(json!(SessionVariant::AccessToken)), - }).exec(&db.0).await?; + }) + .exec(&db.0) + .await?; cookies.add(create_cookie(api_key.clone())); Ok(Json(api_key)) } - None => Err(ErrorResponse::create_error("Tenant does not exist.")) + None => Err(ErrorResponse::create_error("Tenant does not exist.")), } } } @@ -220,7 +209,10 @@ pub async fn auth_rid( match Employee::verify_with_rid(rid, session.clone(), &input.pass, &db.0).await { Ok(data) => { - let auth_log = AuthenticationLog { employee_id: data.id.to_string(), successful: true }; + let auth_log = AuthenticationLog { + employee_id: data.id.to_string(), + successful: true, + }; Kiosk::auth_log(&input.kiosk_id, session.clone(), auth_log, &db.0).await?; let api_key = Uuid::new_v4().to_string(); @@ -229,7 +221,10 @@ pub async fn auth_rid( .checked_add_signed(ChronoDuration::minutes(10)) .unwrap(); - let tenant_data: Option = tenants::Entity::find_by_id(input.tenant_id.clone()).one(&db.0).await?; + let tenant_data: Option = + tenants::Entity::find_by_id(input.tenant_id.clone()) + .one(&db.0) + .await?; match tenant_data { Some(tenant) => { @@ -240,19 +235,27 @@ pub async fn auth_rid( expiry: Set(exp.naive_utc()), tenant_id: Set(tenant.tenant_id), variant: Set(json!(SessionVariant::AccessToken)), - }).exec(&db.0).await?; + }) + .exec(&db.0) + .await?; cookies.add(create_cookie(api_key.clone())); Ok(Json(api_key)) } - None => Err(ErrorResponse::create_error("Tenant does not exist.")) + None => Err(ErrorResponse::create_error("Tenant does not exist.")), } } Err(err) => { - let auth_log = AuthenticationLog { employee_id: rid.to_string(), successful: false }; + let auth_log = AuthenticationLog { + employee_id: rid.to_string(), + successful: false, + }; Kiosk::auth_log(&input.kiosk_id, session.clone(), auth_log, &db.0).await?; - Err(ErrorResponse::custom_unauthorized(&format!("Invalid password or id. Reason: {:?}", err))) + Err(ErrorResponse::custom_unauthorized(&format!( + "Invalid password or id. Reason: {:?}", + err + ))) } } } @@ -267,7 +270,9 @@ pub async fn create( check_permissions!(session.clone(), Action::CreateEmployee); let data = Employee::insert(input_data.data(), &db.0, session.clone(), None, None).await?; - let converted: Convert = Employee::fetch_by_id(&data.last_insert_id, session, &db.0).await.into(); + let converted: Convert = Employee::fetch_by_id(&data.last_insert_id, session, &db.0) + .await + .into(); converted.0 } @@ -301,7 +306,9 @@ pub async fn log( let mut data = Employee::fetch_by_id(id, session.clone(), &db.0).await?; data.clock_history.push(new_attendance); - let converted: Convert = Employee::update_no_geom(data, session, id, &db.0).await.into(); + let converted: Convert = Employee::update_no_geom(data, session, id, &db.0) + .await + .into(); converted.0 } @@ -328,6 +335,7 @@ pub async fn get_status( })); } - data.clock_history.sort_by(|a, b| b.timestamp.cmp(&a.timestamp)); + data.clock_history + .sort_by(|a, b| b.timestamp.cmp(&a.timestamp)); Ok(Json(data.clock_history[0].clone())) } diff --git a/src/methods/employee/mod.rs b/src/methods/employee/mod.rs index 31fada1..c93e2a7 100644 --- a/src/methods/employee/mod.rs +++ b/src/methods/employee/mod.rs @@ -1,7 +1,7 @@ +mod conversions; #[cfg(feature = "process")] pub(crate) mod handlers; mod structs; -mod conversions; #[cfg(feature = "process")] pub use handlers::*; diff --git a/src/methods/employee/structs.rs b/src/methods/employee/structs.rs index 35388bd..afdb144 100644 --- a/src/methods/employee/structs.rs +++ b/src/methods/employee/structs.rs @@ -31,7 +31,7 @@ pub struct Auth { #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema)] pub enum AccountType { FrontLine, - Managerial + Managerial, } #[derive(Serialize, Deserialize, Clone, JsonSchema, Validate)] @@ -56,7 +56,7 @@ pub struct Employee { pub account_type: AccountType, pub created_at: DateTime, - pub updated_at: DateTime + pub updated_at: DateTime, } #[cfg(feature = "types")] @@ -68,7 +68,6 @@ pub struct Access { use enum_iterator::{all, Sequence}; - #[cfg(feature = "types")] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Sequence, JsonSchema)] pub enum Action { @@ -119,10 +118,12 @@ pub enum Action { #[cfg(feature = "types")] pub fn all_actions() -> Vec> { - all::().map(| x | Access { - action: x, - authority: 1 - }).collect::>() + all::() + .map(|x| Access { + action: x, + authority: 1, + }) + .collect::>() } #[cfg(feature = "types")] @@ -143,7 +144,7 @@ pub struct EmployeeInput { pub password: Option, pub clock_history: Vec>, pub level: Vec>, - pub account_type: AccountType + pub account_type: AccountType, } impl Display for Employee { @@ -181,13 +182,13 @@ impl Display for Employee { } } +use crate::methods::Error; #[cfg(feature = "process")] use argon2::{self, Config}; use rand::Rng; use schemars::JsonSchema; use sea_orm::QueryOrder; use validator::Validate; -use crate::methods::Error; #[cfg(feature = "methods")] impl Employee { @@ -208,7 +209,7 @@ impl Employee { let password = empl.password.clone(); if password.is_none() { - return Err(DbErr::AttrNotSet("Field `password` must be present".to_string()).into()) + return Err(DbErr::AttrNotSet("Field `password` must be present".to_string()).into()); } let salt = b"randomsalt"; @@ -217,7 +218,10 @@ impl Employee { let insert_crud = empl.into_active(id, rid, session.tenant_id, hash); - Epl::insert(insert_crud).exec(db).await.map_err(|e| e.into()) + Epl::insert(insert_crud) + .exec(db) + .await + .map_err(|e| e.into()) } pub async fn verify( @@ -228,9 +232,7 @@ impl Employee { ) -> Result { let employee = Self::fetch_by_id(id, session, db).await?; - let is_valid = argon2::verify_encoded( - &employee.auth.hash, pass.as_bytes() - ).unwrap(); + let is_valid = argon2::verify_encoded(&employee.auth.hash, pass.as_bytes()).unwrap(); Ok(is_valid) } @@ -248,11 +250,13 @@ impl Employee { for employee in employee { println!("Validating employee"); - let is_valid = argon2::verify_encoded( - &employee.auth.hash, pass.as_bytes() - ).map_err(|e| DbErr::RecordNotFound(e.to_string()))?; + let is_valid = argon2::verify_encoded(&employee.auth.hash, pass.as_bytes()) + .map_err(|e| DbErr::RecordNotFound(e.to_string()))?; - println!("Found employee is {}", if is_valid { "Valid" } else { "Invalid" }); + println!( + "Found employee is {}", + if is_valid { "Valid" } else { "Invalid" } + ); if is_valid && valid_user.is_none() { valid_user = Some(employee); @@ -266,14 +270,12 @@ impl Employee { } else { Err(DbErr::Query(RuntimeErr::Internal( "Unable to locate user. No user exists.".to_string(), - )).into()) + )) + .into()) } } - pub async fn fetch_recent( - session: Session, - db: &DbConn, - ) -> Result, Error> { + pub async fn fetch_recent(session: Session, db: &DbConn) -> Result, Error> { let res = employee::Entity::find() .filter(employee::Column::TenantId.eq(session.tenant_id)) .order_by_desc(employee::Column::UpdatedAt) @@ -281,10 +283,7 @@ impl Employee { .all(db) .await?; - let mapped: Vec = res - .iter() - .map(|c| c.clone().into()) - .collect(); + let mapped: Vec = res.iter().map(|c| c.clone().into()).collect(); Ok(mapped) } @@ -313,10 +312,7 @@ impl Employee { .all(db) .await?; - let mapped = res - .iter() - .map(|e| e.clone().into()) - .collect(); + let mapped = res.iter().map(|e| e.clone().into()).collect(); Ok(mapped) } @@ -333,10 +329,7 @@ impl Employee { .all(db) .await?; - let mapped = res - .iter() - .map(|e| e.clone().into()) - .collect(); + let mapped = res.iter().map(|e| e.clone().into()).collect(); Ok(mapped) } @@ -353,10 +346,7 @@ impl Employee { .all(db) .await?; - let mapped = res - .iter() - .map(|e| e.clone().into()) - .collect(); + let mapped = res.iter().map(|e| e.clone().into()).collect(); Ok(mapped) } @@ -373,10 +363,7 @@ impl Employee { .all(db) .await?; - let mapped = res - .iter() - .map(|e| e.clone().into()) - .collect(); + let mapped = res.iter().map(|e| e.clone().into()).collect(); Ok(mapped) } @@ -411,7 +398,9 @@ impl Employee { let old_employee = Self::fetch_by_id(id, session.clone(), db).await?; let as_model = employee.from_existing(old_employee, session.tenant_id.clone()); - crate::entities::employee::Entity::update(as_model).exec(db).await?; + crate::entities::employee::Entity::update(as_model) + .exec(db) + .await?; Self::fetch_by_id(id, session, db).await } @@ -450,7 +439,7 @@ impl Employee { tenant_id: Set(session.clone().tenant_id), account_type: Set(json!(empl.account_type)), created_at: Set(empl.created_at.naive_utc()), - updated_at: Set(empl.updated_at.naive_utc()) + updated_at: Set(empl.updated_at.naive_utc()), } .update(db) .await?; diff --git a/src/methods/helpers/handlers.rs b/src/methods/helpers/handlers.rs index b031130..a4aa6dc 100644 --- a/src/methods/helpers/handlers.rs +++ b/src/methods/helpers/handlers.rs @@ -1,4 +1,6 @@ use crate::catchers::Validated; +use crate::guards::Convert; +use crate::pool::InternalDb; use crate::session::ActiveModel; use crate::ContactInformationInput; use crate::{ @@ -45,14 +47,13 @@ pub fn documented_routes(_settings: &OpenApiSettings) -> (Vec, Op /// This route does not require authentication, but is not enabled in release mode. #[openapi(tag = "Helpers")] #[post("/generate")] -pub async fn generate_template(conn: Connection) -> Result, Error> { +pub async fn generate_template(db: InternalDb) -> Result, Error> { if env::var("DEMO").is_err() || env::var("DEMO").unwrap() == "0" { return Err(Error::DemoDisabled( "OpenStock is not in DEMO mode.".to_string(), )); } - let db = conn.into_inner(); let tenant_id = "DEFAULT_TENANT"; let tenant_id2 = "ALTERNATE_TENANT"; let default_employee = example_employee(); @@ -76,42 +77,39 @@ pub async fn generate_template(conn: Connection) -> Result, Error> }; // Add Tenants - let tenant = Tenant::generate(&db, tenant_id) + let tenant = Tenant::generate(&db.0, tenant_id) .await .map_err(ErrorResponse::db_err)?; - let tenant2 = Tenant::generate(&db, tenant_id2) + let tenant2 = Tenant::generate(&db.0, tenant_id2) .await .map_err(ErrorResponse::db_err)?; // Add Employees - let employee = Employee::generate(&db, session.clone()) - .await?; - let _employee2 = Employee::generate(&db, session2.clone()) - .await?; + let employee = Employee::generate(&db.0, session.clone()).await?; + let _employee2 = Employee::generate(&db.0, session2.clone()).await?; // Add other items (aggregated) - let stores = Store::generate(session.clone(), &db) - .await - .map_err(ErrorResponse::db_err)?; - let products = Product::generate(session.clone(), &db) - .await - .map_err(ErrorResponse::db_err)?; - let customer = Customer::generate(session.clone(), &db) - .await?; + let stores = Store::generate(session.clone(), &db.0).await?; + let products = Product::generate(session.clone(), &db.0).await?; + let customer = Customer::generate(session.clone(), &db.0).await?; // Add Kiosks - let kiosk = Kiosk::generate("adbd48ab-f4ca-4204-9c88-3516f3133621", session.clone(), &db) - .await?; + let kiosk = Kiosk::generate( + "adbd48ab-f4ca-4204-9c88-3516f3133621", + session.clone(), + &db.0, + ) + .await?; let _kiosk2 = Kiosk::generate( "adbd48ab-f4ca-4204-9c88-3516f3133622", session2.clone(), - &db, + &db.0, ) .await?; let transaction = Transaction::generate( - &db, + &db.0, &customer.id, Session { id: Uuid::new_v4().to_string(), @@ -125,9 +123,8 @@ pub async fn generate_template(conn: Connection) -> Result, Error> .await .map_err(ErrorResponse::db_err)?; - let promotions = Promotion::generate(session, &db) - .await - .map_err(ErrorResponse::db_err)?; + let promotions = Promotion::generate(session, &db.0) + .await?; Ok(Json(All { employee, @@ -145,11 +142,9 @@ pub async fn generate_template(conn: Connection) -> Result, Error> #[openapi(tag = "Helpers")] #[post("/new", data = "")] pub async fn new_tenant( - conn: Connection, + db: InternalDb, tenant_input: Validated>, - _cookies: &CookieJar<'_>, ) -> Result, Error> { - let db = conn.into_inner(); let data = tenant_input.0.into_inner(); // Create new Tenant @@ -162,7 +157,7 @@ pub async fn new_tenant( updated_at: Utc::now(), }; - Tenant::insert(tenant, &db) + Tenant::insert(tenant, &db.0) .await .map_err(ErrorResponse::db_err)?; @@ -193,52 +188,31 @@ pub async fn new_tenant( ); let employee_insert_result = - Employee::insert(employee, &db, session.clone(), None, Some(employee_id)) - .await?; + Employee::insert(employee, &db.0, session.clone(), None, Some(employee_id)).await?; - match session::Entity::insert::(session.clone().into()) - .exec(&db) - .await - { - Ok(_) => Ok(Json(NewTenantResponse { - tenant_id, - api_key: session.key, - employee_id: employee_insert_result.last_insert_id, - })), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + session::Entity::insert::(session.clone().into()) + .exec(&db.0) + .await?; + + Ok(Json(NewTenantResponse { + tenant_id, + api_key: session.key, + employee_id: employee_insert_result.last_insert_id, + })) } #[openapi(tag = "Helpers")] #[get("/session/")] -pub async fn assign_session_cookie( - _conn: Connection, - key: &str, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let hard_key = key.to_string(); - let cookie = create_cookie(hard_key.clone()); - - cookies.add(cookie); - - Ok(Json(())) +pub async fn assign_session_cookie(key: &str, cookies: &CookieJar<'_>) -> Result<(), Error> { + cookies.add(create_cookie(key.to_string())); + Ok(()) } #[openapi(tag = "Helpers")] #[post("/address", data = "
")] -pub async fn address_to_geolocation( - conn: Connection, - address: &str, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - let session = cookie_status_wrapper(&db, cookies).await?; +pub async fn address_to_geolocation(session: Session, address: &str) -> Convert
{ check_permissions!(session, Action::FetchGeoLocation); - - match convert_addr_to_geo(address) { - Ok(val) => Ok(Json(val)), - Err(status) => Err(status), - } + convert_addr_to_geo(address).into() } pub fn convert_addr_to_geo(address: &str) -> Result { @@ -305,47 +279,30 @@ pub fn convert_addresses_to_geo(address: &str, origin: LatLon) -> Result, - address: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - let session = cookie_status_wrapper(&db, cookies).await?; +pub async fn suggest_addr(address: &str, session: Session) -> Convert> { check_permissions!(session.clone(), Action::FetchGeoLocation); - match convert_addresses_to_geo( + convert_addresses_to_geo( address, LatLon { lat: session.employee.contact.address.lat, lon: session.employee.contact.address.lon, }, - ) { - Ok(val) => Ok(Json(val)), - Err(status) => Err(status), - } + ) + .into() } #[openapi(tag = "Helpers")] #[get("/distance/")] pub async fn distance_to_stores( - conn: Connection, + db: InternalDb, id: &str, - cookies: &CookieJar<'_>, + session: Session, ) -> Result>, Error> { - let db = conn.into_inner(); - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::FetchGeoLocation); - let customer = match Customer::fetch_by_id(id, session.clone(), &db).await { - Ok(c) => c, - Err(reason) => return Err(reason), - }; - - let stores = match Store::fetch_all(session, &db).await { - Ok(s) => s, - Err(reason) => return Err(ErrorResponse::db_err(reason)), - }; + let customer = Customer::fetch_by_id(id, session.clone(), &db.0).await?; + let stores = Store::fetch_all(session, &db.0).await?; let cust = point!(x: customer.contact.address.lat, y: customer.contact.address.lon); diff --git a/src/methods/ingress/handlers.rs b/src/methods/ingress/handlers.rs index bb69c8d..2ec3704 100644 --- a/src/methods/ingress/handlers.rs +++ b/src/methods/ingress/handlers.rs @@ -1,13 +1,11 @@ -use crate::{ - check_permissions, cookie_status_wrapper, methods::Action, methods::Error, Db, ErrorResponse, -}; +use crate::{check_permissions, cookie_status_wrapper, methods::Action, methods::Error, Db, ErrorResponse, Session}; use chrono::Utc; use okapi::openapi3::OpenApi; use rocket::{fs::TempFile, http::CookieJar, post}; use rocket_db_pools::Connection; -use rocket_okapi::{openapi, openapi_get_routes_spec}; use rocket_okapi::settings::OpenApiSettings; +use rocket_okapi::{openapi, openapi_get_routes_spec}; pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, OpenApi) { openapi_get_routes_spec![settings: upload] @@ -19,16 +17,10 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Ingress")] #[post("/upload", format = "plain", data = "")] async fn upload( - conn: Connection, + session: Session, file: TempFile<'_>, - cookies: &CookieJar<'_>, ) -> Result<(), Error> { - let db = conn.into_inner(); - - // Disable verification in testing; - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::AccessAdminPanel); - receive_file(file, session.tenant_id).await } diff --git a/src/methods/kiosk/conversions.rs b/src/methods/kiosk/conversions.rs index ac841c0..c6b582a 100644 --- a/src/methods/kiosk/conversions.rs +++ b/src/methods/kiosk/conversions.rs @@ -1,7 +1,7 @@ -use sea_orm::ActiveValue::Set; -use serde_json::json; use crate::entities::kiosk::ActiveModel; use crate::{Kiosk, Session}; +use sea_orm::ActiveValue::Set; +use serde_json::json; impl Kiosk { pub(crate) fn into_active(self, session: Session) -> ActiveModel { @@ -15,4 +15,4 @@ impl Kiosk { tenant_id: Set(session.tenant_id), } } -} \ No newline at end of file +} diff --git a/src/methods/kiosk/handlers.rs b/src/methods/kiosk/handlers.rs index 5f250c9..184b9d6 100644 --- a/src/methods/kiosk/handlers.rs +++ b/src/methods/kiosk/handlers.rs @@ -1,17 +1,14 @@ use crate::catchers::Validated; -use crate::methods::{Error}; -use crate::pool::{InternalDb}; +use crate::guards::Convert; +use crate::methods::Error; +use crate::pool::InternalDb; +use crate::{check_permissions, methods::Action}; use crate::{AuthenticationLog, Kiosk, KioskInit, KioskPreferences, Session}; use okapi::openapi3::OpenApi; use rocket::serde::json::Json; use rocket::{get, post}; use rocket_okapi::settings::OpenApiSettings; use rocket_okapi::{openapi, openapi_get_routes_spec}; -use crate::{ - check_permissions, - methods::{Action}, -}; -use crate::guards::Convert; pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, OpenApi) { openapi_get_routes_spec![ @@ -43,7 +40,9 @@ pub async fn initialize( check_permissions!(session.clone(), Action::AccessAdminPanel); let kiosk = Kiosk::insert(input_data.data(), session.clone(), &db.0, None).await?; - Kiosk::fetch_by_id(&kiosk.last_insert_id, session, &db.0).await.map(|v| Json(v)) + Kiosk::fetch_by_id(&kiosk.last_insert_id, session, &db.0) + .await + .map(|v| Json(v)) } #[openapi(tag = "Kiosk")] @@ -56,7 +55,9 @@ pub async fn update( ) -> Convert { check_permissions!(session.clone(), Action::AccessAdminPanel); - Kiosk::update(input_data.data(), session, id, &conn.0).await.into() + Kiosk::update(input_data.data(), session, id, &conn.0) + .await + .into() } #[openapi(tag = "Kiosk")] @@ -68,16 +69,14 @@ pub async fn update_preferences( session: Session, ) -> Convert { check_permissions!(session.clone(), Action::ModifyKioskPreferences); - Kiosk::update_preferences(id, session, input_data.data(), &db.0).await.into() + Kiosk::update_preferences(id, session, input_data.data(), &db.0) + .await + .into() } #[openapi(tag = "Kiosk")] #[post("/online/")] -pub async fn update_online_status( - db: InternalDb, - id: &str, - session: Session, -) -> Convert { +pub async fn update_online_status(db: InternalDb, id: &str, session: Session) -> Convert { check_permissions!(session.clone(), Action::FetchKiosk); Kiosk::update_online_to_now(id, session, &db.0).await.into() } @@ -98,5 +97,7 @@ pub async fn auth_log( input_data: Validated>, ) -> Result<(), Error> { check_permissions!(session.clone(), Action::AccessAdminPanel); - Kiosk::auth_log(id, session, input_data.data(), &db.0).await.map(|_| ()) + Kiosk::auth_log(id, session, input_data.data(), &db.0) + .await + .map(|_| ()) } diff --git a/src/methods/kiosk/mod.rs b/src/methods/kiosk/mod.rs index a2ca52d..f78b620 100644 --- a/src/methods/kiosk/mod.rs +++ b/src/methods/kiosk/mod.rs @@ -1,7 +1,7 @@ +mod conversions; #[cfg(feature = "process")] pub(crate) mod handlers; mod structs; -mod conversions; pub use self::structs::*; #[cfg(feature = "process")] diff --git a/src/methods/kiosk/structs.rs b/src/methods/kiosk/structs.rs index 7907203..4ca0146 100644 --- a/src/methods/kiosk/structs.rs +++ b/src/methods/kiosk/structs.rs @@ -1,5 +1,7 @@ +use crate::entities::kiosk::Model; #[cfg(feature = "process")] use crate::entities::prelude::Kiosk as Ksk; +use crate::methods::Error; #[cfg(feature = "process")] use crate::{entities::authrecord::ActiveModel as AuthRecord, entities::kiosk::ActiveModel}; #[cfg(feature = "process")] @@ -15,8 +17,6 @@ use serde::{Deserialize, Serialize}; use serde_json::json; use uuid::Uuid; use validator::Validate; -use crate::entities::kiosk::Model; -use crate::methods::Error; #[cfg(feature = "types")] #[derive(Serialize, Deserialize, Clone, JsonSchema, Validate)] @@ -117,14 +117,13 @@ impl Kiosk { tenant_id: Set(session.tenant_id), }; - Ksk::insert(insert_crud).exec(db).await.map_err(|v| v.into()) + Ksk::insert(insert_crud) + .exec(db) + .await + .map_err(|v| v.into()) } - pub async fn insert_raw( - kiosk: Kiosk, - session: Session, - db: &DbConn, - ) -> Result { + pub async fn insert_raw(kiosk: Kiosk, session: Session, db: &DbConn) -> Result { match kiosk.into_active(session).insert(db).await { Ok(res) => Ok(res), Err(err) => Err(err), diff --git a/src/methods/macros.rs b/src/methods/macros.rs index 9009a5d..51771a5 100644 --- a/src/methods/macros.rs +++ b/src/methods/macros.rs @@ -4,7 +4,8 @@ macro_rules! check_permissions { if !$session.has_permission($permission) { return Err($crate::methods::ErrorResponse::custom_unauthorized( "User is unauthorized, may not have a valid session.", - )).into(); + )) + .into(); } }; } diff --git a/src/methods/payment/discount.rs b/src/methods/payment/discount.rs index 7a82a08..594f6ce 100644 --- a/src/methods/payment/discount.rs +++ b/src/methods/payment/discount.rs @@ -1,6 +1,6 @@ +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::str::FromStr; -use schemars::JsonSchema; #[cfg(feature = "types")] #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] diff --git a/src/methods/product/conversions.rs b/src/methods/product/conversions.rs index 232139f..5284b5a 100644 --- a/src/methods/product/conversions.rs +++ b/src/methods/product/conversions.rs @@ -1,8 +1,11 @@ +use crate::products::{ActiveModel, Model}; +use crate::{ + Product, ProductIdentification, ProductVisibility, Session, TagList, Url, VariantCategoryList, + VariantInformation, +}; use chrono::{DateTime, Utc}; use sea_orm::ActiveValue::Set; use serde_json::json; -use crate::{Product, ProductIdentification, ProductVisibility, Session, TagList, Url, VariantCategoryList, VariantInformation}; -use crate::products::{ActiveModel, Model}; impl Product { pub(crate) fn into_active(self, session: Session) -> ActiveModel { @@ -50,4 +53,4 @@ impl From for Product { updated_at: DateTime::from_naive_utc_and_offset(val.updated_at, Utc), } } -} \ No newline at end of file +} diff --git a/src/methods/product/example.rs b/src/methods/product/example.rs index da94a90..49469a6 100644 --- a/src/methods/product/example.rs +++ b/src/methods/product/example.rs @@ -1,4 +1,8 @@ -use crate::{Address, ContactInformation, DiscountValue, Email, Location, MobileNumber, Product, ProductIdentification, ProductVisibility, Quantity, Stock, StockInformation, Variant, VariantCategory, VariantInformation}; +use crate::{ + Address, ContactInformation, DiscountValue, Email, Location, MobileNumber, Product, + ProductIdentification, ProductVisibility, Quantity, Stock, StockInformation, Variant, + VariantCategory, VariantInformation, +}; pub fn example_products() -> Vec { let mt_wellington = Location { diff --git a/src/methods/product/handlers.rs b/src/methods/product/handlers.rs index 564db19..95142c3 100644 --- a/src/methods/product/handlers.rs +++ b/src/methods/product/handlers.rs @@ -1,16 +1,14 @@ +use crate::catchers::Validated; +use crate::{check_permissions, Session}; +use crate::methods::{Action, Error}; +use crate::pool::{InternalDb}; use okapi::openapi3::OpenApi; -use crate::check_permissions; -use crate::methods::{cookie_status_wrapper, Action, Error, ErrorResponse}; -use crate::pool::Db; use rocket::get; -use rocket::http::CookieJar; +use rocket::post; use rocket::serde::json::Json; -use rocket::{post}; -use rocket_okapi::{openapi, openapi_get_routes_spec}; -use rocket_db_pools::Connection; use rocket_okapi::settings::OpenApiSettings; -use crate::catchers::Validated; - +use rocket_okapi::{openapi, openapi_get_routes_spec}; +use crate::guards::Convert; use super::{Product, ProductWPromotion, Promotion, PromotionInput}; pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, OpenApi) { @@ -36,279 +34,161 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Product")] #[get("/")] pub async fn get( - conn: Connection, + session: Session, + db: InternalDb, id: i32, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert { check_permissions!(session.clone(), Action::FetchProduct); - - match Product::fetch_by_id(&id.to_string(), session, &db).await { - Ok(product) => Ok(Json(product)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Product::fetch_by_id(&id.to_string(), session, &db.0).await.into() } #[openapi(tag = "Product")] #[get("/with_promotions/")] pub async fn get_with_associated_promotions( - conn: Connection, + db: InternalDb, + session: Session, id: i32, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert { check_permissions!(session.clone(), Action::FetchProduct); - - match Product::fetch_by_id_with_promotion(&id.to_string(), session, &db).await { - Ok(product) => Ok(Json(product)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Product::fetch_by_id_with_promotion(&id.to_string(), session, &db.0).await.into() } #[openapi(tag = "Product")] #[get("/name/")] pub async fn get_by_name( - conn: Connection, + db: InternalDb, + session: Session, name: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchProduct); - - match Product::fetch_by_name(name, session, &db).await { - Ok(products) => Ok(Json(products)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Product::fetch_by_name(name, session, &db.0).await.into() } /// References exact name #[openapi(tag = "Product")] #[get("/!name/")] pub async fn get_by_name_exact( - conn: Connection, - name: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + db: InternalDb, + session: Session, + name: &str +) -> Convert> { check_permissions!(session.clone(), Action::FetchProduct); - - match Product::fetch_by_name_exact(name, session, &db).await { - Ok(products) => Ok(Json(products)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Product::fetch_by_name_exact(name, session, &db.0).await.into() } /// Will search by both name, phone and email. #[openapi(tag = "Product")] #[get("/search/")] pub async fn search_query( - conn: Connection, + db: InternalDb, + session: Session, query: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchProduct); - - match Product::search(query, session, &db).await { - Ok(products) => Ok(Json(products)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Product::search(query, session, &db.0).await.into() } #[openapi(tag = "Product")] #[get("/search/with_promotions/")] pub async fn search_with_associated_promotions( - conn: Connection, + db: InternalDb, + session: Session, query: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchProduct); - - match Product::search_with_promotion(query, session, &db).await { - Ok(products) => Ok(Json(products)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Product::search_with_promotion(query, session, &db.0).await.into() } #[openapi(tag = "Product")] #[post("/", data = "")] async fn update( - conn: Connection, - id: &str, + db: InternalDb, + session: Session, input_data: Validated>, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + id: &str, +) -> Convert { check_permissions!(session.clone(), Action::ModifyProduct); - - match Product::update(input_data, session, id, &db).await { - Ok(res) => Ok(Json(res)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Product::update(input_data.data(), session, id, &db.0).await.into() } #[openapi(tag = "Product")] #[post("/", data = "")] pub async fn create( - conn: Connection, + db: InternalDb, input_data: Validated>, - cookies: &CookieJar<'_>, + session: Session, ) -> Result, Error> { - let new_transaction = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::CreateProduct); - match Product::insert(new_transaction, session.clone(), &db).await { - Ok(data) => - match Product::fetch_by_id( - &data.last_insert_id, session, &db - ).await { - Ok(res) => Ok(Json(res)), - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::db_err(reason)) - } - }, - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::db_err(reason)) - } - } + let data = Product::insert(input_data.data(), session.clone(), &db.0).await?; + let converted: Convert = Product::fetch_by_id(&data.last_insert_id, session, &db.0).await.into(); + converted.0 } #[openapi(tag = "Product")] #[post("/generate")] async fn generate( - conn: Connection, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + db: InternalDb, + session: Session, +) -> Convert> { check_permissions!(session.clone(), Action::GenerateTemplateContent); - - match Product::generate(session, &db).await { - Ok(res) => Ok(Json(res)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Product::generate(session, &db.0).await.into() } #[openapi(tag = "Product")] #[get("/promotion/")] pub async fn get_promotion( - conn: Connection, + db: InternalDb, + session: Session, id: i32, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert { check_permissions!(session.clone(), Action::FetchProduct); - - let product = Promotion::fetch_by_id(&id.to_string(), session, &db) - .await - .unwrap(); - Ok(Json(product)) + Promotion::fetch_by_id(&id.to_string(), session, &db.0).await.into() } #[openapi(tag = "Product")] #[get("/promotion/search/")] pub async fn get_promotion_by_query( - conn: Connection, + db: InternalDb, + session: Session, query: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchProduct); - - let product = Promotion::fetch_by_query(query, session, &db).await.unwrap(); - Ok(Json(product)) + Promotion::fetch_by_query(query, session, &db.0).await.into() } #[openapi(tag = "Product")] #[post("/promotion/", data = "")] async fn update_promotion( - conn: Connection, - id: &str, input_data: Validated>, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + db: InternalDb, + session: Session, + id: &str, +) -> Convert { check_permissions!(session.clone(), Action::ModifyProduct); - - match Promotion::update(input_data, session, id, &db).await { - Ok(res) => Ok(Json(res)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Promotion::update(input_data.data(), session, id, &db.0).await.into() } #[openapi(tag = "Product")] #[post("/promotion", data = "")] pub async fn create_promotion( - conn: Connection, + db: InternalDb, input_data: Validated>, - cookies: &CookieJar<'_>, + session: Session ) -> Result, Error> { - let new_promotion = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::CreateProduct); - match Promotion::insert(new_promotion, session.clone(), &db).await { - Ok(data) => - match Promotion::fetch_by_id( - &data.last_insert_id, session, &db - ).await { - Ok(res) => Ok(Json(res)), - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::db_err(reason)) - } - }, - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::db_err(reason)) - } - } + let data = Promotion::insert(input_data.data(), session.clone(), &db.0).await?; + let converted: Convert = Promotion::fetch_by_id(&data.last_insert_id, session, &db.0).await.into(); + converted.0 } #[openapi(tag = "Product")] #[post("/generate/promotion")] async fn generate_promotion( - conn: Connection, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + db: InternalDb, + session: Session +) -> Convert> { check_permissions!(session.clone(), Action::GenerateTemplateContent); - - match Promotion::generate(session, &db).await { - Ok(res) => Ok(Json(res)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Promotion::generate(session, &db.0).await.into() } diff --git a/src/methods/product/mod.rs b/src/methods/product/mod.rs index e1710f1..9d5bf86 100644 --- a/src/methods/product/mod.rs +++ b/src/methods/product/mod.rs @@ -1,8 +1,8 @@ +mod conversions; +mod example; #[cfg(feature = "process")] pub(crate) mod handlers; mod structs; -mod conversions; -mod example; mod variant; #[cfg(feature = "process")] diff --git a/src/methods/product/structs.rs b/src/methods/product/structs.rs index 0cd297d..6601b30 100644 --- a/src/methods/product/structs.rs +++ b/src/methods/product/structs.rs @@ -1,11 +1,11 @@ use std::fmt::Display; -use crate::{History, Session, TransactionType}; +use crate::{methods::Error, History, Session, TransactionType}; use chrono::{DateTime, Utc}; #[cfg(feature = "process")] use sea_orm::{ sea_query::{Expr, Func}, - ActiveModelTrait, ColumnTrait, Condition, DbConn, DbErr, EntityTrait, InsertResult, + ActiveModelTrait, ColumnTrait, Condition, DbConn, EntityTrait, InsertResult, QueryFilter, QuerySelect, Statement, }; use serde::{ @@ -15,8 +15,7 @@ use serde::{ use uuid::Uuid; use super::{ - Promotion, PromotionBuy, PromotionGet, - VariantCategoryList, VariantIdTag, VariantInformation, + Promotion, PromotionBuy, PromotionGet, VariantCategoryList, VariantIdTag, VariantInformation, }; #[cfg(feature = "process")] use crate::entities::prelude::Products; @@ -25,6 +24,7 @@ use crate::entities::prelude::Promotion as Promotions; #[cfg(feature = "process")] use crate::entities::products; +use crate::product::example::example_products; use crate::{ methods::{DiscountValue, TagList, Url}, Note, @@ -33,7 +33,6 @@ use crate::{ use futures::future::join_all; use schemars::JsonSchema; use validator::Validate; -use crate::product::example::example_products; #[cfg(feature = "types")] #[derive(Deserialize, Serialize, Clone, JsonSchema)] @@ -79,7 +78,7 @@ pub struct Product { pub visible: ProductVisibility, pub created_at: DateTime, - pub updated_at: DateTime + pub updated_at: DateTime, } #[cfg(feature = "types")] @@ -115,16 +114,16 @@ impl Product { pdt: Product, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let insert_crud = pdt.into_active(session); match Products::insert(insert_crud).exec(db).await { Ok(res) => Ok(res), - Err(err) => Err(err), + Err(err) => Err(err.into()), } } - pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { + pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { let pdt = Products::find_by_id(id.to_string()) .filter(products::Column::TenantId.eq(session.tenant_id)) .one(db) @@ -139,7 +138,7 @@ impl Product { id: &str, session: Session, db: &DbConn, - ) -> Result { + ) -> Result { let pdt = Products::find_by_id(id.to_string()) .filter(products::Column::TenantId.eq(session.tenant_id)) .one(db) @@ -189,7 +188,7 @@ impl Product { }) } - pub async fn search(query: &str, session: Session, db: &DbConn) -> Result, DbErr> { + pub async fn search(query: &str, session: Session, db: &DbConn) -> Result, Error> { let res = products::Entity::find() .filter(products::Column::TenantId.eq(session.tenant_id)) .filter( @@ -205,10 +204,7 @@ impl Product { .all(db) .await?; - let mapped = res - .iter() - .map(|p| p.clone().into()) - .collect(); + let mapped = res.iter().map(|p| p.clone().into()).collect(); Ok(mapped) } @@ -217,7 +213,7 @@ impl Product { query: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = products::Entity::find() .from_raw_sql( Statement::from_sql_and_values( @@ -303,7 +299,7 @@ impl Product { name: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = products::Entity::find() .having(products::Column::Name.contains(name)) .filter(products::Column::TenantId.eq(session.tenant_id)) @@ -311,10 +307,7 @@ impl Product { .all(db) .await?; - let mapped = res - .iter() - .map(|p| p.clone().into()) - .collect(); + let mapped = res.iter().map(|p| p.clone().into()).collect(); Ok(mapped) } @@ -323,7 +316,7 @@ impl Product { name: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = products::Entity::find() .having(products::Column::Name.eq(name)) .filter(products::Column::TenantId.eq(session.tenant_id)) @@ -331,10 +324,7 @@ impl Product { .all(db) .await?; - let mapped = res - .iter() - .map(|p| p.clone().into()) - .collect(); + let mapped = res.iter().map(|p| p.clone().into()).collect(); Ok(mapped) } @@ -344,24 +334,19 @@ impl Product { session: Session, id: &str, db: &DbConn, - ) -> Result { - pdt.into_active(session.clone()) - .update(db) - .await?; + ) -> Result { + pdt.into_active(session.clone()).update(db).await?; Self::fetch_by_id(id, session, db).await } - pub async fn fetch_all(session: Session, db: &DbConn) -> Result, DbErr> { + pub async fn fetch_all(session: Session, db: &DbConn) -> Result, Error> { let products = Products::find() .filter(products::Column::TenantId.eq(session.tenant_id)) .all(db) .await?; - let mapped = products - .iter() - .map(|p| p.clone().into()) - .collect(); + let mapped = products.iter().map(|p| p.clone().into()).collect(); Ok(mapped) } @@ -370,18 +355,15 @@ impl Product { products: Vec, session: Session, db: &DbConn, - ) -> Result, DbErr> { - let entities = products.into_iter().map(|pdt| - pdt.into_active(session.clone()) - ); + ) -> Result, Error> { + let entities = products + .into_iter() + .map(|pdt| pdt.into_active(session.clone())); - match Products::insert_many(entities).exec(db).await { - Ok(res) => Ok(res), - Err(err) => Err(err), - } + Products::insert_many(entities).exec(db).await.map_err(|e| e.into()) } - pub async fn generate(session: Session, db: &DbConn) -> Result, DbErr> { + pub async fn generate(session: Session, db: &DbConn) -> Result, Error> { let products = example_products(); match Product::insert_many(products, session.clone(), db).await { diff --git a/src/methods/product/variant.rs b/src/methods/product/variant.rs index 69f549b..d04a9af 100644 --- a/src/methods/product/variant.rs +++ b/src/methods/product/variant.rs @@ -1,4 +1,5 @@ use chrono::{DateTime, Days, Utc}; +use rocket_okapi::JsonSchema; #[cfg(feature = "process")] use sea_orm::{ ActiveModelTrait, ColumnTrait, DbConn, DbErr, EntityTrait, InsertResult, QueryFilter, @@ -6,12 +7,12 @@ use sea_orm::{ }; use serde::{Deserialize, Serialize}; use std::fmt::Display; -use rocket_okapi::JsonSchema; #[cfg(feature = "process")] use crate::entities::prelude::Promotion as Promotions; #[cfg(feature = "process")] use crate::entities::promotion; +use crate::methods::Error; use crate::methods::{DiscountValue, HistoryList, Id, StockList, Url}; #[cfg(feature = "process")] use crate::products; @@ -165,7 +166,7 @@ impl Promotion { prm: PromotionInput, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let id = Uuid::new_v4().to_string(); let insert_crud = promotion::ActiveModel { @@ -178,13 +179,10 @@ impl Promotion { tenant_id: Set(session.tenant_id), }; - match Promotions::insert(insert_crud).exec(db).await { - Ok(res) => Ok(res), - Err(err) => Err(err), - } + Promotions::insert(insert_crud).exec(db).await.map_err(|e| e.into()) } - pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { + pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { let pdt = Promotions::find_by_id(id.to_string()) .filter(products::Column::TenantId.eq(session.tenant_id)) .one(db) @@ -205,7 +203,7 @@ impl Promotion { query: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = Promotions::find() .filter(products::Column::TenantId.eq(session.tenant_id)) // Is the bought product @@ -239,7 +237,7 @@ impl Promotion { session: Session, id: &str, db: &DbConn, - ) -> Result { + ) -> Result { promotion::ActiveModel { id: Set(id.to_string()), name: Set(prm.name.to_string()), @@ -255,7 +253,7 @@ impl Promotion { Self::fetch_by_id(id, session, db).await } - pub async fn fetch_all(session: Session, db: &DbConn) -> Result, DbErr> { + pub async fn fetch_all(session: Session, db: &DbConn) -> Result, Error> { let stores = Promotions::find() .filter(promotion::Column::TenantId.eq(session.tenant_id)) .all(db) @@ -280,7 +278,7 @@ impl Promotion { stores: Vec, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let entities = stores.into_iter().map(|prm| { let id = Uuid::new_v4().to_string(); @@ -295,13 +293,10 @@ impl Promotion { } }); - match Promotions::insert_many(entities).exec(db).await { - Ok(res) => Ok(res), - Err(err) => Err(err), - } + Promotions::insert_many(entities).exec(db).await.map_err(|e| e.into()) } - pub async fn generate(session: Session, db: &DbConn) -> Result, DbErr> { + pub async fn generate(session: Session, db: &DbConn) -> Result, Error> { let promotions = example_promotions(); match Promotion::insert_many(promotions, session.clone(), db).await { diff --git a/src/methods/stml/mod.rs b/src/methods/stml/mod.rs index 8085f55..acf2981 100644 --- a/src/methods/stml/mod.rs +++ b/src/methods/stml/mod.rs @@ -2,4 +2,4 @@ mod order; mod stock; pub use self::stock::*; -pub use order::*; \ No newline at end of file +pub use order::*; diff --git a/src/methods/store/conversions.rs b/src/methods/store/conversions.rs index 458f546..1523a6b 100644 --- a/src/methods/store/conversions.rs +++ b/src/methods/store/conversions.rs @@ -1,8 +1,8 @@ +use crate::entities::store::{ActiveModel, Model}; +use crate::{ContactInformation, Session, Store}; use chrono::{DateTime, Utc}; use sea_orm::ActiveValue::Set; use serde_json::json; -use crate::entities::store::{ActiveModel, Model}; -use crate::{ContactInformation, Session, Store}; impl Store { pub(crate) fn into_active(self, session: Session) -> ActiveModel { @@ -26,7 +26,7 @@ impl From for Store { contact: serde_json::from_value::(val.contact).unwrap(), code: serde_json::from_value::(serde_json::Value::String(val.code)).unwrap(), updated_at: DateTime::from_naive_utc_and_offset(val.updated_at, Utc), - created_at: DateTime::from_naive_utc_and_offset(val.created_at, Utc) + created_at: DateTime::from_naive_utc_and_offset(val.created_at, Utc), } } -} \ No newline at end of file +} diff --git a/src/methods/store/example.rs b/src/methods/store/example.rs index 2b89539..8a1f330 100644 --- a/src/methods/store/example.rs +++ b/src/methods/store/example.rs @@ -1,5 +1,5 @@ -use chrono::Utc; use crate::{Address, ContactInformation, Email, MobileNumber, Store}; +use chrono::Utc; pub fn example_stores() -> Vec { vec![ diff --git a/src/methods/store/handlers.rs b/src/methods/store/handlers.rs index 5991ddb..0989bbb 100644 --- a/src/methods/store/handlers.rs +++ b/src/methods/store/handlers.rs @@ -1,9 +1,9 @@ +use crate::catchers::Validated; use okapi::openapi3::OpenApi; use rocket::{get, http::CookieJar, post, serde::json::Json}; use rocket_db_pools::Connection; -use rocket_okapi::{openapi, openapi_get_routes_spec}; use rocket_okapi::settings::OpenApiSettings; -use crate::catchers::Validated; +use rocket_okapi::{openapi, openapi_get_routes_spec}; use crate::{ check_permissions, diff --git a/src/methods/store/mod.rs b/src/methods/store/mod.rs index f9fb6e8..90b4a50 100644 --- a/src/methods/store/mod.rs +++ b/src/methods/store/mod.rs @@ -1,8 +1,8 @@ +mod conversions; +mod example; #[cfg(feature = "process")] pub(crate) mod handlers; mod structs; -mod conversions; -mod example; pub use self::structs::*; #[cfg(feature = "process")] diff --git a/src/methods/store/structs.rs b/src/methods/store/structs.rs index 16980ca..4036dad 100644 --- a/src/methods/store/structs.rs +++ b/src/methods/store/structs.rs @@ -1,11 +1,11 @@ use chrono::{DateTime, Utc}; use schemars::JsonSchema; +use sea_orm::Set; #[cfg(feature = "process")] use sea_orm::{ ActiveModelTrait, ColumnTrait, DbConn, DbErr, EntityTrait, InsertResult, QueryFilter, QuerySelect, RuntimeErr, }; -use sea_orm::Set; use serde::{Deserialize, Serialize}; #[cfg(feature = "process")] @@ -13,15 +13,14 @@ use crate::entities::prelude::Store as StoreEntity; #[cfg(feature = "process")] use crate::entities::store; - #[cfg(feature = "process")] use crate::methods::convert_addr_to_geo; +use crate::methods::store::example::example_stores; use crate::methods::{ContactInformation, Id}; use crate::Session; use serde_json::json; use validator::Validate; -use crate::methods::store::example::example_stores; #[cfg(feature = "types")] #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Validate)] @@ -33,7 +32,7 @@ pub struct Store { pub code: String, pub created_at: DateTime, - pub updated_at: DateTime + pub updated_at: DateTime, } #[cfg(feature = "methods")] @@ -56,11 +55,7 @@ impl Store { session: Session, db: &DbConn, ) -> Result, DbErr> { - let entities = stores - .into_iter() - .map(|s| - s.into_active(session.clone()) - ); + let entities = stores.into_iter().map(|s| s.into_active(session.clone())); match StoreEntity::insert_many(entities).exec(db).await { Ok(res) => Ok(res), @@ -99,10 +94,7 @@ impl Store { .all(db) .await?; - let mapped = stores - .iter() - .map(|e| e.clone().into()) - .collect(); + let mapped = stores.iter().map(|e| e.clone().into()).collect(); Ok(mapped) } @@ -130,9 +122,7 @@ impl Store { model.contact = Set(json!(new_contact)); - model - .update(db) - .await?; + model.update(db).await?; Self::fetch_by_id(id, session, db).await } diff --git a/src/methods/supplier/conversions.rs b/src/methods/supplier/conversions.rs index 3dbe856..6834641 100644 --- a/src/methods/supplier/conversions.rs +++ b/src/methods/supplier/conversions.rs @@ -1,8 +1,8 @@ +use crate::entities::supplier::{ActiveModel, Model}; +use crate::{ContactInformation, Name, Supplier, SupplierInput, Transaction}; use chrono::{DateTime, Utc}; use sea_orm::ActiveValue::Set; use serde_json::json; -use crate::entities::supplier::{ActiveModel, Model}; -use crate::{ContactInformation, Name, Supplier, SupplierInput, Transaction}; impl From for Supplier { fn from(val: Model) -> Self { @@ -10,10 +10,12 @@ impl From for Supplier { id: val.id, name: serde_json::from_value::(val.name).unwrap(), contact: serde_json::from_value::(val.contact).unwrap(), - transaction_history: serde_json::from_value::>(val.transaction_history) - .unwrap(), + transaction_history: serde_json::from_value::>( + val.transaction_history, + ) + .unwrap(), created_at: DateTime::from_naive_utc_and_offset(val.created_at, Utc), - updated_at: DateTime::from_naive_utc_and_offset(val.updated_at, Utc) + updated_at: DateTime::from_naive_utc_and_offset(val.updated_at, Utc), } } } @@ -30,4 +32,4 @@ impl SupplierInput { updated_at: Set(Utc::now().naive_utc()), } } -} \ No newline at end of file +} diff --git a/src/methods/supplier/handlers.rs b/src/methods/supplier/handlers.rs index b7ab933..badb1d7 100644 --- a/src/methods/supplier/handlers.rs +++ b/src/methods/supplier/handlers.rs @@ -1,16 +1,16 @@ -use okapi::openapi3::OpenApi; +use crate::catchers::Validated; use crate::check_permissions; use crate::methods::employee::Action; use crate::methods::{cookie_status_wrapper, Error, ErrorResponse}; use crate::pool::Db; +use okapi::openapi3::OpenApi; use rocket::get; use rocket::http::CookieJar; +use rocket::post; use rocket::serde::json::Json; -use rocket::{post}; use rocket_db_pools::Connection; -use rocket_okapi::{openapi, openapi_get_routes_spec}; use rocket_okapi::settings::OpenApiSettings; -use crate::catchers::Validated; +use rocket_okapi::{openapi, openapi_get_routes_spec}; use super::{Supplier, SupplierInput}; @@ -101,10 +101,7 @@ pub async fn get_by_addr( #[openapi(tag = "Supplier")] #[post("/generate")] -async fn generate( - conn: Connection, - cookies: &CookieJar<'_>, -) -> Result, Error> { +async fn generate(conn: Connection, cookies: &CookieJar<'_>) -> Result, Error> { let db = conn.into_inner(); let session = cookie_status_wrapper(&db, cookies).await?; @@ -150,16 +147,13 @@ pub async fn create( check_permissions!(session.clone(), Action::ModifySupplier); match Supplier::insert(new_data, session.clone(), &db).await { - Ok(data) => - match Supplier::fetch_by_id( - &data.last_insert_id, session, &db - ).await { - Ok(res) => Ok(Json(res)), - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::db_err(reason)) - } - }, + Ok(data) => match Supplier::fetch_by_id(&data.last_insert_id, session, &db).await { + Ok(res) => Ok(Json(res)), + Err(reason) => { + println!("[dberr]: {}", reason); + Err(ErrorResponse::db_err(reason)) + } + }, Err(reason) => { println!("[dberr]: {}", reason); Err(ErrorResponse::input_error()) diff --git a/src/methods/supplier/mod.rs b/src/methods/supplier/mod.rs index f9fb6e8..90b4a50 100644 --- a/src/methods/supplier/mod.rs +++ b/src/methods/supplier/mod.rs @@ -1,8 +1,8 @@ +mod conversions; +mod example; #[cfg(feature = "process")] pub(crate) mod handlers; mod structs; -mod conversions; -mod example; pub use self::structs::*; #[cfg(feature = "process")] diff --git a/src/methods/supplier/structs.rs b/src/methods/supplier/structs.rs index f2e2113..e95d06e 100644 --- a/src/methods/supplier/structs.rs +++ b/src/methods/supplier/structs.rs @@ -1,6 +1,6 @@ -use std::fmt::Display; use chrono::{DateTime, Utc}; use schemars::JsonSchema; +use std::fmt::Display; #[cfg(feature = "process")] use crate::entities::prelude::Supplier as Suppl; @@ -13,17 +13,17 @@ use crate::methods::{ContactInformation, Name, Transaction}; #[cfg(feature = "process")] use crate::methods::convert_addr_to_geo; +use crate::methods::supplier::example::example_supplier; +use sea_orm::ActiveValue::Set; #[cfg(feature = "process")] use sea_orm::{ ActiveModelTrait, ColumnTrait, DbConn, DbErr, EntityTrait, InsertResult, QueryFilter, QuerySelect, RuntimeErr, }; -use sea_orm::ActiveValue::Set; use serde::{Deserialize, Serialize}; use serde_json::json; use uuid::Uuid; use validator::Validate; -use crate::methods::supplier::example::example_supplier; #[cfg(feature = "types")] #[derive(Serialize, Deserialize, Clone, JsonSchema, Validate)] @@ -35,7 +35,7 @@ pub struct Supplier { pub transaction_history: Vec, pub created_at: DateTime, - pub updated_at: DateTime + pub updated_at: DateTime, } #[cfg(feature = "types")] @@ -55,9 +55,10 @@ impl Supplier { ) -> Result, DbErr> { let id = Uuid::new_v4().to_string(); - match Suppl::insert( - suppl.into_active(id, session.tenant_id.clone()) - ).exec(db).await { + match Suppl::insert(suppl.into_active(id, session.tenant_id.clone())) + .exec(db) + .await + { Ok(res) => Ok(res), Err(err) => Err(err), } @@ -85,10 +86,7 @@ impl Supplier { .all(db) .await?; - let mapped = res - .iter() - .map(|s| s.clone().into()) - .collect(); + let mapped = res.iter().map(|s| s.clone().into()).collect(); Ok(mapped) } @@ -105,10 +103,7 @@ impl Supplier { .all(db) .await?; - let mapped = res - .iter() - .map(|s| s.clone().into()) - .collect(); + let mapped = res.iter().map(|s| s.clone().into()).collect(); Ok(mapped) } @@ -125,10 +120,7 @@ impl Supplier { .all(db) .await?; - let mapped = res - .iter() - .map(|s| s.clone().into()) - .collect(); + let mapped = res.iter().map(|s| s.clone().into()).collect(); Ok(mapped) } @@ -163,9 +155,7 @@ impl Supplier { let mut new_contact = suppl.contact.clone(); new_contact.address = ad; - let mut supplier = suppl.into_active( - id.to_string(),session.tenant_id.clone() - ); + let mut supplier = suppl.into_active(id.to_string(), session.tenant_id.clone()); supplier.contact = Set(json!(new_contact)); supplier.update(db).await?; diff --git a/src/methods/tenant/conversions.rs b/src/methods/tenant/conversions.rs index 1cfe4e6..28495bb 100644 --- a/src/methods/tenant/conversions.rs +++ b/src/methods/tenant/conversions.rs @@ -1,8 +1,8 @@ +use crate::tenants::{ActiveModel, Model}; +use crate::{Tenant, TenantSettings}; use chrono::{DateTime, Utc}; use sea_orm::ActiveValue::Set; use serde_json::json; -use crate::{Tenant, TenantSettings}; -use crate::tenants::{ActiveModel, Model}; impl From for Tenant { fn from(val: Model) -> Self { @@ -27,4 +27,4 @@ impl From for ActiveModel { updated_at: Set(val.updated_at.naive_utc()), } } -} \ No newline at end of file +} diff --git a/src/methods/tenant/mod.rs b/src/methods/tenant/mod.rs index 31fada1..c93e2a7 100644 --- a/src/methods/tenant/mod.rs +++ b/src/methods/tenant/mod.rs @@ -1,7 +1,7 @@ +mod conversions; #[cfg(feature = "process")] pub(crate) mod handlers; mod structs; -mod conversions; #[cfg(feature = "process")] pub use handlers::*; diff --git a/src/methods/tenant/structs.rs b/src/methods/tenant/structs.rs index 4a72a54..1b575dc 100644 --- a/src/methods/tenant/structs.rs +++ b/src/methods/tenant/structs.rs @@ -7,7 +7,6 @@ use sea_orm::{DbConn, DbErr, EntityTrait, InsertResult}; use serde::{Deserialize, Serialize}; use validator::Validate; - use crate::Id; #[cfg(feature = "types")] @@ -23,7 +22,7 @@ pub struct Tenant { pub settings: TenantSettings, pub created_at: DateTime, - pub updated_at: DateTime + pub updated_at: DateTime, } #[cfg(feature = "methods")] diff --git a/src/methods/transaction/conversions.rs b/src/methods/transaction/conversions.rs index dba75f4..2436fb1 100644 --- a/src/methods/transaction/conversions.rs +++ b/src/methods/transaction/conversions.rs @@ -1,12 +1,13 @@ +#[cfg(feature = "process")] +use crate::entities::sea_orm_active_enums::TransactionType as SeaORMTType; +use crate::transactions::{ActiveModel, Model}; +use crate::{ + NoteList, OrderList, Payment, Session, Transaction, TransactionCustomer, TransactionInit, + TransactionInput, TransactionType, +}; use chrono::{DateTime, Utc}; use sea_orm::ActiveValue::Set; use serde_json::json; -#[cfg(feature = "process")] -use crate::entities::{ - sea_orm_active_enums::TransactionType as SeaORMTType -}; -use crate::{NoteList, OrderList, Payment, Session, Transaction, TransactionCustomer, TransactionInit, TransactionInput, TransactionType}; -use crate::transactions::{ActiveModel, Model}; impl From for TransactionType { fn from(value: SeaORMTType) -> Self { @@ -89,7 +90,7 @@ impl Transaction { kiosk: Set(self.kiosk), tenant_id: Set(tenant_id), created_at: Set(self.created_at.naive_utc()), - updated_at: Set(self.updated_at.naive_utc()) + updated_at: Set(self.updated_at.naive_utc()), } } } @@ -116,4 +117,4 @@ impl From for Transaction { updated_at: DateTime::from_naive_utc_and_offset(val.updated_at, Utc), } } -} \ No newline at end of file +} diff --git a/src/methods/transaction/example.rs b/src/methods/transaction/example.rs index 52bfa95..4898394 100644 --- a/src/methods/transaction/example.rs +++ b/src/methods/transaction/example.rs @@ -1,6 +1,11 @@ +use crate::{ + Address, ContactInformation, CustomerType, DiscountValue, Email, History, Location, + MobileNumber, Note, Order, OrderStatus, OrderStatusAssignment, Payment, PaymentAction, + PaymentProcessor, PaymentStatus, PickStatus, Price, ProductInstance, ProductPurchase, + TransactionCustomer, TransactionInit, TransactionType, TransitInformation, +}; use chrono::{Days, Duration, Utc}; use uuid::Uuid; -use crate::{Address, ContactInformation, CustomerType, DiscountValue, Email, History, Location, MobileNumber, Note, Order, OrderStatus, OrderStatusAssignment, Payment, PaymentAction, PaymentProcessor, PaymentStatus, PickStatus, Price, ProductInstance, ProductPurchase, TransactionCustomer, TransactionInit, TransactionType, TransitInformation}; pub fn example_transaction(customer_id: &str) -> TransactionInit { let torpedo7 = ContactInformation { diff --git a/src/methods/transaction/handlers.rs b/src/methods/transaction/handlers.rs index 6084d67..ef8707a 100644 --- a/src/methods/transaction/handlers.rs +++ b/src/methods/transaction/handlers.rs @@ -1,18 +1,20 @@ +use crate::catchers::Validated; use okapi::openapi3::OpenApi; use rocket::get; use rocket::http::CookieJar; +use rocket::post; use rocket::serde::json::Json; -use rocket::{post}; use rocket_db_pools::Connection; -use rocket_okapi::{openapi, openapi_get_routes_spec}; use rocket_okapi::settings::OpenApiSettings; -use crate::catchers::Validated; +use rocket_okapi::{openapi, openapi_get_routes_spec}; use super::{Transaction, TransactionInit, TransactionInput}; use crate::methods::employee::Action; use crate::methods::{cookie_status_wrapper, Error, ErrorResponse, QuantityAlterationIntent}; use crate::pool::Db; -use crate::{apply_discount, check_permissions, Order, OrderStatus, ProductStatusUpdate, TransactionType}; +use crate::{ + apply_discount, check_permissions, Order, OrderStatus, ProductStatusUpdate, TransactionType, +}; pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, OpenApi) { openapi_get_routes_spec![ @@ -200,8 +202,7 @@ async fn update_product_status( .unwrap(); let id = tsn.get(0).unwrap().id.as_str(); - match Transaction::update_product_status(id, data, session, &db).await - { + match Transaction::update_product_status(id, data, session, &db).await { Ok(res) => Ok(Json(res)), Err(_) => Err(ErrorResponse::input_error()), } @@ -304,7 +305,9 @@ pub async fn create( } }; - Ok(Json(Transaction::fetch_by_id(&insertion.last_insert_id, session, &db).await?)) + Ok(Json( + Transaction::fetch_by_id(&insertion.last_insert_id, session, &db).await?, + )) } #[openapi(tag = "Transaction")] diff --git a/src/methods/transaction/mod.rs b/src/methods/transaction/mod.rs index 138cdbd..82adad9 100644 --- a/src/methods/transaction/mod.rs +++ b/src/methods/transaction/mod.rs @@ -1,8 +1,8 @@ +mod conversions; +mod example; #[cfg(feature = "process")] pub(crate) mod handlers; mod structs; -mod conversions; -mod example; #[cfg(feature = "process")] pub use handlers::*; diff --git a/src/methods/transaction/structs.rs b/src/methods/transaction/structs.rs index 1fa303f..29048d1 100644 --- a/src/methods/transaction/structs.rs +++ b/src/methods/transaction/structs.rs @@ -20,14 +20,17 @@ use sea_orm::FromQueryResult; use crate::entities::{ prelude::Transactions, sea_orm_active_enums::TransactionType as SeaORMTType, transactions, }; -use crate::{methods::{ - History, Id, NoteList, Order, OrderList, OrderStatus, OrderStatusAssignment, Payment, - Product, Session, Stock, VariantInformation, Error -}, PickStatus, ProductInstance}; +use crate::transaction::example::example_transaction; +use crate::{ + methods::{ + Error, History, Id, NoteList, Order, OrderList, OrderStatus, OrderStatusAssignment, + Payment, Product, Session, Stock, VariantInformation, + }, + PickStatus, ProductInstance, +}; #[cfg(feature = "process")] use sea_orm::DbConn; use validator::Validate; -use crate::transaction::example::example_transaction; #[cfg(feature = "types")] #[derive(Debug, Serialize, Deserialize, Clone, JsonSchema, Validate)] @@ -100,7 +103,7 @@ pub struct Transaction { pub kiosk: Id, pub created_at: DateTime, - pub updated_at: DateTime + pub updated_at: DateTime, } #[cfg(feature = "process")] @@ -162,7 +165,7 @@ pub struct ProductStatusUpdate { pub transaction_id: String, pub product_purchase_id: String, pub product_instance_id: String, - pub new_status: PickStatus + pub new_status: PickStatus, } #[cfg(feature = "methods")] @@ -174,7 +177,10 @@ impl Transaction { ) -> Result, DbErr> { let id = Uuid::new_v4().to_string(); - match Transactions::insert(tsn.into_active(id, session)).exec(db).await { + match Transactions::insert(tsn.into_active(id, session)) + .exec(db) + .await + { Ok(res) => Ok(res), Err(err) => Err(err), } @@ -185,7 +191,10 @@ impl Transaction { session: Session, db: &DbConn, ) -> Result, DbErr> { - match Transactions::insert(tsn.into_active(session.tenant_id)).exec(db).await { + match Transactions::insert(tsn.into_active(session.tenant_id)) + .exec(db) + .await + { Ok(res) => Ok(res), Err(err) => Err(err), } @@ -293,10 +302,7 @@ impl Transaction { .all(db) .await?; - let mapped = res - .iter() - .map(|t| t.clone().into()) - .collect(); + let mapped = res.iter().map(|t| t.clone().into()).collect(); Ok(mapped) } @@ -317,10 +323,7 @@ impl Transaction { .all(db) .await?; - let mapped = res - .iter() - .map(|t| t.clone().into()) - .collect(); + let mapped = res.iter().map(|t| t.clone().into()).collect(); Ok(mapped) } @@ -336,10 +339,7 @@ impl Transaction { .all(db) .await?; - let mapped = tsn - .iter() - .map(|t| t.clone().into()) - .collect(); + let mapped = tsn.iter().map(|t| t.clone().into()).collect(); Ok(mapped) } @@ -439,7 +439,8 @@ impl Transaction { timestamp: i.fulfillment_status.last_updated, }); i.fulfillment_status.last_updated = Utc::now(); - i.fulfillment_status.pick_status = update.new_status.clone(); + i.fulfillment_status.pick_status = + update.new_status.clone(); } i diff --git a/src/migrator/m20230730_000002_customer.rs b/src/migrator/m20230730_000002_customer.rs index 1779f51..5e6c4b7 100644 --- a/src/migrator/m20230730_000002_customer.rs +++ b/src/migrator/m20230730_000002_customer.rs @@ -26,11 +26,7 @@ impl MigrationTrait for Migration { .col(ColumnDef::new(Customer::TenantId).string().not_null()) .col(ColumnDef::new(Customer::Contact).json().not_null()) .col(ColumnDef::new(Customer::CustomerNotes).json().not_null()) - .col( - ColumnDef::new(Customer::Balance) - .big_integer() - .not_null(), - ) + .col(ColumnDef::new(Customer::Balance).big_integer().not_null()) .col(ColumnDef::new(Customer::SpecialPricing).json().not_null()) .col( ColumnDef::new(Customer::AcceptsMarketing) diff --git a/src/migrator/m20230730_000006_session.rs b/src/migrator/m20230730_000006_session.rs index 45b5bfa..ec0963a 100644 --- a/src/migrator/m20230730_000006_session.rs +++ b/src/migrator/m20230730_000006_session.rs @@ -55,5 +55,5 @@ pub enum Session { #[iden = "tenant_id"] TenantId, #[iden = "variant"] - Variant + Variant, } diff --git a/src/pool.rs b/src/pool.rs index e942df6..1564568 100644 --- a/src/pool.rs +++ b/src/pool.rs @@ -2,7 +2,7 @@ use crate::entities::{session, transactions}; #[cfg(feature = "process")] use crate::migrator::Migrator; -use crate::{SessionVariant}; +use crate::SessionVariant; use crate::{example_employee, Customer, Kiosk, Product, Session, Store, Transaction}; #[cfg(feature = "process")] use async_trait::async_trait; @@ -58,9 +58,9 @@ impl<'a> FromRequest<'a> for InternalDb { Outcome::Success(s) => { let database = s.into_inner(); Outcome::Success(InternalDb(database)) - }, + } Outcome::Error(e) => Outcome::Error(e), - Outcome::Forward(f) => Outcome::Forward(f) + Outcome::Forward(f) => Outcome::Forward(f), } } } diff --git a/tests/client_test.rs b/tests/client_test.rs index f326dbc..bd2091b 100644 --- a/tests/client_test.rs +++ b/tests/client_test.rs @@ -3,7 +3,7 @@ use std::time::{Duration, Instant}; #[cfg(feature = "process")] #[tokio::test] async fn main() { - let mut durations: Vec = vec![]; + let mut durations: Vec = vec![]; let client = reqwest::Client::new(); @@ -36,4 +36,4 @@ async fn main() { // let avg_duration = durations.iter().sum::() as f32 / durations.len() as f32; assert_eq!("A", "A"); -} \ No newline at end of file +} From d335ac9afe970d8ea4bfbbc94ecdfd6b205e2931 Mon Sep 17 00:00:00 2001 From: Ben White Date: Tue, 6 Feb 2024 17:17:03 +1100 Subject: [PATCH 5/8] mod: stores --- src/methods/store/handlers.rs | 91 +++++++++-------------------------- 1 file changed, 22 insertions(+), 69 deletions(-) diff --git a/src/methods/store/handlers.rs b/src/methods/store/handlers.rs index 0989bbb..19939b2 100644 --- a/src/methods/store/handlers.rs +++ b/src/methods/store/handlers.rs @@ -4,12 +4,14 @@ use rocket::{get, http::CookieJar, post, serde::json::Json}; use rocket_db_pools::Connection; use rocket_okapi::settings::OpenApiSettings; use rocket_okapi::{openapi, openapi_get_routes_spec}; +use open_stock::{InternalDb, Session}; use crate::{ check_permissions, methods::{cookie_status_wrapper, Action, Error, ErrorResponse}, pool::Db, }; +use crate::guards::Convert; use super::Store; @@ -22,102 +24,53 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Store")] #[get("/")] pub async fn get_all( - conn: Connection, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + db: InternalDb, + session: Session, +) -> Convert> { check_permissions!(session.clone(), Action::FetchStore); - - match Store::fetch_all(session, &db).await { - Ok(stores) => Ok(Json(stores)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Store::fetch_all(session, &db.0).await.into() } #[openapi(tag = "Store")] #[get("/")] pub async fn get( - conn: Connection, + db: InternalDb, + session: Session, id: &str, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert { check_permissions!(session.clone(), Action::FetchStore); - - match Store::fetch_by_id(id, session, &db).await { - Ok(store) => Ok(Json(store)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Store::fetch_by_id(id, session, &db.0).await.into() } #[openapi(tag = "Store")] #[get("/code/")] pub async fn get_by_code( - conn: Connection, + db: InternalDb, + session: Session, code: &str, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert { check_permissions!(session.clone(), Action::FetchStore); - - match Store::fetch_by_code(code, session, &db).await { - Ok(store) => Ok(Json(store)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Store::fetch_by_code(code, session, &db.0).await.into() } #[openapi(tag = "Store")] #[post("/generate")] async fn generate( - conn: Connection, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + db: InternalDb, + session: Session, +) -> Convert> { check_permissions!(session.clone(), Action::GenerateTemplateContent); - - match Store::generate(session, &db).await { - Ok(res) => Ok(Json(res)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Store::generate(session, &db.0).await.into() } #[openapi(tag = "Store")] #[post("/", data = "")] async fn update( - conn: Connection, - id: &str, - cookies: &CookieJar<'_>, + db: InternalDb, + session: Session, input_data: Validated>, + id: &str, ) -> Result, Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::ModifyStore); - - if session - .clone() - .employee - .level - .into_iter() - .find(|x| x.action == Action::ModifyStore) - .unwrap() - .authority - >= 1 - { - match Store::update(input_data, session, id, &db).await { - Ok(res) => Ok(Json(res)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } - } else { - Err(ErrorResponse::unauthorized(Action::ModifyStore)) - } + Store::update(input_data.data(), session, id, &db.0).await.into() } From 2765e9ef5615f8ed03584e323916e8a6b75af4ab Mon Sep 17 00:00:00 2001 From: Ben White Date: Tue, 6 Feb 2024 17:38:48 +1100 Subject: [PATCH 6/8] mod: suppliers --- src/methods/supplier/handlers.rs | 116 ++++++++----------------------- src/methods/supplier/structs.rs | 26 +++---- 2 files changed, 40 insertions(+), 102 deletions(-) diff --git a/src/methods/supplier/handlers.rs b/src/methods/supplier/handlers.rs index badb1d7..babff88 100644 --- a/src/methods/supplier/handlers.rs +++ b/src/methods/supplier/handlers.rs @@ -1,8 +1,8 @@ use crate::catchers::Validated; -use crate::check_permissions; +use crate::{check_permissions, Session}; use crate::methods::employee::Action; use crate::methods::{cookie_status_wrapper, Error, ErrorResponse}; -use crate::pool::Db; +use crate::pool::{Db, InternalDb}; use okapi::openapi3::OpenApi; use rocket::get; use rocket::http::CookieJar; @@ -11,6 +11,7 @@ use rocket::serde::json::Json; use rocket_db_pools::Connection; use rocket_okapi::settings::OpenApiSettings; use rocket_okapi::{openapi, openapi_get_routes_spec}; +use crate::guards::Convert; use super::{Supplier, SupplierInput}; @@ -30,133 +31,76 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Supplier")] #[get("/")] pub async fn get( - conn: Connection, + db: InternalDb, + session: Session, id: &str, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert { check_permissions!(session.clone(), Action::FetchSupplier); - - match Supplier::fetch_by_id(id, session, &db).await { - Ok(supplier) => Ok(Json(supplier)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Supplier::fetch_by_id(id, session, &db.0).await.into() } #[openapi(tag = "Supplier")] #[get("/name/")] pub async fn get_by_name( - conn: Connection, + db: InternalDb, + session: Session, name: &str, - cookies: &CookieJar<'_>, ) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::FetchSupplier); - - match Supplier::fetch_by_name(name, session, &db).await { - Ok(suppliers) => Ok(Json(suppliers)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Supplier::fetch_by_name(name, session, &db.0).await.into() } #[openapi(tag = "Supplier")] #[get("/phone/")] pub async fn get_by_phone( - conn: Connection, + db: InternalDb, + session: Session, phone: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchSupplier); - - match Supplier::fetch_by_phone(phone, session, &db).await { - Ok(suppliers) => Ok(Json(suppliers)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Supplier::fetch_by_phone(phone, session, &db.0).await.into() } #[openapi(tag = "Supplier")] #[get("/addr/")] pub async fn get_by_addr( - conn: Connection, + db: InternalDb, + session: Session, addr: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchSupplier); - - match Supplier::fetch_by_addr(addr, session, &db).await { - Ok(suppliers) => Ok(Json(suppliers)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Supplier::fetch_by_addr(addr, session, &db.0).await.into() } #[openapi(tag = "Supplier")] #[post("/generate")] -async fn generate(conn: Connection, cookies: &CookieJar<'_>) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +async fn generate(session: Session, db: InternalDb) -> Convert { check_permissions!(session.clone(), Action::GenerateTemplateContent); - - match Supplier::generate(session, &db).await { - Ok(res) => Ok(Json(res)), - Err(err) => Err(ErrorResponse::db_err(err)), - } + Supplier::generate(session, &db.0).await.into() } #[openapi(tag = "Supplier")] #[post("/", data = "")] async fn update( - conn: Connection, - id: &str, - cookies: &CookieJar<'_>, + session: Session, + db: InternalDb, input_data: Validated>, -) -> Result, Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + id: &str, +) -> Convert { check_permissions!(session.clone(), Action::ModifySupplier); - - match Supplier::update(input_data, session, id, &db).await { - Ok(res) => Ok(Json(res)), - Err(_) => Err(ErrorResponse::input_error()), - } + Supplier::update(input_data.data(), session, id, &db.0).await.into() } #[openapi(tag = "Supplier")] #[post("/", data = "")] pub async fn create( - conn: Connection, - cookies: &CookieJar<'_>, + session: Session, + db: InternalDb, input_data: Json, ) -> Result, Error> { - let new_data = input_data.clone().into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::ModifySupplier); - match Supplier::insert(new_data, session.clone(), &db).await { - Ok(data) => match Supplier::fetch_by_id(&data.last_insert_id, session, &db).await { - Ok(res) => Ok(Json(res)), - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::db_err(reason)) - } - }, - Err(reason) => { - println!("[dberr]: {}", reason); - Err(ErrorResponse::input_error()) - } - } + let data = Supplier::insert(input_data.data(), session.clone(), &db.0).await?; + let converted: Convert = Supplier::fetch_by_id(&data.last_insert_id, session, &db.0).await.into(); + converted.0 } diff --git a/src/methods/supplier/structs.rs b/src/methods/supplier/structs.rs index e95d06e..9760bed 100644 --- a/src/methods/supplier/structs.rs +++ b/src/methods/supplier/structs.rs @@ -6,6 +6,7 @@ use std::fmt::Display; use crate::entities::prelude::Supplier as Suppl; #[cfg(feature = "process")] use crate::entities::supplier; +use crate::methods::Error; use crate::Session; use crate::methods::{ContactInformation, Name, Transaction}; @@ -52,19 +53,12 @@ impl Supplier { suppl: SupplierInput, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let id = Uuid::new_v4().to_string(); - - match Suppl::insert(suppl.into_active(id, session.tenant_id.clone())) - .exec(db) - .await - { - Ok(res) => Ok(res), - Err(err) => Err(err), - } + Suppl::insert(suppl.into_active(id, session.tenant_id.clone())).exec(db).await.map_err(|e| e.into()) } - pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { + pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { let suppl = Suppl::find_by_id(id.to_string()) .filter(supplier::Column::TenantId.eq(session.tenant_id)) .one(db) @@ -78,7 +72,7 @@ impl Supplier { name: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = supplier::Entity::find() .filter(supplier::Column::TenantId.eq(session.tenant_id)) .having(supplier::Column::Name.contains(name)) @@ -95,7 +89,7 @@ impl Supplier { phone: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = supplier::Entity::find() .filter(supplier::Column::TenantId.eq(session.tenant_id)) .having(supplier::Column::Contact.contains(phone)) @@ -112,7 +106,7 @@ impl Supplier { addr: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = supplier::Entity::find() .filter(supplier::Column::TenantId.eq(session.tenant_id)) .having(supplier::Column::Contact.contains(addr)) @@ -126,7 +120,7 @@ impl Supplier { } /// Generate and insert a default customer. - pub async fn generate(session: Session, db: &DbConn) -> Result { + pub async fn generate(session: Session, db: &DbConn) -> Result { let cust = example_supplier(); // Insert & Fetch Customer let r = Supplier::insert(cust, session.clone(), db).await.unwrap(); @@ -141,7 +135,7 @@ impl Supplier { session: Session, id: &str, db: &DbConn, - ) -> Result { + ) -> Result { let addr = convert_addr_to_geo(&format!( "{} {} {} {}", suppl.contact.address.street, @@ -164,7 +158,7 @@ impl Supplier { } Err(_) => Err(DbErr::Query(RuntimeErr::Internal( "Invalid address format".to_string(), - ))), + )).into()), } } } From 9c633b007d06d5848ead3f75a7608fa090609490 Mon Sep 17 00:00:00 2001 From: Ben White Date: Tue, 6 Feb 2024 21:32:29 +1100 Subject: [PATCH 7/8] mod: transactions & format --- src/methods/helpers/handlers.rs | 3 +- src/methods/ingress/handlers.rs | 10 +- src/methods/product/handlers.rs | 87 +++++------ src/methods/product/structs.rs | 9 +- src/methods/product/variant.rs | 10 +- src/methods/store/handlers.rs | 30 ++-- src/methods/supplier/handlers.rs | 30 ++-- src/methods/supplier/structs.rs | 11 +- src/methods/tenant/handlers.rs | 16 +- src/methods/tenant/structs.rs | 17 +- src/methods/transaction/handlers.rs | 234 ++++++++++------------------ tests/client_test.rs | 1 - 12 files changed, 186 insertions(+), 272 deletions(-) diff --git a/src/methods/helpers/handlers.rs b/src/methods/helpers/handlers.rs index a4aa6dc..4312a6c 100644 --- a/src/methods/helpers/handlers.rs +++ b/src/methods/helpers/handlers.rs @@ -123,8 +123,7 @@ pub async fn generate_template(db: InternalDb) -> Result, Error> { .await .map_err(ErrorResponse::db_err)?; - let promotions = Promotion::generate(session, &db.0) - .await?; + let promotions = Promotion::generate(session, &db.0).await?; Ok(Json(All { employee, diff --git a/src/methods/ingress/handlers.rs b/src/methods/ingress/handlers.rs index 2ec3704..c43fccb 100644 --- a/src/methods/ingress/handlers.rs +++ b/src/methods/ingress/handlers.rs @@ -1,4 +1,7 @@ -use crate::{check_permissions, cookie_status_wrapper, methods::Action, methods::Error, Db, ErrorResponse, Session}; +use crate::{ + check_permissions, cookie_status_wrapper, methods::Action, methods::Error, Db, ErrorResponse, + Session, +}; use chrono::Utc; use okapi::openapi3::OpenApi; @@ -16,10 +19,7 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope /// curl -X POST -H "Content-Type: text/plain" -d "@/to/file/location/" http://127.0.0.1:8000/api/ingress/upload #[openapi(tag = "Ingress")] #[post("/upload", format = "plain", data = "")] -async fn upload( - session: Session, - file: TempFile<'_>, -) -> Result<(), Error> { +async fn upload(session: Session, file: TempFile<'_>) -> Result<(), Error> { check_permissions!(session.clone(), Action::AccessAdminPanel); receive_file(file, session.tenant_id).await } diff --git a/src/methods/product/handlers.rs b/src/methods/product/handlers.rs index 95142c3..c04b8bd 100644 --- a/src/methods/product/handlers.rs +++ b/src/methods/product/handlers.rs @@ -1,15 +1,15 @@ +use super::{Product, ProductWPromotion, Promotion, PromotionInput}; use crate::catchers::Validated; -use crate::{check_permissions, Session}; +use crate::guards::Convert; use crate::methods::{Action, Error}; -use crate::pool::{InternalDb}; +use crate::pool::InternalDb; +use crate::{check_permissions, Session}; use okapi::openapi3::OpenApi; use rocket::get; use rocket::post; use rocket::serde::json::Json; use rocket_okapi::settings::OpenApiSettings; use rocket_okapi::{openapi, openapi_get_routes_spec}; -use crate::guards::Convert; -use super::{Product, ProductWPromotion, Promotion, PromotionInput}; pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, OpenApi) { openapi_get_routes_spec![ @@ -33,13 +33,11 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Product")] #[get("/")] -pub async fn get( - session: Session, - db: InternalDb, - id: i32, -) -> Convert { +pub async fn get(session: Session, db: InternalDb, id: i32) -> Convert { check_permissions!(session.clone(), Action::FetchProduct); - Product::fetch_by_id(&id.to_string(), session, &db.0).await.into() + Product::fetch_by_id(&id.to_string(), session, &db.0) + .await + .into() } #[openapi(tag = "Product")] @@ -50,16 +48,14 @@ pub async fn get_with_associated_promotions( id: i32, ) -> Convert { check_permissions!(session.clone(), Action::FetchProduct); - Product::fetch_by_id_with_promotion(&id.to_string(), session, &db.0).await.into() + Product::fetch_by_id_with_promotion(&id.to_string(), session, &db.0) + .await + .into() } #[openapi(tag = "Product")] #[get("/name/")] -pub async fn get_by_name( - db: InternalDb, - session: Session, - name: &str, -) -> Convert> { +pub async fn get_by_name(db: InternalDb, session: Session, name: &str) -> Convert> { check_permissions!(session.clone(), Action::FetchProduct); Product::fetch_by_name(name, session, &db.0).await.into() } @@ -70,20 +66,18 @@ pub async fn get_by_name( pub async fn get_by_name_exact( db: InternalDb, session: Session, - name: &str + name: &str, ) -> Convert> { check_permissions!(session.clone(), Action::FetchProduct); - Product::fetch_by_name_exact(name, session, &db.0).await.into() + Product::fetch_by_name_exact(name, session, &db.0) + .await + .into() } /// Will search by both name, phone and email. #[openapi(tag = "Product")] #[get("/search/")] -pub async fn search_query( - db: InternalDb, - session: Session, - query: &str, -) -> Convert> { +pub async fn search_query(db: InternalDb, session: Session, query: &str) -> Convert> { check_permissions!(session.clone(), Action::FetchProduct); Product::search(query, session, &db.0).await.into() } @@ -96,7 +90,9 @@ pub async fn search_with_associated_promotions( query: &str, ) -> Convert> { check_permissions!(session.clone(), Action::FetchProduct); - Product::search_with_promotion(query, session, &db.0).await.into() + Product::search_with_promotion(query, session, &db.0) + .await + .into() } #[openapi(tag = "Product")] @@ -108,7 +104,9 @@ async fn update( id: &str, ) -> Convert { check_permissions!(session.clone(), Action::ModifyProduct); - Product::update(input_data.data(), session, id, &db.0).await.into() + Product::update(input_data.data(), session, id, &db.0) + .await + .into() } #[openapi(tag = "Product")] @@ -121,29 +119,26 @@ pub async fn create( check_permissions!(session.clone(), Action::CreateProduct); let data = Product::insert(input_data.data(), session.clone(), &db.0).await?; - let converted: Convert = Product::fetch_by_id(&data.last_insert_id, session, &db.0).await.into(); + let converted: Convert = Product::fetch_by_id(&data.last_insert_id, session, &db.0) + .await + .into(); converted.0 } #[openapi(tag = "Product")] #[post("/generate")] -async fn generate( - db: InternalDb, - session: Session, -) -> Convert> { +async fn generate(db: InternalDb, session: Session) -> Convert> { check_permissions!(session.clone(), Action::GenerateTemplateContent); Product::generate(session, &db.0).await.into() } #[openapi(tag = "Product")] #[get("/promotion/")] -pub async fn get_promotion( - db: InternalDb, - session: Session, - id: i32, -) -> Convert { +pub async fn get_promotion(db: InternalDb, session: Session, id: i32) -> Convert { check_permissions!(session.clone(), Action::FetchProduct); - Promotion::fetch_by_id(&id.to_string(), session, &db.0).await.into() + Promotion::fetch_by_id(&id.to_string(), session, &db.0) + .await + .into() } #[openapi(tag = "Product")] @@ -154,7 +149,9 @@ pub async fn get_promotion_by_query( query: &str, ) -> Convert> { check_permissions!(session.clone(), Action::FetchProduct); - Promotion::fetch_by_query(query, session, &db.0).await.into() + Promotion::fetch_by_query(query, session, &db.0) + .await + .into() } #[openapi(tag = "Product")] @@ -166,7 +163,9 @@ async fn update_promotion( id: &str, ) -> Convert { check_permissions!(session.clone(), Action::ModifyProduct); - Promotion::update(input_data.data(), session, id, &db.0).await.into() + Promotion::update(input_data.data(), session, id, &db.0) + .await + .into() } #[openapi(tag = "Product")] @@ -174,21 +173,21 @@ async fn update_promotion( pub async fn create_promotion( db: InternalDb, input_data: Validated>, - session: Session + session: Session, ) -> Result, Error> { check_permissions!(session.clone(), Action::CreateProduct); let data = Promotion::insert(input_data.data(), session.clone(), &db.0).await?; - let converted: Convert = Promotion::fetch_by_id(&data.last_insert_id, session, &db.0).await.into(); + let converted: Convert = + Promotion::fetch_by_id(&data.last_insert_id, session, &db.0) + .await + .into(); converted.0 } #[openapi(tag = "Product")] #[post("/generate/promotion")] -async fn generate_promotion( - db: InternalDb, - session: Session -) -> Convert> { +async fn generate_promotion(db: InternalDb, session: Session) -> Convert> { check_permissions!(session.clone(), Action::GenerateTemplateContent); Promotion::generate(session, &db.0).await.into() } diff --git a/src/methods/product/structs.rs b/src/methods/product/structs.rs index 6601b30..0e0a9f0 100644 --- a/src/methods/product/structs.rs +++ b/src/methods/product/structs.rs @@ -5,8 +5,8 @@ use chrono::{DateTime, Utc}; #[cfg(feature = "process")] use sea_orm::{ sea_query::{Expr, Func}, - ActiveModelTrait, ColumnTrait, Condition, DbConn, EntityTrait, InsertResult, - QueryFilter, QuerySelect, Statement, + ActiveModelTrait, ColumnTrait, Condition, DbConn, EntityTrait, InsertResult, QueryFilter, + QuerySelect, Statement, }; use serde::{ de::{MapAccess, Visitor}, @@ -360,7 +360,10 @@ impl Product { .into_iter() .map(|pdt| pdt.into_active(session.clone())); - Products::insert_many(entities).exec(db).await.map_err(|e| e.into()) + Products::insert_many(entities) + .exec(db) + .await + .map_err(|e| e.into()) } pub async fn generate(session: Session, db: &DbConn) -> Result, Error> { diff --git a/src/methods/product/variant.rs b/src/methods/product/variant.rs index d04a9af..c33f11c 100644 --- a/src/methods/product/variant.rs +++ b/src/methods/product/variant.rs @@ -179,7 +179,10 @@ impl Promotion { tenant_id: Set(session.tenant_id), }; - Promotions::insert(insert_crud).exec(db).await.map_err(|e| e.into()) + Promotions::insert(insert_crud) + .exec(db) + .await + .map_err(|e| e.into()) } pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { @@ -293,7 +296,10 @@ impl Promotion { } }); - Promotions::insert_many(entities).exec(db).await.map_err(|e| e.into()) + Promotions::insert_many(entities) + .exec(db) + .await + .map_err(|e| e.into()) } pub async fn generate(session: Session, db: &DbConn) -> Result, Error> { diff --git a/src/methods/store/handlers.rs b/src/methods/store/handlers.rs index 19939b2..44c0fb4 100644 --- a/src/methods/store/handlers.rs +++ b/src/methods/store/handlers.rs @@ -1,17 +1,17 @@ use crate::catchers::Validated; use okapi::openapi3::OpenApi; +use open_stock::{InternalDb, Session}; use rocket::{get, http::CookieJar, post, serde::json::Json}; use rocket_db_pools::Connection; use rocket_okapi::settings::OpenApiSettings; use rocket_okapi::{openapi, openapi_get_routes_spec}; -use open_stock::{InternalDb, Session}; +use crate::guards::Convert; use crate::{ check_permissions, methods::{cookie_status_wrapper, Action, Error, ErrorResponse}, pool::Db, }; -use crate::guards::Convert; use super::Store; @@ -23,42 +23,28 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Store")] #[get("/")] -pub async fn get_all( - db: InternalDb, - session: Session, -) -> Convert> { +pub async fn get_all(db: InternalDb, session: Session) -> Convert> { check_permissions!(session.clone(), Action::FetchStore); Store::fetch_all(session, &db.0).await.into() } #[openapi(tag = "Store")] #[get("/")] -pub async fn get( - db: InternalDb, - session: Session, - id: &str, -) -> Convert { +pub async fn get(db: InternalDb, session: Session, id: &str) -> Convert { check_permissions!(session.clone(), Action::FetchStore); Store::fetch_by_id(id, session, &db.0).await.into() } #[openapi(tag = "Store")] #[get("/code/")] -pub async fn get_by_code( - db: InternalDb, - session: Session, - code: &str, -) -> Convert { +pub async fn get_by_code(db: InternalDb, session: Session, code: &str) -> Convert { check_permissions!(session.clone(), Action::FetchStore); Store::fetch_by_code(code, session, &db.0).await.into() } #[openapi(tag = "Store")] #[post("/generate")] -async fn generate( - db: InternalDb, - session: Session, -) -> Convert> { +async fn generate(db: InternalDb, session: Session) -> Convert> { check_permissions!(session.clone(), Action::GenerateTemplateContent); Store::generate(session, &db.0).await.into() } @@ -72,5 +58,7 @@ async fn update( id: &str, ) -> Result, Error> { check_permissions!(session.clone(), Action::ModifyStore); - Store::update(input_data.data(), session, id, &db.0).await.into() + Store::update(input_data.data(), session, id, &db.0) + .await + .into() } diff --git a/src/methods/supplier/handlers.rs b/src/methods/supplier/handlers.rs index babff88..90743a6 100644 --- a/src/methods/supplier/handlers.rs +++ b/src/methods/supplier/handlers.rs @@ -1,8 +1,9 @@ use crate::catchers::Validated; -use crate::{check_permissions, Session}; +use crate::guards::Convert; use crate::methods::employee::Action; use crate::methods::{cookie_status_wrapper, Error, ErrorResponse}; use crate::pool::{Db, InternalDb}; +use crate::{check_permissions, Session}; use okapi::openapi3::OpenApi; use rocket::get; use rocket::http::CookieJar; @@ -11,7 +12,6 @@ use rocket::serde::json::Json; use rocket_db_pools::Connection; use rocket_okapi::settings::OpenApiSettings; use rocket_okapi::{openapi, openapi_get_routes_spec}; -use crate::guards::Convert; use super::{Supplier, SupplierInput}; @@ -30,11 +30,7 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Supplier")] #[get("/")] -pub async fn get( - db: InternalDb, - session: Session, - id: &str, -) -> Convert { +pub async fn get(db: InternalDb, session: Session, id: &str) -> Convert { check_permissions!(session.clone(), Action::FetchSupplier); Supplier::fetch_by_id(id, session, &db.0).await.into() } @@ -52,22 +48,14 @@ pub async fn get_by_name( #[openapi(tag = "Supplier")] #[get("/phone/")] -pub async fn get_by_phone( - db: InternalDb, - session: Session, - phone: &str, -) -> Convert> { +pub async fn get_by_phone(db: InternalDb, session: Session, phone: &str) -> Convert> { check_permissions!(session.clone(), Action::FetchSupplier); Supplier::fetch_by_phone(phone, session, &db.0).await.into() } #[openapi(tag = "Supplier")] #[get("/addr/")] -pub async fn get_by_addr( - db: InternalDb, - session: Session, - addr: &str, -) -> Convert> { +pub async fn get_by_addr(db: InternalDb, session: Session, addr: &str) -> Convert> { check_permissions!(session.clone(), Action::FetchSupplier); Supplier::fetch_by_addr(addr, session, &db.0).await.into() } @@ -88,7 +76,9 @@ async fn update( id: &str, ) -> Convert { check_permissions!(session.clone(), Action::ModifySupplier); - Supplier::update(input_data.data(), session, id, &db.0).await.into() + Supplier::update(input_data.data(), session, id, &db.0) + .await + .into() } #[openapi(tag = "Supplier")] @@ -101,6 +91,8 @@ pub async fn create( check_permissions!(session.clone(), Action::ModifySupplier); let data = Supplier::insert(input_data.data(), session.clone(), &db.0).await?; - let converted: Convert = Supplier::fetch_by_id(&data.last_insert_id, session, &db.0).await.into(); + let converted: Convert = Supplier::fetch_by_id(&data.last_insert_id, session, &db.0) + .await + .into(); converted.0 } diff --git a/src/methods/supplier/structs.rs b/src/methods/supplier/structs.rs index 9760bed..3a42aaf 100644 --- a/src/methods/supplier/structs.rs +++ b/src/methods/supplier/structs.rs @@ -55,7 +55,10 @@ impl Supplier { db: &DbConn, ) -> Result, Error> { let id = Uuid::new_v4().to_string(); - Suppl::insert(suppl.into_active(id, session.tenant_id.clone())).exec(db).await.map_err(|e| e.into()) + Suppl::insert(suppl.into_active(id, session.tenant_id.clone())) + .exec(db) + .await + .map_err(|e| e.into()) } pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { @@ -156,9 +159,9 @@ impl Supplier { Self::fetch_by_id(id, session, db).await } - Err(_) => Err(DbErr::Query(RuntimeErr::Internal( - "Invalid address format".to_string(), - )).into()), + Err(_) => { + Err(DbErr::Query(RuntimeErr::Internal("Invalid address format".to_string())).into()) + } } } } diff --git a/src/methods/tenant/handlers.rs b/src/methods/tenant/handlers.rs index 1c45d58..7f9eb52 100644 --- a/src/methods/tenant/handlers.rs +++ b/src/methods/tenant/handlers.rs @@ -1,21 +1,15 @@ +use open_stock::InternalDb; use rocket::get; use rocket::routes; -use rocket::serde::json::Json; -use rocket_db_pools::Connection; -use crate::methods::Error; -use crate::{Db, ErrorResponse, Tenant}; +use crate::guards::Convert; +use crate::Tenant; pub fn routes() -> Vec { routes![get] } #[get("/")] -pub async fn get(conn: Connection, id: String) -> Result, Error> { - let db = conn.into_inner(); - - match Tenant::fetch_by_id(&id, &db).await { - Ok(tenant) => Ok(Json(tenant)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } +pub async fn get(db: InternalDb, id: String) -> Convert { + Tenant::fetch_by_id(&id, &db.0).await.into() } diff --git a/src/methods/tenant/structs.rs b/src/methods/tenant/structs.rs index 1b575dc..4a9d464 100644 --- a/src/methods/tenant/structs.rs +++ b/src/methods/tenant/structs.rs @@ -1,5 +1,5 @@ #[cfg(feature = "process")] -use crate::{entities::prelude::Tenants, tenants}; +use crate::{entities::prelude::Tenants, methods::Error, tenants}; use chrono::{DateTime, Utc}; use schemars::JsonSchema; #[cfg(feature = "process")] @@ -27,19 +27,17 @@ pub struct Tenant { #[cfg(feature = "methods")] impl Tenant { - pub async fn fetch_by_id(id: &str, db: &DbConn) -> Result { + pub async fn fetch_by_id(id: &str, db: &DbConn) -> Result { let tsn = Tenants::find_by_id(id.to_string()).one(db).await?; if tsn.is_none() { - return Err(DbErr::Custom( - "Unable to query value, returns none".to_string(), - )); + return Err(DbErr::Custom("Unable to query value, returns none".to_string()).into()); } Ok(tsn.unwrap().into()) } - pub async fn generate(db: &DbConn, tenant_id: &str) -> Result { + pub async fn generate(db: &DbConn, tenant_id: &str) -> Result { // Create Transaction let tsn = example_tenant(tenant_id); @@ -56,8 +54,11 @@ impl Tenant { pub async fn insert( tnt: Tenant, db: &DbConn, - ) -> Result, DbErr> { - Tenants::insert(tnt.into()).exec(db).await + ) -> Result, Error> { + Tenants::insert(tnt.into()) + .exec(db) + .await + .map_err(|e| e.into()) } } diff --git a/src/methods/transaction/handlers.rs b/src/methods/transaction/handlers.rs index ef8707a..e260552 100644 --- a/src/methods/transaction/handlers.rs +++ b/src/methods/transaction/handlers.rs @@ -1,20 +1,19 @@ +use super::{Transaction, TransactionInit, TransactionInput}; use crate::catchers::Validated; +use crate::guards::Convert; +use crate::methods::employee::Action; +use crate::methods::{Error, ErrorResponse, QuantityAlterationIntent}; +use crate::{ + apply_discount, check_permissions, Order, OrderStatus, ProductStatusUpdate, TransactionType, +}; use okapi::openapi3::OpenApi; +use open_stock::{InternalDb, Session}; use rocket::get; -use rocket::http::CookieJar; use rocket::post; use rocket::serde::json::Json; -use rocket_db_pools::Connection; use rocket_okapi::settings::OpenApiSettings; use rocket_okapi::{openapi, openapi_get_routes_spec}; - -use super::{Transaction, TransactionInit, TransactionInput}; -use crate::methods::employee::Action; -use crate::methods::{cookie_status_wrapper, Error, ErrorResponse, QuantityAlterationIntent}; -use crate::pool::Db; -use crate::{ - apply_discount, check_permissions, Order, OrderStatus, ProductStatusUpdate, TransactionType, -}; +use sea_orm::DbErr; pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, OpenApi) { openapi_get_routes_spec![ @@ -35,211 +34,149 @@ pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, Ope #[openapi(tag = "Transaction")] #[get("/")] -pub async fn get( - conn: Connection, - id: String, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +pub async fn get(db: InternalDb, session: Session, id: &str) -> Convert { check_permissions!(session.clone(), Action::FetchTransaction); - - match Transaction::fetch_by_id(&id, session, &db).await { - Ok(transaction) => Ok(Json(transaction)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Transaction::fetch_by_id(id, session, &db.0).await.into() } #[openapi(tag = "Transaction")] #[get("/saved")] -pub async fn get_all_saved( - conn: Connection, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +pub async fn get_all_saved(db: InternalDb, session: Session) -> Convert> { check_permissions!(session.clone(), Action::FetchTransaction); - - match Transaction::fetch_all_saved(session, &db).await { - Ok(transaction) => Ok(Json(transaction)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Transaction::fetch_all_saved(session, &db.0).await.into() } #[openapi(tag = "Transaction")] #[get("/ref/")] pub async fn get_by_name( - conn: Connection, + db: InternalDb, + session: Session, name: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchTransaction); - - match Transaction::fetch_by_ref(name, session, &db).await { - Ok(transaction) => Ok(Json(transaction)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Transaction::fetch_by_ref(name, session, &db.0).await.into() } #[openapi(tag = "Transaction")] #[get("/product/")] pub async fn get_by_product_sku( - conn: Connection, + db: InternalDb, + session: Session, sku: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchTransaction); - - match Transaction::fetch_by_ref(sku, session, &db).await { - Ok(transaction) => Ok(Json(transaction)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Transaction::fetch_by_ref(sku, session, &db.0).await.into() } #[openapi(tag = "Transaction")] #[get("/deliverables/")] pub async fn deliverables_search( - conn: Connection, + session: Session, + db: InternalDb, store_id: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchTransaction); - - match Transaction::fetch_deliverable_jobs(store_id, session, &db).await { - Ok(transaction) => Ok(Json(transaction)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Transaction::fetch_deliverable_jobs(store_id, session, &db.0) + .await + .into() } #[openapi(tag = "Transaction")] #[get("/receivables/")] pub async fn receivables_search( - conn: Connection, + db: InternalDb, + session: Session, store_id: &str, - cookies: &CookieJar<'_>, -) -> Result>, Error> { - let db = conn.into_inner(); - let session = cookie_status_wrapper(&db, cookies).await?; +) -> Convert> { check_permissions!(session.clone(), Action::FetchTransaction); - - match Transaction::fetch_receivable_jobs(store_id, session, &db).await { - Ok(transaction) => Ok(Json(transaction)), - Err(reason) => Err(ErrorResponse::db_err(reason)), - } + Transaction::fetch_receivable_jobs(store_id, session, &db.0) + .await + .into() } #[openapi(tag = "Transaction")] #[post("/", data = "")] async fn update( - conn: Connection, - id: &str, + db: InternalDb, + session: Session, input_data: Validated>, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let input_data = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; + id: &str, +) -> Convert { check_permissions!(session.clone(), Action::ModifyTransaction); - - match Transaction::update(input_data, session, id, &db).await { - Ok(res) => Ok(Json(res)), - Err(_) => Err(ErrorResponse::input_error()), - } + Transaction::update(input_data.data(), session, id, &db.0) + .await + .into() } #[openapi(tag = "Transaction")] #[post("/status/order/", data = "")] async fn update_order_status( - conn: Connection, + db: InternalDb, + session: Session, refer: &str, - status: Json, - cookies: &CookieJar<'_>, + status: Validated>, ) -> Result, Error> { - let status = status.clone().into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::ModifyTransaction); - let tsn = Transaction::fetch_by_ref(refer, session.clone(), &db) - .await - .unwrap(); - let id = tsn.get(0).unwrap().id.as_str(); + let fetched_transaction = Transaction::fetch_by_ref(refer, session.clone(), &db.0).await?; - match Transaction::update_order_status(id, refer, status, session, &db).await { - Ok(res) => Ok(Json(res)), - Err(_) => Err(ErrorResponse::input_error()), + match fetched_transaction.get(0) { + Some(transaction) => Transaction::update_order_status( + transaction.id.as_str(), + refer, + status.data(), + session, + &db.0, + ) + .await + .into(), + None => Err(DbErr::RecordNotFound("Could not retrieve transaction".to_string()).into()), } } #[openapi(tag = "Transaction")] #[post("/status/product", data = "")] async fn update_product_status( - conn: Connection, + db: InternalDb, + session: Session, data: Validated>, - cookies: &CookieJar<'_>, ) -> Result, Error> { - let db = conn.into_inner(); - let data = data.clone().0.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::ModifyTransaction); - let tsn = Transaction::fetch_by_ref(&data.transaction_id.clone(), session.clone(), &db) - .await - .unwrap(); - let id = tsn.get(0).unwrap().id.as_str(); + let data = data.data(); + let fetched_transaction = + Transaction::fetch_by_ref(&data.transaction_id, session.clone(), &db.0).await?; - match Transaction::update_product_status(id, data, session, &db).await { - Ok(res) => Ok(Json(res)), - Err(_) => Err(ErrorResponse::input_error()), + match fetched_transaction.get(0) { + Some(transaction) => { + Transaction::update_product_status(transaction.id.as_str(), data, session, &db.0) + .await + .into() + } + None => Err(DbErr::RecordNotFound("Could not retrieve transaction".to_string()).into()), } } #[openapi(tag = "Transaction")] #[post("/generate/")] -async fn generate( - conn: Connection, - customer_id: &str, - cookies: &CookieJar<'_>, -) -> Result, Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +async fn generate(db: InternalDb, session: Session, customer_id: &str) -> Convert { check_permissions!(session.clone(), Action::GenerateTemplateContent); - - match Transaction::generate(&db, customer_id, session).await { - Ok(res) => Ok(Json(res)), - Err(_) => Err(ErrorResponse::input_error()), - } + Transaction::generate(&db.0, customer_id, session) + .await + .into() } #[openapi(tag = "Transaction")] #[post("/", data = "")] pub async fn create( - conn: Connection, + db: InternalDb, + session: Session, input_data: Validated>, - cookies: &CookieJar<'_>, ) -> Result, Error> { - let new_transaction = input_data.clone().0.into_inner(); - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::CreateTransaction); let mut quantity_alteration_intents: Vec = vec![]; + let new_transaction = input_data.data(); // Make and modify the required changes to stock levels new_transaction.products.iter().for_each(|order| { @@ -286,7 +223,7 @@ pub async fn create( let insertion = match new_transaction.transaction_type { TransactionType::Saved => { // We do not need to process intents. Simply save. - Transaction::insert(new_transaction, session.clone(), &db).await? + Transaction::insert(new_transaction, session.clone(), &db.0).await? } _ => { // As we are removing inventory via a purchase, @@ -298,28 +235,21 @@ pub async fn create( )); } - let data = Transaction::insert(new_transaction, session.clone(), &db).await?; - Transaction::process_intents(session.clone(), &db, quantity_alteration_intents).await; + let data = Transaction::insert(new_transaction, session.clone(), &db.0).await?; + Transaction::process_intents(session.clone(), &db.0, quantity_alteration_intents).await; data } }; - Ok(Json( - Transaction::fetch_by_id(&insertion.last_insert_id, session, &db).await?, - )) + Transaction::fetch_by_id(&insertion.last_insert_id, session, &db.0) + .await + .into() } #[openapi(tag = "Transaction")] #[post("/delete/")] -async fn delete(conn: Connection, id: &str, cookies: &CookieJar<'_>) -> Result<(), Error> { - let db = conn.into_inner(); - - let session = cookie_status_wrapper(&db, cookies).await?; +async fn delete(db: InternalDb, session: Session, id: &str) -> Convert<()> { check_permissions!(session.clone(), Action::DeleteTransaction); - - match Transaction::delete(id, session, &db).await { - Ok(_res) => Ok(()), - Err(_) => Err(ErrorResponse::input_error()), - } + Transaction::delete(id, session, &db.0).await.into() } diff --git a/tests/client_test.rs b/tests/client_test.rs index bd2091b..67bfb4b 100644 --- a/tests/client_test.rs +++ b/tests/client_test.rs @@ -28,7 +28,6 @@ async fn main() { durations.push(duration.as_millis()); } } - }).await { Ok(_) => {}, Err(_) => panic!("Panic"), From c9b4652688b0ca714372bb915263f8279ccb7187 Mon Sep 17 00:00:00 2001 From: Ben White Date: Sat, 10 Feb 2024 19:29:03 +1100 Subject: [PATCH 8/8] mod: cranky and ready --- src/methods/common.rs | 2 +- src/methods/helpers/handlers.rs | 26 ++++------------- src/methods/store/handlers.rs | 5 ++-- src/methods/store/structs.rs | 43 ++++++++++++++------------- src/methods/supplier/handlers.rs | 17 ++++------- src/methods/tenant/handlers.rs | 2 +- src/methods/transaction/handlers.rs | 45 +++++++++++++++++------------ src/methods/transaction/structs.rs | 35 +++++++++++----------- 8 files changed, 80 insertions(+), 95 deletions(-) diff --git a/src/methods/common.rs b/src/methods/common.rs index 6c57993..c4b4296 100644 --- a/src/methods/common.rs +++ b/src/methods/common.rs @@ -508,7 +508,7 @@ impl OpenApiResponderInner for Error { pub struct VoidableResult(pub Result); impl VoidableResult { - fn void(self) -> Result<(), Error> { + pub fn void(self) -> Result<(), Error> { self.into() } } diff --git a/src/methods/helpers/handlers.rs b/src/methods/helpers/handlers.rs index 4312a6c..1bfdce3 100644 --- a/src/methods/helpers/handlers.rs +++ b/src/methods/helpers/handlers.rs @@ -77,12 +77,8 @@ pub async fn generate_template(db: InternalDb) -> Result, Error> { }; // Add Tenants - let tenant = Tenant::generate(&db.0, tenant_id) - .await - .map_err(ErrorResponse::db_err)?; - let tenant2 = Tenant::generate(&db.0, tenant_id2) - .await - .map_err(ErrorResponse::db_err)?; + let tenant = Tenant::generate(&db.0, tenant_id).await?; + let tenant2 = Tenant::generate(&db.0, tenant_id2).await?; // Add Employees let employee = Employee::generate(&db.0, session.clone()).await?; @@ -120,8 +116,7 @@ pub async fn generate_template(db: InternalDb) -> Result, Error> { variant: SessionVariant::AccessToken, }, ) - .await - .map_err(ErrorResponse::db_err)?; + .await?; let promotions = Promotion::generate(session, &db.0).await?; @@ -156,9 +151,7 @@ pub async fn new_tenant( updated_at: Utc::now(), }; - Tenant::insert(tenant, &db.0) - .await - .map_err(ErrorResponse::db_err)?; + Tenant::insert(tenant, &db.0).await?; // Create Primary Employee let employee = EmployeeInput { @@ -332,15 +325,8 @@ pub async fn distance_to_stores_from_store( let session = cookie_status_wrapper(&db, cookies).await?; check_permissions!(session.clone(), Action::FetchGeoLocation); - let store_ = match Store::fetch_by_id(store_id, session.clone(), &db).await { - Ok(c) => c, - Err(reason) => return Err(ErrorResponse::db_err(reason)), - }; - - let stores = match Store::fetch_all(session, &db).await { - Ok(s) => s, - Err(reason) => return Err(ErrorResponse::db_err(reason)), - }; + let store_ = Store::fetch_by_id(store_id, session.clone(), &db).await?; + let stores = Store::fetch_all(session, &db).await?; let cust = point!(x: store_.contact.address.lat, y: store_.contact.address.lon); diff --git a/src/methods/store/handlers.rs b/src/methods/store/handlers.rs index 44c0fb4..68f8493 100644 --- a/src/methods/store/handlers.rs +++ b/src/methods/store/handlers.rs @@ -1,12 +1,13 @@ use crate::catchers::Validated; +use crate::Session; use okapi::openapi3::OpenApi; -use open_stock::{InternalDb, Session}; use rocket::{get, http::CookieJar, post, serde::json::Json}; use rocket_db_pools::Connection; use rocket_okapi::settings::OpenApiSettings; use rocket_okapi::{openapi, openapi_get_routes_spec}; use crate::guards::Convert; +use crate::pool::InternalDb; use crate::{ check_permissions, methods::{cookie_status_wrapper, Action, Error, ErrorResponse}, @@ -56,7 +57,7 @@ async fn update( session: Session, input_data: Validated>, id: &str, -) -> Result, Error> { +) -> Convert { check_permissions!(session.clone(), Action::ModifyStore); Store::update(input_data.data(), session, id, &db.0) .await diff --git a/src/methods/store/structs.rs b/src/methods/store/structs.rs index 4036dad..43414b7 100644 --- a/src/methods/store/structs.rs +++ b/src/methods/store/structs.rs @@ -18,7 +18,7 @@ use crate::methods::convert_addr_to_geo; use crate::methods::store::example::example_stores; use crate::methods::{ContactInformation, Id}; -use crate::Session; +use crate::{methods::Error, Session}; use serde_json::json; use validator::Validate; @@ -41,29 +41,28 @@ impl Store { store: Store, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let insert_crud = store.into_active(session); - - match StoreEntity::insert(insert_crud).exec(db).await { - Ok(res) => Ok(res), - Err(err) => Err(err), - } + StoreEntity::insert(insert_crud) + .exec(db) + .await + .map_err(|e| e.into()) } pub async fn insert_many( stores: Vec, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let entities = stores.into_iter().map(|s| s.into_active(session.clone())); - match StoreEntity::insert_many(entities).exec(db).await { - Ok(res) => Ok(res), - Err(err) => Err(err), - } + StoreEntity::insert_many(entities) + .exec(db) + .await + .map_err(|e| e.into()) } - pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { + pub async fn fetch_by_id(id: &str, session: Session, db: &DbConn) -> Result { let store = StoreEntity::find_by_id(id.to_string()) .filter(store::Column::TenantId.eq(session.tenant_id)) .one(db) @@ -71,11 +70,11 @@ impl Store { match store { Some(e) => Ok(e.into()), - None => Err(DbErr::RecordNotFound(id.to_string())), + None => Err(DbErr::RecordNotFound(id.to_string()).into()), } } - pub async fn fetch_by_code(code: &str, session: Session, db: &DbConn) -> Result { + pub async fn fetch_by_code(code: &str, session: Session, db: &DbConn) -> Result { let store = StoreEntity::find() .filter(store::Column::TenantId.eq(session.tenant_id)) .having(store::Column::Code.eq(code)) @@ -84,11 +83,11 @@ impl Store { match store { Some(e) => Ok(e.into()), - None => Err(DbErr::RecordNotFound(code.to_string())), + None => Err(DbErr::RecordNotFound(code.to_string()).into()), } } - pub async fn fetch_all(session: Session, db: &DbConn) -> Result, DbErr> { + pub async fn fetch_all(session: Session, db: &DbConn) -> Result, Error> { let stores = StoreEntity::find() .filter(store::Column::TenantId.eq(session.tenant_id)) .all(db) @@ -104,7 +103,7 @@ impl Store { session: Session, id: &str, db: &DbConn, - ) -> Result { + ) -> Result { let addr = convert_addr_to_geo(&format!( "{} {} {} {}", store.contact.address.street, @@ -126,13 +125,13 @@ impl Store { Self::fetch_by_id(id, session, db).await } - Err(_) => Err(DbErr::Query(RuntimeErr::Internal( - "Invalid address format".to_string(), - ))), + Err(_) => { + Err(DbErr::Query(RuntimeErr::Internal("Invalid address format".to_string())).into()) + } } } - pub async fn generate(session: Session, db: &DbConn) -> Result, DbErr> { + pub async fn generate(session: Session, db: &DbConn) -> Result, Error> { let stores = example_stores(); match Store::insert_many(stores, session.clone(), db).await { diff --git a/src/methods/supplier/handlers.rs b/src/methods/supplier/handlers.rs index 90743a6..d202e3a 100644 --- a/src/methods/supplier/handlers.rs +++ b/src/methods/supplier/handlers.rs @@ -1,20 +1,17 @@ +use super::{Supplier, SupplierInput}; use crate::catchers::Validated; use crate::guards::Convert; use crate::methods::employee::Action; -use crate::methods::{cookie_status_wrapper, Error, ErrorResponse}; -use crate::pool::{Db, InternalDb}; +use crate::methods::Error; +use crate::pool::InternalDb; use crate::{check_permissions, Session}; use okapi::openapi3::OpenApi; use rocket::get; -use rocket::http::CookieJar; use rocket::post; use rocket::serde::json::Json; -use rocket_db_pools::Connection; use rocket_okapi::settings::OpenApiSettings; use rocket_okapi::{openapi, openapi_get_routes_spec}; -use super::{Supplier, SupplierInput}; - pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, OpenApi) { openapi_get_routes_spec![ settings: @@ -37,11 +34,7 @@ pub async fn get(db: InternalDb, session: Session, id: &str) -> Convert")] -pub async fn get_by_name( - db: InternalDb, - session: Session, - name: &str, -) -> Result>, Error> { +pub async fn get_by_name(db: InternalDb, session: Session, name: &str) -> Convert> { check_permissions!(session.clone(), Action::FetchSupplier); Supplier::fetch_by_name(name, session, &db.0).await.into() } @@ -86,7 +79,7 @@ async fn update( pub async fn create( session: Session, db: InternalDb, - input_data: Json, + input_data: Validated>, ) -> Result, Error> { check_permissions!(session.clone(), Action::ModifySupplier); diff --git a/src/methods/tenant/handlers.rs b/src/methods/tenant/handlers.rs index 7f9eb52..9f827d8 100644 --- a/src/methods/tenant/handlers.rs +++ b/src/methods/tenant/handlers.rs @@ -1,8 +1,8 @@ -use open_stock::InternalDb; use rocket::get; use rocket::routes; use crate::guards::Convert; +use crate::pool::InternalDb; use crate::Tenant; pub fn routes() -> Vec { diff --git a/src/methods/transaction/handlers.rs b/src/methods/transaction/handlers.rs index e260552..fcede62 100644 --- a/src/methods/transaction/handlers.rs +++ b/src/methods/transaction/handlers.rs @@ -3,17 +3,19 @@ use crate::catchers::Validated; use crate::guards::Convert; use crate::methods::employee::Action; use crate::methods::{Error, ErrorResponse, QuantityAlterationIntent}; +use crate::pool::InternalDb; +use crate::Session; use crate::{ apply_discount, check_permissions, Order, OrderStatus, ProductStatusUpdate, TransactionType, + VoidableResult, }; use okapi::openapi3::OpenApi; -use open_stock::{InternalDb, Session}; use rocket::get; use rocket::post; use rocket::serde::json::Json; use rocket_okapi::settings::OpenApiSettings; use rocket_okapi::{openapi, openapi_get_routes_spec}; -use sea_orm::DbErr; +use sea_orm::{DbErr, DeleteResult}; pub fn documented_routes(settings: &OpenApiSettings) -> (Vec, OpenApi) { openapi_get_routes_spec![ @@ -114,22 +116,19 @@ async fn update_order_status( db: InternalDb, session: Session, refer: &str, - status: Validated>, + status: Json, ) -> Result, Error> { check_permissions!(session.clone(), Action::ModifyTransaction); let fetched_transaction = Transaction::fetch_by_ref(refer, session.clone(), &db.0).await?; match fetched_transaction.get(0) { - Some(transaction) => Transaction::update_order_status( - transaction.id.as_str(), - refer, - status.data(), - session, - &db.0, - ) - .await - .into(), + Some(transaction) => { + let data = status.0; + Transaction::update_order_status(transaction.id.as_str(), refer, data, session, &db.0) + .await + .map(|v| Json(v)) + } None => Err(DbErr::RecordNotFound("Could not retrieve transaction".to_string()).into()), } } @@ -149,9 +148,11 @@ async fn update_product_status( match fetched_transaction.get(0) { Some(transaction) => { - Transaction::update_product_status(transaction.id.as_str(), data, session, &db.0) - .await - .into() + let converted: Convert = + Transaction::update_product_status(transaction.id.as_str(), data, session, &db.0) + .await + .into(); + converted.0 } None => Err(DbErr::RecordNotFound("Could not retrieve transaction".to_string()).into()), } @@ -242,14 +243,20 @@ pub async fn create( } }; - Transaction::fetch_by_id(&insertion.last_insert_id, session, &db.0) - .await - .into() + let converted: Convert = + Transaction::fetch_by_id(&insertion.last_insert_id, session, &db.0) + .await + .into(); + + converted.0 } #[openapi(tag = "Transaction")] #[post("/delete/")] +// #[guard(Action::DeleteTransaction)] async fn delete(db: InternalDb, session: Session, id: &str) -> Convert<()> { check_permissions!(session.clone(), Action::DeleteTransaction); - Transaction::delete(id, session, &db.0).await.into() + + let voided: VoidableResult = Transaction::delete(id, session, &db.0).await.into(); + voided.void().into() } diff --git a/src/methods/transaction/structs.rs b/src/methods/transaction/structs.rs index 29048d1..8b76616 100644 --- a/src/methods/transaction/structs.rs +++ b/src/methods/transaction/structs.rs @@ -174,7 +174,7 @@ impl Transaction { tsn: TransactionInit, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let id = Uuid::new_v4().to_string(); match Transactions::insert(tsn.into_active(id, session)) @@ -182,7 +182,7 @@ impl Transaction { .await { Ok(res) => Ok(res), - Err(err) => Err(err), + Err(err) => Err(err.into()), } } @@ -190,13 +190,13 @@ impl Transaction { tsn: Transaction, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { match Transactions::insert(tsn.into_active(session.tenant_id)) .exec(db) .await { Ok(res) => Ok(res), - Err(err) => Err(err), + Err(err) => Err(err.into()), } } @@ -204,7 +204,7 @@ impl Transaction { query: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let as_str: Vec = DerivableTransaction::find_by_statement(Statement::from_sql_and_values( DbBackend::MySql, @@ -239,7 +239,7 @@ impl Transaction { query: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let as_str: Vec = DerivableTransaction::find_by_statement(Statement::from_sql_and_values( DbBackend::MySql, @@ -274,22 +274,20 @@ impl Transaction { id: &str, session: Session, db: &DbConn, - ) -> Result { + ) -> Result { let tsn = Transactions::find_by_id(id.to_string()) .filter(transactions::Column::TenantId.eq(session.tenant_id)) .one(db) .await?; if tsn.is_none() { - return Err(DbErr::Custom( - "Unable to query value, returns none".to_string(), - )); + return Err(DbErr::Custom("Unable to query value, returns none".to_string()).into()); } Ok(tsn.unwrap().into()) } - pub async fn fetch_all_saved(session: Session, db: &DbConn) -> Result, DbErr> { + pub async fn fetch_all_saved(session: Session, db: &DbConn) -> Result, Error> { let res = Transactions::find() .filter(transactions::Column::TenantId.eq(session.tenant_id)) .having( @@ -311,7 +309,7 @@ impl Transaction { reference: &str, session: Session, db: &DbConn, - ) -> Result, DbErr> { + ) -> Result, Error> { let res = Transactions::find() .filter(transactions::Column::TenantId.eq(session.tenant_id)) .having( @@ -349,7 +347,7 @@ impl Transaction { session: Session, id: &str, db: &DbConn, - ) -> Result { + ) -> Result { tsn.into_active(id.to_string(), session.clone()) .update(db) .await?; @@ -362,7 +360,7 @@ impl Transaction { session: Session, id: &str, db: &DbConn, - ) -> Result { + ) -> Result { tsn.into_active(session.tenant_id.clone()) .update(db) .await?; @@ -376,7 +374,7 @@ impl Transaction { status: OrderStatus, session: Session, db: &DbConn, - ) -> Result { + ) -> Result { let mut transaction = Transaction::fetch_by_id(id, session.clone(), db).await?; let new_orders = transaction @@ -414,7 +412,7 @@ impl Transaction { update: ProductStatusUpdate, session: Session, db: &DbConn, - ) -> Result { + ) -> Result { let mut transaction = Transaction::fetch_by_id(id, session.clone(), db).await?; let new_orders = transaction @@ -468,7 +466,7 @@ impl Transaction { db: &DbConn, customer_id: &str, session: Session, - ) -> Result { + ) -> Result { // Create Transaction let tsn = example_transaction(customer_id); @@ -578,7 +576,7 @@ impl Transaction { futures::future::join_all(intent_processor).await } - pub async fn delete(id: &str, session: Session, db: &DbConn) -> Result { + pub async fn delete(id: &str, session: Session, db: &DbConn) -> Result { Transactions::delete(transactions::ActiveModel { id: Set(id.to_string()), tenant_id: Set(session.tenant_id), @@ -586,6 +584,7 @@ impl Transaction { }) .exec(db) .await + .map_err(|e| e.into()) } }