feat(server): create specific endpoint for fetching documents, fix client being served again

This commit is contained in:
perf3ct 2025-06-17 04:05:57 +00:00
parent f0f90d71de
commit d7607923be
No known key found for this signature in database
GPG Key ID: 569C4EEC436F5232
3 changed files with 79 additions and 53 deletions

View File

@ -1067,4 +1067,59 @@ impl Database {
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),
}
}
}

View File

@ -283,7 +283,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.nest("/api/webdav", readur::routes::webdav::router())
.merge(readur::swagger::create_swagger_router())
.fallback_service(
ServeDir::new("dist")
ServeDir::new("frontend/dist")
.precompressed_gzip()
.precompressed_br()
.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("."));
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!("dist directory exists: {}", dist_path.exists());

View File

@ -60,17 +60,12 @@ async fn get_document_by_id(
auth_user: AuthUser,
Path(document_id): Path<uuid::Uuid>,
) -> Result<Json<DocumentResponse>, StatusCode> {
// Get documents for user with proper role-based access
let documents = state
// Get specific document with proper role-based access
let document = state
.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
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
// Find the specific document
let document = documents
.into_iter()
.find(|doc| doc.id == document_id)
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
.ok_or(StatusCode::NOT_FOUND)?;
// Convert to DocumentResponse
@ -301,15 +296,11 @@ async fn download_document(
auth_user: AuthUser,
Path(document_id): Path<uuid::Uuid>,
) -> Result<Vec<u8>, StatusCode> {
let documents = state
let document = state
.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
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let document = documents
.into_iter()
.find(|doc| doc.id == document_id)
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
.ok_or(StatusCode::NOT_FOUND)?;
let file_service = FileService::new(state.config.upload_path.clone());
@ -342,15 +333,11 @@ async fn view_document(
auth_user: AuthUser,
Path(document_id): Path<uuid::Uuid>,
) -> Result<Response, StatusCode> {
let documents = state
let document = state
.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
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let document = documents
.into_iter()
.find(|doc| doc.id == document_id)
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
.ok_or(StatusCode::NOT_FOUND)?;
let file_service = FileService::new(state.config.upload_path.clone());
@ -394,15 +381,11 @@ async fn get_document_thumbnail(
auth_user: AuthUser,
Path(document_id): Path<uuid::Uuid>,
) -> Result<Response, StatusCode> {
let documents = state
let document = state
.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
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let document = documents
.into_iter()
.find(|doc| doc.id == document_id)
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
.ok_or(StatusCode::NOT_FOUND)?;
let file_service = FileService::new(state.config.upload_path.clone());
@ -447,15 +430,11 @@ async fn get_document_ocr(
auth_user: AuthUser,
Path(document_id): Path<uuid::Uuid>,
) -> Result<Json<serde_json::Value>, StatusCode> {
let documents = state
let document = state
.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
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let document = documents
.into_iter()
.find(|doc| doc.id == document_id)
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
.ok_or(StatusCode::NOT_FOUND)?;
// Return OCR text and metadata
@ -495,15 +474,11 @@ async fn get_processed_image(
Path(document_id): Path<uuid::Uuid>,
) -> Result<Response, StatusCode> {
// Check if document exists and belongs to user
let documents = state
let _document = state
.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
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let _document = documents
.into_iter()
.find(|doc| doc.id == document_id)
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
.ok_or(StatusCode::NOT_FOUND)?;
// Get processed image record
@ -553,15 +528,11 @@ async fn retry_ocr(
Path(document_id): Path<uuid::Uuid>,
) -> Result<Json<serde_json::Value>, StatusCode> {
// Check if document exists and belongs to user
let documents = state
let document = state
.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
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let document = documents
.into_iter()
.find(|doc| doc.id == document_id)
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
.ok_or(StatusCode::NOT_FOUND)?;
// Check if document is eligible for OCR retry (failed or not processed)