From 8ec00478faef00447bf09a50fc470f6f18462c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9F=83=E6=8B=89?= Date: Tue, 30 Jul 2024 17:01:54 +0800 Subject: [PATCH] wip: merge repository into model --- Cargo.toml | 6 +- assets/banner.txt | 2 +- build.rs | 7 +- rustfmt.toml | 4 +- src/captcha/recaptcha.rs | 19 ++++- src/captcha/traits.rs | 4 +- src/captcha/turnstile.rs | 19 ++++- src/config/mod.rs | 4 +- src/container/docker.rs | 46 ++++++++--- src/container/k8s.rs | 8 +- src/container/traits.rs | 3 +- src/database/mod.rs | 27 +++++-- src/logger/mod.rs | 15 ++-- src/main.rs | 20 ++++- src/media/mod.rs | 6 +- src/model/category/mod.rs | 43 +++++++++- src/model/challenge/mod.rs | 77 +++++++++++++++++- src/model/game/mod.rs | 60 +++++++++++++- src/model/game_challenge/mod.rs | 68 +++++++++++++++- src/model/game_team/mod.rs | 68 +++++++++++++++- src/model/game_team/request.rs | 5 +- src/model/pod/mod.rs | 125 ++++++++++++++++++++++++++++-- src/model/submission/mod.rs | 112 +++++++++++++++++++++++++- src/model/team/mod.rs | 101 +++++++++++++++++++++++- src/model/user/mod.rs | 94 +++++++++++++++++++++- src/model/user_team/mod.rs | 46 ++++++++++- src/repository/category.rs | 31 -------- src/repository/challenge.rs | 67 ---------------- src/repository/game.rs | 49 ------------ src/repository/game_challenge.rs | 51 ------------ src/repository/game_team.rs | 53 ------------- src/repository/mod.rs | 10 --- src/repository/pod.rs | 79 ------------------- src/repository/submission.rs | 90 --------------------- src/repository/team.rs | 84 -------------------- src/repository/user.rs | 77 ------------------ src/repository/user_team.rs | 39 ---------- src/util/jwt.rs | 11 ++- src/util/math.rs | 3 +- src/util/validate.rs | 6 +- src/web/controller/category.rs | 6 +- src/web/controller/challenge.rs | 29 +++++-- src/web/controller/game.rs | 42 +++++++--- src/web/controller/media.rs | 5 +- src/web/controller/pod.rs | 28 +++++-- src/web/controller/submission.rs | 14 +++- src/web/controller/team.rs | 47 +++++++---- src/web/controller/user.rs | 37 ++++++--- src/web/middleware/auth.rs | 21 ++++- src/web/middleware/frontend.rs | 12 ++- src/web/mod.rs | 14 +++- src/web/router/category.rs | 23 ++++-- src/web/router/challenge.rs | 46 ++++++++--- src/web/router/game.rs | 58 ++++++++++---- src/web/router/pod.rs | 28 +++++-- src/web/router/submission.rs | 23 ++++-- src/web/router/team.rs | 63 +++++++++++---- src/web/router/user.rs | 38 ++++++--- src/web/service/category.rs | 22 ++++-- src/web/service/challenge.rs | 60 +++++++++----- src/web/service/game.rs | 21 +++-- src/web/service/game_challenge.rs | 23 ++++-- src/web/service/game_team.rs | 22 ++++-- src/web/service/pod.rs | 73 ++++++++++++----- src/web/service/submission.rs | 73 ++++++++++++----- src/web/service/team.rs | 26 ++++--- src/web/service/user.rs | 55 +++++++++---- src/web/service/user_team.rs | 21 +++-- 68 files changed, 1621 insertions(+), 948 deletions(-) delete mode 100644 src/repository/category.rs delete mode 100644 src/repository/challenge.rs delete mode 100644 src/repository/game.rs delete mode 100644 src/repository/game_challenge.rs delete mode 100644 src/repository/game_team.rs delete mode 100644 src/repository/mod.rs delete mode 100644 src/repository/pod.rs delete mode 100644 src/repository/submission.rs delete mode 100644 src/repository/team.rs delete mode 100644 src/repository/user.rs delete mode 100644 src/repository/user_team.rs diff --git a/Cargo.toml b/Cargo.toml index 17a44e58..60989cbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ tower-http = { version = "0.5", features = ["cors", "fs", "trace"] } serde = { version = "1.0", features = ["derive"] } tracing = { version = "0.1" } tracing-subscriber = { version = "0.3", features = ["env-filter"] } +tracing-appender = "0.2" uuid = { version = "1.8", features = ["v4", "fast-rng", "macro-diagnostics"] } sea-orm = { version = "0.12", features = [ "sqlx-mysql", @@ -56,7 +57,10 @@ wsrx = { version = "0.2", features = ["server"] } serde_yaml = "0.9.34" kube = { version = "0.93", features = ["runtime", "derive"] } k8s-openapi = { version = "0.22", features = ["latest"] } -reqwest = { version = "0.12", features = ["json", "rustls-tls"], default-features = false } +reqwest = { version = "0.12", features = [ + "json", + "rustls-tls", +], default-features = false } async-trait = { version = "0.1" } ring = { version = "0.17" } rustls = { version = "0.23", features = ["ring"] } diff --git a/assets/banner.txt b/assets/banner.txt index 0afc8ce0..35b28572 100644 --- a/assets/banner.txt +++ b/assets/banner.txt @@ -7,4 +7,4 @@ Commit: {{commit}} Build At: {{build_at}} -GitHub: https://github.com/elabosak233/cloudsdale \ No newline at end of file +GitHub: https://github.com/elabosak233/cloudsdale diff --git a/build.rs b/build.rs index c3bd4407..758f059f 100644 --- a/build.rs +++ b/build.rs @@ -14,5 +14,10 @@ fn main() { .trim() ); - println!("cargo:rustc-env=BUILD_AT={}", chrono::Utc::now().format("%Y-%m-%d %H:%M:%S UTC").to_string()); + println!( + "cargo:rustc-env=BUILD_AT={}", + chrono::Utc::now() + .format("%Y-%m-%d %H:%M:%S UTC") + .to_string() + ); } diff --git a/rustfmt.toml b/rustfmt.toml index 477aa0b4..bea95784 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,6 +1,6 @@ merge_derives = true fn_params_layout = "Compressed" -max_width = 160 +max_width = 100 tab_spaces = 4 reorder_imports = true @@ -9,4 +9,4 @@ reorder_imports = true # condense_wildcard_suffixes = true # imports_granularity = "Crate" # brace_style = "PreferSameLine" -# group_imports = "StdExternalCrate" \ No newline at end of file +# group_imports = "StdExternalCrate" diff --git a/src/captcha/recaptcha.rs b/src/captcha/recaptcha.rs index 3757e145..a8cb4a7c 100644 --- a/src/captcha/recaptcha.rs +++ b/src/captcha/recaptcha.rs @@ -22,8 +22,16 @@ struct RecaptchaRequest { impl ICaptcha for Recaptcha { fn new() -> Self { return Recaptcha { - url: crate::config::get_app_config().captcha.recaptcha.url.clone(), - secret_key: crate::config::get_app_config().captcha.recaptcha.secret_key.clone(), + url: crate::config::get_app_config() + .captcha + .recaptcha + .url + .clone(), + secret_key: crate::config::get_app_config() + .captcha + .recaptcha + .secret_key + .clone(), threshold: crate::config::get_app_config().captcha.recaptcha.threshold, }; } @@ -36,7 +44,12 @@ impl ICaptcha for Recaptcha { }; let client = Client::new(); - let resp = client.post(&self.url).json(&request_body).send().await.unwrap(); + let resp = client + .post(&self.url) + .json(&request_body) + .send() + .await + .unwrap(); let response: serde_json::Value = resp.json().await.unwrap(); diff --git a/src/captcha/traits.rs b/src/captcha/traits.rs index ec90d412..f333ed35 100644 --- a/src/captcha/traits.rs +++ b/src/captcha/traits.rs @@ -1,4 +1,6 @@ pub trait ICaptcha { fn new() -> Self; - fn verify(&self, token: String, client_ip: String) -> impl std::future::Future + Send; + fn verify( + &self, token: String, client_ip: String, + ) -> impl std::future::Future + Send; } diff --git a/src/captcha/turnstile.rs b/src/captcha/turnstile.rs index b282e380..cb4a3071 100644 --- a/src/captcha/turnstile.rs +++ b/src/captcha/turnstile.rs @@ -21,8 +21,16 @@ struct TurnstileRequest { impl ICaptcha for Turnstile { fn new() -> Self { return Turnstile { - url: crate::config::get_app_config().captcha.turnstile.url.clone(), - secret_key: crate::config::get_app_config().captcha.turnstile.secret_key.clone(), + url: crate::config::get_app_config() + .captcha + .turnstile + .url + .clone(), + secret_key: crate::config::get_app_config() + .captcha + .turnstile + .secret_key + .clone(), }; } @@ -34,7 +42,12 @@ impl ICaptcha for Turnstile { }; let client = Client::new(); - let resp = client.post(&self.url).json(&request_body).send().await.unwrap(); + let resp = client + .post(&self.url) + .json(&request_body) + .send() + .await + .unwrap(); let response: serde_json::Value = resp.json().await.unwrap(); diff --git a/src/config/mod.rs b/src/config/mod.rs index fb86a2d0..ea90164e 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -28,7 +28,9 @@ pub async fn init() { let target_path = Path::new("application.yml"); if target_path.exists() { let content = fs::read_to_string("application.yml").await.unwrap(); - APP_CONFIG.set(serde_yaml::from_str(&content).unwrap()).unwrap(); + APP_CONFIG + .set(serde_yaml::from_str(&content).unwrap()) + .unwrap(); } else { error!("Configuration application.yml not found."); process::exit(1); diff --git a/src/container/docker.rs b/src/container/docker.rs index 3649c5dc..eff99929 100644 --- a/src/container/docker.rs +++ b/src/container/docker.rs @@ -1,5 +1,5 @@ use super::traits::Container; -use crate::{database::get_db, repository}; +use crate::{database::get_db, model::pod}; use async_trait::async_trait; use bollard::{ container::{Config, CreateContainerOptions, StartContainerOptions}, @@ -7,7 +7,7 @@ use bollard::{ Docker as DockerClient, }; use core::time; -use sea_orm::EntityTrait; +use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; use std::{collections::HashMap, env, error::Error, process, sync::OnceLock}; use tracing::{error, info}; @@ -22,11 +22,22 @@ async fn daemon() { tokio::spawn(async { let interval = time::Duration::from_secs(10); loop { - let (pods, _) = repository::pod::find(None, None, None, None, None, None, Some(false)).await.unwrap(); + let pods = pod::Entity::find() + .filter(pod::Column::RemovedAt.lte(chrono::Utc::now().timestamp())) + .all(&get_db().await) + .await + .unwrap(); for pod in pods { - let _ = get_docker_client().stop_container(pod.name.clone().as_str(), None).await; - let _ = get_docker_client().remove_container(pod.name.clone().as_str(), None).await; - crate::model::pod::Entity::delete_by_id(pod.id).exec(&get_db().await).await.unwrap(); + let _ = get_docker_client() + .stop_container(pod.name.clone().as_str(), None) + .await; + let _ = get_docker_client() + .remove_container(pod.name.clone().as_str(), None) + .await; + crate::model::pod::Entity::delete_by_id(pod.id) + .exec(&get_db().await) + .await + .unwrap(); info!("Cleaned up expired container: {0}", pod.name); } tokio::time::sleep(interval).await; @@ -63,7 +74,8 @@ impl Container for Docker { } async fn create( - &self, name: String, challenge: crate::model::challenge::Model, injected_flag: crate::model::challenge::Flag, + &self, name: String, challenge: crate::model::challenge::Model, + injected_flag: crate::model::challenge::Flag, ) -> Result, Box> { let port_bindings: HashMap>> = challenge .ports @@ -79,9 +91,17 @@ impl Container for Docker { }) .collect(); - let mut env_bindings: Vec = challenge.envs.into_iter().map(|env| format!("{}:{}", env.key, env.value)).collect(); + let mut env_bindings: Vec = challenge + .envs + .into_iter() + .map(|env| format!("{}:{}", env.key, env.value)) + .collect(); - env_bindings.push(format!("{}:{}", injected_flag.env.unwrap_or("FLAG".to_string()), injected_flag.value)); + env_bindings.push(format!( + "{}:{}", + injected_flag.env.unwrap_or("FLAG".to_string()), + injected_flag.value + )); let cfg = Config { image: challenge.image_name.clone(), @@ -132,7 +152,11 @@ impl Container for Docker { } async fn delete(&self, name: String) { - let _ = get_docker_client().stop_container(name.clone().as_str(), None).await; - let _ = get_docker_client().remove_container(name.clone().as_str(), None).await; + let _ = get_docker_client() + .stop_container(name.clone().as_str(), None) + .await; + let _ = get_docker_client() + .remove_container(name.clone().as_str(), None) + .await; } } diff --git a/src/container/k8s.rs b/src/container/k8s.rs index 203d9d7e..6e9a940f 100644 --- a/src/container/k8s.rs +++ b/src/container/k8s.rs @@ -59,7 +59,10 @@ impl Container for K8s { daemon().await; } Err(e) => { - error!("Failed to create Kubernetes client from custom config: {:?}", e); + error!( + "Failed to create Kubernetes client from custom config: {:?}", + e + ); process::exit(1); } }, @@ -71,7 +74,8 @@ impl Container for K8s { } async fn create( - &self, name: String, challenge: crate::model::challenge::Model, injected_flag: crate::model::challenge::Flag, + &self, name: String, challenge: crate::model::challenge::Model, + injected_flag: crate::model::challenge::Flag, ) -> Result, Box> { let client = get_k8s_client().clone(); let pods: Api = Api::namespaced(client, "default"); diff --git a/src/container/traits.rs b/src/container/traits.rs index 06a1b859..cf773457 100644 --- a/src/container/traits.rs +++ b/src/container/traits.rs @@ -5,7 +5,8 @@ use std::error::Error; pub trait Container: Send + Sync { async fn init(&self); async fn create( - &self, name: String, challenge: crate::model::challenge::Model, injected_flag: crate::model::challenge::Flag, + &self, name: String, challenge: crate::model::challenge::Model, + injected_flag: crate::model::challenge::Flag, ) -> Result, Box>; async fn delete(&self, name: String); } diff --git a/src/database/mod.rs b/src/database/mod.rs index 0bf59554..7436ec46 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -2,7 +2,10 @@ mod migration; use bcrypt::{hash, DEFAULT_COST}; use once_cell::sync::Lazy; -use sea_orm::{ActiveModelTrait, ConnectOptions, Database, DatabaseConnection, EntityTrait, PaginatorTrait, Set}; +use sea_orm::{ + ActiveModelTrait, ConnectOptions, Database, DatabaseConnection, EntityTrait, PaginatorTrait, + Set, +}; use std::{process, time::Duration}; use tokio::sync::RwLock; use tracing::{error, info}; @@ -12,8 +15,16 @@ use crate::config; static DB: Lazy>> = Lazy::new(|| RwLock::new(None)); pub async fn init() { - let url = match crate::config::get_app_config().db.provider.to_lowercase().as_str() { - "sqlite" => format!("sqlite://{}?mode=rwc", crate::config::get_app_config().db.sqlite.path.clone()), + let url = match crate::config::get_app_config() + .db + .provider + .to_lowercase() + .as_str() + { + "sqlite" => format!( + "sqlite://{}?mode=rwc", + crate::config::get_app_config().db.sqlite.path.clone() + ), "mysql" => format!( "mysql://{}:{}@{}:{}/{}", crate::config::get_app_config().db.mysql.username, @@ -63,7 +74,10 @@ pub async fn get_db() -> DatabaseConnection { } pub async fn init_admin() { - let total = crate::model::user::Entity::find().count(&get_db().await).await.unwrap(); + let total = crate::model::user::Entity::find() + .count(&get_db().await) + .await + .unwrap(); if total == 0 { let hashed_password = hash("123456".to_string(), DEFAULT_COST).unwrap(); let user = crate::model::user::ActiveModel { @@ -80,7 +94,10 @@ pub async fn init_admin() { } pub async fn init_category() { - let total = crate::model::category::Entity::find().count(&get_db().await).await.unwrap(); + let total = crate::model::category::Entity::find() + .count(&get_db().await) + .await + .unwrap(); if total == 0 { let default_categories = vec![ crate::model::category::ActiveModel { diff --git a/src/logger/mod.rs b/src/logger/mod.rs index b1617de3..26d063cf 100644 --- a/src/logger/mod.rs +++ b/src/logger/mod.rs @@ -9,16 +9,19 @@ pub fn init() { .add_directive(Level::DEBUG.into()) .add_directive("docker_api=info".parse().unwrap()); - let fmt_layer = tracing_subscriber::fmt::layer().with_target(false).with_filter(filter); + let fmt_layer = tracing_subscriber::fmt::layer() + .with_target(false) + .with_filter(filter); - // let file_layer = tracing_subscriber::fmt::layer() - // .with_ansi(false) - // .with_file(true) - // .with_line_number(true); + let file_appender = tracing_appender::rolling::daily("logs", "cds"); + let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender); + let file_layer = tracing_subscriber::fmt::layer() + .with_ansi(false) + .with_writer(non_blocking); tracing_subscriber::registry() .with(fmt_layer) - // .with(file_layer) + .with(file_layer) .init(); info!("Logger initialized successfully."); diff --git a/src/main.rs b/src/main.rs index 2703555e..b83da4d8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,6 @@ mod logger; mod media; mod model; mod proxy; -mod repository; mod traits; mod util; mod web; @@ -27,6 +26,10 @@ async fn main() { .replace("{{build_at}}", env!("BUILD_AT")) ); + bootstrap().await; +} + +async fn bootstrap() { logger::init(); config::init().await; database::init().await; @@ -35,10 +38,19 @@ async fn main() { info!("{:?}", util::jwt::get_secret().await); - let addr = format!("{}:{}", config::get_app_config().axum.host, config::get_app_config().axum.port); + let addr = format!( + "{}:{}", + config::get_app_config().axum.host, + config::get_app_config().axum.port + ); let listener = tokio::net::TcpListener::bind(&addr).await; - info!("Cloudsdale service has been started at {}. Enjoy your hacking challenges!", &addr); + info!( + "Cloudsdale service has been started at {}. Enjoy your hacking challenges!", + &addr + ); - axum::serve(listener.unwrap(), web::get_app()).await.unwrap(); + axum::serve(listener.unwrap(), web::get_app()) + .await + .unwrap(); } diff --git a/src/media/mod.rs b/src/media/mod.rs index 2c297456..683262e8 100644 --- a/src/media/mod.rs +++ b/src/media/mod.rs @@ -6,7 +6,8 @@ use tokio::{ }; pub async fn get(path: String, filename: String) -> Result, Box> { - let filepath = PathBuf::from(crate::config::consts::path::MEDIA).join(format!("{}/{}", path, filename)); + let filepath = + PathBuf::from(crate::config::consts::path::MEDIA).join(format!("{}/{}", path, filename)); match File::open(&filepath).await { Ok(mut file) => { @@ -43,7 +44,8 @@ pub async fn scan_dir(path: String) -> Result, Box } pub async fn save(path: String, filename: String, data: Vec) -> Result<(), Box> { - let filepath = PathBuf::from(crate::config::consts::path::MEDIA).join(format!("{}/{}", path, filename)); + let filepath = + PathBuf::from(crate::config::consts::path::MEDIA).join(format!("{}/{}", path, filename)); if let Some(parent) = filepath.parent() { if metadata(parent).await.is_err() { create_dir_all(parent).await?; diff --git a/src/model/category/mod.rs b/src/model/category/mod.rs index 8464f91a..f5e1933d 100644 --- a/src/model/category/mod.rs +++ b/src/model/category/mod.rs @@ -1,9 +1,11 @@ pub mod request; use axum::async_trait; -use sea_orm::entity::prelude::*; +use sea_orm::{entity::prelude::*, TryIntoModel}; use serde::{Deserialize, Serialize}; +use crate::database::get_db; + use super::challenge; #[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] @@ -37,3 +39,42 @@ impl Related for Entity { #[async_trait] impl ActiveModelBehavior for ActiveModel {} + +pub async fn find( + id: Option, name: Option, +) -> Result<(Vec, u64), DbErr> { + let mut query = crate::model::category::Entity::find(); + if let Some(id) = id { + query = query.filter(crate::model::category::Column::Id.eq(id)); + } + if let Some(name) = name { + query = query.filter(crate::model::category::Column::Name.eq(name)); + } + let total = query.clone().count(&get_db().await).await?; + let categories = query.all(&get_db().await).await?; + Ok((categories, total)) +} + +pub async fn create( + category: crate::model::category::ActiveModel, +) -> Result { + category.insert(&get_db().await).await?.try_into_model() +} + +pub async fn update( + category: crate::model::category::ActiveModel, +) -> Result { + category.update(&get_db().await).await?.try_into_model() +} + +pub async fn delete(id: i64) -> Result<(), DbErr> { + let result = crate::model::category::Entity::delete_by_id(id) + .exec(&get_db().await) + .await?; + Ok(if result.rows_affected == 0 { + return Err(DbErr::RecordNotFound(format!( + "Category with id {} not found", + id + ))); + }) +} diff --git a/src/model/challenge/mod.rs b/src/model/challenge/mod.rs index 583e1d75..a0ee73cf 100644 --- a/src/model/challenge/mod.rs +++ b/src/model/challenge/mod.rs @@ -2,9 +2,11 @@ pub mod request; pub mod response; use axum::async_trait; -use sea_orm::{entity::prelude::*, FromJsonQueryResult, Set}; +use sea_orm::{entity::prelude::*, FromJsonQueryResult, QuerySelect, Set, TryIntoModel}; use serde::{Deserialize, Serialize}; +use crate::database::get_db; + use super::{category, game, game_challenge, pod, submission}; #[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] @@ -122,3 +124,76 @@ impl ActiveModelBehavior for ActiveModel { return Ok(self); } } + +pub async fn find( + id: Option, title: Option, category_id: Option, is_practicable: Option, + is_dynamic: Option, page: Option, size: Option, +) -> Result<(Vec, u64), DbErr> { + let mut query = crate::model::challenge::Entity::find(); + + if let Some(id) = id { + query = query.filter(crate::model::challenge::Column::Id.eq(id)); + } + + if let Some(title) = title { + query = query.filter(crate::model::challenge::Column::Title.contains(title)); + } + + if let Some(category_id) = category_id { + query = query.filter(crate::model::challenge::Column::CategoryId.eq(category_id)); + } + + if let Some(is_practicable) = is_practicable { + query = query.filter(crate::model::challenge::Column::IsPracticable.eq(is_practicable)); + } + + if let Some(is_dynamic) = is_dynamic { + query = query.filter(crate::model::challenge::Column::IsDynamic.eq(is_dynamic)); + } + + let total = query.clone().count(&get_db().await).await?; + + if let Some(page) = page { + if let Some(size) = size { + let offset = (page - 1) * size; + query = query.offset(offset).limit(size); + } + } + + let challenges = query.all(&get_db().await).await?; + + return Ok((challenges, total)); +} + +pub async fn find_by_ids(ids: Vec) -> Result, DbErr> { + let challenges = crate::model::challenge::Entity::find() + .filter(crate::model::challenge::Column::Id.is_in(ids)) + .all(&get_db().await) + .await?; + + return Ok(challenges); +} + +pub async fn create( + challenge: crate::model::challenge::ActiveModel, +) -> Result { + challenge.insert(&get_db().await).await?.try_into_model() +} + +pub async fn update( + challenge: crate::model::challenge::ActiveModel, +) -> Result { + challenge.update(&get_db().await).await?.try_into_model() +} + +pub async fn delete(id: i64) -> Result<(), DbErr> { + let result = crate::model::challenge::Entity::delete_by_id(id) + .exec(&get_db().await) + .await?; + Ok(if result.rows_affected == 0 { + return Err(DbErr::RecordNotFound(format!( + "Challenge with id {} not found", + id + ))); + }) +} diff --git a/src/model/game/mod.rs b/src/model/game/mod.rs index 9fadd5cb..bc826496 100644 --- a/src/model/game/mod.rs +++ b/src/model/game/mod.rs @@ -1,9 +1,11 @@ pub mod request; use axum::async_trait; -use sea_orm::{entity::prelude::*, Set}; +use sea_orm::{entity::prelude::*, QuerySelect, Set, TryIntoModel}; use serde::{Deserialize, Serialize}; +use crate::database::get_db; + use super::{challenge, game_challenge, game_team, pod, submission, team}; #[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] @@ -89,3 +91,59 @@ impl ActiveModelBehavior for ActiveModel { Ok(self) } } + +pub async fn find( + id: Option, title: Option, is_enabled: Option, page: Option, + size: Option, +) -> Result<(Vec, u64), DbErr> { + let mut query = crate::model::game::Entity::find(); + + if let Some(id) = id { + query = query.filter(crate::model::game::Column::Id.eq(id)); + } + + if let Some(title) = title { + query = query.filter(crate::model::game::Column::Title.contains(title)); + } + + if let Some(is_enabled) = is_enabled { + query = query.filter(crate::model::game::Column::IsEnabled.eq(is_enabled)); + } + + let total = query.clone().count(&get_db().await).await?; + + if let Some(page) = page { + if let Some(size) = size { + let offset = (page - 1) * size; + query = query.offset(offset).limit(size); + } + } + + let games = query.all(&get_db().await).await?; + + return Ok((games, total)); +} + +pub async fn create( + game: crate::model::game::ActiveModel, +) -> Result { + game.insert(&get_db().await).await?.try_into_model() +} + +pub async fn update( + game: crate::model::game::ActiveModel, +) -> Result { + game.update(&get_db().await).await?.try_into_model() +} + +pub async fn delete(id: i64) -> Result<(), DbErr> { + let result = crate::model::game::Entity::delete_by_id(id) + .exec(&get_db().await) + .await?; + Ok(if result.rows_affected == 0 { + return Err(DbErr::RecordNotFound(format!( + "Game with id {} not found", + id + ))); + }) +} diff --git a/src/model/game_challenge/mod.rs b/src/model/game_challenge/mod.rs index eb4dde01..c3ad3d1b 100644 --- a/src/model/game_challenge/mod.rs +++ b/src/model/game_challenge/mod.rs @@ -1,9 +1,11 @@ pub mod request; use axum::async_trait; -use sea_orm::entity::prelude::*; +use sea_orm::{entity::prelude::*, TryIntoModel}; use serde::{Deserialize, Serialize}; +use crate::database::get_db; + use super::{challenge, game}; #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] @@ -63,3 +65,67 @@ impl Related for Entity { #[async_trait] impl ActiveModelBehavior for ActiveModel {} + +async fn preload( + mut game_challenges: Vec, +) -> Result, DbErr> { + let challenges = game_challenges + .load_one(crate::model::challenge::Entity, &get_db().await) + .await?; + + for i in 0..game_challenges.len() { + game_challenges[i].challenge = challenges[i].clone(); + } + + return Ok(game_challenges); +} + +pub async fn find( + game_id: Option, challenge_id: Option, +) -> Result<(Vec, u64), DbErr> { + let mut query = crate::model::game_challenge::Entity::find(); + + if let Some(game_id) = game_id { + query = query.filter(crate::model::game_challenge::Column::GameId.eq(game_id)); + } + + if let Some(challenge_id) = challenge_id { + query = query.filter(crate::model::game_challenge::Column::ChallengeId.eq(challenge_id)); + } + + let total = query.clone().count(&get_db().await).await?; + + let mut game_challenges = query.all(&get_db().await).await?; + + game_challenges = preload(game_challenges).await?; + + Ok((game_challenges, total)) +} + +pub async fn create( + game_challenge: crate::model::game_challenge::ActiveModel, +) -> Result { + game_challenge + .insert(&get_db().await) + .await? + .try_into_model() +} + +pub async fn update( + game_challenge: crate::model::game_challenge::ActiveModel, +) -> Result { + game_challenge + .update(&get_db().await) + .await? + .try_into_model() +} + +pub async fn delete(game_id: i64, challenge_id: i64) -> Result<(), DbErr> { + let _result = crate::model::game_challenge::Entity::delete_many() + .filter(crate::model::game_challenge::Column::GameId.eq(game_id)) + .filter(crate::model::game_challenge::Column::ChallengeId.eq(challenge_id)) + .exec(&get_db().await) + .await?; + + return Ok(()); +} diff --git a/src/model/game_team/mod.rs b/src/model/game_team/mod.rs index 56ab9822..8b62c406 100644 --- a/src/model/game_team/mod.rs +++ b/src/model/game_team/mod.rs @@ -1,9 +1,11 @@ pub mod request; use axum::async_trait; -use sea_orm::entity::prelude::*; +use sea_orm::{entity::prelude::*, TryIntoModel}; use serde::{Deserialize, Serialize}; +use crate::database::get_db; + use super::{game, team}; #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] @@ -47,3 +49,67 @@ impl RelationTrait for Relation { #[async_trait] impl ActiveModelBehavior for ActiveModel {} + +async fn preload( + mut game_teams: Vec, +) -> Result, DbErr> { + let team_ids: Vec = game_teams + .iter() + .map(|game_team| game_team.team_id) + .collect(); + + let teams = crate::model::team::find_by_ids(team_ids).await?; + + for game_team in game_teams.iter_mut() { + game_team.team = teams + .iter() + .find(|team| team.id == game_team.team_id) + .cloned(); + } + + return Ok(game_teams); +} + +pub async fn find( + game_id: Option, team_id: Option, +) -> Result<(Vec, u64), DbErr> { + let mut query = crate::model::game_team::Entity::find(); + + if let Some(game_id) = game_id { + query = query.filter(crate::model::game_team::Column::GameId.eq(game_id)); + } + + if let Some(team_id) = team_id { + query = query.filter(crate::model::game_team::Column::TeamId.eq(team_id)); + } + + let total = query.clone().count(&get_db().await).await?; + + let mut game_teams = query.all(&get_db().await).await?; + + game_teams = preload(game_teams).await?; + + Ok((game_teams, total)) +} + +pub async fn create( + user: crate::model::game_team::ActiveModel, +) -> Result { + user.insert(&get_db().await).await?.try_into_model() +} + +pub async fn update( + user: crate::model::game_team::ActiveModel, +) -> Result { + user.update(&get_db().await).await?.try_into_model() +} + +pub async fn delete(game_id: i64, team_id: i64) -> Result<(), DbErr> { + let _result = crate::model::game_team::Entity::delete_many() + .filter(crate::model::game_team::Column::GameId.eq(game_id)) + .filter(crate::model::game_team::Column::TeamId.eq(team_id)) + .exec(&get_db().await) + .await?; + + return Ok(()); +} diff --git a/src/model/game_team/request.rs b/src/model/game_team/request.rs index 0ee76238..3af05dc4 100644 --- a/src/model/game_team/request.rs +++ b/src/model/game_team/request.rs @@ -11,7 +11,10 @@ pub struct FindRequest { impl Default for FindRequest { fn default() -> Self { - FindRequest { game_id: None, team_id: None } + FindRequest { + game_id: None, + team_id: None, + } } } diff --git a/src/model/pod/mod.rs b/src/model/pod/mod.rs index 3fb9032a..50fb4ec0 100644 --- a/src/model/pod/mod.rs +++ b/src/model/pod/mod.rs @@ -1,9 +1,11 @@ pub mod request; use axum::async_trait; -use sea_orm::{entity::prelude::*, FromJsonQueryResult, Set}; +use sea_orm::{entity::prelude::*, FromJsonQueryResult, Set, TryIntoModel}; use serde::{Deserialize, Serialize}; +use crate::database::get_db; + use super::{challenge, game, team, user}; #[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] @@ -50,10 +52,22 @@ pub enum Relation { impl RelationTrait for Relation { fn def(&self) -> RelationDef { match self { - Self::Challenge => Entity::belongs_to(challenge::Entity).from(Column::ChallengeId).to(challenge::Column::Id).into(), - Self::User => Entity::belongs_to(user::Entity).from(Column::UserId).to(user::Column::Id).into(), - Self::Team => Entity::belongs_to(team::Entity).from(Column::TeamId).to(team::Column::Id).into(), - Self::Game => Entity::belongs_to(game::Entity).from(Column::GameId).to(game::Column::Id).into(), + Self::Challenge => Entity::belongs_to(challenge::Entity) + .from(Column::ChallengeId) + .to(challenge::Column::Id) + .into(), + Self::User => Entity::belongs_to(user::Entity) + .from(Column::UserId) + .to(user::Column::Id) + .into(), + Self::Team => Entity::belongs_to(team::Entity) + .from(Column::TeamId) + .to(team::Column::Id) + .into(), + Self::Game => Entity::belongs_to(game::Entity) + .from(Column::GameId) + .to(game::Column::Id) + .into(), } } } @@ -91,3 +105,104 @@ impl ActiveModelBehavior for ActiveModel { } } } + +async fn preload( + mut pods: Vec, +) -> Result, DbErr> { + let users = pods + .load_one(crate::model::user::Entity, &get_db().await) + .await?; + let teams = pods + .load_one(crate::model::team::Entity, &get_db().await) + .await?; + let challenges = pods + .load_one(crate::model::challenge::Entity, &get_db().await) + .await?; + + for i in 0..pods.len() { + let mut pod = pods[i].clone(); + pod.user = users[i].clone(); + pod.team = teams[i].clone(); + pod.challenge = challenges[i].clone(); + pods[i] = pod; + } + + return Ok(pods); +} + +pub async fn find( + id: Option, name: Option, user_id: Option, team_id: Option, + game_id: Option, challenge_id: Option, is_available: Option, +) -> Result<(Vec, u64), DbErr> { + let mut query = crate::model::pod::Entity::find(); + if let Some(id) = id { + query = query.filter(crate::model::pod::Column::Id.eq(id)); + } + + if let Some(name) = name { + query = query.filter(crate::model::pod::Column::Name.eq(name)); + } + + if let Some(user_id) = user_id { + query = query.filter(crate::model::pod::Column::UserId.eq(user_id)); + } + + if let Some(team_id) = team_id { + query = query.filter(crate::model::pod::Column::TeamId.eq(team_id)); + } + + if let Some(game_id) = game_id { + query = query.filter(crate::model::pod::Column::GameId.eq(game_id)); + } + + if let Some(challenge_id) = challenge_id { + query = query.filter(crate::model::pod::Column::ChallengeId.eq(challenge_id)); + } + + if let Some(is_available) = is_available { + match is_available { + true => { + query = query.filter( + crate::model::pod::Column::RemovedAt.gte(chrono::Utc::now().timestamp()), + ) + } + false => { + query = query.filter( + crate::model::pod::Column::RemovedAt.lte(chrono::Utc::now().timestamp()), + ) + } + } + } + + let total = query.clone().count(&get_db().await).await?; + + let mut pods = query.all(&get_db().await).await?; + + pods = preload(pods).await?; + + return Ok((pods, total)); +} + +pub async fn create( + pod: crate::model::pod::ActiveModel, +) -> Result { + return pod.insert(&get_db().await).await?.try_into_model(); +} + +pub async fn update( + pod: crate::model::pod::ActiveModel, +) -> Result { + return pod.update(&get_db().await).await?.try_into_model(); +} + +pub async fn delete(id: i64) -> Result<(), DbErr> { + let result = crate::model::pod::Entity::delete_by_id(id) + .exec(&get_db().await) + .await?; + return Ok(if result.rows_affected == 0 { + return Err(DbErr::RecordNotFound(format!( + "Pod with id {} not found", + id + ))); + }); +} diff --git a/src/model/submission/mod.rs b/src/model/submission/mod.rs index d9b1a85c..09b63780 100644 --- a/src/model/submission/mod.rs +++ b/src/model/submission/mod.rs @@ -1,9 +1,11 @@ pub mod request; use axum::async_trait; -use sea_orm::{entity::prelude::*, Set}; +use sea_orm::{entity::prelude::*, QuerySelect, Set, TryIntoModel}; use serde::{Deserialize, Serialize}; +use crate::database::get_db; + use super::{challenge, game, team, user}; #[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] @@ -123,3 +125,111 @@ impl ActiveModelBehavior for ActiveModel { Ok(self) } } + +async fn preload( + mut submissions: Vec, +) -> Result, DbErr> { + let users = submissions + .load_one(crate::model::user::Entity, &get_db().await) + .await?; + let challenges = submissions + .load_one(crate::model::challenge::Entity, &get_db().await) + .await?; + let teams = submissions + .load_one(crate::model::team::Entity, &get_db().await) + .await?; + let games = submissions + .load_one(crate::model::game::Entity, &get_db().await) + .await?; + + for i in 0..submissions.len() { + let mut submission = submissions[i].clone(); + submission.user = users[i].clone(); + submission.challenge = challenges[i].clone(); + submission.team = teams[i].clone(); + submission.game = games[i].clone(); + submissions[i] = submission; + } + return Ok(submissions); +} + +pub async fn find( + id: Option, user_id: Option, team_id: Option, game_id: Option, + challenge_id: Option, status: Option, page: Option, size: Option, +) -> Result<(Vec, u64), DbErr> { + let mut query = crate::model::submission::Entity::find(); + + if let Some(id) = id { + query = query.filter(crate::model::submission::Column::Id.eq(id)); + } + + if let Some(user_id) = user_id { + query = query.filter(crate::model::submission::Column::UserId.eq(user_id)); + } + + if let Some(team_id) = team_id { + query = query.filter(crate::model::submission::Column::TeamId.eq(team_id)); + } + + if let Some(game_id) = game_id { + query = query.filter(crate::model::submission::Column::GameId.eq(game_id)); + } + + if let Some(challenge_id) = challenge_id { + query = query.filter(crate::model::submission::Column::ChallengeId.eq(challenge_id)); + } + + if let Some(status) = status { + query = query.filter(crate::model::submission::Column::Status.eq(status)); + } + + let total = query.clone().count(&get_db().await).await?; + + if let Some(page) = page { + if let Some(size) = size { + let offset = (page - 1) * size; + query = query.offset(offset).limit(size); + } + } + + let mut submissions = query.all(&get_db().await).await?; + + submissions = preload(submissions).await?; + + return Ok((submissions, total)); +} + +pub async fn find_by_challenge_ids( + challenge_ids: Vec, +) -> Result, DbErr> { + let mut submissions = crate::model::submission::Entity::find() + .filter(crate::model::submission::Column::ChallengeId.is_in(challenge_ids)) + .all(&get_db().await) + .await?; + submissions = preload(submissions).await?; + return Ok(submissions); +} + +pub async fn create( + submission: crate::model::submission::ActiveModel, +) -> Result { + return submission.insert(&get_db().await).await?.try_into_model(); +} + +pub async fn update( + submission: crate::model::submission::ActiveModel, +) -> Result { + return submission.update(&get_db().await).await?.try_into_model(); +} + +pub async fn delete(id: i64) -> Result<(), DbErr> { + let result = crate::model::submission::Entity::delete_by_id(id) + .exec(&get_db().await) + .await?; + return Ok(if result.rows_affected == 0 { + return Err(DbErr::RecordNotFound(format!( + "Submission with id {} not found", + id + ))); + }); +} diff --git a/src/model/team/mod.rs b/src/model/team/mod.rs index 5978003d..b066d188 100644 --- a/src/model/team/mod.rs +++ b/src/model/team/mod.rs @@ -1,9 +1,11 @@ pub mod request; use axum::async_trait; -use sea_orm::{entity::prelude::*, Set}; +use sea_orm::{entity::prelude::*, QuerySelect, Set, TryIntoModel}; use serde::{Deserialize, Serialize}; +use crate::database::get_db; + use super::{game, game_team, pod, submission, user, user_team}; #[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] @@ -90,3 +92,100 @@ impl ActiveModelBehavior for ActiveModel { Ok(self) } } + +async fn preload( + mut teams: Vec, +) -> Result, DbErr> { + let users = teams + .load_many_to_many( + crate::model::user::Entity, + crate::model::user_team::Entity, + &get_db().await, + ) + .await?; + + for i in 0..teams.len() { + let mut team = teams[i].clone(); + team.users = users[i].clone(); + for j in 0..team.users.len() { + let mut user = team.users[j].clone(); + user.simplify(); + if user.id == team.captain_id { + team.captain = Some(team.users[j].clone()); + } + team.users[j] = user; + } + teams[i] = team; + } + + return Ok(teams); +} + +pub async fn find( + id: Option, name: Option, email: Option, page: Option, + size: Option, +) -> Result<(Vec, u64), DbErr> { + let mut query = crate::model::team::Entity::find(); + + if let Some(id) = id { + query = query.filter(crate::model::team::Column::Id.eq(id)); + } + + if let Some(name) = name { + query = query.filter(crate::model::team::Column::Name.contains(name)); + } + + if let Some(email) = email { + query = query.filter(crate::model::team::Column::Email.eq(email)); + } + + let total = query.clone().count(&get_db().await).await?; + + if let Some(page) = page { + if let Some(size) = size { + let offset = (page - 1) * size; + query = query.offset(offset).limit(size); + } + } + + let mut teams = query.all(&get_db().await).await?; + + teams = preload(teams).await?; + + return Ok((teams, total)); +} + +pub async fn find_by_ids(ids: Vec) -> Result, DbErr> { + let mut teams = crate::model::team::Entity::find() + .filter(crate::model::team::Column::Id.is_in(ids)) + .all(&get_db().await) + .await?; + + teams = preload(teams).await?; + + return Ok(teams); +} + +pub async fn create( + team: crate::model::team::ActiveModel, +) -> Result { + return team.insert(&get_db().await).await?.try_into_model(); +} + +pub async fn update( + team: crate::model::team::ActiveModel, +) -> Result { + return team.update(&get_db().await).await?.try_into_model(); +} + +pub async fn delete(id: i64) -> Result<(), DbErr> { + let result = crate::model::team::Entity::delete_by_id(id) + .exec(&get_db().await) + .await?; + return Ok(if result.rows_affected == 0 { + return Err(DbErr::RecordNotFound(format!( + "Team with id {} not found", + id + ))); + }); +} diff --git a/src/model/user/mod.rs b/src/model/user/mod.rs index 25fa8323..2f93fe9f 100644 --- a/src/model/user/mod.rs +++ b/src/model/user/mod.rs @@ -1,9 +1,11 @@ pub mod request; use axum::async_trait; -use sea_orm::{entity::prelude::*, Set}; +use sea_orm::{entity::prelude::*, Condition, QuerySelect, Set, TryIntoModel}; use serde::{Deserialize, Serialize}; +use crate::database::get_db; + use super::{pod, submission, team, user_team}; #[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] @@ -77,3 +79,93 @@ impl ActiveModelBehavior for ActiveModel { Ok(self) } } + +async fn preload( + mut users: Vec, +) -> Result, DbErr> { + let teams = users + .load_many_to_many( + crate::model::team::Entity, + crate::model::user_team::Entity, + &get_db().await, + ) + .await?; + + for i in 0..users.len() { + let mut user = users[i].clone(); + user.teams = teams[i].clone(); + users[i] = user; + } + + return Ok(users); +} + +pub async fn find( + id: Option, name: Option, username: Option, group: Option, + email: Option, page: Option, size: Option, +) -> Result<(Vec, u64), DbErr> { + let mut query = crate::model::user::Entity::find(); + + if let Some(id) = id { + query = query.filter(crate::model::user::Column::Id.eq(id)); + } + + if let Some(name) = name { + let pattern = format!("%{}%", name); + let condition = Condition::any() + .add(crate::model::user::Column::Username.like(&pattern)) + .add(crate::model::user::Column::Nickname.like(&pattern)); + query = query.filter(condition); + } + + if let Some(username) = username { + query = query.filter(crate::model::user::Column::Username.eq(username)); + } + + if let Some(group) = group { + query = query.filter(crate::model::user::Column::Group.eq(group)); + } + + if let Some(email) = email { + query = query.filter(crate::model::user::Column::Email.eq(email)); + } + + let total = query.clone().count(&get_db().await).await?; + + if let Some(page) = page { + if let Some(size) = size { + let offset = (page - 1) * size; + query = query.offset(offset).limit(size); + } + } + + let mut users = query.all(&get_db().await).await?; + + users = preload(users).await?; + + Ok((users, total)) +} + +pub async fn create( + user: crate::model::user::ActiveModel, +) -> Result { + user.insert(&get_db().await).await?.try_into_model() +} + +pub async fn update( + user: crate::model::user::ActiveModel, +) -> Result { + user.update(&get_db().await).await?.try_into_model() +} + +pub async fn delete(id: i64) -> Result<(), DbErr> { + let result = crate::model::user::Entity::delete_by_id(id) + .exec(&get_db().await) + .await?; + Ok(if result.rows_affected == 0 { + return Err(DbErr::RecordNotFound(format!( + "User with id {} not found", + id + ))); + }) +} diff --git a/src/model/user_team/mod.rs b/src/model/user_team/mod.rs index 02909cd4..7660d4c2 100644 --- a/src/model/user_team/mod.rs +++ b/src/model/user_team/mod.rs @@ -1,9 +1,11 @@ pub mod request; use axum::async_trait; -use sea_orm::entity::prelude::*; +use sea_orm::{entity::prelude::*, TryIntoModel}; use serde::{Deserialize, Serialize}; +use crate::database::get_db; + use super::{team, user}; #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] @@ -40,3 +42,45 @@ impl RelationTrait for Relation { #[async_trait] impl ActiveModelBehavior for ActiveModel {} + +pub async fn find( + user_id: Option, team_id: Option, +) -> Result<(Vec, u64), DbErr> { + let mut query = crate::model::user_team::Entity::find(); + + if let Some(user_id) = user_id { + query = query.filter(crate::model::user_team::Column::UserId.eq(user_id)); + } + + if let Some(team_id) = team_id { + query = query.filter(crate::model::user_team::Column::TeamId.eq(team_id)); + } + + let total = query.clone().count(&get_db().await).await?; + + let user_teams = query.all(&get_db().await).await?; + + Ok((user_teams, total)) +} + +pub async fn create( + user_team: crate::model::user_team::ActiveModel, +) -> Result { + user_team.insert(&get_db().await).await?.try_into_model() +} + +pub async fn update( + user_team: crate::model::user_team::ActiveModel, +) -> Result { + user_team.update(&get_db().await).await?.try_into_model() +} + +pub async fn delete(user_id: i64, team_id: i64) -> Result<(), DbErr> { + let _result: sea_orm::DeleteResult = crate::model::user_team::Entity::delete_many() + .filter(crate::model::user_team::Column::UserId.eq(user_id)) + .filter(crate::model::user_team::Column::TeamId.eq(team_id)) + .exec(&get_db().await) + .await?; + + return Ok(()); +} diff --git a/src/repository/category.rs b/src/repository/category.rs deleted file mode 100644 index ce754ff3..00000000 --- a/src/repository/category.rs +++ /dev/null @@ -1,31 +0,0 @@ -use sea_orm::{ActiveModelTrait, ColumnTrait, DbErr, EntityTrait, PaginatorTrait, QueryFilter, TryIntoModel}; - -use crate::database::get_db; - -pub async fn find(id: Option, name: Option) -> Result<(Vec, u64), DbErr> { - let mut query = crate::model::category::Entity::find(); - if let Some(id) = id { - query = query.filter(crate::model::category::Column::Id.eq(id)); - } - if let Some(name) = name { - query = query.filter(crate::model::category::Column::Name.eq(name)); - } - let total = query.clone().count(&get_db().await).await?; - let categories = query.all(&get_db().await).await?; - Ok((categories, total)) -} - -pub async fn create(category: crate::model::category::ActiveModel) -> Result { - category.insert(&get_db().await).await?.try_into_model() -} - -pub async fn update(category: crate::model::category::ActiveModel) -> Result { - category.update(&get_db().await).await?.try_into_model() -} - -pub async fn delete(id: i64) -> Result<(), DbErr> { - let result = crate::model::category::Entity::delete_by_id(id).exec(&get_db().await).await?; - Ok(if result.rows_affected == 0 { - return Err(DbErr::RecordNotFound(format!("Category with id {} not found", id))); - }) -} diff --git a/src/repository/challenge.rs b/src/repository/challenge.rs deleted file mode 100644 index 93862047..00000000 --- a/src/repository/challenge.rs +++ /dev/null @@ -1,67 +0,0 @@ -use sea_orm::{ActiveModelTrait, ColumnTrait, DbErr, EntityTrait, PaginatorTrait, QueryFilter, QuerySelect, TryIntoModel}; - -use crate::database::get_db; - -pub async fn find( - id: Option, title: Option, category_id: Option, is_practicable: Option, is_dynamic: Option, page: Option, - size: Option, -) -> Result<(Vec, u64), DbErr> { - let mut query = crate::model::challenge::Entity::find(); - - if let Some(id) = id { - query = query.filter(crate::model::challenge::Column::Id.eq(id)); - } - - if let Some(title) = title { - query = query.filter(crate::model::challenge::Column::Title.contains(title)); - } - - if let Some(category_id) = category_id { - query = query.filter(crate::model::challenge::Column::CategoryId.eq(category_id)); - } - - if let Some(is_practicable) = is_practicable { - query = query.filter(crate::model::challenge::Column::IsPracticable.eq(is_practicable)); - } - - if let Some(is_dynamic) = is_dynamic { - query = query.filter(crate::model::challenge::Column::IsDynamic.eq(is_dynamic)); - } - - let total = query.clone().count(&get_db().await).await?; - - if let Some(page) = page { - if let Some(size) = size { - let offset = (page - 1) * size; - query = query.offset(offset).limit(size); - } - } - - let challenges = query.all(&get_db().await).await?; - - return Ok((challenges, total)); -} - -pub async fn find_by_ids(ids: Vec) -> Result, DbErr> { - let challenges = crate::model::challenge::Entity::find() - .filter(crate::model::challenge::Column::Id.is_in(ids)) - .all(&get_db().await) - .await?; - - return Ok(challenges); -} - -pub async fn create(challenge: crate::model::challenge::ActiveModel) -> Result { - challenge.insert(&get_db().await).await?.try_into_model() -} - -pub async fn update(challenge: crate::model::challenge::ActiveModel) -> Result { - challenge.update(&get_db().await).await?.try_into_model() -} - -pub async fn delete(id: i64) -> Result<(), DbErr> { - let result = crate::model::challenge::Entity::delete_by_id(id).exec(&get_db().await).await?; - Ok(if result.rows_affected == 0 { - return Err(DbErr::RecordNotFound(format!("Challenge with id {} not found", id))); - }) -} diff --git a/src/repository/game.rs b/src/repository/game.rs deleted file mode 100644 index e3c17e94..00000000 --- a/src/repository/game.rs +++ /dev/null @@ -1,49 +0,0 @@ -use sea_orm::{ActiveModelTrait, ColumnTrait, DbErr, EntityTrait, PaginatorTrait, QueryFilter, QuerySelect, TryIntoModel}; - -use crate::database::get_db; - -pub async fn find( - id: Option, title: Option, is_enabled: Option, page: Option, size: Option, -) -> Result<(Vec, u64), DbErr> { - let mut query = crate::model::game::Entity::find(); - - if let Some(id) = id { - query = query.filter(crate::model::game::Column::Id.eq(id)); - } - - if let Some(title) = title { - query = query.filter(crate::model::game::Column::Title.contains(title)); - } - - if let Some(is_enabled) = is_enabled { - query = query.filter(crate::model::game::Column::IsEnabled.eq(is_enabled)); - } - - let total = query.clone().count(&get_db().await).await?; - - if let Some(page) = page { - if let Some(size) = size { - let offset = (page - 1) * size; - query = query.offset(offset).limit(size); - } - } - - let games = query.all(&get_db().await).await?; - - return Ok((games, total)); -} - -pub async fn create(game: crate::model::game::ActiveModel) -> Result { - game.insert(&get_db().await).await?.try_into_model() -} - -pub async fn update(game: crate::model::game::ActiveModel) -> Result { - game.update(&get_db().await).await?.try_into_model() -} - -pub async fn delete(id: i64) -> Result<(), DbErr> { - let result = crate::model::game::Entity::delete_by_id(id).exec(&get_db().await).await?; - Ok(if result.rows_affected == 0 { - return Err(DbErr::RecordNotFound(format!("Game with id {} not found", id))); - }) -} diff --git a/src/repository/game_challenge.rs b/src/repository/game_challenge.rs deleted file mode 100644 index 19070763..00000000 --- a/src/repository/game_challenge.rs +++ /dev/null @@ -1,51 +0,0 @@ -use sea_orm::{ActiveModelTrait, ColumnTrait, DbErr, EntityTrait, LoaderTrait, PaginatorTrait, QueryFilter, TryIntoModel}; - -use crate::database::get_db; - -async fn preload(mut game_challenges: Vec) -> Result, DbErr> { - let challenges = game_challenges.load_one(crate::model::challenge::Entity, &get_db().await).await?; - - for i in 0..game_challenges.len() { - game_challenges[i].challenge = challenges[i].clone(); - } - - return Ok(game_challenges); -} - -pub async fn find(game_id: Option, challenge_id: Option) -> Result<(Vec, u64), DbErr> { - let mut query = crate::model::game_challenge::Entity::find(); - - if let Some(game_id) = game_id { - query = query.filter(crate::model::game_challenge::Column::GameId.eq(game_id)); - } - - if let Some(challenge_id) = challenge_id { - query = query.filter(crate::model::game_challenge::Column::ChallengeId.eq(challenge_id)); - } - - let total = query.clone().count(&get_db().await).await?; - - let mut game_challenges = query.all(&get_db().await).await?; - - game_challenges = preload(game_challenges).await?; - - Ok((game_challenges, total)) -} - -pub async fn create(game_challenge: crate::model::game_challenge::ActiveModel) -> Result { - game_challenge.insert(&get_db().await).await?.try_into_model() -} - -pub async fn update(game_challenge: crate::model::game_challenge::ActiveModel) -> Result { - game_challenge.update(&get_db().await).await?.try_into_model() -} - -pub async fn delete(game_id: i64, challenge_id: i64) -> Result<(), DbErr> { - let _result = crate::model::game_challenge::Entity::delete_many() - .filter(crate::model::game_challenge::Column::GameId.eq(game_id)) - .filter(crate::model::game_challenge::Column::ChallengeId.eq(challenge_id)) - .exec(&get_db().await) - .await?; - - return Ok(()); -} diff --git a/src/repository/game_team.rs b/src/repository/game_team.rs deleted file mode 100644 index 751a18c9..00000000 --- a/src/repository/game_team.rs +++ /dev/null @@ -1,53 +0,0 @@ -use sea_orm::{ActiveModelTrait, ColumnTrait, DbErr, EntityTrait, PaginatorTrait, QueryFilter, TryIntoModel}; - -use crate::database::get_db; - -async fn preload(mut game_teams: Vec) -> Result, DbErr> { - let team_ids: Vec = game_teams.iter().map(|game_team| game_team.team_id).collect(); - - let teams = super::team::find_by_ids(team_ids).await?; - - for game_team in game_teams.iter_mut() { - game_team.team = teams.iter().find(|team| team.id == game_team.team_id).cloned(); - } - - return Ok(game_teams); -} - -pub async fn find(game_id: Option, team_id: Option) -> Result<(Vec, u64), DbErr> { - let mut query = crate::model::game_team::Entity::find(); - - if let Some(game_id) = game_id { - query = query.filter(crate::model::game_team::Column::GameId.eq(game_id)); - } - - if let Some(team_id) = team_id { - query = query.filter(crate::model::game_team::Column::TeamId.eq(team_id)); - } - - let total = query.clone().count(&get_db().await).await?; - - let mut game_teams = query.all(&get_db().await).await?; - - game_teams = preload(game_teams).await?; - - Ok((game_teams, total)) -} - -pub async fn create(user: crate::model::game_team::ActiveModel) -> Result { - user.insert(&get_db().await).await?.try_into_model() -} - -pub async fn update(user: crate::model::game_team::ActiveModel) -> Result { - user.update(&get_db().await).await?.try_into_model() -} - -pub async fn delete(game_id: i64, team_id: i64) -> Result<(), DbErr> { - let _result = crate::model::game_team::Entity::delete_many() - .filter(crate::model::game_team::Column::GameId.eq(game_id)) - .filter(crate::model::game_team::Column::TeamId.eq(team_id)) - .exec(&get_db().await) - .await?; - - return Ok(()); -} diff --git a/src/repository/mod.rs b/src/repository/mod.rs deleted file mode 100644 index 18865f3f..00000000 --- a/src/repository/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub mod category; -pub mod challenge; -pub mod game; -pub mod game_challenge; -pub mod game_team; -pub mod pod; -pub mod submission; -pub mod team; -pub mod user; -pub mod user_team; diff --git a/src/repository/pod.rs b/src/repository/pod.rs deleted file mode 100644 index 8c45432a..00000000 --- a/src/repository/pod.rs +++ /dev/null @@ -1,79 +0,0 @@ -use sea_orm::{ActiveModelTrait, ColumnTrait, DbErr, EntityTrait, LoaderTrait, PaginatorTrait, QueryFilter, TryIntoModel}; - -use crate::database::get_db; - -async fn preload(mut pods: Vec) -> Result, DbErr> { - let users = pods.load_one(crate::model::user::Entity, &get_db().await).await?; - let teams = pods.load_one(crate::model::team::Entity, &get_db().await).await?; - let challenges = pods.load_one(crate::model::challenge::Entity, &get_db().await).await?; - - for i in 0..pods.len() { - let mut pod = pods[i].clone(); - pod.user = users[i].clone(); - pod.team = teams[i].clone(); - pod.challenge = challenges[i].clone(); - pods[i] = pod; - } - - return Ok(pods); -} - -pub async fn find( - id: Option, name: Option, user_id: Option, team_id: Option, game_id: Option, challenge_id: Option, - is_available: Option, -) -> Result<(Vec, u64), DbErr> { - let mut query = crate::model::pod::Entity::find(); - if let Some(id) = id { - query = query.filter(crate::model::pod::Column::Id.eq(id)); - } - - if let Some(name) = name { - query = query.filter(crate::model::pod::Column::Name.eq(name)); - } - - if let Some(user_id) = user_id { - query = query.filter(crate::model::pod::Column::UserId.eq(user_id)); - } - - if let Some(team_id) = team_id { - query = query.filter(crate::model::pod::Column::TeamId.eq(team_id)); - } - - if let Some(game_id) = game_id { - query = query.filter(crate::model::pod::Column::GameId.eq(game_id)); - } - - if let Some(challenge_id) = challenge_id { - query = query.filter(crate::model::pod::Column::ChallengeId.eq(challenge_id)); - } - - if let Some(is_available) = is_available { - match is_available { - true => query = query.filter(crate::model::pod::Column::RemovedAt.gte(chrono::Utc::now().timestamp())), - false => query = query.filter(crate::model::pod::Column::RemovedAt.lte(chrono::Utc::now().timestamp())), - } - } - - let total = query.clone().count(&get_db().await).await?; - - let mut pods = query.all(&get_db().await).await?; - - pods = preload(pods).await?; - - return Ok((pods, total)); -} - -pub async fn create(pod: crate::model::pod::ActiveModel) -> Result { - return pod.insert(&get_db().await).await?.try_into_model(); -} - -pub async fn update(pod: crate::model::pod::ActiveModel) -> Result { - return pod.update(&get_db().await).await?.try_into_model(); -} - -pub async fn delete(id: i64) -> Result<(), DbErr> { - let result = crate::model::pod::Entity::delete_by_id(id).exec(&get_db().await).await?; - return Ok(if result.rows_affected == 0 { - return Err(DbErr::RecordNotFound(format!("Pod with id {} not found", id))); - }); -} diff --git a/src/repository/submission.rs b/src/repository/submission.rs deleted file mode 100644 index 03fffcc4..00000000 --- a/src/repository/submission.rs +++ /dev/null @@ -1,90 +0,0 @@ -use sea_orm::{ActiveModelTrait, ColumnTrait, DbErr, EntityTrait, LoaderTrait, PaginatorTrait, QueryFilter, QuerySelect, TryIntoModel}; - -use crate::database::get_db; - -pub async fn preload(mut submissions: Vec) -> Result, DbErr> { - let users = submissions.load_one(crate::model::user::Entity, &get_db().await).await?; - let challenges = submissions.load_one(crate::model::challenge::Entity, &get_db().await).await?; - let teams = submissions.load_one(crate::model::team::Entity, &get_db().await).await?; - let games = submissions.load_one(crate::model::game::Entity, &get_db().await).await?; - - for i in 0..submissions.len() { - let mut submission = submissions[i].clone(); - submission.user = users[i].clone(); - submission.challenge = challenges[i].clone(); - submission.team = teams[i].clone(); - submission.game = games[i].clone(); - submissions[i] = submission; - } - return Ok(submissions); -} - -pub async fn find( - id: Option, user_id: Option, team_id: Option, game_id: Option, challenge_id: Option, status: Option, page: Option, - size: Option, -) -> Result<(Vec, u64), DbErr> { - let mut query = crate::model::submission::Entity::find(); - - if let Some(id) = id { - query = query.filter(crate::model::submission::Column::Id.eq(id)); - } - - if let Some(user_id) = user_id { - query = query.filter(crate::model::submission::Column::UserId.eq(user_id)); - } - - if let Some(team_id) = team_id { - query = query.filter(crate::model::submission::Column::TeamId.eq(team_id)); - } - - if let Some(game_id) = game_id { - query = query.filter(crate::model::submission::Column::GameId.eq(game_id)); - } - - if let Some(challenge_id) = challenge_id { - query = query.filter(crate::model::submission::Column::ChallengeId.eq(challenge_id)); - } - - if let Some(status) = status { - query = query.filter(crate::model::submission::Column::Status.eq(status)); - } - - let total = query.clone().count(&get_db().await).await?; - - if let Some(page) = page { - if let Some(size) = size { - let offset = (page - 1) * size; - query = query.offset(offset).limit(size); - } - } - - let mut submissions = query.all(&get_db().await).await?; - - submissions = preload(submissions).await?; - - return Ok((submissions, total)); -} - -pub async fn find_by_challenge_ids(challenge_ids: Vec) -> Result, DbErr> { - let mut submissions = crate::model::submission::Entity::find() - .filter(crate::model::submission::Column::ChallengeId.is_in(challenge_ids)) - .all(&get_db().await) - .await?; - submissions = preload(submissions).await?; - return Ok(submissions); -} - -pub async fn create(submission: crate::model::submission::ActiveModel) -> Result { - return submission.insert(&get_db().await).await?.try_into_model(); -} - -pub async fn update(submission: crate::model::submission::ActiveModel) -> Result { - return submission.update(&get_db().await).await?.try_into_model(); -} - -pub async fn delete(id: i64) -> Result<(), DbErr> { - let result = crate::model::submission::Entity::delete_by_id(id).exec(&get_db().await).await?; - return Ok(if result.rows_affected == 0 { - return Err(DbErr::RecordNotFound(format!("Submission with id {} not found", id))); - }); -} diff --git a/src/repository/team.rs b/src/repository/team.rs deleted file mode 100644 index 309120c2..00000000 --- a/src/repository/team.rs +++ /dev/null @@ -1,84 +0,0 @@ -use sea_orm::{ActiveModelTrait, ColumnTrait, DbErr, EntityTrait, LoaderTrait, PaginatorTrait, QueryFilter, QuerySelect, TryIntoModel}; - -use crate::database::get_db; - -async fn preload(mut teams: Vec) -> Result, DbErr> { - let users = teams - .load_many_to_many(crate::model::user::Entity, crate::model::user_team::Entity, &get_db().await) - .await?; - - for i in 0..teams.len() { - let mut team = teams[i].clone(); - team.users = users[i].clone(); - for j in 0..team.users.len() { - let mut user = team.users[j].clone(); - user.simplify(); - if user.id == team.captain_id { - team.captain = Some(team.users[j].clone()); - } - team.users[j] = user; - } - teams[i] = team; - } - - return Ok(teams); -} - -pub async fn find( - id: Option, name: Option, email: Option, page: Option, size: Option, -) -> Result<(Vec, u64), DbErr> { - let mut query = crate::model::team::Entity::find(); - - if let Some(id) = id { - query = query.filter(crate::model::team::Column::Id.eq(id)); - } - - if let Some(name) = name { - query = query.filter(crate::model::team::Column::Name.contains(name)); - } - - if let Some(email) = email { - query = query.filter(crate::model::team::Column::Email.eq(email)); - } - - let total = query.clone().count(&get_db().await).await?; - - if let Some(page) = page { - if let Some(size) = size { - let offset = (page - 1) * size; - query = query.offset(offset).limit(size); - } - } - - let mut teams = query.all(&get_db().await).await?; - - teams = preload(teams).await?; - - return Ok((teams, total)); -} - -pub async fn find_by_ids(ids: Vec) -> Result, DbErr> { - let mut teams = crate::model::team::Entity::find() - .filter(crate::model::team::Column::Id.is_in(ids)) - .all(&get_db().await) - .await?; - - teams = preload(teams).await?; - - return Ok(teams); -} - -pub async fn create(team: crate::model::team::ActiveModel) -> Result { - return team.insert(&get_db().await).await?.try_into_model(); -} - -pub async fn update(team: crate::model::team::ActiveModel) -> Result { - return team.update(&get_db().await).await?.try_into_model(); -} - -pub async fn delete(id: i64) -> Result<(), DbErr> { - let result = crate::model::team::Entity::delete_by_id(id).exec(&get_db().await).await?; - return Ok(if result.rows_affected == 0 { - return Err(DbErr::RecordNotFound(format!("Team with id {} not found", id))); - }); -} diff --git a/src/repository/user.rs b/src/repository/user.rs deleted file mode 100644 index 88db448a..00000000 --- a/src/repository/user.rs +++ /dev/null @@ -1,77 +0,0 @@ -use sea_orm::{ActiveModelTrait, ColumnTrait, Condition, DbErr, EntityTrait, LoaderTrait, PaginatorTrait, QueryFilter, QuerySelect, TryIntoModel}; - -use crate::database::get_db; - -async fn preload(mut users: Vec) -> Result, DbErr> { - let teams = users - .load_many_to_many(crate::model::team::Entity, crate::model::user_team::Entity, &get_db().await) - .await?; - - for i in 0..users.len() { - let mut user = users[i].clone(); - user.teams = teams[i].clone(); - users[i] = user; - } - - return Ok(users); -} - -pub async fn find( - id: Option, name: Option, username: Option, group: Option, email: Option, page: Option, size: Option, -) -> Result<(Vec, u64), DbErr> { - let mut query = crate::model::user::Entity::find(); - - if let Some(id) = id { - query = query.filter(crate::model::user::Column::Id.eq(id)); - } - - if let Some(name) = name { - let pattern = format!("%{}%", name); - let condition = Condition::any() - .add(crate::model::user::Column::Username.like(&pattern)) - .add(crate::model::user::Column::Nickname.like(&pattern)); - query = query.filter(condition); - } - - if let Some(username) = username { - query = query.filter(crate::model::user::Column::Username.eq(username)); - } - - if let Some(group) = group { - query = query.filter(crate::model::user::Column::Group.eq(group)); - } - - if let Some(email) = email { - query = query.filter(crate::model::user::Column::Email.eq(email)); - } - - let total = query.clone().count(&get_db().await).await?; - - if let Some(page) = page { - if let Some(size) = size { - let offset = (page - 1) * size; - query = query.offset(offset).limit(size); - } - } - - let mut users = query.all(&get_db().await).await?; - - users = preload(users).await?; - - Ok((users, total)) -} - -pub async fn create(user: crate::model::user::ActiveModel) -> Result { - user.insert(&get_db().await).await?.try_into_model() -} - -pub async fn update(user: crate::model::user::ActiveModel) -> Result { - user.update(&get_db().await).await?.try_into_model() -} - -pub async fn delete(id: i64) -> Result<(), DbErr> { - let result = crate::model::user::Entity::delete_by_id(id).exec(&get_db().await).await?; - Ok(if result.rows_affected == 0 { - return Err(DbErr::RecordNotFound(format!("User with id {} not found", id))); - }) -} diff --git a/src/repository/user_team.rs b/src/repository/user_team.rs deleted file mode 100644 index 2906ee43..00000000 --- a/src/repository/user_team.rs +++ /dev/null @@ -1,39 +0,0 @@ -use sea_orm::{ActiveModelTrait, ColumnTrait, DbErr, EntityTrait, PaginatorTrait, QueryFilter, TryIntoModel}; - -use crate::database::get_db; - -pub async fn find(user_id: Option, team_id: Option) -> Result<(Vec, u64), DbErr> { - let mut query = crate::model::user_team::Entity::find(); - - if let Some(user_id) = user_id { - query = query.filter(crate::model::user_team::Column::UserId.eq(user_id)); - } - - if let Some(team_id) = team_id { - query = query.filter(crate::model::user_team::Column::TeamId.eq(team_id)); - } - - let total = query.clone().count(&get_db().await).await?; - - let user_teams = query.all(&get_db().await).await?; - - Ok((user_teams, total)) -} - -pub async fn create(user_team: crate::model::user_team::ActiveModel) -> Result { - user_team.insert(&get_db().await).await?.try_into_model() -} - -pub async fn update(user_team: crate::model::user_team::ActiveModel) -> Result { - user_team.update(&get_db().await).await?.try_into_model() -} - -pub async fn delete(user_id: i64, team_id: i64) -> Result<(), DbErr> { - let _result: sea_orm::DeleteResult = crate::model::user_team::Entity::delete_many() - .filter(crate::model::user_team::Column::UserId.eq(user_id)) - .filter(crate::model::user_team::Column::TeamId.eq(team_id)) - .exec(&get_db().await) - .await?; - - return Ok(()); -} diff --git a/src/util/jwt.rs b/src/util/jwt.rs index 0d07a5cc..fcd146dd 100644 --- a/src/util/jwt.rs +++ b/src/util/jwt.rs @@ -9,7 +9,9 @@ use crate::config; static SECRET: Lazy> = Lazy::new(|| { let mut secret_key = config::get_app_config().auth.jwt.secret_key.clone(); let re = Regex::new(r"\[([Uu][Ii][Dd])\]").unwrap(); - secret_key = re.replace_all(&secret_key, uuid::Uuid::new_v4().simple().to_string()).to_string(); + secret_key = re + .replace_all(&secret_key, uuid::Uuid::new_v4().simple().to_string()) + .to_string(); return Mutex::new(secret_key); }); @@ -51,7 +53,12 @@ pub async fn generate_jwt_token(user_id: i64) -> String { exp: (chrono::Utc::now() + chrono::Duration::seconds(3600)).timestamp() as usize, }; - let token = encode(&Header::default(), &claims, &EncodingKey::from_secret(secret.as_bytes())).unwrap(); + let token = encode( + &Header::default(), + &claims, + &EncodingKey::from_secret(secret.as_bytes()), + ) + .unwrap(); return token; } diff --git a/src/util/math.rs b/src/util/math.rs index 059ccc27..f9964cef 100644 --- a/src/util/math.rs +++ b/src/util/math.rs @@ -8,6 +8,7 @@ use std::f64::consts::E; /// - "x" is the quantity of correct submissions. pub fn curve(s: i64, r: i64, d: i64, x: i64) -> i64 { let ratio = r as f64 / s as f64; - let result = (s as f64 * (ratio + (1.0 - ratio) * E.powf((1.0 - x as f64) / d as f64))).floor() as i64; + let result = + (s as f64 * (ratio + (1.0 - ratio) * E.powf((1.0 - x as f64) / d as f64))).floor() as i64; return result.min(s); } diff --git a/src/util/validate.rs b/src/util/validate.rs index d2a57a33..5d65decc 100644 --- a/src/util/validate.rs +++ b/src/util/validate.rs @@ -26,7 +26,11 @@ where // provide a better error message. // // Have to run that first since `Json` extraction consumes the request. - let path = parts.extract::().await.map(|path| path.as_str().to_owned()).ok(); + let path = parts + .extract::() + .await + .map(|path| path.as_str().to_owned()) + .ok(); let req = Request::from_parts(parts, body); diff --git a/src/web/controller/category.rs b/src/web/controller/category.rs index 77ef2507..cb81a0c1 100644 --- a/src/web/controller/category.rs +++ b/src/web/controller/category.rs @@ -7,8 +7,8 @@ use axum::{ use serde_json::json; use crate::model::category::request::{CreateRequest, FindRequest, UpdateRequest}; -use crate::web::service; use crate::util::validate; +use crate::web::service; /// **Find** can find categories. /// @@ -72,7 +72,9 @@ pub async fn create(validate::Json(body): validate::Json) -> impl /// ## Returns /// - `200`: update successfully. /// - `400`: update failed. -pub async fn update(Path(id): Path, validate::Json(mut body): validate::Json) -> impl IntoResponse { +pub async fn update( + Path(id): Path, validate::Json(mut body): validate::Json, +) -> impl IntoResponse { body.id = Some(id); match service::category::update(body).await { Ok(()) => ( diff --git a/src/web/controller/challenge.rs b/src/web/controller/challenge.rs index 156df30b..1a9631f8 100644 --- a/src/web/controller/challenge.rs +++ b/src/web/controller/challenge.rs @@ -1,14 +1,14 @@ use axum::{ - Extension, extract::{Multipart, Path, Query}, http::{header, Response, StatusCode}, - Json, response::IntoResponse, + response::IntoResponse, + Extension, Json, }; use serde_json::json; use crate::traits::Ext; -use crate::web::service; use crate::util::validate; +use crate::web::service; /// **Find** can be used to find challenges. /// @@ -20,7 +20,10 @@ use crate::util::validate; /// - `200`: find successfully. /// - `403`: operator does not have permission to find challenges. /// - `400`: find failed. -pub async fn find(Extension(ext): Extension, Query(params): Query) -> impl IntoResponse { +pub async fn find( + Extension(ext): Extension, + Query(params): Query, +) -> impl IntoResponse { let operator = ext.operator.unwrap(); if operator.group != "admin" && params.is_detailed.unwrap_or(false) { return ( @@ -49,7 +52,9 @@ pub async fn find(Extension(ext): Extension, Query(params): Query) -> impl IntoResponse { +pub async fn status( + Json(body): Json, +) -> impl IntoResponse { match service::challenge::status(body).await { Ok(status) => ( StatusCode::OK, @@ -67,7 +72,9 @@ pub async fn status(Json(body): Json) -> impl IntoResponse { +pub async fn create( + Json(body): Json, +) -> impl IntoResponse { match service::challenge::create(body).await { Ok(challenge) => ( StatusCode::OK, @@ -86,7 +93,10 @@ pub async fn create(Json(body): Json, validate::Json(mut body): validate::Json) -> impl IntoResponse { +pub async fn update( + Path(id): Path, + validate::Json(mut body): validate::Json, +) -> impl IntoResponse { body.id = Some(id); match service::challenge::update(body).await { Ok(()) => ( @@ -128,7 +138,10 @@ pub async fn find_attachment(Path(id): Path) -> impl IntoResponse { let buffer = crate::media::get(path, filename.to_string()).await.unwrap(); return Response::builder() .header(header::CONTENT_TYPE, "application/octet-stream") - .header(header::CONTENT_DISPOSITION, format!("attachment; filename=\"{}\"", filename)) + .header( + header::CONTENT_DISPOSITION, + format!("attachment; filename=\"{}\"", filename), + ) .body(buffer.into()) .unwrap(); } diff --git a/src/web/controller/game.rs b/src/web/controller/game.rs index d39ebad8..e21f15cb 100644 --- a/src/web/controller/game.rs +++ b/src/web/controller/game.rs @@ -1,15 +1,17 @@ use crate::traits::Ext; +use crate::web::service; use axum::{ - Extension, extract::{Multipart, Path, Query}, http::{Response, StatusCode}, - Json, response::IntoResponse, + response::IntoResponse, + Extension, Json, }; use mime::Mime; use serde_json::json; -use crate::web::service; -pub async fn find(Extension(ext): Extension, Query(params): Query) -> impl IntoResponse { +pub async fn find( + Extension(ext): Extension, Query(params): Query, +) -> impl IntoResponse { let operator = ext.operator.unwrap(); if operator.group != "admin" && !params.is_enabled.unwrap_or(true) { return ( @@ -42,7 +44,9 @@ pub async fn find(Extension(ext): Extension, Query(params): Query) -> impl IntoResponse { +pub async fn create( + Json(body): Json, +) -> impl IntoResponse { match service::game::create(body).await { Ok(challenge) => { return ( @@ -65,7 +69,9 @@ pub async fn create(Json(body): Json } } -pub async fn update(Path(id): Path, Json(mut body): Json) -> impl IntoResponse { +pub async fn update( + Path(id): Path, Json(mut body): Json, +) -> impl IntoResponse { body.id = Some(id); match service::game::update(body).await { Ok(()) => { @@ -108,7 +114,9 @@ pub async fn delete(Path(id): Path) -> impl IntoResponse { } } -pub async fn find_challenge(Query(params): Query) -> impl IntoResponse { +pub async fn find_challenge( + Query(params): Query, +) -> impl IntoResponse { match service::game_challenge::find(params).await { Ok((game_challenges, total)) => { return ( @@ -131,7 +139,9 @@ pub async fn find_challenge(Query(params): Query) -> impl IntoResponse { +pub async fn create_challenge( + Json(body): Json, +) -> impl IntoResponse { match service::game_challenge::create(body).await { Ok(()) => { return ( @@ -153,7 +163,8 @@ pub async fn create_challenge(Json(body): Json, Json(mut body): Json, + Path((id, challenge_id)): Path<(i64, i64)>, + Json(mut body): Json, ) -> impl IntoResponse { body.game_id = Some(id); body.challenge_id = Some(challenge_id); @@ -198,7 +209,9 @@ pub async fn delete_challenge(Path((id, challenge_id)): Path<(i64, i64)>) -> imp } } -pub async fn find_team(Query(params): Query) -> impl IntoResponse { +pub async fn find_team( + Query(params): Query, +) -> impl IntoResponse { match service::game_team::find(params).await { Ok((game_teams, total)) => { return ( @@ -221,7 +234,9 @@ pub async fn find_team(Query(params): Query) -> impl IntoResponse { +pub async fn create_team( + Json(body): Json, +) -> impl IntoResponse { match service::game_team::create(body).await { Ok(()) => { return ( @@ -242,7 +257,10 @@ pub async fn create_team(Json(body): Json, Json(mut body): Json) -> impl IntoResponse { +pub async fn update_team( + Path((id, team_id)): Path<(i64, i64)>, + Json(mut body): Json, +) -> impl IntoResponse { body.game_id = Some(id); body.team_id = Some(team_id); match service::game_team::update(body).await { diff --git a/src/web/controller/media.rs b/src/web/controller/media.rs index 2160964d..72f352f3 100644 --- a/src/web/controller/media.rs +++ b/src/web/controller/media.rs @@ -10,7 +10,10 @@ pub async fn get_file(Path(path): Path) -> impl IntoResponse { Ok(buffer) => { return Response::builder() .header(header::CONTENT_TYPE, "application/octet-stream") - .header(header::CONTENT_DISPOSITION, format!("attachment; filename=\"{}\"", filename)) + .header( + header::CONTENT_DISPOSITION, + format!("attachment; filename=\"{}\"", filename), + ) .body(buffer.into()) .unwrap(); } diff --git a/src/web/controller/pod.rs b/src/web/controller/pod.rs index 457266d9..e5f40a74 100644 --- a/src/web/controller/pod.rs +++ b/src/web/controller/pod.rs @@ -1,15 +1,17 @@ use axum::{ - Extension, extract::{Path, Query}, http::StatusCode, - Json, response::IntoResponse, + response::IntoResponse, + Extension, Json, }; use serde_json::json; use crate::traits::Ext; use crate::web::service; -pub async fn find(Query(params): Query) -> impl IntoResponse { +pub async fn find( + Query(params): Query, +) -> impl IntoResponse { match service::pod::find(params).await { Ok((pods, total)) => ( StatusCode::OK, @@ -29,7 +31,9 @@ pub async fn find(Query(params): Query) } } -pub async fn create(Extension(ext): Extension, Json(mut body): Json) -> impl IntoResponse { +pub async fn create( + Extension(ext): Extension, Json(mut body): Json, +) -> impl IntoResponse { let operator = ext.operator.clone().unwrap(); body.user_id = Some(operator.id); @@ -72,7 +76,13 @@ pub async fn update(Extension(ext): Extension, Path(id): Path) -> impl }) .unwrap(); - if operator.group == "admin" || operator.id == pod.user_id || operator.teams.iter().any(|team| Some(team.id) == pod.team_id) { + if operator.group == "admin" + || operator.id == pod.user_id + || operator + .teams + .iter() + .any(|team| Some(team.id) == pod.team_id) + { match service::pod::update(id).await { Ok(_) => ( StatusCode::OK, @@ -117,7 +127,13 @@ pub async fn delete(Extension(ext): Extension, Path(id): Path) -> impl let pod = pods.get(0).unwrap(); - if operator.group == "admin" || operator.id == pod.user_id || operator.teams.iter().any(|team| Some(team.id) == pod.team_id) { + if operator.group == "admin" + || operator.id == pod.user_id + || operator + .teams + .iter() + .any(|team| Some(team.id) == pod.team_id) + { match service::pod::delete(id).await { Ok(_) => { return ( diff --git a/src/web/controller/submission.rs b/src/web/controller/submission.rs index 9869050b..bc01baeb 100644 --- a/src/web/controller/submission.rs +++ b/src/web/controller/submission.rs @@ -1,8 +1,8 @@ use axum::{ - Extension, extract::{Path, Query}, http::StatusCode, - Json, response::IntoResponse, + response::IntoResponse, + Extension, Json, }; use serde_json::json; @@ -19,7 +19,10 @@ use crate::web::service::submission as submission_service; /// - `200`: find successfully. /// - `403`: operator does not have permission to find submissions. /// - `400`: find failed. -pub async fn find(Extension(ext): Extension, Query(params): Query) -> impl IntoResponse { +pub async fn find( + Extension(ext): Extension, + Query(params): Query, +) -> impl IntoResponse { let operator = ext.operator.unwrap(); if operator.group != "admin" && params.is_detailed.unwrap_or(false) { return ( @@ -48,7 +51,10 @@ pub async fn find(Extension(ext): Extension, Query(params): Query, Json(mut body): Json) -> impl IntoResponse { +pub async fn create( + Extension(ext): Extension, + Json(mut body): Json, +) -> impl IntoResponse { let operator = ext.operator.unwrap(); body.user_id = Some(operator.id); match submission_service::create(body).await { diff --git a/src/web/controller/team.rs b/src/web/controller/team.rs index 7fceb6d5..0c6d098b 100644 --- a/src/web/controller/team.rs +++ b/src/web/controller/team.rs @@ -1,19 +1,25 @@ use crate::traits::Ext; +use crate::web::service::{team as team_service, user_team as user_team_service}; use axum::{ - Extension, extract::{Multipart, Path, Query}, http::{Response, StatusCode}, - Json, response::IntoResponse, + response::IntoResponse, + Extension, Json, }; use mime::Mime; use serde_json::json; -use crate::web::service::{team as team_service, user_team as user_team_service}; fn can_modify_team(user: crate::model::user::Model, team_id: i64) -> bool { - return user.group == "admin" || user.teams.iter().any(|team| team.id == team_id && team.captain_id == user.id); + return user.group == "admin" + || user + .teams + .iter() + .any(|team| team.id == team_id && team.captain_id == user.id); } -pub async fn find(Query(params): Query) -> impl IntoResponse { +pub async fn find( + Query(params): Query, +) -> impl IntoResponse { match team_service::find(params).await { Ok((teams, total)) => ( StatusCode::OK, @@ -33,7 +39,9 @@ pub async fn find(Query(params): Query } } -pub async fn create(Json(body): Json) -> impl IntoResponse { +pub async fn create( + Json(body): Json, +) -> impl IntoResponse { match team_service::create(body).await { Ok(team) => ( StatusCode::OK, @@ -53,7 +61,8 @@ pub async fn create(Json(body): Json } pub async fn update( - Extension(ext): Extension, Path(id): Path, Json(mut body): Json, + Extension(ext): Extension, Path(id): Path, + Json(mut body): Json, ) -> impl IntoResponse { if !can_modify_team(ext.operator.unwrap(), id) { return ( @@ -109,7 +118,9 @@ pub async fn delete(Extension(ext): Extension, Path(id): Path) -> impl } } -pub async fn create_user(Json(body): Json) -> impl IntoResponse { +pub async fn create_user( + Json(body): Json, +) -> impl IntoResponse { match user_team_service::create(body).await { Ok(()) => ( StatusCode::OK, @@ -145,7 +156,9 @@ pub async fn delete_user(Path((id, user_id)): Path<(i64, i64)>) -> impl IntoResp } } -pub async fn get_invite_token(Extension(ext): Extension, Path(id): Path) -> impl IntoResponse { +pub async fn get_invite_token( + Extension(ext): Extension, Path(id): Path, +) -> impl IntoResponse { if !can_modify_team(ext.operator.unwrap(), id) { return ( StatusCode::FORBIDDEN, @@ -177,7 +190,9 @@ pub async fn get_invite_token(Extension(ext): Extension, Path(id): Path, Path(id): Path) -> impl IntoResponse { +pub async fn update_invite_token( + Extension(ext): Extension, Path(id): Path, +) -> impl IntoResponse { if !can_modify_team(ext.operator.unwrap(), id) { return ( StatusCode::FORBIDDEN, @@ -209,7 +224,9 @@ pub async fn update_invite_token(Extension(ext): Extension, Path(id): Path< } } -pub async fn join(Json(body): Json) -> impl IntoResponse { +pub async fn join( + Json(body): Json, +) -> impl IntoResponse { match user_team_service::join(body).await { Ok(()) => { return ( @@ -272,7 +289,9 @@ pub async fn find_avatar(Path(id): Path) -> impl IntoResponse { } } -pub async fn save_avatar(Extension(ext): Extension, Path(id): Path, mut multipart: Multipart) -> impl IntoResponse { +pub async fn save_avatar( + Extension(ext): Extension, Path(id): Path, mut multipart: Multipart, +) -> impl IntoResponse { if !can_modify_team(ext.operator.unwrap(), id) { return ( StatusCode::FORBIDDEN, @@ -337,7 +356,9 @@ pub async fn save_avatar(Extension(ext): Extension, Path(id): Path, mu } } -pub async fn delete_avatar(Extension(ext): Extension, Path(id): Path) -> impl IntoResponse { +pub async fn delete_avatar( + Extension(ext): Extension, Path(id): Path, +) -> impl IntoResponse { if !can_modify_team(ext.operator.unwrap(), id) { return ( StatusCode::FORBIDDEN, diff --git a/src/web/controller/user.rs b/src/web/controller/user.rs index 75762149..701e3873 100644 --- a/src/web/controller/user.rs +++ b/src/web/controller/user.rs @@ -1,14 +1,14 @@ use axum::{ - Extension, extract::{Multipart, Path, Query}, http::{Response, StatusCode}, - Json, response::IntoResponse, + response::IntoResponse, + Extension, Json, }; use mime::Mime; use serde_json::json; -use crate::{traits::Ext, util::validate}; use crate::web::service::user as user_service; +use crate::{traits::Ext, util::validate}; /// **Find** can find user's information. /// @@ -18,7 +18,9 @@ use crate::web::service::user as user_service; /// ## Returns /// - `200`: find successfully. /// - `400`: find failed. -pub async fn find(Query(params): Query) -> impl IntoResponse { +pub async fn find( + Query(params): Query, +) -> impl IntoResponse { match user_service::find(params).await { Ok((users, total)) => ( StatusCode::OK, @@ -46,7 +48,9 @@ pub async fn find(Query(params): Query /// ## Returns /// - `200`: create successfully. /// - `400`: create failed. -pub async fn create(validate::Json(body): validate::Json) -> impl IntoResponse { +pub async fn create( + validate::Json(body): validate::Json, +) -> impl IntoResponse { match user_service::create(body).await { Ok(user) => ( StatusCode::OK, @@ -80,12 +84,15 @@ pub async fn create(validate::Json(body): validate::Json, Path(id): Path, validate::Json(mut body): validate::Json, + Extension(ext): Extension, Path(id): Path, + validate::Json(mut body): validate::Json, ) -> impl IntoResponse { let operator = ext.clone().operator.unwrap(); body.id = Some(id); if operator.group == "admin" - || (operator.id == body.id.unwrap_or(0) && (body.group.clone().is_none() || operator.group == body.group.clone().unwrap_or("".to_string()))) + || (operator.id == body.id.unwrap_or(0) + && (body.group.clone().is_none() + || operator.group == body.group.clone().unwrap_or("".to_string()))) { match user_service::update(body).await { Ok(()) => { @@ -155,7 +162,9 @@ pub async fn delete(Path(id): Path) -> impl IntoResponse { /// ## Returns /// - `200`: login successfully, with token and user information. /// - `400`: login failed. -pub async fn login(Json(body): Json) -> impl IntoResponse { +pub async fn login( + Json(body): Json, +) -> impl IntoResponse { match user_service::login(body).await { Ok((user, token)) => { return ( @@ -189,7 +198,9 @@ pub async fn login(Json(body): Json) /// - `400`: register failed. /// - `409`: username or email has been registered. /// - `500`: internal server error(most likely database error). -pub async fn register(validate::Json(body): validate::Json) -> impl IntoResponse { +pub async fn register( + validate::Json(body): validate::Json, +) -> impl IntoResponse { match user_service::register(body).await { Ok(user) => { return ( @@ -266,7 +277,9 @@ pub async fn find_avatar_metadata(Path(id): Path) -> impl IntoResponse { } } -pub async fn save_avatar(Extension(ext): Extension, Path(id): Path, mut multipart: Multipart) -> impl IntoResponse { +pub async fn save_avatar( + Extension(ext): Extension, Path(id): Path, mut multipart: Multipart, +) -> impl IntoResponse { let operator = ext.operator.unwrap(); if operator.group != "admin" && operator.id != id { return ( @@ -331,7 +344,9 @@ pub async fn save_avatar(Extension(ext): Extension, Path(id): Path, mu } } -pub async fn delete_avatar(Extension(ext): Extension, Path(id): Path) -> impl IntoResponse { +pub async fn delete_avatar( + Extension(ext): Extension, Path(id): Path, +) -> impl IntoResponse { let operator = ext.operator.unwrap(); if operator.group != "admin" && operator.id != id { return ( diff --git a/src/web/middleware/auth.rs b/src/web/middleware/auth.rs index 91db54fc..a402cf1f 100644 --- a/src/web/middleware/auth.rs +++ b/src/web/middleware/auth.rs @@ -14,7 +14,13 @@ use std::pin::Pin; use crate::web::service::user as user_service; use crate::{traits::Ext, util}; -pub fn jwt(group: util::jwt::Group) -> impl Fn(Request, Next) -> Pin> + Send>> + Clone { +pub fn jwt( + group: util::jwt::Group, +) -> impl Fn( + Request, + Next, +) -> Pin> + Send>> + + Clone { move |mut req: Request, next: Next| { Box::pin({ let value = group.clone(); @@ -26,7 +32,8 @@ pub fn jwt(group: util::jwt::Group) -> impl Fn(Request, Next) // .and_then(|header| header.strip_prefix("Bearer ")) .unwrap_or(""); - let decoding_key = DecodingKey::from_secret(util::jwt::get_secret().await.as_bytes()); + let decoding_key = + DecodingKey::from_secret(util::jwt::get_secret().await.as_bytes()); let validation = Validation::default(); match decode::(token, &decoding_key, &validation) { @@ -50,9 +57,15 @@ pub fn jwt(group: util::jwt::Group) -> impl Fn(Request, Next) } let user = users.get(0).unwrap(); - req.extensions_mut().insert(Ext { operator: Some(user.clone()) }); + req.extensions_mut().insert(Ext { + operator: Some(user.clone()), + }); - if (value as u8) <= (util::jwt::Group::from_str(user.group.clone()).unwrap_or(util::jwt::Group::Banned) as u8) { + if (value as u8) + <= (util::jwt::Group::from_str(user.group.clone()) + .unwrap_or(util::jwt::Group::Banned) + as u8) + { return Ok(next.run(req).await); } else { return Ok(( diff --git a/src/web/middleware/frontend.rs b/src/web/middleware/frontend.rs index bbd417bc..e9308ac8 100644 --- a/src/web/middleware/frontend.rs +++ b/src/web/middleware/frontend.rs @@ -18,7 +18,11 @@ pub async fn serve(req: Request, next: Next) -> Result Result { if let Ok(index_content) = fs::read_to_string(PathBuf::from("dist").join("index.html")) { - return Ok(Response::builder().status(StatusCode::OK).body(index_content).unwrap().into_response()); + return Ok(Response::builder() + .status(StatusCode::OK) + .body(index_content) + .unwrap() + .into_response()); } else { return Ok(Response::builder() .status(StatusCode::NOT_FOUND) @@ -33,7 +37,11 @@ pub async fn serve(req: Request, next: Next) -> Result = OnceLock::new(); pub fn init() { let cors = CorsLayer::new() - .allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE, Method::OPTIONS]) + .allow_methods([ + Method::GET, + Method::POST, + Method::PUT, + Method::DELETE, + Method::OPTIONS, + ]) .allow_headers(Any) .allow_origin(Any); let app: Router = Router::new() - .merge(Router::new().nest("/api", router::router()).layer(TraceLayer::new_for_http())) + .merge( + Router::new() + .nest("/api", router::router()) + .layer(TraceLayer::new_for_http()), + ) .layer(from_fn(middleware::frontend::serve)) .layer(cors); diff --git a/src/web/router/category.rs b/src/web/router/category.rs index 01de18fc..489884b8 100644 --- a/src/web/router/category.rs +++ b/src/web/router/category.rs @@ -1,16 +1,25 @@ +use crate::util::jwt::Group; +use crate::web::controller; +use crate::web::middleware::auth; use axum::{ middleware::from_fn, - Router, routing::{delete, get, post, put}, + Router, }; -use crate::web::controller; -use crate::web::middleware::auth; -use crate::util::jwt::Group; pub fn router() -> Router { return Router::new() .route("/", get(controller::category::find)) - .route("/", post(controller::category::create).layer(from_fn(auth::jwt(Group::Admin)))) - .route("/:id", put(controller::category::update).layer(from_fn(auth::jwt(Group::Admin)))) - .route("/:id", delete(controller::category::delete).layer(from_fn(auth::jwt(Group::Admin)))); + .route( + "/", + post(controller::category::create).layer(from_fn(auth::jwt(Group::Admin))), + ) + .route( + "/:id", + put(controller::category::update).layer(from_fn(auth::jwt(Group::Admin))), + ) + .route( + "/:id", + delete(controller::category::delete).layer(from_fn(auth::jwt(Group::Admin))), + ); } diff --git a/src/web/router/challenge.rs b/src/web/router/challenge.rs index 0db238cb..93f02157 100644 --- a/src/web/router/challenge.rs +++ b/src/web/router/challenge.rs @@ -1,22 +1,43 @@ +use crate::util::jwt::Group; +use crate::web::controller; +use crate::web::middleware::auth; use axum::{ extract::DefaultBodyLimit, middleware::from_fn, - Router, routing::{delete, get, post, put}, + Router, }; -use crate::web::controller; -use crate::web::middleware::auth; -use crate::util::jwt::Group; pub fn router() -> Router { return Router::new() - .route("/", get(controller::challenge::find).layer(from_fn(auth::jwt(Group::User)))) - .route("/", post(controller::challenge::create).layer(from_fn(auth::jwt(Group::Admin)))) - .route("/status", post(controller::challenge::status).layer(from_fn(auth::jwt(Group::User)))) - .route("/:id", put(controller::challenge::update).layer(from_fn(auth::jwt(Group::Admin)))) - .route("/:id", delete(controller::challenge::delete).layer(from_fn(auth::jwt(Group::Admin)))) - .route("/:id/attachment", get(controller::challenge::find_attachment)) - .route("/:id/attachment/metadata", get(controller::challenge::find_attachment_metadata)) + .route( + "/", + get(controller::challenge::find).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/", + post(controller::challenge::create).layer(from_fn(auth::jwt(Group::Admin))), + ) + .route( + "/status", + post(controller::challenge::status).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/:id", + put(controller::challenge::update).layer(from_fn(auth::jwt(Group::Admin))), + ) + .route( + "/:id", + delete(controller::challenge::delete).layer(from_fn(auth::jwt(Group::Admin))), + ) + .route( + "/:id/attachment", + get(controller::challenge::find_attachment), + ) + .route( + "/:id/attachment/metadata", + get(controller::challenge::find_attachment_metadata), + ) .route( "/:id/attachment", post(controller::challenge::save_attachment) @@ -25,6 +46,7 @@ pub fn router() -> Router { ) .route( "/:id/attachment", - delete(controller::challenge::delete_attachment).layer(from_fn(auth::jwt(Group::Admin))), + delete(controller::challenge::delete_attachment) + .layer(from_fn(auth::jwt(Group::Admin))), ); } diff --git a/src/web/router/game.rs b/src/web/router/game.rs index 97ce9958..182d6834 100644 --- a/src/web/router/game.rs +++ b/src/web/router/game.rs @@ -1,20 +1,35 @@ +use crate::util::jwt::Group; +use crate::web::controller; +use crate::web::middleware::auth; use axum::{ extract::DefaultBodyLimit, middleware::from_fn, - Router, routing::{delete, get, post, put}, + Router, }; -use crate::web::controller; -use crate::web::middleware::auth; -use crate::util::jwt::Group; pub fn router() -> Router { return Router::new() - .route("/", get(controller::game::find).layer(from_fn(auth::jwt(Group::User)))) - .route("/", post(controller::game::create).layer(from_fn(auth::jwt(Group::Admin)))) - .route("/:id", put(controller::game::update).layer(from_fn(auth::jwt(Group::Admin)))) - .route("/:id", delete(controller::game::delete).layer(from_fn(auth::jwt(Group::Admin)))) - .route("/:id/challenges", get(controller::game::find_challenge).layer(from_fn(auth::jwt(Group::User)))) + .route( + "/", + get(controller::game::find).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/", + post(controller::game::create).layer(from_fn(auth::jwt(Group::Admin))), + ) + .route( + "/:id", + put(controller::game::update).layer(from_fn(auth::jwt(Group::Admin))), + ) + .route( + "/:id", + delete(controller::game::delete).layer(from_fn(auth::jwt(Group::Admin))), + ) + .route( + "/:id/challenges", + get(controller::game::find_challenge).layer(from_fn(auth::jwt(Group::User))), + ) .route( "/:id/challenges", post(controller::game::create_challenge).layer(from_fn(auth::jwt(Group::Admin))), @@ -27,8 +42,14 @@ pub fn router() -> Router { "/:id/challenges/:challenge_id", delete(controller::game::delete_challenge).layer(from_fn(auth::jwt(Group::Admin))), ) - .route("/:id/teams", get(controller::game::find_team).layer(from_fn(auth::jwt(Group::User)))) - .route("/:id/teams", post(controller::game::create_team).layer(from_fn(auth::jwt(Group::User)))) + .route( + "/:id/teams", + get(controller::game::find_team).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/:id/teams", + post(controller::game::create_team).layer(from_fn(auth::jwt(Group::User))), + ) .route( "/:id/teams/:team_id", put(controller::game::update_team).layer(from_fn(auth::jwt(Group::Admin))), @@ -37,8 +58,14 @@ pub fn router() -> Router { "/:id/teams/:team_id", delete(controller::game::delete_team).layer(from_fn(auth::jwt(Group::Admin))), ) - .route("/:id/notices", get(controller::game::find_notice).layer(from_fn(auth::jwt(Group::User)))) - .route("/:id/notices", post(controller::game::create_notice).layer(from_fn(auth::jwt(Group::Admin)))) + .route( + "/:id/notices", + get(controller::game::find_notice).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/:id/notices", + post(controller::game::create_notice).layer(from_fn(auth::jwt(Group::Admin))), + ) .route( "/:id/notices/:notice_id", put(controller::game::update_notice).layer(from_fn(auth::jwt(Group::Admin))), @@ -54,5 +81,8 @@ pub fn router() -> Router { .layer(DefaultBodyLimit::max(3 * 1024 * 1024 /* MB */)) .layer(from_fn(auth::jwt(Group::Admin))), ) - .route("/:id/poster", delete(controller::game::delete_poster).layer(from_fn(auth::jwt(Group::Admin)))); + .route( + "/:id/poster", + delete(controller::game::delete_poster).layer(from_fn(auth::jwt(Group::Admin))), + ); } diff --git a/src/web/router/pod.rs b/src/web/router/pod.rs index d6add79d..b7ad9fea 100644 --- a/src/web/router/pod.rs +++ b/src/web/router/pod.rs @@ -1,16 +1,28 @@ +use crate::util::jwt::Group; +use crate::web::controller; +use crate::web::middleware::auth; use axum::{ middleware::from_fn, - Router, routing::{delete, get, post, put}, + Router, }; -use crate::web::controller; -use crate::web::middleware::auth; -use crate::util::jwt::Group; pub fn router() -> Router { return Router::new() - .route("/", get(controller::pod::find).layer(from_fn(auth::jwt(Group::User)))) - .route("/", post(controller::pod::create).layer(from_fn(auth::jwt(Group::User)))) - .route("/:id", put(controller::pod::update).layer(from_fn(auth::jwt(Group::User)))) - .route("/:id", delete(controller::pod::delete).layer(from_fn(auth::jwt(Group::User)))); + .route( + "/", + get(controller::pod::find).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/", + post(controller::pod::create).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/:id", + put(controller::pod::update).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/:id", + delete(controller::pod::delete).layer(from_fn(auth::jwt(Group::User))), + ); } diff --git a/src/web/router/submission.rs b/src/web/router/submission.rs index 492db21b..1b32d722 100644 --- a/src/web/router/submission.rs +++ b/src/web/router/submission.rs @@ -1,15 +1,24 @@ +use crate::util::jwt::Group; +use crate::web::controller; +use crate::web::middleware::auth; use axum::{ middleware::from_fn, - Router, routing::{delete, get, post}, + Router, }; -use crate::web::controller; -use crate::web::middleware::auth; -use crate::util::jwt::Group; pub fn router() -> Router { return Router::new() - .route("/", get(controller::submission::find).layer(from_fn(auth::jwt(Group::User)))) - .route("/", post(controller::submission::create).layer(from_fn(auth::jwt(Group::User)))) - .route("/:id", delete(controller::submission::delete).layer(from_fn(auth::jwt(Group::Admin)))); + .route( + "/", + get(controller::submission::find).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/", + post(controller::submission::create).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/:id", + delete(controller::submission::delete).layer(from_fn(auth::jwt(Group::Admin))), + ); } diff --git a/src/web/router/team.rs b/src/web/router/team.rs index 03ad7e2b..cfccb25f 100644 --- a/src/web/router/team.rs +++ b/src/web/router/team.rs @@ -1,35 +1,68 @@ +use crate::util::jwt::Group; +use crate::web::controller; +use crate::web::middleware::auth; use axum::{ extract::DefaultBodyLimit, middleware::from_fn, - Router, routing::{delete, get, post, put}, + Router, }; -use crate::web::controller; -use crate::web::middleware::auth; -use crate::util::jwt::Group; pub fn router() -> Router { return Router::new() - .route("/", get(controller::team::find).layer(from_fn(auth::jwt(Group::Guest)))) - .route("/", post(controller::team::create).layer(from_fn(auth::jwt(Group::User)))) - .route("/:id", put(controller::team::update).layer(from_fn(auth::jwt(Group::User)))) - .route("/:id", delete(controller::team::delete).layer(from_fn(auth::jwt(Group::User)))) - .route("/:id/users", post(controller::team::create_user).layer(from_fn(auth::jwt(Group::User)))) + .route( + "/", + get(controller::team::find).layer(from_fn(auth::jwt(Group::Guest))), + ) + .route( + "/", + post(controller::team::create).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/:id", + put(controller::team::update).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/:id", + delete(controller::team::delete).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/:id/users", + post(controller::team::create_user).layer(from_fn(auth::jwt(Group::User))), + ) .route( "/:id/users/:user_id", delete(controller::team::delete_user).layer(from_fn(auth::jwt(Group::User))), ) - .route("/:id/invite", get(controller::team::get_invite_token).layer(from_fn(auth::jwt(Group::User)))) - .route("/:id/invite", put(controller::team::update_invite_token).layer(from_fn(auth::jwt(Group::User)))) - .route("/:id/join", post(controller::team::join).layer(from_fn(auth::jwt(Group::User)))) - .route("/:id/leave", delete(controller::team::leave).layer(from_fn(auth::jwt(Group::User)))) + .route( + "/:id/invite", + get(controller::team::get_invite_token).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/:id/invite", + put(controller::team::update_invite_token).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/:id/join", + post(controller::team::join).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/:id/leave", + delete(controller::team::leave).layer(from_fn(auth::jwt(Group::User))), + ) .route("/:id/avatar", get(controller::team::find_avatar)) - .route("/:id/avatar/metadata", get(controller::team::find_avatar_metadata)) + .route( + "/:id/avatar/metadata", + get(controller::team::find_avatar_metadata), + ) .route( "/:id/avatar", post(controller::team::save_avatar) .layer(DefaultBodyLimit::max(3 * 1024 * 1024 /* MB */)) .layer(from_fn(auth::jwt(Group::User))), ) - .route("/:id/avatar", delete(controller::team::delete_avatar).layer(from_fn(auth::jwt(Group::User)))); + .route( + "/:id/avatar", + delete(controller::team::delete_avatar).layer(from_fn(auth::jwt(Group::User))), + ); } diff --git a/src/web/router/user.rs b/src/web/router/user.rs index 2c38e67f..86b32821 100644 --- a/src/web/router/user.rs +++ b/src/web/router/user.rs @@ -1,28 +1,46 @@ +use crate::util::jwt::Group; +use crate::web::controller; +use crate::web::middleware::auth; use axum::{ extract::DefaultBodyLimit, middleware::from_fn, - Router, routing::{delete, get, post, put}, + Router, }; -use crate::web::controller; -use crate::web::middleware::auth; -use crate::util::jwt::Group; pub fn router() -> Router { return Router::new() - .route("/", get(controller::user::find).layer(from_fn(auth::jwt(Group::Guest)))) - .route("/", post(controller::user::create).layer(from_fn(auth::jwt(Group::Admin)))) - .route("/:id", put(controller::user::update).layer(from_fn(auth::jwt(Group::User)))) - .route("/:id", delete(controller::user::delete).layer(from_fn(auth::jwt(Group::Admin)))) + .route( + "/", + get(controller::user::find).layer(from_fn(auth::jwt(Group::Guest))), + ) + .route( + "/", + post(controller::user::create).layer(from_fn(auth::jwt(Group::Admin))), + ) + .route( + "/:id", + put(controller::user::update).layer(from_fn(auth::jwt(Group::User))), + ) + .route( + "/:id", + delete(controller::user::delete).layer(from_fn(auth::jwt(Group::Admin))), + ) .route("/login", post(controller::user::login)) .route("/register", post(controller::user::register)) .route("/:id/avatar", get(controller::user::find_avatar)) - .route("/:id/avatar/metadata", get(controller::user::find_avatar_metadata)) + .route( + "/:id/avatar/metadata", + get(controller::user::find_avatar_metadata), + ) .route( "/:id/avatar", post(controller::user::save_avatar) .layer(DefaultBodyLimit::max(3 * 1024 * 1024 /* MB */)) .layer(from_fn(auth::jwt(Group::User))), ) - .route("/:id/avatar", delete(controller::user::delete_avatar).layer(from_fn(auth::jwt(Group::User)))); + .route( + "/:id/avatar", + delete(controller::user::delete_avatar).layer(from_fn(auth::jwt(Group::User))), + ); } diff --git a/src/web/service/category.rs b/src/web/service/category.rs index 3370e3a2..912e3f0b 100644 --- a/src/web/service/category.rs +++ b/src/web/service/category.rs @@ -2,27 +2,35 @@ use std::error::Error; use sea_orm::TryIntoModel; -pub async fn find(req: crate::model::category::request::FindRequest) -> Result<(Vec, u64), Box> { - let (categories, total) = crate::repository::category::find(req.id, req.name).await.unwrap(); +pub async fn find( + req: crate::model::category::request::FindRequest, +) -> Result<(Vec, u64), Box> { + let (categories, total) = crate::model::category::find(req.id, req.name) + .await + .unwrap(); return Ok((categories, total)); } -pub async fn create(req: crate::model::category::request::CreateRequest) -> Result> { - match crate::repository::category::create(req.into()).await { +pub async fn create( + req: crate::model::category::request::CreateRequest, +) -> Result> { + match crate::model::category::create(req.into()).await { Ok(port) => return Ok(port.try_into_model().unwrap()), Err(err) => return Err(Box::new(err)), } } -pub async fn update(req: crate::model::category::request::UpdateRequest) -> Result<(), Box> { - match crate::repository::category::update(req.into()).await { +pub async fn update( + req: crate::model::category::request::UpdateRequest, +) -> Result<(), Box> { + match crate::model::category::update(req.into()).await { Ok(_) => return Ok(()), Err(err) => return Err(Box::new(err)), } } pub async fn delete(id: i64) -> Result<(), Box> { - match crate::repository::category::delete(id).await { + match crate::model::category::delete(id).await { Ok(_) => return Ok(()), Err(err) => return Err(Box::new(err)), } diff --git a/src/web/service/challenge.rs b/src/web/service/challenge.rs index 45a0ac5d..2315b876 100644 --- a/src/web/service/challenge.rs +++ b/src/web/service/challenge.rs @@ -3,11 +3,20 @@ use std::error::Error; use sea_orm::TryIntoModel; -pub async fn find(req: crate::model::challenge::request::FindRequest) -> Result<(Vec, u64), ()> { - let (mut challenges, total) = - crate::repository::challenge::find(req.id, req.title, req.category_id, req.is_practicable, req.is_dynamic, req.page, req.size) - .await - .unwrap(); +pub async fn find( + req: crate::model::challenge::request::FindRequest, +) -> Result<(Vec, u64), ()> { + let (mut challenges, total) = crate::model::challenge::find( + req.id, + req.title, + req.category_id, + req.is_practicable, + req.is_dynamic, + req.page, + req.size, + ) + .await + .unwrap(); for challenge in challenges.iter_mut() { let is_detailed = req.is_detailed.unwrap_or(false); @@ -22,16 +31,21 @@ pub async fn find(req: crate::model::challenge::request::FindRequest) -> Result< pub async fn status( req: crate::model::challenge::request::StatusRequest, ) -> Result, Box> { - let mut submissions = crate::repository::submission::find_by_challenge_ids(req.cids.clone()).await.unwrap(); + let mut submissions = crate::model::submission::find_by_challenge_ids(req.cids.clone()) + .await + .unwrap(); - let mut result: HashMap = HashMap::new(); + let mut result: HashMap = + HashMap::new(); for cid in req.cids { - result.entry(cid).or_insert_with(|| crate::model::challenge::response::StatusResponse { - is_solved: false, - solved_times: 0, - bloods: Vec::new(), - }); + result + .entry(cid) + .or_insert_with(|| crate::model::challenge::response::StatusResponse { + is_solved: false, + solved_times: 0, + bloods: Vec::new(), + }); } for submission in submissions.iter_mut() { @@ -61,13 +75,17 @@ pub async fn status( status_response.solved_times += 1; if status_response.bloods.len() < 3 { status_response.bloods.push(submission.clone()); - status_response.bloods.sort_by(|a, b| a.created_at.cmp(&b.created_at)); + status_response + .bloods + .sort_by(|a, b| a.created_at.cmp(&b.created_at)); } else { let last_submission = status_response.bloods.last().unwrap(); if submission.created_at < last_submission.created_at { status_response.bloods.pop(); status_response.bloods.push(submission.clone()); - status_response.bloods.sort_by(|a, b| a.created_at.cmp(&b.created_at)); + status_response + .bloods + .sort_by(|a, b| a.created_at.cmp(&b.created_at)); } } } @@ -75,22 +93,26 @@ pub async fn status( return Ok(result); } -pub async fn create(req: crate::model::challenge::request::CreateRequest) -> Result> { - match crate::repository::challenge::create(req.into()).await { +pub async fn create( + req: crate::model::challenge::request::CreateRequest, +) -> Result> { + match crate::model::challenge::create(req.into()).await { Ok(challenge) => return Ok(challenge.try_into_model().unwrap()), Err(err) => return Err(Box::new(err)), } } -pub async fn update(req: crate::model::challenge::request::UpdateRequest) -> Result<(), Box> { - match crate::repository::challenge::update(req.into()).await { +pub async fn update( + req: crate::model::challenge::request::UpdateRequest, +) -> Result<(), Box> { + match crate::model::challenge::update(req.into()).await { Ok(_) => return Ok(()), Err(err) => return Err(Box::new(err)), } } pub async fn delete(id: i64) -> Result<(), Box> { - match crate::repository::challenge::delete(id).await { + match crate::model::challenge::delete(id).await { Ok(_) => return Ok(()), Err(err) => return Err(Box::new(err)), } diff --git a/src/web/service/game.rs b/src/web/service/game.rs index 42c12d19..a1155056 100644 --- a/src/web/service/game.rs +++ b/src/web/service/game.rs @@ -2,30 +2,35 @@ use std::error::Error; use sea_orm::TryIntoModel; -pub async fn find(req: crate::model::game::request::FindRequest) -> Result<(Vec, u64), Box> { - let (games, total) = crate::repository::game::find(req.id, req.title, req.is_enabled, req.page, req.size) - .await - .unwrap(); +pub async fn find( + req: crate::model::game::request::FindRequest, +) -> Result<(Vec, u64), Box> { + let (games, total) = + crate::model::game::find(req.id, req.title, req.is_enabled, req.page, req.size) + .await + .unwrap(); return Ok((games, total)); } -pub async fn create(req: crate::model::game::request::CreateRequest) -> Result> { - match crate::repository::game::create(req.into()).await { +pub async fn create( + req: crate::model::game::request::CreateRequest, +) -> Result> { + match crate::model::game::create(req.into()).await { Ok(game) => return Ok(game.try_into_model().unwrap()), Err(err) => return Err(Box::new(err)), } } pub async fn update(req: crate::model::game::request::UpdateRequest) -> Result<(), Box> { - match crate::repository::game::update(req.into()).await { + match crate::model::game::update(req.into()).await { Ok(_game) => return Ok(()), Err(err) => return Err(Box::new(err)), } } pub async fn delete(id: i64) -> Result<(), Box> { - match crate::repository::game::delete(id).await { + match crate::model::game::delete(id).await { Ok(_) => return Ok(()), Err(err) => return Err(Box::new(err)), } diff --git a/src/web/service/game_challenge.rs b/src/web/service/game_challenge.rs index 147d5913..f7935084 100644 --- a/src/web/service/game_challenge.rs +++ b/src/web/service/game_challenge.rs @@ -1,13 +1,20 @@ use std::error::Error; -pub async fn find(req: crate::model::game_challenge::request::FindRequest) -> Result<(Vec, u64), Box> { - let (game_challenges, total) = crate::repository::game_challenge::find(req.game_id, req.challenge_id).await.unwrap(); +pub async fn find( + req: crate::model::game_challenge::request::FindRequest, +) -> Result<(Vec, u64), Box> { + let (game_challenges, total) = + crate::model::game_challenge::find(req.game_id, req.challenge_id) + .await + .unwrap(); return Ok((game_challenges, total)); } -pub async fn create(req: crate::model::game_challenge::request::CreateRequest) -> Result<(), Box> { - match crate::repository::game_challenge::create(req.into()).await { +pub async fn create( + req: crate::model::game_challenge::request::CreateRequest, +) -> Result<(), Box> { + match crate::model::game_challenge::create(req.into()).await { Ok(_) => { return Ok(()); } @@ -17,8 +24,10 @@ pub async fn create(req: crate::model::game_challenge::request::CreateRequest) - }; } -pub async fn update(req: crate::model::game_challenge::request::UpdateRequest) -> Result<(), Box> { - match crate::repository::game_challenge::update(req.into()).await { +pub async fn update( + req: crate::model::game_challenge::request::UpdateRequest, +) -> Result<(), Box> { + match crate::model::game_challenge::update(req.into()).await { Ok(_) => { return Ok(()); } @@ -29,7 +38,7 @@ pub async fn update(req: crate::model::game_challenge::request::UpdateRequest) - } pub async fn delete(id: i64, challenge_id: i64) -> Result<(), Box> { - match crate::repository::game_challenge::delete(id, challenge_id).await { + match crate::model::game_challenge::delete(id, challenge_id).await { Ok(_) => { return Ok(()); } diff --git a/src/web/service/game_team.rs b/src/web/service/game_team.rs index 39c1dde1..a0a2bef1 100644 --- a/src/web/service/game_team.rs +++ b/src/web/service/game_team.rs @@ -1,7 +1,11 @@ use std::error::Error; -pub async fn find(req: crate::model::game_team::request::FindRequest) -> Result<(Vec, u64), Box> { - let (mut game_teams, total) = crate::repository::game_team::find(req.game_id, req.team_id).await.unwrap(); +pub async fn find( + req: crate::model::game_team::request::FindRequest, +) -> Result<(Vec, u64), Box> { + let (mut game_teams, total) = crate::model::game_team::find(req.game_id, req.team_id) + .await + .unwrap(); for game_team in game_teams.iter_mut() { if let Some(team) = game_team.team.as_mut() { @@ -12,8 +16,10 @@ pub async fn find(req: crate::model::game_team::request::FindRequest) -> Result< return Ok((game_teams, total)); } -pub async fn create(req: crate::model::game_team::request::CreateRequest) -> Result<(), Box> { - match crate::repository::game_team::create(req.into()).await { +pub async fn create( + req: crate::model::game_team::request::CreateRequest, +) -> Result<(), Box> { + match crate::model::game_team::create(req.into()).await { Ok(_) => { return Ok(()); } @@ -23,8 +29,10 @@ pub async fn create(req: crate::model::game_team::request::CreateRequest) -> Res }; } -pub async fn update(req: crate::model::game_team::request::UpdateRequest) -> Result<(), Box> { - match crate::repository::game_team::update(req.into()).await { +pub async fn update( + req: crate::model::game_team::request::UpdateRequest, +) -> Result<(), Box> { + match crate::model::game_team::update(req.into()).await { Ok(_) => { return Ok(()); } @@ -35,7 +43,7 @@ pub async fn update(req: crate::model::game_team::request::UpdateRequest) -> Res } pub async fn delete(id: i64, challenge_id: i64) -> Result<(), Box> { - match crate::repository::game_team::delete(id, challenge_id).await { + match crate::model::game_team::delete(id, challenge_id).await { Ok(_) => { return Ok(()); } diff --git a/src/web/service/pod.rs b/src/web/service/pod.rs index 7221acea..41dd2e96 100644 --- a/src/web/service/pod.rs +++ b/src/web/service/pod.rs @@ -4,12 +4,20 @@ use regex::Regex; use sea_orm::{IntoActiveModel, Set}; use uuid::Uuid; -use crate::container::traits::Container; - -pub async fn find(req: crate::model::pod::request::FindRequest) -> Result<(Vec, u64), ()> { - let (mut pods, total) = crate::repository::pod::find(req.id, req.name, req.user_id, req.team_id, req.game_id, req.challenge_id, req.is_available) - .await - .unwrap(); +pub async fn find( + req: crate::model::pod::request::FindRequest, +) -> Result<(Vec, u64), ()> { + let (mut pods, total) = crate::model::pod::find( + req.id, + req.name, + req.user_id, + req.team_id, + req.game_id, + req.challenge_id, + req.is_available, + ) + .await + .unwrap(); if let Some(is_detailed) = req.is_detailed { if !is_detailed { @@ -21,10 +29,20 @@ pub async fn find(req: crate::model::pod::request::FindRequest) -> Result<(Vec Result> { - let (challenges, _) = crate::repository::challenge::find(Some(req.challenge_id.clone()), None, None, None, None, None, None) - .await - .unwrap(); +pub async fn create( + req: crate::model::pod::request::CreateRequest, +) -> Result> { + let (challenges, _) = crate::model::challenge::find( + Some(req.challenge_id.clone()), + None, + None, + None, + None, + None, + None, + ) + .await + .unwrap(); let challenge = challenges.get(0).unwrap(); @@ -38,7 +56,12 @@ pub async fn create(req: crate::model::pod::request::CreateRequest) -> Result Result Result Result<(), Box> { - let (pods, total) = crate::repository::pod::find(Some(id), None, None, None, None, None, None).await?; + let (pods, total) = + crate::model::pod::find(Some(id), None, None, None, None, None, None).await?; if total == 0 { return Err("No pod found".into()); } let pod = pods.get(0).unwrap(); - let (challenges, _) = crate::repository::challenge::find(Some(pod.challenge_id.clone()), None, None, None, None, None, None).await?; + let (challenges, _) = crate::model::challenge::find( + Some(pod.challenge_id.clone()), + None, + None, + None, + None, + None, + None, + ) + .await?; let challenge = challenges.get(0).unwrap(); let mut pod = pod.clone().into_active_model(); pod.removed_at = Set(chrono::Utc::now().timestamp() + challenge.duration); - let _ = crate::repository::pod::update(pod).await; + let _ = crate::model::pod::update(pod).await; return Ok(()); } pub async fn delete(id: i64) -> Result<(), Box> { - let (pods, total) = crate::repository::pod::find(Some(id), None, None, None, None, None, None).await?; + let (pods, total) = + crate::model::pod::find(Some(id), None, None, None, None, None, None).await?; if total == 0 { return Err("No pod found".into()); } let pod = pods.get(0).unwrap(); - crate::container::get_container().await.delete(pod.name.clone()).await; + crate::container::get_container() + .await + .delete(pod.name.clone()) + .await; let mut pod = pod.clone().into_active_model(); pod.removed_at = Set(chrono::Utc::now().timestamp()); - let _ = crate::repository::pod::update(pod).await; + let _ = crate::model::pod::update(pod).await; return Ok(()); } diff --git a/src/web/service/submission.rs b/src/web/service/submission.rs index 6c16e326..eb7e7fea 100644 --- a/src/web/service/submission.rs +++ b/src/web/service/submission.rs @@ -2,11 +2,21 @@ use std::error::Error; use sea_orm::{IntoActiveModel, Set}; -pub async fn find(req: crate::model::submission::request::FindRequest) -> Result<(Vec, u64), Box> { - let (mut submissions, total) = - crate::repository::submission::find(req.id, req.user_id, req.team_id, req.game_id, req.challenge_id, req.status, req.page, req.size) - .await - .unwrap(); +pub async fn find( + req: crate::model::submission::request::FindRequest, +) -> Result<(Vec, u64), Box> { + let (mut submissions, total) = crate::model::submission::find( + req.id, + req.user_id, + req.team_id, + req.game_id, + req.challenge_id, + req.status, + req.page, + req.size, + ) + .await + .unwrap(); let is_detailed = req.is_detailed.unwrap_or(false); if !is_detailed { @@ -18,29 +28,52 @@ pub async fn find(req: crate::model::submission::request::FindRequest) -> Result return Ok((submissions, total)); } -pub async fn create(req: crate::model::submission::request::CreateRequest) -> Result> { +pub async fn create( + req: crate::model::submission::request::CreateRequest, +) -> Result> { // Get related challenge - let (challenges, _) = crate::repository::challenge::find(req.challenge_id, None, None, None, None, None, None) - .await - .unwrap(); + let (challenges, _) = + crate::model::challenge::find(req.challenge_id, None, None, None, None, None, None) + .await + .unwrap(); let challenge = challenges.first().unwrap(); // Default submission record - let mut submission = crate::repository::submission::create(req.clone().into()).await.unwrap().into_active_model(); - - let (exist_submissions, total) = crate::repository::submission::find(None, None, None, req.game_id, req.challenge_id, Some(2), None, None) + let mut submission = crate::model::submission::create(req.clone().into()) .await - .unwrap(); + .unwrap() + .into_active_model(); + + let (exist_submissions, total) = crate::model::submission::find( + None, + None, + None, + req.game_id, + req.challenge_id, + Some(2), + None, + None, + ) + .await + .unwrap(); let mut status: i64 = 1; // Wrong answer match challenge.is_dynamic { true => { // Dynamic challenge, verify flag correctness from pods - let (pods, _) = crate::repository::pod::find(None, None, None, None, req.game_id, Some(challenge.id), Some(true)) - .await - .unwrap(); + let (pods, _) = crate::model::pod::find( + None, + None, + None, + None, + req.game_id, + Some(challenge.id), + Some(true), + ) + .await + .unwrap(); for pod in pods { if pod.flag == Some(req.clone().flag) { @@ -70,7 +103,9 @@ pub async fn create(req: crate::model::submission::request::CreateRequest) -> Re } for exist_submission in exist_submissions { - if Some(exist_submission.user_id) == req.user_id || (req.game_id.is_some() && exist_submission.team_id == req.team_id) { + if Some(exist_submission.user_id) == req.user_id + || (req.game_id.is_some() && exist_submission.team_id == req.team_id) + { status = 4; // Invalid break; } @@ -81,13 +116,13 @@ pub async fn create(req: crate::model::submission::request::CreateRequest) -> Re submission.rank = Set((total + 1).try_into().unwrap()); } - let submission = crate::repository::submission::update(submission).await.unwrap(); + let submission = crate::model::submission::update(submission).await.unwrap(); return Ok(submission); } pub async fn delete(id: i64) -> Result<(), Box> { - match crate::repository::submission::delete(id).await { + match crate::model::submission::delete(id).await { Ok(_) => return Ok(()), Err(err) => return Err(Box::new(err)), } diff --git a/src/web/service/team.rs b/src/web/service/team.rs index 7e7409b7..19a8df74 100644 --- a/src/web/service/team.rs +++ b/src/web/service/team.rs @@ -2,15 +2,19 @@ use std::error::Error; use sea_orm::{IntoActiveModel, Set}; -pub async fn find(req: crate::model::team::request::FindRequest) -> Result<(Vec, u64), ()> { - let (teams, total) = crate::repository::team::find(req.id, req.name, req.email, req.page, req.size).await.unwrap(); +pub async fn find( + req: crate::model::team::request::FindRequest, +) -> Result<(Vec, u64), ()> { + let (teams, total) = crate::model::team::find(req.id, req.name, req.email, req.page, req.size) + .await + .unwrap(); return Ok((teams, total)); } pub async fn create(req: crate::model::team::request::CreateRequest) -> Result<(), Box> { - match crate::repository::team::create(req.clone().into()).await { + match crate::model::team::create(req.clone().into()).await { Ok(team) => { - match crate::repository::user_team::create(crate::model::user_team::ActiveModel { + match crate::model::user_team::create(crate::model::user_team::ActiveModel { team_id: Set(team.id), user_id: Set(req.captain_id), }) @@ -27,21 +31,23 @@ pub async fn create(req: crate::model::team::request::CreateRequest) -> Result<( } pub async fn update(req: crate::model::team::request::UpdateRequest) -> Result<(), Box> { - match crate::repository::team::update(req.into()).await { + match crate::model::team::update(req.into()).await { Ok(_) => return Ok(()), Err(err) => return Err(Box::new(err)), } } pub async fn delete(id: i64) -> Result<(), Box> { - match crate::repository::team::delete(id).await { + match crate::model::team::delete(id).await { Ok(()) => return Ok(()), Err(err) => return Err(Box::new(err)), } } pub async fn get_invite_token(id: i64) -> Result> { - let (teams, total) = crate::repository::team::find(Some(id), None, None, None, None).await.unwrap(); + let (teams, total) = crate::model::team::find(Some(id), None, None, None, None) + .await + .unwrap(); if total == 0 { return Err("team_not_found".into()); @@ -53,7 +59,9 @@ pub async fn get_invite_token(id: i64) -> Result> { } pub async fn update_invite_token(id: i64) -> Result> { - let (teams, total) = crate::repository::team::find(Some(id), None, None, None, None).await.unwrap(); + let (teams, total) = crate::model::team::find(Some(id), None, None, None, None) + .await + .unwrap(); if total == 0 { return Err("team_not_found".into()); @@ -63,7 +71,7 @@ pub async fn update_invite_token(id: i64) -> Result> { let token = uuid::Uuid::new_v4().simple().to_string(); team.invite_token = Set(Some(token.clone())); - match crate::repository::team::update(team).await { + match crate::model::team::update(team).await { Ok(_) => return Ok(token), Err(err) => return Err(Box::new(err)), } diff --git a/src/web/service/user.rs b/src/web/service/user.rs index a8ac3657..80ab23c5 100644 --- a/src/web/service/user.rs +++ b/src/web/service/user.rs @@ -5,20 +5,26 @@ use axum::http::StatusCode; use bcrypt::{hash, verify, DEFAULT_COST}; use sea_orm::Set; -pub async fn find(req: crate::model::user::request::FindRequest) -> Result<(Vec, u64), ()> { - let (mut users, total) = crate::repository::user::find(req.id, req.name, None, req.group, req.email, req.page, req.size) - .await - .unwrap(); +pub async fn find( + req: crate::model::user::request::FindRequest, +) -> Result<(Vec, u64), ()> { + let (mut users, total) = crate::model::user::find( + req.id, req.name, None, req.group, req.email, req.page, req.size, + ) + .await + .unwrap(); for user in users.iter_mut() { user.simplify(); } return Ok((users, total)); } -pub async fn create(mut req: crate::model::user::request::CreateRequest) -> Result> { +pub async fn create( + mut req: crate::model::user::request::CreateRequest, +) -> Result> { let hashed_password = hash(req.password, DEFAULT_COST); req.password = hashed_password.unwrap(); - match crate::repository::user::create(req.into()).await { + match crate::model::user::create(req.into()).await { Ok(mut user) => { user.simplify(); return Ok(user); @@ -27,28 +33,33 @@ pub async fn create(mut req: crate::model::user::request::CreateRequest) -> Resu } } -pub async fn update(mut req: crate::model::user::request::UpdateRequest) -> Result<(), Box> { +pub async fn update( + mut req: crate::model::user::request::UpdateRequest, +) -> Result<(), Box> { if let Some(password) = req.password { let hashed_password = hash(password, DEFAULT_COST); req.password = Some(hashed_password.unwrap()); } - match crate::repository::user::update(req.into()).await { + match crate::model::user::update(req.into()).await { Ok(_) => return Ok(()), Err(err) => return Err(Box::new(err)), } } pub async fn delete(id: i64) -> Result<(), Box> { - match crate::repository::user::delete(id).await { + match crate::model::user::delete(id).await { Ok(()) => return Ok(()), Err(err) => return Err(Box::new(err)), } } -pub async fn login(req: crate::model::user::request::LoginRequest) -> Result<(crate::model::user::Model, String), Box> { - let (users, total) = crate::repository::user::find(None, None, Some(req.username), None, None, None, None) - .await - .unwrap(); +pub async fn login( + req: crate::model::user::request::LoginRequest, +) -> Result<(crate::model::user::Model, String), Box> { + let (users, total) = + crate::model::user::find(None, None, Some(req.username), None, None, None, None) + .await + .unwrap(); if total == 0 { return Err("user_not_found".into()); @@ -68,8 +79,20 @@ pub async fn login(req: crate::model::user::request::LoginRequest) -> Result<(cr return Ok((user, token)); } -pub async fn register(req: crate::model::user::request::RegisterRequest) -> Result { - match crate::repository::user::find(None, None, Some(req.clone().username), None, None, None, None).await { +pub async fn register( + req: crate::model::user::request::RegisterRequest, +) -> Result { + match crate::model::user::find( + None, + None, + Some(req.clone().username), + None, + None, + None, + None, + ) + .await + { Ok((_, total)) => { if total != 0 { return Err(StatusCode::CONFLICT); @@ -83,7 +106,7 @@ pub async fn register(req: crate::model::user::request::RegisterRequest) -> Resu user.password = Set(Some(hashed_password)); user.group = Set("user".to_string()); - match crate::repository::user::create(user).await { + match crate::model::user::create(user).await { Ok(user) => return Ok(user), Err(_err) => return Err(StatusCode::INTERNAL_SERVER_ERROR), } diff --git a/src/web/service/user_team.rs b/src/web/service/user_team.rs index bcab65db..547273d3 100644 --- a/src/web/service/user_team.rs +++ b/src/web/service/user_team.rs @@ -1,10 +1,15 @@ use std::error::Error; -pub async fn join(req: crate::model::user_team::request::JoinRequest) -> Result<(), Box> { - let (_, user_total) = crate::repository::user::find(Some(req.user_id), None, None, None, None, None, None) +pub async fn join( + req: crate::model::user_team::request::JoinRequest, +) -> Result<(), Box> { + let (_, user_total) = + crate::model::user::find(Some(req.user_id), None, None, None, None, None, None) + .await + .unwrap(); + let (teams, team_total) = crate::model::team::find(Some(req.team_id), None, None, None, None) .await .unwrap(); - let (teams, team_total) = crate::repository::team::find(Some(req.team_id), None, None, None, None).await.unwrap(); if user_total == 0 || team_total == 0 { return Err("invalid_user_or_team".into()); @@ -16,13 +21,15 @@ pub async fn join(req: crate::model::user_team::request::JoinRequest) -> Result< return Err("invalid_invite_token".into()); } - crate::repository::user_team::create(req.into()).await.unwrap(); + crate::model::user_team::create(req.into()).await.unwrap(); return Ok(()); } -pub async fn create(req: crate::model::user_team::request::CreateRequest) -> Result<(), Box> { - match crate::repository::user_team::create(req.into()).await { +pub async fn create( + req: crate::model::user_team::request::CreateRequest, +) -> Result<(), Box> { + match crate::model::user_team::create(req.into()).await { Ok(_) => { return Ok(()); } @@ -33,7 +40,7 @@ pub async fn create(req: crate::model::user_team::request::CreateRequest) -> Res } pub async fn delete(user_id: i64, team_id: i64) -> Result<(), Box> { - match crate::repository::user_team::delete(user_id, team_id).await { + match crate::model::user_team::delete(user_id, team_id).await { Ok(_) => { return Ok(()); }