From 3d086e511cd6ac1a3254de278e39b42c8a2811ca Mon Sep 17 00:00:00 2001
From: Awiteb
Date: Wed, 17 Jul 2024 18:34:39 +0300
Subject: [PATCH] feat: Replace `whitelist` & `blacklist` tables with
`users_status` table
Signed-off-by: Awiteb
---
crates/oxidetalis/src/database/blacklist.rs | 135 --------
crates/oxidetalis/src/database/mod.rs | 6 +-
crates/oxidetalis/src/database/user_status.rs | 287 ++++++++++++++++++
crates/oxidetalis/src/database/whitelist.rs | 134 --------
crates/oxidetalis/src/routes/user.rs | 2 +-
crates/oxidetalis/src/schemas/user.rs | 12 +-
.../src/websocket/handlers/chat_request.rs | 2 +-
crates/oxidetalis_entities/src/lib.rs | 3 +-
crates/oxidetalis_entities/src/prelude.rs | 17 +-
crates/oxidetalis_entities/src/users.rs | 16 +-
.../src/{blacklist.rs => users_status.rs} | 20 +-
crates/oxidetalis_entities/src/whitelist.rs | 56 ----
...cklist_table.rs => create_users_status.rs} | 67 +++-
.../src/create_whitelist_table.rs | 63 ----
crates/oxidetalis_migrations/src/lib.rs | 6 +-
15 files changed, 383 insertions(+), 443 deletions(-)
delete mode 100644 crates/oxidetalis/src/database/blacklist.rs
create mode 100644 crates/oxidetalis/src/database/user_status.rs
delete mode 100644 crates/oxidetalis/src/database/whitelist.rs
rename crates/oxidetalis_entities/src/{blacklist.rs => users_status.rs} (78%)
delete mode 100644 crates/oxidetalis_entities/src/whitelist.rs
rename crates/oxidetalis_migrations/src/{create_blacklist_table.rs => create_users_status.rs} (52%)
delete mode 100644 crates/oxidetalis_migrations/src/create_whitelist_table.rs
diff --git a/crates/oxidetalis/src/database/blacklist.rs b/crates/oxidetalis/src/database/blacklist.rs
deleted file mode 100644
index 1749b96..0000000
--- a/crates/oxidetalis/src/database/blacklist.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-// OxideTalis Messaging Protocol homeserver implementation
-// Copyright (C) 2024 OxideTalis Developers
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-//! 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::*;
-use sea_orm::DatabaseConnection;
-
-use super::WhiteListExt;
-use crate::{errors::ServerResult, websocket::errors::WsError};
-
-/// Extension trait for the `DatabaseConnection` to work with the blacklist
-/// table
-pub trait BlackListExt {
- /// Returns ture if the `blacklister` are blacklisted the
- /// `target_public_key`
- async fn is_blacklisted(
- &self,
- blacklister: &UserModel,
- target_public_key: &PublicKey,
- ) -> ServerResult;
-
- /// Add the `target_public_key` to the blacklist of the `blacklister` and
- /// remove it from the whitelist table (if it's there)
- async fn add_to_blacklist(
- &self,
- blacklister: &UserModel,
- target_public_key: &PublicKey,
- ) -> ServerResult<()>;
-
- /// Remove the target from blacklist table
- async fn remove_from_blacklist(
- &self,
- 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 {
- #[logcall::logcall]
- async fn is_blacklisted(
- &self,
- blacklister: &UserModel,
- target_public_key: &PublicKey,
- ) -> ServerResult {
- blacklister
- .find_related(BlacklistEntity)
- .filter(BlacklistColumn::Target.eq(target_public_key.to_string()))
- .one(self)
- .await
- .map(|u| u.is_some())
- .map_err(Into::into)
- }
-
- async fn add_to_blacklist(
- &self,
- blacklister: &UserModel,
- target_public_key: &PublicKey,
- ) -> ServerResult<()> {
- if self.is_blacklisted(blacklister, target_public_key).await? {
- return Err(WsError::AlreadyOnTheblacklist.into());
- }
- if blacklister.public_key == target_public_key.to_string() {
- return Err(WsError::CannotAddSelfToBlacklist.into());
- }
- self.remove_from_whitelist(blacklister, target_public_key)
- .await?;
-
- BlacklistActiveModel {
- user_id: Set(blacklister.id),
- target: Set(target_public_key.to_string()),
- blacklisted_at: Set(Utc::now()),
- ..Default::default()
- }
- .save(self)
- .await?;
- Ok(())
- }
-
- async fn remove_from_blacklist(
- &self,
- blacklister: &UserModel,
- target_public_key: &PublicKey,
- ) -> ServerResult<()> {
- if let Some(target_user) = blacklister
- .find_related(BlacklistEntity)
- .filter(BlacklistColumn::Target.eq(target_public_key.to_string()))
- .one(self)
- .await?
- {
- target_user.delete(self).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/database/mod.rs b/crates/oxidetalis/src/database/mod.rs
index dc03f6a..c4011ac 100644
--- a/crates/oxidetalis/src/database/mod.rs
+++ b/crates/oxidetalis/src/database/mod.rs
@@ -16,14 +16,12 @@
//! Database utilities for the OxideTalis homeserver.
-mod blacklist;
mod in_chat_requests;
mod out_chat_requests;
mod user;
-mod whitelist;
+mod user_status;
-pub use blacklist::*;
pub use in_chat_requests::*;
pub use out_chat_requests::*;
pub use user::*;
-pub use whitelist::*;
+pub use user_status::*;
diff --git a/crates/oxidetalis/src/database/user_status.rs b/crates/oxidetalis/src/database/user_status.rs
new file mode 100644
index 0000000..152e1c8
--- /dev/null
+++ b/crates/oxidetalis/src/database/user_status.rs
@@ -0,0 +1,287 @@
+// OxideTalis Messaging Protocol homeserver implementation
+// Copyright (C) 2024 OxideTalis Developers
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! Database extension to work with the whitelist table
+
+use std::num::{NonZeroU32, NonZeroU8};
+
+use chrono::Utc;
+use oxidetalis_core::types::PublicKey;
+use oxidetalis_entities::prelude::*;
+use sea_orm::DatabaseConnection;
+
+use crate::{errors::ServerResult, websocket::errors::WsError};
+
+/// Extension trait for the `DatabaseConnection` to work with the whitelist
+/// table
+pub trait UsersStatusExt {
+ /// Returns ture if the `whitelister` are whitelisted the
+ /// `target_public_key`
+ async fn is_whitelisted(
+ &self,
+ whitelister: &UserModel,
+ target_public_key: &PublicKey,
+ ) -> ServerResult;
+
+ /// Returns ture if the `blacklister` are blacklisted the
+ /// `target_public_key`
+ async fn is_blacklisted(
+ &self,
+ blacklister: &UserModel,
+ target_public_key: &PublicKey,
+ ) -> ServerResult;
+
+ /// Add the `target_public_key` to the whitelist of the `whitelister` and
+ /// remove it from the blacklist table (if it's there)
+ async fn add_to_whitelist(
+ &self,
+ whitelister: &UserModel,
+ target_public_key: &PublicKey,
+ ) -> ServerResult<()>;
+
+ /// Add the `target_public_key` to the blacklist of the `blacklister` and
+ /// remove it from the whitelist table (if it's there)
+ async fn add_to_blacklist(
+ &self,
+ blacklister: &UserModel,
+ target_public_key: &PublicKey,
+ ) -> ServerResult<()>;
+
+ /// Remove the target from whitelist table
+ // FIXME(awiteb): This method will be used when I work on decentralization, So, I'm keeping it
+ // for now
+ #[allow(dead_code)]
+ async fn remove_from_whitelist(
+ &self,
+ whitelister: &UserModel,
+ target_public_key: &PublicKey,
+ ) -> ServerResult<()>;
+
+ /// Remove the target from blacklist table
+ // FIXME(awiteb): This method will be used when I work on decentralization, So, I'm keeping it
+ // for now
+ #[allow(dead_code)]
+ async fn remove_from_blacklist(
+ &self,
+ blacklister: &UserModel,
+ target_public_key: &PublicKey,
+ ) -> ServerResult<()>;
+
+ /// Returns the whitelist of the user
+ async fn user_whitelist(
+ &self,
+ whitelister: &UserModel,
+ page: NonZeroU32,
+ page_size: NonZeroU8,
+ ) -> ServerResult>;
+
+ /// Returns the blacklist of the user
+ async fn user_blacklist(
+ &self,
+ blacklister: &UserModel,
+ page: NonZeroU32,
+ page_size: NonZeroU8,
+ ) -> ServerResult>;
+}
+
+impl UsersStatusExt for DatabaseConnection {
+ async fn is_whitelisted(
+ &self,
+ whitelister: &UserModel,
+ target_public_key: &PublicKey,
+ ) -> ServerResult {
+ whitelister
+ .find_related(UsersStatusEntity)
+ .filter(
+ UsersStatusColumn::Target
+ .eq(target_public_key.to_string())
+ .and(UsersStatusColumn::Status.eq(AccessStatus::Whitelisted)),
+ )
+ .one(self)
+ .await
+ .map(|u| u.is_some())
+ .map_err(Into::into)
+ }
+
+ async fn is_blacklisted(
+ &self,
+ blacklister: &UserModel,
+ target_public_key: &PublicKey,
+ ) -> ServerResult {
+ blacklister
+ .find_related(UsersStatusEntity)
+ .filter(
+ UsersStatusColumn::Target
+ .eq(target_public_key.to_string())
+ .and(UsersStatusColumn::Status.eq(AccessStatus::Blacklisted)),
+ )
+ .one(self)
+ .await
+ .map(|u| u.is_some())
+ .map_err(Into::into)
+ }
+
+ async fn add_to_whitelist(
+ &self,
+ whitelister: &UserModel,
+ target_public_key: &PublicKey,
+ ) -> ServerResult<()> {
+ if self.is_whitelisted(whitelister, target_public_key).await? {
+ return Err(WsError::AlreadyOnTheWhitelist.into());
+ }
+ if whitelister.public_key == target_public_key.to_string() {
+ return Err(WsError::CannotAddSelfToWhitelist.into());
+ }
+
+ if let Some(mut user) = get_user_status(self, whitelister, target_public_key)
+ .await?
+ .map(IntoActiveModel::into_active_model)
+ {
+ user.status = Set(AccessStatus::Whitelisted);
+ user.updated_at = Set(Utc::now());
+ user.update(self).await?;
+ } else {
+ UsersStatusActiveModel {
+ user_id: Set(whitelister.id),
+ target: Set(target_public_key.to_string()),
+ status: Set(AccessStatus::Whitelisted),
+ updated_at: Set(Utc::now()),
+ ..Default::default()
+ }
+ .save(self)
+ .await?;
+ }
+
+ Ok(())
+ }
+
+ async fn add_to_blacklist(
+ &self,
+ blacklister: &UserModel,
+ target_public_key: &PublicKey,
+ ) -> ServerResult<()> {
+ if self.is_blacklisted(blacklister, target_public_key).await? {
+ return Err(WsError::AlreadyOnTheBlacklist.into());
+ }
+ if blacklister.public_key == target_public_key.to_string() {
+ return Err(WsError::CannotAddSelfToBlacklist.into());
+ }
+
+ if let Some(mut user) = get_user_status(self, blacklister, target_public_key)
+ .await?
+ .map(IntoActiveModel::into_active_model)
+ {
+ user.status = Set(AccessStatus::Blacklisted);
+ user.updated_at = Set(Utc::now());
+ user.update(self).await?;
+ } else {
+ UsersStatusActiveModel {
+ user_id: Set(blacklister.id),
+ target: Set(target_public_key.to_string()),
+ status: Set(AccessStatus::Blacklisted),
+ updated_at: Set(Utc::now()),
+ ..Default::default()
+ }
+ .save(self)
+ .await?;
+ }
+
+ Ok(())
+ }
+
+ async fn remove_from_whitelist(
+ &self,
+ whitelister: &UserModel,
+ target_public_key: &PublicKey,
+ ) -> ServerResult<()> {
+ if let Some(target_user) = whitelister
+ .find_related(UsersStatusEntity)
+ .filter(
+ UsersStatusColumn::Target
+ .eq(target_public_key.to_string())
+ .and(UsersStatusColumn::Status.eq(AccessStatus::Whitelisted)),
+ )
+ .one(self)
+ .await?
+ {
+ target_user.delete(self).await?;
+ }
+ Ok(())
+ }
+
+ async fn remove_from_blacklist(
+ &self,
+ blacklister: &UserModel,
+ target_public_key: &PublicKey,
+ ) -> ServerResult<()> {
+ if let Some(target_user) = blacklister
+ .find_related(UsersStatusEntity)
+ .filter(
+ UsersStatusColumn::Target
+ .eq(target_public_key.to_string())
+ .and(UsersStatusColumn::Status.eq(AccessStatus::Blacklisted)),
+ )
+ .one(self)
+ .await?
+ {
+ target_user.delete(self).await?;
+ }
+ Ok(())
+ }
+
+ async fn user_whitelist(
+ &self,
+ whitelister: &UserModel,
+ page: NonZeroU32,
+ page_size: NonZeroU8,
+ ) -> ServerResult> {
+ whitelister
+ .find_related(UsersStatusEntity)
+ .filter(UsersStatusColumn::Status.eq(AccessStatus::Whitelisted))
+ .paginate(self, u64::from(page_size.get()))
+ .fetch_page(u64::from(page.get() - 1))
+ .await
+ .map_err(Into::into)
+ }
+
+ async fn user_blacklist(
+ &self,
+ blacklister: &UserModel,
+ page: NonZeroU32,
+ page_size: NonZeroU8,
+ ) -> ServerResult> {
+ blacklister
+ .find_related(UsersStatusEntity)
+ .filter(UsersStatusColumn::Status.eq(AccessStatus::Blacklisted))
+ .paginate(self, u64::from(page_size.get()))
+ .fetch_page(u64::from(page.get() - 1))
+ .await
+ .map_err(Into::into)
+ }
+}
+
+/// Returns user from user_status table by the entered and target public key
+async fn get_user_status(
+ conn: &DatabaseConnection,
+ user: &UserModel,
+ target_public_key: &PublicKey,
+) -> ServerResult