backend
This commit is contained in:
@@ -123,7 +123,6 @@ pub struct DocumentVersion {
|
|||||||
pub size_bytes: i64,
|
pub size_bytes: i64,
|
||||||
pub checksum: String,
|
pub checksum: String,
|
||||||
pub created_at: NaiveDateTime,
|
pub created_at: NaiveDateTime,
|
||||||
pub operations_summary: serde_json::Value,
|
|
||||||
pub metadata: serde_json::Value,
|
pub metadata: serde_json::Value,
|
||||||
pub tenant_id: Uuid,
|
pub tenant_id: Uuid,
|
||||||
}
|
}
|
||||||
@@ -137,7 +136,6 @@ pub struct NewDocumentVersion {
|
|||||||
pub s3_key: String,
|
pub s3_key: String,
|
||||||
pub size_bytes: i64,
|
pub size_bytes: i64,
|
||||||
pub checksum: String,
|
pub checksum: String,
|
||||||
pub operations_summary: serde_json::Value,
|
|
||||||
pub metadata: serde_json::Value,
|
pub metadata: serde_json::Value,
|
||||||
pub tenant_id: Uuid,
|
pub tenant_id: Uuid,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -658,8 +658,6 @@ pub mod schemas {
|
|||||||
pub created_at: String,
|
pub created_at: String,
|
||||||
pub metadata: Value,
|
pub metadata: Value,
|
||||||
#[schema(nullable)]
|
#[schema(nullable)]
|
||||||
pub operations_summary: Option<Value>,
|
|
||||||
#[schema(nullable)]
|
|
||||||
pub assets: Option<Vec<DocumentAssetSummary>>,
|
pub assets: Option<Vec<DocumentAssetSummary>>,
|
||||||
pub download_path: String,
|
pub download_path: String,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use uuid::Uuid;
|
|||||||
use super::folders::gather_descendant_folder_ids;
|
use super::folders::gather_descendant_folder_ids;
|
||||||
use crate::auth::TenantScopedConn;
|
use crate::auth::TenantScopedConn;
|
||||||
use crate::error::{AppError, AppResult};
|
use crate::error::{AppError, AppResult};
|
||||||
use crate::jobs::{enqueue_job, JOB_ANALYZE_DOCUMENT};
|
use crate::jobs::{enqueue_job, JOB_ANALYZE_DOCUMENT, JOB_INDEX_DOCUMENT_TEXT};
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
Correspondent, Document, DocumentAsset, DocumentAssetObject, DocumentCorrespondent,
|
Correspondent, Document, DocumentAsset, DocumentAssetObject, DocumentCorrespondent,
|
||||||
DocumentVersion, NewDocument, NewDocumentCorrespondent, NewDocumentTag, NewDocumentVersion,
|
DocumentVersion, NewDocument, NewDocumentCorrespondent, NewDocumentTag, NewDocumentVersion,
|
||||||
@@ -138,8 +138,6 @@ pub struct DocumentVersionResponse {
|
|||||||
pub checksum: String,
|
pub checksum: String,
|
||||||
pub created_at: String,
|
pub created_at: String,
|
||||||
pub metadata: Value,
|
pub metadata: Value,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub operations_summary: Option<Value>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Clone, ToSchema)]
|
#[derive(Serialize, Clone, ToSchema)]
|
||||||
@@ -749,7 +747,7 @@ pub async fn get_document(
|
|||||||
drop(conn);
|
drop(conn);
|
||||||
|
|
||||||
let assets = load_asset_responses(&state, tenant_id, version_id).await?;
|
let assets = load_asset_responses(&state, tenant_id, version_id).await?;
|
||||||
let version_response = to_version_response(current_version, true);
|
let version_response = to_version_response(current_version);
|
||||||
|
|
||||||
Ok(Json(DocumentDetailResponse {
|
Ok(Json(DocumentDetailResponse {
|
||||||
document: to_document_response(
|
document: to_document_response(
|
||||||
@@ -1303,6 +1301,7 @@ pub async fn update_document(
|
|||||||
|
|
||||||
let mut changes = DocumentUpdateChangeset::default();
|
let mut changes = DocumentUpdateChangeset::default();
|
||||||
let mut has_changes = false;
|
let mut has_changes = false;
|
||||||
|
let mut title_changed = false;
|
||||||
|
|
||||||
if let Some(ref candidate) = title {
|
if let Some(ref candidate) = title {
|
||||||
let trimmed = candidate.trim();
|
let trimmed = candidate.trim();
|
||||||
@@ -1317,6 +1316,7 @@ pub async fn update_document(
|
|||||||
changes.filename = Some(new_filename);
|
changes.filename = Some(new_filename);
|
||||||
}
|
}
|
||||||
has_changes = true;
|
has_changes = true;
|
||||||
|
title_changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1391,13 +1391,33 @@ pub async fn update_document(
|
|||||||
.find(document.current_version_id)
|
.find(document.current_version_id)
|
||||||
.first(&mut conn)?;
|
.first(&mut conn)?;
|
||||||
|
|
||||||
|
if title_changed {
|
||||||
|
if let Err(err) = enqueue_job(
|
||||||
|
&mut conn,
|
||||||
|
tenant_id,
|
||||||
|
JOB_INDEX_DOCUMENT_TEXT,
|
||||||
|
json!({
|
||||||
|
"document_id": document.id,
|
||||||
|
"document_version_id": current_version.id,
|
||||||
|
}),
|
||||||
|
None,
|
||||||
|
) {
|
||||||
|
warn!(
|
||||||
|
document_id = %document.id,
|
||||||
|
version_id = %current_version.id,
|
||||||
|
error = %err,
|
||||||
|
"failed to enqueue reindex job after title change"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let tags_map = load_tags_for_documents(&mut conn, &[document_id])?;
|
let tags_map = load_tags_for_documents(&mut conn, &[document_id])?;
|
||||||
let mut correspondents_map = load_correspondents_for_documents(&mut conn, &[document_id])?;
|
let mut correspondents_map = load_correspondents_for_documents(&mut conn, &[document_id])?;
|
||||||
let version_id = current_version.id;
|
let version_id = current_version.id;
|
||||||
drop(conn);
|
drop(conn);
|
||||||
|
|
||||||
let assets = load_asset_responses(&state, tenant_id, version_id).await?;
|
let assets = load_asset_responses(&state, tenant_id, version_id).await?;
|
||||||
let version_response = to_version_response(current_version, true);
|
let version_response = to_version_response(current_version);
|
||||||
|
|
||||||
Ok(Json(DocumentDetailResponse {
|
Ok(Json(DocumentDetailResponse {
|
||||||
document: to_document_response(
|
document: to_document_response(
|
||||||
@@ -2133,7 +2153,7 @@ async fn process_upload(
|
|||||||
let correspondents = correspondents_map.remove(&document.id).unwrap_or_default();
|
let correspondents = correspondents_map.remove(&document.id).unwrap_or_default();
|
||||||
drop(conn);
|
drop(conn);
|
||||||
let assets = load_asset_responses(state, tenant_id, version.id).await?;
|
let assets = load_asset_responses(state, tenant_id, version.id).await?;
|
||||||
let version_response = to_version_response(version.clone(), true);
|
let version_response = to_version_response(version.clone());
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
document_id = %document.id,
|
document_id = %document.id,
|
||||||
@@ -2204,7 +2224,6 @@ async fn process_upload(
|
|||||||
size_bytes,
|
size_bytes,
|
||||||
checksum: checksum_hex.clone(),
|
checksum: checksum_hex.clone(),
|
||||||
metadata: Value::Object(Default::default()),
|
metadata: Value::Object(Default::default()),
|
||||||
operations_summary: Value::Object(Default::default()),
|
|
||||||
tenant_id,
|
tenant_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2250,7 +2269,7 @@ async fn process_upload(
|
|||||||
document,
|
document,
|
||||||
tags,
|
tags,
|
||||||
correspondents,
|
correspondents,
|
||||||
Some((to_version_response(version.clone(), true), Vec::new())),
|
Some((to_version_response(version.clone()), Vec::new())),
|
||||||
)?,
|
)?,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -2538,7 +2557,7 @@ pub(crate) async fn load_primary_assets(
|
|||||||
for (doc_id, version_id) in doc_to_version {
|
for (doc_id, version_id) in doc_to_version {
|
||||||
if let Some(version) = version_map.remove(&version_id) {
|
if let Some(version) = version_map.remove(&version_id) {
|
||||||
let assets = assets_by_version.remove(&version_id).unwrap_or_default();
|
let assets = assets_by_version.remove(&version_id).unwrap_or_default();
|
||||||
result.insert(doc_id, (to_version_response(version, false), assets));
|
result.insert(doc_id, (to_version_response(version), assets));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,7 @@ pub fn build_download_path(
|
|||||||
.map_err(|err| AppError::internal(format!("failed to generate download token: {err}")))
|
.map_err(|err| AppError::internal(format!("failed to generate download token: {err}")))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_version_response(
|
pub fn to_version_response(version: DocumentVersion) -> DocumentVersionResponse {
|
||||||
version: DocumentVersion,
|
|
||||||
include_operations_summary: bool,
|
|
||||||
) -> DocumentVersionResponse {
|
|
||||||
DocumentVersionResponse {
|
DocumentVersionResponse {
|
||||||
id: version.id,
|
id: version.id,
|
||||||
version_number: version.version_number,
|
version_number: version.version_number,
|
||||||
@@ -36,11 +33,6 @@ pub fn to_version_response(
|
|||||||
checksum: version.checksum,
|
checksum: version.checksum,
|
||||||
created_at: to_iso(version.created_at),
|
created_at: to_iso(version.created_at),
|
||||||
metadata: version.metadata,
|
metadata: version.metadata,
|
||||||
operations_summary: if include_operations_summary {
|
|
||||||
Some(version.operations_summary)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ diesel::table! {
|
|||||||
#[max_length = 64]
|
#[max_length = 64]
|
||||||
checksum -> Varchar,
|
checksum -> Varchar,
|
||||||
created_at -> Timestamptz,
|
created_at -> Timestamptz,
|
||||||
operations_summary -> Jsonb,
|
|
||||||
metadata -> Jsonb,
|
metadata -> Jsonb,
|
||||||
tenant_id -> Uuid,
|
tenant_id -> Uuid,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::{collections::HashSet, sync::Arc, time::Duration};
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::{json, Map, Value};
|
use serde_json::json;
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
use tracing::{error, warn};
|
use tracing::{error, warn};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@@ -104,7 +104,7 @@ fn analyze_document(
|
|||||||
|
|
||||||
let tenant_id = document.tenant_id;
|
let tenant_id = document.tenant_id;
|
||||||
|
|
||||||
let (supported, reason) = determine_thumbnail_support(&document);
|
let (supported, _reason) = determine_thumbnail_support(&document);
|
||||||
let ocr_supported = document_is_pdf(&document);
|
let ocr_supported = document_is_pdf(&document);
|
||||||
|
|
||||||
let existing_ocr: Option<DocumentAsset> = document_assets::table
|
let existing_ocr: Option<DocumentAsset> = document_assets::table
|
||||||
@@ -117,32 +117,6 @@ fn analyze_document(
|
|||||||
|
|
||||||
let skip_ocr = existing_ocr.is_some() && !payload.force;
|
let skip_ocr = existing_ocr.is_some() && !payload.force;
|
||||||
|
|
||||||
let mut summary_map = match version.operations_summary {
|
|
||||||
Value::Object(map) => map,
|
|
||||||
_ => Map::new(),
|
|
||||||
};
|
|
||||||
summary_map.insert("thumbnail_supported".to_string(), Value::Bool(supported));
|
|
||||||
if let Some(reason) = reason {
|
|
||||||
summary_map.insert("thumbnail_reason".to_string(), Value::String(reason));
|
|
||||||
} else {
|
|
||||||
summary_map.remove("thumbnail_reason");
|
|
||||||
}
|
|
||||||
|
|
||||||
summary_map.insert("ocr_supported".to_string(), Value::Bool(ocr_supported));
|
|
||||||
if ocr_supported {
|
|
||||||
summary_map.remove("ocr_reason");
|
|
||||||
} else {
|
|
||||||
summary_map.insert(
|
|
||||||
"ocr_reason".to_string(),
|
|
||||||
Value::String("document is not a PDF".into()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
diesel::update(document_versions::table.find(version.id))
|
|
||||||
.set(document_versions::operations_summary.eq(Value::Object(summary_map)))
|
|
||||||
.execute(&mut conn)
|
|
||||||
.map_err(|err| format!("{err:?}"))?;
|
|
||||||
|
|
||||||
if supported {
|
if supported {
|
||||||
let enqueue_result = enqueue_job(
|
let enqueue_result = enqueue_job(
|
||||||
&mut conn,
|
&mut conn,
|
||||||
|
|||||||
Reference in New Issue
Block a user