forked from jmug/stoatchat
feat: initial bulk role reorder route
This commit is contained in:
@@ -165,6 +165,9 @@ pub enum EventV1 {
|
|||||||
/// Server role deleted
|
/// Server role deleted
|
||||||
ServerRoleDelete { id: String, role_id: String },
|
ServerRoleDelete { id: String, role_id: String },
|
||||||
|
|
||||||
|
/// Server roles ranks updated
|
||||||
|
ServerRoleRanksUpdate { ranks: Vec<String> },
|
||||||
|
|
||||||
/// Update existing user
|
/// Update existing user
|
||||||
UserUpdate {
|
UserUpdate {
|
||||||
id: String,
|
id: String,
|
||||||
|
|||||||
@@ -267,6 +267,7 @@ auto_derived!(
|
|||||||
pub hoist: Option<bool>,
|
pub hoist: Option<bool>,
|
||||||
/// Ranking position
|
/// Ranking position
|
||||||
///
|
///
|
||||||
|
/// **Deprecated** - use the edit server role positions route.
|
||||||
/// Smaller values take priority.
|
/// Smaller values take priority.
|
||||||
pub rank: Option<i64>,
|
pub rank: Option<i64>,
|
||||||
/// Fields to remove from role object
|
/// Fields to remove from role object
|
||||||
@@ -286,4 +287,9 @@ auto_derived!(
|
|||||||
/// Whether to not send a leave message
|
/// Whether to not send a leave message
|
||||||
pub leave_silently: Option<bool>,
|
pub leave_silently: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// New role positions
|
||||||
|
pub struct DataEditRoleRanks {
|
||||||
|
pub ranks: Vec<String>,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ mod roles_create;
|
|||||||
mod roles_delete;
|
mod roles_delete;
|
||||||
mod roles_edit;
|
mod roles_edit;
|
||||||
mod roles_fetch;
|
mod roles_fetch;
|
||||||
|
mod roles_edit_positions;
|
||||||
mod server_ack;
|
mod server_ack;
|
||||||
mod server_create;
|
mod server_create;
|
||||||
mod server_delete;
|
mod server_delete;
|
||||||
@@ -47,6 +48,7 @@ pub fn routes() -> (Vec<Route>, OpenApi) {
|
|||||||
roles_delete::delete,
|
roles_delete::delete,
|
||||||
permissions_set::set_role_permission,
|
permissions_set::set_role_permission,
|
||||||
permissions_set_default::set_default_permissions,
|
permissions_set_default::set_default_permissions,
|
||||||
emoji_list::list_emoji
|
emoji_list::list_emoji,
|
||||||
|
roles_edit_positions::edit_role_positions
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,22 +45,15 @@ pub async fn edit(
|
|||||||
name,
|
name,
|
||||||
colour,
|
colour,
|
||||||
hoist,
|
hoist,
|
||||||
rank,
|
|
||||||
remove,
|
remove,
|
||||||
|
// rank is deprecated
|
||||||
|
..
|
||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
// Prevent us from moving a role above other roles
|
|
||||||
if let Some(rank) = &rank {
|
|
||||||
if rank <= &member_rank {
|
|
||||||
return Err(create_error!(NotElevated));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let partial = PartialRole {
|
let partial = PartialRole {
|
||||||
name,
|
name,
|
||||||
colour,
|
colour,
|
||||||
hoist,
|
hoist,
|
||||||
rank,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
80
crates/delta/src/routes/servers/roles_edit_positions.rs
Normal file
80
crates/delta/src/routes/servers/roles_edit_positions.rs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
use revolt_database::{events::client::EventV1, util::{permissions::DatabasePermissionQuery, reference::Reference}, Database, PartialRole, User};
|
||||||
|
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||||
|
use rocket::{serde::json::Json, State};
|
||||||
|
use revolt_result::{create_error, Result};
|
||||||
|
use revolt_models::v0;
|
||||||
|
|
||||||
|
/// # Edits server roles ranks
|
||||||
|
///
|
||||||
|
/// Edit's server role's ranks.
|
||||||
|
#[openapi(tag = "Server Permissions")]
|
||||||
|
#[patch("/<target>/roles/ranks", data = "<data>")]
|
||||||
|
pub async fn edit_role_ranks(
|
||||||
|
db: &State<Database>,
|
||||||
|
user: User,
|
||||||
|
target: Reference,
|
||||||
|
data: Json<v0::DataEditRoleRanks>,
|
||||||
|
) -> Result<Json<v0::Server>> {
|
||||||
|
let data = data.into_inner();
|
||||||
|
|
||||||
|
let mut server = target.as_server(db).await?;
|
||||||
|
let mut query = DatabasePermissionQuery::new(db, &user).server(&server);
|
||||||
|
calculate_server_permissions(&mut query)
|
||||||
|
.await
|
||||||
|
.throw_if_lacking_channel_permission(ChannelPermission::ManageRole)?;
|
||||||
|
|
||||||
|
let existing_order = server.roles.keys().cloned().collect::<Vec<_>>();
|
||||||
|
let new_order = data.ranks.clone().into_iter().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// verify all roles are in the new ordering
|
||||||
|
if data.ranks.len() != server.roles.len() && server.roles.iter().all(|(id, _)| data.ranks.contains(id)) {
|
||||||
|
return Err(create_error!(InvalidOperation))
|
||||||
|
}
|
||||||
|
|
||||||
|
let member_top_rank = query.get_member_rank();
|
||||||
|
|
||||||
|
// find all roles above the member which we should not be able to reorder
|
||||||
|
let cant_modify = server.roles.clone()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|(_, role)| if let Some(top_rank) = member_top_rank { role.rank >= top_rank } else { true })
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// check if any roles which we cant reorder have tried to been reordered
|
||||||
|
if cant_modify.iter()
|
||||||
|
.any(|(id, _)| {
|
||||||
|
let existing_rank = existing_order.iter().position(|existing_id| id == existing_id);
|
||||||
|
let new_rank = new_order.iter().position(|new_id| id == new_id);
|
||||||
|
|
||||||
|
existing_rank != new_rank
|
||||||
|
})
|
||||||
|
{
|
||||||
|
return Err(create_error!(NotElevated))
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the roles which have had their rank changed
|
||||||
|
for (role_id, role) in &mut server.roles {
|
||||||
|
let new_rank = new_order.iter().position(|id| id == role_id).unwrap() as i64; // unwrap - we check if its in the data earlier on
|
||||||
|
|
||||||
|
if new_rank != role.rank {
|
||||||
|
// cant use Role::update here because we dont want to publish seperate role update events
|
||||||
|
let partial = PartialRole {
|
||||||
|
rank: Some(new_rank),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
db.update_role(&server.id, role_id, &partial, Vec::new()).await?;
|
||||||
|
|
||||||
|
role.apply_options(PartialRole {
|
||||||
|
rank: Some(new_rank),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// publish bulk update event
|
||||||
|
EventV1::ServerRoleRanksUpdate {
|
||||||
|
ranks: new_order
|
||||||
|
}.p(server.id.clone()).await;
|
||||||
|
|
||||||
|
Ok(Json(server.into()))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user