From c680f788c116eef993a1bc1dc78d874640c48e78 Mon Sep 17 00:00:00 2001 From: Joey Hines Date: Sun, 23 Mar 2025 13:28:18 -0600 Subject: [PATCH] WOOO 1.1 * Fixed help command by implementing my own * General cleanup * Added an error handler --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/config.rs | 2 +- src/discord/admin.rs | 4 +- src/discord/birthday.rs | 2 +- src/discord/celeryman.rs | 4 +- src/discord/color.rs | 2 +- src/discord/emoji_race.rs | 4 +- src/discord/fren_coin.rs | 2 +- src/discord/joke.rs | 9 +- src/discord/little_fren.rs | 2 +- src/discord/mod.rs | 124 +++++++++++++++++--- src/discord/shop.rs | 10 +- src/discord/voices.rs | 2 +- src/migrations/migration_4_update_random.rs | 2 +- src/migrations/mod.rs | 4 +- src/models/api_key.rs | 5 +- src/models/lil_fren.rs | 2 +- src/models/race.rs | 2 +- 19 files changed, 138 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 04c79c4..6ae95e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1080,7 +1080,7 @@ dependencies = [ [[package]] name = "fren" -version = "1.0.0" +version = "1.1.0" dependencies = [ "axum 0.8.1", "base64 0.22.1", diff --git a/Cargo.toml b/Cargo.toml index 343c99f..56752d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fren" -version = "1.0.0" +version = "1.1.0" edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/config.rs b/src/config.rs index abcd551..a60692f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,6 @@ use crate::album_manager::AlbumManager; use crate::error::Error; -use crate::migrations::{do_migration, CURRENT_DB_VERSION}; +use crate::migrations::{CURRENT_DB_VERSION, do_migration}; use config::{Config, File}; use j_db::database::Database; use j_db::metadata::DBMetadata; diff --git a/src/discord/admin.rs b/src/discord/admin.rs index 2dc26d3..2dedfe2 100644 --- a/src/discord/admin.rs +++ b/src/discord/admin.rs @@ -3,8 +3,8 @@ use crate::error::Error; use crate::inventory::ItemType; use crate::models::api_key::Apikey; use crate::models::lil_fren::{ - draw_dancing, draw_frankenstein, draw_gone, draw_magic, draw_mining, draw_resonance_cascade, - draw_sick, draw_sleep, draw_standing, draw_tax_fraud, AliveState, LilFren, + AliveState, LilFren, draw_dancing, draw_frankenstein, draw_gone, draw_magic, draw_mining, + draw_resonance_cascade, draw_sick, draw_sleep, draw_standing, draw_tax_fraud, }; use crate::models::task::Task; use crate::user::User; diff --git a/src/discord/birthday.rs b/src/discord/birthday.rs index 4afea05..ce0a3f1 100644 --- a/src/discord/birthday.rs +++ b/src/discord/birthday.rs @@ -3,7 +3,7 @@ use crate::error::Error; use crate::models::birthday::BirthdayEntry; use poise::serenity_prelude::model::id::UserId; use poise::serenity_prelude::utils::MessageBuilder; -use rand::{rng, Rng}; +use rand::{Rng, rng}; /// Add your birthday to the bot, it can probably be trusted with this info #[poise::command(prefix_command, category = "Birthdays")] diff --git a/src/discord/celeryman.rs b/src/discord/celeryman.rs index 2b5bad8..bd453c1 100644 --- a/src/discord/celeryman.rs +++ b/src/discord/celeryman.rs @@ -18,7 +18,7 @@ pub async fn nudetayne(ctx: Context<'_>) -> Result<(), Error> { Ok(()) } -/// Tayne +/// I have a beta sequence I've been working on #[poise::command(prefix_command, category = "Celery Man")] pub async fn tayne(ctx: Context<'_>) -> Result<(), Error> { ctx.reply("https://media.tenor.com/115eUl2XUaAAAAAM/flarhgunnstow-paul-rudd.gif") @@ -26,7 +26,7 @@ pub async fn tayne(ctx: Context<'_>) -> Result<(), Error> { Ok(()) } -/// THE Celeryman +/// THE Celeryman Sequence #[poise::command(prefix_command, category = "Celery Man")] pub async fn celeryman(ctx: Context<'_>) -> Result<(), Error> { ctx.reply("https://media.tenor.com/1iOUXZFLpBgAAAAM/dance-dancing.gif") diff --git a/src/discord/color.rs b/src/discord/color.rs index 0e33525..356d9f4 100644 --- a/src/discord/color.rs +++ b/src/discord/color.rs @@ -4,7 +4,7 @@ use poise::serenity_prelude::builder::EditRole; use poise::serenity_prelude::model::Colour; /// Set your discord name's color -#[poise::command(prefix_command, guild_only, category = "color")] +#[poise::command(prefix_command, guild_only, category = "Color")] pub async fn set_color( ctx: Context<'_>, #[description = "Color you want your role to be"] diff --git a/src/discord/emoji_race.rs b/src/discord/emoji_race.rs index f5baf89..498c8e5 100644 --- a/src/discord/emoji_race.rs +++ b/src/discord/emoji_race.rs @@ -1,15 +1,15 @@ use crate::discord::Context; use crate::error::Error; use crate::models::race; -use crate::models::race::{Bet, RaceError, Racer, NUMBER_OF_RACERS, RACE_SIZE}; +use crate::models::race::{Bet, NUMBER_OF_RACERS, RACE_SIZE, RaceError, Racer}; use crate::user::User; use j_db::database::Database; use poise::serenity_prelude::builder::EditMessage; use poise::serenity_prelude::model::id::UserId; use poise::serenity_prelude::utils::MessageBuilder; use poise::serenity_prelude::{EmojiIdentifier, Mentionable}; -use rand::seq::IteratorRandom; use rand::rng; +use rand::seq::IteratorRandom; use std::time::Duration; fn cleanup_race(db: &Database) -> Result<(), Error> { diff --git a/src/discord/fren_coin.rs b/src/discord/fren_coin.rs index c31b913..87de4ba 100644 --- a/src/discord/fren_coin.rs +++ b/src/discord/fren_coin.rs @@ -5,7 +5,7 @@ use j_db::database::Database; use log::info; use poise::serenity_prelude::model::id::UserId; use poise::serenity_prelude::prelude::Mentionable; -use rand::{rng, Rng}; +use rand::{Rng, rng}; /// Get your balance or someone else's #[poise::command(prefix_command, category = "Fren Coin", aliases("audit"))] diff --git a/src/discord/joke.rs b/src/discord/joke.rs index 73cd90d..7be118f 100644 --- a/src/discord/joke.rs +++ b/src/discord/joke.rs @@ -1,10 +1,10 @@ +use crate::BAD_APPLE; use crate::album_manager::{Album, AlbumQuery, ImageQuery, ImageSort}; use crate::config::GlobalData; use crate::discord::Context; use crate::error::Error; use crate::models::insult_compliment::{RandomResponseTemplate, ResponseType}; use crate::models::random::{Random, RandomConfig}; -use crate::BAD_APPLE; use chrono::Utc; use emojis::Group; use log::debug; @@ -12,8 +12,8 @@ use poise::serenity_prelude::all::{CreateAttachment, CreateMessage}; use poise::serenity_prelude::constants::MESSAGE_CODE_LIMIT; use poise::serenity_prelude::model::channel::Message; use poise::serenity_prelude::utils::MessageBuilder; -use poise::{serenity_prelude, CreateReply}; -use raas_types::raas::bot::roll::{roll_response, Roll, RollCmd}; +use poise::{CreateReply, serenity_prelude}; +use raas_types::raas::bot::roll::{Roll, RollCmd, roll_response}; use raas_types::raas::resp::response::Resp; use raas_types::raas::service::raas_client::RaasClient; use rand::prelude::IndexedRandom; @@ -142,8 +142,7 @@ pub async fn add_random( #[description = "Random collection to add to"] random_name: String, #[description = "Random message"] random_response: String, ) -> 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 { ctx.reply(format!("Template failed test render, try again: {}", err)) .await?; diff --git a/src/discord/little_fren.rs b/src/discord/little_fren.rs index 01c6a38..bfa8a05 100644 --- a/src/discord/little_fren.rs +++ b/src/discord/little_fren.rs @@ -5,7 +5,7 @@ use crate::models::lil_fren::{AliveState, LilFren, LilFrenState}; use poise::serenity_prelude::model::misc::EmojiIdentifier; use poise::serenity_prelude::utils::MessageBuilder; use rand::prelude::IndexedRandom; -use rand::{rng, Rng}; +use rand::{Rng, rng}; /// Adopt a new little buddy! #[poise::command(prefix_command, guild_only, category = "Lil Buddy")] diff --git a/src/discord/mod.rs b/src/discord/mod.rs index 58204bd..db860d7 100644 --- a/src/discord/mod.rs +++ b/src/discord/mod.rs @@ -12,20 +12,19 @@ pub(crate) mod shop; pub(crate) mod voices; use crate::config::GlobalData; -use crate::error::Error; -use log::{error, info}; -use std::sync::Arc; -use std::time::Duration; - use crate::discord::fren_coin::give_coin; use crate::discord::joke::random; +use crate::error::Error; use crate::models::lil_fren::lil_fren_task; use crate::models::task::Task; -use poise::serenity_prelude::{GuildId, Http, Message, ReactionType, RoleId}; -use poise::{find_command, serenity_prelude as serenity, FrameworkOptions}; +use log::{error, info}; +use poise::serenity_prelude::{GuildId, Http, Message, MessageBuilder, ReactionType, RoleId}; +use poise::{FrameworkOptions, find_command, serenity_prelude as serenity}; use rand::prelude::IteratorRandom; use rand::rng; use songbird::SerenityInit; +use std::sync::Arc; +use std::time::Duration; pub type Context<'a> = poise::Context<'a, Arc, Error>; @@ -148,25 +147,111 @@ async fn handle_unrecognised_commands( async fn pre_command(ctx: Context<'_>) { info!( - "User '{}' is running command '{}' in channel '{}'", + "User '{}' is running command '{}' with invocation '{}' in channel '{}'", ctx.author().name, ctx.invoked_command_name(), + ctx.invocation_string(), ctx.channel_id() ); } -#[poise::command(prefix_command)] +#[poise::command(prefix_command, category = "Help")] pub async fn help(ctx: Context<'_>, command: Option) -> Result<(), Error> { - let configuration = poise::builtins::HelpConfiguration { - extra_text_at_bottom: "Made with 💖 by Joey", - include_description: false, - ..Default::default() - }; - poise::builtins::help(ctx, command.as_deref(), configuration).await?; + if let Some(command) = command { + let command = find_command( + &ctx.framework().options.commands, + &command, + true, + &mut Vec::new(), + ); + + if let Some((command, _, _)) = command { + let mut msg_builder = MessageBuilder::new(); + + msg_builder.push_line(format!("# {}", &command.name)); + msg_builder.push_line(command.description.as_ref().unwrap_or(&"".to_string())); + + let parameters = if !command.parameters.is_empty() { + msg_builder.push_line("### Arguments:"); + for parameter in &command.parameters { + msg_builder.push_line(format!( + "* `{}`: {}", + parameter.name, + parameter.description.as_ref().unwrap_or(&"".to_string()) + )); + } + + let parameters: Vec = command + .parameters + .iter() + .map(|parameter| parameter.name.clone()) + .collect(); + + let mut parameters_str = parameters.join(" "); + + parameters_str.insert(0, ' '); + + parameters_str + } else { + "".to_string() + }; + + msg_builder.push_line("### Usage:"); + + msg_builder.push_line(format!("`!{}{}`", &command.name, parameters)); + + ctx.reply(msg_builder.build()).await?; + } else { + ctx.reply("tbh, no idea what that is. Cringe TBH").await?; + } + } else { + let mut commands: Vec<(String, String)> = ctx + .framework() + .options + .commands + .iter() + .map(|c| { + ( + c.category.as_ref().unwrap_or(&"None".to_string()).clone(), + c.name.clone(), + ) + }) + .collect(); + + if !ctx.data().cfg.admins.contains(&ctx.author().id) { + // Remove admin commands for lame normal users + commands.retain_mut(|(category, _)| !category.eq_ignore_ascii_case("Admin")) + } + + commands.sort_by(|(category1, _), (category2, _)| category1.cmp(category2)); + + let mut msg_builder = MessageBuilder::new(); + + msg_builder.push_line("# Fren Bot"); + msg_builder.push_line_safe("Your best friend in this Discord!"); + msg_builder.push_line(""); + msg_builder.push_italic_line( + "Do `!help ` to get more information on any of the commands below.", + ); + + let mut last_category = "".to_string(); + for (category, command) in &commands { + if !last_category.eq_ignore_ascii_case(category) { + last_category = category.clone(); + msg_builder.push_line(format!("### {}", last_category)); + } + + msg_builder.push_line(format!("* `!{}`", command)); + } + + msg_builder.push_line("-# Made with :sparkling_heart: by Joey"); + + ctx.reply(msg_builder.build()).await?; + } + Ok(()) } - pub async fn run_bot(global_data: GlobalData) { let framework_options: FrameworkOptions, Error> = poise::FrameworkOptions { prefix_options: poise::PrefixFrameworkOptions { @@ -230,6 +315,13 @@ pub async fn run_bot(global_data: GlobalData) { Box::pin(event_handler(ctx, event, framework, data)) }, pre_command: |ctx| Box::pin(pre_command(ctx)), + on_error: |err| { + Box::pin(async move { + if let Err(e) = poise::builtins::on_error(err).await { + error!("Failed to handle error: {}", e) + } + }) + }, ..Default::default() }; diff --git a/src/discord/shop.rs b/src/discord/shop.rs index 4a3ee08..22b7305 100644 --- a/src/discord/shop.rs +++ b/src/discord/shop.rs @@ -1,19 +1,19 @@ use crate::config::GlobalData; use crate::discord::motivate::create_motivation_image; -use crate::discord::{get_role, Context}; +use crate::discord::{Context, get_role}; use crate::error::Error; -use crate::inventory::{nft_value, InventoryError, ItemData, ItemType, Operation}; +use crate::inventory::{InventoryError, ItemData, ItemType, Operation, nft_value}; use crate::models::motivation::MotivationConfig; use crate::models::task::{Task, TaskType}; use crate::user::{User, UserError}; use poise::serenity_prelude::all::{ - parse_user_mention, CreateAttachment, CreateMessage, EditRole, GuildId, Member, + CreateAttachment, CreateMessage, EditRole, GuildId, Member, parse_user_mention, }; use poise::serenity_prelude::model::Colour; use poise::serenity_prelude::prelude::Mentionable; use poise::serenity_prelude::utils::MessageBuilder; use rand::prelude::IndexedRandom; -use rand::{rng, Rng}; +use rand::{Rng, rng}; use std::collections::hash_map::DefaultHasher; use std::hash::Hasher; use std::sync::Arc; @@ -111,7 +111,7 @@ async fn blockable_item( Err(_) => { return Err(Error::CommandError( "I have no clue who that is tbh".to_string(), - )) + )); } }; diff --git a/src/discord/voices.rs b/src/discord/voices.rs index 35818c4..1336db8 100644 --- a/src/discord/voices.rs +++ b/src/discord/voices.rs @@ -8,7 +8,7 @@ use poise::serenity_prelude::model::prelude::GuildId; use poise::serenity_prelude::utils::MessageBuilder; use songbird::driver::Bitrate; use songbird::input::cached::Compressed; -use songbird::{input, Event, EventContext, EventHandler, Songbird, TrackEvent}; +use songbird::{Event, EventContext, EventHandler, Songbird, TrackEvent, input}; use std::borrow::Cow; use std::collections::HashMap; use std::fmt::{Display, Formatter}; diff --git a/src/migrations/migration_4_update_random.rs b/src/migrations/migration_4_update_random.rs index 7d0eca8..5618439 100644 --- a/src/migrations/migration_4_update_random.rs +++ b/src/migrations/migration_4_update_random.rs @@ -3,8 +3,8 @@ use j_db::database::Database; use j_db::error::JDbError; use j_db::migration::Migration; use j_db::model::JdbModel; -use json::number::Number; use json::JsonValue; +use json::number::Number; pub struct Migration4UpdateRandoms {} diff --git a/src/migrations/mod.rs b/src/migrations/mod.rs index a4c54f6..8a8170e 100644 --- a/src/migrations/mod.rs +++ b/src/migrations/mod.rs @@ -1,7 +1,7 @@ -use crate::migrations::migration2_remove_imgur::Migration2RemoveImgur; -use crate::migrations::migration3_remove_img::Migration3RemoveImage; use crate::migrations::migration_4_update_random::Migration4UpdateRandoms; use crate::migrations::migration_5_update_motivation::Migration5UpdateMotivation; +use crate::migrations::migration2_remove_imgur::Migration2RemoveImgur; +use crate::migrations::migration3_remove_img::Migration3RemoveImage; use j_db::database::Database; use j_db::migration; use j_db::migration::Direction; diff --git a/src/models/api_key.rs b/src/models/api_key.rs index b264be5..3a7508a 100644 --- a/src/models/api_key.rs +++ b/src/models/api_key.rs @@ -1,10 +1,10 @@ use crate::error::Error; -use base64::{engine::general_purpose, Engine as _}; +use base64::{Engine as _, engine::general_purpose}; use j_db::database::Database; use j_db::model::JdbModel; use poise::serenity_prelude::model::id::UserId; use rand::distr::Alphanumeric; -use rand::{rng, Rng}; +use rand::{Rng, rng}; use serde::{Deserialize, Serialize}; use sha3::digest::FixedOutput; use sha3::{Digest, Sha3_256}; @@ -62,7 +62,6 @@ impl Apikey { general_purpose::STANDARD_NO_PAD.encode(hash) } - #[allow(dead_code)] pub fn find_key_from_secret(db: &Database, secret: &str) -> Result, Error> { let hash = Self::hash_secret(secret); diff --git a/src/models/lil_fren.rs b/src/models/lil_fren.rs index c6ad012..551a58b 100644 --- a/src/models/lil_fren.rs +++ b/src/models/lil_fren.rs @@ -8,7 +8,7 @@ use poise::serenity_prelude::model::guild::Emoji; use poise::serenity_prelude::model::id::{EmojiId, GuildId}; use poise::serenity_prelude::utils::MessageBuilder; use rand::distr::{Distribution, StandardUniform}; -use rand::{rng, Rng}; +use rand::{Rng, rng}; use serde::{Deserialize, Serialize}; use std::sync::Arc; use std::time::Duration; diff --git a/src/models/race.rs b/src/models/race.rs index b48521e..cf0f9af 100644 --- a/src/models/race.rs +++ b/src/models/race.rs @@ -3,7 +3,7 @@ use crate::user::UserError; use j_db::database::Database; use j_db::model::JdbModel; use poise::serenity_prelude::{Emoji, EmojiId, MessageBuilder, UserId}; -use rand::{rng, Rng}; +use rand::{Rng, rng}; use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter};