diff --git a/crates/oxidetalis/src/database/blacklist.rs b/crates/oxidetalis/src/database/blacklist.rs index 2215ad2..f2f9229 100644 --- a/crates/oxidetalis/src/database/blacklist.rs +++ b/crates/oxidetalis/src/database/blacklist.rs @@ -16,6 +16,8 @@ //! Database extension to work with the blacklist table +use std::num::{NonZeroU32, NonZeroU8}; + use chrono::Utc; use oxidetalis_core::types::PublicKey; use oxidetalis_entities::prelude::*; @@ -39,6 +41,14 @@ pub trait BlackListExt { blacklister: &UserModel, target_public_key: &PublicKey, ) -> ServerResult<()>; + + /// Returns the blacklist of the user + async fn user_blacklist( + &self, + blacklister: &UserModel, + page: NonZeroU32, + page_size: NonZeroU8, + ) -> ServerResult>; } impl BlackListExt for DatabaseConnection { @@ -78,4 +88,19 @@ impl BlackListExt for DatabaseConnection { .await?; Ok(()) } + + async fn user_blacklist( + &self, + blacklister: &UserModel, + page: NonZeroU32, + page_size: NonZeroU8, + ) -> ServerResult> { + blacklister + .find_related(BlacklistEntity) + .select() + .paginate(self, u64::from(page_size.get())) + .fetch_page(u64::from(page.get() - 1)) + .await + .map_err(Into::into) + } } diff --git a/crates/oxidetalis/src/routes/user.rs b/crates/oxidetalis/src/routes/user.rs index febdc14..abd384d 100644 --- a/crates/oxidetalis/src/routes/user.rs +++ b/crates/oxidetalis/src/routes/user.rs @@ -30,11 +30,11 @@ use salvo::{ use super::{ApiError, ApiResult}; use crate::{ - database::{UserTableExt, WhiteListExt}, + database::{BlackListExt, UserTableExt, WhiteListExt}, extensions::DepotExt, middlewares, parameters::Pagination, - schemas::{EmptySchema, MessageSchema, RegisterUserBody, WhiteListedUser}, + schemas::{BlackListedUser, EmptySchema, MessageSchema, RegisterUserBody, WhiteListedUser}, utils, }; @@ -121,11 +121,51 @@ async fn user_whitelist( )) } +/// (🔐) Get blacklisted users +#[endpoint( + operation_id = "blacklist", + tags("User"), + responses( + (status_code = 200, description = "Returns blacklisted users", content_type = "application/json", body = Vec), + (status_code = 403, description = "Not registered user, must register first", content_type = "application/json", body = MessageSchema), + (status_code = 401, description = "The entered signature or public key is invalid", content_type = "application/json", body = MessageSchema), + (status_code = 429, description = "Too many requests", content_type = "application/json", body = MessageSchema), + (status_code = 500, description = "Internal server error", content_type = "application/json", body = MessageSchema), + ), + parameters( + Pagination, + ("X-OTMP-PUBLIC" = PublicKey, Header, description = "Public key of the sender"), + ("X-OTMP-SIGNATURE" = Signature, Header, description = "Signature of the request"), + ), +)] +async fn user_blacklist( + req: &mut Request, + depot: &mut Depot, +) -> ApiResult>> { + let pagination = Pagination::extract(req).await?; + let conn = depot.db_conn(); + let user = conn + .get_user_by_pubk( + &utils::extract_public_key(req) + .expect("Public key should be checked in the middleware"), + ) + .await? + .ok_or(ApiError::NotRegisteredUser)?; + Ok(Json( + conn.user_blacklist(&user, pagination.page, pagination.page_size) + .await? + .into_iter() + .map(Into::into) + .collect(), + )) +} + /// The route of the endpoints of this module pub fn route() -> Router { Router::new() .push(Router::with_path("register").post(register)) .push(Router::with_path("whitelist").get(user_whitelist)) + .push(Router::with_path("blacklist").get(user_blacklist)) .hoop(middlewares::public_key_check) .hoop(middlewares::signature_check) } diff --git a/crates/oxidetalis/src/schemas/user.rs b/crates/oxidetalis/src/schemas/user.rs index dd90f09..c853ebd 100644 --- a/crates/oxidetalis/src/schemas/user.rs +++ b/crates/oxidetalis/src/schemas/user.rs @@ -39,6 +39,15 @@ pub struct WhiteListedUser { pub whitelisted_at: DateTime, } +#[derive(Serialize, Deserialize, Clone, Debug, ToSchema, derive_new::new)] +#[salvo(schema(name = BlackListedUser, example = json!(BlackListedUser::default())))] +pub struct BlackListedUser { + /// User's public key + pub public_key: PublicKey, + /// When the user was blacklisted + pub blacklisted_at: DateTime, +} + impl Default for WhiteListedUser { fn default() -> Self { WhiteListedUser::new( @@ -56,3 +65,21 @@ impl From for WhiteListedUser { } } } + +impl Default for BlackListedUser { + fn default() -> Self { + BlackListedUser::new( + PublicKey::from_str("bYhbrm61ov8GLZfskUYbsCLJTfaacMsuTBYgBABEH9dy").expect("is valid"), + Utc::now(), + ) + } +} + +impl From for BlackListedUser { + fn from(user: BlacklistModel) -> Self { + Self { + public_key: PublicKey::from_str(&user.target).expect("Is valid public key"), + blacklisted_at: user.blacklisted_at, + } + } +}