Add seed and photos
This commit is contained in:
parent
1b75a6a1ac
commit
ff86e9929c
3
.env
3
.env
@ -14,3 +14,6 @@ PAYU_CLIENT_SECRET="12f071174cb7eb79d4aac5bc2f07563f"
|
|||||||
PAYU_CLIENT_MERCHANT_ID=300746
|
PAYU_CLIENT_MERCHANT_ID=300746
|
||||||
|
|
||||||
WEB_HOST=https://bazzar.ita-prog.pl
|
WEB_HOST=https://bazzar.ita-prog.pl
|
||||||
|
|
||||||
|
FILES_PUBLIC_PATH=/files
|
||||||
|
FILES_LOCAL_PATH=./tmp
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
|||||||
/target
|
/target
|
||||||
bazzar.toml
|
bazzar.toml
|
||||||
|
/tmp
|
||||||
|
/uploads
|
||||||
|
101
Cargo.lock
generated
101
Cargo.lock
generated
@ -616,6 +616,7 @@ dependencies = [
|
|||||||
"derive_more",
|
"derive_more",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"email_manager",
|
"email_manager",
|
||||||
|
"fs_manager",
|
||||||
"futures",
|
"futures",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"gumdrop",
|
"gumdrop",
|
||||||
@ -1034,6 +1035,41 @@ dependencies = [
|
|||||||
"cipher",
|
"cipher",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.13.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.13.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.13.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dashmap"
|
name = "dashmap"
|
||||||
version = "4.0.2"
|
version = "4.0.2"
|
||||||
@ -1058,15 +1094,34 @@ dependencies = [
|
|||||||
"actix-rt",
|
"actix-rt",
|
||||||
"chrono",
|
"chrono",
|
||||||
"config",
|
"config",
|
||||||
|
"fake",
|
||||||
"log",
|
"log",
|
||||||
"model",
|
"model",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
|
"rand",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "db-seed"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"actix 0.13.0",
|
||||||
|
"actix-rt",
|
||||||
|
"actix-web",
|
||||||
|
"config",
|
||||||
|
"database_manager",
|
||||||
|
"dotenv",
|
||||||
|
"fake",
|
||||||
|
"log",
|
||||||
|
"model",
|
||||||
|
"pretty_env_logger",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dbg"
|
name = "dbg"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@ -1147,6 +1202,17 @@ version = "0.15.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
|
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dummy"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5bf5ff6f74150b0bbb6e6057718a903b3d8f3fc7096c9190fc162ca99d3b2273"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.6.1"
|
version = "1.6.1"
|
||||||
@ -1212,6 +1278,19 @@ version = "2.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71"
|
checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fake"
|
||||||
|
version = "2.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "21a8531dd3a64fd1cfbe92fad4160bc2060489c6195fe847e045e5788f710bae"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"dummy",
|
||||||
|
"http",
|
||||||
|
"rand",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fake-simd"
|
name = "fake-simd"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@ -1737,6 +1816,12 @@ dependencies = [
|
|||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
@ -1987,6 +2072,12 @@ dependencies = [
|
|||||||
"digest 0.10.3",
|
"digest 0.10.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "md5"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.4.1"
|
version = "2.4.1"
|
||||||
@ -2095,6 +2186,8 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
|
"fake",
|
||||||
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
@ -3376,6 +3469,12 @@ dependencies = [
|
|||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.4.1"
|
version = "2.4.1"
|
||||||
@ -3922,7 +4021,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
|
"md5",
|
||||||
"serde",
|
"serde",
|
||||||
|
"sha1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -11,4 +11,5 @@ members = [
|
|||||||
"actors/search_manager",
|
"actors/search_manager",
|
||||||
"actors/token_manager",
|
"actors/token_manager",
|
||||||
"actors/fs_manager",
|
"actors/fs_manager",
|
||||||
|
"db-seed"
|
||||||
]
|
]
|
||||||
|
@ -3,6 +3,9 @@ name = "database_manager"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
dummy = ["fake", "rand"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
model = { path = "../../shared/model" }
|
model = { path = "../../shared/model" }
|
||||||
config = { path = "../../shared/config" }
|
config = { path = "../../shared/config" }
|
||||||
@ -20,3 +23,6 @@ chrono = { version = "0.4", features = ["serde"] }
|
|||||||
|
|
||||||
log = { version = "0.4", features = [] }
|
log = { version = "0.4", features = [] }
|
||||||
pretty_env_logger = { version = "0.4", features = [] }
|
pretty_env_logger = { version = "0.4", features = [] }
|
||||||
|
|
||||||
|
fake = { version = "2.4.3", features = ["derive", "chrono", "http", "uuid"], optional = true }
|
||||||
|
rand = { version = "0.8.5", optional = true }
|
||||||
|
@ -3,7 +3,7 @@ use sqlx::PgPool;
|
|||||||
|
|
||||||
use super::Result;
|
use super::Result;
|
||||||
use crate::{
|
use crate::{
|
||||||
create_order_item, db_async_handler, shopping_cart_set_state, CreateOrderItem, Database,
|
create_order_item, db_async_handler, shopping_cart_set_state, CreateOrderItem,
|
||||||
ShoppingCartSetState,
|
ShoppingCartSetState,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
#[cfg(feature = "dummy")]
|
||||||
|
use fake::Fake;
|
||||||
use model::{AccountId, AccountState, Email, FullAccount, Login, PassHash, Role};
|
use model::{AccountId, AccountState, Email, FullAccount, Login, PassHash, Role};
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
use super::Result;
|
use super::Result;
|
||||||
use crate::{db_async_handler, Database};
|
use crate::db_async_handler;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@ -37,10 +39,13 @@ FROM accounts
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[derive(actix::Message)]
|
#[derive(actix::Message)]
|
||||||
#[rtype(result = "Result<FullAccount>")]
|
#[rtype(result = "Result<FullAccount>")]
|
||||||
pub struct CreateAccount {
|
pub struct CreateAccount {
|
||||||
|
#[cfg_attr(feature = "dummy", dummy("fake::faker::internet::en::FreeEmail"))]
|
||||||
pub email: Email,
|
pub email: Email,
|
||||||
|
#[cfg_attr(feature = "dummy", dummy("fake::faker::internet::en::Username"))]
|
||||||
pub login: Login,
|
pub login: Login,
|
||||||
pub pass_hash: PassHash,
|
pub pass_hash: PassHash,
|
||||||
pub role: Role,
|
pub role: Role,
|
||||||
@ -68,6 +73,7 @@ RETURNING id, email, login, pass_hash, role, customer_id, state
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[derive(actix::Message)]
|
#[derive(actix::Message)]
|
||||||
#[rtype(result = "Result<FullAccount>")]
|
#[rtype(result = "Result<FullAccount>")]
|
||||||
pub struct UpdateAccount {
|
pub struct UpdateAccount {
|
||||||
|
@ -1,18 +1,23 @@
|
|||||||
pub use account_orders::*;
|
|
||||||
pub use accounts::*;
|
|
||||||
use actix::{Actor, Context};
|
use actix::{Actor, Context};
|
||||||
use config::SharedAppConfig;
|
use config::SharedAppConfig;
|
||||||
pub use order_items::*;
|
|
||||||
pub use products::*;
|
|
||||||
pub use shopping_cart_items::*;
|
|
||||||
pub use shopping_carts::*;
|
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
pub use stocks::*;
|
|
||||||
pub use tokens::*;
|
pub use crate::account_orders::*;
|
||||||
|
pub use crate::accounts::*;
|
||||||
|
pub use crate::order_items::*;
|
||||||
|
pub use crate::photos::*;
|
||||||
|
pub use crate::product_photos::*;
|
||||||
|
pub use crate::products::*;
|
||||||
|
pub use crate::shopping_cart_items::*;
|
||||||
|
pub use crate::shopping_carts::*;
|
||||||
|
pub use crate::stocks::*;
|
||||||
|
pub use crate::tokens::*;
|
||||||
|
|
||||||
pub mod account_orders;
|
pub mod account_orders;
|
||||||
pub mod accounts;
|
pub mod accounts;
|
||||||
pub mod order_items;
|
pub mod order_items;
|
||||||
|
pub mod photos;
|
||||||
|
pub mod product_photos;
|
||||||
pub mod products;
|
pub mod products;
|
||||||
pub mod shopping_cart_items;
|
pub mod shopping_cart_items;
|
||||||
pub mod shopping_carts;
|
pub mod shopping_carts;
|
||||||
@ -22,7 +27,7 @@ pub mod tokens;
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! db_async_handler {
|
macro_rules! db_async_handler {
|
||||||
($msg: ty, $async: ident, $res: ty) => {
|
($msg: ty, $async: ident, $res: ty) => {
|
||||||
impl actix::Handler<$msg> for Database {
|
impl actix::Handler<$msg> for crate::Database {
|
||||||
type Result = actix::ResponseActFuture<Self, Result<$res>>;
|
type Result = actix::ResponseActFuture<Self, Result<$res>>;
|
||||||
|
|
||||||
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
@ -47,7 +52,7 @@ macro_rules! db_async_handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl actix::Handler<$msg> for Database {
|
impl actix::Handler<$msg> for crate::Database {
|
||||||
type Result = actix::ResponseActFuture<Self, Result<$res>>;
|
type Result = actix::ResponseActFuture<Self, Result<$res>>;
|
||||||
|
|
||||||
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
@ -114,6 +119,10 @@ pub enum Error {
|
|||||||
ShoppingCartItem(#[from] shopping_cart_items::Error),
|
ShoppingCartItem(#[from] shopping_cart_items::Error),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
Token(#[from] tokens::Error),
|
Token(#[from] tokens::Error),
|
||||||
|
#[error("{0}")]
|
||||||
|
Photo(#[from] photos::Error),
|
||||||
|
#[error("{0}")]
|
||||||
|
ProductPhoto(#[from] product_photos::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
#[cfg(feature = "dummy")]
|
||||||
|
use fake::Fake;
|
||||||
use model::*;
|
use model::*;
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
use super::Result;
|
use super::Result;
|
||||||
use crate::{db_async_handler, Database};
|
use crate::db_async_handler;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@ -40,6 +42,7 @@ ORDER BY id DESC
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[derive(actix::Message)]
|
#[derive(actix::Message)]
|
||||||
#[rtype(result = "Result<OrderItem>")]
|
#[rtype(result = "Result<OrderItem>")]
|
||||||
pub struct CreateOrderItem {
|
pub struct CreateOrderItem {
|
||||||
|
37
actors/database_manager/src/photos.rs
Normal file
37
actors/database_manager/src/photos.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use crate::Result;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("Failed to create photo")]
|
||||||
|
Create,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(actix::Message)]
|
||||||
|
#[rtype(result = "Result<model::Photo>")]
|
||||||
|
pub struct CreatePhoto {
|
||||||
|
pub local_path: model::LocalPath,
|
||||||
|
pub file_name: model::FileName,
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::db_async_handler!(CreatePhoto, create_photo, model::Photo, inner_create_photo);
|
||||||
|
|
||||||
|
pub(crate) async fn create_photo<'e, E>(msg: CreatePhoto, pool: E) -> Result<model::Photo>
|
||||||
|
where
|
||||||
|
E: sqlx::Executor<'e, Database = sqlx::Postgres>,
|
||||||
|
{
|
||||||
|
sqlx::query_as(
|
||||||
|
r#"
|
||||||
|
INSERT INTO photos (file_name, local_path)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
RETURNING id, local_path, file_name
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(msg.file_name)
|
||||||
|
.bind(msg.local_path)
|
||||||
|
.fetch_one(pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
log::error!("{e:?}");
|
||||||
|
crate::Error::Photo(Error::Create)
|
||||||
|
})
|
||||||
|
}
|
2
actors/database_manager/src/product_photos.rs
Normal file
2
actors/database_manager/src/product_photos.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {}
|
@ -1,11 +1,12 @@
|
|||||||
use actix::Message;
|
use actix::Message;
|
||||||
|
#[cfg(feature = "dummy")]
|
||||||
|
use fake::Fake;
|
||||||
use model::{
|
use model::{
|
||||||
Days, Price, Product, ProductCategory, ProductId, ProductLongDesc, ProductName,
|
Days, Price, Product, ProductCategory, ProductId, ProductLongDesc, ProductName,
|
||||||
ProductShortDesc,
|
ProductShortDesc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Result;
|
use super::Result;
|
||||||
use crate::Database;
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@ -51,6 +52,7 @@ FROM products
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
#[rtype(result = "Result<model::Product>")]
|
#[rtype(result = "Result<model::Product>")]
|
||||||
pub struct CreateProduct {
|
pub struct CreateProduct {
|
||||||
|
@ -2,7 +2,7 @@ use model::*;
|
|||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
use super::Result;
|
use super::Result;
|
||||||
use crate::{db_async_handler, Database};
|
use crate::db_async_handler;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -2,7 +2,7 @@ use model::*;
|
|||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
use super::Result;
|
use super::Result;
|
||||||
use crate::{db_async_handler, Database};
|
use crate::db_async_handler;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -2,7 +2,7 @@ use actix::Message;
|
|||||||
use model::{ProductId, Quantity, QuantityUnit, Stock, StockId};
|
use model::{ProductId, Quantity, QuantityUnit, Stock, StockId};
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
use crate::{Database, Result};
|
use crate::Result;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -2,7 +2,7 @@ use actix::Message;
|
|||||||
use model::{AccountId, Audience, Token};
|
use model::{AccountId, Audience, Token};
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
use crate::{db_async_handler, Database, Result};
|
use crate::{db_async_handler, Result};
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -4,7 +4,7 @@ use std::ffi::OsStr;
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use config::SharedAppConfig;
|
use config::SharedAppConfig;
|
||||||
use model::FileName;
|
use model::{FileName, LocalPath};
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! fs_async_handler {
|
macro_rules! fs_async_handler {
|
||||||
@ -37,6 +37,7 @@ pub enum Error {
|
|||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct FsManager {
|
pub struct FsManager {
|
||||||
config: SharedAppConfig,
|
config: SharedAppConfig,
|
||||||
}
|
}
|
||||||
@ -54,6 +55,9 @@ impl FsManager {
|
|||||||
async fn validate_fs(config: SharedAppConfig) -> Result<()> {
|
async fn validate_fs(config: SharedAppConfig) -> Result<()> {
|
||||||
let l = config.lock();
|
let l = config.lock();
|
||||||
let output_path = l.files().local_path();
|
let output_path = l.files().local_path();
|
||||||
|
|
||||||
|
tokio::fs::create_dir_all(&output_path).await.ok();
|
||||||
|
|
||||||
let test_file = std::path::PathBuf::new()
|
let test_file = std::path::PathBuf::new()
|
||||||
.join(output_path)
|
.join(output_path)
|
||||||
.join(format!("{}", uuid::Uuid::new_v4()));
|
.join(format!("{}", uuid::Uuid::new_v4()));
|
||||||
@ -93,16 +97,21 @@ pub(crate) async fn remove_file(msg: RemoveFile, config: SharedAppConfig) -> Res
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct WriteResult {
|
||||||
|
pub file_name: FileName,
|
||||||
|
pub local_path: LocalPath,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(actix::Message)]
|
#[derive(actix::Message)]
|
||||||
#[rtype(result = "Result<FileName>")]
|
#[rtype(result = "Result<WriteResult>")]
|
||||||
pub struct WriteFile {
|
pub struct WriteFile {
|
||||||
pub file_name: String,
|
pub file_name: String,
|
||||||
pub stream: tokio::sync::mpsc::UnboundedReceiver<u8>,
|
pub stream: tokio::sync::mpsc::UnboundedReceiver<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fs_async_handler!(WriteFile, write_file, FileName);
|
fs_async_handler!(WriteFile, write_file, WriteResult);
|
||||||
|
|
||||||
pub(crate) async fn write_file(msg: WriteFile, config: SharedAppConfig) -> Result<FileName> {
|
pub(crate) async fn write_file(msg: WriteFile, config: SharedAppConfig) -> Result<WriteResult> {
|
||||||
let WriteFile {
|
let WriteFile {
|
||||||
file_name,
|
file_name,
|
||||||
mut stream,
|
mut stream,
|
||||||
@ -128,8 +137,10 @@ pub(crate) async fn write_file(msg: WriteFile, config: SharedAppConfig) -> Resul
|
|||||||
l.files().local_path()
|
l.files().local_path()
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = std::path::PathBuf::new().join(output_path).join(&file_name);
|
let path = std::path::PathBuf::new()
|
||||||
let mut file = match std::fs::File::create(path) {
|
.join(&output_path)
|
||||||
|
.join(&file_name);
|
||||||
|
let mut file = match std::fs::File::create(&path) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(e) => return Err(Error::CantWrite(e)),
|
Err(e) => return Err(Error::CantWrite(e)),
|
||||||
};
|
};
|
||||||
@ -141,5 +152,8 @@ pub(crate) async fn write_file(msg: WriteFile, config: SharedAppConfig) -> Resul
|
|||||||
Err(e) => return Err(Error::CantWrite(e)),
|
Err(e) => return Err(Error::CantWrite(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(FileName::from(file_name))
|
Ok(WriteResult {
|
||||||
|
file_name: FileName::from(file_name),
|
||||||
|
local_path: LocalPath::from(path.to_str().unwrap_or_default().to_string()),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ order_manager = { path = "../actors/order_manager" }
|
|||||||
payment_manager = { path = "../actors/payment_manager" }
|
payment_manager = { path = "../actors/payment_manager" }
|
||||||
search_manager = { path = "../actors/search_manager" }
|
search_manager = { path = "../actors/search_manager" }
|
||||||
token_manager = { path = "../actors/token_manager" }
|
token_manager = { path = "../actors/token_manager" }
|
||||||
|
fs_manager = { path = "../actors/fs_manager" }
|
||||||
|
|
||||||
actix = { version = "0.13", features = [] }
|
actix = { version = "0.13", features = [] }
|
||||||
actix-rt = { version = "2.7", features = [] }
|
actix-rt = { version = "2.7", features = [] }
|
||||||
|
@ -57,6 +57,9 @@ async fn server(opts: ServerOpts) -> Result<()> {
|
|||||||
.expect("Failed to start payment manager")
|
.expect("Failed to start payment manager")
|
||||||
.start();
|
.start();
|
||||||
let search_manager = search_manager::SearchManager::new(app_config.clone());
|
let search_manager = search_manager::SearchManager::new(app_config.clone());
|
||||||
|
let fs_manager = fs_manager::FsManager::build(app_config.clone())
|
||||||
|
.await
|
||||||
|
.expect("Failed to initialize file system storage");
|
||||||
let addr = {
|
let addr = {
|
||||||
let l = app_config.lock();
|
let l = app_config.lock();
|
||||||
let w = l.web();
|
let w = l.web();
|
||||||
@ -84,6 +87,7 @@ async fn server(opts: ServerOpts) -> Result<()> {
|
|||||||
.app_data(Data::new(order_manager.clone()))
|
.app_data(Data::new(order_manager.clone()))
|
||||||
.app_data(Data::new(payment_manager.clone()))
|
.app_data(Data::new(payment_manager.clone()))
|
||||||
.app_data(Data::new(search_manager.clone()))
|
.app_data(Data::new(search_manager.clone()))
|
||||||
|
.app_data(Data::new(fs_manager.clone()))
|
||||||
.configure(routes::configure)
|
.configure(routes::configure)
|
||||||
.service({
|
.service({
|
||||||
let l = app_config.lock();
|
let l = app_config.lock();
|
||||||
|
646
api/src/model.rs
646
api/src/model.rs
@ -1,646 +0,0 @@
|
|||||||
pub mod api;
|
|
||||||
|
|
||||||
use std::fmt::Formatter;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use derive_more::{Deref, Display, From};
|
|
||||||
use serde::de::{Error, Visitor};
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum TransformError {
|
|
||||||
#[error("Given value is below minimal value")]
|
|
||||||
BelowMinimal,
|
|
||||||
#[error("Given value is not valid day flag")]
|
|
||||||
NotDay,
|
|
||||||
#[error("Given value is not valid email address")]
|
|
||||||
NotEmail,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type RecordId = i32;
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
|
||||||
#[sqlx(rename_all = "snake_case")]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum OrderStatus {
|
|
||||||
#[display(fmt = "Potwierdzone")]
|
|
||||||
Confirmed,
|
|
||||||
#[display(fmt = "Odebrane")]
|
|
||||||
Delivered,
|
|
||||||
#[display(fmt = "Opłacone")]
|
|
||||||
Payed,
|
|
||||||
#[display(fmt = "Anulowane")]
|
|
||||||
Cancelled,
|
|
||||||
#[display(fmt = "Wymaga zwrotu płatności")]
|
|
||||||
RequireRefund,
|
|
||||||
#[display(fmt = "Płatność zwrócona")]
|
|
||||||
Refunded,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize, PartialEq)]
|
|
||||||
#[sqlx(rename_all = "snake_case")]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum Role {
|
|
||||||
#[display(fmt = "Adminitrator")]
|
|
||||||
Admin,
|
|
||||||
#[display(fmt = "Użytkownik")]
|
|
||||||
User,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<&str> for Role {
|
|
||||||
fn eq(&self, other: &&str) -> bool {
|
|
||||||
self.as_str() == *other
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Role {
|
|
||||||
pub fn as_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Role::Admin => "Admin",
|
|
||||||
Role::User => "User",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum QuantityUnit {
|
|
||||||
#[sqlx(rename = "g")]
|
|
||||||
Gram,
|
|
||||||
#[sqlx(rename = "dkg")]
|
|
||||||
Decagram,
|
|
||||||
#[sqlx(rename = "kg")]
|
|
||||||
Kilogram,
|
|
||||||
#[sqlx(rename = "piece")]
|
|
||||||
Piece,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
|
||||||
#[sqlx(rename_all = "snake_case")]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum PaymentMethod {
|
|
||||||
PayU,
|
|
||||||
PaymentOnTheSpot,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
|
||||||
#[sqlx(rename_all = "snake_case")]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum ShoppingCartState {
|
|
||||||
Active,
|
|
||||||
Closed,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize, PartialEq)]
|
|
||||||
#[sqlx(rename_all = "snake_case")]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum Audience {
|
|
||||||
Web,
|
|
||||||
Mobile,
|
|
||||||
Feed,
|
|
||||||
AdminPanel,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<&str> for Audience {
|
|
||||||
fn eq(&self, other: &&str) -> bool {
|
|
||||||
self.as_str() == *other
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Audience {
|
|
||||||
pub fn as_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Audience::Web => "Web",
|
|
||||||
Audience::Mobile => "Mobile",
|
|
||||||
Audience::Feed => "Feed",
|
|
||||||
Audience::AdminPanel => "AdminPanel",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize, PartialEq)]
|
|
||||||
#[sqlx(rename_all = "snake_case")]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum AccountState {
|
|
||||||
Active,
|
|
||||||
Suspended,
|
|
||||||
Banned,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Audience {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Web
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Default, Debug, Copy, Clone, Deref, From)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct Price(NonNegative);
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Default, Debug, Copy, Clone, Deref, From)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct Quantity(NonNegative);
|
|
||||||
|
|
||||||
impl TryFrom<i32> for Quantity {
|
|
||||||
type Error = TransformError;
|
|
||||||
|
|
||||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
|
||||||
Ok(Self(value.try_into()?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Deserialize, Serialize, Debug, Deref, From, Display)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct Login(String);
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Debug, Deref, From, Display)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct Email(String);
|
|
||||||
|
|
||||||
impl FromStr for Email {
|
|
||||||
type Err = TransformError;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
if validator::validate_email(s) {
|
|
||||||
Ok(Self(String::from(s)))
|
|
||||||
} else {
|
|
||||||
Err(TransformError::NotEmail)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> serde::Deserialize<'de> for Email {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct EmailVisitor {}
|
|
||||||
impl<'v> Visitor<'v> for EmailVisitor {
|
|
||||||
type Value = String;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
|
||||||
formatter.write_str("valid e-mail address")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
if validator::validate_email(s) {
|
|
||||||
Ok(String::from(s))
|
|
||||||
} else {
|
|
||||||
Err(E::custom("this is not email address"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Email(deserializer.deserialize_str(EmailVisitor {})?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Default, Debug, Copy, Clone, Deref, Display)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct NonNegative(i32);
|
|
||||||
|
|
||||||
impl TryFrom<i32> for NonNegative {
|
|
||||||
type Error = TransformError;
|
|
||||||
|
|
||||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
|
||||||
if value < 0 {
|
|
||||||
Err(TransformError::BelowMinimal)
|
|
||||||
} else {
|
|
||||||
Ok(Self(value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> serde::Deserialize<'de> for NonNegative {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct NonNegativeVisitor;
|
|
||||||
impl<'v> Visitor<'v> for NonNegativeVisitor {
|
|
||||||
type Value = i32;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
|
||||||
formatter.write_str("value equal or greater than 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
if v >= 0 {
|
|
||||||
Ok(v)
|
|
||||||
} else {
|
|
||||||
Err(E::custom("Value must be equal or greater than 0"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
let v = v
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| E::custom("Value must be equal or greater than 0"))?;
|
|
||||||
if v >= 0 {
|
|
||||||
Ok(v)
|
|
||||||
} else {
|
|
||||||
Err(E::custom("Value must be equal or greater than 0"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
let v = v
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| E::custom("Value must be equal or greater than 0"))?;
|
|
||||||
Ok(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
let v = v
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| E::custom("Value must be equal or greater than 0"))?;
|
|
||||||
Ok(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(NonNegative(
|
|
||||||
deserializer.deserialize_i32(NonNegativeVisitor)?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Display, From)]
|
|
||||||
#[serde(rename_all = "lowercase")]
|
|
||||||
pub enum Day {
|
|
||||||
Monday = 1 << 0,
|
|
||||||
Tuesday = 1 << 1,
|
|
||||||
Wednesday = 1 << 2,
|
|
||||||
Thursday = 1 << 3,
|
|
||||||
Friday = 1 << 4,
|
|
||||||
Saturday = 1 << 5,
|
|
||||||
Sunday = 1 << 6,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<i32> for Day {
|
|
||||||
type Error = TransformError;
|
|
||||||
|
|
||||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
|
||||||
if value == (Day::Monday as i32) {
|
|
||||||
Ok(Day::Monday)
|
|
||||||
} else if value == (Day::Tuesday as i32) {
|
|
||||||
Ok(Day::Tuesday)
|
|
||||||
} else if value == (Day::Wednesday as i32) {
|
|
||||||
Ok(Day::Wednesday)
|
|
||||||
} else if value == (Day::Thursday as i32) {
|
|
||||||
Ok(Day::Thursday)
|
|
||||||
} else if value == (Day::Friday as i32) {
|
|
||||||
Ok(Day::Friday)
|
|
||||||
} else if value == (Day::Saturday as i32) {
|
|
||||||
Ok(Day::Saturday)
|
|
||||||
} else if value == (Day::Sunday as i32) {
|
|
||||||
Ok(Day::Sunday)
|
|
||||||
} else {
|
|
||||||
Err(TransformError::NotDay)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Deref, Debug)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct Days(Vec<Day>);
|
|
||||||
|
|
||||||
impl<'q> ::sqlx::encode::Encode<'q, sqlx::Postgres> for Days
|
|
||||||
where
|
|
||||||
i32: ::sqlx::encode::Encode<'q, sqlx::Postgres>,
|
|
||||||
{
|
|
||||||
fn encode_by_ref(
|
|
||||||
&self,
|
|
||||||
buf: &mut <sqlx::Postgres as ::sqlx::database::HasArguments<'q>>::ArgumentBuffer,
|
|
||||||
) -> ::sqlx::encode::IsNull {
|
|
||||||
let value = self.0.iter().fold(1, |memo, v| memo | *v as i32);
|
|
||||||
|
|
||||||
<i32 as ::sqlx::encode::Encode<sqlx::Postgres>>::encode_by_ref(&value, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> usize {
|
|
||||||
<i32 as ::sqlx::encode::Encode<sqlx::Postgres>>::size_hint(&Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'r> ::sqlx::decode::Decode<'r, sqlx::Postgres> for Days
|
|
||||||
where
|
|
||||||
i32: ::sqlx::decode::Decode<'r, sqlx::Postgres>,
|
|
||||||
{
|
|
||||||
fn decode(
|
|
||||||
value: <sqlx::Postgres as ::sqlx::database::HasValueRef<'r>>::ValueRef,
|
|
||||||
) -> ::std::result::Result<
|
|
||||||
Self,
|
|
||||||
::std::boxed::Box<
|
|
||||||
dyn ::std::error::Error + 'static + ::std::marker::Send + ::std::marker::Sync,
|
|
||||||
>,
|
|
||||||
> {
|
|
||||||
let value = <i32 as ::sqlx::decode::Decode<'r, sqlx::Postgres>>::decode(value)?;
|
|
||||||
Ok(Days(
|
|
||||||
(0..9)
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|n| {
|
|
||||||
eprintln!(
|
|
||||||
"d {} {} {} {:?}",
|
|
||||||
n,
|
|
||||||
1 << n,
|
|
||||||
value & 1 << n,
|
|
||||||
Day::try_from(value & 1 << n).ok()
|
|
||||||
);
|
|
||||||
Day::try_from(value & 1 << n).ok()
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl sqlx::Type<sqlx::Postgres> for Days
|
|
||||||
where
|
|
||||||
i32: ::sqlx::Type<sqlx::Postgres>,
|
|
||||||
{
|
|
||||||
fn type_info() -> <sqlx::Postgres as ::sqlx::Database>::TypeInfo {
|
|
||||||
<i32 as ::sqlx::Type<sqlx::Postgres>>::type_info()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compatible(ty: &<sqlx::Postgres as ::sqlx::Database>::TypeInfo) -> bool {
|
|
||||||
<i32 as ::sqlx::Type<sqlx::Postgres>>::compatible(ty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Debug, Deref, From, Display)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct Password(String);
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Debug, Deref, From, Display)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct PasswordConfirmation(String);
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Debug, Deref, From, Display)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct PassHash(String);
|
|
||||||
|
|
||||||
impl PartialEq<PasswordConfirmation> for Password {
|
|
||||||
fn eq(&self, other: &PasswordConfirmation) -> bool {
|
|
||||||
self.0 == other.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Copy, Clone, Debug, Deref, Display, From)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct AccountId(RecordId);
|
|
||||||
|
|
||||||
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
|
||||||
pub struct FullAccount {
|
|
||||||
pub id: AccountId,
|
|
||||||
pub email: Email,
|
|
||||||
pub login: Login,
|
|
||||||
pub pass_hash: PassHash,
|
|
||||||
pub role: Role,
|
|
||||||
pub customer_id: uuid::Uuid,
|
|
||||||
pub state: AccountState,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
|
||||||
pub struct Account {
|
|
||||||
pub id: AccountId,
|
|
||||||
pub email: Email,
|
|
||||||
pub login: Login,
|
|
||||||
pub role: Role,
|
|
||||||
pub customer_id: uuid::Uuid,
|
|
||||||
pub state: AccountState,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<FullAccount> for Account {
|
|
||||||
fn from(
|
|
||||||
FullAccount {
|
|
||||||
id,
|
|
||||||
email,
|
|
||||||
login,
|
|
||||||
pass_hash: _,
|
|
||||||
role,
|
|
||||||
customer_id,
|
|
||||||
state,
|
|
||||||
}: FullAccount,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
id,
|
|
||||||
email,
|
|
||||||
login,
|
|
||||||
role,
|
|
||||||
customer_id,
|
|
||||||
state,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(
|
|
||||||
sqlx::Type,
|
|
||||||
Serialize,
|
|
||||||
Deserialize,
|
|
||||||
Debug,
|
|
||||||
Copy,
|
|
||||||
Clone,
|
|
||||||
PartialEq,
|
|
||||||
Eq,
|
|
||||||
Hash,
|
|
||||||
Deref,
|
|
||||||
Display,
|
|
||||||
From,
|
|
||||||
)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct ProductId(RecordId);
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct ProductName(String);
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct ProductShortDesc(String);
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct ProductLongDesc(String);
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct ProductCategory(String);
|
|
||||||
|
|
||||||
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
|
||||||
pub struct Product {
|
|
||||||
pub id: ProductId,
|
|
||||||
pub name: ProductName,
|
|
||||||
pub short_description: ProductShortDesc,
|
|
||||||
pub long_description: ProductLongDesc,
|
|
||||||
pub category: Option<ProductCategory>,
|
|
||||||
pub price: Price,
|
|
||||||
pub deliver_days_flag: Days,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct StockId(pub RecordId);
|
|
||||||
|
|
||||||
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
|
||||||
pub struct Stock {
|
|
||||||
pub id: StockId,
|
|
||||||
pub product_id: ProductId,
|
|
||||||
pub quantity: Quantity,
|
|
||||||
pub quantity_unit: QuantityUnit,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Display, Deref)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct AccountOrderId(RecordId);
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Clone, Debug, PartialEq, Display, Deref)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct OrderId(String);
|
|
||||||
|
|
||||||
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
|
||||||
pub struct AccountOrder {
|
|
||||||
pub id: AccountOrderId,
|
|
||||||
pub buyer_id: AccountId,
|
|
||||||
pub status: OrderStatus,
|
|
||||||
pub order_id: Option<OrderId>,
|
|
||||||
pub order_ext_id: uuid::Uuid,
|
|
||||||
pub service_order_id: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
|
||||||
pub struct PublicAccountOrder {
|
|
||||||
pub id: AccountOrderId,
|
|
||||||
pub buyer_id: AccountId,
|
|
||||||
pub status: OrderStatus,
|
|
||||||
pub order_id: Option<OrderId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<AccountOrder> for PublicAccountOrder {
|
|
||||||
fn from(
|
|
||||||
AccountOrder {
|
|
||||||
id,
|
|
||||||
buyer_id,
|
|
||||||
status,
|
|
||||||
order_id,
|
|
||||||
order_ext_id: _,
|
|
||||||
service_order_id: _,
|
|
||||||
}: AccountOrder,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
id,
|
|
||||||
buyer_id,
|
|
||||||
status,
|
|
||||||
order_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Copy, Clone, Debug, Deref)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct OrderItemId(pub RecordId);
|
|
||||||
|
|
||||||
#[derive(sqlx::FromRow, Serialize, Deserialize, Debug)]
|
|
||||||
pub struct OrderItem {
|
|
||||||
pub id: OrderItemId,
|
|
||||||
pub product_id: ProductId,
|
|
||||||
pub order_id: AccountOrderId,
|
|
||||||
pub quantity: Quantity,
|
|
||||||
pub quantity_unit: QuantityUnit,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Copy, Clone, Debug, Deref, Display)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct ShoppingCartId(pub RecordId);
|
|
||||||
|
|
||||||
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
|
||||||
pub struct ShoppingCart {
|
|
||||||
pub id: ShoppingCartId,
|
|
||||||
pub buyer_id: AccountId,
|
|
||||||
pub payment_method: PaymentMethod,
|
|
||||||
pub state: ShoppingCartState,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Copy, Clone, Debug, Deref, Display)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct ShoppingCartItemId(RecordId);
|
|
||||||
|
|
||||||
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
|
||||||
pub struct ShoppingCartItem {
|
|
||||||
pub id: ShoppingCartId,
|
|
||||||
pub product_id: ProductId,
|
|
||||||
pub shopping_cart_id: ShoppingCartId,
|
|
||||||
pub quantity: Quantity,
|
|
||||||
pub quantity_unit: QuantityUnit,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ShoppingCartItem {
|
|
||||||
pub fn quantity(&self) -> Quantity {
|
|
||||||
self.quantity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Copy, Clone, Deref, Display, Debug)]
|
|
||||||
#[sqlx(transparent)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct TokenId(RecordId);
|
|
||||||
|
|
||||||
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
|
||||||
pub struct Token {
|
|
||||||
pub id: TokenId,
|
|
||||||
pub customer_id: uuid::Uuid,
|
|
||||||
pub role: Role,
|
|
||||||
/// iss (issuer): Issuer of the JWT
|
|
||||||
pub issuer: String,
|
|
||||||
/// sub (subject): Subject of the JWT (the user)
|
|
||||||
pub subject: i32,
|
|
||||||
/// aud (audience): Recipient for which the JWT is intended
|
|
||||||
pub audience: Audience,
|
|
||||||
/// exp (expiration time): Time after which the JWT expires
|
|
||||||
pub expiration_time: chrono::NaiveDateTime,
|
|
||||||
/// nbt (not before time): Time before which the JWT must not be accepted
|
|
||||||
/// for processing
|
|
||||||
pub not_before_time: chrono::NaiveDateTime,
|
|
||||||
/// iat (issued at time): Time at which the JWT was issued; can be used to
|
|
||||||
/// determine age of the JWT,
|
|
||||||
pub issued_at_time: chrono::NaiveDateTime,
|
|
||||||
/// jti (JWT ID): Unique identifier; can be used to prevent the JWT from
|
|
||||||
/// being replayed (allows a token to be used only once)
|
|
||||||
pub jwt_id: uuid::Uuid,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(sqlx::Type, Serialize, Deserialize, Debug, Deref, Display, From)]
|
|
||||||
pub struct TokenString(String);
|
|
@ -1,126 +0,0 @@
|
|||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use crate::model;
|
|
||||||
use crate::model::{AccountId, AccountOrderId, OrderId, OrderItem, OrderStatus};
|
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct AccountOrders(pub Vec<AccountOrder>);
|
|
||||||
|
|
||||||
impl From<(Vec<model::AccountOrder>, Vec<model::OrderItem>)> for AccountOrders {
|
|
||||||
fn from((orders, mut items): (Vec<model::AccountOrder>, Vec<model::OrderItem>)) -> Self {
|
|
||||||
Self(
|
|
||||||
orders
|
|
||||||
.into_iter()
|
|
||||||
.map(
|
|
||||||
|model::AccountOrder {
|
|
||||||
id,
|
|
||||||
buyer_id,
|
|
||||||
status,
|
|
||||||
order_id,
|
|
||||||
order_ext_id: _,
|
|
||||||
service_order_id: _,
|
|
||||||
}| {
|
|
||||||
AccountOrder {
|
|
||||||
id,
|
|
||||||
buyer_id,
|
|
||||||
status,
|
|
||||||
order_id,
|
|
||||||
items: items.drain_filter(|item| item.order_id == id).collect(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(model::AccountOrder, Vec<model::OrderItem>)> for AccountOrder {
|
|
||||||
fn from(
|
|
||||||
(
|
|
||||||
model::AccountOrder {
|
|
||||||
id,
|
|
||||||
buyer_id,
|
|
||||||
status,
|
|
||||||
order_id,
|
|
||||||
order_ext_id: _,
|
|
||||||
service_order_id: _,
|
|
||||||
},
|
|
||||||
mut items,
|
|
||||||
): (model::AccountOrder, Vec<model::OrderItem>),
|
|
||||||
) -> Self {
|
|
||||||
AccountOrder {
|
|
||||||
id,
|
|
||||||
buyer_id,
|
|
||||||
status,
|
|
||||||
order_id,
|
|
||||||
items: items.drain_filter(|item| item.order_id == id).collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
|
||||||
pub struct AccountOrder {
|
|
||||||
pub id: AccountOrderId,
|
|
||||||
pub buyer_id: AccountId,
|
|
||||||
pub status: OrderStatus,
|
|
||||||
pub order_id: Option<OrderId>,
|
|
||||||
pub items: Vec<OrderItem>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
|
||||||
pub struct ShoppingCartItem {
|
|
||||||
pub id: model::ShoppingCartId,
|
|
||||||
pub product_id: model::ProductId,
|
|
||||||
pub shopping_cart_id: model::ShoppingCartId,
|
|
||||||
pub quantity: model::Quantity,
|
|
||||||
pub quantity_unit: model::QuantityUnit,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
|
||||||
pub struct ShoppingCart {
|
|
||||||
pub id: model::ShoppingCartId,
|
|
||||||
pub buyer_id: AccountId,
|
|
||||||
pub payment_method: model::PaymentMethod,
|
|
||||||
pub state: model::ShoppingCartState,
|
|
||||||
pub items: Vec<ShoppingCartItem>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(model::ShoppingCart, Vec<model::ShoppingCartItem>)> for ShoppingCart {
|
|
||||||
fn from(
|
|
||||||
(
|
|
||||||
model::ShoppingCart {
|
|
||||||
id,
|
|
||||||
buyer_id,
|
|
||||||
payment_method,
|
|
||||||
state,
|
|
||||||
},
|
|
||||||
items,
|
|
||||||
): (model::ShoppingCart, Vec<model::ShoppingCartItem>),
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
id,
|
|
||||||
buyer_id,
|
|
||||||
payment_method,
|
|
||||||
state,
|
|
||||||
items: items
|
|
||||||
.into_iter()
|
|
||||||
.map(
|
|
||||||
|model::ShoppingCartItem {
|
|
||||||
id,
|
|
||||||
product_id,
|
|
||||||
shopping_cart_id,
|
|
||||||
quantity,
|
|
||||||
quantity_unit,
|
|
||||||
}| ShoppingCartItem {
|
|
||||||
id,
|
|
||||||
product_id,
|
|
||||||
shopping_cart_id,
|
|
||||||
quantity,
|
|
||||||
quantity_unit,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +1,111 @@
|
|||||||
use actix_web::web::ServiceConfig;
|
use actix::Addr;
|
||||||
|
use actix_multipart::Multipart;
|
||||||
|
use actix_web::web::{Data, ServiceConfig};
|
||||||
use actix_web::{post, HttpResponse};
|
use actix_web::{post, HttpResponse};
|
||||||
|
use database_manager::{query_db, Database};
|
||||||
|
use fs_manager::FsManager;
|
||||||
|
use futures_util::StreamExt;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum UploadError {
|
||||||
|
#[error("Uploaded file name is invalid")]
|
||||||
|
InvalidName,
|
||||||
|
#[error("Write to disk failed")]
|
||||||
|
FileStreamBroken,
|
||||||
|
#[error("Failed to save in database")]
|
||||||
|
DbSave,
|
||||||
|
}
|
||||||
|
|
||||||
#[post("/product-image")]
|
#[post("/product-image")]
|
||||||
async fn upload_product_image() -> HttpResponse {
|
async fn upload_product_image(
|
||||||
|
mut payload: Multipart,
|
||||||
|
fs: Data<Addr<FsManager>>,
|
||||||
|
db: Data<Addr<Database>>,
|
||||||
|
) -> HttpResponse {
|
||||||
|
let mut name = None;
|
||||||
|
while let Some(Ok(mut field)) = payload.next().await {
|
||||||
|
let field_name = field.name();
|
||||||
|
match field_name {
|
||||||
|
"name" => {
|
||||||
|
if name.is_some() {
|
||||||
|
return HttpResponse::BadRequest().finish();
|
||||||
|
}
|
||||||
|
let mut value = String::with_capacity(300);
|
||||||
|
while let Some(Ok(bytes)) = field.next().await {
|
||||||
|
if let Ok(s) = std::str::from_utf8(&bytes) {
|
||||||
|
value.push_str(s);
|
||||||
|
} else {
|
||||||
|
return HttpResponse::BadRequest().finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name = Some(value);
|
||||||
|
}
|
||||||
|
"photo" => {
|
||||||
|
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
||||||
|
let msg = fs_manager::WriteFile {
|
||||||
|
file_name: match name.take() {
|
||||||
|
Some(name) => name,
|
||||||
|
_ => return HttpResponse::BadRequest().finish(),
|
||||||
|
},
|
||||||
|
stream: rx,
|
||||||
|
};
|
||||||
|
let read = async {
|
||||||
|
while let Some(Ok(data)) = field.next().await {
|
||||||
|
for b in data {
|
||||||
|
if let Err(e) = tx.send(b) {
|
||||||
|
log::error!("{e:?}");
|
||||||
|
return Err(UploadError::InvalidName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
let write = async {
|
||||||
|
let fs_manager::WriteResult {
|
||||||
|
local_path,
|
||||||
|
file_name,
|
||||||
|
} = match fs.send(msg).await {
|
||||||
|
Ok(Ok(file_name)) => file_name,
|
||||||
|
Ok(Err(e)) => {
|
||||||
|
log::error!("{e}");
|
||||||
|
return Err(UploadError::FileStreamBroken);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{e}");
|
||||||
|
return Err(UploadError::FileStreamBroken);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
query_db!(
|
||||||
|
db,
|
||||||
|
database_manager::CreatePhoto {
|
||||||
|
local_path,
|
||||||
|
file_name
|
||||||
|
},
|
||||||
|
UploadError::DbSave
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
match tokio::join!(read, write) {
|
||||||
|
(Ok(_), Ok(_)) => {}
|
||||||
|
(Ok(_), Err(e)) => {
|
||||||
|
log::error!("Write error. {e}");
|
||||||
|
return HttpResponse::BadRequest().finish();
|
||||||
|
}
|
||||||
|
(Err(e), Ok(_)) => {
|
||||||
|
log::error!("Read error. {e:?}");
|
||||||
|
return HttpResponse::BadRequest().finish();
|
||||||
|
}
|
||||||
|
(Err(read), Err(write)) => {
|
||||||
|
log::error!("Read error. {read:?}");
|
||||||
|
log::error!("Write error. {write:?}");
|
||||||
|
return HttpResponse::BadRequest().finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
HttpResponse::NotImplemented().finish()
|
HttpResponse::NotImplemented().finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
db-seed/Cargo.toml
Normal file
21
db-seed/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
name = "db-seed"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
model = { path = "../shared/model", version = "0.1", features = ["db", "dummy"] }
|
||||||
|
config = { path = "../shared/config" }
|
||||||
|
database_manager = { path = "../actors/database_manager", features = ["dummy"] }
|
||||||
|
|
||||||
|
actix = { version = "0.13", features = [] }
|
||||||
|
actix-rt = { version = "2.7", features = [] }
|
||||||
|
actix-web = { version = "4.0", features = [] }
|
||||||
|
|
||||||
|
fake = { version = "2.4.3", features = ["derive", "chrono", "http"] }
|
||||||
|
rand = { version = "0.8.5" }
|
||||||
|
|
||||||
|
dotenv = { version = "0.15", features = [] }
|
||||||
|
|
||||||
|
log = { version = "0.4", features = [] }
|
||||||
|
pretty_env_logger = { version = "0.4", features = [] }
|
37
db-seed/src/main.rs
Normal file
37
db-seed/src/main.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use actix::Actor;
|
||||||
|
use config::{AppConfig, UpdateConfig};
|
||||||
|
use fake::{Fake, Faker};
|
||||||
|
|
||||||
|
pub struct Opts;
|
||||||
|
impl UpdateConfig for Opts {
|
||||||
|
fn update_config(&self, _config: &mut AppConfig) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_web::main]
|
||||||
|
async fn main() {
|
||||||
|
dotenv::dotenv().ok();
|
||||||
|
std::env::set_var("RUST_LOG", "DEBUG");
|
||||||
|
pretty_env_logger::init();
|
||||||
|
|
||||||
|
let config = config::default_load(&Opts);
|
||||||
|
let db = database_manager::Database::build(config)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.start();
|
||||||
|
|
||||||
|
let mut users = Vec::with_capacity(10);
|
||||||
|
for _ in 0..10 {
|
||||||
|
match db
|
||||||
|
.send(Faker.fake::<database_manager::CreateAccount>())
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(Ok(user)) => users.push(user),
|
||||||
|
Ok(Err(e)) => {
|
||||||
|
log::error!("{e}")
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{e}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
migrations/20220506130226_rename_photos_column.sql
Normal file
2
migrations/20220506130226_rename_photos_column.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE photos
|
||||||
|
RENAME COLUMN hashed_path TO file_name;
|
@ -5,6 +5,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
db = ["sqlx", "sqlx-core"]
|
db = ["sqlx", "sqlx-core"]
|
||||||
|
dummy = ["fake", "rand"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0.137" }
|
serde = { version = "1.0.137" }
|
||||||
@ -20,3 +21,6 @@ derive_more = { version = "0.99.17" }
|
|||||||
thiserror = { version = "1.0.31" }
|
thiserror = { version = "1.0.31" }
|
||||||
|
|
||||||
validator = { version = "0.15.0" }
|
validator = { version = "0.15.0" }
|
||||||
|
|
||||||
|
fake = { version = "2.4.3", features = ["derive", "chrono", "http", "uuid"], optional = true }
|
||||||
|
rand = { version = "0.8.5", optional = true }
|
||||||
|
@ -6,6 +6,8 @@ use std::fmt::Formatter;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use derive_more::{Deref, Display, From};
|
use derive_more::{Deref, Display, From};
|
||||||
|
#[cfg(feature = "dummy")]
|
||||||
|
use fake::Fake;
|
||||||
use serde::de::{Error, Visitor};
|
use serde::de::{Error, Visitor};
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
|
|
||||||
@ -21,6 +23,7 @@ pub enum TransformError {
|
|||||||
|
|
||||||
pub type RecordId = i32;
|
pub type RecordId = i32;
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
||||||
@ -40,6 +43,7 @@ pub enum OrderStatus {
|
|||||||
Refunded,
|
Refunded,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize, PartialEq)]
|
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize, PartialEq)]
|
||||||
@ -66,6 +70,7 @@ impl Role {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
@ -80,6 +85,7 @@ pub enum QuantityUnit {
|
|||||||
Piece,
|
Piece,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
||||||
@ -89,6 +95,7 @@ pub enum PaymentMethod {
|
|||||||
PaymentOnTheSpot,
|
PaymentOnTheSpot,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
||||||
@ -98,6 +105,7 @@ pub enum ShoppingCartState {
|
|||||||
Closed,
|
Closed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize, PartialEq)]
|
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize, PartialEq)]
|
||||||
@ -126,6 +134,7 @@ impl Audience {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize, PartialEq)]
|
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize, PartialEq)]
|
||||||
@ -142,12 +151,14 @@ impl Default for Audience {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Deref, From)]
|
#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Deref, From)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct Price(NonNegative);
|
pub struct Price(NonNegative);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Deref, From)]
|
#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Deref, From)]
|
||||||
@ -162,12 +173,16 @@ impl TryFrom<i32> for Quantity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
|
#[cfg_attr(feature = "dummy", dummy("fake::faker::internet::en::Username"))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Deserialize, Serialize, Debug, Deref, From, Display)]
|
#[derive(Deserialize, Serialize, Debug, Deref, From, Display)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct Login(String);
|
pub struct Login(String);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
|
#[cfg_attr(feature = "dummy", dummy("fake::faker::internet::en::FreeEmail"))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Debug, Deref, From, Display)]
|
#[derive(Serialize, Debug, Deref, From, Display)]
|
||||||
@ -215,6 +230,7 @@ impl<'de> serde::Deserialize<'de> for Email {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Default, Debug, Copy, Clone, Deref, Display)]
|
#[derive(Serialize, Default, Debug, Copy, Clone, Deref, Display)]
|
||||||
@ -298,6 +314,7 @@ impl<'de> serde::Deserialize<'de> for NonNegative {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Display, From)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum Day {
|
pub enum Day {
|
||||||
@ -334,6 +351,7 @@ impl TryFrom<i32> for Day {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[derive(Serialize, Deserialize, Deref, Debug)]
|
#[derive(Serialize, Deserialize, Deref, Debug)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct Days(Vec<Day>);
|
pub struct Days(Vec<Day>);
|
||||||
@ -403,18 +421,21 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Deref, From, Display)]
|
#[derive(Serialize, Deserialize, Debug, Deref, From, Display)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct Password(String);
|
pub struct Password(String);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Deref, From, Display)]
|
#[derive(Serialize, Deserialize, Debug, Deref, From, Display)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct PasswordConfirmation(String);
|
pub struct PasswordConfirmation(String);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Deref, From, Display)]
|
#[derive(Serialize, Deserialize, Debug, Deref, From, Display)]
|
||||||
@ -427,12 +448,14 @@ impl PartialEq<PasswordConfirmation> for Password {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Deref, Display, From)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct AccountId(RecordId);
|
pub struct AccountId(RecordId);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct FullAccount {
|
pub struct FullAccount {
|
||||||
@ -445,6 +468,7 @@ pub struct FullAccount {
|
|||||||
pub state: AccountState,
|
pub state: AccountState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Account {
|
pub struct Account {
|
||||||
@ -479,36 +503,42 @@ impl From<FullAccount> for Account {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash, Deref, Display, From)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct ProductId(RecordId);
|
pub struct ProductId(RecordId);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct ProductName(String);
|
pub struct ProductName(String);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct ProductShortDesc(String);
|
pub struct ProductShortDesc(String);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct ProductLongDesc(String);
|
pub struct ProductLongDesc(String);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct ProductCategory(String);
|
pub struct ProductCategory(String);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Product {
|
pub struct Product {
|
||||||
@ -521,12 +551,14 @@ pub struct Product {
|
|||||||
pub deliver_days_flag: Days,
|
pub deliver_days_flag: Days,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct StockId(pub RecordId);
|
pub struct StockId(pub RecordId);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Stock {
|
pub struct Stock {
|
||||||
@ -536,18 +568,21 @@ pub struct Stock {
|
|||||||
pub quantity_unit: QuantityUnit,
|
pub quantity_unit: QuantityUnit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Display, Deref)]
|
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Display, Deref)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct AccountOrderId(RecordId);
|
pub struct AccountOrderId(RecordId);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Display, Deref)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Display, Deref)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct OrderId(String);
|
pub struct OrderId(String);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct AccountOrder {
|
pub struct AccountOrder {
|
||||||
@ -559,6 +594,7 @@ pub struct AccountOrder {
|
|||||||
pub service_order_id: Option<String>,
|
pub service_order_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct PublicAccountOrder {
|
pub struct PublicAccountOrder {
|
||||||
@ -588,11 +624,13 @@ impl From<AccountOrder> for PublicAccountOrder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Deref)]
|
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Deref)]
|
||||||
pub struct OrderItemId(pub RecordId);
|
pub struct OrderItemId(pub RecordId);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct OrderItem {
|
pub struct OrderItem {
|
||||||
@ -603,12 +641,14 @@ pub struct OrderItem {
|
|||||||
pub quantity_unit: QuantityUnit,
|
pub quantity_unit: QuantityUnit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Deref, Display)]
|
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Deref, Display)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct ShoppingCartId(pub RecordId);
|
pub struct ShoppingCartId(pub RecordId);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct ShoppingCart {
|
pub struct ShoppingCart {
|
||||||
@ -618,6 +658,7 @@ pub struct ShoppingCart {
|
|||||||
pub state: ShoppingCartState,
|
pub state: ShoppingCartState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Deref, Display)]
|
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Deref, Display)]
|
||||||
@ -640,12 +681,14 @@ impl ShoppingCartItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone, Deref, Display, Debug)]
|
#[derive(Serialize, Deserialize, Copy, Clone, Deref, Display, Debug)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct TokenId(RecordId);
|
pub struct TokenId(RecordId);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
@ -671,12 +714,50 @@ pub struct Token {
|
|||||||
pub jwt_id: uuid::Uuid,
|
pub jwt_id: uuid::Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Deref, Display, From)]
|
||||||
pub struct TokenString(String);
|
pub struct TokenString(String);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Deref, Display, From)]
|
||||||
|
pub struct LocalPath(String);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Deref, Display, From)]
|
||||||
pub struct FileName(String);
|
pub struct FileName(String);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Deref, Display, From)]
|
||||||
|
pub struct PhotoId(RecordId);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Deref, Display, From)]
|
||||||
|
pub struct ProductPhotoId(RecordId);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct Photo {
|
||||||
|
pub id: PhotoId,
|
||||||
|
pub local_path: LocalPath,
|
||||||
|
pub file_name: FileName,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct ProductPhoto {
|
||||||
|
pub id: ProductPhotoId,
|
||||||
|
pub product_id: ProductId,
|
||||||
|
pub photo_id: PhotoId,
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user