forked from jmug/stoatchat
Merge branch 'main' into feat/livekit
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
use std::{collections::HashSet, ops::BitXor, time::Duration};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
ops::BitXor,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
mongodb::{
|
||||
@@ -22,7 +26,7 @@ struct MigrationInfo {
|
||||
revision: i32,
|
||||
}
|
||||
|
||||
pub const LATEST_REVISION: i32 = 43; // MUST BE +1 to last migration
|
||||
pub const LATEST_REVISION: i32 = 44; // MUST BE +1 to last migration
|
||||
|
||||
pub async fn migrate_database(db: &MongoDb) {
|
||||
let migrations = db.col::<Document>("migrations");
|
||||
@@ -1201,6 +1205,63 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
|
||||
.expect("Failed to update voice channels");
|
||||
};
|
||||
|
||||
if revision <= 43 {
|
||||
info!(
|
||||
"Running migration [revision 43 / 05-06-2025]: convert role ranks to uniform numbers."
|
||||
);
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
struct Role {
|
||||
pub rank: i64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
struct Server {
|
||||
#[serde(rename = "_id")]
|
||||
pub id: String,
|
||||
#[serde(default = "HashMap::<String, Role>::new")]
|
||||
pub roles: HashMap<String, Role>,
|
||||
}
|
||||
|
||||
let mut servers = db
|
||||
.db()
|
||||
.collection::<Server>("servers")
|
||||
.find(doc! {
|
||||
"roles": {
|
||||
"$exists": true,
|
||||
"$ne": []
|
||||
}
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
.filter_map(|s| async { s.ok() })
|
||||
.boxed();
|
||||
|
||||
while let Some(server) = servers.next().await {
|
||||
let mut ordered_roles = server.roles.clone().into_iter().collect::<Vec<_>>();
|
||||
ordered_roles.sort_by(|(_, role_a), (_, role_b)| role_a.rank.cmp(&role_b.rank));
|
||||
let ordered_roles = ordered_roles
|
||||
.into_iter()
|
||||
.map(|(id, _)| id)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut doc = doc! {};
|
||||
|
||||
for id in server.roles.keys() {
|
||||
doc.insert(
|
||||
format!("roles.{id}.rank"),
|
||||
ordered_roles.iter().position(|x| id == x).unwrap() as i64,
|
||||
);
|
||||
}
|
||||
|
||||
db.db()
|
||||
.collection::<Server>("servers")
|
||||
.update_one(doc! { "_id": &server.id }, doc! { "$set": doc })
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Reminder to update LATEST_REVISION when adding new migrations.
|
||||
LATEST_REVISION.max(revision)
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ impl Server {
|
||||
}
|
||||
|
||||
/// Update server data
|
||||
pub async fn update<'a>(
|
||||
pub async fn update(
|
||||
&mut self,
|
||||
db: &Database,
|
||||
partial: PartialServer,
|
||||
@@ -228,6 +228,13 @@ impl Server {
|
||||
}
|
||||
}
|
||||
|
||||
/// Ordered roles list
|
||||
pub fn ordered_roles(&self) -> Vec<(String, Role)> {
|
||||
let mut ordered_roles = self.roles.clone().into_iter().collect::<Vec<_>>();
|
||||
ordered_roles.sort_by(|(_, role_a), (_, role_b)| role_a.rank.cmp(&role_b.rank));
|
||||
ordered_roles
|
||||
}
|
||||
|
||||
/// Set role permission on a server
|
||||
pub async fn set_role_permission(
|
||||
&mut self,
|
||||
@@ -253,6 +260,37 @@ impl Server {
|
||||
Err(create_error!(NotFound))
|
||||
}
|
||||
}
|
||||
|
||||
/// Reorders the server's roles rankings
|
||||
pub async fn set_role_ordering(&mut self, db: &Database, new_order: Vec<String>) -> Result<()> {
|
||||
// New order must always contain every role
|
||||
debug_assert_eq!(self.roles.len(), new_order.len());
|
||||
|
||||
// Set the role's ranks to the positions in the vec
|
||||
for (rank, id) in new_order.iter().enumerate() {
|
||||
self.roles.get_mut(id).unwrap().rank = rank as i64;
|
||||
}
|
||||
|
||||
db.update_server(
|
||||
&self.id,
|
||||
&PartialServer {
|
||||
roles: Some(self.roles.clone()),
|
||||
..Default::default()
|
||||
},
|
||||
Vec::new(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Publish bulk update event
|
||||
EventV1::ServerRoleRanksUpdate {
|
||||
id: self.id.clone(),
|
||||
ranks: new_order,
|
||||
}
|
||||
.p(self.id.clone())
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Role {
|
||||
|
||||
@@ -7,11 +7,5 @@ mod rocket;
|
||||
#[cfg(feature = "rocket-impl")]
|
||||
mod schema;
|
||||
|
||||
#[cfg(feature = "axum-impl")]
|
||||
pub use self::axum::*;
|
||||
#[cfg(feature = "rocket-impl")]
|
||||
pub use self::rocket::*;
|
||||
#[cfg(feature = "rocket-impl")]
|
||||
pub use self::schema::*;
|
||||
pub use model::*;
|
||||
pub use ops::*;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use authifier::models::Session;
|
||||
use iso8601_timestamp::Timestamp;
|
||||
use revolt_result::Result;
|
||||
|
||||
use crate::{FieldsUser, PartialUser, RelationshipStatus, User};
|
||||
@@ -61,4 +62,6 @@ pub trait AbstractUsers: Sync + Send {
|
||||
|
||||
/// Remove push subscription for a session by session id (TODO: remove)
|
||||
async fn remove_push_subscription_by_session_id(&self, session_id: &str) -> Result<()>;
|
||||
|
||||
async fn update_session_last_seen(&self, session_id: &str, when: Timestamp) -> Result<()>;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use ::mongodb::options::{Collation, CollationStrength, FindOneOptions, FindOptions};
|
||||
use authifier::models::Session;
|
||||
use futures::StreamExt;
|
||||
use iso8601_timestamp::Timestamp;
|
||||
use revolt_result::Result;
|
||||
|
||||
use crate::DocumentId;
|
||||
@@ -317,7 +318,26 @@ impl AbstractUsers for MongoDb {
|
||||
)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.map_err(|_| create_database_error!("update_one", COL))
|
||||
.map_err(|_| create_database_error!("update_one", "sessions"))
|
||||
}
|
||||
|
||||
async fn update_session_last_seen(&self, session_id: &str, when: Timestamp) -> Result<()> {
|
||||
let formatted: &str = &when.format();
|
||||
|
||||
self.col::<Session>("sessions")
|
||||
.update_one(
|
||||
doc! {
|
||||
"_id": session_id
|
||||
},
|
||||
doc! {
|
||||
"$set": {
|
||||
"last_seen": formatted
|
||||
}
|
||||
},
|
||||
)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.map_err(|_| create_database_error!("update_one", "sessions"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use authifier::models::Session;
|
||||
use iso8601_timestamp::Timestamp;
|
||||
use revolt_result::Result;
|
||||
|
||||
use crate::{FieldsUser, PartialUser, RelationshipStatus, User};
|
||||
@@ -168,4 +169,8 @@ impl AbstractUsers for ReferenceDb {
|
||||
async fn remove_push_subscription_by_session_id(&self, _session_id: &str) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn update_session_last_seen(&self, _session_id: &str, _when: Timestamp) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user