add custom role management
This commit is contained in:
@@ -3,7 +3,6 @@ use crate::common::{Context, Error};
|
||||
use poise::serenity_prelude as serenity;
|
||||
use serenity::Colour;
|
||||
|
||||
|
||||
// this code uses Member::permissions, which while it is a deprecated function, it doesn't actually matter
|
||||
// since it is only used to display information to the user.
|
||||
#[allow(deprecated)]
|
||||
|
||||
@@ -30,8 +30,8 @@ pub async fn daily(ctx: Context<'_>) -> Result<(), Error> {
|
||||
super::add_balance(id, 50, db).await?;
|
||||
ctx.reply("Added **50** credits to your account!").await?;
|
||||
} else {
|
||||
let until_next_daily = Duration::from_secs(10) - daily.elapsed();
|
||||
ctx.reply(format!("Your daily will be available in {:?}.", format_duration(until_next_daily))).await?;
|
||||
let until_next_daily = Duration::from_secs(24 * 60 * 60) - daily.elapsed();
|
||||
ctx.reply(format!("Your next daily will be available in **{}**.", format_duration(until_next_daily))).await?;
|
||||
}
|
||||
},
|
||||
None => {
|
||||
|
||||
@@ -18,5 +18,6 @@ pub fn commands() -> Vec<Command<Data, Error>> {
|
||||
gambling::wager::wager(),
|
||||
gambling::daily::daily(),
|
||||
eval::eval(),
|
||||
self_roles::role(),
|
||||
]
|
||||
}
|
||||
|
||||
54
src/commands/self_roles/color.rs
Normal file
54
src/commands/self_roles/color.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
|
||||
use crate::common::{Context, Error};
|
||||
|
||||
use hex_color::HexColor;
|
||||
use poise::serenity_prelude::{Color, EditRole};
|
||||
|
||||
/// Change the color of your personal role
|
||||
#[poise::command(slash_command, prefix_command)]
|
||||
pub async fn color(ctx: Context<'_>, color: String) -> Result<(), Error> {
|
||||
let data = ctx.data();
|
||||
let mut db = data.database.lock().await;
|
||||
let db = db.as_mut();
|
||||
|
||||
let color = match HexColor::parse_rgb(&color) {
|
||||
Ok(color) => color,
|
||||
Err(e) => {
|
||||
ctx.reply(format!("Couldn't parse color: {e}")).await?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(guild) = ctx.guild_id() {
|
||||
let role = match super::get_user_role(ctx, ctx.author().id, guild, db).await? {
|
||||
Some(role) => role,
|
||||
None => {
|
||||
let role = guild.create_role(ctx,
|
||||
EditRole::new()
|
||||
.name(format!("{}", color.display_rgb()))
|
||||
.colour(Color::from_rgb(color.r, color.g, color.b))).await?;
|
||||
|
||||
sqlx::query("INSERT INTO selfroles (userid, roleid, guildid) VALUES ($1, $2, $3)")
|
||||
.bind(ctx.author().id.get() as i64)
|
||||
.bind(role.id.get() as i64)
|
||||
.bind(guild.get() as i64)
|
||||
.execute(db).await?;
|
||||
|
||||
let member = guild.member(ctx, ctx.author().id).await?;
|
||||
member.add_role(ctx, role.clone()).await?;
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
30
src/commands/self_roles/disown.rs
Normal file
30
src/commands/self_roles/disown.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
use crate::common::{Context, Error};
|
||||
|
||||
/// Remove and delete your personal role
|
||||
#[poise::command(slash_command, prefix_command)]
|
||||
pub async fn disown(ctx: Context<'_>) -> 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() {
|
||||
if let Some(role) = super::get_user_role(ctx, ctx.author().id, guild, db).await? {
|
||||
guild.delete_role(ctx, role).await?;
|
||||
|
||||
sqlx::query("DELETE FROM selfroles WHERE roleid = $1")
|
||||
.bind(role.get() as i64)
|
||||
.execute(db).await?;
|
||||
|
||||
ctx.reply("Your role has been successfully removed.").await?;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
ctx.reply("You do not currently have a personal role to remove.").await?;
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
ctx.reply("This command must be called within a server.").await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
37
src/commands/self_roles/mod.rs
Normal file
37
src/commands/self_roles/mod.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
use crate::common::{Context, Error};
|
||||
use sqlx::{PgConnection, Row};
|
||||
use poise::serenity_prelude::{RoleId, UserId, GuildId};
|
||||
|
||||
mod register;
|
||||
mod whois;
|
||||
mod color;
|
||||
mod name;
|
||||
mod disown;
|
||||
|
||||
#[poise::command(
|
||||
prefix_command,
|
||||
slash_command,
|
||||
subcommands(
|
||||
"register::register",
|
||||
"whois::whois",
|
||||
"color::color",
|
||||
"name::name",
|
||||
"disown::disown",
|
||||
)
|
||||
)]
|
||||
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<Option<RoleId>, Error> {
|
||||
match sqlx::query("SELECT roleid FROM selfroles WHERE userid = $1 AND guildid = $2")
|
||||
.bind(user.get() as i64)
|
||||
.bind(guild.get() as i64)
|
||||
.fetch_one(db).await
|
||||
{
|
||||
Ok(row) => Ok(Some(RoleId::new(row.try_get::<i64, usize>(0)? as u64))),
|
||||
Err(sqlx::Error::RowNotFound) => Ok(None),
|
||||
Err(e) => return Err(Box::new(e)),
|
||||
}
|
||||
}
|
||||
43
src/commands/self_roles/name.rs
Normal file
43
src/commands/self_roles/name.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
use crate::common::{Context, Error};
|
||||
|
||||
use poise::serenity_prelude::EditRole;
|
||||
|
||||
/// Change the name of your personal role
|
||||
#[poise::command(slash_command, prefix_command)]
|
||||
pub async fn name(ctx: Context<'_>, name: String) -> 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() {
|
||||
let role = match super::get_user_role(ctx, ctx.author().id, guild, db).await? {
|
||||
Some(role) => role,
|
||||
None => {
|
||||
let role = guild.create_role(ctx, EditRole::new().name(name)).await?;
|
||||
|
||||
sqlx::query("INSERT INTO selfroles (userid, roleid, guildid) VALUES ($1, $2, $3)")
|
||||
.bind(ctx.author().id.get() as i64)
|
||||
.bind(role.id.get() as i64)
|
||||
.bind(guild.get() as i64)
|
||||
.execute(db).await?;
|
||||
|
||||
let member = guild.member(ctx, ctx.author().id).await?;
|
||||
member.add_role(ctx, role.clone()).await?;
|
||||
|
||||
ctx.reply(format!("You've been given the {} role!", role)).await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
guild.edit_role(ctx, role, EditRole::new().name(name)).await?;
|
||||
|
||||
ctx.reply("Your custom role's name has been updated!").await?;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
ctx.reply("This command must be run within a server.").await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
29
src/commands/self_roles/register.rs
Normal file
29
src/commands/self_roles/register.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
use crate::common::{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<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().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(())
|
||||
} else {
|
||||
ctx.reply("This command can only be run in a guild!").await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
40
src/commands/self_roles/whois.rs
Normal file
40
src/commands/self_roles/whois.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
use crate::common::{Context, Error};
|
||||
|
||||
use poise::serenity_prelude as serenity;
|
||||
use serenity::UserId;
|
||||
use sqlx::Row;
|
||||
|
||||
/// Let you know who is the owner of a role.
|
||||
#[poise::command(slash_command, prefix_command)]
|
||||
pub async fn whois(ctx: Context<'_>, role: serenity::Role) -> 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() {
|
||||
let row = match sqlx::query("SELECT userid FROM selfroles WHERE roleid = $1")
|
||||
.bind(role.id.get() as i64)
|
||||
.fetch_one(db).await
|
||||
{
|
||||
Ok(row) => row,
|
||||
Err(sqlx::Error::RowNotFound) => {
|
||||
ctx.reply("This role is not owned by anyone.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
Err(e) => return Err(Box::new(e)),
|
||||
};
|
||||
|
||||
let user: i64 = row.try_get(0)?;
|
||||
|
||||
let user = UserId::new(user as u64);
|
||||
|
||||
let member = guild.member(ctx, user).await?;
|
||||
|
||||
ctx.reply(format!("{} owns this role.", member.display_name())).await?;
|
||||
} else {
|
||||
ctx.reply("This command must be used within a server!").await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -7,6 +7,9 @@ use sqlx::PgConnection;
|
||||
pub struct Data {
|
||||
pub database: Arc<Mutex<PgConnection>>,
|
||||
pub mentions: Arc<Mutex<HashMap<UserId, std::time::Instant>>>,
|
||||
|
||||
/// last time the user redeemed a daily
|
||||
pub dailies: Arc<Mutex<HashMap<UserId, std::time::Instant>>>,
|
||||
}
|
||||
|
||||
pub type Error = Box<dyn std::error::Error + Send + Sync>;
|
||||
|
||||
11
src/main.rs
11
src/main.rs
@@ -79,11 +79,22 @@ async fn main() -> Result<(), Error> {
|
||||
"#,
|
||||
).execute(&mut database).await?;
|
||||
|
||||
sqlx::query(
|
||||
r#"
|
||||
CREATE TABLE IF NOT EXISTS selfroles (
|
||||
userid BIGINT PRIMARY KEY,
|
||||
roleid BIGINT,
|
||||
guildid BIGINT
|
||||
)
|
||||
"#,
|
||||
).execute(&mut database).await?;
|
||||
|
||||
println!("Bot is ready!");
|
||||
|
||||
Ok(Data {
|
||||
database: Arc::new(Mutex::new(database)),
|
||||
mentions: Arc::new(Mutex::new(HashMap::new())),
|
||||
dailies: Arc::new(Mutex::new(HashMap::new())),
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user