From 78cd89ec32e0caac580e9bb3e313fa4de1010e10 Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Wed, 10 Jul 2024 14:04:17 +0100 Subject: [PATCH 1/5] fix: execute query to remove users from groups --- crates/core/database/src/models/channels/model.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/core/database/src/models/channels/model.rs b/crates/core/database/src/models/channels/model.rs index d48d7aad..082acaa9 100644 --- a/crates/core/database/src/models/channels/model.rs +++ b/crates/core/database/src/models/channels/model.rs @@ -702,6 +702,8 @@ impl Channel { } } + db.remove_user_from_group(id, &user.id).await?; + EventV1::ChannelGroupLeave { id: id.to_string(), user: user.id.to_string(), From e290d168acde6ac28a951bc951b356586a615148 Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Wed, 10 Jul 2024 14:12:53 +0100 Subject: [PATCH 2/5] feat: add `reason` to ServerMemberLeave event closes #314 --- crates/bonfire/src/events/impl.rs | 2 +- crates/core/database/src/events/client.rs | 10 +++++++--- .../core/database/src/models/server_members/model.rs | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/crates/bonfire/src/events/impl.rs b/crates/bonfire/src/events/impl.rs index 325267f4..f574e578 100644 --- a/crates/bonfire/src/events/impl.rs +++ b/crates/bonfire/src/events/impl.rs @@ -443,7 +443,7 @@ impl State { EventV1::ServerMemberJoin { .. } => { // We will always receive ServerCreate when joining a new server. } - EventV1::ServerMemberLeave { id, user } => { + EventV1::ServerMemberLeave { id, user, .. } => { if user == &self.cache.user_id { self.remove_subscription(id).await; diff --git a/crates/core/database/src/events/client.rs b/crates/core/database/src/events/client.rs index dd20dd4f..74338bfe 100644 --- a/crates/core/database/src/events/client.rs +++ b/crates/core/database/src/events/client.rs @@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize}; use revolt_models::v0::{ AppendMessage, Channel, Emoji, FieldsChannel, FieldsMember, FieldsRole, FieldsServer, FieldsUser, FieldsWebhook, Member, MemberCompositeKey, Message, PartialChannel, PartialMember, - PartialMessage, PartialRole, PartialServer, PartialUser, PartialWebhook, Report, Server, User, - UserSettings, Webhook, + PartialMessage, PartialRole, PartialServer, PartialUser, PartialWebhook, RemovalIntention, + Report, Server, User, UserSettings, Webhook, }; use revolt_result::Error; @@ -136,7 +136,11 @@ pub enum EventV1 { ServerMemberJoin { id: String, user: String }, /// User left server - ServerMemberLeave { id: String, user: String }, + ServerMemberLeave { + id: String, + user: String, + reason: RemovalIntention, + }, /// Server role created or updated ServerRoleUpdate { diff --git a/crates/core/database/src/models/server_members/model.rs b/crates/core/database/src/models/server_members/model.rs index 2a38b8bb..0ca09ed4 100644 --- a/crates/core/database/src/models/server_members/model.rs +++ b/crates/core/database/src/models/server_members/model.rs @@ -229,6 +229,7 @@ impl Member { EventV1::ServerMemberLeave { id: self.id.server.to_string(), user: self.id.user.to_string(), + reason: intention.clone().into(), } .p(self.id.server.to_string()) .await; From 78b9fa168bf5970c1b90e8091c94c35b06fd84ad Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Wed, 10 Jul 2024 14:17:31 +0100 Subject: [PATCH 3/5] chore: bump version to 0.7.14 --- Cargo.lock | 16 ++++++++-------- crates/bonfire/Cargo.toml | 4 ++-- crates/core/config/Cargo.toml | 2 +- crates/core/database/Cargo.toml | 12 ++++++------ crates/core/models/Cargo.toml | 6 +++--- crates/core/permissions/Cargo.toml | 4 ++-- crates/core/presence/Cargo.toml | 2 +- crates/core/result/Cargo.toml | 2 +- crates/delta/Cargo.toml | 2 +- 9 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index be82b60a..8d36ddc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3593,7 +3593,7 @@ dependencies = [ [[package]] name = "revolt-bonfire" -version = "0.7.13" +version = "0.7.14" dependencies = [ "async-channel 2.3.1", "async-std", @@ -3623,7 +3623,7 @@ dependencies = [ [[package]] name = "revolt-config" -version = "0.7.13" +version = "0.7.14" dependencies = [ "async-std", "cached", @@ -3639,7 +3639,7 @@ dependencies = [ [[package]] name = "revolt-database" -version = "0.7.13" +version = "0.7.14" dependencies = [ "async-lock", "async-recursion", @@ -3686,7 +3686,7 @@ dependencies = [ [[package]] name = "revolt-delta" -version = "0.7.13" +version = "0.7.14" dependencies = [ "async-channel 1.6.1", "async-std", @@ -3733,7 +3733,7 @@ dependencies = [ [[package]] name = "revolt-models" -version = "0.7.13" +version = "0.7.14" dependencies = [ "indexmap 1.9.3", "iso8601-timestamp 0.2.11", @@ -3750,7 +3750,7 @@ dependencies = [ [[package]] name = "revolt-permissions" -version = "0.7.13" +version = "0.7.14" dependencies = [ "async-std", "async-trait", @@ -3765,7 +3765,7 @@ dependencies = [ [[package]] name = "revolt-presence" -version = "0.7.13" +version = "0.7.14" dependencies = [ "async-std", "log", @@ -3776,7 +3776,7 @@ dependencies = [ [[package]] name = "revolt-result" -version = "0.7.13" +version = "0.7.14" dependencies = [ "revolt_okapi", "revolt_rocket_okapi", diff --git a/crates/bonfire/Cargo.toml b/crates/bonfire/Cargo.toml index 574a243a..76ff8823 100644 --- a/crates/bonfire/Cargo.toml +++ b/crates/bonfire/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "revolt-bonfire" -version = "0.7.13" +version = "0.7.14" license = "AGPL-3.0-or-later" edition = "2021" @@ -41,7 +41,7 @@ revolt-result = { path = "../core/result" } revolt-models = { path = "../core/models" } revolt-config = { path = "../core/config" } revolt-database = { path = "../core/database" } -revolt-permissions = { version = "0.7.13", path = "../core/permissions" } +revolt-permissions = { version = "0.7.14", path = "../core/permissions" } revolt-presence = { path = "../core/presence", features = ["redis-is-patched"] } # redis diff --git a/crates/core/config/Cargo.toml b/crates/core/config/Cargo.toml index b7639482..94cfbac4 100644 --- a/crates/core/config/Cargo.toml +++ b/crates/core/config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "revolt-config" -version = "0.7.13" +version = "0.7.14" edition = "2021" license = "MIT" authors = ["Paul Makles "] diff --git a/crates/core/database/Cargo.toml b/crates/core/database/Cargo.toml index 43bad241..d69cbfa0 100644 --- a/crates/core/database/Cargo.toml +++ b/crates/core/database/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "revolt-database" -version = "0.7.13" +version = "0.7.14" edition = "2021" license = "AGPL-3.0-or-later" authors = ["Paul Makles "] @@ -23,13 +23,13 @@ default = ["mongodb", "async-std-runtime", "tasks"] [dependencies] # Core -revolt-config = { version = "0.7.13", path = "../config" } -revolt-result = { version = "0.7.13", path = "../result" } -revolt-models = { version = "0.7.13", path = "../models", features = [ +revolt-config = { version = "0.7.14", path = "../config" } +revolt-result = { version = "0.7.14", path = "../result" } +revolt-models = { version = "0.7.14", path = "../models", features = [ "validator", ] } -revolt-presence = { version = "0.7.13", path = "../presence" } -revolt-permissions = { version = "0.7.13", path = "../permissions", features = [ +revolt-presence = { version = "0.7.14", path = "../presence" } +revolt-permissions = { version = "0.7.14", path = "../permissions", features = [ "serde", "bson", ] } diff --git a/crates/core/models/Cargo.toml b/crates/core/models/Cargo.toml index 17c02575..541ffb46 100644 --- a/crates/core/models/Cargo.toml +++ b/crates/core/models/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "revolt-models" -version = "0.7.13" +version = "0.7.14" edition = "2021" license = "MIT" authors = ["Paul Makles "] @@ -19,8 +19,8 @@ default = ["serde", "partials", "rocket"] [dependencies] # Core -revolt-config = { version = "0.7.13", path = "../config" } -revolt-permissions = { version = "0.7.13", path = "../permissions" } +revolt-config = { version = "0.7.14", path = "../config" } +revolt-permissions = { version = "0.7.14", path = "../permissions" } # Utility regex = "1" diff --git a/crates/core/permissions/Cargo.toml b/crates/core/permissions/Cargo.toml index c378f789..5097796d 100644 --- a/crates/core/permissions/Cargo.toml +++ b/crates/core/permissions/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "revolt-permissions" -version = "0.7.13" +version = "0.7.14" edition = "2021" license = "MIT" authors = ["Paul Makles "] @@ -21,7 +21,7 @@ async-std = { version = "1.8.0", features = ["attributes"] } [dependencies] # Core -revolt-result = { version = "0.7.13", path = "../result" } +revolt-result = { version = "0.7.14", path = "../result" } # Utility auto_ops = "0.3.0" diff --git a/crates/core/presence/Cargo.toml b/crates/core/presence/Cargo.toml index c9cc676d..7103bfe2 100644 --- a/crates/core/presence/Cargo.toml +++ b/crates/core/presence/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "revolt-presence" -version = "0.7.13" +version = "0.7.14" edition = "2021" license = "AGPL-3.0-or-later" authors = ["Paul Makles "] diff --git a/crates/core/result/Cargo.toml b/crates/core/result/Cargo.toml index f083deed..5a629796 100644 --- a/crates/core/result/Cargo.toml +++ b/crates/core/result/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "revolt-result" -version = "0.7.13" +version = "0.7.14" edition = "2021" license = "MIT" authors = ["Paul Makles "] diff --git a/crates/delta/Cargo.toml b/crates/delta/Cargo.toml index 83420a58..eb97eff7 100644 --- a/crates/delta/Cargo.toml +++ b/crates/delta/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "revolt-delta" -version = "0.7.13" +version = "0.7.14" license = "AGPL-3.0-or-later" authors = ["Paul Makles "] edition = "2018" From caa0795d07314fad50106ef07f47cccb9a6f4e92 Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Sun, 14 Jul 2024 16:27:11 +0100 Subject: [PATCH 4/5] fix(core/database); never include relations on known users --- crates/core/database/src/util/bridge/v0.rs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/crates/core/database/src/util/bridge/v0.rs b/crates/core/database/src/util/bridge/v0.rs index 747857cd..87ec4ba1 100644 --- a/crates/core/database/src/util/bridge/v0.rs +++ b/crates/core/database/src/util/bridge/v0.rs @@ -1024,6 +1024,8 @@ impl crate::User { } /// Convert user object into user model assuming mutual connection + /// + /// Relations will never be included, i.e. when we process ourselves pub fn into_known<'a, P>(self, perspective: P, is_online: bool) -> User where P: Into>, @@ -1059,19 +1061,7 @@ impl crate::User { discriminator: self.discriminator, display_name: self.display_name, avatar: self.avatar.map(|file| file.into()), - relations: if let Some(crate::User { id, .. }) = perspective { - if id == &self.id { - self.relations - .unwrap_or_default() - .into_iter() - .map(|relation| relation.into()) - .collect() - } else { - vec![] - } - } else { - vec![] - }, + relations: vec![], badges: self.badges.unwrap_or_default() as u32, online: can_see_profile && is_online From 412f4a99d7a98e8d5995a99bbb1ad3f8b4b1f82c Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Sun, 14 Jul 2024 17:03:40 +0100 Subject: [PATCH 5/5] feat(core/events): add user settings / unreads to Ready payload refactor(core/events): make all Ready payload items optional --- crates/bonfire/src/config.rs | 12 ++++ crates/bonfire/src/events/impl.rs | 77 ++++++++++++++++++----- crates/bonfire/src/websocket.rs | 5 +- crates/core/database/src/events/client.rs | 41 +++++++++--- 4 files changed, 109 insertions(+), 26 deletions(-) diff --git a/crates/bonfire/src/config.rs b/crates/bonfire/src/config.rs index 71b8946a..5642d3ba 100644 --- a/crates/bonfire/src/config.rs +++ b/crates/bonfire/src/config.rs @@ -1,5 +1,6 @@ use async_tungstenite::tungstenite::{handshake, Message}; use futures::channel::oneshot::Sender; +use revolt_database::events::client::ReadyPayloadFields; use revolt_result::{create_error, Result}; use serde::{Deserialize, Serialize}; @@ -83,6 +84,17 @@ impl ProtocolConfiguration { pub fn get_protocol_format(&self) -> &ProtocolFormat { &self.format } + + /// Get ready payload fields + pub fn get_ready_payload_fields(&self) -> Vec { + vec![ + ReadyPayloadFields::Users, + ReadyPayloadFields::Servers, + ReadyPayloadFields::Channels, + ReadyPayloadFields::Members, + ReadyPayloadFields::Emoji, + ] + } } /// Object holding one side of a channel for receiving the parsed information diff --git a/crates/bonfire/src/events/impl.rs b/crates/bonfire/src/events/impl.rs index f574e578..426c7e58 100644 --- a/crates/bonfire/src/events/impl.rs +++ b/crates/bonfire/src/events/impl.rs @@ -1,8 +1,9 @@ use std::collections::HashSet; use revolt_database::{ - events::client::EventV1, util::permissions::DatabasePermissionQuery, Channel, Database, Member, - MemberCompositeKey, Presence, RelationshipStatus, + events::client::{EventV1, ReadyPayloadFields}, + util::permissions::DatabasePermissionQuery, + Channel, Database, Member, MemberCompositeKey, Presence, RelationshipStatus, }; use revolt_models::v0; use revolt_permissions::{calculate_channel_permissions, ChannelPermission}; @@ -90,7 +91,11 @@ impl Cache { /// State Manager impl State { /// Generate a Ready packet for the current user - pub async fn generate_ready_payload(&mut self, db: &Database) -> Result { + pub async fn generate_ready_payload( + &mut self, + db: &Database, + fields: Vec, + ) -> Result { let user = self.clone_user(); self.cache.is_bot = user.bot.is_some(); @@ -150,14 +155,36 @@ impl State { .await?; // Fetch customisations. - let emojis = db - .fetch_emoji_by_parent_ids( - &servers - .iter() - .map(|x| x.id.to_string()) - .collect::>(), + let emojis = if fields.contains(&ReadyPayloadFields::Emoji) { + Some( + db.fetch_emoji_by_parent_ids( + &servers + .iter() + .map(|x| x.id.to_string()) + .collect::>(), + ) + .await?, ) - .await?; + } else { + None + }; + + // Fetch user settings + let user_settings = if let Some(ReadyPayloadFields::UserSettings(keys)) = fields + .iter() + .find(|e| matches!(e, ReadyPayloadFields::UserSettings(_))) + { + Some(db.fetch_user_settings(&user.id, &keys).await?) + } else { + None + }; + + // Fetch channel unreads + let channel_unreads = if fields.contains(&ReadyPayloadFields::ChannelUnreads) { + Some(db.fetch_unreads(&user.id).await?) + } else { + None + }; // Copy data into local state cache. self.cache.users = users.iter().cloned().map(|x| (x.id.clone(), x)).collect(); @@ -201,13 +228,31 @@ impl State { for channel in &channels { self.insert_subscription(channel.id().to_string()).await; } - Ok(EventV1::Ready { - users, - servers: servers.into_iter().map(Into::into).collect(), - channels: channels.into_iter().map(Into::into).collect(), - members: members.into_iter().map(Into::into).collect(), - emojis: emojis.into_iter().map(Into::into).collect(), + users: if fields.contains(&ReadyPayloadFields::Users) { + Some(users) + } else { + None + }, + servers: if fields.contains(&ReadyPayloadFields::Servers) { + Some(servers.into_iter().map(Into::into).collect()) + } else { + None + }, + channels: if fields.contains(&ReadyPayloadFields::Channels) { + Some(channels.into_iter().map(Into::into).collect()) + } else { + None + }, + members: if fields.contains(&ReadyPayloadFields::Members) { + Some(members.into_iter().map(Into::into).collect()) + } else { + None + }, + emojis: emojis.map(|vec| vec.into_iter().map(Into::into).collect()), + + user_settings, + channel_unreads: channel_unreads.map(|vec| vec.into_iter().map(Into::into).collect()), }) } diff --git a/crates/bonfire/src/websocket.rs b/crates/bonfire/src/websocket.rs index d84824b8..db77f399 100644 --- a/crates/bonfire/src/websocket.rs +++ b/crates/bonfire/src/websocket.rs @@ -106,7 +106,10 @@ pub async fn client(db: &'static Database, stream: TcpStream, addr: SocketAddr) } // Download required data to local cache and send Ready payload. - let ready_payload = match state.generate_ready_payload(db).await { + let ready_payload = match state + .generate_ready_payload(db, config.get_ready_payload_fields()) + .await + { Ok(ready_payload) => ready_payload, Err(err) => { sentry::capture_error(&err); diff --git a/crates/core/database/src/events/client.rs b/crates/core/database/src/events/client.rs index 74338bfe..a0b3eef9 100644 --- a/crates/core/database/src/events/client.rs +++ b/crates/core/database/src/events/client.rs @@ -2,10 +2,10 @@ use authifier::AuthifierEvent; use serde::{Deserialize, Serialize}; use revolt_models::v0::{ - AppendMessage, Channel, Emoji, FieldsChannel, FieldsMember, FieldsRole, FieldsServer, - FieldsUser, FieldsWebhook, Member, MemberCompositeKey, Message, PartialChannel, PartialMember, - PartialMessage, PartialRole, PartialServer, PartialUser, PartialWebhook, RemovalIntention, - Report, Server, User, UserSettings, Webhook, + AppendMessage, Channel, ChannelUnread, Emoji, FieldsChannel, FieldsMember, FieldsRole, + FieldsServer, FieldsUser, FieldsWebhook, Member, MemberCompositeKey, Message, PartialChannel, + PartialMember, PartialMessage, PartialRole, PartialServer, PartialUser, PartialWebhook, + RemovalIntention, Report, Server, User, UserSettings, Webhook, }; use revolt_result::Error; @@ -39,6 +39,19 @@ pub enum ErrorEvent { APIError(Error), } +/// Fields provided in Ready payload +#[derive(PartialEq)] +pub enum ReadyPayloadFields { + Users, + Servers, + Channels, + Members, + Emoji, + + UserSettings(Vec), + ChannelUnreads, +} + /// Protocol Events #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type")] @@ -52,11 +65,21 @@ pub enum EventV1 { Logout, /// Basic data to cache Ready { - users: Vec, - servers: Vec, - channels: Vec, - members: Vec, - emojis: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + users: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + servers: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + channels: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + members: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + emojis: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + user_settings: Option, + #[serde(skip_serializing_if = "Option::is_none")] + channel_unreads: Option>, }, /// Ping response