feat(server): create specific endpoint for fetching documents, fix client being served again
This commit is contained in:
parent
f0f90d71de
commit
d7607923be
|
|
@ -1067,4 +1067,59 @@ impl Database {
|
||||||
|
|
||||||
Ok(facets)
|
Ok(facets)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_document_by_id(&self, document_id: Uuid, user_id: Uuid, user_role: crate::models::UserRole) -> Result<Option<Document>> {
|
||||||
|
let query = if user_role == crate::models::UserRole::Admin {
|
||||||
|
// Admins can see any document
|
||||||
|
r#"
|
||||||
|
SELECT id, filename, original_filename, file_path, file_size, mime_type, content, ocr_text, ocr_confidence, ocr_word_count, ocr_processing_time_ms, ocr_status, ocr_error, ocr_completed_at, tags, created_at, updated_at, user_id
|
||||||
|
FROM documents
|
||||||
|
WHERE id = $1
|
||||||
|
"#
|
||||||
|
} else {
|
||||||
|
// Regular users can only see their own documents
|
||||||
|
r#"
|
||||||
|
SELECT id, filename, original_filename, file_path, file_size, mime_type, content, ocr_text, ocr_confidence, ocr_word_count, ocr_processing_time_ms, ocr_status, ocr_error, ocr_completed_at, tags, created_at, updated_at, user_id
|
||||||
|
FROM documents
|
||||||
|
WHERE id = $1 AND user_id = $2
|
||||||
|
"#
|
||||||
|
};
|
||||||
|
|
||||||
|
let row = if user_role == crate::models::UserRole::Admin {
|
||||||
|
sqlx::query(query)
|
||||||
|
.bind(document_id)
|
||||||
|
.fetch_optional(&self.pool)
|
||||||
|
.await?
|
||||||
|
} else {
|
||||||
|
sqlx::query(query)
|
||||||
|
.bind(document_id)
|
||||||
|
.bind(user_id)
|
||||||
|
.fetch_optional(&self.pool)
|
||||||
|
.await?
|
||||||
|
};
|
||||||
|
|
||||||
|
match row {
|
||||||
|
Some(row) => Ok(Some(Document {
|
||||||
|
id: row.get("id"),
|
||||||
|
filename: row.get("filename"),
|
||||||
|
original_filename: row.get("original_filename"),
|
||||||
|
file_path: row.get("file_path"),
|
||||||
|
file_size: row.get("file_size"),
|
||||||
|
mime_type: row.get("mime_type"),
|
||||||
|
content: row.get("content"),
|
||||||
|
ocr_text: row.get("ocr_text"),
|
||||||
|
ocr_confidence: row.get("ocr_confidence"),
|
||||||
|
ocr_word_count: row.get("ocr_word_count"),
|
||||||
|
ocr_processing_time_ms: row.get("ocr_processing_time_ms"),
|
||||||
|
ocr_status: row.get("ocr_status"),
|
||||||
|
ocr_error: row.get("ocr_error"),
|
||||||
|
ocr_completed_at: row.get("ocr_completed_at"),
|
||||||
|
tags: row.get("tags"),
|
||||||
|
created_at: row.get("created_at"),
|
||||||
|
updated_at: row.get("updated_at"),
|
||||||
|
user_id: row.get("user_id"),
|
||||||
|
})),
|
||||||
|
None => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -283,7 +283,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
.nest("/api/webdav", readur::routes::webdav::router())
|
.nest("/api/webdav", readur::routes::webdav::router())
|
||||||
.merge(readur::swagger::create_swagger_router())
|
.merge(readur::swagger::create_swagger_router())
|
||||||
.fallback_service(
|
.fallback_service(
|
||||||
ServeDir::new("dist")
|
ServeDir::new("frontend/dist")
|
||||||
.precompressed_gzip()
|
.precompressed_gzip()
|
||||||
.precompressed_br()
|
.precompressed_br()
|
||||||
.fallback(ServeFile::new("dist/index.html"))
|
.fallback(ServeFile::new("dist/index.html"))
|
||||||
|
|
@ -295,7 +295,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let current_dir = std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("."));
|
let current_dir = std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("."));
|
||||||
info!("Server working directory: {}", current_dir.display());
|
info!("Server working directory: {}", current_dir.display());
|
||||||
|
|
||||||
let dist_path = current_dir.join("dist");
|
let dist_path = current_dir.join("frontend/dist");
|
||||||
info!("Looking for static files at: {}", dist_path.display());
|
info!("Looking for static files at: {}", dist_path.display());
|
||||||
info!("dist directory exists: {}", dist_path.exists());
|
info!("dist directory exists: {}", dist_path.exists());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,17 +60,12 @@ async fn get_document_by_id(
|
||||||
auth_user: AuthUser,
|
auth_user: AuthUser,
|
||||||
Path(document_id): Path<uuid::Uuid>,
|
Path(document_id): Path<uuid::Uuid>,
|
||||||
) -> Result<Json<DocumentResponse>, StatusCode> {
|
) -> Result<Json<DocumentResponse>, StatusCode> {
|
||||||
// Get documents for user with proper role-based access
|
// Get specific document with proper role-based access
|
||||||
let documents = state
|
let document = state
|
||||||
.db
|
.db
|
||||||
.get_documents_by_user_with_role(auth_user.user.id, auth_user.user.role, 1000, 0)
|
.get_document_by_id(document_id, auth_user.user.id, auth_user.user.role)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||||
|
|
||||||
// Find the specific document
|
|
||||||
let document = documents
|
|
||||||
.into_iter()
|
|
||||||
.find(|doc| doc.id == document_id)
|
|
||||||
.ok_or(StatusCode::NOT_FOUND)?;
|
.ok_or(StatusCode::NOT_FOUND)?;
|
||||||
|
|
||||||
// Convert to DocumentResponse
|
// Convert to DocumentResponse
|
||||||
|
|
@ -301,15 +296,11 @@ async fn download_document(
|
||||||
auth_user: AuthUser,
|
auth_user: AuthUser,
|
||||||
Path(document_id): Path<uuid::Uuid>,
|
Path(document_id): Path<uuid::Uuid>,
|
||||||
) -> Result<Vec<u8>, StatusCode> {
|
) -> Result<Vec<u8>, StatusCode> {
|
||||||
let documents = state
|
let document = state
|
||||||
.db
|
.db
|
||||||
.get_documents_by_user_with_role(auth_user.user.id, auth_user.user.role, 1000, 0)
|
.get_document_by_id(document_id, auth_user.user.id, auth_user.user.role)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||||
|
|
||||||
let document = documents
|
|
||||||
.into_iter()
|
|
||||||
.find(|doc| doc.id == document_id)
|
|
||||||
.ok_or(StatusCode::NOT_FOUND)?;
|
.ok_or(StatusCode::NOT_FOUND)?;
|
||||||
|
|
||||||
let file_service = FileService::new(state.config.upload_path.clone());
|
let file_service = FileService::new(state.config.upload_path.clone());
|
||||||
|
|
@ -342,15 +333,11 @@ async fn view_document(
|
||||||
auth_user: AuthUser,
|
auth_user: AuthUser,
|
||||||
Path(document_id): Path<uuid::Uuid>,
|
Path(document_id): Path<uuid::Uuid>,
|
||||||
) -> Result<Response, StatusCode> {
|
) -> Result<Response, StatusCode> {
|
||||||
let documents = state
|
let document = state
|
||||||
.db
|
.db
|
||||||
.get_documents_by_user_with_role(auth_user.user.id, auth_user.user.role, 1000, 0)
|
.get_document_by_id(document_id, auth_user.user.id, auth_user.user.role)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||||
|
|
||||||
let document = documents
|
|
||||||
.into_iter()
|
|
||||||
.find(|doc| doc.id == document_id)
|
|
||||||
.ok_or(StatusCode::NOT_FOUND)?;
|
.ok_or(StatusCode::NOT_FOUND)?;
|
||||||
|
|
||||||
let file_service = FileService::new(state.config.upload_path.clone());
|
let file_service = FileService::new(state.config.upload_path.clone());
|
||||||
|
|
@ -394,15 +381,11 @@ async fn get_document_thumbnail(
|
||||||
auth_user: AuthUser,
|
auth_user: AuthUser,
|
||||||
Path(document_id): Path<uuid::Uuid>,
|
Path(document_id): Path<uuid::Uuid>,
|
||||||
) -> Result<Response, StatusCode> {
|
) -> Result<Response, StatusCode> {
|
||||||
let documents = state
|
let document = state
|
||||||
.db
|
.db
|
||||||
.get_documents_by_user_with_role(auth_user.user.id, auth_user.user.role, 1000, 0)
|
.get_document_by_id(document_id, auth_user.user.id, auth_user.user.role)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||||
|
|
||||||
let document = documents
|
|
||||||
.into_iter()
|
|
||||||
.find(|doc| doc.id == document_id)
|
|
||||||
.ok_or(StatusCode::NOT_FOUND)?;
|
.ok_or(StatusCode::NOT_FOUND)?;
|
||||||
|
|
||||||
let file_service = FileService::new(state.config.upload_path.clone());
|
let file_service = FileService::new(state.config.upload_path.clone());
|
||||||
|
|
@ -447,15 +430,11 @@ async fn get_document_ocr(
|
||||||
auth_user: AuthUser,
|
auth_user: AuthUser,
|
||||||
Path(document_id): Path<uuid::Uuid>,
|
Path(document_id): Path<uuid::Uuid>,
|
||||||
) -> Result<Json<serde_json::Value>, StatusCode> {
|
) -> Result<Json<serde_json::Value>, StatusCode> {
|
||||||
let documents = state
|
let document = state
|
||||||
.db
|
.db
|
||||||
.get_documents_by_user_with_role(auth_user.user.id, auth_user.user.role, 1000, 0)
|
.get_document_by_id(document_id, auth_user.user.id, auth_user.user.role)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||||
|
|
||||||
let document = documents
|
|
||||||
.into_iter()
|
|
||||||
.find(|doc| doc.id == document_id)
|
|
||||||
.ok_or(StatusCode::NOT_FOUND)?;
|
.ok_or(StatusCode::NOT_FOUND)?;
|
||||||
|
|
||||||
// Return OCR text and metadata
|
// Return OCR text and metadata
|
||||||
|
|
@ -495,15 +474,11 @@ async fn get_processed_image(
|
||||||
Path(document_id): Path<uuid::Uuid>,
|
Path(document_id): Path<uuid::Uuid>,
|
||||||
) -> Result<Response, StatusCode> {
|
) -> Result<Response, StatusCode> {
|
||||||
// Check if document exists and belongs to user
|
// Check if document exists and belongs to user
|
||||||
let documents = state
|
let _document = state
|
||||||
.db
|
.db
|
||||||
.get_documents_by_user_with_role(auth_user.user.id, auth_user.user.role, 1000, 0)
|
.get_document_by_id(document_id, auth_user.user.id, auth_user.user.role)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||||
|
|
||||||
let _document = documents
|
|
||||||
.into_iter()
|
|
||||||
.find(|doc| doc.id == document_id)
|
|
||||||
.ok_or(StatusCode::NOT_FOUND)?;
|
.ok_or(StatusCode::NOT_FOUND)?;
|
||||||
|
|
||||||
// Get processed image record
|
// Get processed image record
|
||||||
|
|
@ -553,15 +528,11 @@ async fn retry_ocr(
|
||||||
Path(document_id): Path<uuid::Uuid>,
|
Path(document_id): Path<uuid::Uuid>,
|
||||||
) -> Result<Json<serde_json::Value>, StatusCode> {
|
) -> Result<Json<serde_json::Value>, StatusCode> {
|
||||||
// Check if document exists and belongs to user
|
// Check if document exists and belongs to user
|
||||||
let documents = state
|
let document = state
|
||||||
.db
|
.db
|
||||||
.get_documents_by_user_with_role(auth_user.user.id, auth_user.user.role, 1000, 0)
|
.get_document_by_id(document_id, auth_user.user.id, auth_user.user.role)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||||
|
|
||||||
let document = documents
|
|
||||||
.into_iter()
|
|
||||||
.find(|doc| doc.id == document_id)
|
|
||||||
.ok_or(StatusCode::NOT_FOUND)?;
|
.ok_or(StatusCode::NOT_FOUND)?;
|
||||||
|
|
||||||
// Check if document is eligible for OCR retry (failed or not processed)
|
// Check if document is eligible for OCR retry (failed or not processed)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue