use serde::{Deserialize, Serialize}; use crate::impl_get_id; use chrono::{DateTime, Utc}; /// MessageStatus represents the status of a message #[derive(Debug, Clone, Serialize, Deserialize)] pub enum MessageStatus { Sent, Delivered, Read, Failed, } /// MessageMeta contains metadata for a chat message #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MessageMeta { pub created_at: DateTime, pub updated_at: DateTime, pub status: MessageStatus, pub is_edited: bool, pub reactions: Vec, } /// Message represents a chat message #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Message { pub id: u32, // Unique identifier pub thread_id: String, // Thread/conversation identifier pub sender_id: String, // Sender identifier pub recipients: Vec, // List of recipient identifiers pub content: String, // Message content pub attachments: Vec, // References to attachments pub meta: MessageMeta, // Message metadata } impl Message { /// Create a new message pub fn new(id: u32, thread_id: String, sender_id: String, content: String) -> Self { let now = Utc::now(); Self { id, thread_id, sender_id, recipients: Vec::new(), content, attachments: Vec::new(), meta: MessageMeta { created_at: now, updated_at: now, status: MessageStatus::Sent, is_edited: false, reactions: Vec::new(), }, } } /// Add a recipient to this message pub fn add_recipient(&mut self, recipient: String) { self.recipients.push(recipient); } /// Add an attachment to this message pub fn add_attachment(&mut self, attachment: String) { self.attachments.push(attachment); } /// Add a group to this message pub fn add_group(&mut self, group_id: u32) { if !self.groups.contains(&group_id) { self.groups.push(group_id); } } /// Remove a group from this message pub fn remove_group(&mut self, group_id: u32) { self.groups.retain(|&id| id != group_id); } /// Filter by groups - returns true if this message belongs to any of the specified groups pub fn filter_by_groups(&self, groups: &[u32]) -> bool { groups.iter().any(|g| self.groups.contains(g)) } /// Search by content - returns true if the content contains the query (case-insensitive) pub fn search_by_content(&self, query: &str) -> bool { self.content.to_lowercase().contains(&query.to_lowercase()) } /// Update message status pub fn update_status(&mut self, status: MessageStatus) { self.meta.status = status; self.meta.updated_at = Utc::now(); } /// Edit message content pub fn edit_content(&mut self, new_content: String) { self.content = new_content; self.meta.is_edited = true; self.meta.updated_at = Utc::now(); } /// Add a reaction to the message pub fn add_reaction(&mut self, reaction: String) { self.meta.reactions.push(reaction); self.meta.updated_at = Utc::now(); } /// Filter messages that are in the same thread as this message pub fn filter_thread_messages<'a>(&self, messages: &'a [Message]) -> Vec<&'a Message> { messages.iter() .filter(|msg| msg.thread_id == self.thread_id) .collect() } /// Get the database prefix for this model type pub fn db_prefix() -> &'static str { "message" } } // Automatically implement GetId trait for Message impl_get_id!(Message);