diff --git a/Cargo.toml b/Cargo.toml index 3a6e24f74291b450d5af8f6ecf9c2444ff2f7bf8..a1b03c36484e1cb235acc7b5f4462952e801510f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "revolt" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Makles <paulmakles@gmail.com>"] edition = "2018" diff --git a/src/database/message.rs b/src/database/message.rs index c48c71ae87932f55d62c9abdeb02cdd4d0afed1a..96d671bfe649045d2d3cd8fe59fb19c0cce84373 100644 --- a/src/database/message.rs +++ b/src/database/message.rs @@ -2,7 +2,7 @@ use super::get_collection; use crate::guards::channel::ChannelRef; use crate::notifications; use crate::notifications::events::message::Create; -use crate::notifications::events::Notification::MessageCreate; +use crate::notifications::events::Notification; use crate::routes::channel::ChannelType; use bson::{doc, to_bson, UtcDateTime}; @@ -25,7 +25,7 @@ pub struct Message { pub content: String, pub edited: Option<UtcDateTime>, - pub previous_content: Option<Vec<PreviousEntry>>, + pub previous_content: Vec<PreviousEntry>, } // ? TODO: write global send message @@ -37,19 +37,16 @@ impl Message { .insert_one(to_bson(&self).unwrap().as_document().unwrap().clone(), None) .is_ok() { - let data = MessageCreate(Create { - id: self.id.clone(), - nonce: self.nonce.clone(), - channel: self.channel.clone(), - author: self.author.clone(), - content: self.content.clone(), - }); - - match target.channel_type { - 0..=1 => notifications::send_message_threaded(target.recipients.clone(), None, data), - 2 => notifications::send_message_threaded(None, target.guild.clone(), data), - _ => unreachable!(), - }; + notifications::send_message_given_channel( + Notification::message_create(Create { + id: self.id.clone(), + nonce: self.nonce.clone(), + channel: self.channel.clone(), + author: self.author.clone(), + content: self.content.clone(), + }), + &target, + ); let short_content: String = self.content.chars().take(24).collect(); diff --git a/src/notifications/events/groups.rs b/src/notifications/events/groups.rs new file mode 100644 index 0000000000000000000000000000000000000000..876f13d163faa0a0b8545a6196301038926fb064 --- /dev/null +++ b/src/notifications/events/groups.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct UserJoin { + pub id: String, + pub user: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct UserLeave { + pub id: String, + pub user: String, +} diff --git a/src/notifications/events/guilds.rs b/src/notifications/events/guilds.rs new file mode 100644 index 0000000000000000000000000000000000000000..3b1b95d2052ca750b17aa1f89d6b7151e8c31acb --- /dev/null +++ b/src/notifications/events/guilds.rs @@ -0,0 +1,33 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct UserJoin { + pub id: String, + pub user: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct UserLeave { + pub id: String, + pub user: String, + pub banned: bool, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ChannelCreate { + pub id: String, + pub channel: String, + pub name: String, + pub description: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ChannelDelete { + pub id: String, + pub channel: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Delete { + pub id: String, +} diff --git a/src/notifications/events/message.rs b/src/notifications/events/message.rs index b668150b3845fe3c905c2da8afcbb158def84452..6398bae43a875916d87ceabd8645e1588f508581 100644 --- a/src/notifications/events/message.rs +++ b/src/notifications/events/message.rs @@ -8,3 +8,14 @@ pub struct Create { pub author: String, pub content: String, } + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Edit { + pub id: String, + pub content: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Delete { + pub id: String, +} diff --git a/src/notifications/events/mod.rs b/src/notifications/events/mod.rs index 70aa92da9c7e3350eb21f3663fafc602441a3db2..ec079fb1a51c2e313cae420469584c869f8f84aa 100644 --- a/src/notifications/events/mod.rs +++ b/src/notifications/events/mod.rs @@ -1,11 +1,25 @@ use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; +pub mod groups; +pub mod guilds; pub mod message; +pub mod users; +#[allow(non_camel_case_types)] #[derive(Serialize, Deserialize, Debug, Clone)] pub enum Notification { - MessageCreate(message::Create), + message_create(message::Create), + message_edit(message::Edit), + message_delete(message::Delete), + group_user_join(groups::UserJoin), + group_user_leave(groups::UserLeave), + guild_user_join(guilds::UserJoin), + guild_user_leave(guilds::UserLeave), + guild_channel_create(guilds::ChannelCreate), + guild_channel_delete(guilds::ChannelDelete), + guild_delete(guilds::Delete), + user_friend_status(users::FriendStatus), } impl Notification { diff --git a/src/notifications/events/users.rs b/src/notifications/events/users.rs new file mode 100644 index 0000000000000000000000000000000000000000..88617ebced6490c301fb21bbc937c28a304bc91f --- /dev/null +++ b/src/notifications/events/users.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct FriendStatus { + pub id: String, + pub status: i32, +} diff --git a/src/notifications/mod.rs b/src/notifications/mod.rs index 4a2cb9a36eb67bfebdd2d5c39d9dc912ad6f072b..ae911814b26ec0111a95444b0fd5ad84ed7e7dd4 100644 --- a/src/notifications/mod.rs +++ b/src/notifications/mod.rs @@ -1,3 +1,5 @@ +use crate::guards::channel::ChannelRef; + use once_cell::sync::OnceCell; use std::sync::mpsc::{channel, Sender}; use std::thread; @@ -62,3 +64,11 @@ pub fn send_message_threaded<U: Into<Option<Vec<String>>>, G: Into<Option<String .is_ok() } } + +pub fn send_message_given_channel(data: events::Notification, channel: &ChannelRef) { + match channel.channel_type { + 0..=1 => send_message_threaded(channel.recipients.clone(), None, data), + 2 => send_message_threaded(None, channel.guild.clone(), data), + _ => unreachable!(), + }; +} diff --git a/src/notifications/pubsub.rs b/src/notifications/pubsub.rs index 06d516be396be1160b656ca4a92d9dd3f8973c61..03e32111aaf3bee8b7946f794f6a6aec18b2d680 100644 --- a/src/notifications/pubsub.rs +++ b/src/notifications/pubsub.rs @@ -18,8 +18,6 @@ pub struct PubSubMessage { user_recipients: Option<Vec<String>>, target_guild: Option<String>, - - notification_type: String, data: Notification, } @@ -29,10 +27,6 @@ pub fn send_message(users: Option<Vec<String>>, guild: Option<String>, data: Not source: SOURCEID.get().unwrap().to_string(), user_recipients: users.into(), target_guild: guild.into(), - notification_type: match data { - Notification::MessageCreate(_) => "message_create", - } - .to_string(), data, }; diff --git a/src/routes/channel.rs b/src/routes/channel.rs index 07c12f4dbc2e3dd50f1f1d12ea1a299885494e53..eb134e7f53e51361cbdd8d5ec24d271802cdd38f 100644 --- a/src/routes/channel.rs +++ b/src/routes/channel.rs @@ -5,6 +5,10 @@ use crate::database::{ }; use crate::guards::auth::UserRef; use crate::guards::channel::ChannelRef; +use crate::notifications::{ + self, + events::{groups::*, guilds::ChannelDelete, message::*, Notification}, +}; use crate::util::vec_to_set; use bson::{doc, from_bson, Bson, Bson::UtcDatetime}; @@ -218,10 +222,18 @@ pub fn add_member(user: UserRef, target: ChannelRef, member: UserRef) -> Option< author: "system".to_string(), content: format!("<@{}> added <@{}> to the group.", &user.id, &member.id), edited: None, - previous_content: None, + previous_content: vec![], }) .send(&target) { + notifications::send_message_given_channel( + Notification::group_user_join(UserJoin { + id: target.id.clone(), + user: member.id.clone(), + }), + &target, + ); + Some(Response::Result(super::Status::Ok)) } else { Some(Response::PartialStatus( @@ -285,10 +297,18 @@ pub fn remove_member(user: UserRef, target: ChannelRef, member: UserRef) -> Opti author: "system".to_string(), content: format!("<@{}> removed <@{}> from the group.", &user.id, &member.id), edited: None, - previous_content: None, + previous_content: vec![], }) .send(&target) { + notifications::send_message_given_channel( + Notification::group_user_leave(UserLeave { + id: target.id.clone(), + user: member.id.clone(), + }), + &target, + ); + Some(Response::Result(super::Status::Ok)) } else { Some(Response::PartialStatus( @@ -327,7 +347,7 @@ pub fn delete(user: UserRef, target: ChannelRef) -> Option<Response> { Some(Response::Result(super::Status::Ok)) } else { Some(Response::InternalServerError( - json!({ "error": "Failed to delete group." }), + json!({ "error": "Failed to delete channel." }), )) } } else { @@ -395,10 +415,18 @@ pub fn delete(user: UserRef, target: ChannelRef) -> Option<Response> { author: "system".to_string(), content: format!("<@{}> left the group.", &user.id), edited: None, - previous_content: None, + previous_content: vec![], }) .send(&target) { + notifications::send_message_given_channel( + Notification::group_user_leave(UserLeave { + id: target.id.clone(), + user: user.id.clone(), + }), + &target, + ); + Some(Response::Result(super::Status::Ok)) } else { Some(Response::PartialStatus( @@ -413,9 +441,10 @@ pub fn delete(user: UserRef, target: ChannelRef) -> Option<Response> { } } 2 => { + let guild_id = target.guild.unwrap(); if database::get_collection("guilds") .update_one( - doc! { "_id": target.guild.unwrap() }, + doc! { "_id": &guild_id }, doc! { "$pull": { "invites": { @@ -427,6 +456,15 @@ pub fn delete(user: UserRef, target: ChannelRef) -> Option<Response> { ) .is_ok() { + notifications::send_message_threaded( + None, + guild_id.clone(), + Notification::guild_channel_delete(ChannelDelete { + id: guild_id.clone(), + channel: target.id.clone(), + }), + ); + try_delete() } else { Some(Response::InternalServerError( @@ -512,7 +550,7 @@ pub fn send_message( author: user.id, content, edited: None, - previous_content: None, + previous_content: vec![], }; if message.send(&target) { @@ -533,28 +571,21 @@ pub fn get_message(user: UserRef, target: ChannelRef, message: Message) -> Optio return Some(Response::LackingPermission(Permission::ReadMessages)); } - let prev = - // ! CHECK IF USER HAS PERMISSION TO VIEW EDITS OF MESSAGES - if let Some(previous) = message.previous_content { - let mut entries = vec![]; - for entry in previous { - entries.push(json!({ - "content": entry.content, - "time": entry.time.timestamp(), - })); - } - - Some(entries) - } else { - None - }; + // ! CHECK IF USER HAS PERMISSION TO VIEW EDITS OF MESSAGES + let mut entries = vec![]; + for entry in message.previous_content { + entries.push(json!({ + "content": entry.content, + "time": entry.time.timestamp(), + })); + } Some(Response::Success(json!({ "id": message.id, "author": message.author, "content": message.content, "edited": if let Some(t) = message.edited { Some(t.timestamp()) } else { None }, - "previous_content": prev, + "previous_content": entries, }))) } @@ -596,7 +627,7 @@ pub fn edit_message( }, "$push": { "previous_content": { - "content": message.content, + "content": &message.content, "time": time, } }, @@ -604,19 +635,13 @@ pub fn edit_message( None, ) { Ok(_) => { - /*websocket::queue_message( - get_recipients(&target), - json!({ - "type": "message_update", - "data": { - "id": message.id, - "channel": target.id, - "content": edit.content.clone(), - "edited": edited.timestamp() - }, - }) - .to_string(), - );*/ + notifications::send_message_given_channel( + Notification::message_edit(Edit { + id: message.id.clone(), + content: message.content, + }), + &target, + ); Some(Response::Result(super::Status::Ok)) } @@ -641,17 +666,12 @@ pub fn delete_message(user: UserRef, target: ChannelRef, message: Message) -> Op match col.delete_one(doc! { "_id": &message.id }, None) { Ok(_) => { - /*websocket::queue_message( - get_recipients(&target), - json!({ - "type": "message_delete", - "data": { - "id": message.id, - "channel": target.id - }, - }) - .to_string(), - );*/ + notifications::send_message_given_channel( + Notification::message_delete(Delete { + id: message.id.clone(), + }), + &target, + ); Some(Response::Result(super::Status::Ok)) } diff --git a/src/routes/guild.rs b/src/routes/guild.rs index e44b3daa3f77d05e8bcc076bef3d3a8bbfff2bb0..eb0d49c8a2e16900ebcb365830bcc1c8913e3e3b 100644 --- a/src/routes/guild.rs +++ b/src/routes/guild.rs @@ -4,6 +4,10 @@ use crate::database::{self, channel::Channel, Permission, PermissionCalculator}; use crate::guards::auth::UserRef; use crate::guards::channel::ChannelRef; use crate::guards::guild::{get_invite, get_member, GuildRef}; +use crate::notifications::{ + self, + events::{guilds::*, Notification}, +}; use crate::util::gen_token; use bson::{doc, from_bson, Bson}; @@ -180,6 +184,14 @@ pub fn remove_guild(user: UserRef, target: GuildRef) -> Option<Response> { ) .is_ok() { + notifications::send_message_threaded( + None, + target.id.clone(), + Notification::guild_delete(Delete { + id: target.id.clone(), + }), + ); + Some(Response::Result(super::Status::Ok)) } else { Some(Response::InternalServerError( @@ -212,6 +224,16 @@ pub fn remove_guild(user: UserRef, target: GuildRef) -> Option<Response> { ) .is_ok() { + notifications::send_message_threaded( + None, + target.id.clone(), + Notification::guild_user_leave(UserLeave { + id: target.id.clone(), + user: user.id.clone(), + banned: false, + }), + ); + Some(Response::Result(super::Status::Ok)) } else { Some(Response::InternalServerError( @@ -268,13 +290,24 @@ pub fn create_channel( "nonce": &nonce, "type": 2, "guild": &target.id, - "name": name, - "description": description, + "name": &name, + "description": &description, }, None, ) .is_ok() { + notifications::send_message_threaded( + None, + target.id.clone(), + Notification::guild_channel_create(ChannelCreate { + id: target.id.clone(), + channel: id.clone(), + name: name.clone(), + description: description.clone(), + }), + ); + Some(Response::Success(json!({ "id": &id }))) } else { Some(Response::BadRequest( @@ -442,6 +475,15 @@ pub fn use_invite(user: UserRef, code: String) -> Response { ) .is_ok() { + notifications::send_message_threaded( + None, + guild_id.clone(), + Notification::guild_user_join(UserJoin { + id: guild_id.clone(), + user: user.id.clone(), + }), + ); + Response::Success(json!({ "guild": &guild_id, "channel": &invite.channel, @@ -636,6 +678,16 @@ pub fn kick_member(user: UserRef, target: GuildRef, other: String) -> Option<Res ) .is_ok() { + notifications::send_message_threaded( + None, + target.id.clone(), + Notification::guild_user_leave(UserLeave { + id: target.id.clone(), + user: other.clone(), + banned: false, + }), + ); + Some(Response::Result(super::Status::Ok)) } else { Some(Response::InternalServerError( @@ -712,6 +764,16 @@ pub fn ban_member( ) .is_ok() { + notifications::send_message_threaded( + None, + target.id.clone(), + Notification::guild_user_leave(UserLeave { + id: target.id.clone(), + user: other.clone(), + banned: true, + }), + ); + Some(Response::Result(super::Status::Ok)) } else { Some(Response::InternalServerError( diff --git a/src/routes/user.rs b/src/routes/user.rs index 71ccc83f64fc27a261c6595407e16c2058f4b077..e41b1451067e09c01491e089155b7393e894e93b 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -1,6 +1,10 @@ use super::Response; use crate::database::{self, get_relationship, get_relationship_internal, mutual, Relationship}; use crate::guards::auth::UserRef; +use crate::notifications::{ + self, + events::{users::*, Notification}, +}; use crate::routes::channel; use bson::doc; @@ -32,7 +36,7 @@ pub fn user(user: UserRef, target: UserRef) -> Response { Response::Success(json!({ "id": target.id, "username": target.username, - "relationship": get_relationship(&user, &target) as u8, + "relationship": get_relationship(&user, &target) as i32, "mutual": { "guilds": mutual::find_mutual_guilds(&user.id, &target.id), "friends": mutual::find_mutual_friends(&user.id, &target.id), @@ -67,7 +71,7 @@ pub fn lookup(user: UserRef, query: Json<LookupQuery>) -> Response { results.push(json!({ "id": id, "username": doc.get_str("username").unwrap(), - "relationship": get_relationship_internal(&user.id, &id, &relationships) as u8 + "relationship": get_relationship_internal(&user.id, &id, &relationships) as i32 })); } } @@ -186,7 +190,7 @@ pub fn get_friends(user: UserRef) -> Response { /// retrieve friend status with user #[get("/<target>/friend")] pub fn get_friend(user: UserRef, target: UserRef) -> Response { - Response::Success(json!({ "status": get_relationship(&user, &target) as u8 })) + Response::Success(json!({ "status": get_relationship(&user, &target) as i32 })) } /// create or accept a friend request @@ -218,8 +222,8 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response { if col .update_one( doc! { - "_id": target.id, - "relations.id": user.id + "_id": target.id.clone(), + "relations.id": user.id.clone() }, doc! { "$set": { @@ -230,7 +234,25 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response { ) .is_ok() { - Response::Success(json!({ "status": Relationship::Friend as u8 })) + notifications::send_message_threaded( + vec![target.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: user.id.clone(), + status: Relationship::Friend as i32, + }), + ); + + notifications::send_message_threaded( + vec![user.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: target.id.clone(), + status: Relationship::Friend as i32, + }), + ); + + Response::Success(json!({ "status": Relationship::Friend as i32 })) } else { Response::InternalServerError( json!({ "error": "Failed to commit! Try re-adding them as a friend." }), @@ -269,12 +291,12 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response { if col .update_one( doc! { - "_id": target.id + "_id": target.id.clone() }, doc! { "$push": { "relations": { - "id": user.id, + "id": user.id.clone(), "status": Relationship::Incoming as i32 } } @@ -283,7 +305,25 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response { ) .is_ok() { - Response::Success(json!({ "status": Relationship::Outgoing as u8 })) + notifications::send_message_threaded( + vec![user.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: target.id.clone(), + status: Relationship::Outgoing as i32, + }), + ); + + notifications::send_message_threaded( + vec![target.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: user.id.clone(), + status: Relationship::Incoming as i32, + }), + ); + + Response::Success(json!({ "status": Relationship::Outgoing as i32 })) } else { Response::InternalServerError( json!({ "error": "Failed to commit! Try re-adding them as a friend." }), @@ -327,12 +367,12 @@ pub fn remove_friend(user: UserRef, target: UserRef) -> Response { if col .update_one( doc! { - "_id": target.id + "_id": target.id.clone() }, doc! { "$pull": { "relations": { - "id": user.id + "id": user.id.clone() } } }, @@ -340,7 +380,25 @@ pub fn remove_friend(user: UserRef, target: UserRef) -> Response { ) .is_ok() { - Response::Success(json!({ "status": Relationship::NONE as u8 })) + notifications::send_message_threaded( + vec![user.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: target.id.clone(), + status: Relationship::NONE as i32, + }), + ); + + notifications::send_message_threaded( + vec![target.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: user.id.clone(), + status: Relationship::NONE as i32, + }), + ); + + Response::Success(json!({ "status": Relationship::NONE as i32 })) } else { Response::InternalServerError( json!({ "error": "Failed to commit! Target remains in same state." }), @@ -365,7 +423,9 @@ pub fn block_user(user: UserRef, target: UserRef) -> Response { let col = database::get_collection("users"); match get_relationship(&user, &target) { - Relationship::Friend | Relationship::Incoming | Relationship::Outgoing => { + Relationship::Friend + | Relationship::Incoming + | Relationship::Outgoing => { if col .update_one( doc! { @@ -384,8 +444,8 @@ pub fn block_user(user: UserRef, target: UserRef) -> Response { if col .update_one( doc! { - "_id": target.id, - "relations.id": user.id + "_id": target.id.clone(), + "relations.id": user.id.clone() }, doc! { "$set": { @@ -396,7 +456,91 @@ pub fn block_user(user: UserRef, target: UserRef) -> Response { ) .is_ok() { - Response::Success(json!({ "status": Relationship::Blocked as u8 })) + notifications::send_message_threaded( + vec![user.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: target.id.clone(), + status: Relationship::Blocked as i32, + }), + ); + + notifications::send_message_threaded( + vec![target.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: user.id.clone(), + status: Relationship::BlockedOther as i32, + }), + ); + + Response::Success(json!({ "status": Relationship::Blocked as i32 })) + } else { + Response::InternalServerError( + json!({ "error": "Failed to commit! Try blocking the user again, remove it first." }), + ) + } + } else { + Response::InternalServerError( + json!({ "error": "Failed to commit to database, try again." }), + ) + } + } + + Relationship::NONE => { + if col + .update_one( + doc! { + "_id": user.id.clone(), + }, + doc! { + "$push": { + "relations": { + "id": target.id.clone(), + "status": Relationship::Blocked as i32, + } + } + }, + None, + ) + .is_ok() + { + if col + .update_one( + doc! { + "_id": target.id.clone(), + }, + doc! { + "$push": { + "relations": { + "id": user.id.clone(), + "status": Relationship::BlockedOther as i32, + } + } + }, + None, + ) + .is_ok() + { + notifications::send_message_threaded( + vec![user.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: target.id.clone(), + status: Relationship::Blocked as i32, + }), + ); + + notifications::send_message_threaded( + vec![target.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: user.id.clone(), + status: Relationship::BlockedOther as i32, + }), + ); + + Response::Success(json!({ "status": Relationship::Blocked as i32 })) } else { Response::InternalServerError( json!({ "error": "Failed to commit! Try blocking the user again, remove it first." }), @@ -427,16 +571,23 @@ pub fn block_user(user: UserRef, target: UserRef) -> Response { ) .is_ok() { - Response::Success(json!({ "status": Relationship::Blocked as u8 })) + notifications::send_message_threaded( + vec![user.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: target.id.clone(), + status: Relationship::Blocked as i32, + }), + ); + + Response::Success(json!({ "status": Relationship::Blocked as i32 })) } else { Response::InternalServerError( json!({ "error": "Failed to commit to database, try again." }), ) } } - Relationship::SELF | Relationship::NONE => { - Response::BadRequest(json!({ "error": "This has no effect." })) - } + Relationship::SELF => Response::BadRequest(json!({ "error": "This has no effect." })), } } @@ -463,7 +614,16 @@ pub fn unblock_user(user: UserRef, target: UserRef) -> Response { ) .is_ok() { - Response::Success(json!({ "status": Relationship::BlockedOther as u8 })) + notifications::send_message_threaded( + vec![user.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: target.id.clone(), + status: Relationship::BlockedOther as i32, + }), + ); + + Response::Success(json!({ "status": Relationship::BlockedOther as i32 })) } else { Response::InternalServerError( json!({ "error": "Failed to commit to database, try again." }), @@ -490,12 +650,12 @@ pub fn unblock_user(user: UserRef, target: UserRef) -> Response { if col .update_one( doc! { - "_id": target.id + "_id": target.id.clone() }, doc! { "$pull": { "relations": { - "id": user.id + "id": user.id.clone() } } }, @@ -503,7 +663,25 @@ pub fn unblock_user(user: UserRef, target: UserRef) -> Response { ) .is_ok() { - Response::Success(json!({ "status": Relationship::NONE as u8 })) + notifications::send_message_threaded( + vec![user.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: target.id.clone(), + status: Relationship::NONE as i32, + }), + ); + + notifications::send_message_threaded( + vec![target.id.clone()], + None, + Notification::user_friend_status(FriendStatus { + id: user.id.clone(), + status: Relationship::NONE as i32, + }), + ); + + Response::Success(json!({ "status": Relationship::NONE as i32 })) } else { Response::InternalServerError( json!({ "error": "Failed to commit! Target remains in same state." }),