diff --git a/src/models.rs b/src/models.rs index 2015379..91e999d 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1023,4 +1023,102 @@ impl From for IgnoredFileResponse { created_at: ignored_file.created_at, } } +} + +// Additional response schemas for better API documentation + +#[derive(Debug, Serialize, Deserialize, ToSchema)] +pub struct DocumentListResponse { + /// List of documents + pub documents: Vec, + /// Total number of documents (without pagination) + pub total: i64, + /// Number of documents returned in this response + pub count: i64, + /// Pagination offset used + pub offset: i64, + /// Pagination limit used + pub limit: i64, +} + +#[derive(Debug, Serialize, Deserialize, ToSchema)] +pub struct DocumentOcrResponse { + /// Document ID + pub document_id: Uuid, + /// Original filename + pub filename: String, + /// Whether the document has OCR text available + pub has_ocr_text: bool, + /// OCR text content (if available) + pub ocr_text: Option, + /// OCR processing confidence score (0-100) + pub ocr_confidence: Option, + /// Current OCR processing status + pub ocr_status: Option, + /// Time taken for OCR processing in milliseconds + pub ocr_processing_time_ms: Option, + /// Language detected in the document + pub detected_language: Option, + /// Number of pages processed (for multi-page documents) + pub pages_processed: Option, +} + +#[derive(Debug, Serialize, Deserialize, ToSchema)] +pub struct DocumentOperationResponse { + /// Whether the operation was successful + pub success: bool, + /// Human-readable message describing the result + pub message: String, + /// Document ID(s) affected by the operation + pub document_ids: Vec, + /// Number of documents processed + pub count: i64, + /// Any warnings or additional information + pub warnings: Vec, +} + +#[derive(Debug, Serialize, Deserialize, ToSchema)] +pub struct BulkDeleteResponse { + /// Whether the operation was successful + pub success: bool, + /// Number of documents successfully deleted + pub deleted_count: i64, + /// Number of documents that failed to delete + pub failed_count: i64, + /// List of document IDs that were successfully deleted + pub deleted_documents: Vec, + /// List of document IDs that failed to delete + pub failed_documents: Vec, + /// Number of files successfully deleted from storage + pub files_deleted: i64, + /// Number of files that failed to delete from storage + pub files_failed: i64, + /// Any warnings or additional information + pub warnings: Vec, +} + +#[derive(Debug, Serialize, Deserialize, ToSchema)] +pub struct PaginationInfo { + /// Total number of items available + pub total: i64, + /// Number of items returned in current response + pub count: i64, + /// Current offset + pub offset: i64, + /// Current limit + pub limit: i64, + /// Whether there are more items available + pub has_more: bool, +} + +#[derive(Debug, Serialize, Deserialize, ToSchema)] +pub struct DocumentDuplicatesResponse { + /// List of document groups that are duplicates of each other + pub duplicate_groups: Vec>, + /// Total number of duplicate documents found + pub total_duplicates: i64, + /// Number of duplicate groups + pub group_count: i64, + /// Pagination information + pub pagination: PaginationInfo, } \ No newline at end of file diff --git a/src/routes/auth.rs b/src/routes/auth.rs index a485efb..c41a746 100644 --- a/src/routes/auth.rs +++ b/src/routes/auth.rs @@ -27,7 +27,8 @@ pub fn router() -> Router> { request_body = CreateUser, responses( (status = 200, description = "User registered successfully", body = UserResponse), - (status = 400, description = "Bad request - invalid user data") + (status = 400, description = "Bad request - username/email already exists or invalid data"), + (status = 500, description = "Internal server error") ) )] async fn register( @@ -71,7 +72,8 @@ async fn register( request_body = LoginRequest, responses( (status = 200, description = "Login successful", body = LoginResponse), - (status = 401, description = "Unauthorized - invalid credentials") + (status = 401, description = "Unauthorized - invalid credentials"), + (status = 500, description = "Internal server error") ) )] async fn login( @@ -110,7 +112,8 @@ async fn login( ), responses( (status = 200, description = "Current user information", body = UserResponse), - (status = 401, description = "Unauthorized - invalid or missing token") + (status = 401, description = "Unauthorized - invalid or missing token"), + (status = 500, description = "Internal server error") ) )] async fn me(auth_user: AuthUser) -> Json { diff --git a/src/routes/ignored_files.rs b/src/routes/ignored_files.rs index abb04e2..e3ac73e 100644 --- a/src/routes/ignored_files.rs +++ b/src/routes/ignored_files.rs @@ -83,7 +83,8 @@ pub fn ignored_files_routes() -> Router> { params(IgnoredFilesQuery), responses( (status = 200, description = "List of ignored files", body = Vec), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] pub async fn list_ignored_files( @@ -133,8 +134,9 @@ pub async fn list_ignored_files( ), responses( (status = 200, description = "Ignored file details", body = IgnoredFileResponse), + (status = 401, description = "Unauthorized"), (status = 404, description = "Ignored file not found"), - (status = 401, description = "Unauthorized") + (status = 500, description = "Internal server error") ) )] pub async fn get_ignored_file( @@ -169,8 +171,9 @@ pub async fn get_ignored_file( ), responses( (status = 200, description = "Ignored file deleted successfully"), + (status = 401, description = "Unauthorized"), (status = 404, description = "Ignored file not found"), - (status = 401, description = "Unauthorized") + (status = 500, description = "Internal server error") ) )] pub async fn delete_ignored_file( @@ -211,7 +214,8 @@ pub async fn delete_ignored_file( responses( (status = 200, description = "Ignored files deleted successfully"), (status = 400, description = "Bad request - no ignored file IDs provided"), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] pub async fn bulk_delete_ignored_files( @@ -262,7 +266,8 @@ pub async fn bulk_delete_ignored_files( ), responses( (status = 200, description = "Ignored files statistics", body = IgnoredFilesStats), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] pub async fn get_ignored_files_stats( diff --git a/src/routes/metrics.rs b/src/routes/metrics.rs index fa1916d..feb37ed 100644 --- a/src/routes/metrics.rs +++ b/src/routes/metrics.rs @@ -86,6 +86,7 @@ pub fn router() -> Router> { responses( (status = 200, description = "System metrics and monitoring data", body = SystemMetrics), (status = 401, description = "Unauthorized - valid authentication required"), + (status = 403, description = "Forbidden - Admin access required"), (status = 500, description = "Internal server error") ) )] diff --git a/src/routes/notifications.rs b/src/routes/notifications.rs index 4e6efbf..a41a055 100644 --- a/src/routes/notifications.rs +++ b/src/routes/notifications.rs @@ -42,7 +42,8 @@ pub fn router() -> Router> { ), responses( (status = 200, description = "List of user notifications", body = Vec), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] async fn get_notifications( @@ -71,7 +72,8 @@ async fn get_notifications( ), responses( (status = 200, description = "Notification summary with unread count and recent notifications", body = NotificationSummary), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] async fn get_notification_summary( @@ -99,8 +101,9 @@ async fn get_notification_summary( ), responses( (status = 200, description = "Notification marked as read"), + (status = 401, description = "Unauthorized"), (status = 404, description = "Notification not found"), - (status = 401, description = "Unauthorized") + (status = 500, description = "Internal server error") ) )] async fn mark_notification_read( @@ -126,7 +129,8 @@ async fn mark_notification_read( ), responses( (status = 200, description = "All notifications marked as read"), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] async fn mark_all_notifications_read( @@ -154,8 +158,9 @@ async fn mark_all_notifications_read( ), responses( (status = 200, description = "Notification deleted"), + (status = 401, description = "Unauthorized"), (status = 404, description = "Notification not found"), - (status = 401, description = "Unauthorized") + (status = 500, description = "Internal server error") ) )] async fn delete_notification( diff --git a/src/routes/queue.rs b/src/routes/queue.rs index 3298cba..79fb66c 100644 --- a/src/routes/queue.rs +++ b/src/routes/queue.rs @@ -36,6 +36,7 @@ pub fn router() -> Router> { responses( (status = 200, description = "OCR queue statistics including pending jobs, processing status, and performance metrics"), (status = 401, description = "Unauthorized - valid authentication required"), + (status = 403, description = "Forbidden - Admin access required"), (status = 500, description = "Internal server error") ) )] @@ -70,7 +71,9 @@ async fn get_queue_stats( ), responses( (status = 200, description = "Failed items requeued successfully"), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 403, description = "Forbidden - Admin access required"), + (status = 500, description = "Internal server error") ) )] async fn requeue_failed( diff --git a/src/routes/search.rs b/src/routes/search.rs index d153dbc..5d43534 100644 --- a/src/routes/search.rs +++ b/src/routes/search.rs @@ -24,6 +24,7 @@ pub fn router() -> Router> { get, path = "/api/search", tag = "search", + description = "Search documents with basic relevance ranking and OCR text matching", security( ("bearer_auth" = []) ), @@ -76,6 +77,7 @@ async fn search_documents( get, path = "/api/search/enhanced", tag = "search", + description = "Enhanced search with improved ranking, text snippets, and query suggestions", security( ("bearer_auth" = []) ), @@ -84,7 +86,8 @@ async fn search_documents( ), responses( (status = 200, description = "Enhanced search results with snippets and suggestions", body = SearchResponse), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] async fn enhanced_search_documents( @@ -138,12 +141,14 @@ fn generate_search_suggestions(query: &str) -> Vec { get, path = "/api/search/facets", tag = "search", + description = "Get available search facets (MIME types, tags) with document counts for filtering", security( ("bearer_auth" = []) ), responses( (status = 200, description = "Search facets with counts", body = SearchFacetsResponse), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] async fn get_search_facets( diff --git a/src/routes/settings.rs b/src/routes/settings.rs index c8b0506..a6457f7 100644 --- a/src/routes/settings.rs +++ b/src/routes/settings.rs @@ -27,7 +27,8 @@ pub fn router() -> Router> { ), responses( (status = 200, description = "User settings", body = SettingsResponse), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] async fn get_settings( @@ -112,7 +113,8 @@ async fn get_settings( responses( (status = 200, description = "Settings updated successfully", body = SettingsResponse), (status = 400, description = "Bad request - invalid settings data"), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] async fn update_settings( diff --git a/src/routes/sources.rs b/src/routes/sources.rs index 204e57a..18bdf7c 100644 --- a/src/routes/sources.rs +++ b/src/routes/sources.rs @@ -36,7 +36,8 @@ pub fn router() -> Router> { ), responses( (status = 200, description = "List of user sources", body = Vec), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] async fn list_sources( @@ -64,7 +65,8 @@ async fn list_sources( responses( (status = 201, description = "Source created successfully", body = SourceResponse), (status = 400, description = "Bad request - invalid source data"), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] async fn create_source( @@ -103,8 +105,9 @@ async fn create_source( ), responses( (status = 200, description = "Source details with stats", body = SourceWithStats), + (status = 401, description = "Unauthorized"), (status = 404, description = "Source not found"), - (status = 401, description = "Unauthorized") + (status = 500, description = "Internal server error") ) )] async fn get_source( @@ -159,9 +162,10 @@ async fn get_source( request_body = UpdateSource, responses( (status = 200, description = "Source updated successfully", body = SourceResponse), - (status = 404, description = "Source not found"), (status = 400, description = "Bad request - invalid update data"), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 404, description = "Source not found"), + (status = 500, description = "Internal server error") ) )] async fn update_source( @@ -214,8 +218,9 @@ async fn update_source( ), responses( (status = 204, description = "Source deleted successfully"), + (status = 401, description = "Unauthorized"), (status = 404, description = "Source not found"), - (status = 401, description = "Unauthorized") + (status = 500, description = "Internal server error") ) )] async fn delete_source( @@ -248,9 +253,11 @@ async fn delete_source( ), responses( (status = 200, description = "Sync triggered successfully"), + (status = 401, description = "Unauthorized"), (status = 404, description = "Source not found"), (status = 409, description = "Source is already syncing"), - (status = 401, description = "Unauthorized") + (status = 500, description = "Internal server error"), + (status = 501, description = "Not implemented - Source type not supported") ) )] async fn trigger_sync( @@ -341,9 +348,10 @@ async fn trigger_sync( ), responses( (status = 200, description = "Sync stopped successfully"), + (status = 401, description = "Unauthorized"), (status = 404, description = "Source not found"), (status = 409, description = "Source is not currently syncing"), - (status = 401, description = "Unauthorized") + (status = 500, description = "Internal server error") ) )] async fn stop_sync( @@ -411,8 +419,9 @@ async fn stop_sync( ), responses( (status = 200, description = "Connection test result", body = serde_json::Value), + (status = 401, description = "Unauthorized"), (status = 404, description = "Source not found"), - (status = 401, description = "Unauthorized") + (status = 500, description = "Internal server error") ) )] async fn test_connection( @@ -540,8 +549,9 @@ fn validate_config_for_type( ), responses( (status = 200, description = "Crawl estimate result", body = serde_json::Value), + (status = 401, description = "Unauthorized"), (status = 404, description = "Source not found"), - (status = 401, description = "Unauthorized") + (status = 500, description = "Internal server error") ) )] async fn estimate_crawl( @@ -580,7 +590,8 @@ async fn estimate_crawl( responses( (status = 200, description = "Crawl estimate result", body = serde_json::Value), (status = 400, description = "Bad request - invalid configuration"), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] async fn estimate_crawl_with_config( @@ -652,7 +663,8 @@ struct TestConnectionRequest { responses( (status = 200, description = "Connection test result", body = serde_json::Value), (status = 400, description = "Bad request - invalid configuration"), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error") ) )] async fn test_connection_with_config( diff --git a/src/routes/users.rs b/src/routes/users.rs index 9deb20a..c3ce835 100644 --- a/src/routes/users.rs +++ b/src/routes/users.rs @@ -37,7 +37,9 @@ pub fn router() -> Router> { ), responses( (status = 200, description = "List of all users", body = Vec), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 403, description = "Forbidden - Admin access required"), + (status = 500, description = "Internal server error") ) )] async fn list_users( @@ -67,8 +69,10 @@ async fn list_users( ), responses( (status = 200, description = "User information", body = UserResponse), + (status = 401, description = "Unauthorized"), + (status = 403, description = "Forbidden - Admin access required"), (status = 404, description = "User not found"), - (status = 401, description = "Unauthorized") + (status = 500, description = "Internal server error") ) )] async fn get_user( @@ -98,7 +102,9 @@ async fn get_user( responses( (status = 200, description = "User created successfully", body = UserResponse), (status = 400, description = "Bad request - invalid user data"), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 403, description = "Forbidden - Admin access required"), + (status = 500, description = "Internal server error") ) )] async fn create_user( @@ -130,7 +136,9 @@ async fn create_user( responses( (status = 200, description = "User updated successfully", body = UserResponse), (status = 400, description = "Bad request - invalid user data"), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 403, description = "Forbidden - Admin access required"), + (status = 500, description = "Internal server error") ) )] async fn update_user( @@ -161,8 +169,10 @@ async fn update_user( ), responses( (status = 204, description = "User deleted successfully"), - (status = 403, description = "Forbidden - cannot delete yourself"), - (status = 401, description = "Unauthorized") + (status = 401, description = "Unauthorized"), + (status = 403, description = "Forbidden - Admin access required or cannot delete yourself"), + (status = 404, description = "User not found"), + (status = 500, description = "Internal server error") ) )] async fn delete_user( diff --git a/src/swagger.rs b/src/swagger.rs index 27ac635..77416f7 100644 --- a/src/swagger.rs +++ b/src/swagger.rs @@ -13,7 +13,9 @@ use crate::{ Source, SourceResponse, CreateSource, UpdateSource, SourceWithStats, WebDAVSourceConfig, LocalFolderSourceConfig, S3SourceConfig, WebDAVCrawlEstimate, WebDAVTestConnection, WebDAVConnectionResult, WebDAVSyncStatus, - ProcessedImage, CreateProcessedImage, IgnoredFileResponse, IgnoredFilesQuery + ProcessedImage, CreateProcessedImage, IgnoredFileResponse, IgnoredFilesQuery, + DocumentListResponse, DocumentOcrResponse, DocumentOperationResponse, + BulkDeleteResponse, PaginationInfo, DocumentDuplicatesResponse }, routes::{ metrics::{ @@ -130,7 +132,8 @@ use crate::{ // Labels schemas Label, CreateLabel, UpdateLabel, LabelAssignment, LabelQuery, LabelBulkUpdateRequest, // Document schemas - BulkDeleteRequest + BulkDeleteRequest, DocumentListResponse, DocumentOcrResponse, DocumentOperationResponse, + BulkDeleteResponse, PaginationInfo, DocumentDuplicatesResponse ) ), tags(