fix: add back missing early adopter badge

This commit is contained in:
Zomatree
2025-04-22 19:44:30 +01:00
parent 02f18705f4
commit cc9ff9a632
6 changed files with 48 additions and 17 deletions

View File

@@ -1,5 +1,6 @@
use std::collections::HashSet; use std::collections::HashSet;
use futures::future::join_all;
use revolt_database::{ use revolt_database::{
events::client::{EventV1, ReadyPayloadFields}, events::client::{EventV1, ReadyPayloadFields},
util::permissions::DatabasePermissionQuery, util::permissions::DatabasePermissionQuery,
@@ -201,13 +202,12 @@ impl State {
.collect(); .collect();
// Make all users appear from our perspective. // Make all users appear from our perspective.
let mut users: Vec<v0::User> = users let mut users: Vec<v0::User> = join_all(users
.into_iter() .into_iter()
.map(|other_user| { .map(|other_user| async {
let is_online = online_ids.contains(&other_user.id); let is_online = online_ids.contains(&other_user.id);
other_user.into_known(&user, is_online) other_user.into_known(&user, is_online).await
}) })).await;
.collect();
// Make sure we see our own user correctly. // Make sure we see our own user correctly.
users.push(user.into_self(true).await); users.push(user.into_self(true).await);

View File

@@ -70,6 +70,8 @@ max_concurrent_connections = 50
[api.livekit.nodes] [api.livekit.nodes]
[api.users]
[pushd] [pushd]
# this changes the names of the queues to not overlap # this changes the names of the queues to not overlap
# prod/beta if they happen to be on the same exchange/instance. # prod/beta if they happen to be on the same exchange/instance.

View File

@@ -188,6 +188,10 @@ pub struct LiveKitNode {
pub secret: String pub secret: String
} }
pub struct ApiUsers {
pub early_adopter_cutoff: Option<u64>
}
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
pub struct Api { pub struct Api {
pub registration: ApiRegistration, pub registration: ApiRegistration,
@@ -195,6 +199,7 @@ pub struct Api {
pub security: ApiSecurity, pub security: ApiSecurity,
pub workers: ApiWorkers, pub workers: ApiWorkers,
pub livekit: ApiLiveKit, pub livekit: ApiLiveKit,
pub users: ApiUsers,
} }
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]

View File

@@ -3,12 +3,13 @@ use std::{collections::HashSet, str::FromStr, time::Duration};
use crate::{events::client::EventV1, Database, File, RatelimitEvent, AMQP}; use crate::{events::client::EventV1, Database, File, RatelimitEvent, AMQP};
use authifier::config::{EmailVerificationConfig, Template}; use authifier::config::{EmailVerificationConfig, Template};
use futures::future::join_all;
use iso8601_timestamp::Timestamp; use iso8601_timestamp::Timestamp;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use redis_kiss::{get_connection, AsyncCommands}; use redis_kiss::{get_connection, AsyncCommands};
use revolt_config::{config, FeaturesLimits}; 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_presence::filter_online;
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use serde_json::json; use serde_json::json;
@@ -349,15 +350,16 @@ impl User {
) -> Result<Vec<v0::User>> { ) -> Result<Vec<v0::User>> {
let online_ids = filter_online(ids).await; let online_ids = filter_online(ids).await;
Ok(db Ok(join_all(
db
.fetch_users(ids) .fetch_users(ids)
.await? .await?
.into_iter() .into_iter()
.map(|user| { .map(|user| async {
let is_online = online_ids.contains(&user.id); 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 /// Find a free discriminator for a given username
@@ -821,4 +823,18 @@ impl User {
) )
.await .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
}
} }

View File

@@ -1015,6 +1015,8 @@ impl crate::User {
(RelationshipStatus::None, false) (RelationshipStatus::None, false)
}; };
let badges = self.get_badges().await;
User { User {
username: self.username, username: self.username,
discriminator: self.discriminator, discriminator: self.discriminator,
@@ -1033,7 +1035,7 @@ impl crate::User {
} else { } else {
vec![] vec![]
}, },
badges: self.badges.unwrap_or_default() as u32, badges,
online: can_see_profile online: can_see_profile
&& revolt_presence::is_online(&self.id).await && revolt_presence::is_online(&self.id).await
&& !matches!( && !matches!(
@@ -1059,7 +1061,7 @@ impl crate::User {
/// Convert user object into user model assuming mutual connection /// Convert user object into user model assuming mutual connection
/// ///
/// Relations will never be included, i.e. when we process ourselves /// 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 where
P: Into<Option<&'a crate::User>>, P: Into<Option<&'a crate::User>>,
{ {
@@ -1089,13 +1091,15 @@ impl crate::User {
(RelationshipStatus::None, false) (RelationshipStatus::None, false)
}; };
let badges = self.get_badges().await;
User { User {
username: self.username, username: self.username,
discriminator: self.discriminator, discriminator: self.discriminator,
display_name: self.display_name, display_name: self.display_name,
avatar: self.avatar.map(|file| file.into()), avatar: self.avatar.map(|file| file.into()),
relations: vec![], relations: vec![],
badges: self.badges.unwrap_or_default() as u32, badges,
online: can_see_profile online: can_see_profile
&& is_online && is_online
&& !matches!( && !matches!(
@@ -1119,14 +1123,16 @@ impl crate::User {
} }
/// Convert user object into user model without presence information /// 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 { User {
username: self.username, username: self.username,
discriminator: self.discriminator, discriminator: self.discriminator,
display_name: self.display_name, display_name: self.display_name,
avatar: self.avatar.map(|file| file.into()), avatar: self.avatar.map(|file| file.into()),
relations: vec![], relations: vec![],
badges: self.badges.unwrap_or_default() as u32, badges,
online: is_online online: is_online
&& !matches!( && !matches!(
self.status, self.status,
@@ -1145,6 +1151,8 @@ impl crate::User {
} }
pub async fn into_self(self, force_online: bool) -> User { pub async fn into_self(self, force_online: bool) -> User {
let badges = self.get_badges().await;
User { User {
username: self.username, username: self.username,
discriminator: self.discriminator, discriminator: self.discriminator,
@@ -1159,7 +1167,7 @@ impl crate::User {
.collect() .collect()
}) })
.unwrap_or_default(), .unwrap_or_default(),
badges: self.badges.unwrap_or_default() as u32, badges,
online: (force_online || revolt_presence::is_online(&self.id).await) online: (force_online || revolt_presence::is_online(&self.id).await)
&& !matches!( && !matches!(
self.status, self.status,

View File

@@ -84,7 +84,7 @@ pub async fn message_send(
// Create model user / members // Create model user / members
let model_user = user let model_user = user
.clone() .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<v0::Member> = query let model_member: Option<v0::Member> = query
.member_ref() .member_ref()