diff --git a/healthcheck b/healthcheck index 3504c39..2fceaa4 100755 --- a/healthcheck +++ b/healthcheck @@ -5,7 +5,7 @@ export $(grep -v '^#' /etc/reminder-rs/config.env | xargs -d '\n') REGEX='mysql://([A-Za-z]+)@(.+)/(.+)' [[ $DATABASE_URL =~ $REGEX ]] -VAR=$(mysql -u "${BASH_REMATCH[1]}" -h "${BASH_REMATCH[2]}" -N -D "${BASH_REMATCH[3]}" -e "SELECT COUNT(1) FROM reminders WHERE utc_time < NOW() - INTERVAL 10 MINUTE AND enabled = 1") +VAR=$(mysql -u "${BASH_REMATCH[1]}" -h "${BASH_REMATCH[2]}" -N -D "${BASH_REMATCH[3]}" -e "SELECT COUNT(1) FROM reminders WHERE utc_time < NOW() - INTERVAL 10 MINUTE AND enabled = 1 AND status = 'pending'") if [ "$VAR" -gt 0 ] then diff --git a/migrations/20230731170452_reminder_archive.sql b/migrations/20230731170452_reminder_archive.sql new file mode 100644 index 0000000..89863a8 --- /dev/null +++ b/migrations/20230731170452_reminder_archive.sql @@ -0,0 +1,2 @@ +ALTER TABLE reminders ADD COLUMN `status` ENUM ('pending', 'sent', 'failed', 'deleted') NOT NULL DEFAULT 'pending'; +ALTER TABLE reminders ADD COLUMN `status_message` TEXT; diff --git a/postman/src/sender.rs b/postman/src/sender.rs index eb05823..60392ed 100644 --- a/postman/src/sender.rs +++ b/postman/src/sender.rs @@ -302,6 +302,7 @@ INNER JOIN ON reminders.channel_id = channels.id WHERE + reminders.`status` = 'pending' AND reminders.`id` IN ( SELECT MIN(id) @@ -358,7 +359,7 @@ WHERE && self.interval_days == Some(0) && self.interval_months == Some(0) { - self.force_delete(pool).await; + self.set_sent(pool).await; } let now = Utc::now(); @@ -408,9 +409,9 @@ WHERE None::<&'static str>, ) .await; - self.force_delete(pool).await; + self.set_failed(pool, "Failed to update 4 times and so is being deleted").await; } else if self.expires.map_or(false, |expires| updated_reminder_time > expires) { - self.force_delete(pool).await; + self.set_sent(pool).await; } else { sqlx::query!( "UPDATE reminders SET `utc_time` = ? WHERE `id` = ?", @@ -422,7 +423,7 @@ WHERE .expect(&format!("Could not update time on Reminder {}", self.id)); } } else { - self.force_delete(pool).await; + self.set_sent(pool).await; } } @@ -468,13 +469,28 @@ WHERE } } - async fn force_delete(&self, pool: impl Executor<'_, Database = Database> + Copy) { - sqlx::query!("DELETE FROM reminders WHERE `id` = ?", self.id) + async fn set_sent(&self, pool: impl Executor<'_, Database = Database> + Copy) { + sqlx::query!("UPDATE reminders SET `status` = 'sent' WHERE `id` = ?", self.id) .execute(pool) .await .expect(&format!("Could not delete Reminder {}", self.id)); } + async fn set_failed( + &self, + pool: impl Executor<'_, Database = Database> + Copy, + message: &'static str, + ) { + sqlx::query!( + "UPDATE reminders SET `status` = 'failed', `status_message` = ? WHERE `id` = ?", + message, + self.id + ) + .execute(pool) + .await + .expect(&format!("Could not delete Reminder {}", self.id)); + } + async fn pin_message>(&self, message_id: M, http: impl AsRef) { let _ = http.as_ref().pin_message(self.channel_id, message_id.into(), None).await; } @@ -649,7 +665,11 @@ WHERE None::<&'static str>, ) .await; - self.force_delete(pool).await; + self.set_failed( + pool, + "Could not be sent as channel does not exist", + ) + .await; } 10004 => { self.log_error( @@ -658,7 +678,8 @@ WHERE None::<&'static str>, ) .await; - self.force_delete(pool).await; + self.set_failed(pool, "Could not be sent as guild does not exist") + .await; } 50001 => { self.log_error( @@ -667,7 +688,11 @@ WHERE None::<&'static str>, ) .await; - self.force_delete(pool).await; + self.set_failed( + pool, + "Could not be sent as permissions are invalid", + ) + .await; } 50007 => { self.log_error( @@ -676,7 +701,8 @@ WHERE None::<&'static str>, ) .await; - self.force_delete(pool).await; + self.set_failed(pool, "Could not be sent as user has DMs disabled") + .await; } _ => { self.log_error( diff --git a/src/component_models/mod.rs b/src/component_models/mod.rs index 11d6cbf..65fd9e2 100644 --- a/src/component_models/mod.rs +++ b/src/component_models/mod.rs @@ -168,10 +168,13 @@ impl ComponentDataModel { ComponentDataModel::DelSelector(selector) => { let selected_id = component.data.values.join(","); - sqlx::query!("DELETE FROM reminders WHERE FIND_IN_SET(id, ?)", selected_id) - .execute(&data.database) - .await - .unwrap(); + sqlx::query!( + "UPDATE reminders SET `status` = 'pending' WHERE FIND_IN_SET(id, ?)", + selected_id + ) + .execute(&data.database) + .await + .unwrap(); let reminders = Reminder::from_guild( &ctx, diff --git a/src/models/reminder/mod.rs b/src/models/reminder/mod.rs index 27c601a..5e69971 100644 --- a/src/models/reminder/mod.rs +++ b/src/models/reminder/mod.rs @@ -159,6 +159,7 @@ LEFT JOIN ON reminders.set_by = users.id WHERE + `status` = 'pending' AND channels.channel = ? AND FIND_IN_SET(reminders.enabled, ?) ORDER BY @@ -217,6 +218,7 @@ LEFT JOIN ON reminders.set_by = users.id WHERE + `status` = 'pending' AND FIND_IN_SET(channels.channel, ?) ", channels @@ -251,6 +253,7 @@ LEFT JOIN ON reminders.set_by = users.id WHERE + `status` = 'pending' AND channels.guild_id = (SELECT id FROM guilds WHERE guild = ?) ", guild_id.as_u64() @@ -286,6 +289,7 @@ LEFT JOIN ON reminders.set_by = users.id WHERE + `status` = 'pending' AND channels.id = (SELECT dm_channel FROM users WHERE user = ?) ", user.as_u64() @@ -300,7 +304,10 @@ WHERE &self, db: impl Executor<'_, Database = Database>, ) -> Result<(), sqlx::Error> { - sqlx::query!("DELETE FROM reminders WHERE uid = ?", self.uid).execute(db).await.map(|_| ()) + sqlx::query!("UPDATE reminders SET `status` = 'deleted' WHERE uid = ?", self.uid) + .execute(db) + .await + .map(|_| ()) } pub fn display_content(&self) -> &str { diff --git a/web/src/routes/admin.rs b/web/src/routes/admin.rs index ea46732..ee5303f 100644 --- a/web/src/routes/admin.rs +++ b/web/src/routes/admin.rs @@ -45,7 +45,7 @@ pub async fn bot_data(cookies: &CookieJar<'_>, pool: &State>) -> Jso } let backlog = sqlx::query!( - "SELECT COUNT(1) AS backlog FROM reminders WHERE `utc_time` < NOW() AND enabled = 1" + "SELECT COUNT(1) AS backlog FROM reminders WHERE `utc_time` < NOW() AND enabled = 1 AND `status` = 'pending'" ) .fetch_one(pool.inner()) .await @@ -61,6 +61,7 @@ pub async fn bot_data(cookies: &CookieJar<'_>, pool: &State>) -> Jso `utc_time` < DATE_ADD(NOW(), INTERVAL 1 DAY) AND `utc_time` >= NOW() AND `enabled` = 1 AND + `status` = 'pending' AND `interval_seconds` IS NULL AND `interval_months` IS NULL AND `interval_days` IS NULL @@ -80,6 +81,7 @@ pub async fn bot_data(cookies: &CookieJar<'_>, pool: &State>) -> Jso WHERE `utc_time` < DATE_ADD(NOW(), INTERVAL 1 DAY) AND `utc_time` >= NOW() AND + `status` = 'pending' AND `enabled` = 1 AND ( `interval_seconds` IS NOT NULL OR `interval_months` IS NOT NULL OR @@ -102,6 +104,7 @@ pub async fn bot_data(cookies: &CookieJar<'_>, pool: &State>) -> Jso `utc_time` < DATE_ADD(NOW(), INTERVAL 31 DAY) AND `utc_time` >= NOW() AND `enabled` = 1 AND + `status` = 'pending' AND `interval_seconds` IS NULL AND `interval_months` IS NULL AND `interval_days` IS NULL @@ -121,6 +124,7 @@ pub async fn bot_data(cookies: &CookieJar<'_>, pool: &State>) -> Jso WHERE `utc_time` < DATE_ADD(NOW(), INTERVAL 31 DAY) AND `utc_time` >= NOW() AND + `status` = 'pending' AND `enabled` = 1 AND ( `interval_seconds` IS NOT NULL OR `interval_months` IS NOT NULL OR @@ -169,9 +173,11 @@ pub async fn bot_data(cookies: &CookieJar<'_>, pool: &State>) -> Jso "SELECT COUNT(1) AS count FROM reminders WHERE - `interval_seconds` IS NOT NULL OR - `interval_months` IS NOT NULL OR - `interval_days` IS NOT NULL" + `status` = 'pending' AND ( + `interval_seconds` IS NOT NULL OR + `interval_months` IS NOT NULL OR + `interval_days` IS NOT NULL + )" ) .fetch_one(pool.inner()) .await @@ -181,6 +187,7 @@ pub async fn bot_data(cookies: &CookieJar<'_>, pool: &State>) -> Jso "SELECT COUNT(1) AS count FROM reminders WHERE + `status` = 'pending' AND `interval_seconds` IS NULL AND `interval_months` IS NULL AND `interval_days` IS NULL" diff --git a/web/src/routes/dashboard/guild.rs b/web/src/routes/dashboard/guild.rs index c31be7a..38aa541 100644 --- a/web/src/routes/dashboard/guild.rs +++ b/web/src/routes/dashboard/guild.rs @@ -362,7 +362,7 @@ pub async fn get_reminders( reminders.utc_time FROM reminders LEFT JOIN channels ON channels.id = reminders.channel_id - WHERE FIND_IN_SET(channels.channel, ?)", + WHERE `status` = 'pending' AND FIND_IN_SET(channels.channel, ?)", channels ) .fetch_all(pool.inner()) @@ -602,7 +602,7 @@ pub async fn delete_reminder( reminder: Json, pool: &State>, ) -> JsonResult { - match sqlx::query!("DELETE FROM reminders WHERE uid = ?", reminder.uid) + match sqlx::query!("UPDATE reminders SET `status` = 'deleted' WHERE uid = ?", reminder.uid) .execute(pool.inner()) .await {