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 poise::serenity_prelude as serenity;
|
||||||
use serenity::Colour;
|
use serenity::Colour;
|
||||||
|
|
||||||
|
|
||||||
// this code uses Member::permissions, which while it is a deprecated function, it doesn't actually matter
|
// 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.
|
// since it is only used to display information to the user.
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ pub async fn daily(ctx: Context<'_>) -> Result<(), Error> {
|
|||||||
super::add_balance(id, 50, db).await?;
|
super::add_balance(id, 50, db).await?;
|
||||||
ctx.reply("Added **50** credits to your account!").await?;
|
ctx.reply("Added **50** credits to your account!").await?;
|
||||||
} else {
|
} else {
|
||||||
let until_next_daily = Duration::from_secs(10) - daily.elapsed();
|
let until_next_daily = Duration::from_secs(24 * 60 * 60) - daily.elapsed();
|
||||||
ctx.reply(format!("Your daily will be available in {:?}.", format_duration(until_next_daily))).await?;
|
ctx.reply(format!("Your next daily will be available in **{}**.", format_duration(until_next_daily))).await?;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
|||||||
@@ -18,5 +18,6 @@ pub fn commands() -> Vec<Command<Data, Error>> {
|
|||||||
gambling::wager::wager(),
|
gambling::wager::wager(),
|
||||||
gambling::daily::daily(),
|
gambling::daily::daily(),
|
||||||
eval::eval(),
|
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 struct Data {
|
||||||
pub database: Arc<Mutex<PgConnection>>,
|
pub database: Arc<Mutex<PgConnection>>,
|
||||||
pub mentions: Arc<Mutex<HashMap<UserId, std::time::Instant>>>,
|
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>;
|
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?;
|
).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!");
|
println!("Bot is ready!");
|
||||||
|
|
||||||
Ok(Data {
|
Ok(Data {
|
||||||
database: Arc::new(Mutex::new(database)),
|
database: Arc::new(Mutex::new(database)),
|
||||||
mentions: Arc::new(Mutex::new(HashMap::new())),
|
mentions: Arc::new(Mutex::new(HashMap::new())),
|
||||||
|
dailies: Arc::new(Mutex::new(HashMap::new())),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user