From 697132082aee39c705439c66752a9a56a882a177 Mon Sep 17 00:00:00 2001 From: Yannick Funk Date: Wed, 1 Sep 2021 21:52:24 +0200 Subject: [PATCH 1/5] First draft for push notifications --- src/database/entities/message.rs | 71 +++++++++++++++++++- src/database/entities/microservice/autumn.rs | 5 ++ 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/database/entities/message.rs b/src/database/entities/message.rs index 4e8192a4..5e9682cb 100644 --- a/src/database/entities/message.rs +++ b/src/database/entities/message.rs @@ -1,4 +1,4 @@ -use crate::util::variables::{USE_JANUARY, VAPID_PRIVATE_KEY}; +use crate::util::variables::{USE_JANUARY, VAPID_PRIVATE_KEY, PUBLIC_URL}; use crate::{ database::*, notifications::{events::ClientboundNotification, websocket::is_online}, @@ -17,6 +17,55 @@ use ulid::Ulid; use web_push::{ ContentEncoding, SubscriptionInfo, VapidSignatureBuilder, WebPushClient, WebPushMessageBuilder, }; +use std::time::SystemTime; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct PushNotification { + pub icon: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub image: Option, + pub body: String, + pub timestamp: u64, +} + +impl PushNotification { + pub async fn new(msg: Message) -> Self { + let author = Ref::from(msg.author) + .expect("id valid") + .fetch_user() + .await + .expect("user valid"); + + let icon = if let Some(avatar) = author.avatar { + avatar.get_autumn_url() + } else { + format!("{}/users/{}/default_avatar", PUBLIC_URL.as_str(), &author.id) + }; + + let image = msg.attachments.map_or(None, |attachments| { + attachments + .first() + .map_or(None, |v| Some(v.get_autumn_url())) + }); + + let body = match msg.content { + Content::Text(body) => body, + Content::SystemMessage(sys_msg) => sys_msg.into() + }; + + let timestamp = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .expect("system time should be valid") + .as_secs(); + + Self { + icon, + image, + body, + timestamp, + } + } +} #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type")] @@ -43,6 +92,23 @@ pub enum SystemMessage { ChannelIconChanged { by: String }, } +impl Into for SystemMessage { + fn into(self) -> String { + match self { + SystemMessage::Text { content } => content, + SystemMessage::UserAdded { .. } => "User added to the channel.".to_string(), + SystemMessage::UserRemove { .. } => "User removed from the channel.".to_string(), + SystemMessage::UserJoined { .. } => "User joined the channel.".to_string(), + SystemMessage::UserLeft { .. } => "User left the channel.".to_string(), + SystemMessage::UserKicked { .. } => "User kicked from the channel.".to_string(), + SystemMessage::UserBanned { .. } => "User banned from the channel.".to_string(), + SystemMessage::ChannelRenamed { .. } => "Channel renamed.".to_string(), + SystemMessage::ChannelDescriptionChanged { .. } => "Channel description changed.".to_string(), + SystemMessage::ChannelIconChanged { .. } => "Channel icon changed.".to_string() + } + } +} + #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(untagged)] pub enum Content { @@ -235,7 +301,7 @@ impl Message { } let mentions = self.mentions.clone(); - let enc = serde_json::to_string(&self).unwrap(); + let enc = serde_json::to_string(&PushNotification::new(self.clone()).await).unwrap(); ClientboundNotification::Message(self).publish(channel.id().to_string()); /* @@ -312,6 +378,7 @@ impl Message { .unwrap(); let signature = sig_builder.build().unwrap(); builder.set_vapid_signature(signature); + println!("{:#}", enc); builder.set_payload(ContentEncoding::AesGcm, enc.as_bytes()); let m = builder.build().unwrap(); client.send(m).await.ok(); diff --git a/src/database/entities/microservice/autumn.rs b/src/database/entities/microservice/autumn.rs index d9cf3c5f..0cac5a9f 100644 --- a/src/database/entities/microservice/autumn.rs +++ b/src/database/entities/microservice/autumn.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::database::*; use crate::util::result::{Error, Result}; +use crate::util::variables::AUTUMN_URL; #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type")] @@ -112,4 +113,8 @@ impl File { with: "attachment", }) } + + pub fn get_autumn_url(&self) -> String { + format!("{}/{}/{}", AUTUMN_URL.as_str(), self.tag, self.id) + } } From b5aa0ee9717d2e4cd34b3be9cc2dab3f611d1051 Mon Sep 17 00:00:00 2001 From: Yannick Funk Date: Thu, 2 Sep 2021 18:24:22 +0200 Subject: [PATCH 2/5] Remove print --- src/database/entities/message.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/database/entities/message.rs b/src/database/entities/message.rs index 5e9682cb..bbdbb9b3 100644 --- a/src/database/entities/message.rs +++ b/src/database/entities/message.rs @@ -378,7 +378,6 @@ impl Message { .unwrap(); let signature = sig_builder.build().unwrap(); builder.set_vapid_signature(signature); - println!("{:#}", enc); builder.set_payload(ContentEncoding::AesGcm, enc.as_bytes()); let m = builder.build().unwrap(); client.send(m).await.ok(); From f6b55574b133a795e1978fc2fc47149671e66243 Mon Sep 17 00:00:00 2001 From: Yannick Funk Date: Thu, 2 Sep 2021 20:32:36 +0200 Subject: [PATCH 3/5] Only build notification when there are subscriptions --- src/database/entities/message.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/database/entities/message.rs b/src/database/entities/message.rs index bbdbb9b3..89f71d34 100644 --- a/src/database/entities/message.rs +++ b/src/database/entities/message.rs @@ -301,8 +301,8 @@ impl Message { } let mentions = self.mentions.clone(); - let enc = serde_json::to_string(&PushNotification::new(self.clone()).await).unwrap(); - ClientboundNotification::Message(self).publish(channel.id().to_string()); + + ClientboundNotification::Message(self.clone()).publish(channel.id().to_string()); /* Web Push Test Code @@ -365,6 +365,7 @@ impl Message { } if subscriptions.len() > 0 { + let enc = serde_json::to_string(&PushNotification::new(self).await).unwrap(); let client = WebPushClient::new(); let key = base64::decode_config(VAPID_PRIVATE_KEY.clone(), base64::URL_SAFE).unwrap(); From 5a17038012820fd4e7bfb19c606ae139344eebfc Mon Sep 17 00:00:00 2001 From: Yannick Funk Date: Thu, 2 Sep 2021 20:34:26 +0200 Subject: [PATCH 4/5] Remove whitespace --- src/database/entities/message.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/database/entities/message.rs b/src/database/entities/message.rs index 89f71d34..26d4bef0 100644 --- a/src/database/entities/message.rs +++ b/src/database/entities/message.rs @@ -301,7 +301,6 @@ impl Message { } let mentions = self.mentions.clone(); - ClientboundNotification::Message(self.clone()).publish(channel.id().to_string()); /* From 43b75a2310e61197174757fb82e800193bf20c2a Mon Sep 17 00:00:00 2001 From: Yannick Funk Date: Thu, 2 Sep 2021 23:22:23 +0200 Subject: [PATCH 5/5] Add author and tag to push notification --- src/database/entities/message.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/database/entities/message.rs b/src/database/entities/message.rs index 26d4bef0..c92d6f0c 100644 --- a/src/database/entities/message.rs +++ b/src/database/entities/message.rs @@ -21,15 +21,17 @@ use std::time::SystemTime; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct PushNotification { + pub author: String, pub icon: String, #[serde(skip_serializing_if = "Option::is_none")] pub image: Option, pub body: String, + pub tag: String, pub timestamp: u64, } impl PushNotification { - pub async fn new(msg: Message) -> Self { + pub async fn new(msg: Message, channel: &Channel) -> Self { let author = Ref::from(msg.author) .expect("id valid") .fetch_user() @@ -59,9 +61,11 @@ impl PushNotification { .as_secs(); Self { + author: author.username, icon, image, body, + tag: channel.id().to_string(), timestamp, } } @@ -364,7 +368,7 @@ impl Message { } if subscriptions.len() > 0 { - let enc = serde_json::to_string(&PushNotification::new(self).await).unwrap(); + let enc = serde_json::to_string(&PushNotification::new(self, &c_clone).await).unwrap(); let client = WebPushClient::new(); let key = base64::decode_config(VAPID_PRIVATE_KEY.clone(), base64::URL_SAFE).unwrap();