Public Access
Add proper logging, make commands modularized, add new commands and add event handler
Run cargo test / Run tests (push) Has been cancelled
Run cargo test / Run tests (push) Has been cancelled
This commit is contained in:
1 parent
1732644dd1
commit
c7be6b70dc
16 files changed
+554
-84
No files matched your search
@@ -0,0 +1,232 @@
|
||||
use crate::{Context, Error};
|
||||
use crate::shared_functions::get_all_admin_users;
|
||||
use poise::serenity_prelude as sere;
|
||||
use tracing::{error, warn, info, debug, trace};
|
||||
|
||||
#[derive(Debug, poise::ChoiceParameter)]
|
||||
pub enum AdminOperationType {
|
||||
#[name = "Add user"]
|
||||
AddUser,
|
||||
#[name = "Remove user"]
|
||||
RemoveUser,
|
||||
#[name = "List users"]
|
||||
ListUsers,
|
||||
#[name = "Add role"]
|
||||
AddRole,
|
||||
#[name = "Remove role"]
|
||||
RemoveRole,
|
||||
#[name = "List roles"]
|
||||
ListRoles,
|
||||
}
|
||||
|
||||
/// Admin command
|
||||
#[poise::command(slash_command, prefix_command)]
|
||||
pub async fn manage_admins(ctx: Context<'_>,
|
||||
#[description = "Operation to perform"]
|
||||
operation: Option<AdminOperationType>,
|
||||
#[description = "User"]
|
||||
user: Option<sere::Member>,
|
||||
#[description = "Role"]
|
||||
role: Option<sere::Role>
|
||||
) -> Result<(), Error> {
|
||||
trace!("manage_admins command called by user {}", ctx.author().id.get());
|
||||
let response_message = ctx.say("Running command...").await?;
|
||||
|
||||
if !is_admin(ctx).await? {
|
||||
debug!("User {} is not an admin, denying access", ctx.author().id.get());
|
||||
response_message.edit(ctx, poise::CreateReply::default().content("You are not allowed to run this command.")).await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
|
||||
match operation {
|
||||
Some(AdminOperationType::AddUser) => {
|
||||
if let Some(s_user) = user {
|
||||
add_admin_user(ctx, &response_message, s_user).await?;
|
||||
} else {
|
||||
edit_response_message(&response_message, ctx, "Please provide a user".to_string(), false).await?;
|
||||
}
|
||||
}
|
||||
Some(AdminOperationType::RemoveUser) => {
|
||||
if let Some(s_user) = user {
|
||||
remove_admin_user(ctx, &response_message, s_user).await?;
|
||||
} else {
|
||||
edit_response_message(&response_message, ctx, "Please provide a user".to_string(), false).await?;
|
||||
}
|
||||
}
|
||||
Some(AdminOperationType::ListUsers) => {
|
||||
list_admin_users(ctx, &response_message).await?;
|
||||
}
|
||||
Some(AdminOperationType::AddRole) => {
|
||||
if let Some(s_role) = role {
|
||||
add_admin_role(ctx, &response_message, s_role).await?;
|
||||
} else {
|
||||
edit_response_message(&response_message, ctx, "Please provide a role".to_string(), false).await?;
|
||||
}
|
||||
}
|
||||
Some(AdminOperationType::RemoveRole) => {
|
||||
if let Some(s_role) = role {
|
||||
remove_admin_role(ctx, &response_message, s_role).await?;
|
||||
} else {
|
||||
edit_response_message(&response_message, ctx, "Please provide a role".to_string(), false).await?;
|
||||
}
|
||||
}
|
||||
Some(AdminOperationType::ListRoles) => {
|
||||
list_admin_roles(ctx, &response_message).await?;
|
||||
}
|
||||
None => {
|
||||
edit_response_message(&response_message, ctx, "Please provide an operation".to_string(), false).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn is_admin(ctx: Context<'_>) -> Result<bool, Error> {
|
||||
let user_running_command = ctx.author().id.get() as i64;
|
||||
let admins = get_all_admin_users(ctx).await?;
|
||||
|
||||
for user in admins {
|
||||
if user.id.get() as i64 == user_running_command {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
async fn add_admin_user<'a>(ctx: Context<'a>, msg: &poise::ReplyHandle<'a>, user: sere::Member) -> Result<(), Error> {
|
||||
trace!("Executing add_admin_user for user {}", user.user.name);
|
||||
if is_target_admin_user(ctx, &user).await? {
|
||||
trace!("User {} is already an admin", user.user.name);
|
||||
edit_response_message(msg, ctx, format!("{} is already an admin", user.user.name), false).await?;
|
||||
return Ok(());
|
||||
}
|
||||
let query = sqlx::query!("INSERT INTO admin_users (guild_id, user_id) VALUES ($1, $2);", ctx.guild_id().unwrap().get() as i64, user.user.id.get() as i64).execute(&ctx.data().pool).await;
|
||||
match query {
|
||||
Ok(_) => {
|
||||
info!("Added user {} as admin in guild {}", user.user.name, ctx.guild_id().unwrap().get());
|
||||
edit_response_message(msg, ctx, format!("Added {} as admin", user.user.name), false).await?;
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to add user {} as admin in guild {}: {:?}", user.user.name, ctx.guild_id().unwrap().get(), e);
|
||||
edit_response_message(msg, ctx, format!("Failed to add {} as admin: {}", user.user.name, e), false).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn edit_response_message<'a>(response_message: &poise::ReplyHandle<'a>, ctx: Context<'_>, content: String, silent: bool) -> Result<(), Error> {
|
||||
if silent {
|
||||
response_message.edit(ctx, poise::CreateReply::default().content(content).allowed_mentions(serenity::all::CreateAllowedMentions::new().empty_users())).await?;
|
||||
} else {
|
||||
response_message.edit(ctx, poise::CreateReply::default().content(content)).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn is_target_admin_user(ctx: Context<'_>, user: &sere::Member) -> Result<bool, Error> {
|
||||
let admins = get_all_admin_users(ctx).await?;
|
||||
for admin in admins {
|
||||
if admin.id.get() as i64 == user.user.id.get() as i64 {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
|
||||
async fn remove_admin_user<'a>(ctx: Context<'a>, msg: &poise::ReplyHandle<'a>, user: sere::Member) -> Result<(), Error> {
|
||||
trace!("Executing remove_admin_user for user {}", user.user.name);
|
||||
if !is_target_admin_user(ctx, &user).await? {
|
||||
trace!("User {} is not an admin", user.user.name);
|
||||
edit_response_message(msg, ctx, format!("{} is not an admin", user.user.name), false).await?;
|
||||
return Ok(());
|
||||
}
|
||||
let query = sqlx::query!("DELETE FROM admin_users WHERE guild_id = $1 AND user_id = $2;", ctx.guild_id().unwrap().get() as i64, user.user.id.get() as i64).execute(&ctx.data().pool).await;
|
||||
match query {
|
||||
Ok(_) => {
|
||||
info!("Removed user {} as admin in guild {}", user.user.name, ctx.guild_id().unwrap().get());
|
||||
edit_response_message(msg, ctx, format!("Removed {} as admin", user.user.name), false).await?;
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to remove user {} as admin in guild {}: {:?}", user.user.name, ctx.guild_id().unwrap().get(), e);
|
||||
edit_response_message(msg, ctx, format!("Failed to remove {} as admin: {}", user.user.name, e), false).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn list_admin_users<'a>(ctx: Context<'a>, msg: &poise::ReplyHandle<'a>) -> Result<(), Error> {
|
||||
let admins = get_all_admin_users(ctx).await?;
|
||||
let admin_strings: Vec<String> = admins.iter().map(|user| format!("<@{}>", user.id.get())).collect();
|
||||
edit_response_message(msg, ctx, format!("Admin users: {}", admin_strings.join(", ")), true).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn add_admin_role<'a>(ctx: Context<'a>, msg: &poise::ReplyHandle<'a>, role: sere::Role) -> Result<(), Error> {
|
||||
trace!("Executing add_admin_role for role {}", role.name);
|
||||
if is_target_admin_role(ctx, &role).await? {
|
||||
trace!("Role {} is already an admin role", role.name);
|
||||
edit_response_message(msg, ctx, format!("{} is already an admin role", role.name), false).await?;
|
||||
return Ok(());
|
||||
}
|
||||
let query = sqlx::query!("INSERT INTO admin_roles (guild_id, role_id) VALUES ($1, $2);", ctx.guild_id().unwrap().get() as i64, role.id.get() as i64).execute(&ctx.data().pool).await;
|
||||
match query {
|
||||
Ok(_) => {
|
||||
info!("Added role {} as admin role in guild {}", role.name, ctx.guild_id().unwrap().get());
|
||||
edit_response_message(msg, ctx, format!("Added {} as admin role", role.name), false).await?;
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to add role {} as admin role in guild {}: {:?}", role.name, ctx.guild_id().unwrap().get(), e);
|
||||
edit_response_message(msg, ctx, format!("Failed to add {} as admin role: {}", role.name, e), false).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn remove_admin_role<'a>(ctx: Context<'a>, msg: &poise::ReplyHandle<'a>, role: sere::Role) -> Result<(), Error> {
|
||||
trace!("Executing remove_admin_role for role {}", role.name);
|
||||
if !is_target_admin_role(ctx, &role).await? {
|
||||
trace!("Role {} is not an admin role", role.name);
|
||||
edit_response_message(msg, ctx, format!("{} is not an admin role", role.name), false).await?;
|
||||
return Ok(());
|
||||
}
|
||||
let query = sqlx::query!("DELETE FROM admin_roles WHERE guild_id = $1 AND role_id = $2;", ctx.guild_id().unwrap().get() as i64, role.id.get() as i64).execute(&ctx.data().pool).await;
|
||||
match query {
|
||||
Ok(_) => {
|
||||
info!("Removed role {} as admin role in guild {}", role.name, ctx.guild_id().unwrap().get());
|
||||
edit_response_message(msg, ctx, format!("Removed {} as admin role", role.name), false).await?;
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to remove role {} as admin role in guild {}: {:?}", role.name, ctx.guild_id().unwrap().get(), e);
|
||||
edit_response_message(msg, ctx, format!("Failed to remove {} as admin role: {}", role.name, e), false).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn list_admin_roles<'a>(ctx: Context<'a>, msg: &poise::ReplyHandle<'a>) -> Result<(), Error> {
|
||||
let roles = sqlx::query!("SELECT role_id FROM admin_roles WHERE guild_id = $1", ctx.guild_id().unwrap().get() as i64).fetch_all(&ctx.data().pool).await?;
|
||||
let role_strings: Vec<String> = roles.iter().map(|role| format!("<@&{}>", role.role_id)).collect();
|
||||
edit_response_message(msg, ctx, format!("Admin roles: {}", role_strings.join(", ")), true).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_admin_roles(ctx: Context<'_>) -> Result<Vec<sere::Role>, Error> {
|
||||
let roles = sqlx::query!("SELECT role_id FROM admin_roles WHERE guild_id = $1", ctx.guild_id().unwrap().get() as i64).fetch_all(&ctx.data().pool).await?;
|
||||
let mut admin_roles = Vec::new();
|
||||
for role in roles {
|
||||
admin_roles.push(ctx.guild().unwrap().roles.get(&sere::RoleId::new(role.role_id as u64)).unwrap().clone());
|
||||
}
|
||||
Ok(admin_roles)
|
||||
}
|
||||
|
||||
async fn is_target_admin_role<'a>(ctx: Context<'a>, role: &sere::Role) -> Result<bool, Error> {
|
||||
let roles = get_admin_roles(ctx).await?;
|
||||
for r in roles {
|
||||
if r.id.get() as i64 == role.id.get() as i64 {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
Reference in new issue
Block a user