Add all possible notifications.

This commit is contained in:
Paul Makles
2020-04-13 17:47:48 +01:00
parent 0f793f84a2
commit 8043690d38
12 changed files with 435 additions and 96 deletions

View File

@@ -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();

View File

@@ -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,
}

View File

@@ -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,
}

View File

@@ -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,
}

View File

@@ -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 {

View File

@@ -0,0 +1,7 @@
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FriendStatus {
pub id: String,
pub status: i32,
}

View File

@@ -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!(),
};
}

View File

@@ -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,
};

View File

@@ -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))
}

View File

@@ -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(

View File

@@ -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." }),