From 8be51dc4f0b324216da5fdf953b289670791f62c Mon Sep 17 00:00:00 2001 From: Zomatree <39768508+Zomatree@users.noreply.github.com> Date: Sat, 15 Jan 2022 10:43:47 +0000 Subject: [PATCH] feat(messaging): add sendable embeds (#119) --- src/database/entities/microservice/january.rs | 18 +++++++ src/routes/channels/message_edit.rs | 54 ++++++++++++++----- src/routes/channels/message_send.rs | 44 +++++++++++++-- src/task_queue/task_process_embeds.rs | 6 ++- 4 files changed, 103 insertions(+), 19 deletions(-) diff --git a/src/database/entities/microservice/january.rs b/src/database/entities/microservice/january.rs index 28820451..862ce88b 100644 --- a/src/database/entities/microservice/january.rs +++ b/src/database/entities/microservice/january.rs @@ -3,6 +3,7 @@ use crate::util::{ variables::JANUARY_URL, variables::MAX_EMBED_COUNT, }; +use crate::database::entities::microservice::autumn::File; use linkify::{LinkFinder, LinkKind}; use regex::Regex; use serde::{Deserialize, Serialize}; @@ -92,11 +93,28 @@ pub struct Metadata { colour: Option, } +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Text { + #[serde(skip_serializing_if = "Option::is_none")] + pub icon_url: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub url: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub title: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub media: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub colour: Option, +} + #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type")] pub enum Embed { Website(Metadata), Image(Image), + Text(Text), None, } diff --git a/src/routes/channels/message_edit.rs b/src/routes/channels/message_edit.rs index 3b44c88c..f0799f8f 100644 --- a/src/routes/channels/message_edit.rs +++ b/src/routes/channels/message_edit.rs @@ -1,8 +1,9 @@ use crate::database::*; use crate::util::result::{Error, Result, EmptyResponse}; +use crate::routes::channels::message_send::SendableEmbed; use chrono::Utc; -use mongodb::bson::{doc, Bson, DateTime, Document}; +use mongodb::bson::{Bson, Document, doc, to_document}; use rocket::serde::json::Json; use serde::{Deserialize, Serialize}; use validator::Validate; @@ -10,7 +11,9 @@ use validator::Validate; #[derive(Validate, Serialize, Deserialize)] pub struct Data { #[validate(length(min = 1, max = 2000))] - content: String, + content: Option, + #[validate(length(min = 0, max = 10))] + embeds: Option> } #[patch("//messages/", data = "")] @@ -35,26 +38,48 @@ pub async fn req(user: User, target: Ref, msg: Ref, edit: Json) -> Result< } let edited = Utc::now(); - let mut set = doc! { - "content": &edit.content, - "edited": Bson::DateTime(edited) - }; + let mut set = doc! { "edited": Bson::DateTime(edited) }; + let mut unset = doc! {}; + let mut update = json!({ "edited": Bson::DateTime(edited) }); - message.content = Content::Text(edit.content.clone()); - let mut update = json!({ "content": edit.content, "edited": DateTime(edited) }); + if let Some(new_content) = &edit.content { + set.insert("content", new_content.clone()); + update.as_object_mut().unwrap().insert("content".to_string(), json!(new_content.clone())); + message.content = Content::Text(new_content.clone()); + } + + let mut new_embeds: Vec = vec![]; if let Some(embeds) = &message.embeds { - let new_embeds: Vec = vec![]; - for embed in embeds { match embed { - Embed::Website(_) | Embed::Image(_) | Embed::None => {} // Otherwise push to new_embeds. + Embed::Text(embed) => new_embeds.push(Embed::Text(embed.clone())), + _ => {} } } + } + + if let Some(edited_embeds) = &edit.embeds { + new_embeds.clear(); + + for embed in edited_embeds { + new_embeds.push(embed.clone().into_embed(message.id.clone()).await?); + } + } + + if new_embeds.len() > 0 { + let embed_docs: Vec = new_embeds + .clone() + .into_iter() + .map(|embed| to_document(&embed).unwrap()) + .collect(); let obj = update.as_object_mut().unwrap(); - obj.insert("embeds".to_string(), json!(new_embeds)); - set.insert("embeds", new_embeds); + obj.insert("embeds".to_string(), json!(embed_docs)); + set.insert("embeds", embed_docs); + message.embeds = Some(new_embeds) + } else if edit.embeds.is_some() { + unset.insert("embeds", 1 as u32); } get_collection("messages") @@ -63,7 +88,8 @@ pub async fn req(user: User, target: Ref, msg: Ref, edit: Json) -> Result< "_id": &message.id }, doc! { - "$set": set + "$set": set, + "$unset": unset }, None, ) diff --git a/src/routes/channels/message_send.rs b/src/routes/channels/message_send.rs index d58b0890..afa2cce9 100644 --- a/src/routes/channels/message_send.rs +++ b/src/routes/channels/message_send.rs @@ -18,6 +18,35 @@ pub struct Reply { mention: bool } +#[derive(Validate, Serialize, Deserialize, Clone, Debug)] +pub struct SendableEmbed { + icon_url: Option, + url: Option, + #[validate(length(min = 1, max = 100))] + title: Option, + #[validate(length(min = 1, max = 2000))] + description: Option, + media: Option, + colour: Option, +} + +impl SendableEmbed { + pub async fn into_embed(self, message_id: String) -> Result { + let media = if let Some(id) = self.media { + Some(File::find_and_use(&id, "attachments", "message", &message_id).await?) + } else { None }; + + Ok(Embed::Text(Text { + icon_url: self.icon_url, + url: self.url, + title: self.title, + description: self.description, + media, + colour: self.colour + })) + } +} + #[derive(Validate, Serialize, Deserialize)] pub struct Data { #[validate(length(min = 0, max = 2000))] @@ -27,7 +56,9 @@ pub struct Data { nonce: Option, replies: Option>, #[validate] - masquerade: Option + masquerade: Option, + #[validate(length(min = 1, max = 10))] + embeds: Option> } lazy_static! { @@ -114,6 +145,14 @@ pub async fn message_send(user: User, _r: Ratelimiter, mut idempotency: Idempote } } + let mut embeds = vec![]; + + if let Some(sendable_embeds) = message.embeds { + for sendable_embed in sendable_embeds { + embeds.push(sendable_embed.into_embed(id.clone()).await?) + } + } + let msg = Message { id, channel: target.id().to_string(), @@ -122,8 +161,7 @@ pub async fn message_send(user: User, _r: Ratelimiter, mut idempotency: Idempote content: Content::Text(message.content.clone()), nonce: Some(idempotency.key), edited: None, - embeds: None, - + embeds: if embeds.len() > 0 { Some(embeds) } else { None }, attachments: if attachments.len() > 0 { Some(attachments) } else { None }, mentions: if mentions.len() > 0 { Some(mentions.into_iter().collect::>()) diff --git a/src/task_queue/task_process_embeds.rs b/src/task_queue/task_process_embeds.rs index be79b3e8..112a0eea 100644 --- a/src/task_queue/task_process_embeds.rs +++ b/src/task_queue/task_process_embeds.rs @@ -31,8 +31,10 @@ pub async fn run() { "_id": &id }, doc! { - "$set": { - "embeds": bson + "$push": { + "embeds": { + "$each": bson + } } }, None,