From 1d5dae47518261f6f904bab1bccbf1c77a3622af Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Tue, 25 Jun 2024 21:01:45 +0100 Subject: [PATCH] feat(core): include user and member on Message events --- .../database/src/models/channels/model.rs | 6 ++ .../database/src/models/messages/model.rs | 23 +++++-- .../src/models/server_members/model.rs | 4 +- crates/core/database/src/util/bridge/v0.rs | 68 +++++++++++++------ crates/core/models/src/v0/messages.rs | 6 ++ .../delta/src/routes/channels/channel_edit.rs | 8 +-- .../delta/src/routes/channels/message_edit.rs | 2 +- .../src/routes/channels/message_fetch.rs | 2 +- .../delta/src/routes/channels/message_send.rs | 19 +++++- .../src/routes/webhooks/webhook_execute.rs | 4 +- .../routes/webhooks/webhook_execute_github.rs | 9 ++- 11 files changed, 117 insertions(+), 34 deletions(-) diff --git a/crates/core/database/src/models/channels/model.rs b/crates/core/database/src/models/channels/model.rs index 4a879c8c..d48d7aad 100644 --- a/crates/core/database/src/models/channels/model.rs +++ b/crates/core/database/src/models/channels/model.rs @@ -377,6 +377,8 @@ impl Channel { username: &user.username, avatar: user.avatar.as_ref().map(|file| file.id.as_ref()), }, + None, + None, self, false, ) @@ -688,6 +690,8 @@ impl Channel { username: name, avatar: None, }, + None, + None, self, false, ) @@ -723,6 +727,8 @@ impl Channel { username: &user.username, avatar: user.avatar.as_ref().map(|file| file.id.as_ref()), }, + None, + None, self, false, ) diff --git a/crates/core/database/src/models/messages/model.rs b/crates/core/database/src/models/messages/model.rs index b46e73c7..ea79c016 100644 --- a/crates/core/database/src/models/messages/model.rs +++ b/crates/core/database/src/models/messages/model.rs @@ -213,6 +213,8 @@ impl Message { channel: Channel, data: DataMessageSend, author: MessageAuthor<'_>, + user: Option, + member: Option, limits: FeaturesLimits, mut idempotency: IdempotencyKey, generate_embeds: bool, @@ -362,7 +364,9 @@ impl Message { message.nonce = Some(idempotency.into_key()); // Send the message - message.send(db, author, &channel, generate_embeds).await?; + message + .send(db, author, user, member, &channel, generate_embeds) + .await?; Ok(message) } @@ -371,13 +375,15 @@ impl Message { pub async fn send_without_notifications( &mut self, db: &Database, + user: Option, + member: Option, is_dm: bool, generate_embeds: bool, ) -> Result<()> { db.insert_message(self).await?; // Fan out events - EventV1::Message(self.clone().into()) + EventV1::Message(self.clone().into_model(user, member)) .p(self.channel.to_string()) .await; @@ -418,11 +424,15 @@ impl Message { &mut self, db: &Database, author: MessageAuthor<'_>, + user: Option, + member: Option, channel: &Channel, generate_embeds: bool, ) -> Result<()> { self.send_without_notifications( db, + user, + member, matches!(channel, Channel::DirectMessage { .. }), generate_embeds, ) @@ -438,7 +448,12 @@ impl Message { _ => vec![], } }, - PushNotification::from(self.clone().into(), Some(author), &channel.id()).await, + PushNotification::from( + self.clone().into_model(None, None), + Some(author), + &channel.id(), + ) + .await, ) .await; @@ -500,7 +515,7 @@ impl Message { .fetch_messages(query) .await? .into_iter() - .map(Into::into) + .map(|msg| msg.into_model(None, None)) .collect(); if let Some(true) = include_users { diff --git a/crates/core/database/src/models/server_members/model.rs b/crates/core/database/src/models/server_members/model.rs index 63a35ec3..2a38b8bb 100644 --- a/crates/core/database/src/models/server_members/model.rs +++ b/crates/core/database/src/models/server_members/model.rs @@ -150,7 +150,7 @@ impl Member { id: user.id.clone(), } .into_message(id.to_string()) - .send_without_notifications(db, false, false) + .send_without_notifications(db, None, None, false, false) .await .ok(); } @@ -250,7 +250,7 @@ impl Member { } .into_message(id.to_string()) // TODO: support notifications here in the future? - .send_without_notifications(db, false, false) + .send_without_notifications(db, None, None, false, false) .await .ok(); } diff --git a/crates/core/database/src/util/bridge/v0.rs b/crates/core/database/src/util/bridge/v0.rs index 5c1291f4..b0319059 100644 --- a/crates/core/database/src/util/bridge/v0.rs +++ b/crates/core/database/src/util/bridge/v0.rs @@ -459,26 +459,28 @@ impl From for crate::Metadata { } } -impl From for Message { - fn from(value: crate::Message) -> Self { +impl crate::Message { + pub fn into_model(self, user: Option, member: Option) -> Message { Message { - id: value.id, - nonce: value.nonce, - channel: value.channel, - author: value.author, - webhook: value.webhook, - content: value.content, - system: value.system.map(|system| system.into()), - attachments: value + id: self.id, + nonce: self.nonce, + channel: self.channel, + author: self.author, + user, + member, + webhook: self.webhook, + content: self.content, + system: self.system.map(|system| system.into()), + attachments: self .attachments .map(|v| v.into_iter().map(|f| f.into()).collect()), - edited: value.edited, - embeds: value.embeds, - mentions: value.mentions, - replies: value.replies, - reactions: value.reactions, - interactions: value.interactions.into(), - masquerade: value.masquerade.map(|masq| masq.into()), + edited: self.edited, + embeds: self.embeds, + mentions: self.mentions, + replies: self.replies, + reactions: self.reactions, + interactions: self.interactions.into(), + masquerade: self.masquerade.map(|masq| masq.into()), } } } @@ -490,6 +492,8 @@ impl From for PartialMessage { nonce: value.nonce, channel: value.channel, author: value.author, + user: None, + member: None, webhook: value.webhook, content: value.content, system: value.system.map(|system| system.into()), @@ -1089,7 +1093,33 @@ impl crate::User { } } - pub async fn into_self(self) -> User { + /// Convert user object into user model without presence information + pub fn into_known_static<'a>(self, is_online: bool) -> User { + User { + username: self.username, + discriminator: self.discriminator, + display_name: self.display_name, + avatar: self.avatar.map(|file| file.into()), + relations: vec![], + badges: self.badges.unwrap_or_default() as u32, + online: is_online + && !matches!( + self.status, + Some(crate::UserStatus { + presence: Some(crate::Presence::Invisible), + .. + }) + ), + status: self.status.map(|status| status.into()), + flags: self.flags.unwrap_or_default() as u32, + privileged: self.privileged, + bot: self.bot.map(|bot| bot.into()), + relationship: RelationshipStatus::None, // events client will populate this from cache + id: self.id, + } + } + + pub async fn into_self(self, force_online: bool) -> User { User { username: self.username, discriminator: self.discriminator, @@ -1105,7 +1135,7 @@ impl crate::User { }) .unwrap_or_default(), badges: self.badges.unwrap_or_default() as u32, - online: revolt_presence::is_online(&self.id).await + online: (force_online || revolt_presence::is_online(&self.id).await) && !matches!( self.status, Some(crate::UserStatus { diff --git a/crates/core/models/src/v0/messages.rs b/crates/core/models/src/v0/messages.rs index 885abaed..ce2e3cf0 100644 --- a/crates/core/models/src/v0/messages.rs +++ b/crates/core/models/src/v0/messages.rs @@ -31,6 +31,12 @@ auto_derived_partial!( pub channel: String, /// Id of the user or webhook that sent this message pub author: String, + /// The user that sent this message + #[serde(skip_serializing_if = "Option::is_none")] + pub user: Option, + /// The member that sent this message + #[serde(skip_serializing_if = "Option::is_none")] + pub member: Option, /// The webhook that sent this message #[serde(skip_serializing_if = "Option::is_none")] pub webhook: Option, diff --git a/crates/delta/src/routes/channels/channel_edit.rs b/crates/delta/src/routes/channels/channel_edit.rs index 3ee2774b..a26a7b34 100644 --- a/crates/delta/src/routes/channels/channel_edit.rs +++ b/crates/delta/src/routes/channels/channel_edit.rs @@ -73,7 +73,7 @@ pub async fn edit( return Err(create_error!(InvalidOperation)); } .into_message(channel.id().to_string()) - .send(db, user.as_author_for_system(), &channel, false) + .send(db, user.as_author_for_system(), None, None, &channel, false) .await .ok(); } @@ -151,7 +151,7 @@ pub async fn edit( by: user.id.clone(), } .into_message(channel.id().to_string()) - .send(db, user.as_author_for_system(), &channel, false) + .send(db, user.as_author_for_system(), None, None, &channel, false) .await .ok(); } @@ -161,7 +161,7 @@ pub async fn edit( by: user.id.clone(), } .into_message(channel.id().to_string()) - .send(db, user.as_author_for_system(), &channel, false) + .send(db, user.as_author_for_system(), None, None, &channel, false) .await .ok(); } @@ -171,7 +171,7 @@ pub async fn edit( by: user.id.clone(), } .into_message(channel.id().to_string()) - .send(db, user.as_author_for_system(), &channel, false) + .send(db, user.as_author_for_system(), None, None, &channel, false) .await .ok(); } diff --git a/crates/delta/src/routes/channels/message_edit.rs b/crates/delta/src/routes/channels/message_edit.rs index 41958e34..507ce03f 100644 --- a/crates/delta/src/routes/channels/message_edit.rs +++ b/crates/delta/src/routes/channels/message_edit.rs @@ -97,5 +97,5 @@ pub async fn edit( } } - Ok(Json(message.into())) + Ok(Json(message.into_model(None, None))) } diff --git a/crates/delta/src/routes/channels/message_fetch.rs b/crates/delta/src/routes/channels/message_fetch.rs index e2d4f94a..b5e89685 100644 --- a/crates/delta/src/routes/channels/message_fetch.rs +++ b/crates/delta/src/routes/channels/message_fetch.rs @@ -29,5 +29,5 @@ pub async fn fetch( return Err(create_error!(NotFound)); } - Ok(Json(message.into())) + Ok(Json(message.into_model(None, None))) } diff --git a/crates/delta/src/routes/channels/message_send.rs b/crates/delta/src/routes/channels/message_send.rs index 28b90651..93a29057 100644 --- a/crates/delta/src/routes/channels/message_send.rs +++ b/crates/delta/src/routes/channels/message_send.rs @@ -5,6 +5,7 @@ use revolt_database::{ }; use revolt_database::{Interactions, Message}; use revolt_models::v0; +use revolt_permissions::PermissionQuery; use revolt_permissions::{calculate_channel_permissions, ChannelPermission}; use revolt_result::{create_error, Result}; use rocket::serde::json::Json; @@ -75,18 +76,34 @@ pub async fn message_send( // Create the message let author: v0::User = user.clone().into(db, Some(&user)).await; + + // Make sure we have server member (edge case if server owner) + query.are_we_a_member().await; + + // Create model user / members + let model_user = user + .clone() + .into_known_static(revolt_presence::is_online(&user.id).await); + + let model_member: Option = query + .member_ref() + .as_ref() + .map(|member| member.clone().into_owned().into()); + Ok(Json( Message::create_from_api( db, channel, data, v0::MessageAuthor::User(&author), + Some(model_user.clone()), + model_member.clone(), user.limits().await, idempotency, permissions.has_channel_permission(ChannelPermission::SendEmbeds), allow_mentions, ) .await? - .into(), + .into_model(Some(model_user), model_member), )) } diff --git a/crates/delta/src/routes/webhooks/webhook_execute.rs b/crates/delta/src/routes/webhooks/webhook_execute.rs index 6a6eebc4..29b33dde 100644 --- a/crates/delta/src/routes/webhooks/webhook_execute.rs +++ b/crates/delta/src/routes/webhooks/webhook_execute.rs @@ -59,12 +59,14 @@ pub async fn webhook_execute( channel, data, v0::MessageAuthor::Webhook(&webhook.into()), + None, + None, config().await.features.limits.default, idempotency, true, true, ) .await? - .into(), + .into_model(None, None), )) } diff --git a/crates/delta/src/routes/webhooks/webhook_execute_github.rs b/crates/delta/src/routes/webhooks/webhook_execute_github.rs index 16142bef..85bf2e42 100644 --- a/crates/delta/src/routes/webhooks/webhook_execute_github.rs +++ b/crates/delta/src/routes/webhooks/webhook_execute_github.rs @@ -1072,6 +1072,13 @@ pub async fn webhook_execute_github( #[allow(clippy::disallowed_methods)] message.attach_sendable_embed(db, sendable_embed).await?; message - .send(db, MessageAuthor::Webhook(&webhook.into()), &channel, false) + .send( + db, + MessageAuthor::Webhook(&webhook.into()), + None, + None, + &channel, + false, + ) .await }