Merge pull request 'Added configurable event reminders' (#10) from config_reminders into master

Reviewed-on: https://git.etztech.xyz/ZeroHD/HypeBot/pulls/10
master
Joey Hines 2020-08-09 17:06:04 +02:00
commit 47a1bc9a2a
4 changed files with 79 additions and 36 deletions

View File

@ -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
```

View File

@ -80,8 +80,10 @@ pub fn get_countdown_link(event_name: &String, utc: &DateTime<Utc>) -> 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::<Vec<String>>().join(" ");
let ping_roles = config
.ping_roles
.clone()
.into_iter()
.map(|role| format!("<@&{}>", role))
.collect::<Vec<String>>()
.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::<SchedulerKey>()
.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<Http>, data: &Arc<RwLock<ShareMap>>, event: &Event) {
let scheduler = {
let mut context = data.write();
@ -257,24 +264,48 @@ pub fn schedule_event(http: &Arc<Http>, data: &Arc<RwLock<ShareMap>>, event: &Ev
.clone()
};
if event.reminder_sent < 1 {
let config = get_config(&data).unwrap();
if let Some(reminders) = config.reminders {
let event_time: DateTime<Utc> = DateTime::<Utc>::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<Http>, data: &Arc<RwLock<ShareMap>>, event: &Event) -> DateResult {
pub fn send_reminders(
http: &Arc<Http>,
data: &Arc<RwLock<ShareMap>>,
event: &Event,
reminder_msg: &String,
) -> DateResult {
let config = get_config(&data).unwrap();
let event_channel_id = config.event_channel;
let event_time: DateTime<Utc> = DateTime::<Utc>::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::<u64>() {
// Get message id
@ -284,27 +315,13 @@ pub fn send_reminders(http: &Arc<Http>, data: &Arc<RwLock<ShareMap>>, event: &Ev
.unwrap_or(Vec::<User>::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

View File

@ -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<Vec<EventReminder>>,
}
struct ConfigValueVisitor;

View File

@ -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,