#![feature(drain_filter)] pub mod api; #[cfg(feature = "dummy")] mod dummy; pub mod encrypt; use std::fmt::{Display, Formatter}; use std::ops; use std::ops::BitOr; use std::str::FromStr; use derive_more::{Deref, DerefMut, Display, From}; #[cfg(feature = "dummy")] use fake::Fake; #[cfg(feature = "dummy")] use rand::Rng; use serde::de::{Error, Visitor}; use serde::{Deserialize, Deserializer, Serialize}; pub use crate::encrypt::*; #[derive(Debug, Hash, 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(Clone, Debug, Hash, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub struct Category { pub name: &'static str, pub key: &'static str, pub svg: &'static str, } impl Category { pub const CAMERAS_NAME: &'static str = "Cameras"; pub const CAMERAS_KEY: &'static str = "cameras"; pub const DRUGSTORE_NAME: &'static str = "Drugstore"; pub const DRUGSTORE_KEY: &'static str = "drugstore"; pub const SPEAKERS_NAME: &'static str = "Speakers"; pub const SPEAKERS_KEY: &'static str = "speakers"; pub const PHONES_NAME: &'static str = "Phones"; pub const PHONES_KEY: &'static str = "phones"; pub const SWEETS_NAME: &'static str = "Sweets"; pub const SWEETS_KEY: &'static str = "sweets"; pub const MEMORY_NAME: &'static str = "Memory"; pub const MEMORY_KEY: &'static str = "memory"; pub const PANTS_NAME: &'static str = "Pants"; pub const PANTS_KEY: &'static str = "pants"; pub const CLOTHES_NAME: &'static str = "Clothes"; pub const CLOTHES_KEY: &'static str = "clothes"; pub const PLATES_NAME: &'static str = "Plates"; pub const PLATES_KEY: &'static str = "plates"; } macro_rules! category_svg { ($name: expr) => { concat!("/svg/", $name, ".svg") }; } pub const CATEGORIES: [Category; 9] = [ Category { name: Category::CAMERAS_NAME, key: Category::CAMERAS_KEY, svg: category_svg!("cameras"), }, Category { name: Category::DRUGSTORE_NAME, key: Category::DRUGSTORE_KEY, svg: category_svg!("drugstore"), }, Category { name: Category::SPEAKERS_NAME, key: Category::SPEAKERS_KEY, svg: category_svg!("speakers"), }, Category { name: Category::PHONES_NAME, key: Category::PHONES_KEY, svg: category_svg!("phones"), }, Category { name: Category::SWEETS_NAME, key: Category::SWEETS_KEY, svg: category_svg!("sweets"), }, Category { name: Category::MEMORY_NAME, key: Category::MEMORY_KEY, svg: category_svg!("memory"), }, Category { name: Category::PANTS_NAME, key: Category::PANTS_KEY, svg: category_svg!("pants"), }, Category { name: Category::CLOTHES_NAME, key: Category::CLOTHES_KEY, svg: category_svg!("clothes"), }, Category { name: Category::PLATES_NAME, key: Category::PLATES_KEY, svg: category_svg!("plates"), }, ]; #[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, Hash, PartialEq, Display, Deserialize, Serialize)] #[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, } #[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, Hash, PartialEq, Display, Deserialize, Serialize)] #[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", } } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[derive(Copy, Clone, Debug, PartialEq, Hash, Display, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub enum QuantityUnit { #[cfg_attr(feature = "db", sqlx(rename = "g"))] Gram, #[cfg_attr(feature = "db", sqlx(rename = "dkg"))] Decagram, #[cfg_attr(feature = "db", sqlx(rename = "kg"))] Kilogram, #[cfg_attr(feature = "db", sqlx(rename = "piece"))] Piece, } impl QuantityUnit { pub fn name(self) -> &'static str { match self { Self::Gram => "Gram", Self::Decagram => "Decagram", Self::Kilogram => "Kilogram", Self::Piece => "Piece", } } pub fn short_name(&self) -> &'static str { match self { Self::Gram => "g", Self::Decagram => "dkg", Self::Kilogram => "kg", Self::Piece => "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, Hash, PartialEq, Display, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub enum PaymentMethod { PayU, PaymentOnTheSpot, } impl Default for PaymentMethod { fn default() -> Self { Self::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, Hash, PartialEq, Display, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub enum ShoppingCartState { Active, 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, Hash, Display, Deserialize, Serialize, PartialEq)] #[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", } } } #[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)] #[serde(rename_all = "snake_case")] pub enum AccountState { Active, Suspended, Banned, } impl Default for Audience { fn default() -> Self { Self::Web } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive( Default, Debug, Copy, Clone, Hash, PartialOrd, PartialEq, Serialize, Deserialize, Deref, From, )] #[serde(transparent)] pub struct Price(NonNegative); impl Price { pub fn from_u32(price: u32) -> Self { Self(NonNegative(price as i32)) } } impl ops::Mul for Price { type Output = Self; fn mul(self, rhs: Quantity) -> Self::Output { Self(NonNegative(rhs.0 .0 * self.0 .0)) } } #[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, PartialEq, Copy, Clone, Hash, Deref, From)] #[serde(transparent)] pub struct Quantity(NonNegative); impl Quantity { pub fn from_u32(v: u32) -> Self { Self(NonNegative(v.try_into().unwrap_or_default())) } } impl ops::Add for Quantity { type Output = Self; fn add(self, rhs: Self) -> Self::Output { Self(self.0 + rhs.0) } } impl ops::Sub for Quantity { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { Self(self.0 - rhs.0) } } impl TryFrom for Quantity { type Error = TransformError; fn try_from(value: i32) -> Result { Ok(Self(value.try_into()?)) } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Deref, From, Display)] #[serde(transparent)] pub struct Login(String); impl Login { pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive( Serialize, Debug, Clone, Default, PartialOrd, PartialEq, Deref, DerefMut, From, Display, )] #[serde(transparent)] pub struct Email(String); impl Email { pub fn invalid_empty() -> Self { Self("".into()) } pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive( Serialize, Deserialize, Debug, Clone, Default, PartialOrd, PartialEq, Deref, DerefMut, From, Display, )] #[serde(transparent)] pub struct Phone(String); impl Phone { pub fn invalid_empty() -> Self { Self("".into()) } pub fn new>(s: S) -> Self { Self(s.into()) } } impl FromStr for Email { type Err = TransformError; fn from_str(s: &str) -> Result { if validator::validate_email(s) { Ok(Self(String::from(s))) } else { Err(TransformError::NotEmail) } } } impl<'de> serde::Deserialize<'de> for Email { fn deserialize(deserializer: D) -> Result 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(self, s: &str) -> Result 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 {})?)) } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Default, Debug, PartialEq, PartialOrd, Copy, Clone, Hash, Serialize, Deref, Display)] #[serde(transparent)] pub struct NonNegative(i32); impl ops::Add for NonNegative { type Output = Self; fn add(self, rhs: Self) -> Self::Output { Self(self.0 + rhs.0) } } impl ops::Sub for NonNegative { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { Self((self.0 - rhs.0).max(0)) } } impl TryFrom for NonNegative { type Error = TransformError; fn try_from(value: i32) -> Result { if value < 0 { Err(TransformError::BelowMinimal) } else { Ok(Self(value)) } } } impl<'de> serde::Deserialize<'de> for NonNegative { fn deserialize(deserializer: D) -> Result 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(self, v: i32) -> Result where E: Error, { if v >= 0 { Ok(v) } else { Err(E::custom("Value must be equal or greater than 0")) } } fn visit_i64(self, v: i64) -> Result 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(self, v: u32) -> Result 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(self, v: u64) -> Result 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)?, )) } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[derive( Debug, Copy, Clone, Hash, PartialOrd, PartialEq, Serialize, Deserialize, Display, From, )] #[serde(rename_all = "lowercase")] pub enum Day { Monday = 1, Tuesday = 1 << 1, Wednesday = 1 << 2, Thursday = 1 << 3, Friday = 1 << 4, Saturday = 1 << 5, Sunday = 1 << 6, } impl Day { pub fn name(&self) -> &str { match self { Self::Monday => "Monday", Self::Tuesday => "Tuesday", Self::Wednesday => "Wednesday", Self::Thursday => "Thursday", Self::Friday => "Friday", Self::Saturday => "Saturday", Self::Sunday => "Sunday", } } pub fn short_name(&self) -> &'static str { match self { Self::Monday => "Mon", Self::Tuesday => "Tue", Self::Wednesday => "Wed", Self::Thursday => "Thu", Self::Friday => "Fri", Self::Saturday => "Sat", Self::Sunday => "Sun", } } } impl BitOr for Day { type Output = Days; fn bitor(self, rhs: Self) -> Self::Output { Days(vec![self, rhs]) } } impl TryFrom for Day { type Error = TransformError; fn try_from(value: i32) -> Result { 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) } } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[derive(Hash, Debug, PartialOrd, PartialEq, Serialize, Deserialize)] #[serde(transparent)] pub struct Days(pub Vec); impl BitOr for Days { type Output = Self; fn bitor(mut self, rhs: Day) -> Self::Output { self.0.push(rhs); self } } impl ops::Deref for Days { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } #[cfg(feature = "db")] 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 >::ArgumentBuffer, ) -> ::sqlx::encode::IsNull { let value = self.0.iter().fold(0, |memo, v| memo | *v as i32); >::encode_by_ref(&value, buf) } fn size_hint(&self) -> usize { >::size_hint(&Default::default()) } } #[cfg(feature = "db")] impl<'r> ::sqlx::decode::Decode<'r, sqlx::Postgres> for Days where i32: ::sqlx::decode::Decode<'r, sqlx::Postgres>, { fn decode( value: >::ValueRef, ) -> Result> { let value = >::decode(value)?; Ok(Days( (0..7) .into_iter() .filter_map(|n| Day::try_from(value & 1 << n).ok()) .collect(), )) } } #[cfg(feature = "db")] impl sqlx::Type for Days where i32: ::sqlx::Type, { fn type_info() -> ::TypeInfo { >::type_info() } fn compatible(ty: &::TypeInfo) -> bool { >::compatible(ty) } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Serialize, Deserialize, Debug, Deref, Display)] #[serde(transparent)] pub struct ResetToken(String); impl ResetToken { pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Serialize, Deserialize, Debug, Clone, Deref, From, Display)] #[serde(transparent)] pub struct Password(String); impl Password { pub fn new>(pass: S) -> Self { Self(pass.into()) } } #[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, From, Display)] #[serde(transparent)] pub struct PasswordConfirmation(String); impl PasswordConfirmation { pub fn new>(pass: S) -> Self { Self(pass.into()) } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Serialize, Deserialize, Debug, PartialEq, Deref, From, Display)] #[serde(transparent)] pub struct PassHash(String); impl PassHash { pub fn new>(s: S) -> Self { Self(s.into()) } } impl PartialEq for Password { fn eq(&self, other: &PasswordConfirmation) -> bool { self.0 == other.0 } } #[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, PartialOrd, PartialEq, 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, Debug, PartialEq)] 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, } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::FromRow))] #[derive(Serialize, Deserialize, Debug)] 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 for Account { fn from( FullAccount { id, email, login, pass_hash: _, role, customer_id, state, }: FullAccount, ) -> Self { Self { id, email, login, role, customer_id, state, } } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Deref, From)] #[serde(transparent)] pub struct ProductId(RecordId); impl Display for ProductId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!("{}", self.0)) } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Debug, Clone, Hash, PartialEq, Serialize, Deserialize, Deref, Display, From)] #[serde(transparent)] pub struct ProductName(String); impl ProductName { pub fn new>(s: S) -> Self { Self(s.into()) } pub fn into_inner(self) -> String { self.0 } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Debug, Clone, Hash, PartialEq, Serialize, Deserialize, Deref, Display, From)] #[serde(transparent)] pub struct ProductShortDesc(String); impl ProductShortDesc { pub fn new>(s: S) -> Self { Self(s.into()) } pub fn into_inner(self) -> String { self.0 } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Debug, Clone, Hash, PartialEq, Serialize, Deserialize, Deref, Display, From)] #[serde(transparent)] pub struct ProductLongDesc(String); impl ProductLongDesc { pub fn into_inner(self) -> String { self.0 } } impl ProductLongDesc { pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Debug, Clone, Hash, PartialEq, Serialize, Deserialize, Deref, Display, From)] #[serde(transparent)] pub struct ProductCategory(String); impl ProductCategory { pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::FromRow))] #[derive(Debug, Hash, PartialEq, Serialize, Deserialize)] pub struct Product { pub id: ProductId, pub name: ProductName, pub short_description: ProductShortDesc, pub long_description: ProductLongDesc, pub category: Option, pub price: Price, 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(Debug, PartialEq, Copy, Clone, Serialize, Deserialize)] #[serde(transparent)] pub struct StockId(pub RecordId); #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::FromRow))] #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct Stock { pub id: StockId, pub product_id: ProductId, pub quantity: Quantity, 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(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Display, Deref)] #[serde(transparent)] pub struct OrderAddressId(RecordId); #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Display, Deref)] #[serde(transparent)] pub struct OrderId(RecordId); #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Display, Deref)] #[serde(transparent)] pub struct ExtOrderId(String); impl ExtOrderId { pub fn new>(s: S) -> Self { Self(s.into()) } pub fn into_inner(self) -> String { self.0 } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::FromRow))] #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct Order { pub id: OrderId, pub buyer_id: AccountId, pub status: OrderStatus, pub order_ext_id: uuid::Uuid, pub service_order_id: Option, pub checkout_notes: Option, pub address_id: OrderAddressId, } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::FromRow))] #[derive(Serialize, Deserialize)] pub struct PublicOrder { pub id: OrderId, pub buyer_id: AccountId, pub status: OrderStatus, pub checkout_notes: String, pub address_id: OrderAddressId, } impl From for PublicOrder { fn from( Order { id, buyer_id, status, order_ext_id: _, service_order_id: _, checkout_notes, address_id, }: Order, ) -> Self { Self { id, buyer_id, status, checkout_notes: checkout_notes.unwrap_or_default(), address_id, } } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Deref)] pub struct OrderItemId(pub RecordId); #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::FromRow))] #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct OrderItem { pub id: OrderItemId, pub product_id: ProductId, pub order_id: OrderId, pub quantity: Quantity, 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, PartialEq, 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(Debug, PartialEq, Serialize, Deserialize)] pub struct ShoppingCart { pub id: ShoppingCartId, pub buyer_id: AccountId, pub payment_method: PaymentMethod, pub state: ShoppingCartState, pub checkout_notes: Option, } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(PartialEq, Copy, Clone, Debug, Serialize, Deserialize, Deref, Display)] #[serde(transparent)] pub struct ShoppingCartItemId(RecordId); #[cfg_attr(feature = "db", derive(sqlx::FromRow))] #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct ShoppingCartItem { pub id: ShoppingCartItemId, 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 } } #[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, PartialEq, Deref, Display, Debug)] #[serde(transparent)] pub struct TokenId(RecordId); #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::FromRow))] #[derive(Debug, PartialEq, 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, } impl Token { pub fn account_id(&self) -> AccountId { AccountId(self.subject) } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Deref, Display, From)] pub struct AccessTokenString(String); impl AccessTokenString { pub fn new>(s: S) -> Self { Self(s.into()) } } impl From for AccessTokenString { fn from(r: RefreshTokenString) -> Self { Self(r.0) } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Deref, Display, From)] pub struct RefreshTokenString(String); impl From for RefreshTokenString { fn from(r: AccessTokenString) -> Self { Self(r.0) } } impl RefreshTokenString { pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Debug, Hash, PartialEq, Serialize, Deserialize, Deref, Display, From)] pub struct LocalPath(String); impl LocalPath { pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Debug, Hash, PartialEq, Serialize, Deserialize, Deref, Display, From)] pub struct UniqueName(String); impl UniqueName { pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive(Debug, Hash, PartialEq, Serialize, Deserialize, Deref, Display, From)] pub struct FileName(String); impl FileName { pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive( Debug, Copy, Clone, Hash, PartialOrd, PartialEq, Serialize, Deserialize, 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(Debug, Hash, Copy, Clone, PartialEq, Serialize, Deserialize, Deref, Display, From)] pub struct ProductPhotoId(RecordId); #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::FromRow))] #[derive(Debug, Hash, PartialEq, Serialize, Deserialize)] pub struct Photo { pub id: PhotoId, pub local_path: LocalPath, pub file_name: FileName, pub unique_name: UniqueName, } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::FromRow))] #[derive(Debug, Hash, PartialEq, Serialize, Deserialize)] pub struct ProductLinkedPhoto { pub photo_id: PhotoId, pub local_path: LocalPath, pub file_name: FileName, pub unique_name: UniqueName, pub product_id: ProductId, } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::FromRow))] #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct ProductPhoto { pub id: ProductPhotoId, pub product_id: ProductId, pub photo_id: PhotoId, } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "snake_case")] pub enum ShippingMethod { /// Build-in InPost shipping InPost, /// Shop owner will ship product manually Manual, } #[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, Hash, PartialOrd, PartialEq, Deref, Display, From, )] pub struct AddressId(RecordId); impl AddressId { pub fn new(id: RecordId) -> Self { Self(id) } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive( Serialize, Deserialize, Debug, Clone, Default, PartialOrd, PartialEq, Deref, DerefMut, From, Display, )] #[serde(transparent)] pub struct Name(String); impl Name { pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive( Serialize, Deserialize, Debug, Clone, Default, PartialOrd, PartialEq, Deref, DerefMut, From, Display, )] #[serde(transparent)] pub struct Street(String); impl Street { pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive( Serialize, Deserialize, Debug, Clone, Default, PartialOrd, PartialEq, Deref, DerefMut, From, Display, )] #[serde(transparent)] pub struct City(String); impl City { pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive( Serialize, Deserialize, Debug, Clone, Default, PartialOrd, PartialEq, Deref, DerefMut, From, Display, )] #[serde(transparent)] pub struct Country(String); impl Country { pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] #[derive( Serialize, Deserialize, Debug, Clone, Default, PartialOrd, PartialEq, Deref, DerefMut, From, Display, )] #[serde(transparent)] pub struct Zip(String); impl Zip { pub fn new>(s: S) -> Self { Self(s.into()) } } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::FromRow))] #[derive(Serialize, Deserialize, PartialEq, Debug)] pub struct AccountAddress { pub id: AddressId, pub name: Name, pub email: Email, pub phone: Phone, pub street: Street, pub city: City, pub country: Country, pub zip: Zip, pub account_id: AccountId, pub is_default: bool, } #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::FromRow))] #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct OrderAddress { pub id: OrderAddressId, pub name: Name, pub email: Email, pub street: Street, pub city: City, pub country: Country, pub zip: Zip, pub phone: Phone, }