From ee89cb40c50ebd17e086cb0933e1f71391c3d3de Mon Sep 17 00:00:00 2001 From: jude Date: Sun, 3 Sep 2023 15:01:42 +0100 Subject: [PATCH] Move errors route into get_reminders route. Add database migration. --- .../20230903131153_reminder_status_timing.sql | 4 ++ src/component_models/mod.rs | 22 ++++--- src/models/reminder/mod.rs | 11 ++-- web/src/lib.rs | 1 - web/src/routes/dashboard/export.rs | 2 + web/src/routes/dashboard/guild.rs | 59 ++++++------------- web/src/routes/dashboard/mod.rs | 16 ++--- web/static/css/style.css | 38 ++++++++++++ web/static/js/main.js | 9 ++- web/static/js/reminder_errors.js | 12 ++-- web/templates/dashboard.html.tera | 22 +++---- .../reminder_dashboard.html.tera | 2 +- .../reminder_errors.html.tera | 46 +++++++++++++++ .../{ => templates}/guild_reminder.html.tera | 0 .../templates/reminder_error.html.tera | 13 ++++ 15 files changed, 172 insertions(+), 85 deletions(-) create mode 100644 migrations/20230903131153_reminder_status_timing.sql rename web/templates/reminder_dashboard/{ => templates}/guild_reminder.html.tera (100%) create mode 100644 web/templates/reminder_dashboard/templates/reminder_error.html.tera diff --git a/migrations/20230903131153_reminder_status_timing.sql b/migrations/20230903131153_reminder_status_timing.sql new file mode 100644 index 0000000..742b1a9 --- /dev/null +++ b/migrations/20230903131153_reminder_status_timing.sql @@ -0,0 +1,4 @@ +ALTER TABLE reminders ADD COLUMN `status_change_time` DATETIME; + +-- This is a best-guess as to the status change time. +UPDATE reminders SET `status_change_time` = `utc_time`; diff --git a/src/component_models/mod.rs b/src/component_models/mod.rs index 9251796..ff1832a 100644 --- a/src/component_models/mod.rs +++ b/src/component_models/mod.rs @@ -166,15 +166,21 @@ impl ComponentDataModel { .await; } ComponentDataModel::DelSelector(selector) => { - let selected_id = component.data.values.join(","); + for id in &component.data.values { + match id.parse::() { + Ok(id) => { + if let Some(reminder) = Reminder::from_id(&data.database, id).await { + reminder.delete(&data.database).await.unwrap(); + } else { + warn!("Attempt to delete non-existent reminder"); + } + } - sqlx::query!( - "UPDATE reminders SET `status` = 'deleted' WHERE FIND_IN_SET(id, ?)", - selected_id - ) - .execute(&data.database) - .await - .unwrap(); + Err(e) => { + warn!("Error casting ID to integer: {:?}.", e); + } + } + } let reminders = Reminder::from_guild( &ctx, diff --git a/src/models/reminder/mod.rs b/src/models/reminder/mod.rs index 5e69971..edf9d24 100644 --- a/src/models/reminder/mod.rs +++ b/src/models/reminder/mod.rs @@ -304,10 +304,13 @@ WHERE &self, db: impl Executor<'_, Database = Database>, ) -> Result<(), sqlx::Error> { - sqlx::query!("UPDATE reminders SET `status` = 'deleted' WHERE uid = ?", self.uid) - .execute(db) - .await - .map(|_| ()) + sqlx::query!( + "UPDATE reminders SET `status` = 'deleted', `status_change_time` = NOW() WHERE uid = ?", + self.uid + ) + .execute(db) + .await + .map(|_| ()) } pub fn display_content(&self) -> &str { diff --git a/web/src/lib.rs b/web/src/lib.rs index ab77794..c45e2d5 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -166,7 +166,6 @@ pub async fn initialize( routes::dashboard::guild::get_reminders, routes::dashboard::guild::edit_reminder, routes::dashboard::guild::delete_reminder, - routes::dashboard::guild::get_reminder_errors, routes::dashboard::export::export_reminders, routes::dashboard::export::export_reminder_templates, routes::dashboard::export::export_todos, diff --git a/web/src/routes/dashboard/export.rs b/web/src/routes/dashboard/export.rs index d1f33c1..86cf10e 100644 --- a/web/src/routes/dashboard/export.rs +++ b/web/src/routes/dashboard/export.rs @@ -171,6 +171,8 @@ pub async fn import_reminders( uid: generate_uid(), username: record.username, utc_time: record.utc_time, + status: "pending".to_string(), + status_change_time: None, }; create_reminder( diff --git a/web/src/routes/dashboard/guild.rs b/web/src/routes/dashboard/guild.rs index 0d34365..4c33798 100644 --- a/web/src/routes/dashboard/guild.rs +++ b/web/src/routes/dashboard/guild.rs @@ -26,7 +26,7 @@ use crate::{ routes::{ dashboard::{ create_database_channel, create_reminder, template_name_default, DeleteReminder, - DeleteReminderTemplate, PatchReminder, Reminder, ReminderError, ReminderTemplate, + DeleteReminderTemplate, PatchReminder, Reminder, ReminderTemplate, }, JsonResult, }, @@ -318,15 +318,18 @@ pub async fn create_guild_reminder( .await } -#[get("/api/guild//reminders")] +#[get("/api/guild//reminders?")] pub async fn get_reminders( id: u64, cookies: &CookieJar<'_>, serenity_context: &State, pool: &State>, + status: Option, ) -> JsonResult { check_authorization!(cookies, serenity_context.inner(), id); + let status = status.unwrap_or("pending".to_string()); + sqlx::query_as_unchecked!( Reminder, "SELECT @@ -355,10 +358,13 @@ pub async fn get_reminders( reminders.tts, reminders.uid, reminders.username, - reminders.utc_time + reminders.utc_time, + reminders.status, + reminders.status_change_time FROM reminders LEFT JOIN channels ON channels.id = reminders.channel_id - WHERE `status` = 'pending' AND reminders.guild_id = (SELECT id FROM guilds WHERE guild = ?)", + WHERE FIND_IN_SET(`status`, ?) AND reminders.guild_id = (SELECT id FROM guilds WHERE guild = ?)", + status, id ) .fetch_all(pool.inner()) @@ -567,7 +573,9 @@ pub async fn edit_reminder( reminders.tts, reminders.uid, reminders.username, - reminders.utc_time + reminders.utc_time, + reminders.status, + reminders.status_change_time FROM reminders LEFT JOIN channels ON channels.id = reminders.channel_id WHERE uid = ?", @@ -591,9 +599,12 @@ pub async fn delete_reminder( reminder: Json, pool: &State>, ) -> JsonResult { - match sqlx::query!("UPDATE reminders SET `status` = 'deleted' WHERE uid = ?", reminder.uid) - .execute(pool.inner()) - .await + match sqlx::query!( + "UPDATE reminders SET `status` = 'deleted', `status_change_time` = NOW() WHERE uid = ?", + reminder.uid + ) + .execute(pool.inner()) + .await { Ok(_) => Ok(json!({})), @@ -604,35 +615,3 @@ pub async fn delete_reminder( } } } - -#[get("/api/guild//errors")] -pub async fn get_reminder_errors( - id: u64, - cookies: &CookieJar<'_>, - serenity_context: &State, - pool: &State>, -) -> JsonResult { - check_authorization!(cookies, serenity_context.inner(), id); - - sqlx::query_as_unchecked!( - ReminderError, - "SELECT - reminders.status, - reminders.utc_time, - reminders.name, - reminders.uid, - reminders.channel_id AS channel - FROM reminders - LEFT JOIN channels ON channels.id = reminders.channel_id - WHERE (`status` = 'failed' OR reminders.channel_id IS NULL) AND reminders.guild_id = (SELECT id FROM guilds WHERE guild = ?)", - id - ) - .fetch_all(pool.inner()) - .await - .map(|r| Ok(json!(r))) - .unwrap_or_else(|e| { - warn!("Failed to complete SQL query: {:?}", e); - - json_err!("Could not load reminders") - }) -} diff --git a/web/src/routes/dashboard/mod.rs b/web/src/routes/dashboard/mod.rs index c56089a..65ff743 100644 --- a/web/src/routes/dashboard/mod.rs +++ b/web/src/routes/dashboard/mod.rs @@ -150,18 +150,8 @@ pub struct Reminder { uid: String, username: Option, utc_time: NaiveDateTime, -} - -#[derive(Serialize)] -pub struct ReminderError { - #[serde(with = "string")] - channel: u64, status: String, - #[serde(default = "name_default")] - name: String, - #[serde(default)] - uid: String, - utc_time: NaiveDateTime, + status_change_time: Option, } #[derive(Serialize, Deserialize)] @@ -574,7 +564,9 @@ pub async fn create_reminder( reminders.tts, reminders.uid, reminders.username, - reminders.utc_time + reminders.utc_time, + reminders.status, + reminders.status_change_time FROM reminders LEFT JOIN channels ON channels.id = reminders.channel_id WHERE uid = ?", diff --git a/web/static/css/style.css b/web/static/css/style.css index fb42aa9..e254b9c 100644 --- a/web/static/css/style.css +++ b/web/static/css/style.css @@ -688,6 +688,44 @@ li.highlight { /* END */ +div.reminderError { + margin: 10px; + padding: 14px; + background-color: #f5f5f5; + border-radius: 8px; +} + +div.reminderError .errorHead { + display: flex; + flex-direction: row; +} + +div.reminderError .errorIcon { + padding: 8px; + border-radius: 4px; + margin-right: 12px; +} + +div.reminderError .errorIcon.deleted { + background-color: #e7e5e4; +} + +div.reminderError .errorIcon.success { + background-color: #d9f99d; +} + +div.reminderError .errorIcon.errored { + background-color: #fecaca; +} + +div.reminderError .errorHead .reminderName { + font-size: 1rem; + display: flex; + flex-direction: column; + justify-content: center; + color: rgb(54, 54, 54); +} + /* other stuff */ .half-rem { diff --git a/web/static/js/main.js b/web/static/js/main.js index cd164c7..9aec630 100644 --- a/web/static/js/main.js +++ b/web/static/js/main.js @@ -57,7 +57,7 @@ function switch_pane(selector) { el.classList.add("is-hidden"); }); - document.getElementById(selector).classList.remove("is-hidden"); + document.querySelector(`*[data-name=${selector}]`).classList.remove("is-hidden"); } function update_select(sel) { @@ -735,16 +735,19 @@ document.addEventListener("DOMContentLoaded", async () => { }); } - const matches = window.location.href.match(/dashboard\/(\d+)/); + const matches = window.location.href.match( + /dashboard\/(\d+)(\/)?([a-zA-Z\-]+)?/ + ); if (matches) { let id = matches[1]; + let kind = matches[3]; let name = guildNames[id]; const event = new CustomEvent("guildSwitched", { detail: { guild_name: name, guild_id: id, - pane: "guild", + pane: kind, }, }); diff --git a/web/static/js/reminder_errors.js b/web/static/js/reminder_errors.js index ff12367..4affb99 100644 --- a/web/static/js/reminder_errors.js +++ b/web/static/js/reminder_errors.js @@ -1,16 +1,18 @@ function loadErrors() { - return fetch(`/dashboard/api/guild/${guildId()}/errors`).then((response) => - response.json() - ); + return fetch( + `/dashboard/api/guild/${guildId()}/reminders?status=deleted,sent,error` + ).then((response) => response.json()); } document.addEventListener("paneLoad", (ev) => { - if (ev.detail.pane !== "reminder-errors") { + if (ev.detail.pane !== "errors") { return; } // Load errors - loadErrors().then((res) => {}); + loadErrors().then((res) => { + console.log(res); + }); $loader.classList.add("is-hidden"); }); diff --git a/web/templates/dashboard.html.tera b/web/templates/dashboard.html.tera index 18585c8..1e12718 100644 --- a/web/templates/dashboard.html.tera +++ b/web/templates/dashboard.html.tera @@ -332,16 +332,16 @@

Press the to get started

-