Allow multiple reminder dates for a single chat group
This commit is contained in:
65
src/main.rs
65
src/main.rs
@@ -14,13 +14,15 @@ use bot::fetch_and_announce_appointment;
|
||||
use chrono::{DateTime, Days, NaiveTime, TimeZone, Utc};
|
||||
use chrono_tz::Europe;
|
||||
use db::ChatInfo;
|
||||
use diesel::result::Error::NotFound;
|
||||
use diesel::{Connection, RunQueryDsl, SqliteConnection};
|
||||
use diesel::result::Error::{self, NotFound};
|
||||
use diesel::{
|
||||
BelongingToDsl, Connection, GroupedBy, RunQueryDsl, SelectableHelper, SqliteConnection,
|
||||
};
|
||||
use diesel::{ExpressionMethods, QueryDsl};
|
||||
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
|
||||
use error::ConfigLoadError;
|
||||
use log::*;
|
||||
use serde::{de::Error, Deserialize, Deserializer};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use teloxide::adaptors::Throttle;
|
||||
use teloxide::prelude::RequesterExt;
|
||||
use teloxide::requests::Requester;
|
||||
@@ -29,7 +31,7 @@ use teloxide::{adaptors::throttle::Limits, Bot};
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::bot::Command;
|
||||
use crate::db::DbChat;
|
||||
use crate::db::{DbChat, DbReminder};
|
||||
|
||||
#[macro_use]
|
||||
extern crate rust_i18n;
|
||||
@@ -49,7 +51,7 @@ pub struct Config {
|
||||
|
||||
fn deserialize_time<'de, D: Deserializer<'de>>(deserializer: D) -> Result<NaiveTime, D::Error> {
|
||||
let s: String = Deserialize::deserialize(deserializer)?;
|
||||
NaiveTime::parse_from_str(&s, "%H:%M").map_err(D::Error::custom)
|
||||
NaiveTime::parse_from_str(&s, "%H:%M").map_err(serde::de::Error::custom)
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -146,15 +148,29 @@ struct Reminder<Tz: TimeZone> {
|
||||
// Checks if the date of the next appointment has changed (and announces if so)
|
||||
// Additionally, checks if it is time for a reminder and sends that reminder if necessary
|
||||
async fn check_task(bot: &Throttle<Bot>, config: &Config, db: &Database) -> Result<()> {
|
||||
let chats = db.lock().await.transaction(|db| {
|
||||
let chats = db.lock().await.transaction::<_, Error, _>(|db| {
|
||||
use schema::chat::dsl::*;
|
||||
chat.load::<DbChat>(db)
|
||||
use schema::reminder::dsl::*;
|
||||
let chats = chat.load::<DbChat>(db)?;
|
||||
|
||||
let reminders: Vec<DbReminder> = DbReminder::belonging_to(&chats)
|
||||
.select(DbReminder::as_select())
|
||||
.order(days_ahead.asc())
|
||||
.load(db)?;
|
||||
|
||||
let reminders_per_chat = reminders
|
||||
.grouped_by(&chats)
|
||||
.into_iter()
|
||||
.zip(chats)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(reminders_per_chat)
|
||||
})?;
|
||||
|
||||
let now = Utc::now().with_timezone(&Europe::Berlin);
|
||||
|
||||
for chat in chats {
|
||||
let mut chat_info = ChatInfo::from(chat);
|
||||
for (reminders, chat) in chats {
|
||||
let mut chat_info = ChatInfo::from_db(chat, reminders);
|
||||
fetch_and_announce_appointment(bot, &mut chat_info, db).await?;
|
||||
|
||||
let appointment = match chat_info.next_appointment {
|
||||
@@ -170,17 +186,24 @@ async fn check_task(bot: &Throttle<Bot>, config: &Config, db: &Database) -> Resu
|
||||
text: t!("messages.starting_now", locale = &chat_info.locale),
|
||||
});
|
||||
} else {
|
||||
let reminder_day =
|
||||
appointment.start.date_naive() - Days::new(chat_info.remind_days_ahead);
|
||||
let reminder_date_time = if chat_info.remind_days_ahead == 0 {
|
||||
reminder_day.and_time(config.reminder_time)
|
||||
} else {
|
||||
reminder_day.and_time(config.preceeding_day_reminder_time)
|
||||
};
|
||||
let reminder_date_time = reminder_date_time
|
||||
.and_local_timezone(now.timezone())
|
||||
.unwrap();
|
||||
if now >= reminder_date_time {
|
||||
// This assumes that remind_days_ahead is sorted in ascending order
|
||||
let most_recent_active_reminder = chat_info
|
||||
.remind_days_ahead
|
||||
.iter()
|
||||
.map(|days_ahead| {
|
||||
let reminder_day = appointment.start.date_naive() - Days::new(*days_ahead);
|
||||
let reminder_date_time = if *days_ahead == 0 {
|
||||
reminder_day.and_time(config.reminder_time)
|
||||
} else {
|
||||
reminder_day.and_time(config.preceeding_day_reminder_time)
|
||||
};
|
||||
reminder_date_time
|
||||
.and_local_timezone(now.timezone())
|
||||
.unwrap()
|
||||
})
|
||||
.find(|reminder_datetime| now >= *reminder_datetime);
|
||||
|
||||
if let Some(reminder_date_time) = most_recent_active_reminder {
|
||||
// TODO This can have weird effects if it's happenig around midnight, since it's not timezone aware (and may even mix multiple timezones)
|
||||
let remaining_time = appointment.start.date_naive() - now.date_naive();
|
||||
let remaining_days = remaining_time.num_days();
|
||||
@@ -203,7 +226,7 @@ async fn check_task(bot: &Throttle<Bot>, config: &Config, db: &Database) -> Resu
|
||||
reminder = Some(Reminder {
|
||||
time: reminder_date_time,
|
||||
text: reminder_text,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user