diff --git a/Cargo.lock b/Cargo.lock index e38fe02..60fb911 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,14 +9,13 @@ dependencies = [ "actix 0.13.0", "actix-rt", "bus", - "chrono", "config", "database_manager", "log", "model", "pretty_env_logger", + "serde", "thiserror", - "uuid 0.8.2", ] [[package]] @@ -840,6 +839,7 @@ dependencies = [ "log", "model", "pretty_env_logger", + "serde", "thiserror", "uuid 0.8.2", ] @@ -1159,6 +1159,7 @@ dependencies = [ "model", "pretty_env_logger", "rand", + "serde", "sqlx", "sqlx-core", "thiserror", @@ -1393,6 +1394,50 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fluent" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f69378194459db76abd2ce3952b790db103ceb003008d3d50d97c41ff847a7" +dependencies = [ + "fluent-bundle", + "unic-langid", +] + +[[package]] +name = "fluent-bundle" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e242c601dec9711505f6d5bbff5bedd4b61b2469f2e8bb8e57ee7c9747a87ffd" +dependencies = [ + "fluent-langneg", + "fluent-syntax", + "intl-memoizer", + "intl_pluralrules", + "rustc-hash", + "self_cell", + "smallvec", + "unic-langid", +] + +[[package]] +name = "fluent-langneg" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "fluent-syntax" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0abed97648395c902868fee9026de96483933faa54ea3b40d652f7dfe61ca78" +dependencies = [ + "thiserror", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1443,6 +1488,7 @@ dependencies = [ "log", "model", "pretty_env_logger", + "serde", "thiserror", "tokio", "uuid 0.8.2", @@ -1982,6 +2028,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "intl-memoizer" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c310433e4a310918d6ed9243542a6b83ec1183df95dff8f23f87bb88a264a66f" +dependencies = [ + "type-map", + "unic-langid", +] + +[[package]] +name = "intl_pluralrules" +version = "7.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b18f988384267d7066cc2be425e6faf352900652c046b6971d2e228d3b1c5ecf" +dependencies = [ + "tinystr", + "unic-langid", +] + [[package]] name = "ipnet" version = "2.5.0" @@ -2063,6 +2129,21 @@ dependencies = [ "sha2", ] +[[package]] +name = "lang_provider" +version = "0.1.0" +dependencies = [ + "actix 0.13.0", + "actix-rt", + "config", + "fluent", + "log", + "model", + "pretty_env_logger", + "thiserror", + "unic-langid", +] + [[package]] name = "language-tags" version = "0.3.2" @@ -2531,6 +2612,7 @@ dependencies = [ "log", "model", "pretty_env_logger", + "serde", "thiserror", "uuid 0.8.2", ] @@ -3076,6 +3158,12 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.2.3" @@ -3258,6 +3346,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "self_cell" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af" + [[package]] name = "semver" version = "0.9.0" @@ -3831,6 +3925,12 @@ dependencies = [ "syn", ] +[[package]] +name = "tinystr" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29738eedb4388d9ea620eeab9384884fc3f06f586a2eddb56bedc5885126c7c1" + [[package]] name = "tinytemplate" version = "1.2.1" @@ -3867,6 +3967,8 @@ dependencies = [ "config", "database_manager", "derive_more", + "futures", + "futures-util", "hmac", "jwt", "log", @@ -3878,6 +3980,7 @@ dependencies = [ "serde", "sha2", "thiserror", + "tokio", "uuid 0.8.2", ] @@ -4047,6 +4150,15 @@ dependencies = [ "unchecked-index", ] +[[package]] +name = "type-map" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d3364c5e96cb2ad1603037ab253ddd34d7fb72a58bdddf4b7350760fc69a46" +dependencies = [ + "rustc-hash", +] + [[package]] name = "typenum" version = "1.15.0" @@ -4095,6 +4207,24 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" +[[package]] +name = "unic-langid" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73328fcd730a030bdb19ddf23e192187a6b01cd98be6d3140622a89129459ce5" +dependencies = [ + "unic-langid-impl", +] + +[[package]] +name = "unic-langid-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a4a8eeaf0494862c1404c95ec2f4c33a2acff5076f64314b465e3ddae1b934d" +dependencies = [ + "tinystr", +] + [[package]] name = "unic-segment" version = "0.9.0" diff --git a/actors/account_manager/Cargo.toml b/actors/account_manager/Cargo.toml index 1e6e2b3..3e13e33 100644 --- a/actors/account_manager/Cargo.toml +++ b/actors/account_manager/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" model = { path = "../../shared/model" } config = { path = "../../shared/config" } database_manager = { path = "../database_manager" } +#token_manager = { path = "../token_manager" } bus = { path = "../../shared/bus" } actix = { version = "0.13", features = [] } @@ -14,5 +15,7 @@ actix-rt = { version = "2.7", features = [] } thiserror = { version = "1.0.31" } +serde = { version = "1.0.137", features = ["derive"] } + log = { version = "0.4", features = [] } pretty_env_logger = { version = "0.4", features = [] } diff --git a/actors/account_manager/src/lib.rs b/actors/account_manager/src/lib.rs index 3db2788..e1611ae 100644 --- a/actors/account_manager/src/lib.rs +++ b/actors/account_manager/src/lib.rs @@ -1,11 +1,23 @@ +use actix::Addr; +use config::SharedAppConfig; use database_manager::query_db; +use model::{Email, Encrypt, FullAccount, Login, Password, Role}; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] +#[serde(rename_all = "kebab-case", tag = "account")] pub enum Error { + #[error("Unable to send or receive msg from database")] + DbCritical, #[error("Failed to load account data")] Account, #[error("Failed to load account addresses")] Addresses, + #[error("Unable to save record")] + Saving, + #[error("Unable to hash password")] + Hashing, + #[error("{0}")] + Db(#[from] database_manager::Error), } pub type Result = std::result::Result; @@ -19,7 +31,8 @@ macro_rules! account_async_handler { fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result { use actix::WrapFuture; let db = self.db.clone(); - Box::pin(async { $async(msg, db).await }.into_actor(self)) + let config = self.config.clone(); + Box::pin(async { $async(msg, db, config).await }.into_actor(self)) } } }; @@ -60,14 +73,14 @@ macro_rules! query_account { }; } -#[derive(Debug)] pub struct AccountManager { - db: actix::Addr, + db: Addr, + config: SharedAppConfig, } impl AccountManager { - pub fn new(db: actix::Addr) -> Self { - Self { db } + pub fn new(config: SharedAppConfig, db: Addr) -> Self { + Self { config, db } } } @@ -76,7 +89,7 @@ impl actix::Actor for AccountManager { } pub struct MeResult { - pub account: model::FullAccount, + pub account: FullAccount, pub addresses: Vec, } @@ -88,8 +101,12 @@ pub struct Me { account_async_handler!(Me, me, MeResult); -pub(crate) async fn me(msg: Me, db: actix::Addr) -> Result { - let account: model::FullAccount = query_db!( +pub(crate) async fn me( + msg: Me, + db: Addr, + _config: SharedAppConfig, +) -> Result { + let account: FullAccount = query_db!( db, database_manager::FindAccount { account_id: msg.account_id @@ -105,3 +122,43 @@ pub(crate) async fn me(msg: Me, db: actix::Addr) -> ); Ok(MeResult { account, addresses }) } + +#[derive(actix::Message)] +#[rtype(result = "Result")] +pub struct CreateAccount { + pub email: Email, + pub login: Login, + pub password: Password, + pub role: Role, +} + +account_async_handler!(CreateAccount, create_account, FullAccount); + +pub(crate) async fn create_account( + msg: CreateAccount, + db: Addr, + config: SharedAppConfig, +) -> Result { + let hash = { + match msg.password.encrypt(&config.lock().web().pass_salt()) { + Ok(hash) => hash, + Err(e) => { + log::error!("{e:?}"); + return Err(Error::Hashing); + } + } + }; + + let account: FullAccount = query_db!( + db, + database_manager::CreateAccount { + email: msg.email, + login: msg.login, + pass_hash: model::PassHash::new(hash), + role: msg.role, + }, + Error::DbCritical, + Error::Saving + ); + Ok(account) +} diff --git a/actors/cart_manager/src/lib.rs b/actors/cart_manager/src/lib.rs index 7946b7d..dc12a67 100644 --- a/actors/cart_manager/src/lib.rs +++ b/actors/cart_manager/src/lib.rs @@ -4,7 +4,6 @@ use std::collections::HashSet; use database_manager::{query_db, Database}; use model::{PaymentMethod, ShoppingCartId}; -use serde::Serialize; #[macro_export] macro_rules! cart_async_handler { @@ -56,8 +55,8 @@ macro_rules! query_cart { }; } -#[derive(Debug, thiserror::Error, Serialize)] -#[serde(rename_all = "kebab-case")] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] +#[serde(rename_all = "kebab-case", tag = "cart")] pub enum Error { #[error("System can't ensure shopping cart existence")] ShoppingCartFailed, diff --git a/actors/database_manager/Cargo.toml b/actors/database_manager/Cargo.toml index 2b86f6b..75fcef3 100644 --- a/actors/database_manager/Cargo.toml +++ b/actors/database_manager/Cargo.toml @@ -28,3 +28,5 @@ fake = { version = "2.4.3", features = ["derive", "chrono", "http", "uuid"], opt rand = { version = "0.8.5", optional = true } itertools = { version = "0.10.3" } + +serde = { version = "1.0", features = ["derive"] } diff --git a/actors/database_manager/src/account_orders.rs b/actors/database_manager/src/account_orders.rs index ad99b41..080d635 100644 --- a/actors/database_manager/src/account_orders.rs +++ b/actors/database_manager/src/account_orders.rs @@ -7,7 +7,8 @@ use crate::{ ShoppingCartSetState, }; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] +#[serde(rename_all = "kebab-case", tag = "account-order")] pub enum Error { #[error("Can't create account order")] CantCreate, diff --git a/actors/database_manager/src/accounts.rs b/actors/database_manager/src/accounts.rs index df4ef64..b4c0e60 100644 --- a/actors/database_manager/src/accounts.rs +++ b/actors/database_manager/src/accounts.rs @@ -5,7 +5,8 @@ use sqlx::PgPool; use crate::{db_async_handler, Result}; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] +#[serde(rename_all = "kebab-case")] pub enum Error { #[error("Can't create account")] CantCreate, diff --git a/actors/database_manager/src/addresses.rs b/actors/database_manager/src/addresses.rs index db8c077..928a1e9 100644 --- a/actors/database_manager/src/addresses.rs +++ b/actors/database_manager/src/addresses.rs @@ -1,6 +1,6 @@ use crate::{db_async_handler, Result}; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] pub enum Error { #[error("Can't load account addresses")] AccountAddresses, diff --git a/actors/database_manager/src/lib.rs b/actors/database_manager/src/lib.rs index b3d3a1a..ae6221d 100644 --- a/actors/database_manager/src/lib.rs +++ b/actors/database_manager/src/lib.rs @@ -42,10 +42,16 @@ macro_rules! db_async_handler { }; ($msg: ty, $async: ident, $res: ty, $inner_async: ident) => { async fn $inner_async(msg: $msg, pool: sqlx::PgPool) -> Result<$res> { - let mut t = pool.begin().await?; + let mut t = pool.begin().await.map_err(|e| { + log::error!("{:?}", e); + $crate::Error::TransactionFailed + })?; match $async(msg, &mut t).await { Ok(res) => { - t.commit().await?; + t.commit().await.map_err(|e| { + log::error!("{:?}", e); + $crate::Error::TransactionFailed + })?; Ok(res) } Err(e) => { @@ -116,10 +122,9 @@ macro_rules! query_db { }; } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] +#[serde(rename_all = "kebab-case")] pub enum Error { - #[error("Failed to connect to database. {0:?}")] - Connect(#[from] sqlx::Error), #[error("{0}")] Account(#[from] accounts::Error), #[error("{0}")] @@ -142,6 +147,8 @@ pub enum Error { ProductPhoto(#[from] product_photos::Error), #[error("{0}")] AccountAddress(#[from] addresses::Error), + #[error("Failed to start or finish transaction")] + TransactionFailed, } pub type Result = std::result::Result; @@ -161,10 +168,13 @@ impl Clone for Database { } impl Database { - pub async fn build(config: SharedAppConfig) -> Result { + pub async fn build(config: SharedAppConfig) -> Self { let url = config.lock().database().url(); - let pool = sqlx::PgPool::connect(&url).await.map_err(Error::Connect)?; - Ok(Database { pool }) + let pool = PgPool::connect(&url).await.unwrap_or_else(|e| { + log::error!("Failed to connect to database. {e:?}"); + std::process::exit(1); + }); + Database { pool } } pub fn pool(&self) -> &PgPool { diff --git a/actors/database_manager/src/order_items.rs b/actors/database_manager/src/order_items.rs index 7ae285a..5ebfda6 100644 --- a/actors/database_manager/src/order_items.rs +++ b/actors/database_manager/src/order_items.rs @@ -6,7 +6,7 @@ use sqlx::PgPool; use super::Result; use crate::db_async_handler; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] pub enum Error { #[error("Can't create order item")] CantCreate, diff --git a/actors/database_manager/src/photos.rs b/actors/database_manager/src/photos.rs index 95103ed..8cf9f1a 100644 --- a/actors/database_manager/src/photos.rs +++ b/actors/database_manager/src/photos.rs @@ -1,6 +1,6 @@ use crate::{MultiLoad, Result}; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] pub enum Error { #[error("Failed to create photo")] Create, diff --git a/actors/database_manager/src/product_photos.rs b/actors/database_manager/src/product_photos.rs index dcb6f96..ab45354 100644 --- a/actors/database_manager/src/product_photos.rs +++ b/actors/database_manager/src/product_photos.rs @@ -1,6 +1,6 @@ use crate::{db_async_handler, Result}; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] pub enum Error { #[error("Failed to attach photo to product")] Create, diff --git a/actors/database_manager/src/products.rs b/actors/database_manager/src/products.rs index 0473678..f7f207f 100644 --- a/actors/database_manager/src/products.rs +++ b/actors/database_manager/src/products.rs @@ -9,7 +9,7 @@ use model::{ use super::Result; use crate::MultiLoad; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] pub enum Error { #[error("Unable to load all products")] All, diff --git a/actors/database_manager/src/shopping_cart_items.rs b/actors/database_manager/src/shopping_cart_items.rs index c839e5e..4708e12 100644 --- a/actors/database_manager/src/shopping_cart_items.rs +++ b/actors/database_manager/src/shopping_cart_items.rs @@ -4,7 +4,7 @@ use sqlx::PgPool; use super::Result; use crate::db_async_handler; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] pub enum Error { #[error("Can't create shopping cart item")] CantCreate, diff --git a/actors/database_manager/src/shopping_carts.rs b/actors/database_manager/src/shopping_carts.rs index 745f007..165baa3 100644 --- a/actors/database_manager/src/shopping_carts.rs +++ b/actors/database_manager/src/shopping_carts.rs @@ -4,7 +4,7 @@ use sqlx::PgPool; use super::Result; use crate::db_async_handler; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] pub enum Error { #[error("Can't create shopping cart")] CantCreate, diff --git a/actors/database_manager/src/stocks.rs b/actors/database_manager/src/stocks.rs index 7445727..f94e918 100644 --- a/actors/database_manager/src/stocks.rs +++ b/actors/database_manager/src/stocks.rs @@ -4,7 +4,7 @@ use sqlx::PgPool; use crate::{MultiLoad, Result}; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] pub enum Error { #[error("Unable to load all stocks")] All, diff --git a/actors/database_manager/src/tokens.rs b/actors/database_manager/src/tokens.rs index e15ac98..37d93aa 100644 --- a/actors/database_manager/src/tokens.rs +++ b/actors/database_manager/src/tokens.rs @@ -4,7 +4,7 @@ use sqlx::PgPool; use crate::{db_async_handler, Result}; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] pub enum Error { #[error("Failed to save new token")] Create, diff --git a/actors/email_manager/src/lib.rs b/actors/email_manager/src/lib.rs index d02cbfd..7e88a2f 100644 --- a/actors/email_manager/src/lib.rs +++ b/actors/email_manager/src/lib.rs @@ -20,7 +20,8 @@ macro_rules! mail_async_handler { static STYLE: &str = include_str!("../assets/style.css"); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, thiserror::Error)] +#[serde(rename_all = "kebab-case", tag = "email")] pub enum Error { #[error("Failed to render reset password template")] ResetPassTemplate, diff --git a/actors/fs_manager/Cargo.toml b/actors/fs_manager/Cargo.toml index 0c4fbc2..4bc221f 100644 --- a/actors/fs_manager/Cargo.toml +++ b/actors/fs_manager/Cargo.toml @@ -15,6 +15,8 @@ actix-rt = { version = "2.7", features = [] } thiserror = { version = "1.0.31" } +serde = { version = "1.0", features = ["derive"] } + uuid = { version = "0.8", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] } diff --git a/actors/fs_manager/src/lib.rs b/actors/fs_manager/src/lib.rs index 74e05fa..d97052f 100644 --- a/actors/fs_manager/src/lib.rs +++ b/actors/fs_manager/src/lib.rs @@ -69,16 +69,17 @@ macro_rules! query_fs { }; } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] +#[serde(rename_all = "kebab-case", tag = "fs")] pub enum Error { #[error("Can't access file system. Please check privileges")] StorageUnavailable, - #[error("Can't write to file. Please check privileges. {0:?}")] - CantWrite(std::io::Error), + #[error("Can't write to file. Please check privileges.")] + CantWrite, #[error("Can't write to file. There's no more space on disk")] NoSpace, - #[error("Can't remove file. Please check privileges. {0:?}")] - CantRemove(std::io::Error), + #[error("Can't remove file. Please check privileges.")] + CantRemove, #[error("Can't write to file. Invalid path, no filename")] InvalidPath, } @@ -141,7 +142,10 @@ pub(crate) async fn remove_file(msg: RemoveFile, config: SharedAppConfig) -> Res { Ok(_) => Ok(()), Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()), - Err(e) => Err(Error::CantRemove(e)), + Err(e) => { + log::error!("{:?}", e); + Err(Error::CantRemove) + } } } @@ -201,7 +205,10 @@ pub(crate) async fn write_file(msg: WriteFile, config: SharedAppConfig) -> Resul ); let mut file = match std::fs::File::create(&path) { Ok(f) => f, - Err(e) => return Err(Error::CantWrite(e)), + Err(e) => { + log::error!("{:?}", e); + return Err(Error::CantWrite); + } }; let mut counter = 0; @@ -213,7 +220,10 @@ pub(crate) async fn write_file(msg: WriteFile, config: SharedAppConfig) -> Resul match file.write(&b) { Ok(_) => {} Err(e) if e.kind() == std::io::ErrorKind::StorageFull => return Err(Error::NoSpace), - Err(e) => return Err(Error::CantWrite(e)), + Err(e) => { + log::error!("{:?}", e); + return Err(Error::CantWrite); + } } } log::debug!("File {:?} successfully written", unique_name); diff --git a/actors/lang_provider/Cargo.toml b/actors/lang_provider/Cargo.toml index e69de29..b993442 100644 --- a/actors/lang_provider/Cargo.toml +++ b/actors/lang_provider/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "lang_provider" +version = "0.1.0" +edition = "2021" + +[dependencies] +model = { path = "../../shared/model" } +config = { path = "../../shared/config" } + +actix = { version = "0.13", features = [] } +actix-rt = { version = "2.7", features = [] } + +thiserror = { version = "1.0.31" } + +log = { version = "0.4", features = [] } +pretty_env_logger = { version = "0.4", features = [] } + +fluent = { version = "0.16.0" } +unic-langid = { version = "0.9.0" } diff --git a/actors/lang_provider/locales/en/cart.ftl b/actors/lang_provider/locales/en/cart.ftl index e69de29..057cde4 100644 --- a/actors/lang_provider/locales/en/cart.ftl +++ b/actors/lang_provider/locales/en/cart.ftl @@ -0,0 +1,7 @@ +# Cart +shopping-cart-failed = "Failed to load shopping cart. Please try later." +cart-not-available = "Failed to load your shopping cart. Please try later." +cant-modify-item = "At least one item in cart can't be modify. Please try later." +cant-modify-cart = "Can't modify shopping cart. Please try later." +db = "There was an expected error. Please try later." +update-failed = "At least one item in cart can't be modify. Please try later." diff --git a/actors/lang_provider/locales/pl/cart.ftl b/actors/lang_provider/locales/pl/cart.ftl index e69de29..8da0416 100644 --- a/actors/lang_provider/locales/pl/cart.ftl +++ b/actors/lang_provider/locales/pl/cart.ftl @@ -0,0 +1,7 @@ +# Cart +shopping-cart-failed = "Nastąpił błąd podczas wczytywania koszyka. Proszę spróbuj później." +cart-not-available = "Nastąpił błąd podczas wczytywania twojego koszyka. Proszę spróbuj później." +cant-modify-item = "Przynajmniej jeden przedmiot z twojego koszyka nie mógł być zmieniony. Proszę spróbuj później." +cant-modify-cart = "Nie mogliśmy zapisać zmian w twoim koszyku. Proszę spróbuj później." +db = "Nastąpił nieoczekiwany błąd. Proszę spróbuj później." +update-failed = "Przynajmniej jeden przedmiot z twojego koszyka nie mógł być zmieniony. Proszę spróbuj później." diff --git a/actors/order_manager/Cargo.toml b/actors/order_manager/Cargo.toml index 074a85d..0b3e976 100644 --- a/actors/order_manager/Cargo.toml +++ b/actors/order_manager/Cargo.toml @@ -13,6 +13,8 @@ actix-rt = { version = "2.7", features = [] } thiserror = { version = "1.0.31" } +serde = { version = "1.0.137", features = ["derive"] } + uuid = { version = "0.8", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] } diff --git a/actors/order_manager/src/lib.rs b/actors/order_manager/src/lib.rs index 64c8882..9725059 100644 --- a/actors/order_manager/src/lib.rs +++ b/actors/order_manager/src/lib.rs @@ -19,7 +19,8 @@ macro_rules! order_async_handler { }; } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] +#[serde(rename_all = "kebab-case", tag = "order")] pub enum Error { #[error("Database actor failed")] DatabaseInternal, diff --git a/actors/payment_manager/src/lib.rs b/actors/payment_manager/src/lib.rs index 4a78f25..22cb0ea 100644 --- a/actors/payment_manager/src/lib.rs +++ b/actors/payment_manager/src/lib.rs @@ -61,14 +61,17 @@ macro_rules! query_pay { pub type PayUClient = Arc>; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] +#[serde(rename_all = "kebab-case", tag = "pay")] pub enum Error { - #[error("{0}")] - PayU(#[from] pay_u::Error), #[error("Failed to create order")] CreateOrder, #[error("Failed to create order. Shopping cart is not available")] UnavailableShoppingCart, + #[error("Can't place order")] + PaymentFailed, + #[error("Order data is invalid. Please check order details")] + InvalidOrder, } pub type Result = std::result::Result; @@ -81,7 +84,7 @@ pub struct PaymentManager { } impl PaymentManager { - pub async fn build(config: SharedAppConfig, db: Addr) -> Result { + pub async fn build(config: SharedAppConfig, db: Addr) -> Self { let mut client = { let l = config.lock(); let p = l.payment(); @@ -91,12 +94,15 @@ impl PaymentManager { p.payu_client_merchant_id(), ) }; - client.authorize().await?; - Ok(Self { + client.authorize().await.unwrap_or_else(|e| { + log::error!("{}", e); + std::process::exit(1); + }); + Self { client: Arc::new(Mutex::new(client)), db, config, - }) + } } } @@ -255,7 +261,11 @@ pub(crate) async fn request_payment( msg.customer_ip, msg.currency, format!("Order #{}", db_order.id), - )? + ) + .map_err(|e| { + log::error!("{}", e); + Error::InvalidOrder + })? .with_products(cart_products.into_iter().map(|p| { pay_u::Product::new( p.name.to_string(), @@ -270,7 +280,11 @@ pub(crate) async fn request_payment( .with_notify_url(notify_uri) .with_continue_url(continue_uri), ) - .await? + .await + .map_err(|e| { + log::error!("{}", e); + Error::PaymentFailed + })? }; query_db!( diff --git a/actors/search_manager/src/lib.rs b/actors/search_manager/src/lib.rs index 432cfb2..dcee6fa 100644 --- a/actors/search_manager/src/lib.rs +++ b/actors/search_manager/src/lib.rs @@ -23,7 +23,8 @@ macro_rules! search_async_handler { }; } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] +#[serde(rename_all = "kebab-case", tag = "search")] pub enum Error { #[error("Can't create index")] CantCreate, diff --git a/actors/token_manager/Cargo.toml b/actors/token_manager/Cargo.toml index 786010d..b7258a3 100644 --- a/actors/token_manager/Cargo.toml +++ b/actors/token_manager/Cargo.toml @@ -31,3 +31,7 @@ rand_core = { version = "0.6", features = ["std"] } jwt = { version = "0.16", features = [] } hmac = { version = "0.12", features = [] } sha2 = { version = "0.10", features = [] } + +tokio = { version = "1.17", features = ["full"] } +futures = { version = "0.3", features = [] } +futures-util = { version = "0.3", features = [] } diff --git a/actors/token_manager/src/lib.rs b/actors/token_manager/src/lib.rs index 618924b..cf85237 100644 --- a/actors/token_manager/src/lib.rs +++ b/actors/token_manager/src/lib.rs @@ -106,7 +106,8 @@ macro_rules! query_tm { pub jti: uuid::Uuid, }*/ -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)] +#[serde(rename_all = "kebab-case", tag = "token")] pub enum Error { #[error("Unable to save new token")] Save, @@ -248,6 +249,62 @@ pub(crate) async fn create_token( Ok((token, token_string)) } +pub struct AuthPair { + pub access_token: Token, + pub access_token_string: AccessTokenString, + pub _refresh_token: Token, + pub refresh_token_string: model::RefreshTokenString, +} + +#[derive(Message)] +#[rtype(result = "Result")] +pub struct CreatePair { + pub customer_id: uuid::Uuid, + pub role: Role, + pub id: AccountId, +} + +token_async_handler!(CreatePair, create_pair, AuthPair); + +pub(crate) async fn create_pair( + msg: CreatePair, + db: Addr, + config: SharedAppConfig, +) -> Result { + let (access_token, refresh_token) = tokio::join!( + create_token( + CreateToken { + customer_id: msg.customer_id, + role: msg.role, + subject: msg.id, + audience: Some(model::Audience::Web), + exp: None + }, + db.clone(), + config.clone() + ), + create_token( + CreateToken { + customer_id: msg.customer_id, + role: msg.role, + subject: msg.id, + audience: Some(model::Audience::Web), + exp: Some((chrono::Utc::now() + chrono::Duration::days(31)).naive_utc()) + }, + db.clone(), + config.clone() + ) + ); + let (access_token, access_token_string): (Token, AccessTokenString) = access_token?; + let (refresh_token, refresh_token_string): (Token, AccessTokenString) = refresh_token?; + Ok(AuthPair { + access_token, + access_token_string, + _refresh_token: refresh_token, + refresh_token_string: refresh_token_string.into(), + }) +} + #[derive(Message)] #[rtype(result = "Result")] pub struct Validate { diff --git a/api/src/main.rs b/api/src/main.rs index 5da2003..8c79c91 100644 --- a/api/src/main.rs +++ b/api/src/main.rs @@ -47,20 +47,20 @@ async fn server(opts: ServerOpts) -> Result<()> { let app_config = config::default_load(&opts); let db = database_manager::Database::build(app_config.clone()) - .await? + .await .start(); let token_manager = token_manager::TokenManager::new(app_config.clone(), db.clone()).start(); let order_manager = order_manager::OrderManager::new(app_config.clone(), db.clone()).start(); let payment_manager = payment_manager::PaymentManager::build(app_config.clone(), db.clone()) .await - .expect("Failed to start payment manager") .start(); let search_manager = search_manager::SearchManager::new(app_config.clone()).start(); let fs_manager = fs_manager::FsManager::build(app_config.clone()) .await .expect("Failed to initialize file system storage"); let cart_manager = cart_manager::CartManager::new(db.clone()).start(); - let account_manager = account_manager::AccountManager::new(db.clone()).start(); + let account_manager = + account_manager::AccountManager::new(app_config.clone(), db.clone()).start(); let addr = { let l = app_config.lock(); let w = l.web(); @@ -110,7 +110,7 @@ async fn migrate(opts: MigrateOpts) -> Result<()> { use sqlx::migrate::MigrateError; let config = config::default_load(&opts); - let db = database_manager::Database::build(config).await?; + let db = database_manager::Database::build(config).await; let res: std::result::Result<(), MigrateError> = sqlx::migrate!("../migrations").run(db.pool()).await; match res { @@ -140,7 +140,7 @@ async fn create_account(opts: CreateAccountOpts) -> Result<()> { } let config = config::default_load(&opts); let db = database_manager::Database::build(config.clone()) - .await? + .await .start(); let pass = match opts.pass_file { Some(path) => std::fs::read_to_string(path).map_err(Error::PassFile)?, @@ -204,7 +204,7 @@ async fn reindex(opts: ReIndexOpts) -> Result<()> { let config = config::default_load(&opts); opts.update_config(&mut *config.lock()); let db = database_manager::Database::build(config.clone()) - .await? + .await .start(); let search = search_manager::SearchManager::new(config).start(); let products: Vec = db diff --git a/api/src/routes/admin/api_v1.rs b/api/src/routes/admin/api_v1/mod.rs similarity index 83% rename from api/src/routes/admin/api_v1.rs rename to api/src/routes/admin/api_v1/mod.rs index 1943c7f..868263b 100644 --- a/api/src/routes/admin/api_v1.rs +++ b/api/src/routes/admin/api_v1/mod.rs @@ -13,7 +13,7 @@ use model::Encrypt; use token_manager::TokenManager; use crate::routes; -use crate::routes::{create_auth_pair, AdminError, AuthPair, RequireUser}; +use crate::routes::RequireUser; #[delete("/logout")] async fn logout( @@ -40,26 +40,31 @@ async fn sign_in( login: payload.login, email: payload.email, }, - routes::Error::Admin(AdminError::DatabaseConnection) + routes::Error::CriticalFailure ); if payload.password.validate(&account.pass_hash).is_err() { return Err(routes::Error::Unauthorized); } - let role = account.role; - - let AuthPair { + let token_manager::AuthPair { access_token, access_token_string, _refresh_token: _, refresh_token_string, - } = create_auth_pair(tm, account).await?; + } = tm + .send(token_manager::CreatePair { + customer_id: account.customer_id, + role: account.role, + id: account.id, + }) + .await + .map_err(|_| routes::Error::CriticalFailure)??; Ok(Json(model::api::SessionOutput { access_token: access_token_string, refresh_token: refresh_token_string, exp: access_token.expiration_time, - role, + role: account.role, })) } diff --git a/api/src/routes/admin/api_v1/orders.rs b/api/src/routes/admin/api_v1/orders.rs index a8e8d73..a1d7997 100644 --- a/api/src/routes/admin/api_v1/orders.rs +++ b/api/src/routes/admin/api_v1/orders.rs @@ -6,7 +6,6 @@ use database_manager::Database; use model::api::AccountOrders; use token_manager::TokenManager; -use crate::routes::admin::Error; use crate::routes::RequireUser; use crate::{admin_send_db, routes}; diff --git a/api/src/routes/admin/api_v1/products.rs b/api/src/routes/admin/api_v1/products.rs index 6cfbe0d..a18f7a8 100644 --- a/api/src/routes/admin/api_v1/products.rs +++ b/api/src/routes/admin/api_v1/products.rs @@ -12,7 +12,6 @@ use search_manager::SearchManager; use serde::Deserialize; use token_manager::TokenManager; -use crate::routes::admin::Error; use crate::routes::RequireUser; use crate::{admin_send_db, routes}; diff --git a/api/src/routes/admin/api_v1/stocks.rs b/api/src/routes/admin/api_v1/stocks.rs index 819613b..c8af3d8 100644 --- a/api/src/routes/admin/api_v1/stocks.rs +++ b/api/src/routes/admin/api_v1/stocks.rs @@ -7,7 +7,6 @@ use model::{ProductId, Quantity, QuantityUnit, StockId}; use serde::Deserialize; use token_manager::TokenManager; -use crate::routes::admin::Error; use crate::routes::RequireUser; use crate::{admin_send_db, routes}; diff --git a/api/src/routes/admin.rs b/api/src/routes/admin/mod.rs similarity index 56% rename from api/src/routes/admin.rs rename to api/src/routes/admin/mod.rs index 5d72fba..b7375e0 100644 --- a/api/src/routes/admin.rs +++ b/api/src/routes/admin/mod.rs @@ -1,9 +1,6 @@ mod api_v1; use actix_web::web::{scope, ServiceConfig}; -use actix_web::{get, HttpResponse}; - -use crate::routes::Result; #[macro_export] macro_rules! admin_send_db { @@ -12,17 +9,17 @@ macro_rules! admin_send_db { Ok(Ok(res)) => res, Ok(Err(e)) => { log::error!("{}", e); - return Err(crate::routes::Error::Admin(Error::Database(e))); + return Err(crate::routes::Error::from(e)); } Err(e) => { log::error!("{}", e); - return Err(crate::routes::Error::Admin(Error::DatabaseConnection)); + return Err(crate::routes::Error::CriticalFailure); } } }}; } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, serde::Serialize, thiserror::Error)] pub enum Error { #[error("Can't register new account")] Register, @@ -36,17 +33,6 @@ pub enum Error { Database(#[from] database_manager::Error), } -#[get("")] -async fn landing() -> Result { - Ok(HttpResponse::NotImplemented() - .append_header(("Content-Type", "text/html")) - .body(include_str!("../../assets/index.html"))) -} - pub fn configure(config: &mut ServiceConfig) { - config.service( - scope("/admin") - .service(landing) - .configure(api_v1::configure), - ); + config.service(scope("/admin").configure(api_v1::configure)); } diff --git a/api/src/routes/mod.rs b/api/src/routes/mod.rs index b11b41d..d05d8b5 100644 --- a/api/src/routes/mod.rs +++ b/api/src/routes/mod.rs @@ -8,7 +8,7 @@ use actix::Addr; use actix_session::Session; use actix_web::body::BoxBody; use actix_web::http::StatusCode; -use actix_web::web::{Data, ServiceConfig}; +use actix_web::web::ServiceConfig; use actix_web::{HttpRequest, HttpResponse, Responder, ResponseError}; use model::api::Failure; use token_manager::{query_tm, TokenManager}; @@ -32,19 +32,23 @@ impl RequireLogin for Session { } } -#[derive(Debug, derive_more::From)] +#[derive(Debug, serde::Serialize, derive_more::From)] +#[serde(rename_all = "kebab-case")] pub enum Error { #[from(ignore)] Unauthorized, CriticalFailure, - Admin(admin::Error), Public(public::Error), -} - -impl From for Error { - fn from(v1: V1Error) -> Self { - Self::Public(PublicError::ApiV1(v1)) - } + Admin(admin::Error), + Account(account_manager::Error), + Cart(cart_manager::Error), + Database(database_manager::Error), + Email(email_manager::Error), + Fs(fs_manager::Error), + Order(order_manager::Error), + Pay(payment_manager::Error), + Search(search_manager::Error), + Token(token_manager::Error), } impl From for Error { @@ -56,12 +60,30 @@ impl From for Error { impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let msg = match self { - Error::Unauthorized => String::from("Unauthorized"), - Error::Admin(e) => format!("{e}"), - Error::Public(e) => format!("{e}"), + Error::Unauthorized => serde_json::to_string(&Failure { + errors: vec![String::from("Unauthorized")], + }) + .unwrap_or_default(), + Error::Admin(e) => serde_json::to_string(&Failure { + errors: vec![format!("{}", e)], + }) + .unwrap_or_default(), + Error::Public(e) => serde_json::to_string(&Failure { + errors: vec![format!("{}", e)], + }) + .unwrap_or_default(), Error::CriticalFailure => String::from("Something went wrong"), + Error::Account(_e) => serde_json::to_string(&self).unwrap_or_default(), + Error::Cart(_e) => serde_json::to_string(&self).unwrap_or_default(), + Error::Database(_e) => serde_json::to_string(&self).unwrap_or_default(), + Error::Email(_e) => serde_json::to_string(&self).unwrap_or_default(), + Error::Fs(_e) => serde_json::to_string(&self).unwrap_or_default(), + Error::Order(_e) => serde_json::to_string(&self).unwrap_or_default(), + Error::Pay(_e) => serde_json::to_string(&self).unwrap_or_default(), + Error::Search(_e) => serde_json::to_string(&self).unwrap_or_default(), + Error::Token(_e) => serde_json::to_string(&self).unwrap_or_default(), }; - f.write_str(&serde_json::to_string(&Failure { errors: vec![msg] }).unwrap()) + f.write_str(&msg) } } @@ -74,6 +96,15 @@ impl ResponseError for Error { } Error::Admin(_) => StatusCode::BAD_REQUEST, Error::Public(_) => StatusCode::BAD_REQUEST, + Error::Account(_) => StatusCode::BAD_REQUEST, + Error::Cart(_) => StatusCode::BAD_REQUEST, + Error::Database(_) => StatusCode::BAD_REQUEST, + Error::Email(_) => StatusCode::BAD_REQUEST, + Error::Fs(_) => StatusCode::BAD_REQUEST, + Error::Order(_) => StatusCode::BAD_REQUEST, + Error::Pay(_) => StatusCode::BAD_REQUEST, + Error::Search(_) => StatusCode::BAD_REQUEST, + Error::Token(_) => StatusCode::BAD_REQUEST, } } } @@ -82,41 +113,9 @@ impl Responder for Error { type Body = BoxBody; fn respond_to(self, _req: &HttpRequest) -> HttpResponse { - match self { - Error::Public(PublicError::DatabaseConnection) | Error::CriticalFailure => { - HttpResponse::InternalServerError() - .content_type("application/json") - .json(Failure { - errors: vec![format!("{}", self)], - }) - } - Error::Unauthorized => HttpResponse::Unauthorized() - .content_type("application/json") - .json(Failure { - errors: vec![format!("{}", self)], - }), - Error::Public(PublicError::Database(..)) | Error::Admin(..) => { - HttpResponse::BadRequest() - .content_type("application/json") - .json(Failure { - errors: vec![format!("{}", self)], - }) - } - Error::Public(PublicError::ApiV1(V1Error::ShoppingCart(ref e))) => match e { - V1ShoppingCartError::Ensure => HttpResponse::InternalServerError() - .content_type("application/json") - .json(Failure { - errors: vec![format!("{}", self)], - }), - }, - Error::Public(PublicError::ApiV1( - V1Error::ModifyItem | V1Error::RemoveItem | V1Error::AddOrder, - )) => HttpResponse::BadRequest() - .content_type("application/json") - .json(Failure { - errors: vec![format!("{}", self)], - }), - } + HttpResponse::build(self.status_code()) + .content_type("application/json") + .body(format!("{}", self)) } } @@ -160,45 +159,3 @@ impl RequireUser for actix_web_httpauth::extractors::bearer::BearerAuth { } } } - -pub struct AuthPair { - pub access_token: model::Token, - pub access_token_string: model::AccessTokenString, - pub _refresh_token: model::Token, - pub refresh_token_string: model::RefreshTokenString, -} - -pub async fn create_auth_pair( - tm: Data>, - account: model::FullAccount, -) -> Result { - let (access_token, refresh_token) = query_tm!( - multi, - tm, - Error::Public(PublicError::DatabaseConnection), - token_manager::CreateToken { - customer_id: account.customer_id, - role: account.role, - subject: account.id, - audience: Some(model::Audience::Web), - exp: None - }, - token_manager::CreateToken { - customer_id: account.customer_id, - role: account.role, - subject: account.id, - audience: Some(model::Audience::Web), - exp: Some((chrono::Utc::now() + chrono::Duration::days(31)).naive_utc()) - } - ); - let (access_token, access_token_string): (model::Token, model::AccessTokenString) = - access_token?; - let (refresh_token, refresh_token_string): (model::Token, model::AccessTokenString) = - refresh_token?; - Ok(AuthPair { - access_token, - access_token_string, - _refresh_token: refresh_token, - refresh_token_string: refresh_token_string.into(), - }) -} diff --git a/api/src/routes/public/api_v1.rs b/api/src/routes/public/api_v1/mod.rs similarity index 81% rename from api/src/routes/public/api_v1.rs rename to api/src/routes/public/api_v1/mod.rs index d8b338b..3238974 100644 --- a/api/src/routes/public/api_v1.rs +++ b/api/src/routes/public/api_v1/mod.rs @@ -3,13 +3,13 @@ mod unrestricted; use actix_web::web::{scope, ServiceConfig}; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, serde::Serialize, serde::Deserialize, thiserror::Error)] pub enum ShoppingCartError { #[error("Shopping cart can't be found or created")] Ensure, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, serde::Serialize, serde::Deserialize, thiserror::Error)] pub enum Error { #[error("{0}")] ShoppingCart(ShoppingCartError), diff --git a/api/src/routes/public/api_v1/restricted.rs b/api/src/routes/public/api_v1/restricted.rs index cdb5d23..9277b3a 100644 --- a/api/src/routes/public/api_v1/restricted.rs +++ b/api/src/routes/public/api_v1/restricted.rs @@ -12,7 +12,7 @@ use token_manager::TokenManager; use crate::routes; use crate::routes::public::api_v1::{Error as ApiV1Error, ShoppingCartError}; use crate::routes::public::Error as PublicError; -use crate::routes::{create_auth_pair, AuthPair, RequireUser, Result}; +use crate::routes::{RequireUser, Result}; /// This requires [model::AccessTokenString] to be set as bearer #[post("/token/verify")] @@ -42,20 +42,25 @@ async fn refresh_token( routes::Error::Unauthorized ); - let role = account.role; - - let AuthPair { + let token_manager::AuthPair { access_token, access_token_string, _refresh_token: _, refresh_token_string, - } = create_auth_pair(tm, account).await?; + } = tm + .send(token_manager::CreatePair { + customer_id: account.customer_id, + role: account.role, + id: account.id, + }) + .await + .map_err(|_| routes::Error::CriticalFailure)??; Ok(Json(model::api::SessionOutput { access_token: access_token_string, refresh_token: refresh_token_string, exp: access_token.expiration_time, - role, + role: account.role, })) } diff --git a/api/src/routes/public/api_v1/unrestricted.rs b/api/src/routes/public/api_v1/unrestricted.rs index f08382e..c9c0ae7 100644 --- a/api/src/routes/public/api_v1/unrestricted.rs +++ b/api/src/routes/public/api_v1/unrestricted.rs @@ -10,7 +10,7 @@ use token_manager::TokenManager; use crate::public_send_db; use crate::routes::public::Error as PublicError; -use crate::routes::{self, create_auth_pair, AuthPair}; +use crate::routes::{self}; #[get("/search")] async fn search( @@ -134,11 +134,6 @@ pub async fn create_account( config: Data, tm: Data>, ) -> routes::Result> { - if payload.password != payload.password_confirmation { - return Err(routes::Error::Admin( - routes::admin::Error::DifferentPasswords, - )); - } let hash = { match payload.password.encrypt(&config.lock().web().pass_salt()) { Ok(hash) => hash, @@ -149,32 +144,35 @@ pub async fn create_account( } }; - let account: model::FullAccount = query_db!( - db, - database_manager::CreateAccount { + let account: model::FullAccount = db + .send(database_manager::CreateAccount { email: payload.email, login: payload.login, - pass_hash: model::PassHash::from(hash), + pass_hash: model::PassHash::new(hash), role: model::Role::User, - }, - passthrough routes::Error::Public, - routes::Error::CriticalFailure - ); + }) + .await + .map_err(|_| routes::Error::CriticalFailure)??; - let role = account.role; - - let AuthPair { + let token_manager::AuthPair { access_token, access_token_string, _refresh_token: _, refresh_token_string, - } = create_auth_pair(tm, account).await?; + } = tm + .send(token_manager::CreatePair { + customer_id: account.customer_id, + role: account.role, + id: account.id, + }) + .await + .map_err(|_| routes::Error::CriticalFailure)??; Ok(Json(model::api::SessionOutput { access_token: access_token_string, refresh_token: refresh_token_string, exp: access_token.expiration_time, - role, + role: account.role, })) } @@ -198,20 +196,25 @@ async fn sign_in( return Err(routes::Error::Unauthorized); } - let role = account.role; - - let AuthPair { + let token_manager::AuthPair { access_token, access_token_string, _refresh_token: _, refresh_token_string, - } = create_auth_pair(tm, account).await?; + } = tm + .send(token_manager::CreatePair { + customer_id: account.customer_id, + role: account.role, + id: account.id, + }) + .await + .map_err(|_| routes::Error::CriticalFailure)??; Ok(Json(model::api::SessionOutput { access_token: access_token_string, refresh_token: refresh_token_string, exp: access_token.expiration_time, - role, + role: account.role, })) } diff --git a/api/src/routes/public.rs b/api/src/routes/public/mod.rs similarity index 94% rename from api/src/routes/public.rs rename to api/src/routes/public/mod.rs index f3b016c..34db43d 100644 --- a/api/src/routes/public.rs +++ b/api/src/routes/public/mod.rs @@ -44,7 +44,7 @@ macro_rules! public_send_db { }}; } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, serde::Serialize, thiserror::Error)] pub enum Error { #[error("{0}")] ApiV1(#[from] api_v1::Error), @@ -56,7 +56,7 @@ pub enum Error { #[get("/")] async fn landing() -> HttpResponse { - HttpResponse::NotImplemented().body("") + HttpResponse::NotImplemented().finish() } #[get("/config")] @@ -90,7 +90,7 @@ macro_rules! serve_svg { ($name: expr) => { HttpResponse::Ok() .append_header(("Content-Type", "image/svg+xml")) - .body(include_bytes!(concat!("../../assets/svg/", $name, ".svg")).to_vec()) + .body(include_bytes!(concat!("../../../assets/svg/", $name, ".svg")).to_vec()) }; } diff --git a/shared/model/src/api.rs b/shared/model/src/api.rs index 95dfeca..3a61a28 100644 --- a/shared/model/src/api.rs +++ b/shared/model/src/api.rs @@ -417,7 +417,6 @@ pub struct CreateAccountInput { pub email: Email, pub login: Login, pub password: Password, - pub password_confirmation: PasswordConfirmation, } #[derive(Serialize, Deserialize, Debug)]