//! Scheduled messages — maps to `message_scheduled` table. //! //! A message that the user has composed but wants to send at a future time. //! A background job picks up rows where `scheduled_at <= now()` and dispatches //! them through the normal send path. use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; /// A message scheduled to be sent at a future time. /// /// Maps to the `message_scheduled` table. A background job picks up rows /// where `scheduled_at <= now()` and dispatches them through the normal send path. #[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)] pub struct MessageScheduled { pub id: Uuid, pub channel_id: Uuid, pub author_id: Uuid, pub thread_id: Option, pub reply_to_message_id: Option, pub body: String, pub metadata: Option, /// When the message should be sent. pub scheduled_at: DateTime, /// "pending" | "sent" | "cancelled" | "failed" pub status: String, /// Set after the message is dispatched; points to the sent `message.id`. pub sent_message_id: Option, /// Error message if dispatch failed. pub error: Option, pub created_at: DateTime, pub updated_at: DateTime, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] #[serde(rename_all = "snake_case")] pub enum ScheduledStatus { #[default] Pending, Sent, Cancelled, Failed, } impl ScheduledStatus { pub fn as_str(&self) -> &'static str { match self { Self::Pending => "pending", Self::Sent => "sent", Self::Cancelled => "cancelled", Self::Failed => "failed", } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_scheduled_serialize() { let s = MessageScheduled { id: Uuid::now_v7(), channel_id: Uuid::now_v7(), author_id: Uuid::now_v7(), thread_id: None, reply_to_message_id: None, body: "Good morning everyone!".into(), metadata: None, scheduled_at: Utc::now(), status: ScheduledStatus::Pending.as_str().into(), sent_message_id: None, error: None, created_at: Utc::now(), updated_at: Utc::now(), }; let json = serde_json::to_value(&s).unwrap(); assert_eq!(json["status"], "pending"); } }