diff --git a/README.md b/README.md index bc07568..4bd263f 100644 --- a/README.md +++ b/README.md @@ -41,4 +41,19 @@ ping_roles = [0] event_timezone = "America/New_York" # Path to place logs in log_path = "log/" + +# Configurable Reminders +[[reminders]] +# Message to send, "{EVENT_NAME}" gets replaced with the event's name +msg = "{EVENT_NAME} is starting now!" +# number of minutes before an event to send the reminder +reminder_time = 0 + +[[reminders]] +msg = "{EVENT_NAME} is starting in 1 minute!" +reminder_time = 1 + +[[reminders]] +msg = "{EVENT_NAME} is starting in 5 minutes!" +reminder_time = 5 ``` \ No newline at end of file diff --git a/src/discord/mod.rs b/src/discord/mod.rs index c7879a6..e780fe3 100644 --- a/src/discord/mod.rs +++ b/src/discord/mod.rs @@ -80,8 +80,10 @@ pub fn get_countdown_link(event_name: &String, utc: &DateTime) -> String { let msg = event_name.replace(" ", "+"); let time = utc.format("%G%m%dT%H%M").to_string(); - format!("https://www.timeanddate.com/countdown/generic?iso={}&p0=&msg={}&font=sanserif&csz=1", time, msg) - + format!( + "https://www.timeanddate.com/countdown/generic?iso={}&p0=&msg={}&font=sanserif&csz=1", + time, msg + ) } /// Sends the event message to the event channel @@ -98,9 +100,13 @@ pub fn send_event_msg( let native_time = utc_time.with_timezone(&config.event_timezone); - let ping_roles = config.ping_roles.clone().into_iter().map(|role| { - format!("<@&{}>", role) - }).collect::>().join(" "); + let ping_roles = config + .ping_roles + .clone() + .into_iter() + .map(|role| format!("<@&{}>", role)) + .collect::>() + .join(" "); // Send message let msg = channel.id().send_message(&http, |m| { @@ -208,7 +214,7 @@ pub fn get_scheduler( let mut context = data.write(); Ok(context .get_mut::() - .ok_or(CommandError("Unable to scheduler".to_string()))? + .ok_or(CommandError("Unable to get scheduler".to_string()))? .clone()) } @@ -248,6 +254,7 @@ pub fn permission_check(ctx: &mut Context, msg: &Message, _command_name: &str) - false } +/// Schedule event reminders pub fn schedule_event(http: &Arc, data: &Arc>, event: &Event) { let scheduler = { let mut context = data.write(); @@ -257,24 +264,48 @@ pub fn schedule_event(http: &Arc, data: &Arc>, event: &Ev .clone() }; - if event.reminder_sent < 1 { + let config = get_config(&data).unwrap(); + + if let Some(reminders) = config.reminders { let event_time: DateTime = DateTime::::from_utc(event.event_time.clone(), Utc); - let reminder_time = event_time - chrono::Duration::minutes(10); + let delete_time = event_time + chrono::Duration::minutes(1); let mut scheduler = scheduler.write(); + + for reminder in reminders { + let reminder_time = + event_time - chrono::Duration::minutes(reminder.reminder_time as i64); + + if reminder_time > chrono::offset::Utc::now() { + let reminder_msg = reminder.msg.clone(); + let http = http.clone(); + let data = data.clone(); + let event = event.clone(); + + scheduler.add_task_datetime(reminder_time, move |_| { + send_reminders(&http, &data, &event, &reminder_msg) + }); + } + } + let http = http.clone(); let data = data.clone(); let event = event.clone(); - - scheduler.add_task_datetime(reminder_time, move |_| send_reminders(&http, &data, &event)); + scheduler.add_task_datetime(delete_time, move |_| { + delete_event(&http, &data, &event); + DateResult::Done + }); } } /// Send reminders -pub fn send_reminders(http: &Arc, data: &Arc>, event: &Event) -> DateResult { +pub fn send_reminders( + http: &Arc, + data: &Arc>, + event: &Event, + reminder_msg: &String, +) -> DateResult { let config = get_config(&data).unwrap(); let event_channel_id = config.event_channel; - let event_time: DateTime = DateTime::::from_utc(event.event_time.clone(), Utc); - let delete_time = event_time + chrono::Duration::minutes(60); if let Ok(message_id) = event.message_id.parse::() { // Get message id @@ -284,27 +315,13 @@ pub fn send_reminders(http: &Arc, data: &Arc>, event: &Ev .unwrap_or(Vec::::new()); // Build reminder message - let msg: String = format!("Hello! **{}** is starting soon!", &event.event_name); + let msg: String = reminder_msg.replace("{EVENT_NAME}", event.event_name.as_str()); // Send reminder to each reacted user for user in reaction_users { send_dm_message(&http, user, &msg); } } - - set_reminder(config.db_url.clone(), event.id, 1).ok(); - - let scheduler = get_scheduler(data).unwrap(); - let mut scheduler = scheduler.write(); - - let http = http.clone(); - let data = data.clone(); - let event = event.clone(); - - scheduler.add_task_datetime(delete_time, move |_| { - delete_event(&http, &data, &event); - DateResult::Done - }); } DateResult::Done diff --git a/src/hypebot_config.rs b/src/hypebot_config.rs index 0b07737..e50825b 100644 --- a/src/hypebot_config.rs +++ b/src/hypebot_config.rs @@ -5,6 +5,12 @@ use serde::{Deserialize, Deserializer}; use serenity::prelude::TypeMapKey; use std::fmt; +#[derive(Debug, Deserialize, Clone)] +pub struct EventReminder { + pub msg: String, + pub reminder_time: u32, +} + #[derive(Debug, Deserialize, Clone)] pub struct HypeBotConfig { pub db_url: String, @@ -17,6 +23,7 @@ pub struct HypeBotConfig { #[serde(deserialize_with = "from_tz_string")] pub event_timezone: Tz, pub log_path: String, + pub reminders: Option>, } struct ConfigValueVisitor; diff --git a/src/main.rs b/src/main.rs index 174006f..ad21e9c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,13 +10,13 @@ extern crate log4rs; use chrono::{DateTime, Utc}; use clap::{App, Arg}; use log::LevelFilter; -use log4rs::append::rolling_file::{RollingFileAppender}; -use log4rs::config::{Appender, Config, Root}; -use log4rs::encode::pattern::PatternEncoder; use log4rs::append::console::ConsoleAppender; use log4rs::append::rolling_file::policy::compound::roll::fixed_window::FixedWindowRoller; use log4rs::append::rolling_file::policy::compound::trigger::size::SizeTrigger; use log4rs::append::rolling_file::policy::compound::CompoundPolicy; +use log4rs::append::rolling_file::RollingFileAppender; +use log4rs::config::{Appender, Config, Root}; +use log4rs::encode::pattern::PatternEncoder; use log4rs::filter::threshold::ThresholdFilter; use log4rs::init_config; use serenity::client::Client; @@ -28,10 +28,10 @@ use serenity::model::id::UserId; use serenity::model::prelude::Ready; use serenity::prelude::{Context, EventHandler, RwLock}; use std::collections::HashSet; +use std::path::Path; use std::process::exit; use std::sync::Arc; use white_rabbit::{DateResult, Scheduler}; -use std::path::Path; mod database; mod discord; @@ -41,8 +41,8 @@ use database::models::NewEvent; use database::*; use discord::events::{CANCEL_COMMAND, CONFIRM_COMMAND, CREATE_COMMAND}; use discord::{ - delete_event, get_config, get_scheduler, log_error, permission_check, - send_message_to_reaction_users, schedule_event, DraftEvent, SchedulerKey, + delete_event, get_config, get_scheduler, log_error, permission_check, schedule_event, + send_message_to_reaction_users, DraftEvent, SchedulerKey, }; use hypebot_config::HypeBotConfig; @@ -71,7 +71,9 @@ impl EventHandler for Handler { return; } }; - if reaction.channel_id.0 == config.event_channel && reaction.emoji.as_data() == INTERESTED_EMOJI { + if reaction.channel_id.0 == config.event_channel + && reaction.emoji.as_data() == INTERESTED_EMOJI + { send_message_to_reaction_users( &ctx, &reaction, @@ -89,7 +91,9 @@ impl EventHandler for Handler { return; } }; - if reaction.channel_id.0 == config.event_channel && reaction.emoji.as_data() == INTERESTED_EMOJI { + if reaction.channel_id.0 == config.event_channel + && reaction.emoji.as_data() == INTERESTED_EMOJI + { send_message_to_reaction_users( &ctx, &reaction,