DownloadLink
This commit is contained in:
@@ -17,9 +17,10 @@ use uuid::Uuid;
|
||||
|
||||
use crate::documents::{
|
||||
asset::{
|
||||
build_download_path, derive_document_title, filename_with_retained_extension,
|
||||
build_download_link, derive_document_title, filename_with_retained_extension,
|
||||
to_asset_detail_response, to_version_response, DocumentAssetDetailResponse,
|
||||
DocumentAssetResponse, DocumentVersionDetailResponse, DocumentVersionResponse,
|
||||
DownloadLink,
|
||||
},
|
||||
correspondents::{
|
||||
insert_document_correspondents, normalize_correspondent_ids, DocumentCorrespondentResponse,
|
||||
@@ -359,7 +360,8 @@ impl<'a> DocumentsService<'a> {
|
||||
.unwrap_or_else(|| (Vec::new(), Vec::new()));
|
||||
|
||||
let assets = self.load_asset_responses(conn, tenant_id, current_version.id, user_id)?;
|
||||
let current_version_data = Some((to_version_response(current_version), assets));
|
||||
let download = build_download_link(self.state, &doc, current_version.id, user_id)?;
|
||||
let current_version_data = Some((to_version_response(current_version), assets, download));
|
||||
|
||||
let response =
|
||||
self.to_document_response(user_id, doc, tags, correspondents, current_version_data)?;
|
||||
@@ -662,10 +664,12 @@ impl<'a> DocumentsService<'a> {
|
||||
let current_version = doc_to_version
|
||||
.get(&doc.id)
|
||||
.and_then(|version_id| version_map.remove(version_id))
|
||||
.map(|version| {
|
||||
.map(|version| -> AppResult<_> {
|
||||
let assets = assets_by_version.remove(&version.id).unwrap_or_default();
|
||||
(to_version_response(version), assets)
|
||||
});
|
||||
let download = build_download_link(self.state, &doc, version.id, user_id)?;
|
||||
Ok((to_version_response(version), assets, download))
|
||||
})
|
||||
.transpose()?;
|
||||
self.to_document_response(user_id, doc, tags, correspondents, current_version)
|
||||
})
|
||||
.collect()
|
||||
@@ -818,13 +822,15 @@ impl<'a> DocumentsService<'a> {
|
||||
.cloned()
|
||||
.unwrap_or_else(|| (Vec::new(), Vec::new()));
|
||||
|
||||
let download = build_download_link(self.state, &document, version.id, user_id)?;
|
||||
|
||||
DocumentDetailResponse {
|
||||
document: self.to_document_response(
|
||||
user_id,
|
||||
document,
|
||||
tags,
|
||||
correspondents,
|
||||
Some((to_version_response(version.clone()), Vec::new())),
|
||||
Some((to_version_response(version.clone()), Vec::new(), download)),
|
||||
)?,
|
||||
}
|
||||
};
|
||||
@@ -962,9 +968,69 @@ impl<'a> DocumentsService<'a> {
|
||||
|
||||
drop(conn);
|
||||
|
||||
let (url, expires_at) = self.asset_download_url(asset.id, tenant_id, user_id)?;
|
||||
let download = self.asset_download_link(asset.id, tenant_id, user_id)?;
|
||||
|
||||
Ok(to_asset_detail_response(asset, Some(url), Some(expires_at)))
|
||||
Ok(to_asset_detail_response(asset, Some(download)))
|
||||
}
|
||||
|
||||
pub async fn get_document_download_link(
|
||||
&self,
|
||||
conn: &mut PgPooledConnection,
|
||||
tenant_id: Uuid,
|
||||
user_id: Uuid,
|
||||
document_id: Uuid,
|
||||
) -> AppResult<DownloadLink> {
|
||||
let document = load_active_document(conn, tenant_id, document_id)?;
|
||||
let version: DocumentVersion = document_versions::table
|
||||
.find(document.current_version_id)
|
||||
.filter(document_versions::tenant_id.eq(tenant_id))
|
||||
.first(conn)?;
|
||||
|
||||
build_download_link(self.state, &document, version.id, user_id)
|
||||
}
|
||||
|
||||
pub async fn get_document_version_download_link(
|
||||
&self,
|
||||
conn: &mut PgPooledConnection,
|
||||
tenant_id: Uuid,
|
||||
user_id: Uuid,
|
||||
document_id: Uuid,
|
||||
version_id: Uuid,
|
||||
) -> AppResult<DownloadLink> {
|
||||
let document = load_active_document(conn, tenant_id, document_id)?;
|
||||
|
||||
let version: Option<DocumentVersion> = document_versions::table
|
||||
.find(version_id)
|
||||
.filter(document_versions::document_id.eq(document_id))
|
||||
.filter(document_versions::tenant_id.eq(tenant_id))
|
||||
.first(conn)
|
||||
.optional()?;
|
||||
|
||||
let Some(version) = version else {
|
||||
return Err(AppError::not_found());
|
||||
};
|
||||
|
||||
build_download_link(self.state, &document, version.id, user_id)
|
||||
}
|
||||
|
||||
pub async fn get_asset_download_link(
|
||||
&self,
|
||||
conn: &mut PgPooledConnection,
|
||||
tenant_id: Uuid,
|
||||
user_id: Uuid,
|
||||
asset_id: Uuid,
|
||||
) -> AppResult<DownloadLink> {
|
||||
let asset: Option<DocumentAsset> = document_assets::table
|
||||
.find(asset_id)
|
||||
.filter(document_assets::tenant_id.eq(tenant_id))
|
||||
.first(conn)
|
||||
.optional()?;
|
||||
|
||||
let Some(asset) = asset else {
|
||||
return Err(AppError::not_found());
|
||||
};
|
||||
|
||||
self.asset_download_link(asset.id, tenant_id, user_id)
|
||||
}
|
||||
|
||||
pub fn list_document_versions(
|
||||
@@ -1001,13 +1067,13 @@ impl<'a> DocumentsService<'a> {
|
||||
.first(conn)?;
|
||||
|
||||
let assets = self.load_asset_responses(conn, tenant_id, version.id, user_id)?;
|
||||
let download_path = build_download_path(self.state, &document, version.id, user_id)?;
|
||||
let download = build_download_link(self.state, &document, version.id, user_id)?;
|
||||
let version_core = to_version_response(version);
|
||||
|
||||
Ok(DocumentVersionDetailResponse {
|
||||
version: version_core,
|
||||
assets,
|
||||
download_path,
|
||||
download,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1157,6 +1223,7 @@ impl<'a> DocumentsService<'a> {
|
||||
let version_id = current_version.id;
|
||||
let assets = self.load_asset_responses(conn, tenant_id, version_id, user_id)?;
|
||||
let version_response = to_version_response(current_version);
|
||||
let download = build_download_link(self.state, &document, version_id, user_id)?;
|
||||
let (tags, correspondents) = tags_and_correspondents
|
||||
.get(&document_id)
|
||||
.cloned()
|
||||
@@ -1167,7 +1234,7 @@ impl<'a> DocumentsService<'a> {
|
||||
document,
|
||||
tags,
|
||||
correspondents,
|
||||
Some((version_response, assets)),
|
||||
Some((version_response, assets, download)),
|
||||
)?;
|
||||
|
||||
Ok(DocumentDetailResponse {
|
||||
@@ -1327,21 +1394,22 @@ impl<'a> DocumentsService<'a> {
|
||||
|
||||
fn to_document_response(
|
||||
&self,
|
||||
user_id: Uuid,
|
||||
_user_id: Uuid,
|
||||
doc: Document,
|
||||
tags: Vec<Tag>,
|
||||
correspondents: Vec<DocumentCorrespondentResponse>,
|
||||
current_version: Option<(DocumentVersionResponse, Vec<DocumentAssetResponse>)>,
|
||||
current_version: Option<(
|
||||
DocumentVersionResponse,
|
||||
Vec<DocumentAssetResponse>,
|
||||
DownloadLink,
|
||||
)>,
|
||||
) -> AppResult<DocumentResponse> {
|
||||
let current_version = match current_version {
|
||||
Some((version, assets)) => {
|
||||
let download_path = build_download_path(self.state, &doc, version.id, user_id)?;
|
||||
Some(DocumentVersionDetailResponse {
|
||||
version,
|
||||
assets,
|
||||
download_path,
|
||||
})
|
||||
}
|
||||
Some((version, assets, download)) => Some(DocumentVersionDetailResponse {
|
||||
version,
|
||||
assets,
|
||||
download,
|
||||
}),
|
||||
None => None,
|
||||
};
|
||||
|
||||
@@ -1469,6 +1537,7 @@ impl<'a> DocumentsService<'a> {
|
||||
.unwrap_or_else(|| (Vec::new(), Vec::new()));
|
||||
|
||||
let assets = self.load_asset_responses(conn, tenant_id, version.id, user_id)?;
|
||||
let download = build_download_link(self.state, &document, version.id, user_id)?;
|
||||
let version_response = to_version_response(version.clone());
|
||||
|
||||
info!(
|
||||
@@ -1483,19 +1552,19 @@ impl<'a> DocumentsService<'a> {
|
||||
document,
|
||||
tags,
|
||||
correspondents_list,
|
||||
Some((version_response, assets)),
|
||||
Some((version_response, assets, download)),
|
||||
)?,
|
||||
};
|
||||
|
||||
Ok(Some(detail))
|
||||
}
|
||||
|
||||
fn asset_download_url(
|
||||
fn asset_download_link(
|
||||
&self,
|
||||
asset_id: Uuid,
|
||||
tenant_id: Uuid,
|
||||
user_id: Uuid,
|
||||
) -> AppResult<(String, i64)> {
|
||||
) -> AppResult<DownloadLink> {
|
||||
let token = self
|
||||
.state
|
||||
.jwt
|
||||
@@ -1512,7 +1581,10 @@ impl<'a> DocumentsService<'a> {
|
||||
.ok_or_else(|| AppError::internal("failed to compute download expiry"))?
|
||||
.timestamp_millis();
|
||||
|
||||
Ok((format!("/api/download/{token}"), expires_at))
|
||||
Ok(DownloadLink {
|
||||
url: format!("/api/download/{token}"),
|
||||
expires_at,
|
||||
})
|
||||
}
|
||||
|
||||
fn asset_response(
|
||||
@@ -1521,15 +1593,14 @@ impl<'a> DocumentsService<'a> {
|
||||
tenant_id: Uuid,
|
||||
user_id: Uuid,
|
||||
) -> AppResult<DocumentAssetResponse> {
|
||||
let (url, expires_at) = self.asset_download_url(asset.id, tenant_id, user_id)?;
|
||||
let download = self.asset_download_link(asset.id, tenant_id, user_id)?;
|
||||
|
||||
Ok(DocumentAssetResponse {
|
||||
id: asset.id,
|
||||
asset_type: asset.asset_type,
|
||||
mime_type: asset.mime_type,
|
||||
metadata: asset.metadata,
|
||||
url: Some(url),
|
||||
expires_at: Some(expires_at),
|
||||
download: Some(download),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user