reminder-bot/src/commands/reminder_cmds.rs

397 lines
11 KiB
Rust
Raw Normal View History

2020-09-01 14:34:50 +00:00
use regex_command_attr::command;
use serenity::{
client::Context,
model::{
channel::{
Message,
},
},
framework::standard::CommandResult,
};
use crate::{
models::{
ChannelData,
GuildData,
2020-09-01 14:34:50 +00:00
UserData,
2020-09-05 20:17:45 +00:00
Reminder,
2020-09-01 14:34:50 +00:00
},
SQLPool,
time_parser::TimeParser,
};
use chrono::NaiveDateTime;
2020-09-05 20:17:45 +00:00
use regex::Regex;
use std::default::Default;
lazy_static! {
static ref REGEX_CHANNEL: Regex = Regex::new(r#"^\s*<#(\d+)>\s*$"#).unwrap();
}
2020-09-01 14:34:50 +00:00
#[command]
2020-09-01 17:48:40 +00:00
#[supports_dm(false)]
#[permission_level(Restricted)]
2020-09-01 14:34:50 +00:00
async fn pause(ctx: &Context, msg: &Message, args: String) -> CommandResult {
let pool = ctx.data.read().await
.get::<SQLPool>().cloned().expect("Could not get SQLPool from data");
let user_data = UserData::from_id(&msg.author, &ctx, &pool).await.unwrap();
let mut channel = ChannelData::from_channel(msg.channel(&ctx).await.unwrap(), &pool).await.unwrap();
2020-09-01 14:34:50 +00:00
if args.len() == 0 {
channel.paused = !channel.paused;
channel.paused_until = None;
channel.commit_changes(&pool).await;
2020-09-01 14:34:50 +00:00
if channel.paused {
2020-09-01 17:37:43 +00:00
let _ = msg.channel_id.say(&ctx, user_data.response(&pool, "pause/paused_indefinite").await).await;
2020-09-01 14:34:50 +00:00
}
else {
2020-09-01 17:37:43 +00:00
let _ = msg.channel_id.say(&ctx, user_data.response(&pool, "pause/unpaused").await).await;
2020-09-01 14:34:50 +00:00
}
}
else {
let parser = TimeParser::new(args, user_data.timezone.parse().unwrap());
let pause_until = parser.timestamp();
match pause_until {
Ok(timestamp) => {
channel.paused = true;
channel.paused_until = Some(NaiveDateTime::from_timestamp(timestamp, 0));
channel.commit_changes(&pool).await;
2020-09-01 14:34:50 +00:00
2020-09-01 17:37:43 +00:00
let _ = msg.channel_id.say(&ctx, user_data.response(&pool, "pause/paused_until").await).await;
2020-09-01 14:34:50 +00:00
},
Err(_) => {
2020-09-01 17:37:43 +00:00
let _ = msg.channel_id.say(&ctx, user_data.response(&pool, "pause/invalid_time").await).await;
2020-09-01 14:34:50 +00:00
},
}
}
Ok(())
}
#[command]
2020-09-01 17:48:40 +00:00
#[permission_level(Restricted)]
async fn offset(ctx: &Context, msg: &Message, args: String) -> CommandResult {
let pool = ctx.data.read().await
.get::<SQLPool>().cloned().expect("Could not get SQLPool from data");
let user_data = UserData::from_id(&msg.author, &ctx, &pool).await.unwrap();
if args.len() == 0 {
let _ = msg.channel_id.say(&ctx, user_data.response(&pool, "offset/help").await).await;
}
else {
let parser = TimeParser::new(args, user_data.timezone());
if let Ok(displacement) = parser.displacement() {
if let Some(guild) = msg.guild(&ctx).await {
let guild_data = GuildData::from_guild(guild, &pool).await.unwrap();
sqlx::query!(
"
UPDATE reminders
INNER JOIN `channels`
ON `channels`.id = reminders.channel_id
SET
reminders.`time` = reminders.`time` + ?
WHERE channels.guild_id = ?
", displacement, guild_data.id)
.execute(&pool)
.await
.unwrap();
} else {
sqlx::query!(
"
UPDATE reminders SET `time` = `time` + ? WHERE reminders.channel_id = ?
", displacement, user_data.dm_channel)
.execute(&pool)
.await
.unwrap();
}
let response = user_data.response(&pool, "offset/success").await.replacen("{}", &displacement.to_string(), 1);
let _ = msg.channel_id.say(&ctx, response).await;
} else {
let _ = msg.channel_id.say(&ctx, user_data.response(&pool, "offset/invalid_time").await).await;
}
}
Ok(())
}
2020-09-01 17:37:43 +00:00
#[command]
2020-09-01 17:48:40 +00:00
#[permission_level(Restricted)]
2020-09-01 17:37:43 +00:00
async fn nudge(ctx: &Context, msg: &Message, args: String) -> CommandResult {
let pool = ctx.data.read().await
.get::<SQLPool>().cloned().expect("Could not get SQLPool from data");
let user_data = UserData::from_id(&msg.author, &ctx, &pool).await.unwrap();
let mut channel = ChannelData::from_channel(msg.channel(&ctx).await.unwrap(), &pool).await.unwrap();
if args.len() == 0 {
let _ = msg.channel_id.say(&ctx, user_data.response(&pool, "nudge/invalid_time").await).await;
}
else {
let parser = TimeParser::new(args, user_data.timezone.parse().unwrap());
let nudge_time = parser.displacement();
match nudge_time {
Ok(displacement) => {
if displacement < i16::MIN as i64 || displacement > i16::MAX as i64 {
let _ = msg.channel_id.say(&ctx, user_data.response(&pool, "nudge/invalid_time").await).await;
}
else {
channel.nudge = displacement as i16;
channel.commit_changes(&pool).await;
let response = user_data.response(&pool, "nudge/success").await.replacen("{}", &displacement.to_string(), 1);
let _ = msg.channel_id.say(&ctx, response).await;
}
},
Err(_) => {
let _ = msg.channel_id.say(&ctx, user_data.response(&pool, "nudge/invalid_time").await).await;
},
}
}
Ok(())
}
2020-09-05 20:17:45 +00:00
enum TimeDisplayType {
Absolute,
Relative,
}
struct LookFlags {
pub limit: u16,
pub show_disabled: bool,
pub channel_id: Option<u64>,
time_display: TimeDisplayType,
}
impl Default for LookFlags {
fn default() -> Self {
Self {
limit: u16::MAX,
show_disabled: true,
channel_id: None,
time_display: TimeDisplayType::Relative
}
}
}
impl LookFlags {
fn from_string(args: &str) -> Self {
let mut new_flags: Self = Default::default();
for arg in args.split(" ") {
match arg {
"enabled" => {
new_flags.show_disabled = false;
},
"time" => {
new_flags.time_display = TimeDisplayType::Absolute;
},
param => {
if let Ok(val) = param.parse::<u16>() {
new_flags.limit = val;
}
else {
new_flags.channel_id = REGEX_CHANNEL.captures(&args)
.map(|cap| cap.get(1))
.flatten()
.map(|c| c.as_str().parse::<u64>().unwrap());
}
}
}
}
new_flags
}
fn display_time(&self, timestamp: u64) -> String {
String::from("")
}
}
#[command]
2020-09-07 23:12:17 +00:00
#[permission_level(Managed)]
2020-09-05 20:17:45 +00:00
async fn look(ctx: &Context, msg: &Message, args: String) -> CommandResult {
let pool = ctx.data.read().await
.get::<SQLPool>().cloned().expect("Could not get SQLPool from data");
let user_data = UserData::from_id(&msg.author, &ctx, &pool).await.unwrap();
let flags = LookFlags::from_string(&args);
let enabled = if flags.show_disabled { None } else { Some(false) };
let reminders = if let Some(guild_id) = msg.guild_id.map(|f| f.as_u64().to_owned()) {
let channel_id = flags.channel_id.unwrap_or(msg.channel_id.as_u64().to_owned());
sqlx::query_as!(Reminder,
"
SELECT
2020-09-07 23:12:17 +00:00
reminders.id, reminders.time, reminders.name, reminders.channel_id
2020-09-05 20:17:45 +00:00
FROM
reminders
INNER JOIN
channels
ON
reminders.channel_id = channels.id
WHERE
channels.guild_id = (SELECT id FROM guilds WHERE guild = ?) AND
channels.channel = ? AND
reminders.enabled != ?
LIMIT
?
", guild_id, channel_id, enabled, flags.limit)
.fetch_all(&pool)
.await
}
else {
sqlx::query_as!(Reminder,
"
SELECT
2020-09-07 23:12:17 +00:00
id, time, name, channel_id
2020-09-05 20:17:45 +00:00
FROM
reminders
WHERE
2020-09-07 23:12:17 +00:00
reminders.channel_id = (SELECT id FROM channels WHERE channel = ?) AND
2020-09-05 20:17:45 +00:00
reminders.enabled != ?
LIMIT
?
", msg.channel_id.as_u64(), enabled, flags.limit)
.fetch_all(&pool)
.await
2020-09-07 23:12:17 +00:00
}.unwrap();
2020-09-05 20:17:45 +00:00
if reminders.len() == 0 {
let _ = msg.channel_id.say(&ctx, user_data.response(&pool, "look/no_reminders").await).await;
}
else {
let inter = user_data.response(&pool, "look/inter").await;
let display = reminders
.iter()
.map(|reminder| format!("'{}' *{}* **{}**", reminder.name, &inter, reminder.time))
.collect::<Vec<String>>().join("\n");
let _ = msg.channel_id.say(&ctx, display).await;
}
Ok(())
}
2020-09-07 23:12:17 +00:00
#[command]
#[permission_level(Managed)]
async fn delete(ctx: &Context, msg: &Message, args: String) -> CommandResult {
let pool = ctx.data.read().await
.get::<SQLPool>().cloned().expect("Could not get SQLPool from data");
let user_data = UserData::from_id(&msg.author, &ctx, &pool).await.unwrap();
let _ = msg.channel_id.say(&ctx, user_data.response(&pool, "del/listing").await).await;
let reminders = if let Some(guild_id) = msg.guild_id.map(|f| f.as_u64().to_owned()) {
sqlx::query_as!(Reminder,
"
SELECT
reminders.id, reminders.time, reminders.name, reminders.channel_id
FROM
reminders
INNER JOIN
channels
ON
reminders.channel_id = channels.id
WHERE
channels.guild_id = (SELECT id FROM guilds WHERE guild = ?)
", guild_id)
.fetch_all(&pool)
.await
}
else {
sqlx::query_as!(Reminder,
"
SELECT
id, time, name, channel_id
FROM
reminders
WHERE
channel_id = (SELECT id FROM channels WHERE channel = ?)
", msg.channel_id.as_u64())
.fetch_all(&pool)
.await
}.unwrap();
let mut reminder_ids: Vec<u32> = vec![];
let enumerated_reminders = reminders
.iter()
.enumerate()
.map(|(count, reminder)| {
reminder_ids.push(reminder.id);
format!("**{}**: '{}' *{}* at {}", count + 1, reminder.name, reminder.channel_id, reminder.time)
})
.collect::<Vec<String>>()
.join("\n");
let _ = msg.channel_id.say(&ctx, enumerated_reminders).await;
let _ = msg.channel_id.say(&ctx, user_data.response(&pool, "del/listed").await).await;
let reply = msg.channel_id.await_reply(&ctx)
.filter_limit(1)
.author_id(msg.author.id)
.channel_id(msg.channel_id).await;
if let Some(content) = reply.map(|m| m.content.replace(",", " ")) {
let parts = content.split(" ").filter(|i| i.len() > 0).collect::<Vec<&str>>();
let valid_parts = parts
.iter()
.filter_map(
|i|
i.parse::<usize>()
.ok()
.map(
|val|
reminder_ids.get(val)
)
.flatten()
)
.map(|item| item.to_string())
.collect::<Vec<String>>();
if parts.len() == valid_parts.len() {
sqlx::query!(
"
DELETE FROM reminders WHERE id IN (?)
", valid_parts.join(","))
.execute(&pool)
.await;
// TODO add deletion events to event list
let _ = msg.channel_id.say(&ctx, user_data.response(&pool, "del/count").await).await;
}
}
Ok(())
}