diff --git a/crates/delta/src/routes/channels/message_edit.rs b/crates/delta/src/routes/channels/message_edit.rs index cf6e6b74..cd226917 100644 --- a/crates/delta/src/routes/channels/message_edit.rs +++ b/crates/delta/src/routes/channels/message_edit.rs @@ -53,11 +53,7 @@ pub async fn req( return Err(Error::CannotEditMessage); } - if let Some(new_embeds) = &edit.embeds { - Message::validate_sum(&edit.content, new_embeds)?; - } else { - Message::validate_sum(&edit.content, &vec![])?; - } + Message::validate_sum(&edit.content, edit.embeds.as_deref().unwrap_or_default())?; message.edited = Some(Timestamp::now_utc()); let mut partial = PartialMessage { @@ -85,7 +81,7 @@ pub async fn req( new_embeds.clear(); for embed in embeds { - new_embeds.push(embed.clone().into_embed(db, message.id.clone()).await?); + new_embeds.push(embed.clone().into_embed(db, &message.id).await?); } } diff --git a/crates/delta/src/routes/channels/message_send.rs b/crates/delta/src/routes/channels/message_send.rs index ef25699e..455327e7 100644 --- a/crates/delta/src/routes/channels/message_send.rs +++ b/crates/delta/src/routes/channels/message_send.rs @@ -47,14 +47,14 @@ pub async fn message_send( } // Check permissions for embeds - if !data.embeds.is_empty() { + if data.embeds.as_ref().is_some_and(|v| !v.is_empty()) { permissions .throw_permission(db, Permission::SendEmbeds) .await?; } // Check permissions for files - if !data.attachments.is_empty() { + if data.attachments.as_ref().is_some_and(|v| !v.is_empty()) { permissions .throw_permission(db, Permission::UploadFiles) .await?; diff --git a/crates/delta/src/routes/webhooks/webhook_execute_github.rs b/crates/delta/src/routes/webhooks/webhook_execute_github.rs index c165b92d..0ca0b8c8 100644 --- a/crates/delta/src/routes/webhooks/webhook_execute_github.rs +++ b/crates/delta/src/routes/webhooks/webhook_execute_github.rs @@ -1065,7 +1065,7 @@ pub async fn webhook_execute_github( let message_id = Ulid::new().to_string(); let embed = sendable_embed - .into_embed(legacy_db, message_id.clone()) + .into_embed(legacy_db, &message_id) .await?; let mut message = Message { diff --git a/crates/quark/src/impl/generic/channels/channel.rs b/crates/quark/src/impl/generic/channels/channel.rs index ee4067b2..b9b135e8 100644 --- a/crates/quark/src/impl/generic/channels/channel.rs +++ b/crates/quark/src/impl/generic/channels/channel.rs @@ -11,7 +11,7 @@ use crate::{ }, tasks::{ack::AckEvent, process_embeds}, types::push::MessageAuthor, - variables::delta::{MAX_ATTACHMENT_COUNT, MAX_REPLY_COUNT}, + variables::delta::{MAX_ATTACHMENT_COUNT, MAX_REPLY_COUNT, MAX_EMBED_COUNT}, web::idempotency::IdempotencyKey, Database, Error, OverrideField, Ref, Result, }; @@ -411,14 +411,14 @@ impl Channel { mut idempotency: IdempotencyKey, generate_embeds: bool, ) -> Result { - Message::validate_sum(&data.content, &data.embeds)?; + Message::validate_sum(&data.content, data.embeds.as_deref().unwrap_or_default())?; idempotency.consume_nonce(data.nonce).await?; // Check the message is not empty if (data.content.as_ref().map_or(true, |v| v.is_empty())) - && (data.attachments.is_empty()) - && (data.embeds.is_empty()) + && (data.attachments.as_ref().map_or(true, |v| v.is_empty())) + && (data.embeds.as_ref().map_or(true, |v| v.is_empty())) { return Err(Error::EmptyMessage); } @@ -497,15 +497,21 @@ impl Channel { // Add attachments to message. let mut attachments = vec![]; - if data.attachments.len() > *MAX_ATTACHMENT_COUNT { + if data.attachments.as_ref().is_some_and(|v| v.len() > *MAX_ATTACHMENT_COUNT) { return Err(Error::TooManyAttachments { max: *MAX_ATTACHMENT_COUNT, }); } - for attachment_id in data.attachments { + if data.embeds.as_ref().is_some_and(|v| v.len() > *MAX_EMBED_COUNT) { + return Err(Error::TooManyEmbeds { + max: *MAX_EMBED_COUNT + }) + } + + for attachment_id in data.attachments.as_deref().unwrap_or_default() { attachments.push( - db.find_and_use_attachment(&attachment_id, "attachments", "message", &message_id) + db.find_and_use_attachment(attachment_id, "attachments", "message", &message_id) .await?, ); } @@ -516,8 +522,8 @@ impl Channel { // Process included embeds. let mut embeds = vec![]; - for sendable_embed in data.embeds { - embeds.push(sendable_embed.into_embed(db, message_id.clone()).await?) + for sendable_embed in data.embeds.unwrap_or_default() { + embeds.push(sendable_embed.into_embed(db, &message_id).await?) } if !embeds.is_empty() { diff --git a/crates/quark/src/impl/generic/channels/message.rs b/crates/quark/src/impl/generic/channels/message.rs index dcf56de3..f92279bb 100644 --- a/crates/quark/src/impl/generic/channels/message.rs +++ b/crates/quark/src/impl/generic/channels/message.rs @@ -170,7 +170,7 @@ impl Message { } /// Validate the sum of content of a message is under threshold - pub fn validate_sum(content: &Option, embeds: &Vec) -> Result<()> { + pub fn validate_sum(content: &Option, embeds: &[SendableEmbed]) -> Result<()> { let mut running_total = 0; if let Some(content) = content { running_total += content.len(); @@ -353,13 +353,13 @@ impl From for String { } impl SendableEmbed { - pub async fn into_embed(self, db: &Database, message_id: String) -> Result { + pub async fn into_embed(self, db: &Database, message_id: &str) -> Result { self.validate() .map_err(|error| Error::FailedValidation { error })?; let media = if let Some(id) = self.media { Some( - db.find_and_use_attachment(&id, "attachments", "message", &message_id) + db.find_and_use_attachment(&id, "attachments", "message", message_id) .await?, ) } else { diff --git a/crates/quark/src/models/channels/message.rs b/crates/quark/src/models/channels/message.rs index 09e2b5d9..6f0d3810 100644 --- a/crates/quark/src/models/channels/message.rs +++ b/crates/quark/src/models/channels/message.rs @@ -269,16 +269,15 @@ pub struct DataMessageSend { #[validate(length(min = 0, max = 2000))] pub content: Option, /// Attachments to include in message - #[serde(default)] - pub attachments: Vec, + + pub attachments: Option>, /// Messages to reply to pub replies: Option>, /// Embeds to include in message /// /// Text embed content contributes to the content length cap - #[serde(default)] - #[validate(length(min = 0, max = 10))] - pub embeds: Vec, + #[validate] + pub embeds: Option>, /// Masquerade to apply to this message #[validate] pub masquerade: Option, diff --git a/crates/quark/src/util/result.rs b/crates/quark/src/util/result.rs index a717d999..45ffaf97 100644 --- a/crates/quark/src/util/result.rs +++ b/crates/quark/src/util/result.rs @@ -53,6 +53,9 @@ pub enum Error { TooManyChannels { max: usize, }, + TooManyEmbeds { + max: usize, + }, EmptyMessage, PayloadTooLarge, CannotRemoveYourself, @@ -191,6 +194,7 @@ impl<'r> Responder<'r, 'static> for Error { Error::TooManyEmoji { .. } => Status::BadRequest, Error::TooManyChannels { .. } => Status::BadRequest, Error::TooManyRoles { .. } => Status::BadRequest, + Error::TooManyEmbeds { .. } => Status::BadRequest, Error::ReachedMaximumBots => Status::BadRequest, Error::IsBot => Status::BadRequest,