diff --git a/src/discord/joke.rs b/src/discord/joke.rs index 424f71b..9c5300c 100644 --- a/src/discord/joke.rs +++ b/src/discord/joke.rs @@ -1,10 +1,19 @@ 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::{command, group, GlobalData, BAD_APPLE}; +use crate::BAD_APPLE; use chrono::Utc; 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::resp::response::Resp; use raas_types::raas::service::raas_client::RaasClient; @@ -12,29 +21,10 @@ use rand::prelude::IndexedRandom; use rand::rng; use reqwest::Client; use serde::{Deserialize, Serialize}; -use serenity::all::{CreateAttachment, CreateMessage}; -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 songbird::id::UserId; use std::collections::HashMap; 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)] struct DadJoke { pub id: String, @@ -42,10 +32,8 @@ struct DadJoke { pub status: i32, } -#[command] -#[aliases("dad")] -#[description("Ask your dad")] -async fn dad_joke(ctx: &Context, msg: &Message, _args: Args) -> CommandResult { +#[poise::command(prefix_command, category = "Joke")] +pub async fn dad_joke(ctx: Context<'_>) -> Result<(), Error> { let client = Client::new(); let joke: DadJoke = client @@ -56,7 +44,7 @@ async fn dad_joke(ctx: &Context, msg: &Message, _args: Args) -> CommandResult { .json() .await?; - msg.reply(&ctx.http, joke.joke).await?; + ctx.reply(joke.joke).await?; Ok(()) } @@ -114,10 +102,12 @@ pub async fn render_random( )?) } -pub async fn random(ctx: &Context, msg: &Message, random_name: &str) -> CommandResult { - let data = ctx.data.read().await; - let global_data = data.get::().unwrap(); - +pub async fn random( + ctx: &serenity_prelude::Context, + global_data: &GlobalData, + msg: &Message, + random_name: &str, +) -> Result<(), Error> { let random = match RandomConfig::get_random(&global_data.db, random_name)? { None => return Ok(()), Some(r) => r, @@ -132,12 +122,7 @@ pub async fn random(ctx: &Context, msg: &Message, random_name: &str) -> CommandR Some(resp) => resp, }; - let guild_member = msg - .guild_id - .unwrap() - .member(&ctx.http, msg.author.id) - .await - .unwrap(); + let guild_member = msg.guild_id.unwrap().member(&ctx, msg.author.id).await?; let reply = render_random( guild_member.display_name(), @@ -151,59 +136,33 @@ pub async fn random(ctx: &Context, msg: &Message, random_name: &str) -> CommandR Ok(()) } -#[command] -#[example("8ball Funny Response haha")] -pub async fn add_random(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult { - if args.len() < 2 { - msg.reply( - &ctx.http, - "Look kid, you need to provide both the random name and response", - ) - .await?; - return Ok(()); - } - - let data = ctx.data.read().await; - let global_data = data.get::().unwrap(); - - let random_name = args.parse::()?; - 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?; +#[poise::command(prefix_command, category = "Joke")] +pub async fn add_random( + ctx: Context<'_>, + #[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 + { + ctx.reply(format!("Template failed test render, try again: {}", err)) + .await?; } else { - RandomConfig::add_random(&global_data.db, &random_name, random_response)?; - msg.reply(&ctx.http, "New random added!").await?; + RandomConfig::add_random(&ctx.data().db, &random_name, &random_response)?; + ctx.reply("New random added!").await?; } Ok(()) } -#[command] -#[example("8ball Funny Response haha")] -pub async fn list_random(ctx: &Context, msg: &Message, args: Args) -> CommandResult { - if args.is_empty() { - msg.reply( - &ctx.http, - "Look kid, you need to provide both the random name", - ) - .await?; - return Ok(()); - } +#[poise::command(prefix_command, category = "Joke")] +pub async fn list_random( + ctx: Context<'_>, + #[description = "Random collection to list"] random_name: String, +) -> Result<(), Error> { + let random = RandomConfig::get_random(&ctx.data().db, &random_name)?; - let data = ctx.data.read().await; - let global_data = data.get::().unwrap(); - - let random_name = args.parse::()?; - - let random = RandomConfig::get_random(&global_data.db, &random_name)?; - - let dm_channel = msg.author.id.create_dm_channel(&ctx.http).await?; + let dm_channel = ctx.author().id.create_dm_channel(&ctx).await?; if let Some(random) = random { let mut msg_builder = MessageBuilder::new(); 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 { - let random = global_data.db.get::(resp)?; + let random = ctx.data().db.get::(resp)?; let line_msg = format!("* ({}) ({}) {}", resp, random.score, random.response); 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(); } @@ -226,45 +185,42 @@ pub async fn list_random(ctx: &Context, msg: &Message, args: Args) -> CommandRes } if !msg_builder.0.is_empty() { - dm_channel.say(&ctx.http, msg_builder.build()).await?; + dm_channel.say(&ctx, msg_builder.build()).await?; } } else { - msg.reply( - &ctx.http, - "*glances to the back room*, nope we ain't got that random", - ) - .await?; + ctx.reply("*glances to the back room*, nope we ain't got that random") + .await?; } Ok(()) } -#[command] -#[aliases("roll")] -#[description("Roll a die!")] -async fn roll(ctx: &Context, msg: &Message, args: Args) -> CommandResult { - let roll = args.rest().parse::(); +#[poise::command(prefix_command, category = "Joke")] +pub async fn roll( + ctx: Context<'_>, + #[description = "die to roll"] + #[rest] + die_roll: String, +) -> Result<(), Error> { + let roll = die_roll.parse::(); let reply = match 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(()) } -#[command] -#[aliases("real_roll")] -#[description("Roll a real die!")] -async fn real_roll(ctx: &Context, msg: &Message, _args: Args) -> CommandResult { - let data = ctx.data.read().await; - let global = data.get::().unwrap(); +#[poise::command(prefix_command, category = "Joke")] +pub async fn real_roll(ctx: Context<'_>) -> Result<(), Error> { + let addr = ctx.data().cfg.raas_server.clone(); - 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; @@ -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!") - .await?; - let response = client.send_request(roll_request).await?; + ctx.reply("Sent roll request, please hang on!").await?; + let response = client + .send_request(roll_request) + .await + .map_err(|err| Error::RaasError(err.to_string()))?; let raas_response = response.into_inner(); - println!( - "Got resp: {} @ {}", + debug!( + "Got resp from RaaS: {} @ {}", raas_response.id, raas_response.timestamp ); match raas_response.resp.unwrap() { Resp::RollResp(roll_resp) => { if let roll_response::Response::RollImage(img) = roll_resp.response.unwrap() { - msg.channel_id + ctx.channel_id() .send_message( - &ctx.http, + &ctx, CreateMessage::new() .content("Your roll my friend, hope its good I can't read!") .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) => { - msg.reply( - &ctx.http, - format!( - "My real flesh encountered an error. Get Dad to fix it. `{}`", - err.msg - ), - ) + ctx.reply(format!( + "My real flesh encountered an error. Get Dad to fix it. `{}`", + err.msg + )) .await?; } } @@ -316,22 +271,20 @@ async fn real_roll(ctx: &Context, msg: &Message, _args: Args) -> CommandResult { Ok(()) } -#[command] -#[bucket = "bad_apple"] -async fn bad_apple(ctx: &Context, msg: &Message, _args: Args) -> CommandResult { +#[poise::command(prefix_command, category = "Joke")] +pub async fn bad_apple(ctx: Context<'_>) -> Result<(), Error> { let mut frames = BAD_APPLE.split('|'); let first_frame = frames.next().unwrap(); 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?; return Ok(()); } - let mut bad_apple_msg = msg + let bad_apple_msg = ctx .reply( - &ctx.http, MessageBuilder::default() .push_codeblock_safe(first_frame, None) .build(), @@ -344,8 +297,8 @@ async fn bad_apple(ctx: &Context, msg: &Message, _args: Args) -> CommandResult { if (idx % 10) == 0 { bad_apple_msg .edit( - &ctx.http, - EditMessage::new().content( + ctx, + CreateReply::default().content( MessageBuilder::default() .push_codeblock_safe(frame, None) .build(), @@ -358,30 +311,26 @@ async fn bad_apple(ctx: &Context, msg: &Message, _args: Args) -> CommandResult { Ok(()) } -#[command] -#[aliases("compliment")] -async fn insult(ctx: &Context, msg: &Message, args: Args) -> CommandResult { - let data = ctx.data.read().await; - let global = data.get::().unwrap(); - - let pool = if msg.content.as_str().starts_with("!insult") { +#[poise::command(prefix_command, category = "Joke", aliases("compliment"))] +pub async fn insult( + ctx: Context<'_>, + #[description = "person to compliment/insult"] target: String, +) -> Result<(), Error> { + let pool = if ctx.invoked_command_name() == "insult" { ResponseType::Insult - } else if msg.content.as_str().starts_with("!compliment") { + } else if ctx.invoked_command_name() == "compliment" { ResponseType::Compliment } 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(()); }; - let target = args.rest(); - - let output = RandomResponseTemplate::get_random_response(&global.db, pool, target)?; + let output = RandomResponseTemplate::get_random_response(&ctx.data().db, pool, &target)?; if let Some(output) = output { - msg.reply(&ctx.http, output).await?; + ctx.reply(output).await?; } else { - msg.reply(&ctx, format!("No {}s, mr freeman??", msg.content)) - .await?; + ctx.reply(format!("No {}s, mr freeman??", target)).await?; } Ok(()) @@ -406,13 +355,14 @@ fn get_unicode_emojis() -> Vec { emoji.iter().map(|e| e.to_string()).collect() } -#[command] -#[aliases("🎱")] -async fn emoji_8ball(ctx: &Context, msg: &Message) -> CommandResult { - let data = ctx.data.read().await; - let global = data.get::().unwrap(); - - let guild_emojis = global.cfg.guild_id.emojis(&ctx.http).await?; +#[poise::command(prefix_command, category = "Joke", aliases("🎱"))] +pub async fn emoji_8ball( + ctx: Context<'_>, + #[description = "prompt to dissect using magic"] + #[rest] + _prompt: String, +) -> Result<(), Error> { + let guild_emojis = ctx.guild_id().unwrap().emojis(&ctx).await?; let mut emojis: Vec = guild_emojis.iter().map(|e| e.to_string()).collect(); let mut unicode_emojis = get_unicode_emojis(); @@ -421,7 +371,7 @@ async fn emoji_8ball(ctx: &Context, msg: &Message) -> CommandResult { let emoji_msg: Vec = emojis.choose_multiple(&mut rng(), 3).cloned().collect(); - msg.reply(&ctx.http, emoji_msg.join("")).await?; + ctx.reply(emoji_msg.join("")).await?; Ok(()) } diff --git a/src/discord/mod.rs b/src/discord/mod.rs index f5d0346..55df4c6 100644 --- a/src/discord/mod.rs +++ b/src/discord/mod.rs @@ -5,14 +5,16 @@ mod celeryman; mod color; mod emoji_race; mod fren_coin; +mod joke; use crate::config::GlobalData; use crate::error::Error; -use log::info; +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::models::task::Task; use poise::serenity_prelude::{Message, ReactionType}; 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) .await .unwrap_or_else(|e| { - println!("Error processing album command: {}", e); + error!("Error processing album command: {}", e); true }); if !parsed_album { - // handle random later + match random(ctx, data, message, &command).await { + Ok(_) => {} + Err(e) => error!("Error processing random command: {}", e), + } } Ok(()) @@ -173,6 +178,14 @@ pub async fn run_bot(global_data: GlobalData) { emoji_race::start_race(), fren_coin::balance(), 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| { Box::pin(event_handler(ctx, event, framework, data)) diff --git a/src/error.rs b/src/error.rs index c4a8967..a17b6f9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -14,6 +14,7 @@ pub enum Error { DbError(j_db::error::JDbError), ReqwestError(reqwest::Error), ParseFailure, + RaasError(String), } impl StdError for Error {} @@ -65,6 +66,7 @@ impl Display for Error { Error::DbError(e) => write!(f, "DB error: {}", e), Error::ReqwestError(e) => write!(f, "Reqwest Error: {}", e), Error::ParseFailure => write!(f, "Failed to parse something or other"), + Error::RaasError(msg) => write!(f, "Got error from RaaS: {}", msg), } } }