diff --git a/.env.example b/.env.example
index 47e599c..31e7a04 100644
--- a/.env.example
+++ b/.env.example
@@ -7,6 +7,5 @@ DATABASE_PASSWORD=P@$$W0RD
MAIN_URL=http://localhost:3000
SERVER_PORT=8181
JWT_SECRET=jwt_secrete
-ADMIN_PASSWORD=P@$$W0RD
-SMTP_EMAIL=example@example.example
-SMTP_PASSWORD=P@$$W0RD
\ No newline at end of file
+ADMIN_NAME=L0g1N
+ADMIN_PASSWORD=P@SSW0RD
diff --git a/.gitignore b/.gitignore
index 5f32e70..836600a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
target/
-.env
\ No newline at end of file
+.env
+.idea/
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 897e722..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
diff --git a/.idea/ExternalDeptBackend.iml b/.idea/ExternalDeptBackend.iml
deleted file mode 100644
index cf84ae4..0000000
--- a/.idea/ExternalDeptBackend.iml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
deleted file mode 100644
index a55e7a1..0000000
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index df87cf9..0000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
deleted file mode 100644
index 1a79a9a..0000000
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 935d22e..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index c9a217c..07f39d2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -23,6 +23,8 @@ dependencies = [
"serde_json",
"thiserror 2.0.5",
"tokio",
+ "utoipa",
+ "utoipa-swagger-ui",
]
[[package]]
@@ -131,6 +133,15 @@ dependencies = [
"windows-sys 0.59.0",
]
+[[package]]
+name = "arbitrary"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
+dependencies = [
+ "derive_arbitrary",
+]
+
[[package]]
name = "async-stream"
version = "0.3.6"
@@ -237,6 +248,15 @@ version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
[[package]]
name = "blowfish"
version = "0.9.1"
@@ -354,6 +374,30 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+[[package]]
+name = "cpufeatures"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
[[package]]
name = "crypto-common"
version = "0.1.6"
@@ -408,6 +452,17 @@ dependencies = [
"powerfmt",
]
+[[package]]
+name = "derive_arbitrary"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "devise"
version = "0.4.2"
@@ -492,6 +547,16 @@ dependencies = [
"syn",
]
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+]
+
[[package]]
name = "displaydoc"
version = "0.2.5"
@@ -613,6 +678,16 @@ dependencies = [
"version_check",
]
+[[package]]
+name = "flate2"
+version = "1.0.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
[[package]]
name = "fnv"
version = "1.0.7"
@@ -1206,6 +1281,12 @@ dependencies = [
"scopeguard",
]
+[[package]]
+name = "lockfree-object-pool"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
+
[[package]]
name = "log"
version = "0.4.22"
@@ -1269,6 +1350,16 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+[[package]]
+name = "mime_guess"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@@ -1841,6 +1932,40 @@ dependencies = [
"uncased",
]
+[[package]]
+name = "rust-embed"
+version = "8.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0"
+dependencies = [
+ "rust-embed-impl",
+ "rust-embed-utils",
+ "walkdir",
+]
+
+[[package]]
+name = "rust-embed-impl"
+version = "8.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rust-embed-utils",
+ "syn",
+ "walkdir",
+]
+
+[[package]]
+name = "rust-embed-utils"
+version = "8.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d"
+dependencies = [
+ "sha2",
+ "walkdir",
+]
+
[[package]]
name = "rustc-demangle"
version = "0.1.24"
@@ -1903,6 +2028,15 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
[[package]]
name = "schannel"
version = "0.1.27"
@@ -2007,6 +2141,17 @@ dependencies = [
"serde",
]
+[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
[[package]]
name = "sharded-slab"
version = "0.1.7"
@@ -2031,6 +2176,12 @@ dependencies = [
"libc",
]
+[[package]]
+name = "simd-adler32"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
+
[[package]]
name = "simple_asn1"
version = "0.6.2"
@@ -2507,6 +2658,46 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+[[package]]
+name = "utoipa"
+version = "5.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "435c6f69ef38c9017b4b4eea965dfb91e71e53d869e896db40d1cf2441dd75c0"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_json",
+ "utoipa-gen",
+]
+
+[[package]]
+name = "utoipa-gen"
+version = "5.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a77d306bc75294fd52f3e99b13ece67c02c1a2789190a6f31d32f736624326f7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "utoipa-swagger-ui"
+version = "7.1.1-rc.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd1174c37d2bdc9a2ce8d94aa0baf3e3c4862f80b7b1fb592738f374ab9f8803"
+dependencies = [
+ "mime_guess",
+ "regex",
+ "rocket",
+ "rust-embed",
+ "serde",
+ "serde_json",
+ "url",
+ "utoipa",
+ "zip",
+]
+
[[package]]
name = "valuable"
version = "0.1.0"
@@ -2525,6 +2716,16 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
[[package]]
name = "want"
version = "0.3.1"
@@ -2610,6 +2811,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
@@ -2906,3 +3116,34 @@ dependencies = [
"quote",
"syn",
]
+
+[[package]]
+name = "zip"
+version = "2.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae9c1ea7b3a5e1f4b922ff856a129881167511563dc219869afe3787fc0c1a45"
+dependencies = [
+ "arbitrary",
+ "crc32fast",
+ "crossbeam-utils",
+ "displaydoc",
+ "flate2",
+ "indexmap",
+ "memchr",
+ "thiserror 2.0.5",
+ "zopfli",
+]
+
+[[package]]
+name = "zopfli"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
+dependencies = [
+ "bumpalo",
+ "crc32fast",
+ "lockfree-object-pool",
+ "log",
+ "once_cell",
+ "simd-adler32",
+]
diff --git a/Cargo.toml b/Cargo.toml
index fc36dc0..a213ef6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,5 +21,8 @@ rocket_cors = "0.6.0"
chrono = { version = "0.4", features = ["serde"] }
regex = "1.11.1"
diesel_migrations = "2.0"
+utoipa = { version = "5.1.0", features = ["chrono"] }
+utoipa-swagger-ui = { version = "7.1.1-rc.0", features = ["rocket"] }
+
[default.databases]
-postgres = { url = "{env:DATABASE_URL}" }
\ No newline at end of file
+postgres = { url = "{env:DATABASE_URL}" }
diff --git "a/\\" "b/\\"
deleted file mode 100644
index 9ab753e..0000000
--- "a/\\"
+++ /dev/null
@@ -1 +0,0 @@
-pub mod create_jwt;
diff --git a/api b/api
deleted file mode 100644
index e69de29..0000000
diff --git a/migrations/2024-12-12-214746_set_up_database/up.sql b/migrations/2024-12-12-214746_set_up_database/up.sql
index 5e99107..44ffd8e 100644
--- a/migrations/2024-12-12-214746_set_up_database/up.sql
+++ b/migrations/2024-12-12-214746_set_up_database/up.sql
@@ -4,16 +4,13 @@ CREATE TYPE hackathon_category_2024 AS ENUM ('education', 'military', 'web3_0',
CREATE TYPE type_media AS ENUM ('video', 'photo');
-- Function for Updated Timestamp
-CREATE
-OR REPLACE FUNCTION update_timestamp()
+CREATE OR REPLACE FUNCTION update_timestamp()
RETURNS TRIGGER AS $$
BEGIN
- NEW.updated_at
-= CURRENT_TIMESTAMP;
-RETURN NEW;
+ NEW.updated_at = CURRENT_TIMESTAMP;
+ RETURN NEW;
END;
-$$
-LANGUAGE plpgsql;
+$$ LANGUAGE plpgsql;
-- University Table
CREATE TABLE hackathon_university_2024
@@ -72,17 +69,15 @@ CREATE TRIGGER update_hackathon_user_updated_at
EXECUTE FUNCTION update_timestamp();
-- Trigger to Increment Team Member Count
-CREATE
-OR REPLACE FUNCTION increment_team_member_count()
+CREATE OR REPLACE FUNCTION increment_team_member_count()
RETURNS TRIGGER AS $$
BEGIN
-UPDATE hackathon_team_2024
-SET count_members = count_members + 1
-WHERE id = NEW.team_id;
-RETURN NEW;
+ UPDATE hackathon_team_2024
+ SET count_members = count_members + 1
+ WHERE id = NEW.team_id;
+ RETURN NEW;
END;
-$$
-LANGUAGE plpgsql;
+$$ LANGUAGE plpgsql;
CREATE TRIGGER increment_team_member_trigger
AFTER INSERT
@@ -90,13 +85,31 @@ CREATE TRIGGER increment_team_member_trigger
FOR EACH ROW
EXECUTE FUNCTION increment_team_member_count();
+-- Trigger to Decrement Team Member Count
+CREATE OR REPLACE FUNCTION decrement_team_member_count()
+RETURNS TRIGGER AS $$
+BEGIN
+ UPDATE hackathon_team_2024
+ SET count_members = count_members - 1
+ WHERE id = OLD.team_id;
+ RETURN OLD;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE TRIGGER decrement_team_member_trigger
+ AFTER DELETE OR UPDATE OF team_id
+ ON hackathon_user_2024
+ FOR EACH ROW
+ WHEN (OLD.team_id IS NOT NULL)
+ EXECUTE FUNCTION decrement_team_member_count();
+
-- News Table
CREATE TABLE news
(
id SERIAL PRIMARY KEY,
description TEXT NOT NULL,
preview_id INT,
- header VARCHAR(255) NOT NULL,
+ header VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
@@ -116,7 +129,8 @@ CREATE TABLE news_media
type_media type_media NOT NULL,
position INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ CONSTRAINT unique_position_per_news UNIQUE (news_id, position)
);
CREATE TRIGGER update_news_media_updated_at
@@ -130,7 +144,7 @@ CREATE TABLE announcement_banner
(
id SERIAL PRIMARY KEY,
src_url TEXT NOT NULL,
- type_media type_media NOT NULL,
+ type_media type_media NOT NULL DEFAULT 'photo',
description VARCHAR(255) NOT NULL,
showing BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
@@ -142,3 +156,4 @@ CREATE TRIGGER update_announcement_banner_updated_at
ON announcement_banner
FOR EACH ROW
EXECUTE FUNCTION update_timestamp();
+
diff --git a/src/api/admin/get.rs b/src/api/admin/get.rs
index 342d4a0..dd1a3af 100644
--- a/src/api/admin/get.rs
+++ b/src/api/admin/get.rs
@@ -1,9 +1,20 @@
-use crate::models::admin::admin_jwt;
-use log::info;
+use crate::{middleware::admin_token_match::AdminAuthData, utils::prelude_api::*};
use rocket::get;
-#[allow(dead_code)]
+#[utoipa::path(
+ get,
+ path = "/api/admin/get",
+ operation_id = "get_admin",
+ tag = "Admin",
+ responses(
+ (status = 200, description = "Successfully authenticated admin"),
+ (status = 401, description = "Unauthorized error"),
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
#[get("/admin/get")]
-pub async fn get(claims: admin_jwt::AdminJwt) {
- info!("Welcome, user with ID: {}", claims.admin_name);
+pub async fn get(admin: AdminAuthData) {
+ info!("Auth data admin: {:?}", admin);
}
diff --git a/src/api/admin/post.rs b/src/api/admin/post.rs
index 941a5b2..fedfcea 100644
--- a/src/api/admin/post.rs
+++ b/src/api/admin/post.rs
@@ -1,12 +1,22 @@
use crate::dto::request::admin::login_admin::LoginAdminData;
use crate::error::api_error::ApiError;
-use crate::models::admin::admin_jwt;
-use crate::utils::env_configuration::EnvConfiguration;
+use crate::middleware::admin_token_match::AdminAuthData;
use crate::utils::prelude_api::*;
use crate::utils::security;
use chrono::{Duration, Utc};
use rocket::post;
+#[utoipa::path(
+ post,
+ path = "/api/admin/login",
+ request_body = LoginAdminData,
+ operation_id = "login_admin",
+ tag = "Admin",
+ responses(
+ (status = 200, description = "Login successfully", body = String),
+ (status = 422, description = "Validation error", body = ApiErrorBody),
+ ),
+)]
#[post("/admin/login", data = "")]
pub async fn login(data: Json) -> Result {
let data = data.into_inner();
@@ -14,26 +24,16 @@ pub async fn login(data: Json) -> Result {
admin_name,
admin_password,
} = data;
- let password_env = EnvConfiguration::get().admin_password.to_owned();
- let name_env = EnvConfiguration::get().admin_name.to_owned();
- if name_env != admin_name {
- return Err(ApiError::ValidationError(
- "Error validation admin name".to_string(),
- ));
- }
- if password_env != admin_password {
- return Err(ApiError::ValidationError(
- "Error validation admin password".to_string(),
- ));
- }
- let my_claims = admin_jwt::AdminJwt {
+ let auth = AdminAuthData {
admin_password,
admin_name,
exp: (Utc::now() + Duration::hours(24)).timestamp() as u64,
};
- match security::encoded_data(&my_claims) {
+ auth.check_admin()?;
+
+ match security::encoded_data(&auth) {
Ok(token) => Ok(token),
Err(err) => Err(ApiError::TokenGenerationError(err.to_string())),
}
diff --git a/src/api/hackathon_2024/team/delete.rs b/src/api/hackathon_2024/team/delete.rs
index 14bc33a..bbbd2ad 100644
--- a/src/api/hackathon_2024/team/delete.rs
+++ b/src/api/hackathon_2024/team/delete.rs
@@ -1,9 +1,25 @@
-use crate::diesel::prelude::*;
-use crate::middleware::admin_match::AdminMatch;
+use crate::utils::prelude_api::*;
use rocket::delete;
+#[utoipa::path(
+ delete,
+ path = "/api/hackathon_2024/team/by_id/{id}",
+ tag = "Hackathon Team 2024",
+ operation_id = "delete_team_by_id",
+ params(
+ ("id" = i32, Path, description = "ID of the team to delete")
+ ),
+ responses(
+ (status = 200, description = "Team updated successfully"),
+ (status = 401, description = "Unauthorized error"),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
#[delete("/hackathon_2024/team/by_id/")]
-pub async fn by_id(db_pool: &DbState, id: i32, admin_match: AdminMatch) -> Result<(), ApiError> {
+pub async fn by_id(db_pool: &DbState, id: i32, admin_match: AdminAuthData) -> Result<(), ApiError> {
admin_match.check_admin()?;
let id = crate::diesel::utils::hackathon_2024::team::delete::by_id(db_pool, id)?;
info!("Successfully deleted team from hackathon_team_2024 with id {id}");
diff --git a/src/api/hackathon_2024/team/get.rs b/src/api/hackathon_2024/team/get.rs
index e10e5aa..65f1243 100644
--- a/src/api/hackathon_2024/team/get.rs
+++ b/src/api/hackathon_2024/team/get.rs
@@ -1,20 +1,40 @@
-use crate::diesel::models::hackathon_2024::team::HackathonTeam2024Queryable;
+use crate::dto::response::hackathon_2024::team::{Team, VecTeam};
use crate::utils::prelude_api::*;
use rocket::get;
+#[utoipa::path(
+ get,
+ path = "/api/hackathon_2024/team/all",
+ tag = "Hackathon Team 2024",
+ operation_id = "get_all_team",
+ responses(
+ (status = 200, description = "All team get successfully", body = Vec),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+)]
#[get("/hackathon_2024/team/all")]
-pub async fn all(db_pool: &DbState) -> Result>, ApiError> {
- Ok(Json(
+pub async fn all(db_pool: &DbState) -> Result, ApiError> {
+ Ok(Json(VecTeam(
crate::diesel::utils::hackathon_2024::team::fetch::all(db_pool)?,
- ))
+ )))
}
+#[utoipa::path(
+ get,
+ path = "/api/hackathon_2024/team/by_id/{id}",
+ tag = "Hackathon Team 2024",
+ operation_id = "get_team_by_id",
+ params(
+ ("id" = i32, Path, description = "ID of the team to get")
+ ),
+ responses(
+ (status = 200, description = "Team get successfully", body = Team),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+)]
#[get("/hackathon_2024/team/by_id/")]
-pub async fn by_id(
- db_pool: &DbState,
- id: i32,
-) -> Result, ApiError> {
- Ok(Json(
+pub async fn by_id(db_pool: &DbState, id: i32) -> Result, ApiError> {
+ Ok(Json(Team(
crate::diesel::utils::hackathon_2024::team::fetch::by_id(db_pool, id)?,
- ))
+ )))
}
diff --git a/src/api/hackathon_2024/team/post.rs b/src/api/hackathon_2024/team/post.rs
index 5db883d..503e3dd 100644
--- a/src/api/hackathon_2024/team/post.rs
+++ b/src/api/hackathon_2024/team/post.rs
@@ -3,6 +3,18 @@ use crate::utils::prelude_api::*;
use crate::utils::security::hashing_data;
use rocket::post;
+#[utoipa::path(
+ post,
+ path = "/api/hackathon_2024/team/create",
+ request_body = TeamCreateData,
+ tag = "Hackathon Team 2024",
+ operation_id = "create_team",
+ responses(
+ (status = 200, description = "Team created successfully"),
+ (status = 422, description = "Validation error", body = ApiErrorBody),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+)]
#[post("/hackathon_2024/team/create", data = "")]
pub async fn create(db_pool: &DbState, data: Json) -> Result<(), ApiError> {
let mut team = data.into_inner().0;
diff --git a/src/api/hackathon_2024/team/put.rs b/src/api/hackathon_2024/team/put.rs
index e1c5b52..d2fd0ea 100644
--- a/src/api/hackathon_2024/team/put.rs
+++ b/src/api/hackathon_2024/team/put.rs
@@ -1,13 +1,30 @@
use crate::dto::request::hackathon_2024::team::TeamUpdateData;
-use crate::middleware::admin_match::AdminMatch;
use crate::utils::prelude_api::*;
use rocket::put;
+#[utoipa::path(
+ put,
+ path = "/api/hackathon_2024/team/by_id",
+ tag = "Hackathon Team 2024",
+ request_body = TeamUpdateData,
+ operation_id = "put_team_by_id",
+ params(
+ ("id" = i32, Path, description = "ID of the team to update")
+ ),
+ responses(
+ (status = 200, description = "Team updated successfully"),
+ (status = 401, description = "Unauthorized error"),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
#[put("/hackathon_2024/team/by_id", data = "")]
pub async fn by_id(
db_pool: &DbState,
data: Json,
- admin_match: AdminMatch,
+ admin_match: AdminAuthData,
) -> Result<(), ApiError> {
admin_match.check_admin()?;
let data = data.into_inner();
diff --git a/src/api/hackathon_2024/university/delete.rs b/src/api/hackathon_2024/university/delete.rs
index cd0bde3..e33f5a9 100644
--- a/src/api/hackathon_2024/university/delete.rs
+++ b/src/api/hackathon_2024/university/delete.rs
@@ -1,9 +1,26 @@
-use crate::middleware::admin_match::AdminMatch;
use crate::utils::prelude_api::*;
use rocket::delete;
+#[utoipa::path(
+ delete,
+ path = "/api/hackathon_2024/university/by_id/{id}",
+ tag = "Hackathon University 2024",
+ operation_id = "delete_university_by_id",
+ responses(
+ (status = 200, description = "University deleted successfully"),
+ (status = 401, description = "Unauthorized error"),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+ operation_id = "delete_university_by_id",
+ params(
+ ("id" = i32, Path, description = "ID of the university to delete")
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
#[delete("/hackathon_2024/university/by_id/")]
-pub async fn by_id(db_pool: &DbState, id: i32, admin_match: AdminMatch) -> Result<(), ApiError> {
+pub async fn by_id(db_pool: &DbState, id: i32, admin_match: AdminAuthData) -> Result<(), ApiError> {
admin_match.check_admin()?;
let id = crate::diesel::utils::hackathon_2024::university::delete::by_id(db_pool, id)?;
info!("Successfully deleted university from hackathon_university_2024 with id {id}");
diff --git a/src/api/hackathon_2024/university/get.rs b/src/api/hackathon_2024/university/get.rs
index 817785a..e548b5f 100644
--- a/src/api/hackathon_2024/university/get.rs
+++ b/src/api/hackathon_2024/university/get.rs
@@ -2,6 +2,16 @@ use crate::dto::response::hackathon_2024::university::{University, VecUniversity
use crate::utils::prelude_api::*;
use rocket::get;
+#[utoipa::path(
+ get,
+ path = "/api/hackathon_2024/university/all",
+ tag = "Hackathon University 2024",
+ operation_id = "get_all_university",
+ responses(
+ (status = 200, description = "All university fetched successfully", body = Vec),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+)]
#[get("/hackathon_2024/university/all")]
pub async fn all(db_pool: &DbState) -> Result, ApiError> {
Ok(Json(VecUniversity(
@@ -9,6 +19,20 @@ pub async fn all(db_pool: &DbState) -> Result, ApiError> {
)))
}
+#[utoipa::path(
+ get,
+ path = "/api/hackathon_2024/university/by_id/{id}",
+ tag = "Hackathon University 2024",
+ operation_id = "get_university_by_id",
+ params(
+ ("id" = i32, Path, description = "ID of the university to fetch")
+ ),
+ responses(
+ (status = 200, description = "Single university fetched by id successfully", body = University),
+ (status = 401, description = "Unauthorized error"),
+ (status = 500, description = "Database error"),
+ ),
+)]
#[get("/hackathon_2024/university/by_id/")]
pub async fn by_id(db_pool: &DbState, id: i32) -> Result, ApiError> {
Ok(Json(University(
diff --git a/src/api/hackathon_2024/university/post.rs b/src/api/hackathon_2024/university/post.rs
index 17c2514..931f891 100644
--- a/src/api/hackathon_2024/university/post.rs
+++ b/src/api/hackathon_2024/university/post.rs
@@ -1,13 +1,26 @@
-use crate::dto::request::hackathon_2024::university::University;
-use crate::middleware::admin_match::AdminMatch;
+use crate::dto::request::hackathon_2024::university::{University, VecUniversity};
use crate::utils::prelude_api::*;
use rocket::post;
+#[utoipa::path(
+ post,
+ path = "/api/hackathon_2024/university/create",
+ request_body = University, tag = "Hackathon University 2024",
+ operation_id = "create_university",
+ responses(
+ (status = 200, description = "University created successfully"),
+ (status = 401, description = "Unauthorized error", body = ApiErrorBody),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
#[post("/hackathon_2024/university/create", data = "")]
pub async fn create(
db_pool: &DbState,
data: Json,
- admin_match: AdminMatch,
+ admin_match: AdminAuthData,
) -> Result<(), ApiError> {
admin_match.check_admin()?;
let id = crate::diesel::utils::hackathon_2024::university::insert::new(
@@ -17,3 +30,32 @@ pub async fn create(
info!("Succeed insert new university with id - {id}");
Ok(())
}
+
+#[utoipa::path(
+ post,
+ path = "/api/hackathon_2024/university/create_by_vec",
+ request_body = Vec, tag = "Hackathon University 2024",
+ operation_id = "create_university_by_vec",
+ responses(
+ (status = 200, description = "Vec university created successfully"),
+ (status = 401, description = "Unauthorized error", body = ApiErrorBody),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
+#[post("/hackathon_2024/university/create_by_vec", data = "")]
+pub async fn create_by_vec(
+ db_pool: &DbState,
+ data: Json,
+ admin_match: AdminAuthData,
+) -> Result<(), ApiError> {
+ admin_match.check_admin()?;
+ let id = crate::diesel::utils::hackathon_2024::university::insert::new_by_vec(
+ db_pool,
+ data.into_inner().0,
+ )?;
+ info!("Succeed insert new university with id - {id}");
+ Ok(())
+}
diff --git a/src/api/hackathon_2024/university/put.rs b/src/api/hackathon_2024/university/put.rs
index 6a6e0fe..b8f32b8 100644
--- a/src/api/hackathon_2024/university/put.rs
+++ b/src/api/hackathon_2024/university/put.rs
@@ -1,13 +1,29 @@
use crate::dto::request::hackathon_2024::university::University;
-use crate::middleware::admin_match::AdminMatch;
use crate::utils::prelude_api::*;
use rocket::put;
+#[utoipa::path(
+ put,
+ path = "/api/hackathon_2024/university/by_id/{id}",
+ request_body = University, tag = "Hackathon University 2024",
+ operation_id = "put_university_by_id",
+ params(
+ ("id" = i32, Path, description = "ID of the university to update")
+ ),
+ responses(
+ (status = 200, description = "University updated successfully"),
+ (status = 401, description = "Unauthorized error"),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
#[put("/hackathon_2024/university/by_id/", data = "")]
pub async fn by_id(
db_pool: &DbState,
id: i32,
- admin_match: AdminMatch,
+ admin_match: AdminAuthData,
data: Json,
) -> Result<(), ApiError> {
admin_match.check_admin()?;
diff --git a/src/api/hackathon_2024/user/delete.rs b/src/api/hackathon_2024/user/delete.rs
index de1c3c9..3d5deb9 100644
--- a/src/api/hackathon_2024/user/delete.rs
+++ b/src/api/hackathon_2024/user/delete.rs
@@ -1,14 +1,28 @@
-use crate::diesel::configurator::DbPool;
-use crate::error::api_error::ApiError;
-use crate::middleware::admin_match::AdminMatch;
-use log::info;
-use rocket::{delete, State};
+use crate::utils::prelude_api::*;
+use rocket::delete;
+#[utoipa::path(
+ delete,
+ path = "/api/hackathon_2024/user/by_id/{user_id}",
+ tag = "Hackathon User 2024",
+ operation_id = "update_user_by_id",
+ params(
+ ("id" = i32, Path, description = "ID of the user to delete")
+ ),
+ responses(
+ (status = 200, description = "User deleted successfully"),
+ (status = 401, description = "Unauthorized error"),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
#[delete("/hackathon_2024/user/by_id/")]
pub async fn by_id(
- db_pool: &State,
+ db_pool: &DbState,
user_id: i32,
- admin_match: AdminMatch,
+ admin_match: AdminAuthData,
) -> Result<(), ApiError> {
admin_match.check_admin()?;
let user_id = crate::diesel::utils::hackathon_2024::user::delete::by_id(db_pool, user_id)?;
diff --git a/src/api/hackathon_2024/user/get.rs b/src/api/hackathon_2024/user/get.rs
index 17de422..9104ea1 100644
--- a/src/api/hackathon_2024/user/get.rs
+++ b/src/api/hackathon_2024/user/get.rs
@@ -1,7 +1,6 @@
use crate::api::hackathon_2024::user::local::create_user_by_jwt;
use crate::dto::response::hackathon_2024::user::User;
use crate::dto::response::hackathon_2024::user::VecUser;
-use crate::middleware::admin_match::AdminMatch;
use crate::middleware::claims::Claims;
use crate::utils::prelude_api::*;
use crate::utils::security::decoded_data;
@@ -14,6 +13,19 @@ pub async fn confirm_new_user(db_pool: &DbState, jwt_token: String) -> Result<()
}
#[allow(dead_code)]
+#[utoipa::path(
+ get,
+ path = "/api/hackathon_2024/user/authorization_user",
+ tag = "Hackathon User 2024",
+ operation_id = "get_authorization_user",
+ responses(
+ (status = 200, description = "User fetched successfully", body = User),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
#[get("/hackathon_2024/user/authorization_user")]
pub async fn authorization_user(db_pool: &DbState, claims: Claims) -> Result, ApiError> {
Ok(Json(User(
@@ -21,10 +33,105 @@ pub async fn authorization_user(db_pool: &DbState, claims: Claims) -> Result),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
#[get("/hackathon_2024/user/all")]
-pub async fn all(db_pool: &DbState, admin_match: AdminMatch) -> Result, ApiError> {
+pub async fn all(db_pool: &DbState, admin_match: AdminAuthData) -> Result, ApiError> {
admin_match.check_admin()?;
Ok(Json(VecUser(
crate::diesel::utils::hackathon_2024::user::fetch::all(db_pool)?,
)))
}
+
+#[utoipa::path(
+ get,
+ path = "/api/hackathon_2024/user/by_id/{id}",
+ tag = "Hackathon User 2024",
+ operation_id = "get_user_by_id",
+ params(
+ ("id" = i32, Path, description = "ID of the user to fetch")
+ ),
+ responses(
+ (status = 200, description = "User fetched successfully", body = User),
+ (status = 401, description = "Unauthorized error"),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
+#[get("/hackathon_2024/user/by_id/")]
+pub async fn by_id(
+ db_pool: &DbState,
+ id: i32,
+ admin_match: AdminAuthData,
+) -> Result, ApiError> {
+ admin_match.check_admin()?;
+ Ok(Json(User(
+ crate::diesel::utils::hackathon_2024::user::fetch::by_id(db_pool, id)?,
+ )))
+}
+
+#[utoipa::path(
+ get,
+ path = "/api/hackathon_2024/user/by_university/{id}",
+ tag = "Hackathon User 2024",
+ operation_id = "get_user_by_university",
+ params(
+ ("id" = i32, Path, description = "ID of the user`s university to fetch")
+ ),
+ responses(
+ (status = 200, description = "User fetched successfully", body = Vec),
+ (status = 401, description = "Unauthorized error"),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
+#[get("/hackathon_2024/user/by_university/")]
+pub async fn by_university(
+ db_pool: &DbState,
+ id: i32,
+ admin_match: AdminAuthData,
+) -> Result, ApiError> {
+ admin_match.check_admin()?;
+ Ok(Json(VecUser(
+ crate::diesel::utils::hackathon_2024::user::fetch::by_university(db_pool, id)?,
+ )))
+}
+
+#[utoipa::path(
+ get,
+ path = "/api/hackathon_2024/user/by_team/{id}",
+ tag = "Hackathon User 2024",
+ operation_id = "get_user_by_team",
+ params(
+ ("id" = i32, Path, description = "ID of the user`s team to fetch")
+ ),
+ responses(
+ (status = 200, description = "User fetched successfully", body = Vec),
+ (status = 401, description = "Unauthorized error"),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
+#[get("/hackathon_2024/user/by_team/")]
+pub async fn by_team(db_pool: &DbState, id: i32) -> Result, ApiError> {
+ Ok(Json(VecUser(
+ crate::diesel::utils::hackathon_2024::user::fetch::by_team(db_pool, id)?,
+ )))
+}
diff --git a/src/api/hackathon_2024/user/post.rs b/src/api/hackathon_2024/user/post.rs
index 5a79856..56a5958 100644
--- a/src/api/hackathon_2024/user/post.rs
+++ b/src/api/hackathon_2024/user/post.rs
@@ -4,6 +4,18 @@ use crate::utils::security::verify_password;
use crate::utils::validation;
use rocket::post;
+#[utoipa::path(
+ post,
+ path = "/api/hackathon_2024/user/registration_by_tg",
+ request_body = RegistrationData,
+ tag = "Hackathon User 2024",
+ operation_id = "user_registration_by_tg",
+ responses(
+ (status = 200, description = "User registration successfully"),
+ (status = 422, description = "Validation error", body = ApiErrorBody),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+)]
#[post("/hackathon_2024/user/registration_by_tg", data = "")]
pub async fn registration_by_tg(
db_pool: &DbState,
diff --git a/src/api/hackathon_2024/user/put.rs b/src/api/hackathon_2024/user/put.rs
index 9a3ff78..3b47c96 100644
--- a/src/api/hackathon_2024/user/put.rs
+++ b/src/api/hackathon_2024/user/put.rs
@@ -1,17 +1,35 @@
use crate::dto::request::hackathon_2024::user::User;
-use crate::middleware::admin_match::AdminMatch;
use crate::utils::prelude_api::*;
use rocket::put;
-#[put("/hackathon_2024/user/by_id/", data = "")]
+
+#[utoipa::path(
+ put,
+ path = "/api/hackathon_2024/user/by_id/{id}",
+ request_body = User,
+ tag = "Hackathon User 2024",
+ operation_id = "update_user_by_id",
+ params(
+ ("id" = i32, Path, description = "ID of the user to update")
+ ),
+ responses(
+ (status = 200, description = "User updated successfully", body = String),
+ (status = 401, description = "Unauthorized error"),
+ (status = 500, description = "Database error", body = ApiErrorBody),
+ ),
+ security(
+ ("bearer_auth" = [])
+ )
+)]
+#[put("/hackathon_2024/user/by_id/", data = "")]
pub async fn by_id(
db_pool: &DbState,
data: Json,
- user_id: i32,
- admin_match: AdminMatch,
+ id: i32,
+ admin_match: AdminAuthData,
) -> Result {
admin_match.check_admin()?;
let data = data.into_inner();
- crate::diesel::utils::hackathon_2024::user::update::by_id(db_pool, user_id, &data.0)?;
+ crate::diesel::utils::hackathon_2024::user::update::by_id(db_pool, id, &data.0)?;
Ok(format!(
"Successfully updated hackathon_user_2024 with email: {}",
data.0.nickname_tg
diff --git a/src/api/test/get.rs b/src/api/test/get.rs
index 2e5dbb7..b23866a 100644
--- a/src/api/test/get.rs
+++ b/src/api/test/get.rs
@@ -1,7 +1,14 @@
use rocket::get;
use rocket::serde::json::Json;
-#[allow(dead_code)]
+#[utoipa::path(
+ get,
+ tag = "Test",
+ path = "/api/test/ping",
+ responses(
+ (status = 200, description = "Ping the server to check if it's running", body = String)
+ )
+)]
#[get("/test/ping")]
pub async fn ping() -> Json<&'static str> {
Json("pong")
diff --git a/src/diesel/configurator.rs b/src/diesel/configurator.rs
index 373411a..acfcb00 100644
--- a/src/diesel/configurator.rs
+++ b/src/diesel/configurator.rs
@@ -1,3 +1,4 @@
+use super::prelude::DbState;
use crate::error::api_error::ApiError;
use crate::utils::constants::diesel::MIGRATIONS;
use crate::utils::env_configuration::EnvConfiguration;
@@ -6,7 +7,6 @@ use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
use diesel::sql_types::Text;
use diesel::RunQueryDsl;
use diesel_migrations::MigrationHarness;
-use rocket::State;
pub type DbPool = Pool>;
@@ -73,7 +73,7 @@ pub fn configuration_database() -> DbPool {
}
pub fn get_connection(
- db_pool: &State,
+ db_pool: &DbState,
) -> Result>, ApiError> {
db_pool
.get()
diff --git a/src/diesel/models/hackathon_2024/category.rs b/src/diesel/models/hackathon_2024/category.rs
index 06ddd54..19e1bf0 100644
--- a/src/diesel/models/hackathon_2024/category.rs
+++ b/src/diesel/models/hackathon_2024/category.rs
@@ -11,7 +11,18 @@ use serialize::IsNull;
use std::fmt::Debug;
use std::io::Write;
-#[derive(Debug, Clone, Copy, PartialEq, Eq, FromSqlRow, AsExpression, Deserialize, Serialize)]
+#[derive(
+ Debug,
+ Clone,
+ Copy,
+ PartialEq,
+ Eq,
+ FromSqlRow,
+ AsExpression,
+ Deserialize,
+ Serialize,
+ utoipa::ToSchema,
+)]
#[diesel(sql_type = crate::diesel::schema::sql_types::HackathonCategory2024)]
pub enum HackathonCategory2024Enum {
Education,
diff --git a/src/diesel/models/hackathon_2024/team.rs b/src/diesel/models/hackathon_2024/team.rs
index c9dedea..1b62145 100644
--- a/src/diesel/models/hackathon_2024/team.rs
+++ b/src/diesel/models/hackathon_2024/team.rs
@@ -3,36 +3,36 @@ use chrono::NaiveDateTime;
use diesel::{Insertable, Queryable};
use serde::{Deserialize, Serialize};
-#[derive(Debug, Queryable, Serialize)]
+#[derive(Debug, Queryable, Serialize, utoipa::ToSchema)]
#[diesel(table_name = crate::diesel::schema::hackathon_team_2024)]
pub struct HackathonTeam2024Queryable {
- #[allow(dead_code)]
+ #[schema(example = "1")]
pub id: i32,
- #[allow(dead_code)]
+ #[schema(example = "Team 1")]
pub name: String,
- #[allow(dead_code)]
+ #[schema(example = "Education")]
pub category: HackathonCategory2024Enum,
- #[allow(dead_code)]
+ #[schema(example = "$2b$12$9pK8ha/nYGLwRWG53UK/EuOlGYJjS/aXPCPKxdX3o7UfiuQrtFDiq")]
pub password_registration: String,
- #[allow(dead_code)]
+ #[schema(example = "2")]
pub count_members: i32,
- #[allow(dead_code)]
- pub email: String,
- #[allow(dead_code)]
+ #[schema(example = "skalse_456")]
+ pub nickname_tg: String,
+ #[schema(example = "2025-01-19T15:06:19.027744")]
pub created_at: Option,
- #[allow(dead_code)]
+ #[schema(example = "2025-01-19T15:06:19.027744")]
pub updated_at: Option,
}
-#[derive(Insertable, Debug, Deserialize, Serialize)]
+#[derive(Insertable, Debug, Deserialize, Serialize, utoipa::ToSchema)]
#[diesel(table_name = crate::diesel::schema::hackathon_team_2024)]
pub struct HackathonTeam2024Insertable {
- #[allow(dead_code)]
+ #[schema(example = "Team 1")]
pub name: String,
- #[allow(dead_code)]
+ #[schema(example = "Education")]
pub category: HackathonCategory2024Enum,
- #[allow(dead_code)]
+ #[schema(example = "real_password123!AAA")]
pub password_registration: String,
- #[allow(dead_code)]
+ #[schema(example = "skalse_456")]
pub nickname_tg: String,
}
diff --git a/src/diesel/models/hackathon_2024/university.rs b/src/diesel/models/hackathon_2024/university.rs
index 6ff5322..a2251a9 100644
--- a/src/diesel/models/hackathon_2024/university.rs
+++ b/src/diesel/models/hackathon_2024/university.rs
@@ -1,22 +1,24 @@
use chrono::NaiveDateTime;
use diesel::{Insertable, Queryable};
use serde::{Deserialize, Serialize};
+use utoipa::ToSchema;
-#[derive(Debug, Queryable, Serialize)]
+#[derive(Debug, Queryable, Serialize, ToSchema)]
#[diesel(table_name = crate::diesel::schema::hackathon_university_2024)]
pub struct HackathonUniversity2024Queryable {
- #[allow(dead_code)]
+ #[schema(example = "1")]
pub id: i32,
- #[allow(dead_code)]
+ #[schema(example = "Innovation University")]
pub name: String,
- #[allow(dead_code)]
+ #[schema(example = "2025-01-19T15:06:19.027744")]
pub created_at: Option,
- #[allow(dead_code)]
+ #[schema(example = "2025-01-19T15:06:19.027744")]
pub updated_at: Option,
}
-#[derive(Insertable, Debug, Deserialize, Serialize)]
+#[derive(Insertable, Debug, Deserialize, Serialize, ToSchema)]
#[diesel(table_name = crate::diesel::schema::hackathon_university_2024)]
pub struct HackathonUniversity2024Insertable {
+ #[schema(example = "Innovation University")]
pub name: String,
}
diff --git a/src/diesel/models/hackathon_2024/user.rs b/src/diesel/models/hackathon_2024/user.rs
index d895d78..18a7894 100644
--- a/src/diesel/models/hackathon_2024/user.rs
+++ b/src/diesel/models/hackathon_2024/user.rs
@@ -1,37 +1,44 @@
use chrono::NaiveDateTime;
use diesel::{Insertable, Queryable};
use serde::{Deserialize, Serialize};
+use utoipa::ToSchema;
-#[derive(Debug, Queryable, Serialize)]
+#[derive(Debug, Queryable, Serialize, ToSchema)]
#[diesel(table_name = crate::diesel::schema::hackathon_user_2024)]
pub struct HackathonUser2024Queryable {
- #[allow(dead_code)]
+ #[schema(example = "1")]
pub id: i32,
- #[allow(dead_code)]
+ #[schema(example = "Skalse")]
pub first_name: String,
- #[allow(dead_code)]
+ #[schema(example = "Batya")]
pub last_name: String,
- #[allow(dead_code)]
+ #[schema(example = "skalse_456")]
pub nickname_tg: String,
- #[allow(dead_code)]
+ #[schema(example = "1234567890")]
pub phone: String,
- #[allow(dead_code)]
+ #[schema(example = "1")]
pub university_id: Option,
- #[allow(dead_code)]
+ #[schema(example = "1")]
pub team_id: Option,
- #[allow(dead_code)]
+ #[schema(example = "2025-01-19T15:06:19.027744")]
pub created_at: Option,
- #[allow(dead_code)]
+ #[schema(example = "2025-01-19T15:06:19.027744")]
pub updated_at: Option,
}
-#[derive(Insertable, Debug, Deserialize, Serialize)]
+#[derive(Insertable, Debug, Deserialize, Serialize, ToSchema)]
#[diesel(table_name = crate::diesel::schema::hackathon_user_2024)]
pub struct HackathonUser2024Insertable {
+ #[schema(example = "Skalse")]
pub first_name: String,
+ #[schema(example = "Batya")]
pub last_name: String,
+ #[schema(example = "skalse_456")]
pub nickname_tg: String,
+ #[schema(example = "+380123456789")]
pub phone: String,
+ #[schema(example = "1")]
pub university_id: i32,
+ #[schema(example = "1")]
pub team_id: i32,
}
diff --git a/src/diesel/prelude.rs b/src/diesel/prelude.rs
index 8009d47..b481818 100644
--- a/src/diesel/prelude.rs
+++ b/src/diesel/prelude.rs
@@ -5,6 +5,5 @@ pub use diesel::ExpressionMethods;
pub use diesel::QueryDsl;
pub use diesel::RunQueryDsl;
pub use log::error;
-pub use log::info;
pub use rocket::State;
pub type DbState = State;
diff --git a/src/diesel/utils/hackathon_2024/team/delete.rs b/src/diesel/utils/hackathon_2024/team/delete.rs
index 740646d..31d6a07 100644
--- a/src/diesel/utils/hackathon_2024/team/delete.rs
+++ b/src/diesel/utils/hackathon_2024/team/delete.rs
@@ -10,6 +10,6 @@ pub fn by_id(db_pool: &State, id: i32) -> Result {
.execute(&mut get_connection(db_pool)?)
.map_err(|err| {
error!("Error deleting hackathon_university_2024 with id {id}");
- ApiError::DatabaseErrorResult(err)
+ err.into()
})
}
diff --git a/src/diesel/utils/hackathon_2024/team/fetch.rs b/src/diesel/utils/hackathon_2024/team/fetch.rs
index 28bd95a..32a695f 100644
--- a/src/diesel/utils/hackathon_2024/team/fetch.rs
+++ b/src/diesel/utils/hackathon_2024/team/fetch.rs
@@ -1,14 +1,16 @@
use crate::diesel::models::hackathon_2024::team::HackathonTeam2024Queryable;
use crate::diesel::prelude::*;
use crate::diesel::schema::hackathon_team_2024::dsl::hackathon_team_2024;
+
pub fn by_id(db_pool: &DbState, team_id: i32) -> Result {
hackathon_team_2024
.filter(crate::diesel::schema::hackathon_team_2024::columns::id.eq(team_id))
.first::(&mut get_connection(db_pool)?)
- .map_err(ApiError::DatabaseErrorResult)
+ .map_err(|err| err.into())
}
+
pub fn all(db_pool: &State) -> Result, ApiError> {
hackathon_team_2024
.load::(&mut get_connection(db_pool)?)
- .map_err(ApiError::DatabaseErrorResult)
+ .map_err(|err| err.into())
}
diff --git a/src/diesel/utils/hackathon_2024/team/insert.rs b/src/diesel/utils/hackathon_2024/team/insert.rs
index 7911dbd..8e93945 100644
--- a/src/diesel/utils/hackathon_2024/team/insert.rs
+++ b/src/diesel/utils/hackathon_2024/team/insert.rs
@@ -9,6 +9,6 @@ pub fn new(db_pool: &DbState, data: HackathonTeam2024Insertable) -> Result(&mut db_connection)
.map_err(|err| {
error!("Error inserting hackathon 2024 team with id - {:?}", err);
- ApiError::DatabaseErrorResult(err)
+ err.into()
})
}
diff --git a/src/diesel/utils/hackathon_2024/team/update.rs b/src/diesel/utils/hackathon_2024/team/update.rs
index a71f78e..6f2d45c 100644
--- a/src/diesel/utils/hackathon_2024/team/update.rs
+++ b/src/diesel/utils/hackathon_2024/team/update.rs
@@ -18,6 +18,6 @@ pub fn by_data(db_pool: &DbState, data: &TeamUpdateData) -> Result Result {
- diesel::delete(
- hackathon_university_2024
- .filter(crate::diesel::schema::hackathon_university_2024::id.eq(id)),
- )
- .execute(&mut get_connection(db_pool)?)
- .map_err(|err| {
- log::error!("Error deleting university from hackathon_university_2024 with id {id}");
- ApiError::DatabaseErrorResult(err)
- })
+pub fn by_id(db_pool: &DbState, delete_id: i32) -> Result {
+ diesel::delete(hackathon_university_2024.filter(id.eq(delete_id)))
+ .returning(id)
+ .get_result(&mut get_connection(db_pool)?)
+ .map_err(|err| {
+ error!("Error deleting university from hackathon_university_2024 with id {delete_id}");
+ err.into()
+ })
}
diff --git a/src/diesel/utils/hackathon_2024/university/fetch.rs b/src/diesel/utils/hackathon_2024/university/fetch.rs
index 28155ed..eaf0dac 100644
--- a/src/diesel/utils/hackathon_2024/university/fetch.rs
+++ b/src/diesel/utils/hackathon_2024/university/fetch.rs
@@ -1,20 +1,22 @@
use crate::diesel::models::hackathon_2024::university::HackathonUniversity2024Queryable;
use crate::diesel::prelude::*;
use crate::diesel::schema::hackathon_university_2024::dsl::hackathon_university_2024;
+
pub fn by_id(db_pool: &DbState, id: i32) -> Result {
hackathon_university_2024
.filter(crate::diesel::schema::hackathon_university_2024::columns::id.eq(id))
.first::(&mut get_connection(db_pool)?)
.map_err(|err| {
error!("Error to get hackathon_university_2024 with id {id}");
- ApiError::DatabaseErrorResult(err)
+ err.into()
})
}
+
pub fn all(db_pool: &State) -> Result, ApiError> {
hackathon_university_2024
.load::(&mut get_connection(db_pool)?)
.map_err(|err| {
error!("Error to get all hackathon_university_2024");
- ApiError::DatabaseErrorResult(err)
+ err.into()
})
}
diff --git a/src/diesel/utils/hackathon_2024/university/insert.rs b/src/diesel/utils/hackathon_2024/university/insert.rs
index b7d10da..2233fbd 100644
--- a/src/diesel/utils/hackathon_2024/university/insert.rs
+++ b/src/diesel/utils/hackathon_2024/university/insert.rs
@@ -15,6 +15,24 @@ pub fn new(
"Error inserting hackathon 2024 university with id - {:?}",
err
);
- ApiError::DatabaseErrorResult(err)
+ err.into()
+ })
+}
+
+pub fn new_by_vec(
+ db_pool: &State,
+ data: Vec,
+) -> Result {
+ let mut db_connection = get_connection(db_pool)?;
+ diesel::insert_into(crate::diesel::schema::hackathon_university_2024::table)
+ .values(data)
+ .returning(crate::diesel::schema::hackathon_university_2024::id)
+ .get_result::(&mut db_connection)
+ .map_err(|err| {
+ error!(
+ "Error inserting hackathon 2024 university with id - {:?}",
+ err
+ );
+ err.into()
})
}
diff --git a/src/diesel/utils/hackathon_2024/university/update.rs b/src/diesel/utils/hackathon_2024/university/update.rs
index dfa9069..72d0fbd 100644
--- a/src/diesel/utils/hackathon_2024/university/update.rs
+++ b/src/diesel/utils/hackathon_2024/university/update.rs
@@ -7,15 +7,16 @@ pub fn by_id(
db_pool: &State,
university_id: i32,
data: HackathonUniversity2024Insertable,
-) -> Result {
+) -> Result {
diesel::update(hackathon_university_2024.filter(id.eq(university_id)))
.set((
name.eq(data.name),
updated_at.eq(chrono::Utc::now().naive_utc()),
))
- .execute(&mut get_connection(db_pool)?)
+ .returning(id)
+ .get_result(&mut get_connection(db_pool)?)
.map_err(|err| {
error!("Error updating hackathon_university_2024");
- ApiError::DatabaseErrorResult(err)
+ err.into()
})
}
diff --git a/src/diesel/utils/hackathon_2024/user/delete.rs b/src/diesel/utils/hackathon_2024/user/delete.rs
index d5b4d76..1965ec5 100644
--- a/src/diesel/utils/hackathon_2024/user/delete.rs
+++ b/src/diesel/utils/hackathon_2024/user/delete.rs
@@ -2,11 +2,11 @@ use crate::diesel::prelude::*;
use crate::diesel::schema::hackathon_user_2024::dsl::hackathon_user_2024;
use crate::diesel::schema::hackathon_user_2024::id;
-pub fn by_id(db_pool: &State, user_id: i32) -> Result {
+pub fn by_id(db_pool: &DbState, user_id: i32) -> Result {
diesel::delete(hackathon_user_2024.filter(id.eq(user_id)))
.execute(&mut get_connection(db_pool)?)
.map_err(|err| {
error!("Error deleting hackathon_user_2024");
- ApiError::DatabaseErrorResult(err)
+ err.into()
})
}
diff --git a/src/diesel/utils/hackathon_2024/user/fetch.rs b/src/diesel/utils/hackathon_2024/user/fetch.rs
index 89ef0cb..d2eb3e5 100644
--- a/src/diesel/utils/hackathon_2024/user/fetch.rs
+++ b/src/diesel/utils/hackathon_2024/user/fetch.rs
@@ -1,16 +1,37 @@
use crate::diesel::models::hackathon_2024::user::HackathonUser2024Queryable;
use crate::diesel::prelude::*;
use crate::diesel::schema::hackathon_user_2024::dsl::hackathon_user_2024;
-use crate::diesel::schema::hackathon_user_2024::id;
+use crate::diesel::schema::hackathon_user_2024::{id, team_id, university_id};
pub fn all(db_pool: &DbState) -> Result, ApiError> {
hackathon_user_2024
.load::(&mut get_connection(db_pool)?)
- .map_err(ApiError::DatabaseErrorResult)
+ .map_err(|err| err.into())
}
-pub fn by_id(db_pool: &DbState, user_id: i32) -> Result {
+
+pub fn by_id(db_pool: &DbState, path_id: i32) -> Result {
hackathon_user_2024
- .filter(id.eq(user_id))
+ .filter(id.eq(path_id))
.first::(&mut get_connection(db_pool)?)
- .map_err(ApiError::DatabaseErrorResult)
+ .map_err(|err| err.into())
+}
+
+pub fn by_university(
+ db_pool: &DbState,
+ path_id: i32,
+) -> Result, ApiError> {
+ hackathon_user_2024
+ .filter(university_id.eq(path_id))
+ .load::(&mut get_connection(db_pool)?)
+ .map_err(|err| err.into())
+}
+
+pub fn by_team(
+ db_pool: &DbState,
+ path_id: i32,
+) -> Result, ApiError> {
+ hackathon_user_2024
+ .filter(team_id.eq(path_id))
+ .load::(&mut get_connection(db_pool)?)
+ .map_err(|err| err.into())
}
diff --git a/src/diesel/utils/hackathon_2024/user/insert.rs b/src/diesel/utils/hackathon_2024/user/insert.rs
index 5be4902..8794837 100644
--- a/src/diesel/utils/hackathon_2024/user/insert.rs
+++ b/src/diesel/utils/hackathon_2024/user/insert.rs
@@ -8,6 +8,6 @@ pub fn new(db_pool: &DbState, data: HackathonUser2024Insertable) -> Result(&mut get_connection(db_pool)?)
.map_err(|err| {
error!("Error inserting hackathon_user_2024");
- ApiError::DatabaseErrorResult(err)
+ err.into()
})
}
diff --git a/src/diesel/utils/hackathon_2024/user/update.rs b/src/diesel/utils/hackathon_2024/user/update.rs
index 4e898ba..e2c909d 100644
--- a/src/diesel/utils/hackathon_2024/user/update.rs
+++ b/src/diesel/utils/hackathon_2024/user/update.rs
@@ -23,6 +23,6 @@ pub fn by_id(
.execute(&mut get_connection(dp_pool)?)
.map_err(|err| {
error!("Error updating hackathon_user_2024, bellow error");
- ApiError::DatabaseErrorResult(err)
+ err.into()
})
}
diff --git a/src/dto/request/admin/login_admin.rs b/src/dto/request/admin/login_admin.rs
index 4966832..fe27436 100644
--- a/src/dto/request/admin/login_admin.rs
+++ b/src/dto/request/admin/login_admin.rs
@@ -1,7 +1,9 @@
use serde::Deserialize;
-#[derive(Deserialize)]
+#[derive(Deserialize, utoipa::ToSchema)]
pub struct LoginAdminData {
+ #[schema(example = "P@SSW0RD")]
pub admin_password: String,
+ #[schema(example = "L0g1N")]
pub admin_name: String,
}
diff --git a/src/dto/request/hackathon_2024/team.rs b/src/dto/request/hackathon_2024/team.rs
index b55ab6c..8734771 100644
--- a/src/dto/request/hackathon_2024/team.rs
+++ b/src/dto/request/hackathon_2024/team.rs
@@ -1,19 +1,28 @@
use crate::diesel::models::hackathon_2024::category::HackathonCategory2024Enum;
use crate::diesel::models::hackathon_2024::team::HackathonTeam2024Insertable;
use serde::Deserialize;
+use utoipa::ToSchema;
-#[derive(Deserialize)]
+#[derive(Deserialize, ToSchema)]
pub struct TeamRegistrationData {
+ #[schema(example = "1")]
pub id: i32,
+ #[schema(example = "real_password123!AAA")]
pub password: String,
}
-#[derive(Debug, Deserialize)]
+#[derive(Debug, Deserialize, ToSchema)]
pub struct TeamUpdateData {
+ #[schema(example = "1")]
pub id: i32,
+ #[schema(example = "Team 2")]
pub name: String,
+ #[schema(example = "Military")]
pub category: HackathonCategory2024Enum,
+ #[schema(example = "bredovschik")]
pub nickname_tg: String,
}
-#[derive(Debug, Deserialize)]
+
+#[derive(Debug, Deserialize, ToSchema)]
+#[schema(title = "HackathonTeam2024Insertable", value_type = HackathonTeam2024Insertable, as = HackathonTeam2024Insertable)]
pub struct TeamCreateData(pub HackathonTeam2024Insertable);
diff --git a/src/dto/request/hackathon_2024/university.rs b/src/dto/request/hackathon_2024/university.rs
index ae82690..785a957 100644
--- a/src/dto/request/hackathon_2024/university.rs
+++ b/src/dto/request/hackathon_2024/university.rs
@@ -1,4 +1,12 @@
-#[derive(serde::Deserialize)]
-pub struct University(
- pub crate::diesel::models::hackathon_2024::university::HackathonUniversity2024Insertable,
-);
+use serde::Deserialize;
+use utoipa::ToSchema;
+
+use crate::diesel::models::hackathon_2024::university::HackathonUniversity2024Insertable;
+
+#[derive(Deserialize, ToSchema)]
+#[schema(title = "HackathonUniversity2024Insertable", value_type = HackathonUniversity2024Insertable, as = HackathonUniversity2024Insertable)]
+pub struct University(pub HackathonUniversity2024Insertable);
+
+#[derive(Deserialize, ToSchema)]
+#[schema(title = "VecHackathonUniversity2024Insertable", value_type = Vec, as = Vec)]
+pub struct VecUniversity(pub Vec);
diff --git a/src/dto/request/hackathon_2024/user.rs b/src/dto/request/hackathon_2024/user.rs
index fec945f..078444f 100644
--- a/src/dto/request/hackathon_2024/user.rs
+++ b/src/dto/request/hackathon_2024/user.rs
@@ -1,18 +1,19 @@
use crate::diesel::models::hackathon_2024::user::HackathonUser2024Insertable;
use crate::dto::request::hackathon_2024::team::TeamRegistrationData;
use serde::Deserialize;
+use utoipa::ToSchema;
#[non_exhaustive]
-#[derive(Deserialize)]
+#[derive(Deserialize, ToSchema)]
pub struct RegistrationData {
pub user_data: HackathonUser2024Insertable,
pub team_data: TeamRegistrationData,
}
-#[allow(dead_code)]
-#[derive(serde::Deserialize)]
+#[derive(serde::Deserialize, ToSchema)]
+#[schema(title = "HackathonUser2024Insertable", value_type = HackathonUser2024Insertable, as = HackathonUser2024Insertable)]
pub struct User(pub HackathonUser2024Insertable);
-#[allow(dead_code)]
-#[derive(serde::Deserialize)]
-pub struct VecUser(pub Vec);
+#[derive(serde::Deserialize, ToSchema)]
+#[schema(title = "VecHackathonUser2024Insertable", value_type = Vec, as = Vec)]
+pub struct VecUser(#[allow(dead_code)] pub Vec);
diff --git a/src/dto/response/admin.rs b/src/dto/response/admin.rs
new file mode 100644
index 0000000..4a4a856
--- /dev/null
+++ b/src/dto/response/admin.rs
@@ -0,0 +1,4 @@
+#[derive(serde::Serialize)]
+pub struct AdminResponse {
+ pub admin_auth: bool,
+}
diff --git a/src/dto/response/hackathon_2024/team.rs b/src/dto/response/hackathon_2024/team.rs
index cb4cd6c..de4f68a 100644
--- a/src/dto/response/hackathon_2024/team.rs
+++ b/src/dto/response/hackathon_2024/team.rs
@@ -1,7 +1,11 @@
-#[derive(serde::Serialize)]
-pub struct Team(pub crate::diesel::models::hackathon_2024::team::HackathonTeam2024Queryable);
+use crate::diesel::models::hackathon_2024::team::HackathonTeam2024Queryable;
+use serde::Serialize;
+use utoipa::ToSchema;
-#[derive(serde::Serialize)]
-pub struct VecTeam(
- pub Vec,
-);
+#[derive(Serialize, ToSchema)]
+#[schema(title = "HackathonTeam2024Queryable", value_type = HackathonTeam2024Queryable, as = HackathonTeam2024Queryable)]
+pub struct Team(pub HackathonTeam2024Queryable);
+
+#[derive(Serialize, ToSchema)]
+#[schema(title = "VecHackathonTeam2024Queryable", value_type = Vec, as = Vec)]
+pub struct VecTeam(pub Vec);
diff --git a/src/dto/response/hackathon_2024/university.rs b/src/dto/response/hackathon_2024/university.rs
index 294c006..f688e90 100644
--- a/src/dto/response/hackathon_2024/university.rs
+++ b/src/dto/response/hackathon_2024/university.rs
@@ -1,9 +1,11 @@
-#[derive(serde::Serialize)]
-pub struct University(
- pub crate::diesel::models::hackathon_2024::university::HackathonUniversity2024Queryable,
-);
+use crate::diesel::models::hackathon_2024::university::HackathonUniversity2024Queryable;
+use serde::Serialize;
+use utoipa::ToSchema;
-#[derive(serde::Serialize)]
-pub struct VecUniversity(
- pub Vec,
-);
+#[derive(Serialize, ToSchema)]
+#[schema(title = "HackathonUniversity2024Queryable", value_type = HackathonUniversity2024Queryable, as = HackathonUniversity2024Queryable)]
+pub struct University(pub HackathonUniversity2024Queryable);
+
+#[derive(Serialize, ToSchema)]
+#[schema(title = "VecHackathonUniversity2024Queryable", value_type = Vec, as = Vec)]
+pub struct VecUniversity(pub Vec);
diff --git a/src/dto/response/hackathon_2024/user.rs b/src/dto/response/hackathon_2024/user.rs
index ece1d3f..9a326d7 100644
--- a/src/dto/response/hackathon_2024/user.rs
+++ b/src/dto/response/hackathon_2024/user.rs
@@ -1,7 +1,11 @@
use crate::diesel::models::hackathon_2024::user::HackathonUser2024Queryable;
+use serde::Serialize;
+use utoipa::ToSchema;
-#[derive(serde::Serialize)]
+#[derive(Serialize, ToSchema)]
+#[schema(title = "HackathonUser2024Queryable", value_type = HackathonUser2024Queryable, as = HackathonUser2024Queryable)]
pub struct User(pub HackathonUser2024Queryable);
-#[derive(serde::Serialize)]
+#[derive(Serialize, ToSchema)]
+#[schema(title = "VecHackathonUser2024Queryable", value_type = Vec, as = Vec)]
pub struct VecUser(pub Vec);
diff --git a/src/dto/response/mod.rs b/src/dto/response/mod.rs
index 2086991..38246c8 100644
--- a/src/dto/response/mod.rs
+++ b/src/dto/response/mod.rs
@@ -1,2 +1,2 @@
+pub mod admin;
pub mod hackathon_2024;
-pub mod user;
diff --git a/src/dto/response/user.rs b/src/dto/response/user.rs
deleted file mode 100644
index c329b56..0000000
--- a/src/dto/response/user.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use rocket::serde::Serialize;
-
-#[derive(Debug, Serialize)]
-pub struct UserLoginResponse {
- #[allow(dead_code)]
- pub id: i32,
- #[allow(dead_code)]
- pub email: String,
- #[allow(dead_code)]
- pub token: String,
-}
diff --git a/src/error/api_error.rs b/src/error/api_error.rs
index c56e570..ed5f9f8 100644
--- a/src/error/api_error.rs
+++ b/src/error/api_error.rs
@@ -5,7 +5,7 @@ use serde::Serialize;
use std::io::Cursor;
use thiserror::Error;
-#[derive(Error, Debug)]
+#[derive(Error, Debug, utoipa::ToSchema)]
pub enum ApiError {
#[allow(dead_code)]
#[error("Error not found")]
@@ -13,7 +13,7 @@ pub enum ApiError {
#[allow(dead_code)]
#[error("Database result error occurred")]
- DatabaseErrorResult(#[from] diesel::result::Error),
+ DatabaseErrorResult(String),
#[allow(dead_code)]
#[error("Database connection error occurred")]
@@ -118,8 +118,14 @@ impl<'r> Responder<'r, 'static> for ApiError {
}
}
-#[derive(Serialize)]
-struct ApiErrorBody {
+#[derive(Serialize, utoipa::ToSchema)]
+pub struct ApiErrorBody {
error: String,
message: String,
}
+
+impl From for ApiError {
+ fn from(err: diesel::result::Error) -> Self {
+ ApiError::DatabaseErrorResult(err.to_string())
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 621da26..ad8c5c9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,6 +6,7 @@ mod error;
mod middleware;
mod models;
mod server;
+mod swagger;
#[cfg(test)]
mod tests;
mod utils;
diff --git a/src/middleware/admin_match.rs b/src/middleware/admin_match.rs
deleted file mode 100644
index fd9c82e..0000000
--- a/src/middleware/admin_match.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use crate::error::api_error::ApiError;
-use crate::utils::env_configuration::CONFIG;
-use rocket::http::Status;
-use rocket::request::FromRequest;
-use rocket::{request, warn, Request};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize)]
-pub struct AdminMatch {
- is_admin: bool,
-}
-
-impl AdminMatch {
- #[allow(dead_code)]
- pub fn new(is_admin: bool) -> Self {
- AdminMatch { is_admin }
- }
- #[allow(dead_code)]
- pub fn check_admin(&self) -> Result {
- match &self.is_admin {
- true => Ok(true),
- false => Err(ApiError::Unauthorized(
- "Don't admin matching password".to_owned(),
- )),
- }
- }
-}
-
-#[rocket::async_trait]
-impl<'r> FromRequest<'r> for AdminMatch {
- type Error = ApiError;
-
- #[allow(dead_code)]
- async fn from_request(req: &'r Request<'_>) -> request::Outcome {
- let header_password = req.headers().get_one("Admin");
-
- match header_password {
- Some(header_password) => {
- let env_password = CONFIG.get().unwrap().admin_password.as_str();
- if header_password == env_password {
- request::Outcome::Success(AdminMatch { is_admin: true })
- } else {
- warn!("Error admin password");
- request::Outcome::Error((
- Status::Unauthorized,
- ApiError::HeaderMismatched("Admin header mismatched".to_owned()),
- ))
- }
- }
- None => {
- warn!("Token not found in header \"Authorization\"");
- request::Outcome::Error((
- Status::Unauthorized,
- ApiError::HeaderMismatched("Admin header mismatched".to_owned()),
- ))
- }
- }
- }
-}
diff --git a/src/middleware/admin_token_match.rs b/src/middleware/admin_token_match.rs
new file mode 100644
index 0000000..db55d1d
--- /dev/null
+++ b/src/middleware/admin_token_match.rs
@@ -0,0 +1,64 @@
+use crate::diesel::prelude::ApiError;
+use crate::utils::prelude_api::EnvConfiguration;
+use crate::utils::security;
+use rocket::http::Status;
+use rocket::request::FromRequest;
+use rocket::{request, Request};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema, utoipa::IntoParams)]
+pub struct AdminAuthData {
+ pub admin_password: String,
+ pub admin_name: String,
+ pub exp: u64,
+}
+
+impl AdminAuthData {
+ pub fn check_admin(&self) -> Result<(), ApiError> {
+ log::info!(
+ "Admin name: {}, Admin password: {}",
+ EnvConfiguration::get().admin_name,
+ EnvConfiguration::get().admin_password
+ );
+ if self.admin_name != EnvConfiguration::get().admin_name {
+ Err(ApiError::ValidationError(format!(
+ "Error validation admin name: {}",
+ self.admin_name
+ )))
+ } else if self.admin_password != EnvConfiguration::get().admin_password {
+ Err(ApiError::ValidationError(format!(
+ "Error validation admin password: {}",
+ self.admin_password
+ )))
+ } else {
+ Ok(())
+ }
+ }
+}
+
+#[rocket::async_trait]
+impl<'r> FromRequest<'r> for AdminAuthData {
+ type Error = ApiError;
+
+ #[allow(dead_code)]
+ async fn from_request(req: &'r Request<'_>) -> request::Outcome {
+ let token = req
+ .headers()
+ .get_one("Authorization")
+ .and_then(|header| header.strip_prefix("Bearer "));
+
+ match token {
+ Some(token) => match security::decoded_data::(token) {
+ Ok(token_data) => request::Outcome::Success(token_data.claims),
+ Err(_) => request::Outcome::Error((
+ Status::Unauthorized,
+ ApiError::Unauthorized("Admin not authorized".to_string()),
+ )),
+ },
+ None => request::Outcome::Error((
+ Status::Unauthorized,
+ ApiError::HeaderMismatched("Admin header mismatched".to_owned()),
+ )),
+ }
+ }
+}
diff --git a/src/middleware/get_user.rs b/src/middleware/get_user.rs
deleted file mode 100644
index 4d81874..0000000
--- a/src/middleware/get_user.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use crate::models::admin::admin_jwt;
-use crate::utils::security;
-use rocket::http::Status;
-use rocket::request::FromRequest;
-use rocket::{request, Request};
-
-#[rocket::async_trait]
-impl<'r> FromRequest<'r> for admin_jwt::AdminJwt {
- type Error = ();
-
- #[allow(dead_code)]
- async fn from_request(req: &'r Request<'_>) -> request::Outcome {
- let token = req
- .headers()
- .get_one("Authorization")
- .and_then(|header| header.strip_prefix("Bearer "));
-
- match token {
- Some(token) => match security::decoded_data::(token) {
- Ok(token_data) => request::Outcome::Success(token_data.claims),
- Err(_) => request::Outcome::Error((Status::Unauthorized, ())),
- },
- None => request::Outcome::Error((Status::Unauthorized, ())),
- }
- }
-}
diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs
index c6d3a72..06fd8c7 100644
--- a/src/middleware/mod.rs
+++ b/src/middleware/mod.rs
@@ -1,3 +1,2 @@
-pub mod admin_match;
+pub mod admin_token_match;
pub mod claims;
-pub mod get_user;
diff --git a/src/models/admin/admin_jwt.rs b/src/models/admin/admin_jwt.rs
deleted file mode 100644
index e90ab11..0000000
--- a/src/models/admin/admin_jwt.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-use serde::{Deserialize, Serialize};
-
-#[allow(dead_code)]
-#[derive(Debug, Serialize, Deserialize)]
-pub struct AdminJwt {
- pub admin_password: String,
- pub admin_name: String,
- pub exp: u64,
-}
diff --git a/src/models/admin/mod.rs b/src/models/admin/mod.rs
deleted file mode 100644
index 0c04a8b..0000000
--- a/src/models/admin/mod.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub mod admin_jwt;
diff --git a/src/models/mod.rs b/src/models/mod.rs
index 38246c8..60226f9 100644
--- a/src/models/mod.rs
+++ b/src/models/mod.rs
@@ -1,2 +1 @@
-pub mod admin;
pub mod hackathon_2024;
diff --git a/src/server.rs b/src/server.rs
index eec5378..8f125c0 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -1,11 +1,14 @@
use crate::api;
use crate::diesel::configurator::{configuration_database, DbPool};
+use crate::swagger::ApiDoc;
use crate::utils::env_configuration::EnvConfiguration;
use log::LevelFilter;
use rocket::figment::Figment;
use rocket::{routes, Config};
use rocket_cors::{AllowedHeaders, AllowedOrigins, Cors, CorsOptions};
use std::net::IpAddr;
+use utoipa::OpenApi;
+use utoipa_swagger_ui::SwaggerUi;
pub struct Server;
@@ -42,7 +45,10 @@ impl Server {
}
fn configure_cors() -> Cors {
- let exact = &[&format!("https://{}", EnvConfiguration::get().main_url)];
+ let exact = &[
+ &format!("https://{}", EnvConfiguration::get().main_url,),
+ &format!("http://0.0.0.0:{}", EnvConfiguration::get().server_port),
+ ];
CorsOptions {
allowed_origins: AllowedOrigins::some_exact(exact),
allowed_methods: vec!["GET", "POST", "PUT", "DELETE"]
@@ -61,6 +67,10 @@ impl Server {
rocket::custom(config)
.attach(cors)
.manage(db_pool)
+ .mount(
+ "/",
+ SwaggerUi::new("/swagger-ui/<_..>").url("/api-doc/openapi.json", ApiDoc::openapi()),
+ )
.mount(
"/api",
routes![
@@ -71,8 +81,12 @@ impl Server {
api::hackathon_2024::user::get::all,
api::hackathon_2024::user::put::by_id,
api::hackathon_2024::user::delete::by_id,
+ api::hackathon_2024::user::get::by_id,
+ api::hackathon_2024::user::get::by_university,
+ api::hackathon_2024::user::get::by_team,
// /hackathon_2024/university/*
api::hackathon_2024::university::post::create,
+ api::hackathon_2024::university::post::create_by_vec,
api::hackathon_2024::university::get::all,
api::hackathon_2024::university::get::by_id,
api::hackathon_2024::university::put::by_id,
diff --git a/src/swagger/mod.rs b/src/swagger/mod.rs
new file mode 100644
index 0000000..5d56d33
--- /dev/null
+++ b/src/swagger/mod.rs
@@ -0,0 +1,60 @@
+use crate::api;
+use utoipa::openapi::security::{HttpAuthScheme, HttpBuilder, SecurityScheme};
+use utoipa::{Modify, OpenApi};
+
+#[derive(OpenApi)]
+#[openapi(
+ paths(
+ // /test/*
+ api::test::get::ping,
+ // /hackathon_2024/user/*
+ api::hackathon_2024::user::post::registration_by_tg,
+ api::hackathon_2024::user::get::all,
+ api::hackathon_2024::user::put::by_id,
+ api::hackathon_2024::user::delete::by_id,
+ api::hackathon_2024::user::get::by_id,
+ api::hackathon_2024::user::get::by_university,
+ api::hackathon_2024::user::get::by_team,
+ // /hackathon_2024/university/*
+ api::hackathon_2024::university::post::create,
+ api::hackathon_2024::university::post::create_by_vec,
+ api::hackathon_2024::university::get::all,
+ api::hackathon_2024::university::get::by_id,
+ api::hackathon_2024::university::put::by_id,
+ api::hackathon_2024::university::delete::by_id,
+ // /hackathon_2024/team/*
+ api::hackathon_2024::team::post::create,
+ api::hackathon_2024::team::get::all,
+ api::hackathon_2024::team::get::by_id,
+ api::hackathon_2024::team::put::by_id,
+ api::hackathon_2024::team::delete::by_id,
+ // /adnmin/
+ api::admin::post::login,
+ api::admin::get::get,
+ // /other/*
+ ),
+ info(
+ title = "ExternalDept API",
+ version = "1.0.0"
+ ),
+ modifiers(&SecurityAddon)
+)]
+pub struct ApiDoc;
+
+struct SecurityAddon;
+
+impl Modify for SecurityAddon {
+ fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
+ let components = openapi.components.as_mut().unwrap();
+
+ components.add_security_scheme(
+ "bearer_auth",
+ SecurityScheme::Http(
+ HttpBuilder::new()
+ .scheme(HttpAuthScheme::Bearer)
+ .bearer_format("JWT")
+ .build(),
+ ),
+ );
+ }
+}
diff --git a/src/utils/prelude_api.rs b/src/utils/prelude_api.rs
index fe8a534..82648aa 100644
--- a/src/utils/prelude_api.rs
+++ b/src/utils/prelude_api.rs
@@ -1,5 +1,6 @@
pub use crate::diesel::prelude::DbState;
-pub use crate::error::api_error::ApiError;
+pub use crate::error::api_error::{ApiError, ApiErrorBody};
+pub use crate::middleware::admin_token_match::AdminAuthData;
#[allow(unused_imports)]
pub use crate::utils::env_configuration::EnvConfiguration;
pub use log::info;