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
97 lines
2.9 KiB
Rust
97 lines
2.9 KiB
Rust
//! File / image attachment on a message — new table `message_attachment`.
|
|
//!
|
|
//! Discord-style: each message can have multiple attachments. Files are
|
|
//! uploaded to S3 first, then the URL is stored here.
|
|
|
|
use chrono::{DateTime, Utc};
|
|
use serde::{Deserialize, Serialize};
|
|
use uuid::Uuid;
|
|
|
|
/// A file or image attachment on a message.
|
|
///
|
|
/// Maps to the `message_attachment` table. Files are uploaded to object
|
|
/// storage first, then the URL is stored here.
|
|
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
|
|
pub struct MessageAttachment {
|
|
pub id: Uuid,
|
|
pub message_id: Uuid,
|
|
/// Original filename as uploaded by the user.
|
|
pub filename: String,
|
|
/// MIME type: "image/png", "application/pdf", etc.
|
|
pub content_type: Option<String>,
|
|
/// File size in bytes.
|
|
pub size: i64,
|
|
/// Public URL (S3 presigned or CDN).
|
|
pub url: String,
|
|
/// S3 / object-store key for backend access.
|
|
pub storage_key: Option<String>,
|
|
/// Image / video width in pixels.
|
|
pub width: Option<i32>,
|
|
/// Image / video height in pixels.
|
|
pub height: Option<i32>,
|
|
/// Audio / video duration in seconds.
|
|
pub duration_secs: Option<f64>,
|
|
/// Blurred low-res preview for progressive loading (base64 data URI).
|
|
pub blurhash: Option<String>,
|
|
/// Whether this attachment should be rendered as a spoiler (hidden until click).
|
|
pub spoiler: bool,
|
|
pub created_at: DateTime<Utc>,
|
|
}
|
|
|
|
/// Lightweight attachment summary for list views.
|
|
///
|
|
/// Omits URL and storage_key to reduce payload size.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct AttachmentSummary {
|
|
pub id: Uuid,
|
|
pub filename: String,
|
|
pub content_type: Option<String>,
|
|
pub size: i64,
|
|
pub width: Option<i32>,
|
|
pub height: Option<i32>,
|
|
pub spoiler: bool,
|
|
}
|
|
|
|
impl From<MessageAttachment> for AttachmentSummary {
|
|
fn from(a: MessageAttachment) -> Self {
|
|
Self {
|
|
id: a.id,
|
|
filename: a.filename,
|
|
content_type: a.content_type,
|
|
size: a.size,
|
|
width: a.width,
|
|
height: a.height,
|
|
spoiler: a.spoiler,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_attachment_conversion() {
|
|
let att = MessageAttachment {
|
|
id: Uuid::now_v7(),
|
|
message_id: Uuid::now_v7(),
|
|
filename: "photo.png".into(),
|
|
content_type: Some("image/png".into()),
|
|
size: 1024,
|
|
url: "https://cdn.example.com/photo.png".into(),
|
|
storage_key: None,
|
|
width: Some(800),
|
|
height: Some(600),
|
|
duration_secs: None,
|
|
blurhash: None,
|
|
spoiler: false,
|
|
created_at: Utc::now(),
|
|
};
|
|
|
|
let summary: AttachmentSummary = att.into();
|
|
assert_eq!(summary.filename, "photo.png");
|
|
assert_eq!(summary.size, 1024);
|
|
assert_eq!(summary.width, Some(800));
|
|
}
|
|
}
|