proxy downloads
This commit is contained in:
@@ -20,10 +20,11 @@ use uuid::Uuid;
|
||||
|
||||
use crate::documents::{
|
||||
asset::{
|
||||
build_download_path, derive_document_title, filename_with_retained_extension,
|
||||
load_asset_responses_with_conn, load_primary_assets, to_asset_detail_response,
|
||||
to_asset_object_response, to_version_response, DocumentAssetDetailResponse,
|
||||
DocumentAssetResponse, DocumentVersionDetailResponse, DocumentVersionResponse,
|
||||
asset_object_disposition, build_download_path, derive_document_title,
|
||||
filename_with_retained_extension, load_asset_responses_with_conn, load_primary_assets,
|
||||
to_asset_detail_response, to_asset_object_response, to_version_response,
|
||||
DocumentAssetDetailResponse, DocumentAssetResponse, DocumentVersionDetailResponse,
|
||||
DocumentVersionResponse,
|
||||
},
|
||||
correspondents::{
|
||||
insert_document_correspondents, normalize_correspondent_ids, DocumentCorrespondentResponse,
|
||||
@@ -905,6 +906,7 @@ impl<'a> DocumentsService<'a> {
|
||||
&self,
|
||||
mut conn: PgPooledConnection,
|
||||
tenant_id: Uuid,
|
||||
user_id: Uuid,
|
||||
asset_id: Uuid,
|
||||
start: i32,
|
||||
limit: i32,
|
||||
@@ -945,25 +947,43 @@ impl<'a> DocumentsService<'a> {
|
||||
.checked_add((PRESIGNED_URL_EXPIRY_SECONDS as i64) * 1000)
|
||||
.ok_or_else(|| AppError::internal("failed to compute expiry timestamp"))?;
|
||||
|
||||
let storage = self.state.storage_for_tenant(tenant_id)?;
|
||||
let storage = (!self.state.config.proxy_downloads)
|
||||
.then(|| self.state.storage_for_tenant(tenant_id))
|
||||
.transpose()?;
|
||||
|
||||
let mut object_responses = Vec::with_capacity(objects.len());
|
||||
for object in objects {
|
||||
let response_disposition = presign_disposition_for_asset(&asset, &object);
|
||||
let response_disposition = asset_object_disposition(&asset, &object);
|
||||
|
||||
let url = storage
|
||||
.presign_get_object(
|
||||
&object.s3_key,
|
||||
Duration::from_secs(PRESIGNED_URL_EXPIRY_SECONDS),
|
||||
response_disposition.as_deref(),
|
||||
)
|
||||
.await
|
||||
.storage_context("failed to generate asset URL")?;
|
||||
let (url, object_expires_at) = if self.state.config.proxy_downloads {
|
||||
let token = self
|
||||
.state
|
||||
.jwt
|
||||
.generate_asset_download_token(asset.id, object.id, user_id, tenant_id)
|
||||
.map_err(|err| {
|
||||
error!(error = ?err, "failed to issue asset download token");
|
||||
AppError::internal("failed to issue asset download token")
|
||||
})?;
|
||||
(format!("/download/{token}"), None)
|
||||
} else {
|
||||
let storage = storage
|
||||
.as_ref()
|
||||
.expect("storage preloaded when proxy disabled");
|
||||
let url = storage
|
||||
.presign_get_object(
|
||||
&object.s3_key,
|
||||
Duration::from_secs(PRESIGNED_URL_EXPIRY_SECONDS),
|
||||
response_disposition.as_deref(),
|
||||
)
|
||||
.await
|
||||
.storage_context("failed to generate asset URL")?;
|
||||
(url, Some(expires_at))
|
||||
};
|
||||
|
||||
object_responses.push(to_asset_object_response(
|
||||
object,
|
||||
Some(url),
|
||||
Some(expires_at),
|
||||
object_expires_at,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1008,7 +1028,7 @@ impl<'a> DocumentsService<'a> {
|
||||
.first(conn)?;
|
||||
|
||||
let assets = load_asset_responses_with_conn(conn, tenant_id, version.id)?;
|
||||
let download_path = build_download_path(self.state, &document, user_id)?;
|
||||
let download_path = build_download_path(self.state, &document, version.id, user_id)?;
|
||||
let version_core = to_version_response(version);
|
||||
|
||||
Ok(DocumentVersionDetailResponse {
|
||||
@@ -1326,11 +1346,14 @@ impl<'a> DocumentsService<'a> {
|
||||
current_version: Option<(DocumentVersionResponse, Vec<DocumentAssetResponse>)>,
|
||||
) -> AppResult<DocumentResponse> {
|
||||
let current_version = match current_version {
|
||||
Some((version, assets)) => Some(DocumentVersionDetailResponse {
|
||||
version,
|
||||
assets,
|
||||
download_path: build_download_path(self.state, &doc, user_id)?,
|
||||
}),
|
||||
Some((version, assets)) => {
|
||||
let download_path = build_download_path(self.state, &doc, version.id, user_id)?;
|
||||
Some(DocumentVersionDetailResponse {
|
||||
version,
|
||||
assets,
|
||||
download_path,
|
||||
})
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
@@ -1466,11 +1489,3 @@ impl<'a> DocumentsService<'a> {
|
||||
Ok(Some(detail))
|
||||
}
|
||||
}
|
||||
|
||||
fn presign_disposition_for_asset(
|
||||
asset: &DocumentAsset,
|
||||
object: &DocumentAssetObject,
|
||||
) -> Option<String> {
|
||||
let filename = format!("{}-{}", asset.asset_type, object.ordinal);
|
||||
inline_content_disposition(&filename)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user