Merge branch 'master' into unify-last-message

This commit is contained in:
Yannick Funk
2021-09-13 20:19:54 +02:00
committed by GitHub
36 changed files with 1115 additions and 802 deletions

View File

@@ -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},
@@ -11,12 +11,68 @@ use mongodb::{
bson::{doc, to_bson, DateTime, Document},
options::FindOptions,
};
use rauth::entities::{Model, Session};
use rocket::serde::json::Value;
use serde::{Deserialize, Serialize};
use ulid::Ulid;
use web_push::{
ContentEncoding, SubscriptionInfo, VapidSignatureBuilder, WebPushClient, WebPushMessageBuilder,
};
use web_push::{ContentEncoding, SubscriptionInfo, SubscriptionKeys, VapidSignatureBuilder, WebPushClient, WebPushMessageBuilder};
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<String>,
pub body: String,
pub tag: String,
pub timestamp: u64,
}
impl PushNotification {
pub async fn new(msg: Message, channel: &Channel) -> Self {
let author = Ref::from_unchecked(msg.author.clone())
.fetch_user()
.await;
let (author, avatar) = if let Ok(author) = author {
(Some(author.username), author.avatar)
} else {
(None, None)
};
let icon = if let Some(avatar) = avatar {
avatar.get_autumn_url()
} else {
format!("{}/users/{}/default_avatar", PUBLIC_URL.as_str(), msg.author)
};
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 {
author: author.unwrap_or_else(|| "Unknown".into()),
icon,
image,
body,
tag: channel.id().to_string(),
timestamp,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type")]
@@ -43,6 +99,23 @@ pub enum SystemMessage {
ChannelIconChanged { by: String },
}
impl Into<String> 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 {
@@ -177,8 +250,7 @@ impl Message {
}
let mentions = self.mentions.clone();
let enc = serde_json::to_string(&self).unwrap();
ClientboundNotification::Message(self).publish(channel.id().to_string());
ClientboundNotification::Message(self.clone()).publish(channel.id().to_string());
/*
Web Push Test Code
@@ -204,59 +276,47 @@ impl Message {
}
// Fetch their corresponding sessions.
if let Ok(mut cursor) = get_collection("accounts")
.find(
doc! {
"_id": {
"$in": target_ids
},
"sessions.subscription": {
"$exists": true
}
},
FindOptions::builder()
.projection(doc! { "sessions": 1 })
.build(),
)
.await
{
let mut subscriptions = vec![];
while let Some(result) = cursor.next().await {
if let Ok(doc) = result {
if let Ok(sessions) = doc.get_array("sessions") {
for session in sessions {
if let Some(doc) = session.as_document() {
if let Ok(sub) = doc.get_document("subscription") {
let endpoint = sub.get_str("endpoint").unwrap().to_string();
let p256dh = sub.get_str("p256dh").unwrap().to_string();
let auth = sub.get_str("auth").unwrap().to_string();
subscriptions
.push(SubscriptionInfo::new(endpoint, p256dh, auth));
}
}
if target_ids.len() > 0 {
if let Ok(mut cursor) = Session::find(
&get_db(),
doc! {
"_id": {
"$in": target_ids
},
"subscription": {
"$exists": true
}
}
}
}
if subscriptions.len() > 0 {
},
None
)
.await {
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();
for subscription in subscriptions {
let mut builder = WebPushMessageBuilder::new(&subscription).unwrap();
let sig_builder = VapidSignatureBuilder::from_pem(
std::io::Cursor::new(&key),
&subscription,
)
.unwrap();
let signature = sig_builder.build().unwrap();
builder.set_vapid_signature(signature);
builder.set_payload(ContentEncoding::AesGcm, enc.as_bytes());
let m = builder.build().unwrap();
client.send(m).await.ok();
while let Some(Ok(session)) = cursor.next().await {
if let Some(sub) = session.subscription {
let subscription = SubscriptionInfo {
endpoint: sub.endpoint,
keys: SubscriptionKeys {
auth: sub.auth,
p256dh: sub.p256dh
}
};
let mut builder = WebPushMessageBuilder::new(&subscription).unwrap();
let sig_builder = VapidSignatureBuilder::from_pem(
std::io::Cursor::new(&key),
&subscription,
)
.unwrap();
let signature = sig_builder.build().unwrap();
builder.set_vapid_signature(signature);
builder.set_payload(ContentEncoding::AesGcm, enc.as_bytes());
let m = builder.build().unwrap();
client.send(m).await.ok();
}
}
}
}
@@ -350,7 +410,7 @@ impl Message {
let attachment_ids: Vec<String> =
attachments.iter().map(|f| f.id.to_string()).collect();
get_collection("attachments")
.update_one(
.update_many(
doc! {
"_id": {
"$in": attachment_ids
@@ -365,7 +425,7 @@ impl Message {
)
.await
.map_err(|_| Error::DatabaseError {
operation: "update_one",
operation: "update_many",
with: "attachment",
})?;
}

View File

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

View File

@@ -46,6 +46,9 @@ pub enum Special {
None,
YouTube {
id: String,
#[serde(skip_serializing_if = "Option::is_none")]
timestamp: Option<String>,
},
Twitch {
content_type: TwitchType,