Organize code
This commit is contained in:
parent
b5dfb64f89
commit
e7446e7df2
1353
Cargo.lock
generated
1353
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -4,60 +4,61 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix = { version = "0.13.0" }
|
actix = { version = "0.13.0", features = [] }
|
||||||
actix-rt = { version = "2.7.0" }
|
actix-rt = { version = "2.7.0", features = [] }
|
||||||
actix-web = { version = "4.0.1" }
|
actix-web = { version = "4.0.1", features = [] }
|
||||||
actix-web-httpauth = { version = "0.6.0" }
|
actix-web-httpauth = { version = "0.6.0", features = [] }
|
||||||
actix-auth = { version = "0.1.0" }
|
actix-cors = { version = "0.6.1", features = [] }
|
||||||
actix-cors = { version = "0.6.1" }
|
actix-files = { version = "0.6.0", features = [] }
|
||||||
actix-files = { version = "0.6.0" }
|
actix-multipart = { version = "0.4.0", features = [] }
|
||||||
actix-multipart = { version = "0.4.0" }
|
actix-broker = { version = "0.4.2", features = [] }
|
||||||
actix-broker = { version = "0.4.2" }
|
actix-identity = { version = "0.4.0", features = [] }
|
||||||
actix-identity = { version = "0.4.0" }
|
actix-web-opentelemetry = { version = "0.12.0", features = [] }
|
||||||
actix-web-opentelemetry = { version = "0.12.0" }
|
|
||||||
actix-session = { version = "0.6.2", features = ["actix-redis", "redis-actor-session"] }
|
actix-session = { version = "0.6.2", features = ["actix-redis", "redis-actor-session"] }
|
||||||
actix-redis = { version = "0.11.0" }
|
actix-redis = { version = "0.11.0", features = [] }
|
||||||
|
|
||||||
gumdrop = { version = "0.8.1" }
|
gumdrop = { version = "0.8.1", features = [] }
|
||||||
|
|
||||||
tera = { version = "1.15.0" }
|
tera = { version = "1.15.0", features = [] }
|
||||||
|
|
||||||
tracing = { version = "0.1.33" }
|
tracing = { version = "0.1.33", features = [] }
|
||||||
|
|
||||||
uuid = { version = "0.8.2", features = ["serde"] }
|
uuid = { version = "0.8.2", features = ["serde"] }
|
||||||
chrono = { version = "*", features = ["serde"] }
|
chrono = { version = "*", features = ["serde"] }
|
||||||
|
|
||||||
serde = { version = "1.0.136", features = ["derive"] }
|
serde = { version = "1.0.136", features = ["derive"] }
|
||||||
serde_json = { version = "1.0.79" }
|
serde_json = { version = "1.0.79", features = [] }
|
||||||
toml = { version = "0.5.8" }
|
toml = { version = "0.5.8", features = [] }
|
||||||
|
|
||||||
sqlx = { version = "0.5.13", features = ["migrate", "runtime-actix-rustls", "all-types", "postgres"] }
|
sqlx = { version = "0.5.13", features = ["migrate", "runtime-actix-rustls", "all-types", "postgres"] }
|
||||||
sqlx-core = { version = "0.5.13" }
|
sqlx-core = { version = "0.5.13", features = [] }
|
||||||
|
|
||||||
thiserror = { version = "1.0.30" }
|
thiserror = { version = "1.0.30", features = [] }
|
||||||
|
|
||||||
validator = { version = "0.14.0" }
|
validator = { version = "0.14.0", features = [] }
|
||||||
|
|
||||||
log = { version = "0.4.16" }
|
log = { version = "0.4.16", features = [] }
|
||||||
pretty_env_logger = { version = "0.4.0" }
|
pretty_env_logger = { version = "0.4.0", features = [] }
|
||||||
|
|
||||||
dotenv = { version = "0.15.0" }
|
dotenv = { version = "0.15.0", features = [] }
|
||||||
|
|
||||||
derive_more = { version = "0.99.17" }
|
derive_more = { version = "0.99.17", features = [] }
|
||||||
parking_lot = { version = "0.12.0" }
|
parking_lot = { version = "0.12.0", features = [] }
|
||||||
|
|
||||||
password-hash = { version = "0.4.0", features = ["alloc"] }
|
password-hash = { version = "0.4.0", features = ["alloc"] }
|
||||||
argon2 = { version = "0.4.0", features = ["parallel", "password-hash"] }
|
argon2 = { version = "0.4.0", features = ["parallel", "password-hash"] }
|
||||||
rand_core = { version = "0.6", features = ["std"] }
|
rand_core = { version = "0.6", features = ["std"] }
|
||||||
|
|
||||||
tokio = { version = "1.17.0", features = ["full"] }
|
tokio = { version = "1.17.0", features = ["full"] }
|
||||||
futures = { version = "0.3.21" }
|
futures = { version = "0.3.21", features = [] }
|
||||||
futures-util = { version = "0.3.21" }
|
futures-util = { version = "0.3.21", features = [] }
|
||||||
|
|
||||||
jwt = { version = "0.16.0", features = [] }
|
jwt = { version = "0.16.0", features = [] }
|
||||||
hmac = { version = "0.12.1" }
|
hmac = { version = "0.12.1", features = [] }
|
||||||
sha2 = { version = "0.10.2" }
|
sha2 = { version = "0.10.2", features = [] }
|
||||||
|
|
||||||
oauth2 = { version = "4.1.0" }
|
oauth2 = { version = "4.1.0", features = [] }
|
||||||
|
|
||||||
async-trait = { version = "0.1.53" }
|
async-trait = { version = "0.1.53", features = [] }
|
||||||
|
|
||||||
|
jemallocator = { version = "0.3.2", features = [] }
|
||||||
|
@ -1,11 +1,25 @@
|
|||||||
use actix::{Actor, Addr, Context, Message};
|
use actix::{Actor, Addr, Context, Message};
|
||||||
|
|
||||||
use crate::database::Database;
|
use crate::database::{self, Database};
|
||||||
use crate::model::{
|
use crate::model::{
|
||||||
AccountId, ProductId, Quantity, QuantityUnit, ShoppingCartId, ShoppingCartItem,
|
AccountId, ProductId, Quantity, QuantityUnit, ShoppingCartId, ShoppingCartItem,
|
||||||
ShoppingCartItemId, ShoppingCartState,
|
ShoppingCartItemId, ShoppingCartState,
|
||||||
};
|
};
|
||||||
use crate::{cart_async_handler, database};
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! cart_async_handler {
|
||||||
|
($msg: ty, $async: ident, $res: ty) => {
|
||||||
|
impl actix::Handler<$msg> for CartManager {
|
||||||
|
type Result = actix::ResponseActFuture<Self, Result<$res>>;
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
use actix::WrapFuture;
|
||||||
|
let db = self.db.clone();
|
||||||
|
Box::pin(async { $async(msg, db).await }.into_actor(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -18,6 +18,21 @@ pub mod shopping_carts;
|
|||||||
pub mod stocks;
|
pub mod stocks;
|
||||||
pub mod tokens;
|
pub mod tokens;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! db_async_handler {
|
||||||
|
($msg: ty, $async: ident, $res: ty) => {
|
||||||
|
impl actix::Handler<$msg> for Database {
|
||||||
|
type Result = actix::ResponseActFuture<Self, Result<$res>>;
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
use actix::WrapFuture;
|
||||||
|
let pool = self.pool.clone();
|
||||||
|
Box::pin(async { $async(msg, pool).await }.into_actor(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Failed to connect to database. {0:?}")]
|
#[error("Failed to connect to database. {0:?}")]
|
||||||
@ -46,6 +61,8 @@ pub struct Database {
|
|||||||
pool: PgPool,
|
pool: PgPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type SharedDatabase = actix::Addr<Database>;
|
||||||
|
|
||||||
impl Clone for Database {
|
impl Clone for Database {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
pub mod cart_manager;
|
pub mod cart_manager;
|
||||||
pub mod database;
|
pub mod database;
|
||||||
|
pub mod order_manager;
|
||||||
pub mod token_manager;
|
pub mod token_manager;
|
||||||
|
70
api/src/actors/order_manager.rs
Normal file
70
api/src/actors/order_manager.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
use actix::Addr;
|
||||||
|
use actix_web::Message;
|
||||||
|
use sqlx_core::postgres::PgPool;
|
||||||
|
|
||||||
|
use crate::database::{Database, SharedDatabase, self};
|
||||||
|
use crate::model::{AccountOrder, OrderStatus, ShoppingCartId};
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! order_async_handler {
|
||||||
|
($msg: ty, $async: ident, $res: ty) => {
|
||||||
|
impl actix::Handler<$msg> for OrderManager {
|
||||||
|
type Result = actix::ResponseActFuture<Self, Result<$res>>;
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
use actix::WrapFuture;
|
||||||
|
let db = self.db.clone();
|
||||||
|
Box::pin(async { $async(msg, db).await }.into_actor(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {}
|
||||||
|
|
||||||
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
pub struct OrderManager {
|
||||||
|
db: SharedDatabase,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl actix::Actor for OrderManager {
|
||||||
|
type Context = actix::Context<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OrderManager {
|
||||||
|
pub fn new(db: SharedDatabase) -> Self {
|
||||||
|
Self { db }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message, Debug)]
|
||||||
|
#[rtype(result = "Result<AccountOrder>")]
|
||||||
|
pub struct CreateOrder {
|
||||||
|
pub shopping_cart_id: ShoppingCartId,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn create_order(msg: CreateOrder, db: SharedDatabase) -> Result<AccountOrder> {
|
||||||
|
let cart = match db.send(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn change(current: OrderStatus, next: OrderStatus) -> Option<OrderStatus> {
|
||||||
|
match (current, next) {
|
||||||
|
// paying
|
||||||
|
(OrderStatus::Confirmed, OrderStatus::Payed) => Some(OrderStatus::Payed),
|
||||||
|
|
||||||
|
// delivering
|
||||||
|
(OrderStatus::Confirmed | OrderStatus::Payed, OrderStatus::Delivered) => {
|
||||||
|
Some(OrderStatus::Delivered)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cancelling
|
||||||
|
(OrderStatus::Confirmed, OrderStatus::Cancelled) => Some(OrderStatus::Cancelled),
|
||||||
|
(OrderStatus::Payed, OrderStatus::Cancelled) => Some(OrderStatus::RequireRefund),
|
||||||
|
(OrderStatus::Payed, OrderStatus::RequireRefund) => Some(OrderStatus::RequireRefund),
|
||||||
|
(OrderStatus::RequireRefund, OrderStatus::Refunded) => Some(OrderStatus::Refunded),
|
||||||
|
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,23 @@ use sha2::Sha256;
|
|||||||
|
|
||||||
use crate::database::{Database, TokenByJti};
|
use crate::database::{Database, TokenByJti};
|
||||||
use crate::model::{AccountId, Audience, Token, TokenString};
|
use crate::model::{AccountId, Audience, Token, TokenString};
|
||||||
use crate::{database, token_async_handler, Role};
|
use crate::{database, Role};
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! token_async_handler {
|
||||||
|
($msg: ty, $async: ident, $res: ty) => {
|
||||||
|
impl actix::Handler<$msg> for TokenManager {
|
||||||
|
type Result = actix::ResponseActFuture<Self, Result<$res>>;
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
use actix::WrapFuture;
|
||||||
|
let db = self.db.clone();
|
||||||
|
let secret = self.secret.clone();
|
||||||
|
Box::pin(async { $async(msg, db, secret).await }.into_actor(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/*struct Jwt {
|
/*struct Jwt {
|
||||||
/// cti (customer id): Customer uuid identifier used by payment service
|
/// cti (customer id): Customer uuid identifier used by payment service
|
||||||
|
@ -1,21 +1 @@
|
|||||||
use crate::model::OrderStatus;
|
use crate::model::OrderStatus;
|
||||||
|
|
||||||
pub fn change(current: OrderStatus, next: OrderStatus) -> Option<OrderStatus> {
|
|
||||||
match (current, next) {
|
|
||||||
// paying
|
|
||||||
(OrderStatus::Confirmed, OrderStatus::Payed) => Some(OrderStatus::Payed),
|
|
||||||
|
|
||||||
// delivering
|
|
||||||
(OrderStatus::Confirmed | OrderStatus::Payed, OrderStatus::Delivered) => {
|
|
||||||
Some(OrderStatus::Delivered)
|
|
||||||
}
|
|
||||||
|
|
||||||
// cancelling
|
|
||||||
(OrderStatus::Confirmed, OrderStatus::Cancelled) => Some(OrderStatus::Cancelled),
|
|
||||||
(OrderStatus::Payed, OrderStatus::Cancelled) => Some(OrderStatus::RequireRefund),
|
|
||||||
(OrderStatus::Payed, OrderStatus::RequireRefund) => Some(OrderStatus::RequireRefund),
|
|
||||||
(OrderStatus::RequireRefund, OrderStatus::Refunded) => Some(OrderStatus::Refunded),
|
|
||||||
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -9,6 +9,7 @@ use actix_web::middleware::Logger;
|
|||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use actix_web::{App, HttpServer};
|
use actix_web::{App, HttpServer};
|
||||||
use gumdrop::Options;
|
use gumdrop::Options;
|
||||||
|
use jemallocator::Jemalloc;
|
||||||
use password_hash::SaltString;
|
use password_hash::SaltString;
|
||||||
use validator::{validate_email, validate_length};
|
use validator::{validate_email, validate_length};
|
||||||
|
|
||||||
@ -20,7 +21,9 @@ pub mod actors;
|
|||||||
pub mod logic;
|
pub mod logic;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
pub mod routes;
|
pub mod routes;
|
||||||
mod utils;
|
|
||||||
|
#[global_allocator]
|
||||||
|
static GLOBAL: Jemalloc = Jemalloc;
|
||||||
|
|
||||||
trait ResolveDbUrl {
|
trait ResolveDbUrl {
|
||||||
fn own_db_url(&self) -> Option<String>;
|
fn own_db_url(&self) -> Option<String>;
|
||||||
|
@ -178,7 +178,7 @@ async fn register(
|
|||||||
async fn landing() -> Result<HttpResponse> {
|
async fn landing() -> Result<HttpResponse> {
|
||||||
Ok(HttpResponse::NotImplemented()
|
Ok(HttpResponse::NotImplemented()
|
||||||
.append_header(("Content-Type", "text/html"))
|
.append_header(("Content-Type", "text/html"))
|
||||||
.body(include_str!("../../../assets/index.html")))
|
.body(include_str!("../../assets/index.html")))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure(config: &mut ServiceConfig) {
|
pub fn configure(config: &mut ServiceConfig) {
|
@ -20,7 +20,7 @@ pub enum Error {
|
|||||||
AddItem,
|
AddItem,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure(config: &mut ServiceConfig) {
|
pub(crate) fn configure(config: &mut ServiceConfig) {
|
||||||
config.service(
|
config.service(
|
||||||
scope("/api/v1")
|
scope("/api/v1")
|
||||||
.configure(unrestricted::configure)
|
.configure(unrestricted::configure)
|
||||||
|
@ -186,7 +186,9 @@ async fn delete_cart_item(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure(config: &mut ServiceConfig) {
|
pub(crate) async fn create_order() {}
|
||||||
|
|
||||||
|
pub(crate) fn configure(config: &mut ServiceConfig) {
|
||||||
config.service(scope("")
|
config.service(scope("")
|
||||||
.app_data(actix_web_httpauth::extractors::bearer::Config::default()
|
.app_data(actix_web_httpauth::extractors::bearer::Config::default()
|
||||||
.realm("user api")
|
.realm("user api")
|
||||||
|
@ -84,6 +84,6 @@ async fn sign_in(
|
|||||||
Ok(HttpResponse::Created().json(SignInOutput { token: string }))
|
Ok(HttpResponse::Created().json(SignInOutput { token: string }))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure(config: &mut ServiceConfig) {
|
pub(crate) fn configure(config: &mut ServiceConfig) {
|
||||||
config.service(products).service(stocks).service(sign_in);
|
config.service(products).service(stocks).service(sign_in);
|
||||||
}
|
}
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
#[macro_export]
|
|
||||||
macro_rules! db_async_handler {
|
|
||||||
($msg: ty, $async: ident, $res: ty) => {
|
|
||||||
impl actix::Handler<$msg> for Database {
|
|
||||||
type Result = actix::ResponseActFuture<Self, Result<$res>>;
|
|
||||||
|
|
||||||
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
|
||||||
use actix::WrapFuture;
|
|
||||||
let pool = self.pool.clone();
|
|
||||||
Box::pin(async { $async(msg, pool).await }.into_actor(self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! cart_async_handler {
|
|
||||||
($msg: ty, $async: ident, $res: ty) => {
|
|
||||||
impl actix::Handler<$msg> for CartManager {
|
|
||||||
type Result = actix::ResponseActFuture<Self, Result<$res>>;
|
|
||||||
|
|
||||||
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
|
||||||
use actix::WrapFuture;
|
|
||||||
let db = self.db.clone();
|
|
||||||
Box::pin(async { $async(msg, db).await }.into_actor(self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! token_async_handler {
|
|
||||||
($msg: ty, $async: ident, $res: ty) => {
|
|
||||||
impl actix::Handler<$msg> for TokenManager {
|
|
||||||
type Result = actix::ResponseActFuture<Self, Result<$res>>;
|
|
||||||
|
|
||||||
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
|
||||||
use actix::WrapFuture;
|
|
||||||
let db = self.db.clone();
|
|
||||||
let secret = self.secret.clone();
|
|
||||||
Box::pin(async { $async(msg, db, secret).await }.into_actor(self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user