diff --git a/cipher_discord_bot/src/app/mod.rs b/cipher_discord_bot/src/app/mod.rs index 8259f62..2d5e8be 100644 --- a/cipher_discord_bot/src/app/mod.rs +++ b/cipher_discord_bot/src/app/mod.rs @@ -29,6 +29,8 @@ pub enum AppError { SerenityError(#[from] serenity::Error), #[error(transparent)] RepositoryError(#[from] RepositoryError), + #[error("staff-only command used by non-staff user")] + StaffOnly { command_name: String }, } pub type AppContext<'a, R, E> = poise::ApplicationContext<'a, AppData, AppError>; diff --git a/cipher_discord_bot/src/app/on_error.rs b/cipher_discord_bot/src/app/on_error.rs index 9091ff3..18a98d9 100644 --- a/cipher_discord_bot/src/app/on_error.rs +++ b/cipher_discord_bot/src/app/on_error.rs @@ -158,7 +158,7 @@ where format!("nsfw-only command `{}` cannot be run in non-nsfw channels", ctx.command().qualified_name), log::Level::Info, ), - F::CommandCheckFailed { error, ctx, .. } => error.map(Into::into).unwrap_or_else(|| ErrorMessage::new( + F::CommandCheckFailed { error, ctx, .. } => error.map(|err| err.into()).unwrap_or_else(|| ErrorMessage::new( "Command Check Failed", "A pre-command check failed without a reason. Please contact a bot administrator to review the logs for further details.", format!("pre-command check for command `{}` either denied access or errored without a reason", ctx.command().qualified_name), @@ -293,6 +293,13 @@ where format!("repository backend error: {}", error), log::Level::Error, ), + + A::StaffOnly { command_name } => ErrorMessage::new( + "Staff Only Command", + format!("`/{}` can only be used by staff.", command_name), + format!("staff-only command `{}` cannot be run by non-staff users", command_name), + log::Level::Info, + ) } } } diff --git a/cipher_discord_bot/src/commands/profile.rs b/cipher_discord_bot/src/commands/profile.rs index 2129c14..d3d52d7 100644 --- a/cipher_discord_bot/src/commands/profile.rs +++ b/cipher_discord_bot/src/commands/profile.rs @@ -1,3 +1,4 @@ +use cipher_core::repository::staff_role_repository::StaffRoleRepository; use cipher_core::repository::user_repository::NewUser; use cipher_core::repository::user_repository::User; use cipher_core::repository::user_repository::UserRepository; @@ -10,6 +11,7 @@ use serenity::all::CreateEmbed; use serenity::all::Member; use crate::app::AppContext; +use crate::app::AppData; use crate::app::AppError; use crate::utils; @@ -69,11 +71,27 @@ pub async fn edit(ctx: AppContext<'_, R, R: Ok(()) } +async fn is_staff(ctx: poise::Context<'_, AppData, AppError>) -> Result> +where + R: RepositoryProvider, +{ + let roles: Vec<_> = match ctx.author_member().await { + Some(member) => member.roles.iter().map(|r| r.get()).collect(), + None => return Ok(false), + }; + + match ctx.data().repository().await?.staff_roles_contains(&roles).await { + Ok(true) => Ok(true), + Ok(false) => Err(AppError::StaffOnly { command_name: ctx.command().qualified_name.clone() }), + Err(err) => Err(AppError::from(err)), + } +} + /// Edit any user's profile. #[poise::command( slash_command, hide_in_help, - owners_only, + check = "is_staff", )] pub async fn overwrite( ctx: AppContext<'_, R, R::BackendError>,