diff --git a/src/database/entities/channel.rs b/src/database/entities/channel.rs index 04267b580fc3bf889c5b7e0b02e87eec573ccd21..5138793bf99d0aefbd51e006b66b08ebb08f2d60 100644 --- a/src/database/entities/channel.rs +++ b/src/database/entities/channel.rs @@ -1,7 +1,8 @@ use crate::database::*; use crate::notifications::events::ClientboundNotification; use crate::util::result::{Error, Result}; -use mongodb::bson::to_document; +use mongodb::bson::{doc, to_document}; +use rocket_contrib::json::JsonValue; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Clone)] @@ -62,4 +63,50 @@ impl Channel { Ok(()) } + + pub async fn publish_update(&self, partial: JsonValue) -> Result<()> { + let id = self.id().to_string(); + ClientboundNotification::ChannelUpdate(partial) + .publish(id) + .await + .ok(); + + Ok(()) + } + + pub async fn delete(&self) -> Result<()> { + let id = self.id(); + get_collection("messages") + .delete_many( + doc! { + "channel": id + }, + None, + ) + .await + .map_err(|_| Error::DatabaseError { + operation: "delete_many", + with: "messages", + })?; + + get_collection("channels") + .delete_one( + doc! { + "_id": id + }, + None, + ) + .await + .map_err(|_| Error::DatabaseError { + operation: "delete_one", + with: "channel", + })?; + + ClientboundNotification::ChannelDelete { id: id.to_string() } + .publish(id.to_string()) + .await + .ok(); + + Ok(()) + } } diff --git a/src/database/entities/message.rs b/src/database/entities/message.rs index ed3bd0fc0811d2642a7dda0abf51fa17de6d76d6..fd38f940fca3c99761e7a03dff4ea290c7fe8840 100644 --- a/src/database/entities/message.rs +++ b/src/database/entities/message.rs @@ -3,30 +3,11 @@ use crate::{ notifications::events::ClientboundNotification, util::result::{Error, Result}, }; -use mongodb::bson::{to_bson, DateTime}; +use mongodb::bson::{doc, to_bson, DateTime}; +use rocket_contrib::json::JsonValue; use serde::{Deserialize, Serialize}; use ulid::Ulid; -/*#[derive(Serialize, Deserialize, Debug)] -pub struct PreviousEntry { - pub content: String, - pub time: DateTime, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct Message { - #[serde(rename = "_id")] - pub id: String, - pub nonce: Option<String>, - pub channel: String, - pub author: String, - - pub content: String, - pub edited: Option<DateTime>, - - pub previous_content: Vec<PreviousEntry>, -}*/ - #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Message { #[serde(rename = "_id")] @@ -72,9 +53,9 @@ impl Message { Ok(()) } - pub async fn publish_edit(self) -> Result<()> { + pub async fn publish_update(&self, partial: JsonValue) -> Result<()> { let channel = self.channel.clone(); - ClientboundNotification::MessageEdit(self) + ClientboundNotification::MessageUpdate(partial) .publish(channel) .await .ok(); @@ -82,9 +63,22 @@ impl Message { Ok(()) } - pub async fn publish_delete(self) -> Result<()> { + pub async fn delete(&self) -> Result<()> { + get_collection("messages") + .delete_one( + doc! { + "_id": &self.id + }, + None, + ) + .await + .map_err(|_| Error::DatabaseError { + operation: "delete_one", + with: "message", + })?; + let channel = self.channel.clone(); - ClientboundNotification::MessageDelete { id: self.id } + ClientboundNotification::MessageDelete { id: self.id.clone() } .publish(channel) .await .ok(); diff --git a/src/notifications/events.rs b/src/notifications/events.rs index 9056ce04da1d1a0d05cea36a569a96a64601cc63..e51ff9a4e05d1427a54c54671c9ef897bc2130bb 100644 --- a/src/notifications/events.rs +++ b/src/notifications/events.rs @@ -1,5 +1,6 @@ use hive_pubsub::PubSub; use rauth::auth::Session; +use rocket_contrib::json::JsonValue; use serde::{Deserialize, Serialize}; use snafu::Snafu; @@ -38,12 +39,13 @@ pub enum ClientboundNotification { }, Message(Message), - MessageEdit(Message), + MessageUpdate(JsonValue), MessageDelete { id: String, }, ChannelCreate(Channel), + ChannelUpdate(JsonValue), ChannelGroupJoin { id: String, user: String, @@ -52,6 +54,9 @@ pub enum ClientboundNotification { id: String, user: String, }, + ChannelDelete { + id: String, + }, UserRelationship { id: String, @@ -95,17 +100,31 @@ pub fn prehandle_hook(notification: &ClientboundNotification) { .unsubscribe(&user.to_string(), &id.to_string()) .ok(); } - ClientboundNotification::UserRelationship { id, user, status } => match status { - RelationshipStatus::None => { + ClientboundNotification::UserRelationship { id, user, status } => { + if status != &RelationshipStatus::None { + subscribe_if_exists(id.clone(), user.clone()).ok(); + } + } + _ => {} + } +} + +pub fn posthandle_hook(notification: &ClientboundNotification) { + match ¬ification { + ClientboundNotification::ChannelDelete { id } => { + get_hive() + .hive + .drop_topic(&id) + .ok(); + } + ClientboundNotification::UserRelationship { id, user, status } => { + if status == &RelationshipStatus::None { get_hive() .hive .unsubscribe(&id.to_string(), &user.to_string()) .ok(); - } - _ => { - subscribe_if_exists(id.clone(), user.clone()).ok(); - } - }, + } + } _ => {} } } diff --git a/src/notifications/hive.rs b/src/notifications/hive.rs index e7d79bfad092e9ee4a5d40f803d15f3fec5b8d94..3541e5308f7bab1344195280d20bf193a73eaf0b 100644 --- a/src/notifications/hive.rs +++ b/src/notifications/hive.rs @@ -14,6 +14,8 @@ static HIVE: OnceCell<Hive> = OnceCell::new(); pub async fn init_hive() { let hive = MongodbPubSub::new( |ids, notification| { + super::events::posthandle_hook(¬ification); + if let Ok(data) = to_string(¬ification) { debug!("Pushing out notification. {}", data); websocket::publish(ids, notification); diff --git a/src/routes/channels/delete_channel.rs b/src/routes/channels/delete_channel.rs index aea50711ae6e663310bf756468ff7e642aa76166..ac871c59bcf1ad5f165dad4768d1cdc319526135 100644 --- a/src/routes/channels/delete_channel.rs +++ b/src/routes/channels/delete_channel.rs @@ -1,5 +1,5 @@ -use crate::database::*; use crate::util::result::{Error, Result}; +use crate::{database::*, notifications::events::ClientboundNotification}; use mongodb::bson::doc; @@ -12,7 +12,7 @@ pub async fn req(user: User, target: Ref) -> Result<()> { Err(Error::LabelMe)? } - match target { + match &target { Channel::SavedMessages { .. } => Err(Error::NoEffect), Channel::DirectMessage { .. } => { get_collection("channels") @@ -35,6 +35,77 @@ pub async fn req(user: User, target: Ref) -> Result<()> { Ok(()) } - _ => unimplemented!(), + Channel::Group { + id, + owner, + recipients, + .. + } => { + if &user.id == owner { + if let Some(new_owner) = recipients.iter().find(|x| *x != &user.id) { + get_collection("channels") + .update_one( + doc! { + "_id": &id + }, + doc! { + "$set": { + "owner": new_owner + }, + "$pull": { + "recipients": &user.id + } + }, + None, + ) + .await + .map_err(|_| Error::DatabaseError { + operation: "update_one", + with: "channel", + })?; + + target.publish_update(json!({ "owner": new_owner })).await?; + } else { + return target.delete().await + } + } else { + get_collection("channels") + .update_one( + doc! { + "_id": &id + }, + doc! { + "$pull": { + "recipients": &user.id + } + }, + None, + ) + .await + .map_err(|_| Error::DatabaseError { + operation: "update_one", + with: "channel", + })?; + } + + ClientboundNotification::ChannelGroupLeave { + id: id.clone(), + user: user.id.clone(), + } + .publish(id.clone()) + .await + .ok(); + + Message::create( + "00000000000000000000000000".to_string(), + id.clone(), + format!("<@{}> left the group.", user.id), + ) + .publish() + .await + .ok(); + + Ok(()) + } } } diff --git a/src/routes/channels/message_delete.rs b/src/routes/channels/message_delete.rs index 61204e70d76bfaae7ddc04c17d69ddfee1a792fd..f47c635935754ff0724e41140073f5333a226543 100644 --- a/src/routes/channels/message_delete.rs +++ b/src/routes/channels/message_delete.rs @@ -20,20 +20,5 @@ pub async fn req(user: User, target: Ref, msg: Ref) -> Result<()> { } } - get_collection("messages") - .delete_one( - doc! { - "_id": &message.id - }, - None, - ) - .await - .map_err(|_| Error::DatabaseError { - operation: "delete_one", - with: "message", - })?; - - message.publish_delete().await?; - - Ok(()) + message.delete().await } diff --git a/src/routes/channels/message_edit.rs b/src/routes/channels/message_edit.rs index 0e57c1868cd260a3c999b9ae8fb2dbde67acef06..cedba51e2011fd67215386b1a69210bbd7700088 100644 --- a/src/routes/channels/message_edit.rs +++ b/src/routes/channels/message_edit.rs @@ -25,7 +25,7 @@ pub async fn req(user: User, target: Ref, msg: Ref, edit: Json<Data>) -> Result< Err(Error::LabelMe)? } - let mut message = msg.fetch_message().await?; + let message = msg.fetch_message().await?; if message.author != user.id { Err(Error::CannotEditMessage)? } @@ -50,9 +50,5 @@ pub async fn req(user: User, target: Ref, msg: Ref, edit: Json<Data>) -> Result< with: "message", })?; - message.content = edit.content.clone(); - message.edited = Some(DateTime(edited)); - message.publish_edit().await?; - - Ok(()) + message.publish_update(json!({ "content": edit.content, "edited": DateTime(edited) })).await } diff --git a/src/routes/root.rs b/src/routes/root.rs index 8f8f5e8368112da948a7ae12b17b283a7ada7f72..7b5d4163015ba8c75180a7cbb61592bbdc96738c 100644 --- a/src/routes/root.rs +++ b/src/routes/root.rs @@ -8,7 +8,7 @@ use rocket_contrib::json::JsonValue; #[get("/")] pub async fn root() -> JsonValue { json!({ - "revolt": "0.3.1-alpha.0", + "revolt": "0.3.1", "features": { "registration": !*DISABLE_REGISTRATION, "captcha": {