feat(core): include user and member on Message events

This commit is contained in:
Paul Makles
2024-06-25 21:01:45 +01:00
parent ac20b6bc99
commit 1d5dae4751
11 changed files with 117 additions and 34 deletions

View File

@@ -377,6 +377,8 @@ impl Channel {
username: &user.username, username: &user.username,
avatar: user.avatar.as_ref().map(|file| file.id.as_ref()), avatar: user.avatar.as_ref().map(|file| file.id.as_ref()),
}, },
None,
None,
self, self,
false, false,
) )
@@ -688,6 +690,8 @@ impl Channel {
username: name, username: name,
avatar: None, avatar: None,
}, },
None,
None,
self, self,
false, false,
) )
@@ -723,6 +727,8 @@ impl Channel {
username: &user.username, username: &user.username,
avatar: user.avatar.as_ref().map(|file| file.id.as_ref()), avatar: user.avatar.as_ref().map(|file| file.id.as_ref()),
}, },
None,
None,
self, self,
false, false,
) )

View File

@@ -213,6 +213,8 @@ impl Message {
channel: Channel, channel: Channel,
data: DataMessageSend, data: DataMessageSend,
author: MessageAuthor<'_>, author: MessageAuthor<'_>,
user: Option<v0::User>,
member: Option<v0::Member>,
limits: FeaturesLimits, limits: FeaturesLimits,
mut idempotency: IdempotencyKey, mut idempotency: IdempotencyKey,
generate_embeds: bool, generate_embeds: bool,
@@ -362,7 +364,9 @@ impl Message {
message.nonce = Some(idempotency.into_key()); message.nonce = Some(idempotency.into_key());
// Send the message // Send the message
message.send(db, author, &channel, generate_embeds).await?; message
.send(db, author, user, member, &channel, generate_embeds)
.await?;
Ok(message) Ok(message)
} }
@@ -371,13 +375,15 @@ impl Message {
pub async fn send_without_notifications( pub async fn send_without_notifications(
&mut self, &mut self,
db: &Database, db: &Database,
user: Option<v0::User>,
member: Option<v0::Member>,
is_dm: bool, is_dm: bool,
generate_embeds: bool, generate_embeds: bool,
) -> Result<()> { ) -> Result<()> {
db.insert_message(self).await?; db.insert_message(self).await?;
// Fan out events // Fan out events
EventV1::Message(self.clone().into()) EventV1::Message(self.clone().into_model(user, member))
.p(self.channel.to_string()) .p(self.channel.to_string())
.await; .await;
@@ -418,11 +424,15 @@ impl Message {
&mut self, &mut self,
db: &Database, db: &Database,
author: MessageAuthor<'_>, author: MessageAuthor<'_>,
user: Option<v0::User>,
member: Option<v0::Member>,
channel: &Channel, channel: &Channel,
generate_embeds: bool, generate_embeds: bool,
) -> Result<()> { ) -> Result<()> {
self.send_without_notifications( self.send_without_notifications(
db, db,
user,
member,
matches!(channel, Channel::DirectMessage { .. }), matches!(channel, Channel::DirectMessage { .. }),
generate_embeds, generate_embeds,
) )
@@ -438,7 +448,12 @@ impl Message {
_ => vec![], _ => 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; .await;
@@ -500,7 +515,7 @@ impl Message {
.fetch_messages(query) .fetch_messages(query)
.await? .await?
.into_iter() .into_iter()
.map(Into::into) .map(|msg| msg.into_model(None, None))
.collect(); .collect();
if let Some(true) = include_users { if let Some(true) = include_users {

View File

@@ -150,7 +150,7 @@ impl Member {
id: user.id.clone(), id: user.id.clone(),
} }
.into_message(id.to_string()) .into_message(id.to_string())
.send_without_notifications(db, false, false) .send_without_notifications(db, None, None, false, false)
.await .await
.ok(); .ok();
} }
@@ -250,7 +250,7 @@ impl Member {
} }
.into_message(id.to_string()) .into_message(id.to_string())
// TODO: support notifications here in the future? // TODO: support notifications here in the future?
.send_without_notifications(db, false, false) .send_without_notifications(db, None, None, false, false)
.await .await
.ok(); .ok();
} }

View File

@@ -459,26 +459,28 @@ impl From<Metadata> for crate::Metadata {
} }
} }
impl From<crate::Message> for Message { impl crate::Message {
fn from(value: crate::Message) -> Self { pub fn into_model(self, user: Option<User>, member: Option<Member>) -> Message {
Message { Message {
id: value.id, id: self.id,
nonce: value.nonce, nonce: self.nonce,
channel: value.channel, channel: self.channel,
author: value.author, author: self.author,
webhook: value.webhook, user,
content: value.content, member,
system: value.system.map(|system| system.into()), webhook: self.webhook,
attachments: value content: self.content,
system: self.system.map(|system| system.into()),
attachments: self
.attachments .attachments
.map(|v| v.into_iter().map(|f| f.into()).collect()), .map(|v| v.into_iter().map(|f| f.into()).collect()),
edited: value.edited, edited: self.edited,
embeds: value.embeds, embeds: self.embeds,
mentions: value.mentions, mentions: self.mentions,
replies: value.replies, replies: self.replies,
reactions: value.reactions, reactions: self.reactions,
interactions: value.interactions.into(), interactions: self.interactions.into(),
masquerade: value.masquerade.map(|masq| masq.into()), masquerade: self.masquerade.map(|masq| masq.into()),
} }
} }
} }
@@ -490,6 +492,8 @@ impl From<crate::PartialMessage> for PartialMessage {
nonce: value.nonce, nonce: value.nonce,
channel: value.channel, channel: value.channel,
author: value.author, author: value.author,
user: None,
member: None,
webhook: value.webhook, webhook: value.webhook,
content: value.content, content: value.content,
system: value.system.map(|system| system.into()), 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 { User {
username: self.username, username: self.username,
discriminator: self.discriminator, discriminator: self.discriminator,
@@ -1105,7 +1135,7 @@ impl crate::User {
}) })
.unwrap_or_default(), .unwrap_or_default(),
badges: self.badges.unwrap_or_default() as u32, 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!( && !matches!(
self.status, self.status,
Some(crate::UserStatus { Some(crate::UserStatus {

View File

@@ -31,6 +31,12 @@ auto_derived_partial!(
pub channel: String, pub channel: String,
/// Id of the user or webhook that sent this message /// Id of the user or webhook that sent this message
pub author: String, pub author: String,
/// The user that sent this message
#[serde(skip_serializing_if = "Option::is_none")]
pub user: Option<User>,
/// The member that sent this message
#[serde(skip_serializing_if = "Option::is_none")]
pub member: Option<Member>,
/// The webhook that sent this message /// The webhook that sent this message
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub webhook: Option<MessageWebhook>, pub webhook: Option<MessageWebhook>,

View File

@@ -73,7 +73,7 @@ pub async fn edit(
return Err(create_error!(InvalidOperation)); return Err(create_error!(InvalidOperation));
} }
.into_message(channel.id().to_string()) .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 .await
.ok(); .ok();
} }
@@ -151,7 +151,7 @@ pub async fn edit(
by: user.id.clone(), by: user.id.clone(),
} }
.into_message(channel.id().to_string()) .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 .await
.ok(); .ok();
} }
@@ -161,7 +161,7 @@ pub async fn edit(
by: user.id.clone(), by: user.id.clone(),
} }
.into_message(channel.id().to_string()) .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 .await
.ok(); .ok();
} }
@@ -171,7 +171,7 @@ pub async fn edit(
by: user.id.clone(), by: user.id.clone(),
} }
.into_message(channel.id().to_string()) .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 .await
.ok(); .ok();
} }

View File

@@ -97,5 +97,5 @@ pub async fn edit(
} }
} }
Ok(Json(message.into())) Ok(Json(message.into_model(None, None)))
} }

View File

@@ -29,5 +29,5 @@ pub async fn fetch(
return Err(create_error!(NotFound)); return Err(create_error!(NotFound));
} }
Ok(Json(message.into())) Ok(Json(message.into_model(None, None)))
} }

View File

@@ -5,6 +5,7 @@ use revolt_database::{
}; };
use revolt_database::{Interactions, Message}; use revolt_database::{Interactions, Message};
use revolt_models::v0; use revolt_models::v0;
use revolt_permissions::PermissionQuery;
use revolt_permissions::{calculate_channel_permissions, ChannelPermission}; use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use rocket::serde::json::Json; use rocket::serde::json::Json;
@@ -75,18 +76,34 @@ pub async fn message_send(
// Create the message // Create the message
let author: v0::User = user.clone().into(db, Some(&user)).await; 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<v0::Member> = query
.member_ref()
.as_ref()
.map(|member| member.clone().into_owned().into());
Ok(Json( Ok(Json(
Message::create_from_api( Message::create_from_api(
db, db,
channel, channel,
data, data,
v0::MessageAuthor::User(&author), v0::MessageAuthor::User(&author),
Some(model_user.clone()),
model_member.clone(),
user.limits().await, user.limits().await,
idempotency, idempotency,
permissions.has_channel_permission(ChannelPermission::SendEmbeds), permissions.has_channel_permission(ChannelPermission::SendEmbeds),
allow_mentions, allow_mentions,
) )
.await? .await?
.into(), .into_model(Some(model_user), model_member),
)) ))
} }

View File

@@ -59,12 +59,14 @@ pub async fn webhook_execute(
channel, channel,
data, data,
v0::MessageAuthor::Webhook(&webhook.into()), v0::MessageAuthor::Webhook(&webhook.into()),
None,
None,
config().await.features.limits.default, config().await.features.limits.default,
idempotency, idempotency,
true, true,
true, true,
) )
.await? .await?
.into(), .into_model(None, None),
)) ))
} }

View File

@@ -1072,6 +1072,13 @@ pub async fn webhook_execute_github(
#[allow(clippy::disallowed_methods)] #[allow(clippy::disallowed_methods)]
message.attach_sendable_embed(db, sendable_embed).await?; message.attach_sendable_embed(db, sendable_embed).await?;
message message
.send(db, MessageAuthor::Webhook(&webhook.into()), &channel, false) .send(
db,
MessageAuthor::Webhook(&webhook.into()),
None,
None,
&channel,
false,
)
.await .await
} }