diff --git a/crates/core/permissions/src/models/channel.rs b/crates/core/permissions/src/models/channel.rs index aca22b5c..a27f410a 100644 --- a/crates/core/permissions/src/models/channel.rs +++ b/crates/core/permissions/src/models/channel.rs @@ -96,8 +96,10 @@ pub enum ChannelPermission { /// Mention roles MentionRoles = 1 << 38, + MoveChannels = 1 << 39, + // * Misc. permissions - // % Bits 38 to 52: free area + // % Bits 40 to 52: free area // % Bits 53 to 64: do not use // * Grant all permissions diff --git a/crates/delta/src/routes/servers/category_edit.rs b/crates/delta/src/routes/servers/category_edit.rs index e503e290..1c824fd3 100644 --- a/crates/delta/src/routes/servers/category_edit.rs +++ b/crates/delta/src/routes/servers/category_edit.rs @@ -34,10 +34,11 @@ pub async fn edit( .ok_or(create_error!(UnknownCategory))? .clone(); - let mut query = DatabasePermissionQuery::new(db, &user).server(&server); - calculate_server_permissions(&mut query) - .await - .throw_if_lacking_channel_permission(ChannelPermission::ManageChannel)?; + let mut query = DatabasePermissionQuery::new(db, &user).server(&server).category(&category); + let permissions = calculate_server_permissions(&mut query) + .await; + + permissions.throw_if_lacking_channel_permission(ChannelPermission::ManageChannel)?; let DataEditCategory { title, @@ -45,9 +46,24 @@ pub async fn edit( remove } = data; + if channels.is_some() { + permissions.throw_if_lacking_channel_permission(ChannelPermission::MoveChannels)?; + } + + // if any channel we are adding to this category are in another category we need to make sure we have MoveChannels in the category before moving it over. + for category in server.categories.values() { + if category.channels.iter().any(|c| channels.as_ref().is_some_and(|cs| cs.contains(c))) { + let mut category_query = query.clone().category(category); + + calculate_server_permissions(&mut category_query) + .await + .throw_if_lacking_channel_permission(ChannelPermission::MoveChannels)?; + } + } + // remove the channels from any existing categories to avoid it having two for category in server.categories.values_mut() { - category.channels.retain(|c| channels.as_ref().map_or(false, |cs| cs.contains(c))); + category.channels.retain(|c| channels.as_ref().is_some_and(|cs| cs.contains(c))); } // only keep channels which exist in the server