From cc9ff9a6322b0b51bafd8c5f0b23e54a069bd8df Mon Sep 17 00:00:00 2001 From: Zomatree Date: Tue, 22 Apr 2025 19:44:30 +0100 Subject: [PATCH] fix: add back missing early adopter badge --- crates/bonfire/src/events/impl.rs | 10 +++---- crates/core/config/Revolt.toml | 2 ++ crates/core/config/src/lib.rs | 5 ++++ .../core/database/src/models/users/model.rs | 26 +++++++++++++++---- crates/core/database/src/util/bridge/v0.rs | 20 +++++++++----- .../delta/src/routes/channels/message_send.rs | 2 +- 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/crates/bonfire/src/events/impl.rs b/crates/bonfire/src/events/impl.rs index 5be05c72..6605d46d 100644 --- a/crates/bonfire/src/events/impl.rs +++ b/crates/bonfire/src/events/impl.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; +use futures::future::join_all; use revolt_database::{ events::client::{EventV1, ReadyPayloadFields}, util::permissions::DatabasePermissionQuery, @@ -201,13 +202,12 @@ impl State { .collect(); // Make all users appear from our perspective. - let mut users: Vec = users + let mut users: Vec = join_all(users .into_iter() - .map(|other_user| { + .map(|other_user| async { let is_online = online_ids.contains(&other_user.id); - other_user.into_known(&user, is_online) - }) - .collect(); + other_user.into_known(&user, is_online).await + })).await; // Make sure we see our own user correctly. users.push(user.into_self(true).await); diff --git a/crates/core/config/Revolt.toml b/crates/core/config/Revolt.toml index 73b2bc9a..469abe29 100644 --- a/crates/core/config/Revolt.toml +++ b/crates/core/config/Revolt.toml @@ -70,6 +70,8 @@ max_concurrent_connections = 50 [api.livekit.nodes] +[api.users] + [pushd] # this changes the names of the queues to not overlap # prod/beta if they happen to be on the same exchange/instance. diff --git a/crates/core/config/src/lib.rs b/crates/core/config/src/lib.rs index 29174e7d..b6867de4 100644 --- a/crates/core/config/src/lib.rs +++ b/crates/core/config/src/lib.rs @@ -188,6 +188,10 @@ pub struct LiveKitNode { pub secret: String } +pub struct ApiUsers { + pub early_adopter_cutoff: Option +} + #[derive(Deserialize, Debug, Clone)] pub struct Api { pub registration: ApiRegistration, @@ -195,6 +199,7 @@ pub struct Api { pub security: ApiSecurity, pub workers: ApiWorkers, pub livekit: ApiLiveKit, + pub users: ApiUsers, } #[derive(Deserialize, Debug, Clone)] diff --git a/crates/core/database/src/models/users/model.rs b/crates/core/database/src/models/users/model.rs index 6768258e..f52cf5ae 100644 --- a/crates/core/database/src/models/users/model.rs +++ b/crates/core/database/src/models/users/model.rs @@ -3,12 +3,13 @@ use std::{collections::HashSet, str::FromStr, time::Duration}; use crate::{events::client::EventV1, Database, File, RatelimitEvent, AMQP}; use authifier::config::{EmailVerificationConfig, Template}; +use futures::future::join_all; use iso8601_timestamp::Timestamp; use once_cell::sync::Lazy; use rand::seq::SliceRandom; use redis_kiss::{get_connection, AsyncCommands}; use revolt_config::{config, FeaturesLimits}; -use revolt_models::v0::{self, UserFlags}; +use revolt_models::v0::{self, UserFlags, UserBadges}; use revolt_presence::filter_online; use revolt_result::{create_error, Result}; use serde_json::json; @@ -349,15 +350,16 @@ impl User { ) -> Result> { let online_ids = filter_online(ids).await; - Ok(db + Ok(join_all( + db .fetch_users(ids) .await? .into_iter() - .map(|user| { + .map(|user| async { let is_online = online_ids.contains(&user.id); - user.into_known(perspective, is_online) + user.into_known(perspective, is_online).await }) - .collect()) + ).await) } /// Find a free discriminator for a given username @@ -821,4 +823,18 @@ impl User { ) .await } + + /// Gets the user's badges along with calculating any dynamic badges + pub async fn get_badges(&self) -> u32 { + let config = config().await; + let badges = self.badges.unwrap_or_default() as u32; + + if let Some(cutoff) = config.api.users.early_adopter_cutoff { + if Ulid::from_string(&self.id).unwrap().timestamp_ms() < cutoff { + return badges + UserBadges::EarlyAdopter as u32 + }; + }; + + badges + } } diff --git a/crates/core/database/src/util/bridge/v0.rs b/crates/core/database/src/util/bridge/v0.rs index 0d702efd..ab6246e4 100644 --- a/crates/core/database/src/util/bridge/v0.rs +++ b/crates/core/database/src/util/bridge/v0.rs @@ -1015,6 +1015,8 @@ impl crate::User { (RelationshipStatus::None, false) }; + let badges = self.get_badges().await; + User { username: self.username, discriminator: self.discriminator, @@ -1033,7 +1035,7 @@ impl crate::User { } else { vec![] }, - badges: self.badges.unwrap_or_default() as u32, + badges, online: can_see_profile && revolt_presence::is_online(&self.id).await && !matches!( @@ -1059,7 +1061,7 @@ 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 + pub async fn into_known<'a, P>(self, perspective: P, is_online: bool) -> User where P: Into>, { @@ -1089,13 +1091,15 @@ impl crate::User { (RelationshipStatus::None, false) }; + let badges = self.get_badges().await; + 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, + badges, online: can_see_profile && is_online && !matches!( @@ -1119,14 +1123,16 @@ impl crate::User { } /// Convert user object into user model without presence information - pub fn into_known_static(self, is_online: bool) -> User { + pub async fn into_known_static<'a>(self, is_online: bool) -> User { + let badges = self.get_badges().await; + 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, + badges, online: is_online && !matches!( self.status, @@ -1145,6 +1151,8 @@ impl crate::User { } pub async fn into_self(self, force_online: bool) -> User { + let badges = self.get_badges().await; + User { username: self.username, discriminator: self.discriminator, @@ -1159,7 +1167,7 @@ impl crate::User { .collect() }) .unwrap_or_default(), - badges: self.badges.unwrap_or_default() as u32, + badges, online: (force_online || revolt_presence::is_online(&self.id).await) && !matches!( self.status, diff --git a/crates/delta/src/routes/channels/message_send.rs b/crates/delta/src/routes/channels/message_send.rs index 86d33d79..e0e8f315 100644 --- a/crates/delta/src/routes/channels/message_send.rs +++ b/crates/delta/src/routes/channels/message_send.rs @@ -84,7 +84,7 @@ pub async fn message_send( // Create model user / members let model_user = user .clone() - .into_known_static(revolt_presence::is_online(&user.id).await); + .into_known_static(revolt_presence::is_online(&user.id).await).await; let model_member: Option = query .member_ref()