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
|
||||
|
||||
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
|
||||
bazzar.toml
|
||||
/tmp
|
||||
/uploads
|
||||
|
101
Cargo.lock
generated
101
Cargo.lock
generated
@ -616,6 +616,7 @@ dependencies = [
|
||||
"derive_more",
|
||||
"dotenv",
|
||||
"email_manager",
|
||||
"fs_manager",
|
||||
"futures",
|
||||
"futures-util",
|
||||
"gumdrop",
|
||||
@ -1034,6 +1035,41 @@ dependencies = [
|
||||
"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]]
|
||||
name = "dashmap"
|
||||
version = "4.0.2"
|
||||
@ -1058,15 +1094,34 @@ dependencies = [
|
||||
"actix-rt",
|
||||
"chrono",
|
||||
"config",
|
||||
"fake",
|
||||
"log",
|
||||
"model",
|
||||
"pretty_env_logger",
|
||||
"rand",
|
||||
"sqlx",
|
||||
"sqlx-core",
|
||||
"thiserror",
|
||||
"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]]
|
||||
name = "dbg"
|
||||
version = "1.0.4"
|
||||
@ -1147,6 +1202,17 @@ version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
@ -1212,6 +1278,19 @@ version = "2.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
@ -1737,6 +1816,12 @@ dependencies = [
|
||||
"tokio-native-tls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.3"
|
||||
@ -1987,6 +2072,12 @@ dependencies = [
|
||||
"digest 0.10.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md5"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
@ -2095,6 +2186,8 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"derive_more",
|
||||
"fake",
|
||||
"rand",
|
||||
"serde",
|
||||
"sqlx",
|
||||
"sqlx-core",
|
||||
@ -3376,6 +3469,12 @@ dependencies = [
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.1"
|
||||
@ -3922,7 +4021,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"md5",
|
||||
"serde",
|
||||
"sha1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -11,4 +11,5 @@ members = [
|
||||
"actors/search_manager",
|
||||
"actors/token_manager",
|
||||
"actors/fs_manager",
|
||||
"db-seed"
|
||||
]
|
||||
|
@ -3,6 +3,9 @@ name = "database_manager"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
dummy = ["fake", "rand"]
|
||||
|
||||
[dependencies]
|
||||
model = { path = "../../shared/model" }
|
||||
config = { path = "../../shared/config" }
|
||||
@ -20,3 +23,6 @@ chrono = { version = "0.4", features = ["serde"] }
|
||||
|
||||
log = { 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 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,
|
||||
};
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
#[cfg(feature = "dummy")]
|
||||
use fake::Fake;
|
||||
use model::{AccountId, AccountState, Email, FullAccount, Login, PassHash, Role};
|
||||
use sqlx::PgPool;
|
||||
|
||||
use super::Result;
|
||||
use crate::{db_async_handler, Database};
|
||||
use crate::db_async_handler;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
@ -37,10 +39,13 @@ FROM accounts
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<FullAccount>")]
|
||||
pub struct CreateAccount {
|
||||
#[cfg_attr(feature = "dummy", dummy("fake::faker::internet::en::FreeEmail"))]
|
||||
pub email: Email,
|
||||
#[cfg_attr(feature = "dummy", dummy("fake::faker::internet::en::Username"))]
|
||||
pub login: Login,
|
||||
pub pass_hash: PassHash,
|
||||
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)]
|
||||
#[rtype(result = "Result<FullAccount>")]
|
||||
pub struct UpdateAccount {
|
||||
|
@ -1,18 +1,23 @@
|
||||
pub use account_orders::*;
|
||||
pub use accounts::*;
|
||||
use actix::{Actor, Context};
|
||||
use config::SharedAppConfig;
|
||||
pub use order_items::*;
|
||||
pub use products::*;
|
||||
pub use shopping_cart_items::*;
|
||||
pub use shopping_carts::*;
|
||||
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 accounts;
|
||||
pub mod order_items;
|
||||
pub mod photos;
|
||||
pub mod product_photos;
|
||||
pub mod products;
|
||||
pub mod shopping_cart_items;
|
||||
pub mod shopping_carts;
|
||||
@ -22,7 +27,7 @@ pub mod tokens;
|
||||
#[macro_export]
|
||||
macro_rules! db_async_handler {
|
||||
($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>>;
|
||||
|
||||
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>>;
|
||||
|
||||
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),
|
||||
#[error("{0}")]
|
||||
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>;
|
||||
|
@ -1,8 +1,10 @@
|
||||
#[cfg(feature = "dummy")]
|
||||
use fake::Fake;
|
||||
use model::*;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use super::Result;
|
||||
use crate::{db_async_handler, Database};
|
||||
use crate::db_async_handler;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
@ -40,6 +42,7 @@ ORDER BY id DESC
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<OrderItem>")]
|
||||
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;
|
||||
#[cfg(feature = "dummy")]
|
||||
use fake::Fake;
|
||||
use model::{
|
||||
Days, Price, Product, ProductCategory, ProductId, ProductLongDesc, ProductName,
|
||||
ProductShortDesc,
|
||||
};
|
||||
|
||||
use super::Result;
|
||||
use crate::Database;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
@ -51,6 +52,7 @@ FROM products
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[derive(Message)]
|
||||
#[rtype(result = "Result<model::Product>")]
|
||||
pub struct CreateProduct {
|
||||
|
@ -2,7 +2,7 @@ use model::*;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use super::Result;
|
||||
use crate::{db_async_handler, Database};
|
||||
use crate::db_async_handler;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
|
@ -2,7 +2,7 @@ use model::*;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use super::Result;
|
||||
use crate::{db_async_handler, Database};
|
||||
use crate::db_async_handler;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
|
@ -2,7 +2,7 @@ use actix::Message;
|
||||
use model::{ProductId, Quantity, QuantityUnit, Stock, StockId};
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{Database, Result};
|
||||
use crate::Result;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
|
@ -2,7 +2,7 @@ use actix::Message;
|
||||
use model::{AccountId, Audience, Token};
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{db_async_handler, Database, Result};
|
||||
use crate::{db_async_handler, Result};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
|
@ -4,7 +4,7 @@ use std::ffi::OsStr;
|
||||
use std::io::Write;
|
||||
|
||||
use config::SharedAppConfig;
|
||||
use model::FileName;
|
||||
use model::{FileName, LocalPath};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! fs_async_handler {
|
||||
@ -37,6 +37,7 @@ pub enum Error {
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FsManager {
|
||||
config: SharedAppConfig,
|
||||
}
|
||||
@ -54,6 +55,9 @@ impl FsManager {
|
||||
async fn validate_fs(config: SharedAppConfig) -> Result<()> {
|
||||
let l = config.lock();
|
||||
let output_path = l.files().local_path();
|
||||
|
||||
tokio::fs::create_dir_all(&output_path).await.ok();
|
||||
|
||||
let test_file = std::path::PathBuf::new()
|
||||
.join(output_path)
|
||||
.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)]
|
||||
#[rtype(result = "Result<FileName>")]
|
||||
#[rtype(result = "Result<WriteResult>")]
|
||||
pub struct WriteFile {
|
||||
pub file_name: String,
|
||||
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 {
|
||||
file_name,
|
||||
mut stream,
|
||||
@ -128,8 +137,10 @@ pub(crate) async fn write_file(msg: WriteFile, config: SharedAppConfig) -> Resul
|
||||
l.files().local_path()
|
||||
};
|
||||
|
||||
let path = std::path::PathBuf::new().join(output_path).join(&file_name);
|
||||
let mut file = match std::fs::File::create(path) {
|
||||
let path = std::path::PathBuf::new()
|
||||
.join(&output_path)
|
||||
.join(&file_name);
|
||||
let mut file = match std::fs::File::create(&path) {
|
||||
Ok(f) => f,
|
||||
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)),
|
||||
}
|
||||
}
|
||||
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" }
|
||||
search_manager = { path = "../actors/search_manager" }
|
||||
token_manager = { path = "../actors/token_manager" }
|
||||
fs_manager = { path = "../actors/fs_manager" }
|
||||
|
||||
actix = { version = "0.13", features = [] }
|
||||
actix-rt = { version = "2.7", features = [] }
|
||||
|
@ -57,6 +57,9 @@ async fn server(opts: ServerOpts) -> Result<()> {
|
||||
.expect("Failed to start payment manager")
|
||||
.start();
|
||||
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 l = app_config.lock();
|
||||
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(payment_manager.clone()))
|
||||
.app_data(Data::new(search_manager.clone()))
|
||||
.app_data(Data::new(fs_manager.clone()))
|
||||
.configure(routes::configure)
|
||||
.service({
|
||||
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 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")]
|
||||
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()
|
||||
}
|
||||
|
||||
|
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]
|
||||
db = ["sqlx", "sqlx-core"]
|
||||
dummy = ["fake", "rand"]
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0.137" }
|
||||
@ -20,3 +21,6 @@ derive_more = { version = "0.99.17" }
|
||||
thiserror = { version = "1.0.31" }
|
||||
|
||||
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 derive_more::{Deref, Display, From};
|
||||
#[cfg(feature = "dummy")]
|
||||
use fake::Fake;
|
||||
use serde::de::{Error, Visitor};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
|
||||
@ -21,6 +23,7 @@ pub enum TransformError {
|
||||
|
||||
pub type RecordId = i32;
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
||||
@ -40,6 +43,7 @@ pub enum OrderStatus {
|
||||
Refunded,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||
#[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))]
|
||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
@ -80,6 +85,7 @@ pub enum QuantityUnit {
|
||||
Piece,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
||||
@ -89,6 +95,7 @@ pub enum PaymentMethod {
|
||||
PaymentOnTheSpot,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
||||
@ -98,6 +105,7 @@ pub enum ShoppingCartState {
|
||||
Closed,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||
#[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", sqlx(rename_all = "snake_case"))]
|
||||
#[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", sqlx(transparent))]
|
||||
#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Deref, From)]
|
||||
#[serde(transparent)]
|
||||
pub struct Price(NonNegative);
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||
#[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", sqlx(transparent))]
|
||||
#[derive(Deserialize, Serialize, Debug, Deref, From, Display)]
|
||||
#[serde(transparent)]
|
||||
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", sqlx(transparent))]
|
||||
#[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", sqlx(transparent))]
|
||||
#[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)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum Day {
|
||||
@ -334,6 +351,7 @@ impl TryFrom<i32> for Day {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[derive(Serialize, Deserialize, Deref, Debug)]
|
||||
#[serde(transparent)]
|
||||
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", sqlx(transparent))]
|
||||
#[derive(Serialize, Deserialize, Debug, Deref, From, Display)]
|
||||
#[serde(transparent)]
|
||||
pub struct Password(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, From, Display)]
|
||||
#[serde(transparent)]
|
||||
pub struct PasswordConfirmation(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, 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", sqlx(transparent))]
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Deref, Display, From)]
|
||||
#[serde(transparent)]
|
||||
pub struct AccountId(RecordId);
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct FullAccount {
|
||||
@ -445,6 +468,7 @@ pub struct FullAccount {
|
||||
pub state: AccountState,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
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", sqlx(transparent))]
|
||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash, Deref, Display, From)]
|
||||
#[serde(transparent)]
|
||||
pub struct ProductId(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, Clone, Deref, Display, From)]
|
||||
#[serde(transparent)]
|
||||
pub struct ProductName(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, Clone, Deref, Display, From)]
|
||||
#[serde(transparent)]
|
||||
pub struct ProductShortDesc(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, Clone, Deref, Display, From)]
|
||||
#[serde(transparent)]
|
||||
pub struct ProductLongDesc(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, Clone, Deref, Display, From)]
|
||||
#[serde(transparent)]
|
||||
pub struct ProductCategory(String);
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Product {
|
||||
@ -521,12 +551,14 @@ pub struct Product {
|
||||
pub deliver_days_flag: Days,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct StockId(pub RecordId);
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Stock {
|
||||
@ -536,18 +568,21 @@ pub struct Stock {
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Display, Deref)]
|
||||
#[serde(transparent)]
|
||||
pub struct AccountOrderId(RecordId);
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Display, Deref)]
|
||||
#[serde(transparent)]
|
||||
pub struct OrderId(String);
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AccountOrder {
|
||||
@ -559,6 +594,7 @@ pub struct AccountOrder {
|
||||
pub service_order_id: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
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", sqlx(transparent))]
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Deref)]
|
||||
pub struct OrderItemId(pub RecordId);
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct OrderItem {
|
||||
@ -603,12 +641,14 @@ pub struct OrderItem {
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Deref, Display)]
|
||||
#[serde(transparent)]
|
||||
pub struct ShoppingCartId(pub RecordId);
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ShoppingCart {
|
||||
@ -618,6 +658,7 @@ pub struct ShoppingCart {
|
||||
pub state: ShoppingCartState,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||
#[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", sqlx(transparent))]
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Deref, Display, Debug)]
|
||||
#[serde(transparent)]
|
||||
pub struct TokenId(RecordId);
|
||||
|
||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Token {
|
||||
@ -671,12 +714,50 @@ pub struct Token {
|
||||
pub jwt_id: uuid::Uuid,
|
||||
}
|
||||
|
||||
#[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 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", sqlx(transparent))]
|
||||
#[derive(Serialize, Deserialize, Debug, Deref, Display, From)]
|
||||
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