* Fixed help command by implementing my own
* General cleanup
* Added an error handler
This commit is contained in:
Joey Hines 2025-03-23 13:28:18 -06:00
parent c5cada372e
commit c680f788c1
Signed by: joeyahines
GPG Key ID: 38BA6F25C94C9382
19 changed files with 138 additions and 48 deletions

2
Cargo.lock generated
View File

@ -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",

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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")]

View File

@ -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")

View File

@ -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"]

View File

@ -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> {

View File

@ -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"))]

View File

@ -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?;

View File

@ -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")]

View File

@ -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<GlobalData>, 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<String>) -> 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<String> = 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 <command>` 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<Arc<GlobalData>, 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()
};

View File

@ -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(),
))
));
}
};

View File

@ -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};

View File

@ -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 {}

View File

@ -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;

View File

@ -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<Option<Self>, Error> {
let hash = Self::hash_secret(secret);

View File

@ -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;

View File

@ -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};