This commit is contained in:
2025-11-06 12:26:29 +01:00
parent 4027ac66cb
commit a6f79dbc75
12 changed files with 344 additions and 199 deletions
+41 -40
View File
@@ -33,6 +33,7 @@ use crate::documents::{
tags::{assign_tags as assign_tags_to_document, load_tags_for_documents},
};
use crate::error::{AppError, AppResult};
use crate::http::responders::{accepted_json, created_json, no_content, ok_json, JsonResponse};
use crate::jobs::{
enqueue_job, JobQueueError, JOB_ANALYZE_DOCUMENT, JOB_INDEX_DOCUMENT_TEXT, JOB_PURGE_DOCUMENT,
};
@@ -46,7 +47,7 @@ use crate::schema::{
};
use crate::state::AppState;
use crate::utils::{
db::{no_content, validate_bulk_ids, IntoJsonResponse},
db::validate_bulk_ids,
error::StorageResultExt,
http::inline_content_disposition,
json::{classify_nullable, NullableValue},
@@ -372,7 +373,7 @@ pub async fn list_documents(
user_id,
..
}: TenantScopedConn,
) -> AppResult<Json<Vec<DocumentResponse>>> {
) -> AppResult<JsonResponse<Vec<DocumentResponse>>> {
let DocumentListQuery {
folder_id,
include_descendants,
@@ -455,7 +456,7 @@ pub async fn list_documents(
})?;
if ids.is_empty() {
return Ok(Json(vec![]));
return ok_json(Vec::<DocumentResponse>::new());
}
quickwit_order = Some(ids.clone());
@@ -480,7 +481,7 @@ pub async fn list_documents(
let docs_set: HashSet<Uuid> = docs_without_tags.into_iter().collect();
if docs_set.is_empty() {
return Ok(Json(vec![]));
return ok_json(Vec::<DocumentResponse>::new());
}
let new_filter = match &filter_ids {
@@ -519,7 +520,7 @@ pub async fn list_documents(
let matching_doc_ids: HashSet<Uuid> = doc_id_set.unwrap_or_default();
if matching_doc_ids.is_empty() {
return Ok(Json(vec![]));
return ok_json(Vec::<DocumentResponse>::new());
}
let new_filter = match &filter_ids {
@@ -566,7 +567,7 @@ pub async fn list_documents(
let matching_doc_ids: HashSet<Uuid> = doc_id_set.unwrap_or_default();
if matching_doc_ids.is_empty() {
return Ok(Json(vec![]));
return ok_json(Vec::<DocumentResponse>::new());
}
let new_filter = match &filter_ids {
@@ -581,7 +582,7 @@ pub async fn list_documents(
if let Some(ref set) = filter_ids {
if set.is_empty() {
return Ok(Json(vec![]));
return ok_json(Vec::<DocumentResponse>::new());
}
let ids_vec: Vec<Uuid> = set.iter().copied().collect();
@@ -606,7 +607,7 @@ pub async fn list_documents(
};
if relevant_ids.is_empty() {
return Ok(Json(vec![]));
return ok_json(Vec::<DocumentResponse>::new());
}
let mut fetched: Vec<Document> = docs_query.load(&mut conn)?;
@@ -631,7 +632,7 @@ pub async fn list_documents(
let response = hydrate_documents(&state, &mut conn, tenant_id, user_id, docs)?;
Ok(Json(response))
ok_json(response)
}
#[utoipa::path(
@@ -648,7 +649,7 @@ pub async fn check_document(
tenant_id,
..
}: TenantScopedConn,
) -> AppResult<Json<DocumentCheckResponse>> {
) -> AppResult<JsonResponse<DocumentCheckResponse>> {
let checksum_raw = query.checksum.trim();
if checksum_raw.is_empty() {
return Err(AppError::bad_request("checksum must not be empty"));
@@ -672,7 +673,7 @@ pub async fn check_document(
.optional()?;
if let Some((document, version)) = record {
Ok(Json(DocumentCheckResponse {
ok_json(DocumentCheckResponse {
exists: true,
document_id: Some(document.id),
title: Some(document.title.clone()),
@@ -680,9 +681,9 @@ pub async fn check_document(
version_id: Some(version.id),
version_number: Some(version.version_number),
created_at: Some(to_iso(document.created_at)),
}))
})
} else {
Ok(Json(DocumentCheckResponse {
ok_json(DocumentCheckResponse {
exists: false,
document_id: None,
title: None,
@@ -690,7 +691,7 @@ pub async fn check_document(
version_id: None,
version_number: None,
created_at: None,
}))
})
}
}
@@ -710,7 +711,7 @@ pub async fn get_document(
user_id,
..
}: TenantScopedConn,
) -> AppResult<Json<DocumentDetailResponse>> {
) -> AppResult<JsonResponse<DocumentDetailResponse>> {
let doc: Document = documents::table
.find(document_id)
.filter(documents::tenant_id.eq(tenant_id))
@@ -731,7 +732,7 @@ pub async fn get_document(
let assets = load_asset_responses(&state, tenant_id, version_id).await?;
let version_response = to_version_response(current_version);
Ok(Json(DocumentDetailResponse {
ok_json(DocumentDetailResponse {
document: to_document_response(
&state,
user_id,
@@ -740,7 +741,7 @@ pub async fn get_document(
correspondents_map.remove(&document_id).unwrap_or_default(),
Some((version_response, assets)),
)?,
}))
})
}
#[utoipa::path(
@@ -760,7 +761,7 @@ pub async fn upload_document(
tenant_id, user_id, ..
}: TenantScopedConn,
mut multipart: Multipart,
) -> AppResult<impl IntoResponse> {
) -> AppResult<JsonResponse<DocumentDetailResponse>> {
let mut file_bytes: Option<Vec<u8>> = None;
let mut original_name: Option<String> = None;
let mut content_type: Option<String> = None;
@@ -938,7 +939,7 @@ pub async fn upload_document(
reused_existing = false,
"document upload succeeded",
);
(StatusCode::CREATED, Json(detail)).into_response()
created_json(detail)?
}
UploadOutcome::Reused(detail) => {
info!(
@@ -948,7 +949,7 @@ pub async fn upload_document(
reused_existing = true,
"document upload succeeded",
);
(StatusCode::OK, Json(detail)).into_response()
ok_json(detail)?
}
};
@@ -1012,7 +1013,7 @@ pub async fn reanalyze_selected_documents(
..
}: TenantScopedConn,
Json(payload): Json<BulkReanalyzeSelectionRequest>,
) -> AppResult<(StatusCode, Json<BulkReanalyzeResponse>)> {
) -> AppResult<JsonResponse<BulkReanalyzeResponse>> {
let BulkReanalyzeSelectionRequest {
mut document_ids,
force,
@@ -1053,7 +1054,7 @@ pub async fn reanalyze_selected_documents(
queued += 1;
}
Ok((StatusCode::ACCEPTED, Json(BulkReanalyzeResponse { queued })))
accepted_json(BulkReanalyzeResponse { queued })
}
#[utoipa::path(
@@ -1071,7 +1072,7 @@ pub async fn list_document_assets(
tenant_id,
..
}: TenantScopedConn,
) -> AppResult<Json<Vec<DocumentAssetResponse>>> {
) -> AppResult<JsonResponse<Vec<DocumentAssetResponse>>> {
let document: Document = documents::table
.find(document_id)
.filter(documents::tenant_id.eq(tenant_id))
@@ -1084,7 +1085,7 @@ pub async fn list_document_assets(
drop(conn);
let assets = load_asset_responses(&state, tenant_id, version_id).await?;
Ok(Json(assets))
ok_json(assets)
}
#[utoipa::path(
@@ -1103,7 +1104,7 @@ pub async fn get_document_asset(
tenant_id,
..
}: TenantScopedConn,
) -> AppResult<Json<DocumentAssetDetailResponse>> {
) -> AppResult<JsonResponse<DocumentAssetDetailResponse>> {
let asset: DocumentAsset = match document_assets::table
.find(asset_id)
.filter(document_assets::tenant_id.eq(tenant_id))
@@ -1168,7 +1169,7 @@ pub async fn get_document_asset(
return Err(AppError::not_found());
}
Ok(Json(to_asset_detail_response(asset, object_responses)))
ok_json(to_asset_detail_response(asset, object_responses))
}
fn presign_disposition_for_asset(
@@ -1193,7 +1194,7 @@ pub async fn list_document_versions(
tenant_id,
..
}: TenantScopedConn,
) -> AppResult<Json<Vec<DocumentVersionResponse>>> {
) -> AppResult<JsonResponse<Vec<DocumentVersionResponse>>> {
let document: Document = documents::table
.find(document_id)
.filter(documents::tenant_id.eq(tenant_id))
@@ -1212,7 +1213,7 @@ pub async fn list_document_versions(
let versions: Vec<DocumentVersionResponse> =
versions.into_iter().map(to_version_response).collect();
Ok(Json(versions))
ok_json(versions)
}
#[utoipa::path(
@@ -1234,7 +1235,7 @@ pub async fn get_document_version(
user_id,
..
}: TenantScopedConn,
) -> AppResult<Json<DocumentVersionDetailResponse>> {
) -> AppResult<JsonResponse<DocumentVersionDetailResponse>> {
let document: Document = documents::table
.find(document_id)
.filter(documents::tenant_id.eq(tenant_id))
@@ -1256,11 +1257,11 @@ pub async fn get_document_version(
let download_path = build_download_path(&state, &document, user_id)?;
let version_core = to_version_response(version);
Ok(Json(DocumentVersionDetailResponse {
ok_json(DocumentVersionDetailResponse {
version: version_core,
assets,
download_path,
}))
})
}
#[utoipa::path(
@@ -1416,7 +1417,7 @@ pub async fn update_document(
..
}: TenantScopedConn,
Json(payload): Json<Value>,
) -> AppResult<Json<DocumentDetailResponse>> {
) -> AppResult<JsonResponse<DocumentDetailResponse>> {
let mut document: Document = documents::table
.find(document_id)
.filter(documents::tenant_id.eq(tenant_id))
@@ -1566,7 +1567,7 @@ pub async fn update_document(
let assets = load_asset_responses(&state, tenant_id, version_id).await?;
let version_response = to_version_response(current_version);
Ok(Json(DocumentDetailResponse {
ok_json(DocumentDetailResponse {
document: to_document_response(
&state,
user_id,
@@ -1575,7 +1576,7 @@ pub async fn update_document(
correspondents_map.remove(&document_id).unwrap_or_default(),
Some((version_response, assets)),
)?,
}))
})
}
#[utoipa::path(
@@ -1686,7 +1687,7 @@ pub async fn bulk_move_documents(
..
}: TenantScopedConn,
Json(payload): Json<BulkMoveRequest>,
) -> AppResult<(StatusCode, Json<BulkMoveResponse>)> {
) -> AppResult<JsonResponse<BulkMoveResponse>> {
let BulkMoveRequest {
mut document_ids,
folder_id,
@@ -1759,7 +1760,7 @@ pub async fn bulk_move_documents(
};
let body = BulkMoveResponse { updated };
Ok((StatusCode::OK, body.into_json()?))
ok_json(body)
}
#[utoipa::path(
@@ -1866,7 +1867,7 @@ pub async fn bulk_assign_correspondents(
..
}: TenantScopedConn,
Json(payload): Json<BulkCorrespondentsRequest>,
) -> AppResult<(StatusCode, Json<BulkCorrespondentResponse>)> {
) -> AppResult<JsonResponse<BulkCorrespondentResponse>> {
if payload.assignments.is_empty() {
return Err(AppError::bad_request("assignments must not be empty"));
}
@@ -1947,7 +1948,7 @@ pub async fn bulk_assign_correspondents(
})?;
let body = BulkCorrespondentResponse { assigned, removed };
Ok((StatusCode::OK, body.into_json()?))
ok_json(body)
}
#[utoipa::path(
@@ -2052,7 +2053,7 @@ pub async fn bulk_update_tags(
..
}: TenantScopedConn,
Json(payload): Json<BulkTagRequest>,
) -> AppResult<(StatusCode, Json<BulkTagResponse>)> {
) -> AppResult<JsonResponse<BulkTagResponse>> {
let BulkTagRequest {
mut document_ids,
mut tag_ids,
@@ -2126,7 +2127,7 @@ pub async fn bulk_update_tags(
}
};
Ok((StatusCode::OK, response.into_json()?))
ok_json(response)
}
#[utoipa::path(