From 0def108010005e51c1503c449c246b88f7bde42e Mon Sep 17 00:00:00 2001 From: minneelyyyy Date: Sun, 8 Dec 2024 12:15:54 -0500 Subject: [PATCH] new role management commands, bug fix, table restructuring, better output --- Cargo.lock | 3 --- src/commands/self_roles/color.rs | 19 +++++++------- src/commands/self_roles/disown.rs | 2 +- src/commands/self_roles/mod.rs | 4 ++- src/commands/self_roles/name.rs | 5 ++-- src/commands/self_roles/register.rs | 35 ++++++++++++++++---------- src/commands/self_roles/remove.rs | 39 +++++++++++++++++++++++++++++ src/commands/self_roles/whois.rs | 4 +-- src/common.rs | 16 ++++++++++-- src/main.rs | 5 ++-- 10 files changed, 97 insertions(+), 35 deletions(-) create mode 100644 src/commands/self_roles/remove.rs diff --git a/Cargo.lock b/Cargo.lock index 67e8de1..7d2be5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -204,7 +204,6 @@ dependencies = [ name = "bot" version = "0.1.0" dependencies = [ - "chrono", "clap", "dotenv", "hex_color", @@ -294,10 +293,8 @@ checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", - "js-sys", "num-traits", "serde", - "wasm-bindgen", "windows-targets 0.52.6", ] diff --git a/src/commands/self_roles/color.rs b/src/commands/self_roles/color.rs index 4248e27..26cdb61 100644 --- a/src/commands/self_roles/color.rs +++ b/src/commands/self_roles/color.rs @@ -20,8 +20,15 @@ pub async fn color(ctx: Context<'_>, color: String) -> Result<(), Error> { }; if let Some(guild) = ctx.guild_id() { - let role = match super::get_user_role(ctx, ctx.author().id, guild, db).await? { - Some(role) => role, + match super::get_user_role(ctx.author().id, guild, db).await? { + Some(role) => { + guild.edit_role(ctx, role, EditRole::new().colour(Color::from_rgb(color.r, color.g, color.b))).await?; + let role = guild.role(ctx, role).await?; + + ctx.reply(format!("{}'s color has been updated!", role)).await?; + + Ok(()) + }, None => { let role = guild.create_role(ctx, EditRole::new() @@ -40,13 +47,7 @@ pub async fn color(ctx: Context<'_>, color: String) -> Result<(), Error> { ctx.reply(format!("You have been given the {} role!", role)).await?; return Ok(()); } - }; - - guild.edit_role(ctx, role, EditRole::new().colour(Color::from_rgb(color.r, color.g, color.b))).await?; - - ctx.reply("Your custom role's color has been updated!").await?; - - Ok(()) + } } else { ctx.reply("This command must be run within a server.").await?; Ok(()) diff --git a/src/commands/self_roles/disown.rs b/src/commands/self_roles/disown.rs index 80b3ac1..f95e997 100644 --- a/src/commands/self_roles/disown.rs +++ b/src/commands/self_roles/disown.rs @@ -9,7 +9,7 @@ pub async fn disown(ctx: Context<'_>) -> Result<(), Error> { let db = db.as_mut(); if let Some(guild) = ctx.guild_id() { - if let Some(role) = super::get_user_role(ctx, ctx.author().id, guild, db).await? { + if let Some(role) = super::get_user_role(ctx.author().id, guild, db).await? { guild.delete_role(ctx, role).await?; sqlx::query("DELETE FROM selfroles WHERE roleid = $1") diff --git a/src/commands/self_roles/mod.rs b/src/commands/self_roles/mod.rs index b0c5a98..46dae12 100644 --- a/src/commands/self_roles/mod.rs +++ b/src/commands/self_roles/mod.rs @@ -8,6 +8,7 @@ mod whois; mod color; mod name; mod disown; +mod remove; #[poise::command( prefix_command, @@ -18,13 +19,14 @@ mod disown; "color::color", "name::name", "disown::disown", + "remove::remove", ) )] pub async fn role(_ctx: Context<'_>) -> Result<(), Error> { Ok(()) } -pub async fn get_user_role(_ctx: Context<'_>, user: UserId, guild: GuildId, db: &mut PgConnection) -> Result, Error> { +pub async fn get_user_role(user: UserId, guild: GuildId, db: &mut PgConnection) -> Result, Error> { match sqlx::query("SELECT roleid FROM selfroles WHERE userid = $1 AND guildid = $2") .bind(user.get() as i64) .bind(guild.get() as i64) diff --git a/src/commands/self_roles/name.rs b/src/commands/self_roles/name.rs index 6e40b07..e4d6ee0 100644 --- a/src/commands/self_roles/name.rs +++ b/src/commands/self_roles/name.rs @@ -11,7 +11,7 @@ pub async fn name(ctx: Context<'_>, name: String) -> Result<(), Error> { let db = db.as_mut(); if let Some(guild) = ctx.guild_id() { - let role = match super::get_user_role(ctx, ctx.author().id, guild, db).await? { + let role = match super::get_user_role(ctx.author().id, guild, db).await? { Some(role) => role, None => { let role = guild.create_role(ctx, EditRole::new().name(name)).await?; @@ -32,8 +32,9 @@ pub async fn name(ctx: Context<'_>, name: String) -> Result<(), Error> { }; guild.edit_role(ctx, role, EditRole::new().name(name)).await?; + let role = guild.role(ctx, role).await?; - ctx.reply("Your custom role's name has been updated!").await?; + ctx.reply(format!("Your custom role's name has been updated to {}.", role)).await?; Ok(()) } else { diff --git a/src/commands/self_roles/register.rs b/src/commands/self_roles/register.rs index cb7070b..f4efa1e 100644 --- a/src/commands/self_roles/register.rs +++ b/src/commands/self_roles/register.rs @@ -1,27 +1,36 @@ -use crate::common::{Context, Error}; +use crate::common::{self, Context, Error}; use poise::serenity_prelude as serenity; /// Register an existing role as a user's custom role #[poise::command(slash_command, prefix_command, required_permissions = "MANAGE_ROLES")] -pub async fn register(ctx: Context<'_>, user: Option, role: serenity::Role) -> Result<(), Error> { +pub async fn register(ctx: Context<'_>, user: serenity::User, role: serenity::Role) -> Result<(), Error> { let data = ctx.data(); let mut db = data.database.lock().await; let db = db.as_mut(); - let user = user.as_ref().unwrap_or(ctx.author()); + if let Some(guild) = ctx.guild_id() { + match super::get_user_role(user.id, guild, db).await? { + Some(role) => { + common::no_ping_reply(&ctx, format!("{} already has the role {} registered.", user, role)).await?; + Ok(()) + }, + None => { + sqlx::query("INSERT INTO selfroles (userid, guildid, roleid) VALUES ($1, $2, $3)") + .bind(user.id.get() as i64) + .bind(guild.get() as i64) + .bind(role.id.get() as i64) + .execute(db).await?; - if let Some(guild) = ctx.guild().map(|g| g.id) { - sqlx::query("INSERT INTO selfroles (userid, roleid, guildid) VALUES ($1, $2, $3) ON CONFLICT (userid) DO UPDATE SET roleid = EXCLUDED.roleid") - .bind(user.id.get() as i64) - .bind(role.id.get() as i64) - .bind(guild.get() as i64) - .execute(db).await?; - - ctx.reply(format!("**{}** now has **{}** set as their personal role.", user.display_name(), role.name)).await?; - - Ok(()) + let member = guild.member(ctx, user.id).await?; + member.add_role(ctx, role.id).await?; + + common::no_ping_reply(&ctx, format!("{} now has {} set as their personal role.", user, role)).await?; + + Ok(()) + } + } } else { ctx.reply("This command can only be run in a guild!").await?; Ok(()) diff --git a/src/commands/self_roles/remove.rs b/src/commands/self_roles/remove.rs new file mode 100644 index 0000000..3493dbb --- /dev/null +++ b/src/commands/self_roles/remove.rs @@ -0,0 +1,39 @@ + +use crate::common::{self, Context, Error}; + +use poise::serenity_prelude as serenity; + +/// force remove someone's role (this does not delete the role) +#[poise::command(slash_command, prefix_command, required_permissions = "MANAGE_ROLES")] +pub async fn remove(ctx: Context<'_>, user: serenity::User) -> Result<(), Error> { + let data = ctx.data(); + let mut db = data.database.lock().await; + let db = db.as_mut(); + + if let Some(guild) = ctx.guild_id() { + match super::get_user_role(user.id, guild, db).await? { + Some(role) => { + sqlx::query("DELETE FROM selfroles WHERE userid = $1 AND guildid = $2") + .bind(user.id.get() as i64) + .bind(guild.get() as i64) + .execute(db).await?; + + let member = guild.member(ctx, user.id).await?; + + member.remove_role(ctx, role).await?; + let role = guild.role(ctx, role).await?; + + common::no_ping_reply(&ctx, format!("{} has had {} removed.", user, role)).await?; + + Ok(()) + }, + None => { + common::no_ping_reply(&ctx, format!("{} does not have a personal role to remove.", user)).await?; + Ok(()) + } + } + } else { + ctx.reply("This command can only be run in a guild!").await?; + Ok(()) + } +} diff --git a/src/commands/self_roles/whois.rs b/src/commands/self_roles/whois.rs index c9762c1..8475494 100644 --- a/src/commands/self_roles/whois.rs +++ b/src/commands/self_roles/whois.rs @@ -1,5 +1,5 @@ -use crate::common::{Context, Error}; +use crate::common::{self, Context, Error}; use poise::serenity_prelude as serenity; use serenity::UserId; @@ -31,7 +31,7 @@ pub async fn whois(ctx: Context<'_>, role: serenity::Role) -> Result<(), Error> let member = guild.member(ctx, user).await?; - ctx.reply(format!("{} owns this role.", member.display_name())).await?; + common::no_ping_reply(&ctx, format!("{} owns this role.", member)).await?; } else { ctx.reply("This command must be used within a server!").await?; } diff --git a/src/common.rs b/src/common.rs index f61938b..9a7ba04 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use tokio::sync::Mutex; use std::collections::HashMap; -use poise::serenity_prelude::UserId; +use poise::{serenity_prelude::UserId, ReplyHandle}; use sqlx::PgConnection; pub struct Data { @@ -13,4 +13,16 @@ pub struct Data { } pub type Error = Box; -pub type Context<'a> = poise::Context<'a, Data, Error>; \ No newline at end of file +pub type Context<'a> = poise::Context<'a, Data, Error>; + +use poise::serenity_prelude::builder::CreateAllowedMentions; +use poise::CreateReply; + +pub async fn no_ping_reply<'a>(ctx: &'a Context<'_>, text: impl Into) -> Result, Error> { + Ok(ctx.send( + CreateReply::default() + .content(text.into()) + .reply(true) + .allowed_mentions(CreateAllowedMentions::new()) + ).await?) +} diff --git a/src/main.rs b/src/main.rs index b02446f..c040bc0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -82,9 +82,10 @@ async fn main() -> Result<(), Error> { sqlx::query( r#" CREATE TABLE IF NOT EXISTS selfroles ( - userid BIGINT, + userid BIGINT NOT NULL, + guildid BIGINT NOT NULL, roleid BIGINT, - guildid BIGINT + UNIQUE (userid, guildid) ) "#, ).execute(&mut database).await?;