821537186e
- 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
78 lines
2.5 KiB
Rust
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());
|
|
}
|
|
}
|