Add back in joke commands

This commit is contained in:
Joey Hines 2025-03-22 18:12:55 -06:00
parent 0a84a0c07c
commit 3005178a62
Signed by: joeyahines
GPG Key ID: 38BA6F25C94C9382
3 changed files with 119 additions and 154 deletions

View File

@ -1,10 +1,19 @@
use crate::album_manager::{Album, AlbumQuery, ImageQuery, ImageSort}; use crate::album_manager::{Album, AlbumQuery, ImageQuery, ImageSort};
use crate::config::GlobalData;
use crate::discord::Context;
use crate::error::Error; use crate::error::Error;
use crate::models::insult_compliment::{RandomResponseTemplate, ResponseType}; use crate::models::insult_compliment::{RandomResponseTemplate, ResponseType};
use crate::models::random::{Random, RandomConfig}; use crate::models::random::{Random, RandomConfig};
use crate::{command, group, GlobalData, BAD_APPLE}; use crate::BAD_APPLE;
use chrono::Utc; use chrono::Utc;
use emojis::Group; use emojis::Group;
use log::debug;
use poise::serenity_prelude::all::{CreateAttachment, CreateMessage};
use poise::serenity_prelude::builder::EditMessage;
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 raas_types::raas::bot::roll::{roll_response, Roll, RollCmd};
use raas_types::raas::resp::response::Resp; use raas_types::raas::resp::response::Resp;
use raas_types::raas::service::raas_client::RaasClient; use raas_types::raas::service::raas_client::RaasClient;
@ -12,29 +21,10 @@ use rand::prelude::IndexedRandom;
use rand::rng; use rand::rng;
use reqwest::Client; use reqwest::Client;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serenity::all::{CreateAttachment, CreateMessage}; use songbird::id::UserId;
use serenity::builder::EditMessage;
use serenity::client::Context;
use serenity::constants::MESSAGE_CODE_LIMIT;
use serenity::framework::standard::{Args, CommandResult};
use serenity::model::channel::Message;
use serenity::utils::MessageBuilder;
use std::collections::HashMap; use std::collections::HashMap;
use std::time::Duration; use std::time::Duration;
#[group]
#[commands(
dad_joke,
roll,
real_roll,
bad_apple,
insult,
add_random,
list_random,
emoji_8ball
)]
pub struct Joke;
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
struct DadJoke { struct DadJoke {
pub id: String, pub id: String,
@ -42,10 +32,8 @@ struct DadJoke {
pub status: i32, pub status: i32,
} }
#[command] #[poise::command(prefix_command, category = "Joke")]
#[aliases("dad")] pub async fn dad_joke(ctx: Context<'_>) -> Result<(), Error> {
#[description("Ask your dad")]
async fn dad_joke(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
let client = Client::new(); let client = Client::new();
let joke: DadJoke = client let joke: DadJoke = client
@ -56,7 +44,7 @@ async fn dad_joke(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
.json() .json()
.await?; .await?;
msg.reply(&ctx.http, joke.joke).await?; ctx.reply(joke.joke).await?;
Ok(()) Ok(())
} }
@ -114,10 +102,12 @@ pub async fn render_random(
)?) )?)
} }
pub async fn random(ctx: &Context, msg: &Message, random_name: &str) -> CommandResult { pub async fn random(
let data = ctx.data.read().await; ctx: &serenity_prelude::Context,
let global_data = data.get::<GlobalData>().unwrap(); global_data: &GlobalData,
msg: &Message,
random_name: &str,
) -> Result<(), Error> {
let random = match RandomConfig::get_random(&global_data.db, random_name)? { let random = match RandomConfig::get_random(&global_data.db, random_name)? {
None => return Ok(()), None => return Ok(()),
Some(r) => r, Some(r) => r,
@ -132,12 +122,7 @@ pub async fn random(ctx: &Context, msg: &Message, random_name: &str) -> CommandR
Some(resp) => resp, Some(resp) => resp,
}; };
let guild_member = msg let guild_member = msg.guild_id.unwrap().member(&ctx, msg.author.id).await?;
.guild_id
.unwrap()
.member(&ctx.http, msg.author.id)
.await
.unwrap();
let reply = render_random( let reply = render_random(
guild_member.display_name(), guild_member.display_name(),
@ -151,59 +136,33 @@ pub async fn random(ctx: &Context, msg: &Message, random_name: &str) -> CommandR
Ok(()) Ok(())
} }
#[command] #[poise::command(prefix_command, category = "Joke")]
#[example("8ball Funny Response haha")] pub async fn add_random(
pub async fn add_random(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult { ctx: Context<'_>,
if args.len() < 2 { #[description = "Random collection to add to"] random_name: String,
msg.reply( #[description = "Random message"] random_response: String,
&ctx.http, ) -> Result<(), Error> {
"Look kid, you need to provide both the random name and response", if let Err(err) =
) render_random(&ctx.author().display_name(), ctx.data(), &random_response).await
.await?; {
return Ok(()); ctx.reply(format!("Template failed test render, try again: {}", err))
} .await?;
let data = ctx.data.read().await;
let global_data = data.get::<GlobalData>().unwrap();
let random_name = args.parse::<String>()?;
args.advance();
let random_response = args.rest();
if let Err(err) = render_random(&msg.author.name, global_data, random_response).await {
msg.reply(
&ctx.http,
format!("Template failed test render, try again: {}", err),
)
.await?;
} else { } else {
RandomConfig::add_random(&global_data.db, &random_name, random_response)?; RandomConfig::add_random(&ctx.data().db, &random_name, &random_response)?;
msg.reply(&ctx.http, "New random added!").await?; ctx.reply("New random added!").await?;
} }
Ok(()) Ok(())
} }
#[command] #[poise::command(prefix_command, category = "Joke")]
#[example("8ball Funny Response haha")] pub async fn list_random(
pub async fn list_random(ctx: &Context, msg: &Message, args: Args) -> CommandResult { ctx: Context<'_>,
if args.is_empty() { #[description = "Random collection to list"] random_name: String,
msg.reply( ) -> Result<(), Error> {
&ctx.http, let random = RandomConfig::get_random(&ctx.data().db, &random_name)?;
"Look kid, you need to provide both the random name",
)
.await?;
return Ok(());
}
let data = ctx.data.read().await; let dm_channel = ctx.author().id.create_dm_channel(&ctx).await?;
let global_data = data.get::<GlobalData>().unwrap();
let random_name = args.parse::<String>()?;
let random = RandomConfig::get_random(&global_data.db, &random_name)?;
let dm_channel = msg.author.id.create_dm_channel(&ctx.http).await?;
if let Some(random) = random { if let Some(random) = random {
let mut msg_builder = MessageBuilder::new(); let mut msg_builder = MessageBuilder::new();
msg_builder.push_line(format!( msg_builder.push_line(format!(
@ -213,12 +172,12 @@ pub async fn list_random(ctx: &Context, msg: &Message, args: Args) -> CommandRes
)); ));
for resp in random.responses { for resp in random.responses {
let random = global_data.db.get::<Random>(resp)?; let random = ctx.data().db.get::<Random>(resp)?;
let line_msg = format!("* ({}) ({}) {}", resp, random.score, random.response); let line_msg = format!("* ({}) ({}) {}", resp, random.score, random.response);
if (msg_builder.0.len() + line_msg.len()) > MESSAGE_CODE_LIMIT { if (msg_builder.0.len() + line_msg.len()) > MESSAGE_CODE_LIMIT {
dm_channel.say(&ctx.http, msg_builder.build()).await?; dm_channel.say(&ctx, msg_builder.build()).await?;
msg_builder.0.clear(); msg_builder.0.clear();
} }
@ -226,45 +185,42 @@ pub async fn list_random(ctx: &Context, msg: &Message, args: Args) -> CommandRes
} }
if !msg_builder.0.is_empty() { if !msg_builder.0.is_empty() {
dm_channel.say(&ctx.http, msg_builder.build()).await?; dm_channel.say(&ctx, msg_builder.build()).await?;
} }
} else { } else {
msg.reply( ctx.reply("*glances to the back room*, nope we ain't got that random")
&ctx.http, .await?;
"*glances to the back room*, nope we ain't got that random",
)
.await?;
} }
Ok(()) Ok(())
} }
#[command] #[poise::command(prefix_command, category = "Joke")]
#[aliases("roll")] pub async fn roll(
#[description("Roll a die!")] ctx: Context<'_>,
async fn roll(ctx: &Context, msg: &Message, args: Args) -> CommandResult { #[description = "die to roll"]
let roll = args.rest().parse::<ndm::Dice>(); #[rest]
die_roll: String,
) -> Result<(), Error> {
let roll = die_roll.parse::<ndm::Dice>();
let reply = match roll { let reply = match roll {
Ok(roll) => format!("You rolled: **{}**", roll), Ok(roll) => format!("You rolled: **{}**", roll),
Err(_) => "Error parsing dice roll".to_string(), Err(err) => format!("Error parsing dice roll: {}", err),
}; };
msg.reply(&ctx.http, reply).await?; ctx.reply(reply).await?;
Ok(()) Ok(())
} }
#[command] #[poise::command(prefix_command, category = "Joke")]
#[aliases("real_roll")] pub async fn real_roll(ctx: Context<'_>) -> Result<(), Error> {
#[description("Roll a real die!")] let addr = ctx.data().cfg.raas_server.clone();
async fn real_roll(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
let data = ctx.data.read().await;
let global = data.get::<GlobalData>().unwrap();
let addr = global.cfg.raas_server.clone(); let mut client = RaasClient::connect(addr)
.await
let mut client = RaasClient::connect(addr).await?; .map_err(|err| Error::RaasError(err.to_string()))?;
let rolls = 3; let rolls = 3;
@ -277,23 +233,25 @@ async fn real_roll(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
})), })),
}; };
msg.reply(&ctx.http, "Sent roll request, please hang on!") ctx.reply("Sent roll request, please hang on!").await?;
.await?; let response = client
let response = client.send_request(roll_request).await?; .send_request(roll_request)
.await
.map_err(|err| Error::RaasError(err.to_string()))?;
let raas_response = response.into_inner(); let raas_response = response.into_inner();
println!( debug!(
"Got resp: {} @ {}", "Got resp from RaaS: {} @ {}",
raas_response.id, raas_response.timestamp raas_response.id, raas_response.timestamp
); );
match raas_response.resp.unwrap() { match raas_response.resp.unwrap() {
Resp::RollResp(roll_resp) => { Resp::RollResp(roll_resp) => {
if let roll_response::Response::RollImage(img) = roll_resp.response.unwrap() { if let roll_response::Response::RollImage(img) = roll_resp.response.unwrap() {
msg.channel_id ctx.channel_id()
.send_message( .send_message(
&ctx.http, &ctx,
CreateMessage::new() CreateMessage::new()
.content("Your roll my friend, hope its good I can't read!") .content("Your roll my friend, hope its good I can't read!")
.add_file(CreateAttachment::bytes(img.img, "roll.jpg")), .add_file(CreateAttachment::bytes(img.img, "roll.jpg")),
@ -302,13 +260,10 @@ async fn real_roll(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
} }
} }
Resp::Error(err) => { Resp::Error(err) => {
msg.reply( ctx.reply(format!(
&ctx.http, "My real flesh encountered an error. Get Dad to fix it. `{}`",
format!( err.msg
"My real flesh encountered an error. Get Dad to fix it. `{}`", ))
err.msg
),
)
.await?; .await?;
} }
} }
@ -316,22 +271,20 @@ async fn real_roll(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
Ok(()) Ok(())
} }
#[command] #[poise::command(prefix_command, category = "Joke")]
#[bucket = "bad_apple"] pub async fn bad_apple(ctx: Context<'_>) -> Result<(), Error> {
async fn bad_apple(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
let mut frames = BAD_APPLE.split('|'); let mut frames = BAD_APPLE.split('|');
let first_frame = frames.next().unwrap(); let first_frame = frames.next().unwrap();
if first_frame.len() > 2000 { if first_frame.len() > 2000 {
msg.reply(&ctx.http, format!("Frame too big: {}", first_frame.len())) ctx.reply(format!("Frame too big: {}", first_frame.len()))
.await?; .await?;
return Ok(()); return Ok(());
} }
let mut bad_apple_msg = msg let bad_apple_msg = ctx
.reply( .reply(
&ctx.http,
MessageBuilder::default() MessageBuilder::default()
.push_codeblock_safe(first_frame, None) .push_codeblock_safe(first_frame, None)
.build(), .build(),
@ -344,8 +297,8 @@ async fn bad_apple(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
if (idx % 10) == 0 { if (idx % 10) == 0 {
bad_apple_msg bad_apple_msg
.edit( .edit(
&ctx.http, ctx,
EditMessage::new().content( CreateReply::default().content(
MessageBuilder::default() MessageBuilder::default()
.push_codeblock_safe(frame, None) .push_codeblock_safe(frame, None)
.build(), .build(),
@ -358,30 +311,26 @@ async fn bad_apple(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
Ok(()) Ok(())
} }
#[command] #[poise::command(prefix_command, category = "Joke", aliases("compliment"))]
#[aliases("compliment")] pub async fn insult(
async fn insult(ctx: &Context, msg: &Message, args: Args) -> CommandResult { ctx: Context<'_>,
let data = ctx.data.read().await; #[description = "person to compliment/insult"] target: String,
let global = data.get::<GlobalData>().unwrap(); ) -> Result<(), Error> {
let pool = if ctx.invoked_command_name() == "insult" {
let pool = if msg.content.as_str().starts_with("!insult") {
ResponseType::Insult ResponseType::Insult
} else if msg.content.as_str().starts_with("!compliment") { } else if ctx.invoked_command_name() == "compliment" {
ResponseType::Compliment ResponseType::Compliment
} else { } else {
msg.reply(&ctx, "The h*ck did you just say to me??").await?; ctx.reply("The h*ck did you just say to me??").await?;
return Ok(()); return Ok(());
}; };
let target = args.rest(); let output = RandomResponseTemplate::get_random_response(&ctx.data().db, pool, &target)?;
let output = RandomResponseTemplate::get_random_response(&global.db, pool, target)?;
if let Some(output) = output { if let Some(output) = output {
msg.reply(&ctx.http, output).await?; ctx.reply(output).await?;
} else { } else {
msg.reply(&ctx, format!("No {}s, mr freeman??", msg.content)) ctx.reply(format!("No {}s, mr freeman??", target)).await?;
.await?;
} }
Ok(()) Ok(())
@ -406,13 +355,14 @@ fn get_unicode_emojis() -> Vec<String> {
emoji.iter().map(|e| e.to_string()).collect() emoji.iter().map(|e| e.to_string()).collect()
} }
#[command] #[poise::command(prefix_command, category = "Joke", aliases("🎱"))]
#[aliases("🎱")] pub async fn emoji_8ball(
async fn emoji_8ball(ctx: &Context, msg: &Message) -> CommandResult { ctx: Context<'_>,
let data = ctx.data.read().await; #[description = "prompt to dissect using magic"]
let global = data.get::<GlobalData>().unwrap(); #[rest]
_prompt: String,
let guild_emojis = global.cfg.guild_id.emojis(&ctx.http).await?; ) -> Result<(), Error> {
let guild_emojis = ctx.guild_id().unwrap().emojis(&ctx).await?;
let mut emojis: Vec<String> = guild_emojis.iter().map(|e| e.to_string()).collect(); let mut emojis: Vec<String> = guild_emojis.iter().map(|e| e.to_string()).collect();
let mut unicode_emojis = get_unicode_emojis(); let mut unicode_emojis = get_unicode_emojis();
@ -421,7 +371,7 @@ async fn emoji_8ball(ctx: &Context, msg: &Message) -> CommandResult {
let emoji_msg: Vec<String> = emojis.choose_multiple(&mut rng(), 3).cloned().collect(); let emoji_msg: Vec<String> = emojis.choose_multiple(&mut rng(), 3).cloned().collect();
msg.reply(&ctx.http, emoji_msg.join("")).await?; ctx.reply(emoji_msg.join("")).await?;
Ok(()) Ok(())
} }

View File

@ -5,14 +5,16 @@ mod celeryman;
mod color; mod color;
mod emoji_race; mod emoji_race;
mod fren_coin; mod fren_coin;
mod joke;
use crate::config::GlobalData; use crate::config::GlobalData;
use crate::error::Error; use crate::error::Error;
use log::info; use log::{error, info};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use crate::discord::fren_coin::give_coin; use crate::discord::fren_coin::give_coin;
use crate::discord::joke::random;
use crate::models::task::Task; use crate::models::task::Task;
use poise::serenity_prelude::{Message, ReactionType}; use poise::serenity_prelude::{Message, ReactionType};
use poise::{find_command, serenity_prelude as serenity, FrameworkOptions}; use poise::{find_command, serenity_prelude as serenity, FrameworkOptions};
@ -121,12 +123,15 @@ async fn handle_unrecognised_commands(
let parsed_album = album::parse_album(ctx, message, data, &command, tags) let parsed_album = album::parse_album(ctx, message, data, &command, tags)
.await .await
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
println!("Error processing album command: {}", e); error!("Error processing album command: {}", e);
true true
}); });
if !parsed_album { if !parsed_album {
// handle random later match random(ctx, data, message, &command).await {
Ok(_) => {}
Err(e) => error!("Error processing random command: {}", e),
}
} }
Ok(()) Ok(())
@ -173,6 +178,14 @@ pub async fn run_bot(global_data: GlobalData) {
emoji_race::start_race(), emoji_race::start_race(),
fren_coin::balance(), fren_coin::balance(),
fren_coin::gift(), fren_coin::gift(),
joke::add_random(),
joke::dad_joke(),
joke::bad_apple(),
joke::emoji_8ball(),
joke::insult(),
joke::list_random(),
joke::real_roll(),
joke::roll(),
], ],
event_handler: |ctx, event, framework, data| { event_handler: |ctx, event, framework, data| {
Box::pin(event_handler(ctx, event, framework, data)) Box::pin(event_handler(ctx, event, framework, data))

View File

@ -14,6 +14,7 @@ pub enum Error {
DbError(j_db::error::JDbError), DbError(j_db::error::JDbError),
ReqwestError(reqwest::Error), ReqwestError(reqwest::Error),
ParseFailure, ParseFailure,
RaasError(String),
} }
impl StdError for Error {} impl StdError for Error {}
@ -65,6 +66,7 @@ impl Display for Error {
Error::DbError(e) => write!(f, "DB error: {}", e), Error::DbError(e) => write!(f, "DB error: {}", e),
Error::ReqwestError(e) => write!(f, "Reqwest Error: {}", e), Error::ReqwestError(e) => write!(f, "Reqwest Error: {}", e),
Error::ParseFailure => write!(f, "Failed to parse something or other"), Error::ParseFailure => write!(f, "Failed to parse something or other"),
Error::RaasError(msg) => write!(f, "Got error from RaaS: {}", msg),
} }
} }
} }