Files
imks/models/message_notification.rs
zhenyi 821537186e refactor(tests): reformat code and update dependency management
- Reorganized import statements in adapter tests for better readability
- Replaced or_insert_with(Vec::new) with or_default() in test closures
- Updated Cargo.lock with new dependency versions and checksums
- Added TLS features to tonic dependency configuration
- Included sqlx, chrono, and uuid dependencies with specific features
- Added jsonwebtoken and arc-swap as project dependencies
- Reformatted assertion statements to comply with line length limits
- Adjusted base64 import order in engine codec module
- Updated protobuf include statement formatting
2026-06-11 12:11:05 +08:00

98 lines
2.8 KiB
Rust

//! Notification delivery tracking — maps to `message_notification` table.
//!
//! Records when a message triggers a notification for a user (mention, reply,
//! thread activity, etc.) and tracks the delivery/read lifecycle.
//! Separate from `message_mention` which only covers @mentions.
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
/// A notification triggered for a user by a message.
///
/// Maps to the `message_notification` table. Records when a message triggers
/// a notification (mention, reply, thread activity) and tracks delivery/read.
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
pub struct MessageNotification {
pub id: Uuid,
pub message_id: Uuid,
pub channel_id: Uuid,
pub user_id: Uuid,
/// "mention" | "reply" | "thread" | "watch"
pub reason: String,
/// "pending" | "delivered" | "read" | "dismissed"
pub status: String,
/// Channel of delivery: "push" | "email" | "in_app"
pub delivery_channel: Option<String>,
pub delivered_at: Option<DateTime<Utc>>,
pub read_at: Option<DateTime<Utc>>,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum NotificationReason {
#[default]
Mention,
Reply,
Thread,
Watch,
}
impl NotificationReason {
pub fn as_str(&self) -> &'static str {
match self {
Self::Mention => "mention",
Self::Reply => "reply",
Self::Thread => "thread",
Self::Watch => "watch",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum NotificationStatus {
#[default]
Pending,
Delivered,
Read,
Dismissed,
}
impl NotificationStatus {
pub fn as_str(&self) -> &'static str {
match self {
Self::Pending => "pending",
Self::Delivered => "delivered",
Self::Read => "read",
Self::Dismissed => "dismissed",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_notification_serialize() {
let n = MessageNotification {
id: Uuid::now_v7(),
message_id: Uuid::now_v7(),
channel_id: Uuid::now_v7(),
user_id: Uuid::now_v7(),
reason: NotificationReason::Mention.as_str().into(),
status: NotificationStatus::Pending.as_str().into(),
delivery_channel: Some("push".into()),
delivered_at: None,
read_at: None,
created_at: Utc::now(),
};
let json = serde_json::to_value(&n).unwrap();
assert_eq!(json["reason"], "mention");
assert_eq!(json["status"], "pending");
}
}