Files
Oxicloud/src/application/dtos/share_dto.rs
T
cjw 6ee26e46e6 feat(share): inline media preview on single-file share landing
The public share page only rendered media previews for FOLDER shares —
a single-file share got a bare icon + download button, even for images
and videos the browser can play natively.

Backend: resolve the shared file's mime_type + size at read time and
expose them on ShareDto (meta + password-verify endpoints, one shared
enrichment helper). Display-only enrichment: a failed file lookup
leaves the fields None instead of failing the response — the download
endpoint still surfaces the real error.

Frontend: the 'file' view now reuses the folder grid's lazyVideo
(poster-seek + retry) for video and imageRetry for images, with
Range-aware streaming already provided by /api/s/{token}/file/{id}.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-14 16:00:30 +08:00

66 lines
2.1 KiB
Rust

use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use crate::domain::entities::share::Share;
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ShareDto {
pub id: String,
pub item_id: String,
pub item_name: Option<String>,
pub item_type: String,
pub token: String,
pub url: String,
pub has_password: bool,
pub expires_at: Option<u64>,
pub created_at: u64,
pub created_by: String,
pub access_count: u64,
/// File shares only: the shared file's MIME type, resolved at read time
/// so anonymous viewers can render an inline media preview (video player
/// / image) instead of a bare download button. Absent for folder shares
/// and whenever the file lookup fails (display-only enrichment).
#[serde(skip_serializing_if = "Option::is_none")]
pub mime_type: Option<String>,
/// File shares only: the shared file's size in bytes (see `mime_type`).
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CreateShareDto {
pub item_id: String,
pub item_name: Option<String>,
pub item_type: String,
pub password: Option<String>,
pub expires_at: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct UpdateShareDto {
pub password: Option<String>,
pub expires_at: Option<u64>,
}
impl ShareDto {
pub fn from_entity(share: &Share, base_url: &str) -> Self {
let url = format!("{}/s/{}", base_url, share.token());
Self {
id: share.id().to_string(),
item_id: share.item_id().to_string(),
item_name: share.item_name().map(|s| s.to_string()),
item_type: share.item_type().to_string(),
token: share.token().to_string(),
url,
has_password: share.has_password(),
expires_at: share.expires_at(),
created_at: share.created_at(),
created_by: share.created_by().to_string(),
access_count: share.access_count(),
mime_type: None,
size: None,
}
}
}