Better errors, move create auth pair
This commit is contained in:
parent
9882b575de
commit
28e9736562
134
Cargo.lock
generated
134
Cargo.lock
generated
@ -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"
|
||||
|
@ -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 = [] }
|
||||
|
@ -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<T> = std::result::Result<T, Error>;
|
||||
@ -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<database_manager::Database>,
|
||||
db: Addr<database_manager::Database>,
|
||||
config: SharedAppConfig,
|
||||
}
|
||||
|
||||
impl AccountManager {
|
||||
pub fn new(db: actix::Addr<database_manager::Database>) -> Self {
|
||||
Self { db }
|
||||
pub fn new(config: SharedAppConfig, db: Addr<database_manager::Database>) -> 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<model::Address>,
|
||||
}
|
||||
|
||||
@ -88,8 +101,12 @@ pub struct Me {
|
||||
|
||||
account_async_handler!(Me, me, MeResult);
|
||||
|
||||
pub(crate) async fn me(msg: Me, db: actix::Addr<database_manager::Database>) -> Result<MeResult> {
|
||||
let account: model::FullAccount = query_db!(
|
||||
pub(crate) async fn me(
|
||||
msg: Me,
|
||||
db: Addr<database_manager::Database>,
|
||||
_config: SharedAppConfig,
|
||||
) -> Result<MeResult> {
|
||||
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<database_manager::Database>) ->
|
||||
);
|
||||
Ok(MeResult { account, addresses })
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<FullAccount>")]
|
||||
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<database_manager::Database>,
|
||||
config: SharedAppConfig,
|
||||
) -> Result<FullAccount> {
|
||||
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)
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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"] }
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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<T> = std::result::Result<T, Error>;
|
||||
@ -161,10 +168,13 @@ impl Clone for Database {
|
||||
}
|
||||
|
||||
impl Database {
|
||||
pub async fn build(config: SharedAppConfig) -> Result<Self> {
|
||||
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 {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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"] }
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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" }
|
@ -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."
|
@ -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."
|
@ -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"] }
|
||||
|
||||
|
@ -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,
|
||||
|
@ -61,14 +61,17 @@ macro_rules! query_pay {
|
||||
|
||||
pub type PayUClient = Arc<Mutex<pay_u::Client>>;
|
||||
|
||||
#[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<T> = std::result::Result<T, Error>;
|
||||
@ -81,7 +84,7 @@ pub struct PaymentManager {
|
||||
}
|
||||
|
||||
impl PaymentManager {
|
||||
pub async fn build(config: SharedAppConfig, db: Addr<Database>) -> Result<Self> {
|
||||
pub async fn build(config: SharedAppConfig, db: Addr<Database>) -> 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!(
|
||||
|
@ -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,
|
||||
|
@ -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 = [] }
|
||||
|
@ -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<AuthPair>")]
|
||||
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<Database>,
|
||||
config: SharedAppConfig,
|
||||
) -> Result<AuthPair> {
|
||||
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<Token>")]
|
||||
pub struct Validate {
|
||||
|
@ -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<model::Product> = db
|
||||
|
@ -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,
|
||||
}))
|
||||
}
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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<HttpResponse> {
|
||||
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));
|
||||
}
|
@ -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<V1Error> 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<V1ShoppingCartError> for Error {
|
||||
@ -56,12 +60,30 @@ impl From<V1ShoppingCartError> 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<Self::Body> {
|
||||
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<Addr<TokenManager>>,
|
||||
account: model::FullAccount,
|
||||
) -> Result<AuthPair> {
|
||||
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(),
|
||||
})
|
||||
}
|
||||
|
@ -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),
|
@ -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,
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -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<SharedAppConfig>,
|
||||
tm: Data<Addr<TokenManager>>,
|
||||
) -> routes::Result<Json<model::api::SessionOutput>> {
|
||||
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,
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
};
|
||||
}
|
||||
|
@ -417,7 +417,6 @@ pub struct CreateAccountInput {
|
||||
pub email: Email,
|
||||
pub login: Login,
|
||||
pub password: Password,
|
||||
pub password_confirmation: PasswordConfirmation,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
Loading…
Reference in New Issue
Block a user