FrenBot/src/models/task.rs
Joey Hines 67ff69aca0
Updated serenity version and added new commands
+ Added task.rs to handle periodic tasks
2024-01-15 16:53:17 -07:00

201 lines
6.3 KiB
Rust

use crate::config::GlobalData;
use crate::discord::shop::restock_shop;
use crate::error::Error;
use crate::models::birthday::BirthdayEntry;
use crate::models::insult_compliment::{RandomResponseTemplate, ResponseType};
use chrono::{Days, Duration, TimeZone, Timelike, Utc};
use j_db::database::Database;
use j_db::model::JdbModel;
use serde::{Deserialize, Serialize};
use serenity::all::Mentionable;
use serenity::prelude::Context;
#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq)]
pub enum TaskType {
RemoveRole { user_id: u64, role_id: u64 },
CheckBirthdays,
HandleReload,
RestockShop,
}
impl TaskType {
pub fn exclusive(&self) -> bool {
matches!(
self,
TaskType::CheckBirthdays | TaskType::HandleReload | TaskType::RestockShop
)
}
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Task {
id: Option<u64>,
task_type: TaskType,
time: chrono::DateTime<Utc>,
}
impl JdbModel for Task {
fn id(&self) -> Option<u64> {
self.id
}
fn set_id(&mut self, id: u64) {
self.id = Some(id)
}
fn tree() -> String {
"tasks".to_string()
}
fn check_unique(&self, _other: &Self) -> bool {
true
}
}
impl Task {
pub fn add_task(
db: &Database,
task_type: TaskType,
time: chrono::DateTime<chrono::Utc>,
) -> Result<(), Error> {
if task_type.exclusive() {
let old_tasks: Vec<Task> = db
.filter(|_, task: &Task| task.task_type == task_type)?
.collect();
for task in old_tasks {
db.remove::<Task>(task.id().unwrap())?;
}
}
db.insert::<Task>(Task {
id: None,
task_type,
time,
})?;
println!("Adding {:?} task to run at {}", task_type, time);
Ok(())
}
pub async fn create_reoccurring_tasks(ctx: &Context) -> Result<(), Error> {
let mut data = ctx.data.write().await;
let global_data = data.get_mut::<GlobalData>().unwrap();
Task::add_task(&global_data.db, TaskType::CheckBirthdays, Utc::now())?;
Task::add_task(&global_data.db, TaskType::RestockShop, Utc::now())?;
Task::add_task(
&global_data.db,
TaskType::HandleReload,
Utc::now() + Duration::hours(1),
)?;
Ok(())
}
pub async fn run_tasks(ctx: &Context) -> Result<(), Error> {
let mut data = ctx.data.write().await;
let global_data = data.get_mut::<GlobalData>().unwrap();
let active_tasks: Vec<Task> = global_data
.db
.filter(|_, task: &Task| task.time < chrono::Utc::now())?
.collect();
for task in active_tasks {
match task.task_type {
TaskType::RemoveRole { user_id, role_id } => {
let user = global_data
.cfg
.guild_id
.member(&ctx.http, user_id)
.await
.unwrap();
println!("Removing role {} from {}", role_id, user.display_name());
user.remove_role(&ctx.http, role_id).await.unwrap();
}
TaskType::CheckBirthdays => {
println!("Checking Birthdays");
let todays_birthdays = BirthdayEntry::todays_birthdays(
&global_data.db,
chrono::Utc::now().date_naive(),
)
.unwrap();
for birth in todays_birthdays {
if let Ok(user) = global_data
.cfg
.guild_id
.member(&ctx.http, birth.discord_id)
.await
{
global_data
.cfg
.announcement_channel
.say(&ctx.http, format!("Happy birthday {}!", user.mention()))
.await
.unwrap();
let compliment = RandomResponseTemplate::get_random_response(
&global_data.db,
ResponseType::Compliment,
user.display_name(),
)
.unwrap()
.unwrap();
global_data
.cfg
.announcement_channel
.say(&ctx.http, compliment)
.await
.unwrap();
}
}
let next_check = chrono_tz::America::Chicago
.from_utc_datetime(&Utc::now().naive_utc())
.with_hour(8)
.unwrap()
.with_minute(0)
.unwrap()
.with_second(0)
.unwrap()
.checked_add_days(Days::new(1))
.unwrap();
Task::add_task(
&global_data.db,
TaskType::CheckBirthdays,
next_check.with_timezone(&Utc),
)?;
}
TaskType::HandleReload => {
println!("Reloading config...");
global_data.reload().await.unwrap();
Task::add_task(
&global_data.db,
TaskType::HandleReload,
Utc::now() + Duration::hours(1),
)?;
}
TaskType::RestockShop => {
println!("Restocking Shop...");
restock_shop(ctx, global_data).await.unwrap();
Task::add_task(
&global_data.db,
TaskType::RestockShop,
Utc::now() + Duration::hours(1),
)?;
}
}
let _ = global_data.db.remove::<Task>(task.id().unwrap()).is_ok();
}
Ok(())
}
}