Add status update time to sender
This commit is contained in:
		@@ -472,10 +472,17 @@ WHERE
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn set_sent(&self, pool: impl Executor<'_, Database = Database> + Copy) {
 | 
					    async fn set_sent(&self, pool: impl Executor<'_, Database = Database> + Copy) {
 | 
				
			||||||
        sqlx::query!("UPDATE reminders SET `status` = 'sent' WHERE `id` = ?", self.id)
 | 
					        sqlx::query!(
 | 
				
			||||||
            .execute(pool)
 | 
					            "
 | 
				
			||||||
            .await
 | 
					            UPDATE reminders
 | 
				
			||||||
            .expect(&format!("Could not delete Reminder {}", self.id));
 | 
					            SET `status` = 'sent', `status_change_time` = NOW()
 | 
				
			||||||
 | 
					            WHERE `id` = ?
 | 
				
			||||||
 | 
					            ",
 | 
				
			||||||
 | 
					            self.id
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .execute(pool)
 | 
				
			||||||
 | 
					        .await
 | 
				
			||||||
 | 
					        .expect(&format!("Could not delete Reminder {}", self.id));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn set_failed(
 | 
					    async fn set_failed(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,11 @@ impl ChannelData {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if let Ok(c) = sqlx::query_as_unchecked!(
 | 
					        if let Ok(c) = sqlx::query_as_unchecked!(
 | 
				
			||||||
            Self,
 | 
					            Self,
 | 
				
			||||||
            "SELECT id, name, nudge, blacklisted, webhook_id, webhook_token, paused, paused_until, guild_id AS db_guild_id FROM channels WHERE channel = ?",
 | 
					            "
 | 
				
			||||||
 | 
					            SELECT id, name, nudge, blacklisted, webhook_id, webhook_token, paused, paused_until,
 | 
				
			||||||
 | 
					                guild_id AS db_guild_id
 | 
				
			||||||
 | 
					            FROM channels WHERE channel = ?
 | 
				
			||||||
 | 
					            ",
 | 
				
			||||||
            channel_id
 | 
					            channel_id
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        .fetch_one(pool)
 | 
					        .fetch_one(pool)
 | 
				
			||||||
@@ -31,12 +35,18 @@ impl ChannelData {
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            Ok(c)
 | 
					            Ok(c)
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            let props = channel.to_owned().guild().map(|g| (g.guild_id.as_u64().to_owned(), g.name));
 | 
					            let props =
 | 
				
			||||||
 | 
					                channel.to_owned().guild().map(|g| (g.guild_id.as_u64().to_owned(), g.name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let (guild_id, channel_name) = if let Some((a, b)) = props { (Some(a), Some(b)) } else { (None, None) };
 | 
					            let (guild_id, channel_name) =
 | 
				
			||||||
 | 
					                if let Some((a, b)) = props { (Some(a), Some(b)) } else { (None, None) };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            sqlx::query!(
 | 
					            sqlx::query!(
 | 
				
			||||||
                "INSERT IGNORE INTO channels (channel, name, guild_id) VALUES (?, ?, (SELECT id FROM guilds WHERE guild = ?))",
 | 
					                "
 | 
				
			||||||
 | 
					                INSERT IGNORE INTO channels
 | 
				
			||||||
 | 
					                (channel, name, guild_id)
 | 
				
			||||||
 | 
					                VALUES (?, ?, (SELECT id FROM guilds WHERE guild = ?))
 | 
				
			||||||
 | 
					                ",
 | 
				
			||||||
                channel_id,
 | 
					                channel_id,
 | 
				
			||||||
                channel_name,
 | 
					                channel_name,
 | 
				
			||||||
                guild_id
 | 
					                guild_id
 | 
				
			||||||
@@ -47,7 +57,10 @@ impl ChannelData {
 | 
				
			|||||||
            Ok(sqlx::query_as_unchecked!(
 | 
					            Ok(sqlx::query_as_unchecked!(
 | 
				
			||||||
                Self,
 | 
					                Self,
 | 
				
			||||||
                "
 | 
					                "
 | 
				
			||||||
SELECT id, name, nudge, blacklisted, webhook_id, webhook_token, paused, paused_until, guild_id AS db_guild_id FROM channels WHERE channel = ?
 | 
					                SELECT id, name, nudge, blacklisted, webhook_id, webhook_token, paused,
 | 
				
			||||||
 | 
					                    paused_until, guild_id AS db_guild_id
 | 
				
			||||||
 | 
					                FROM channels
 | 
				
			||||||
 | 
					                WHERE channel = ?
 | 
				
			||||||
                ",
 | 
					                ",
 | 
				
			||||||
                channel_id
 | 
					                channel_id
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
@@ -59,9 +72,10 @@ SELECT id, name, nudge, blacklisted, webhook_id, webhook_token, paused, paused_u
 | 
				
			|||||||
    pub async fn commit_changes(&self, pool: &MySqlPool) {
 | 
					    pub async fn commit_changes(&self, pool: &MySqlPool) {
 | 
				
			||||||
        sqlx::query!(
 | 
					        sqlx::query!(
 | 
				
			||||||
            "
 | 
					            "
 | 
				
			||||||
UPDATE channels SET name = ?, nudge = ?, blacklisted = ?, webhook_id = ?, webhook_token = ?, paused = ?, paused_until \
 | 
					            UPDATE channels
 | 
				
			||||||
             = ? WHERE id = ?
 | 
					            SET name = ?, nudge = ?, blacklisted = ?, webhook_id = ?, webhook_token = ?,
 | 
				
			||||||
            ",
 | 
					                paused = ?, paused_until = ?
 | 
				
			||||||
 | 
					            WHERE id = ?",
 | 
				
			||||||
            self.name,
 | 
					            self.name,
 | 
				
			||||||
            self.nudge,
 | 
					            self.nudge,
 | 
				
			||||||
            self.blacklisted,
 | 
					            self.blacklisted,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -145,7 +145,7 @@ pub async fn import_reminders(
 | 
				
			|||||||
                                    attachment: record.attachment,
 | 
					                                    attachment: record.attachment,
 | 
				
			||||||
                                    attachment_name: record.attachment_name,
 | 
					                                    attachment_name: record.attachment_name,
 | 
				
			||||||
                                    avatar: record.avatar,
 | 
					                                    avatar: record.avatar,
 | 
				
			||||||
                                    channel: channel_id,
 | 
					                                    channel: Some(channel_id),
 | 
				
			||||||
                                    content: record.content,
 | 
					                                    content: record.content,
 | 
				
			||||||
                                    embed_author: record.embed_author,
 | 
					                                    embed_author: record.embed_author,
 | 
				
			||||||
                                    embed_author_url: record.embed_author_url,
 | 
					                                    embed_author_url: record.embed_author_url,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -332,7 +332,8 @@ pub async fn get_reminders(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    sqlx::query_as_unchecked!(
 | 
					    sqlx::query_as_unchecked!(
 | 
				
			||||||
        Reminder,
 | 
					        Reminder,
 | 
				
			||||||
        "SELECT
 | 
					        "
 | 
				
			||||||
 | 
					        SELECT
 | 
				
			||||||
         reminders.attachment,
 | 
					         reminders.attachment,
 | 
				
			||||||
         reminders.attachment_name,
 | 
					         reminders.attachment_name,
 | 
				
			||||||
         reminders.avatar,
 | 
					         reminders.avatar,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -124,8 +124,8 @@ pub struct Reminder {
 | 
				
			|||||||
    attachment: Option<Vec<u8>>,
 | 
					    attachment: Option<Vec<u8>>,
 | 
				
			||||||
    attachment_name: Option<String>,
 | 
					    attachment_name: Option<String>,
 | 
				
			||||||
    avatar: Option<String>,
 | 
					    avatar: Option<String>,
 | 
				
			||||||
    #[serde(with = "string")]
 | 
					    #[serde(with = "string_opt")]
 | 
				
			||||||
    channel: u64,
 | 
					    channel: Option<u64>,
 | 
				
			||||||
    content: String,
 | 
					    content: String,
 | 
				
			||||||
    embed_author: String,
 | 
					    embed_author: String,
 | 
				
			||||||
    embed_author_url: Option<String>,
 | 
					    embed_author_url: Option<String>,
 | 
				
			||||||
@@ -310,6 +310,34 @@ mod string {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod string_opt {
 | 
				
			||||||
 | 
					    use std::{fmt::Display, str::FromStr};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use serde::{de, Deserialize, Deserializer, Serializer};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn serialize<T, S>(value: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        T: Display,
 | 
				
			||||||
 | 
					        S: Serializer,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        match value {
 | 
				
			||||||
 | 
					            Some(value) => serializer.collect_str(value),
 | 
				
			||||||
 | 
					            None => serializer.serialize_none(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn deserialize<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        T: FromStr,
 | 
				
			||||||
 | 
					        T::Err: Display,
 | 
				
			||||||
 | 
					        D: Deserializer<'de>,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Option::deserialize(deserializer)?
 | 
				
			||||||
 | 
					            .map(|d: String| d.parse().map_err(de::Error::custom))
 | 
				
			||||||
 | 
					            .transpose()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod base64s {
 | 
					mod base64s {
 | 
				
			||||||
    use serde::{de, Deserialize, Deserializer, Serializer};
 | 
					    use serde::{de, Deserialize, Deserializer, Serializer};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -374,7 +402,7 @@ pub async fn create_reminder(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // validate channel
 | 
					    // validate channel
 | 
				
			||||||
    let channel = ChannelId(reminder.channel).to_channel_cached(&ctx);
 | 
					    let channel = reminder.channel.map(|c| ChannelId(c).to_channel_cached(&ctx)).flatten();
 | 
				
			||||||
    let channel_exists = channel.is_some();
 | 
					    let channel_exists = channel.is_some();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let channel_matches_guild =
 | 
					    let channel_matches_guild =
 | 
				
			||||||
@@ -382,14 +410,14 @@ pub async fn create_reminder(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if !channel_matches_guild || !channel_exists {
 | 
					    if !channel_matches_guild || !channel_exists {
 | 
				
			||||||
        warn!(
 | 
					        warn!(
 | 
				
			||||||
            "Error in `create_reminder`: channel {} not found for guild {} (channel exists: {})",
 | 
					            "Error in `create_reminder`: channel {:?} not found for guild {} (channel exists: {})",
 | 
				
			||||||
            reminder.channel, guild_id, channel_exists
 | 
					            reminder.channel, guild_id, channel_exists
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return Err(json!({"error": "Channel not found"}));
 | 
					        return Err(json!({"error": "Channel not found"}));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let channel = create_database_channel(&ctx, ChannelId(reminder.channel), pool).await;
 | 
					    let channel = create_database_channel(&ctx, ChannelId(reminder.channel.unwrap()), pool).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if let Err(e) = channel {
 | 
					    if let Err(e) = channel {
 | 
				
			||||||
        warn!("`create_database_channel` returned an error code: {:?}", e);
 | 
					        warn!("`create_database_channel` returned an error code: {:?}", e);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,10 @@ document.addEventListener("paneLoad", (ev) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    loadErrors()
 | 
					    loadErrors()
 | 
				
			||||||
        .then((res) => {
 | 
					        .then((res) => {
 | 
				
			||||||
 | 
					            res = res
 | 
				
			||||||
 | 
					                .filter((r) => r.status_change_time !== null)
 | 
				
			||||||
 | 
					                .sort((a, b) => a.status_change_time < b.status_change_time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (const reminder of res) {
 | 
					            for (const reminder of res) {
 | 
				
			||||||
                const newRow = template.content.cloneNode(true);
 | 
					                const newRow = template.content.cloneNode(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user