Files
imks/models/message_draft.rs
T
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

78 lines
2.5 KiB
Rust

//! Message drafts — maps to `message_draft` table.
//!
//! Stores unsent messages so they survive browser refreshes and sync across
//! the user's connected devices. One draft per (channel, user, optional thread).
//! Drafts are upserted on every keystroke debounce and deleted on send.
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
/// A user's unsent message draft in a channel.
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
pub struct MessageDraft {
pub id: Uuid,
pub channel_id: Uuid,
pub user_id: Uuid,
/// Thread the draft belongs to (NULL = top-level).
pub thread_id: Option<Uuid>,
/// Message this draft is replying to (NULL = new message).
pub reply_to_message_id: Option<Uuid>,
/// Plain text or markdown body.
pub body: String,
/// Extensible metadata (attachments to be uploaded, etc.).
pub metadata: Option<serde_json::Value>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
/// Input for upserting a draft (sent from client on debounced keystroke).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DraftUpsertInput {
pub channel_id: Uuid,
pub thread_id: Option<Uuid>,
pub reply_to_message_id: Option<Uuid>,
pub body: String,
pub metadata: Option<serde_json::Value>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_draft_upsert_input_serialize() {
let input = DraftUpsertInput {
channel_id: Uuid::now_v7(),
thread_id: None,
reply_to_message_id: None,
body: "hello, this is a draft".to_string(),
metadata: None,
};
let json = serde_json::to_value(&input).unwrap();
assert_eq!(json["body"], "hello, this is a draft");
assert!(json["thread_id"].is_null());
}
#[test]
fn test_draft_serialize() {
let draft = MessageDraft {
id: Uuid::now_v7(),
channel_id: Uuid::now_v7(),
user_id: Uuid::now_v7(),
thread_id: Some(Uuid::now_v7()),
reply_to_message_id: None,
body: "draft body".to_string(),
metadata: Some(serde_json::json!({"pending_attachments": []})),
created_at: Utc::now(),
updated_at: Utc::now(),
};
let json = serde_json::to_value(&draft).unwrap();
assert_eq!(json["body"], "draft body");
assert!(json["thread_id"].is_string());
assert!(json["metadata"]["pending_attachments"].is_array());
}
}