From 699a02c642140c16f3a2acef830b6aa9de3b3e3c Mon Sep 17 00:00:00 2001 From: Joey Hines Date: Sun, 16 Mar 2025 15:56:26 -0600 Subject: [PATCH] Add birthdays and bring back task handling --- src/discord/birthday.rs | 78 ++++++++++++++--------------------------- src/discord/mod.rs | 34 +++++++++++++----- src/models/task.rs | 53 +++++++++++++--------------- 3 files changed, 76 insertions(+), 89 deletions(-) diff --git a/src/discord/birthday.rs b/src/discord/birthday.rs index 874826f..bdd9b0c 100644 --- a/src/discord/birthday.rs +++ b/src/discord/birthday.rs @@ -1,33 +1,19 @@ +use crate::discord::Context; +use crate::error::Error; use crate::models::birthday::BirthdayEntry; -use crate::{command, group, GlobalData}; -use rand::{thread_rng, Rng}; -use serenity::client::Context; -use serenity::framework::standard::{Args, CommandResult}; -use serenity::model::channel::Message; -use serenity::model::id::UserId; -use serenity::utils::MessageBuilder; +use poise::serenity_prelude::model::id::UserId; +use poise::serenity_prelude::utils::MessageBuilder; +use rand::{rng, Rng}; -#[group] -#[commands(add_birthday, list_birthdays)] -pub struct Birthday; - -#[command] -#[description("Add your birthday to the bot. Please use American dates or i will cut u.")] -#[example("add_birthday 04/21/1997")] -pub async fn add_birthday(ctx: &Context, msg: &Message, args: Args) -> CommandResult { - if args.is_empty() { - msg.reply( - &ctx.http, - "Look just give me a day, doesn't matter. I'm not the IRS", - ) - .await?; - return Ok(()); - } - - let date_split: Vec<&str> = args.rest().split('/').collect(); +#[poise::command(prefix_command, category = "Birthdays")] +pub async fn add_birthday( + ctx: Context<'_>, + #[description = "date in the form of mm/dd/yyyy"] date: String, +) -> Result<(), Error> { + let date_split: Vec<&str> = date.split('/').collect(); if date_split.len() < 3 { - msg.reply(&ctx.http, "Try again with a real date").await?; + ctx.reply("Try again with a real date, liberal").await?; return Ok(()); } @@ -36,43 +22,31 @@ pub async fn add_birthday(ctx: &Context, msg: &Message, args: Args) -> CommandRe let year: i32 = date_split[2].parse().unwrap_or(0); if month == 0 || day == 0 || year == 0 { - msg.reply(&ctx.http, "Try again with a real date").await?; + ctx.reply("Try again with a real date, commie").await?; return Ok(()); } if let Some(date) = chrono::NaiveDate::from_ymd_opt(year, month, day) { - let data = ctx.data.read().await; - let global_data = data.get::().unwrap(); + BirthdayEntry::add_birthday(&ctx.data().db, ctx.author().id.get(), date)?; - BirthdayEntry::add_birthday(&global_data.db, msg.author.id.get(), date)?; - - msg.reply( - &ctx.http, - format!( - "Thank you subject #{}, I am now {}% closer to making a full AI replica of you.", - msg.author.id.get(), - thread_rng().gen_range(0.0..100.0) - ), - ) + ctx.reply(format!( + "Thank you subject #{}, I am now {}% closer to making a full AI replica of you.", + ctx.author().id.get(), + rng().random_range(0.0..100.0) + )) .await?; } else { - msg.reply(&ctx.http, "Try again with a real date").await?; + ctx.reply("Try again with a real date, time wizard").await?; return Ok(()); } Ok(()) } -#[command] -#[description("Add your birthday to the bot. Please use American dates or i will cut u.")] -pub async fn list_birthdays(ctx: &Context, msg: &Message) -> CommandResult { - let data = ctx.data.read().await; - let global_data = data.get::().unwrap(); - - let birthdays: Vec = global_data - .db - .filter(|_, _: &BirthdayEntry| true)? - .collect(); +#[poise::command(prefix_command, category = "Birthdays")] +pub async fn list_birthdays(ctx: Context<'_>) -> Result<(), Error> { + let birthdays: Vec = + ctx.data().db.filter(|_, _: &BirthdayEntry| true)?.collect(); let mut msg_builder = MessageBuilder::new(); @@ -80,7 +54,7 @@ pub async fn list_birthdays(ctx: &Context, msg: &Message) -> CommandResult { for birthday in birthdays { let user_id = UserId::from(birthday.discord_id); - let user = user_id.to_user(&ctx.http).await?; + let user = user_id.to_user(ctx).await?; msg_builder.push_line(format!( "* {} {}", @@ -89,7 +63,7 @@ pub async fn list_birthdays(ctx: &Context, msg: &Message) -> CommandResult { )); } - msg.reply(&ctx.http, msg_builder.build()).await?; + ctx.reply(msg_builder.build()).await?; Ok(()) } diff --git a/src/discord/mod.rs b/src/discord/mod.rs index 2a98d3b..5930505 100644 --- a/src/discord/mod.rs +++ b/src/discord/mod.rs @@ -1,26 +1,42 @@ mod admin; mod album; +mod birthday; mod celeryman; use crate::config::GlobalData; use crate::error::Error; use log::info; use magick_rust::bindings::wchar_t; +use std::sync::Arc; +use std::time::Duration; +use crate::models::task::Task; use poise::serenity_prelude::Message; use poise::{find_command, serenity_prelude as serenity, FrameworkOptions}; -pub type Context<'a> = poise::Context<'a, GlobalData, Error>; +pub type Context<'a> = poise::Context<'a, Arc, Error>; async fn event_handler( ctx: &serenity::Context, event: &serenity::FullEvent, - framework: poise::FrameworkContext<'_, GlobalData, Error>, - data: &GlobalData, + framework: poise::FrameworkContext<'_, Arc, Error>, + data: &Arc, ) -> Result<(), Error> { match event { serenity::FullEvent::Ready { data_about_bot, .. } => { info!("Bot ready, and logged in as {}", data_about_bot.user.name); + + { + let data = data.clone(); + let ctx = ctx.clone(); + tokio::spawn(async move { + let _ = Task::create_reoccurring_tasks(&data).await.is_ok(); + loop { + let _ = Task::run_tasks(&ctx, &data).await.is_ok(); + tokio::time::sleep(Duration::from_secs(5)).await; + } + }); + } } serenity::FullEvent::Message { new_message } => { if new_message.content.starts_with("!") { @@ -79,7 +95,7 @@ async fn pre_command(ctx: Context<'_>) { } pub async fn run_bot(global_data: GlobalData) { - let framework_options: FrameworkOptions = poise::FrameworkOptions { + let framework_options: FrameworkOptions, Error> = poise::FrameworkOptions { prefix_options: poise::PrefixFrameworkOptions { prefix: Some("!".into()), ignore_bots: true, @@ -88,9 +104,6 @@ pub async fn run_bot(global_data: GlobalData) { ..Default::default() }, commands: vec![ - celeryman::nudetayne(), - celeryman::celeryman(), - celeryman::tayne(), admin::dump_db(), admin::load_db(), admin::add_key(), @@ -101,6 +114,11 @@ pub async fn run_bot(global_data: GlobalData) { admin::list_tasks(), album::add_image(), album::list_albums(), + birthday::add_birthday(), + birthday::list_birthdays(), + celeryman::nudetayne(), + celeryman::celeryman(), + celeryman::tayne(), ], event_handler: |ctx, event, framework, data| { Box::pin(event_handler(ctx, event, framework, data)) @@ -116,7 +134,7 @@ pub async fn run_bot(global_data: GlobalData) { .setup(move |ctx, _ready, framework| { Box::pin(async move { poise::builtins::register_globally(ctx, &framework.options().commands).await?; - Ok(global_data) + Ok(Arc::new(global_data)) }) }) .build(); diff --git a/src/models/task.rs b/src/models/task.rs index 5d55e1d..0cadbee 100644 --- a/src/models/task.rs +++ b/src/models/task.rs @@ -1,4 +1,5 @@ use crate::config::GlobalData; +use std::sync::Arc; //use crate::discord::shop::restock_shop; use crate::discord::Context; use crate::error::Error; @@ -80,11 +81,11 @@ impl Task { Ok(()) } - pub async fn create_reoccurring_tasks(ctx: Context<'_>) -> Result<(), Error> { - Task::add_task(&ctx.data().db, TaskType::CheckBirthdays, Utc::now())?; - Task::add_task(&ctx.data().db, TaskType::RestockShop, Utc::now())?; + pub async fn create_reoccurring_tasks(data: &Arc) -> Result<(), Error> { + Task::add_task(&data.db, TaskType::CheckBirthdays, Utc::now())?; + Task::add_task(&data.db, TaskType::RestockShop, Utc::now())?; Task::add_task( - &ctx.data().db, + &data.db, TaskType::HandleReload, Utc::now() + Duration::hours(1), )?; @@ -92,9 +93,11 @@ impl Task { Ok(()) } - pub async fn run_tasks(ctx: Context<'_>) -> Result<(), Error> { - let active_tasks: Vec = ctx - .data() + pub async fn run_tasks( + ctx: &poise::serenity_prelude::Context, + data: &Arc, + ) -> Result<(), Error> { + let active_tasks: Vec = data .db .filter(|_, task: &Task| task.time < Utc::now())? .collect(); @@ -102,43 +105,35 @@ impl Task { for task in active_tasks { match task.task_type { TaskType::RemoveRole { user_id, role_id } => { - let user = ctx.data().cfg.guild_id.member(ctx.http(), user_id).await?; + let user = data.cfg.guild_id.member(&ctx.http, user_id).await?; info!("Removing role {} from {}", role_id, user.display_name()); - user.remove_role(ctx.http(), role_id).await?; + user.remove_role(&ctx.http, role_id).await?; } TaskType::CheckBirthdays => { info!("Checking Birthdays"); - let todays_birthdays = BirthdayEntry::todays_birthdays( - &ctx.data().db, - chrono::Utc::now().date_naive(), - )?; + let todays_birthdays = + BirthdayEntry::todays_birthdays(&data.db, chrono::Utc::now().date_naive())?; for birth in todays_birthdays { - if let Ok(user) = ctx - .data() - .cfg - .guild_id - .member(ctx.http(), birth.discord_id) - .await + if let Ok(user) = + data.cfg.guild_id.member(&ctx.http, birth.discord_id).await { - ctx.data() - .cfg + data.cfg .announcement_channel - .say(ctx.http(), format!("Happy birthday {}!", user.mention())) + .say(&ctx.http, format!("Happy birthday {}!", user.mention())) .await?; let compliment = RandomResponseTemplate::get_random_response( - &ctx.data().db, + &data.db, ResponseType::Compliment, user.display_name(), )? .unwrap_or("I couldn't think of anything funny tbh...".to_string()); - ctx.data() - .cfg + data.cfg .announcement_channel - .say(ctx.http(), compliment) + .say(&ctx.http, compliment) .await?; } } @@ -155,7 +150,7 @@ impl Task { .unwrap(); Task::add_task( - &ctx.data().db, + &data.db, TaskType::CheckBirthdays, next_check.with_timezone(&Utc), )?; @@ -173,14 +168,14 @@ impl Task { // } Task::add_task( - &ctx.data().db, + &data.db, TaskType::RestockShop, Utc::now() + Duration::hours(1), )?; } } - let _ = ctx.data().db.remove::(task.id().unwrap()).is_ok(); + let _ = data.db.remove::(task.id().unwrap()).is_ok(); } Ok(())