Merge remote-tracking branch 'origin/main' into livekit

This commit is contained in:
Zomatree
2025-06-02 02:11:51 +01:00
parent 48e0b48ea9
commit ea1c165d80
89 changed files with 1662 additions and 1651 deletions

View File

@@ -64,6 +64,10 @@ pub async fn create_database(db: &MongoDb) {
.await
.expect("Failed to create user_settings collection.");
db.create_collection("policy_changes")
.await
.expect("Failed to create policy_changes collection.");
db.create_collection("safety_reports")
.await
.expect("Failed to create safety_reports collection.");

View File

@@ -5,10 +5,11 @@ use crate::{
bson::{doc, from_bson, from_document, to_document, Bson, DateTime, Document},
options::FindOptions,
},
AbstractChannels, AbstractServers, Channel, Invite, MongoDb, DISCRIMINATOR_SEARCH_SPACE,
AbstractChannels, AbstractServers, Channel, Invite, MongoDb, User, DISCRIMINATOR_SEARCH_SPACE,
};
use bson::oid::ObjectId;
use bson::{oid::ObjectId, to_bson};
use futures::StreamExt;
use iso8601_timestamp::Timestamp;
use rand::seq::SliceRandom;
use revolt_permissions::DEFAULT_WEBHOOK_PERMISSIONS;
use revolt_result::{Error, ErrorType};
@@ -21,7 +22,7 @@ struct MigrationInfo {
revision: i32,
}
pub const LATEST_REVISION: i32 = 33;
pub const LATEST_REVISION: i32 = 43; // MUST BE +1 to last migration
pub async fn migrate_database(db: &MongoDb) {
let migrations = db.col::<Document>("migrations");
@@ -1131,6 +1132,42 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
}
if revision <= 32 {
info!(
"Running migration [revision 32 / 12-05-2025]: (Authifier) Add last_seen to sessions."
);
let db = authifier::Database::MongoDb(authifier::database::MongoDb(db.db()));
db.run_migration(authifier::Migration::M2025_02_20AddLastSeenToSession)
.await
.unwrap();
}
if revision <= 40 {
info!(
"Running migration [revision |> 40 / 30-05-2025]: Set last policy acknowlegement date to now and create policy changes collection."
);
db.db()
.create_collection("policy_changes")
.await
.expect("Failed to create policy_changes collection.");
db.db()
.collection::<User>("users")
.update_many(
doc! {},
doc! {
"$set": {
"last_acknowledged_policy_change": to_bson(&Timestamp::now_utc())
.expect("failed to serialise timestamp")
}
},
)
.await
.expect("failed to update users");
}
if revision <= 41 {
info!("Running migration [revision 32 / 26-01-2025]: Add `is_publishing` and `is_receiving` to members");
db.col::<Document>("server_members")
@@ -1147,7 +1184,7 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
.expect("Failed to update members");
}
if revision <= 33 {
if revision <= 42 {
info!("Running migration [revision 33 / 29-04-2025]: Convert all `VoiceChannel`'s into `TextChannel` ");
db.col::<Document>("channels")

View File

@@ -1,4 +1,3 @@
use revolt_config::config;
use revolt_result::Result;
use ulid::Ulid;

View File

@@ -142,7 +142,7 @@ mod tests {
..Default::default()
};
db.insert_webhook(&webhook).await.unwrap();
webhook.create(&db).await.unwrap();
let mut updated_webhook = webhook.clone();
updated_webhook

View File

@@ -338,13 +338,10 @@ impl Channel {
db.insert_channel(&channel).await?;
match &channel {
Channel::DirectMessage { .. } => {
let event = EventV1::ChannelCreate(channel.clone().into());
event.clone().private(user_a.id.clone()).await;
event.private(user_b.id.clone()).await;
}
_ => {}
if let Channel::DirectMessage { .. } = &channel {
let event = EventV1::ChannelCreate(channel.clone().into());
event.clone().private(user_a.id.clone()).await;
event.private(user_b.id.clone()).await;
};
Ok(channel)

View File

@@ -28,7 +28,7 @@ auto_derived_partial!(
/// Size of this file (in bytes)
pub size: isize,
},
"PartialFile"
"PartialFileHash"
);
auto_derived!(

View File

@@ -5,7 +5,7 @@ use iso8601_timestamp::Timestamp;
use revolt_config::{config, FeaturesLimits};
use revolt_models::v0::{
self, BulkMessageResponse, DataMessageSend, Embed, MessageAuthor, MessageFlags, MessageSort,
MessageWebhook, PushNotification, ReplyIntent, SendableEmbed, Text
MessageWebhook, PushNotification, ReplyIntent, SendableEmbed, Text,
};
use revolt_permissions::{calculate_channel_permissions, ChannelPermission, PermissionValue};
use revolt_result::{ErrorType, Result};
@@ -288,9 +288,9 @@ impl Message {
.map_err(|_| create_error!(InvalidOperation))?;
// Check the message is not empty
if (data.content.as_ref().map_or(true, |v| v.is_empty()))
&& (data.attachments.as_ref().map_or(true, |v| v.is_empty()))
&& (data.embeds.as_ref().map_or(true, |v| v.is_empty()))
if (data.content.as_ref().is_none_or(|v| v.is_empty()))
&& (data.attachments.as_ref().is_none_or(|v| v.is_empty()))
&& (data.embeds.as_ref().is_none_or(|v| v.is_empty()))
{
return Err(create_error!(EmptyMessage));
}
@@ -384,7 +384,7 @@ impl Message {
mut user_mentions,
mut role_mentions,
mut mentions_everyone,
mut mentions_online
mut mentions_online,
} = message_mentions;
if allow_mass_mentions && server_id.is_some() && !role_mentions.is_empty() {
@@ -492,7 +492,9 @@ impl Message {
let valid_members = db.fetch_members(server.as_str(), &mentions_vec[..]).await;
if let Ok(valid_members) = valid_members {
let valid_mentions = HashSet::<&String, RandomState>::from_iter(valid_members.iter().map(|m| &m.id.user));
let valid_mentions = HashSet::<&String, RandomState>::from_iter(
valid_members.iter().map(|m| &m.id.user),
);
user_mentions.retain(|m| valid_mentions.contains(m)); // quick pass, validate mentions are in the server
@@ -506,7 +508,8 @@ impl Message {
.members_can_see_channel()
.await;
user_mentions.retain(|m| *member_channel_view_perms.get(m).unwrap_or(&false));
user_mentions
.retain(|m| *member_channel_view_perms.get(m).unwrap_or(&false));
}
} else {
revolt_config::capture_error(&valid_members.unwrap_err());
@@ -520,7 +523,9 @@ impl Message {
}
if !user_mentions.is_empty() {
message.mentions.replace(user_mentions.into_iter().collect());
message
.mentions
.replace(user_mentions.into_iter().collect());
}
if !role_mentions.is_empty() {
@@ -654,7 +659,7 @@ impl Message {
pub async fn send(
&mut self,
db: &Database,
amqp: Option<&AMQP>, // this is optional mostly for tests.
_amqp: Option<&AMQP>, // this is optional mostly for tests.
author: MessageAuthor<'_>,
user: Option<v0::User>,
member: Option<v0::Member>,

View File

@@ -8,6 +8,7 @@ mod emojis;
mod file_hashes;
mod files;
mod messages;
mod policy_changes;
mod ratelimit_events;
mod safety_reports;
mod safety_snapshots;
@@ -27,6 +28,7 @@ pub use emojis::*;
pub use file_hashes::*;
pub use files::*;
pub use messages::*;
pub use policy_changes::*;
pub use ratelimit_events::*;
pub use safety_reports::*;
pub use safety_snapshots::*;
@@ -51,6 +53,7 @@ pub trait AbstractDatabase:
+ file_hashes::AbstractAttachmentHashes
+ files::AbstractAttachments
+ messages::AbstractMessages
+ policy_changes::AbstractPolicyChange
+ ratelimit_events::AbstractRatelimitEvents
+ safety_reports::AbstractReport
+ safety_snapshots::AbstractSnapshot

View File

@@ -0,0 +1,5 @@
mod model;
mod ops;
pub use model::*;
pub use ops::*;

View File

@@ -0,0 +1,20 @@
use iso8601_timestamp::Timestamp;
auto_derived!(
/// Platform policy change
pub struct PolicyChange {
/// Unique Id
#[serde(rename = "_id")]
pub id: String,
/// Time at which this policy was created
pub created_time: Timestamp,
/// Time at which this policy is effective
pub effective_time: Timestamp,
/// Message shown to users
pub description: String,
/// URL with details about changes
pub url: String,
}
);

View File

@@ -0,0 +1,15 @@
use revolt_result::Result;
use crate::PolicyChange;
mod mongodb;
mod reference;
#[async_trait]
pub trait AbstractPolicyChange: Sync + Send {
/// Fetch all policy changes
async fn fetch_policy_changes(&self) -> Result<Vec<PolicyChange>>;
/// Acknowledge policy changes
async fn acknowledge_policy_changes(&self, user_id: &str) -> Result<()>;
}

View File

@@ -0,0 +1,46 @@
use bson::to_bson;
use iso8601_timestamp::Timestamp;
use revolt_result::Result;
use crate::MongoDb;
use crate::PolicyChange;
use crate::User;
use super::AbstractPolicyChange;
static COL: &str = "policy_changes";
#[async_trait]
impl AbstractPolicyChange for MongoDb {
/// Fetch all policy changes
async fn fetch_policy_changes(&self) -> Result<Vec<PolicyChange>> {
query!(self, find, COL, doc! {})
}
/// Acknowledge policy changes
async fn acknowledge_policy_changes(&self, user_id: &str) -> Result<()> {
let latest_policy = self
.fetch_policy_changes()
.await?
.into_iter()
.map(|policy| policy.created_time)
.max()
.unwrap_or(Timestamp::UNIX_EPOCH);
self.col::<User>("users")
.update_one(
doc! {
"_id": user_id
},
doc! {
"$set": {
"last_acknowledged_policy_change": to_bson(&latest_policy)
.map_err(|_| create_database_error!("to_bson", "timestamp"))?
}
},
)
.await
.map(|_| ())
.map_err(|_| create_database_error!("update_one", COL))
}
}

View File

@@ -0,0 +1,31 @@
use iso8601_timestamp::Timestamp;
use revolt_result::Result;
use crate::PolicyChange;
use crate::ReferenceDb;
use super::AbstractPolicyChange;
#[async_trait]
impl AbstractPolicyChange for ReferenceDb {
/// Fetch all policy changes
async fn fetch_policy_changes(&self) -> Result<Vec<PolicyChange>> {
let policy_changes = self.policy_changes.lock().await;
Ok(policy_changes.values().cloned().collect())
}
/// Acknowledge policy changes
async fn acknowledge_policy_changes(&self, user_id: &str) -> Result<()> {
let mut users = self.users.lock().await;
let user = users.get_mut(user_id).expect("user doesn't exist");
user.last_acknowledged_policy_change = self
.fetch_policy_changes()
.await?
.into_iter()
.map(|policy| policy.created_time)
.max()
.unwrap_or(Timestamp::UNIX_EPOCH);
Ok(())
}
}

View File

@@ -85,8 +85,8 @@ impl SnapshotContent {
Ok((
SnapshotContent::Message {
message,
prior_context: prior_context.into_iter().map(Into::into).collect(),
leading_context: leading_context.into_iter().map(Into::into).collect(),
prior_context: prior_context.into_iter().collect(),
leading_context: leading_context.into_iter().collect(),
},
files,
))

View File

@@ -13,6 +13,7 @@ auto_derived!(
}
);
#[allow(clippy::disallowed_methods)]
impl ServerBan {
/// Create ban
pub async fn create(

View File

@@ -180,7 +180,7 @@ impl Member {
}
/// Update member data
pub async fn update<'a>(
pub async fn update(
&mut self,
db: &Database,
partial: PartialMember,

View File

@@ -285,7 +285,7 @@ impl Role {
}
/// Update server data
pub async fn update<'a>(
pub async fn update(
&mut self,
db: &Database,
server_id: &str,

View File

@@ -9,7 +9,7 @@ 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, UserBadges};
use revolt_models::v0::{self, UserBadges, UserFlags};
use revolt_presence::filter_online;
use revolt_result::{create_error, Result};
use serde_json::json;
@@ -58,6 +58,8 @@ auto_derived_partial!(
/// Time until user is unsuspended
#[serde(skip_serializing_if = "Option::is_none")]
pub suspended_until: Option<Timestamp>,
/// Last acknowledged policy change
pub last_acknowledged_policy_change: Timestamp,
},
"PartialUser"
);
@@ -179,6 +181,7 @@ impl Default for User {
privileged: Default::default(),
bot: Default::default(),
suspended_until: Default::default(),
last_acknowledged_policy_change: Timestamp::UNIX_EPOCH,
}
}
}
@@ -201,6 +204,7 @@ impl User {
id: account_id.into().unwrap_or_else(|| Ulid::new().to_string()),
discriminator: User::find_discriminator(db, &username, None).await?,
username,
last_acknowledged_policy_change: Timestamp::now_utc(),
..Default::default()
};
@@ -350,16 +354,13 @@ impl User {
) -> Result<Vec<v0::User>> {
let online_ids = filter_online(ids).await;
Ok(join_all(
db
.fetch_users(ids)
.await?
.into_iter()
.map(|user| async {
Ok(
join_all(db.fetch_users(ids).await?.into_iter().map(|user| async {
let is_online = online_ids.contains(&user.id);
user.into_known(perspective, is_online).await
})
).await)
}))
.await,
)
}
/// Find a free discriminator for a given username
@@ -653,7 +654,7 @@ impl User {
}
/// Update user data
pub async fn update<'a>(
pub async fn update(
&mut self,
db: &Database,
partial: PartialUser,
@@ -831,7 +832,7 @@ impl User {
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
return badges + UserBadges::EarlyAdopter as u32;
};
};

View File

@@ -6,7 +6,7 @@ use revolt_rocket_okapi::{
use crate::User;
impl<'r> OpenApiFromRequest<'r> for User {
impl OpenApiFromRequest<'_> for User {
fn from_request_input(
_gen: &mut OpenApiGenerator,
_name: String,