use revolt_database::{ util::{permissions::DatabasePermissionQuery, reference::Reference}, voice::{sync_voice_permissions, VoiceClient}, Database, PartialRole, User }; use revolt_models::v0; use revolt_permissions::{calculate_server_permissions, ChannelPermission}; use revolt_result::{create_error, Result}; use rocket::{serde::json::Json, State}; use validator::Validate; /// # Edit Role /// /// Edit a role by its id. #[openapi(tag = "Server Permissions")] #[patch("//roles/", data = "", rank = 1)] pub async fn edit( db: &State, voice_client: &State, user: User, target: Reference<'_>, role_id: String, data: Json, ) -> Result> { let data = data.into_inner(); data.validate().map_err(|error| { create_error!(FailedValidation { error: error.to_string() }) })?; 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 member_rank = query.get_member_rank().unwrap_or(i64::MIN); if let Some(mut role) = server.roles.remove(&role_id) { // Prevent us from editing roles above us if role.rank <= member_rank { return Err(create_error!(NotElevated)); } let v0::DataEditRole { name, colour, hoist, remove, .. } = data; let partial = PartialRole { name, colour, hoist, ..Default::default() }; role.update( db, &server.id, &role_id, partial, remove.into_iter().map(Into::into).collect(), ) .await?; for channel_id in &server.channels { let channel = Reference::from_unchecked(channel_id).as_channel(db).await?; sync_voice_permissions(db, voice_client, &channel, Some(&server), Some(&role_id)).await?; }; Ok(Json(role.into())) } else { Err(create_error!(NotFound)) } }