Add role commands

This commit is contained in:
Joey Hines 2025-03-28 20:09:53 -06:00
parent caf770f380
commit 843838d676
Signed by: joeyahines
GPG Key ID: 38BA6F25C94C9382
8 changed files with 241 additions and 5 deletions

2
Cargo.lock generated
View File

@ -1080,7 +1080,7 @@ dependencies = [
[[package]] [[package]]
name = "fren" name = "fren"
version = "1.1.1" version = "1.2.0"
dependencies = [ dependencies = [
"axum 0.8.1", "axum 0.8.1",
"base64 0.22.1", "base64 0.22.1",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "fren" name = "fren"
version = "1.1.1" version = "1.2.0"
edition = "2024" edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -1,4 +1,4 @@
use crate::discord::Context; use crate::discord::{Context, get_role};
use crate::error::Error; use crate::error::Error;
use crate::inventory::ItemType; use crate::inventory::ItemType;
use crate::models::api_key::Apikey; use crate::models::api_key::Apikey;
@ -6,12 +6,13 @@ use crate::models::lil_fren::{
AliveState, LilFren, draw_dancing, draw_frankenstein, draw_gone, draw_magic, draw_mining, AliveState, LilFren, draw_dancing, draw_frankenstein, draw_gone, draw_magic, draw_mining,
draw_resonance_cascade, draw_sick, draw_sleep, draw_standing, draw_tax_fraud, draw_resonance_cascade, draw_sick, draw_sleep, draw_standing, draw_tax_fraud,
}; };
use crate::models::managed_roles::ManagedRole;
use crate::models::task::Task; use crate::models::task::Task;
use crate::user::User; use crate::user::User;
use json::JsonValue; use json::JsonValue;
use log::info; use log::info;
use poise::serenity_prelude::{ use poise::serenity_prelude::{
Attachment, CreateAttachment, CreateMessage, EmojiIdentifier, FormattedTimestamp, Attachment, CreateAttachment, CreateMessage, EditRole, EmojiIdentifier, FormattedTimestamp,
FormattedTimestampStyle, MessageBuilder, Timestamp, UserId, FormattedTimestampStyle, MessageBuilder, Timestamp, UserId,
}; };
use std::borrow::Cow; use std::borrow::Cow;
@ -195,3 +196,70 @@ pub async fn list_tasks(ctx: Context<'_>) -> Result<(), Error> {
Ok(()) Ok(())
} }
/// Add a new role that other members can join
#[poise::command(prefix_command, guild_only, category = "Admin", check = "is_admin")]
pub async fn add_role(
ctx: Context<'_>,
#[description = "Role Name"] name: String,
#[description = "Role Description"]
#[rest]
description: String,
) -> Result<(), Error> {
let guild_id = ctx.guild_id().unwrap();
if guild_id
.roles(ctx)
.await?
.iter()
.any(|(_, role)| role.name == name)
{
ctx.reply("That role already exists, try something more original")
.await?;
return Ok(());
}
let role = guild_id
.create_role(ctx, EditRole::new().name(name).mentionable(true))
.await?;
ManagedRole::add_role(&ctx.data().db, role.id, description)?;
ctx.reply(format!(
"Created `{}`, have fun with your friends dear /s",
role.name
))
.await?;
Ok(())
}
/// Remove a joinable role
#[poise::command(prefix_command, guild_only, category = "Admin", check = "is_admin")]
pub async fn remove_role(
ctx: Context<'_>,
#[description = "Role Name"] name: String,
) -> Result<(), Error> {
let guild_id = ctx.guild_id().unwrap();
let role = get_role(ctx.http(), guild_id, &name).await?;
let role = if let Some(role) = role {
role
} else {
ctx.reply("No role by that name. L + Ratio").await?;
return Ok(());
};
if ManagedRole::get_role(&ctx.data().db, role)?.is_none() {
ctx.reply("No role by that name. L + Ratio").await?;
return Ok(());
}
ManagedRole::remove_role(&ctx.data().db, role)?;
guild_id.delete_role(ctx, role).await?;
ctx.reply(format!("Finally got rid of '{}', thank GOD", name))
.await?;
Ok(())
}

View File

@ -140,7 +140,9 @@ pub async fn random(
pub async fn add_random( pub async fn add_random(
ctx: Context<'_>, ctx: Context<'_>,
#[description = "Random collection to add to"] random_name: String, #[description = "Random collection to add to"] random_name: String,
#[description = "Random message"] #[rest] random_response: String, #[description = "Random message"]
#[rest]
random_response: String,
) -> Result<(), Error> { ) -> Result<(), Error> {
if let Err(err) = render_random(ctx.author().display_name(), ctx.data(), &random_response).await if let Err(err) = render_random(ctx.author().display_name(), ctx.data(), &random_response).await
{ {

View File

@ -8,6 +8,7 @@ mod fren_coin;
mod joke; mod joke;
mod little_fren; mod little_fren;
mod motivate; mod motivate;
mod role;
pub(crate) mod shop; pub(crate) mod shop;
pub(crate) mod voices; pub(crate) mod voices;
@ -271,6 +272,8 @@ pub async fn run_bot(global_data: GlobalData) {
admin::debug_buddy(), admin::debug_buddy(),
admin::op_give(), admin::op_give(),
admin::list_tasks(), admin::list_tasks(),
admin::add_role(),
admin::remove_role(),
album::add_image(), album::add_image(),
album::list_albums(), album::list_albums(),
birthday::add_birthday(), birthday::add_birthday(),
@ -301,6 +304,9 @@ pub async fn run_bot(global_data: GlobalData) {
little_fren::play(), little_fren::play(),
motivate::motivation(), motivate::motivation(),
motivate::motivation_add_album(), motivate::motivation_add_album(),
role::list_roles(),
role::join_role(),
role::leave_role(),
shop::buy(), shop::buy(),
shop::inventory(), shop::inventory(),
shop::item_help(), shop::item_help(),

99
src/discord/role.rs Normal file
View File

@ -0,0 +1,99 @@
use crate::discord::{Context, get_role};
use crate::error::Error;
use crate::models::managed_roles::ManagedRole;
use poise::serenity_prelude::MessageBuilder;
/// List all the roles you can join. It's like joining a club but nerdier
#[poise::command(prefix_command, guild_only, category = "Role")]
pub async fn list_roles(ctx: Context<'_>) -> Result<(), Error> {
let roles = ManagedRole::list_roles(&ctx.data().db)?;
let mut role_resp = MessageBuilder::new();
role_resp.push_line(
"Here are all the roles you can join, use `!join_role <role`> to get in on the 'fun':",
);
for role in roles {
let discord_role = ctx.guild_id().unwrap().role(ctx, role.role_id).await?;
role_resp.push_line(format!("* `{}`: {}", discord_role.name, role.description));
}
ctx.reply(role_resp.build()).await?;
Ok(())
}
/// Join a role. Just hope it's not a #CriticalFail
#[poise::command(prefix_command, guild_only, category = "Role")]
pub async fn join_role(
ctx: Context<'_>,
#[description = "Role to join"] role_name: String,
) -> Result<(), Error> {
let role = get_role(ctx.http(), ctx.guild_id().unwrap(), &role_name).await?;
let role = if let Some(role) = role {
role
} else {
ctx.reply(format!("I don't know of this '{}' role. If it exists, only god knows. And I have met god. DO NOT MEET GOD", role_name)).await?;
return Ok(());
};
let managed_role = ManagedRole::get_role(&ctx.data().db, role)?;
if managed_role.is_none() {
ctx.reply("How do you know about that role? Who told you? I can't add you. And we're both DEAD because you mentioned it.").await?;
return Ok(());
};
ctx.author_member()
.await
.unwrap()
.add_role(ctx, role)
.await?;
ctx.reply(format!(
"You have been added to the ~~cult~~ role '{}'",
role_name
))
.await?;
Ok(())
}
/// Leave a role, probably pinged too much anyway tbh
#[poise::command(prefix_command, guild_only, category = "Role")]
pub async fn leave_role(
ctx: Context<'_>,
#[description = "Role to leave"] role_name: String,
) -> Result<(), Error> {
let role = get_role(ctx.http(), ctx.guild_id().unwrap(), &role_name).await?;
let role = if let Some(role) = role {
role
} else {
ctx.reply(format!("I don't know of this '{}' role. If it exists, only god knows. And I have met god. DO NOT MEET GOD", role_name)).await?;
return Ok(());
};
let managed_role = ManagedRole::get_role(&ctx.data().db, role)?;
if managed_role.is_none() {
ctx.reply("How do you know about that role? Who told you? I can't add you. And we're both DEAD because you mentioned it.").await?;
return Ok(());
};
ctx.author_member()
.await
.unwrap()
.remove_role(ctx, role)
.await?;
ctx.reply(format!(
"You have left '{}'. Its over. All things come to an end. But did it have to be this way?",
role_name
))
.await?;
Ok(())
}

View File

@ -0,0 +1,60 @@
use crate::error::Error;
use j_db::database::Database;
use poise::serenity_prelude::RoleId;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ManagedRole {
id: Option<u64>,
pub role_id: RoleId,
pub description: String,
}
impl j_db::model::JdbModel for ManagedRole {
fn id(&self) -> Option<u64> {
self.id
}
fn set_id(&mut self, id: u64) {
self.id = Some(id)
}
fn tree() -> String {
"ManagedRoles".to_string()
}
}
impl ManagedRole {
pub fn new(role_id: RoleId, description: String) -> Self {
Self {
id: None,
role_id,
description,
}
}
pub fn add_role(db: &Database, role_id: RoleId, description: String) -> Result<Self, Error> {
Ok(db.insert(Self::new(role_id, description))?)
}
pub fn get_role(db: &Database, role_id: RoleId) -> Result<Option<Self>, Error> {
Ok(db
.filter(|_, role: &Self| role.role_id == role_id)?
.next()
.clone())
}
pub fn list_roles(db: &Database) -> Result<Vec<Self>, Error> {
Ok(db.filter(|_, _role: &Self| true)?.collect())
}
pub fn remove_role(db: &Database, role_id: RoleId) -> Result<(), Error> {
let role = Self::get_role(db, role_id)?;
if let Some(role) = role {
db.remove::<Self>(role.id.unwrap())?;
}
Ok(())
}
}

View File

@ -2,6 +2,7 @@ pub mod api_key;
pub mod birthday; pub mod birthday;
pub mod insult_compliment; pub mod insult_compliment;
pub mod lil_fren; pub mod lil_fren;
pub mod managed_roles;
pub mod motivation; pub mod motivation;
pub mod race; pub mod race;
pub mod random; pub mod random;