diff --git a/crates/oxidetalis/src/database/blacklist.rs b/crates/oxidetalis/src/database/blacklist.rs new file mode 100644 index 0000000..a35eccb --- /dev/null +++ b/crates/oxidetalis/src/database/blacklist.rs @@ -0,0 +1,52 @@ +// 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 balcklist table + +use oxidetalis_core::types::PublicKey; +use oxidetalis_entities::prelude::*; +use sea_orm::DatabaseConnection; + +use crate::errors::ApiResult; + +/// 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, + ) -> ApiResult; +} + +impl BlackListExt for DatabaseConnection { + #[logcall::logcall] + async fn is_blacklisted( + &self, + blacklister: &UserModel, + target_public_key: &PublicKey, + ) -> ApiResult { + 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) + } +} diff --git a/crates/oxidetalis/src/database/in_chat_requests.rs b/crates/oxidetalis/src/database/in_chat_requests.rs new file mode 100644 index 0000000..137fee3 --- /dev/null +++ b/crates/oxidetalis/src/database/in_chat_requests.rs @@ -0,0 +1,66 @@ +// 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 for the `in_chat_requests` table. + +use chrono::Utc; +use oxidetalis_core::types::PublicKey; +use oxidetalis_entities::prelude::*; +use sea_orm::DatabaseConnection; + +use crate::websocket::errors::{WsError, WsResult}; + +/// Extension trait for the `in_chat_requests` table. +pub trait InChatRequestsExt { + /// Save the chat request in the recipient table + async fn save_in_chat_request( + &self, + requester: &PublicKey, + recipient: &UserModel, + ) -> WsResult<()>; +} + +impl InChatRequestsExt for DatabaseConnection { + #[logcall::logcall] + async fn save_in_chat_request( + &self, + sender: &PublicKey, + recipient: &UserModel, + ) -> WsResult<()> { + if sender.to_string() == recipient.public_key { + return Err(WsError::CannotSendChatRequestToSelf); + } + if recipient + .find_related(InChatRequestsEntity) + .filter(InChatRequestsColumn::Sender.eq(sender.to_string())) + .one(self) + .await + .map_err(|_| WsError::InternalServerError)? + .is_none() + { + InChatRequestsActiveModel { + recipient_id: Set(recipient.id), + sender: Set(sender.to_string()), + in_on: Set(Utc::now()), + ..Default::default() + } + .save(self) + .await + .map_err(|_| WsError::InternalServerError)?; + } + Ok(()) + } +} diff --git a/crates/oxidetalis/src/database/mod.rs b/crates/oxidetalis/src/database/mod.rs index a9578ae..dc03f6a 100644 --- a/crates/oxidetalis/src/database/mod.rs +++ b/crates/oxidetalis/src/database/mod.rs @@ -16,6 +16,14 @@ //! Database utilities for the OxideTalis homeserver. +mod blacklist; +mod in_chat_requests; +mod out_chat_requests; mod user; +mod whitelist; +pub use blacklist::*; +pub use in_chat_requests::*; +pub use out_chat_requests::*; pub use user::*; +pub use whitelist::*; diff --git a/crates/oxidetalis/src/database/out_chat_requests.rs b/crates/oxidetalis/src/database/out_chat_requests.rs new file mode 100644 index 0000000..b687997 --- /dev/null +++ b/crates/oxidetalis/src/database/out_chat_requests.rs @@ -0,0 +1,86 @@ +// 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 for the `out_chat_requests` table. + +use chrono::Utc; +use oxidetalis_core::types::PublicKey; +use oxidetalis_entities::prelude::*; +use sea_orm::DatabaseConnection; + +use crate::{ + errors::ApiResult, + websocket::errors::{WsError, WsResult}, +}; + +/// Extension trait for the `out_chat_requests` table. +pub trait OutChatRequestsExt { + /// Returns true if the `user` have a sended chat request to the `recipient` + async fn have_chat_request_to( + &self, + requester: &UserModel, + recipient: &PublicKey, + ) -> ApiResult; + + /// Save the chat request in the requester table + async fn save_out_chat_request( + &self, + requester: &UserModel, + recipient: &PublicKey, + ) -> WsResult<()>; +} + +impl OutChatRequestsExt for DatabaseConnection { + #[logcall::logcall] + async fn have_chat_request_to( + &self, + requester: &UserModel, + recipient: &PublicKey, + ) -> ApiResult { + requester + .find_related(OutChatRequestsEntity) + .filter(OutChatRequestsColumn::Recipient.eq(recipient.to_string())) + .one(self) + .await + .map(|user| user.is_some()) + .map_err(Into::into) + } + + #[logcall::logcall] + async fn save_out_chat_request( + &self, + requester: &UserModel, + recipient: &PublicKey, + ) -> WsResult<()> { + if self + .have_chat_request_to(requester, recipient) + .await + .map_err(|_| WsError::InternalServerError)? + { + return Err(WsError::AlreadySendChatRequest); + } + OutChatRequestsActiveModel { + sender_id: Set(requester.id), + recipient: Set(recipient.to_string()), + out_on: Set(Utc::now()), + ..Default::default() + } + .save(self) + .await + .map_err(|_| WsError::InternalServerError)?; + Ok(()) + } +} diff --git a/crates/oxidetalis/src/database/whitelist.rs b/crates/oxidetalis/src/database/whitelist.rs new file mode 100644 index 0000000..7a810d2 --- /dev/null +++ b/crates/oxidetalis/src/database/whitelist.rs @@ -0,0 +1,89 @@ +// 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 balcklist table + +use chrono::Utc; +use oxidetalis_core::types::PublicKey; +use oxidetalis_entities::prelude::*; +use sea_orm::DatabaseConnection; + +use crate::{ + errors::ApiResult, + websocket::errors::{WsError, WsResult}, +}; + +/// Extension trait for the `DatabaseConnection` to work with the whitelist +/// table +pub trait WhiteListExt { + /// Returns ture if the `whitelister` are whitelisted the + /// `target_public_key` + async fn is_whitelisted( + &self, + whitelister: &UserModel, + target_public_key: &PublicKey, + ) -> ApiResult; + + /// Add the `target_public_key` to the whitelist of the `whitelister` + async fn add_to_whitelist( + &self, + whitelister: &UserModel, + target_public_key: &PublicKey, + ) -> WsResult<()>; +} + +impl WhiteListExt for DatabaseConnection { + async fn is_whitelisted( + &self, + whitelister: &UserModel, + target_public_key: &PublicKey, + ) -> ApiResult { + whitelister + .find_related(WhitelistEntity) + .filter(WhitelistColumn::Target.eq(target_public_key.to_string())) + .one(self) + .await + .map(|u| u.is_some()) + .map_err(Into::into) + } + + async fn add_to_whitelist( + &self, + whitelister: &UserModel, + target_public_key: &PublicKey, + ) -> WsResult<()> { + if self + .is_whitelisted(whitelister, target_public_key) + .await + .map_err(|_| WsError::InternalServerError)? + { + return Err(WsError::AlreadyOnTheWhitelist); + } + if whitelister.public_key == target_public_key.to_string() { + return Err(WsError::CannotAddSelfToWhitelist); + } + WhitelistActiveModel { + user_id: Set(whitelister.id), + target: Set(target_public_key.to_string()), + whitelisted_at: Set(Utc::now()), + ..Default::default() + } + .save(self) + .await + .map_err(|_| WsError::InternalServerError)?; + Ok(()) + } +}