diff --git a/app/api/diagnostic.py b/app/api/diagnostic.py index 400b2f9f..7fffbcbd 100644 --- a/app/api/diagnostic.py +++ b/app/api/diagnostic.py @@ -3,6 +3,7 @@ Diagnostic API endpoints """ import logging +from typing import Annotated from fastapi import APIRouter, Depends, Request @@ -14,10 +15,12 @@ logger = logging.getLogger(__name__) router = APIRouter() +CurrentUser = Annotated[dict, Depends(get_current_user)] + @router.get("/diagnostic/settings") @require_login -async def diagnostic_settings(request: Request, current_user: dict = Depends(get_current_user)): +async def diagnostic_settings(request: Request, current_user: CurrentUser): """ API endpoint to dump settings to the log and view basic config information This endpoint doesn't expose sensitive information like passwords or tokens diff --git a/app/api/files.py b/app/api/files.py index 0e81f43b..abdc4ed5 100644 --- a/app/api/files.py +++ b/app/api/files.py @@ -6,7 +6,7 @@ import logging import mimetypes import os import uuid -from typing import List, Optional +from typing import Annotated, List, Optional from fastapi import APIRouter, Depends, File, HTTPException, Query, Request, UploadFile from sqlalchemy import asc, desc @@ -27,6 +27,8 @@ logger = logging.getLogger(__name__) router = APIRouter() +DbSession = Annotated[Session, Depends(get_db)] + def get_limiter(): """Get the limiter from app state.""" @@ -39,7 +41,7 @@ def get_limiter(): @require_login def list_files_api( request: Request, - db: Session = Depends(get_db), + db: DbSession, page: int = Query(1, ge=1, description="Page number"), per_page: int = Query(50, ge=1, le=200, description="Items per page"), sort_by: str = Query( @@ -152,7 +154,7 @@ def _get_file_processing_status(db: Session, file_id: int) -> dict: @router.get("/files/{file_id}") @require_login -def get_file_details(request: Request, file_id: int, db: Session = Depends(get_db)): +def get_file_details(request: Request, file_id: int, db: DbSession): """ Get detailed information about a specific file including processing history. """ @@ -205,7 +207,7 @@ def get_file_details(request: Request, file_id: int, db: Session = Depends(get_d @router.delete("/files/{file_id}") @require_login -def delete_file_record(request: Request, file_id: int, db: Session = Depends(get_db)): +def delete_file_record(request: Request, file_id: int, db: DbSession): """ Delete a file record from the database. This only removes the database entry, not the actual file. @@ -240,7 +242,7 @@ def delete_file_record(request: Request, file_id: int, db: Session = Depends(get @router.post("/files/bulk-delete") @require_login -def bulk_delete_files(request: Request, file_ids: List[int], db: Session = Depends(get_db)): +def bulk_delete_files(request: Request, file_ids: List[int], db: DbSession): """ Delete multiple file records from the database. This only removes the database entries, not the actual files. @@ -284,7 +286,7 @@ def bulk_delete_files(request: Request, file_ids: List[int], db: Session = Depen @router.post("/files/bulk-reprocess") @require_login -def bulk_reprocess_files(request: Request, file_ids: List[int], db: Session = Depends(get_db)): +def bulk_reprocess_files(request: Request, file_ids: List[int], db: DbSession): """ Reprocess multiple files by queuing them for processing. """ @@ -345,7 +347,7 @@ def bulk_reprocess_files(request: Request, file_ids: List[int], db: Session = De @router.post("/files/{file_id}/reprocess") @require_login -def reprocess_single_file(request: Request, file_id: int, db: Session = Depends(get_db)): +def reprocess_single_file(request: Request, file_id: int, db: DbSession): """ Reprocess a single file by queuing it for processing again. @@ -487,10 +489,10 @@ def _retry_pipeline_step(file_record: FileRecord, step_name: str, db: Session) - def retry_subtask( request: Request, file_id: int, + db: DbSession, subtask_name: str = Query( ..., description="Name of the subtask to retry (e.g., 'upload_to_dropbox', 'extract_metadata_with_gpt')" ), - db: Session = Depends(get_db), ): """ Retry a specific failed subtask for a file. @@ -603,8 +605,8 @@ def retry_subtask( def get_file_preview( request: Request, file_id: int, + db: DbSession, version: str = Query("original", description="original or processed"), - db: Session = Depends(get_db), ): """ Get file content for preview (original or processed version). @@ -675,8 +677,8 @@ def get_file_preview( def download_file( request: Request, file_id: int, + db: DbSession, version: str = Query("original", description="original or processed"), - db: Session = Depends(get_db), ): """ Download file (original or processed version) as attachment. diff --git a/app/api/logs.py b/app/api/logs.py index 7ef0c434..caeb1225 100644 --- a/app/api/logs.py +++ b/app/api/logs.py @@ -3,7 +3,7 @@ Processing logs API endpoints """ import logging -from typing import Optional +from typing import Annotated, Optional from fastapi import APIRouter, Depends, HTTPException, Query, Request from sqlalchemy import desc @@ -18,12 +18,14 @@ logger = logging.getLogger(__name__) router = APIRouter() +DbSession = Annotated[Session, Depends(get_db)] + @router.get("/logs") @require_login def list_processing_logs( request: Request, - db: Session = Depends(get_db), + db: DbSession, file_id: Optional[int] = Query(None, description="Filter by file ID"), task_id: Optional[str] = Query(None, description="Filter by task ID"), limit: int = Query(100, ge=1, le=1000, description="Number of logs to return"), @@ -81,7 +83,7 @@ def list_processing_logs( @router.get("/logs/file/{file_id}") @require_login -def get_file_processing_logs(request: Request, file_id: int, db: Session = Depends(get_db)): +def get_file_processing_logs(request: Request, file_id: int, db: DbSession): """ Get all processing logs for a specific file. Returns logs ordered by timestamp (oldest first to show processing flow). @@ -125,7 +127,7 @@ def get_file_processing_logs(request: Request, file_id: int, db: Session = Depen @router.get("/logs/task/{task_id}") @require_login -def get_task_processing_logs(request: Request, task_id: str, db: Session = Depends(get_db)): +def get_task_processing_logs(request: Request, task_id: str, db: DbSession): """ Get all processing logs for a specific task. Returns logs ordered by timestamp (oldest first to show processing flow). diff --git a/app/api/settings.py b/app/api/settings.py index 5e9bd4af..7cf74a9e 100644 --- a/app/api/settings.py +++ b/app/api/settings.py @@ -3,7 +3,7 @@ API endpoints for managing application settings. """ import logging -from typing import Any, Dict, Optional +from typing import Annotated, Any, Dict, Optional from fastapi import APIRouter, Depends, HTTPException, Request, status from pydantic import BaseModel, Field @@ -39,6 +39,10 @@ def require_admin(request: Request) -> dict: return user +DbSession = Annotated[Session, Depends(get_db)] +AdminUser = Annotated[dict, Depends(require_admin)] + + class SettingUpdate(BaseModel): """Model for updating a setting""" @@ -63,7 +67,7 @@ class SettingsListResponse(BaseModel): @router.get("/", response_model=SettingsListResponse) -async def get_settings(request: Request, db: Session = Depends(get_db), admin: dict = Depends(require_admin)): +async def get_settings(request: Request, db: DbSession, admin: AdminUser): """ Get all application settings with metadata. Admin only. @@ -89,7 +93,7 @@ async def get_settings(request: Request, db: Session = Depends(get_db), admin: d @router.get("/{key}", response_model=SettingResponse) -async def get_setting(key: str, request: Request, db: Session = Depends(get_db), admin: dict = Depends(require_admin)): +async def get_setting(key: str, request: Request, db: DbSession, admin: AdminUser): """ Get a specific setting by key. Admin only. @@ -114,8 +118,8 @@ async def update_setting( key: str, setting: SettingUpdate, request: Request, - db: Session = Depends(get_db), - admin: dict = Depends(require_admin), + db: DbSession, + admin: AdminUser, ): """ Update a specific setting. @@ -156,9 +160,7 @@ async def update_setting( @router.delete("/{key}") -async def delete_setting( - key: str, request: Request, db: Session = Depends(get_db), admin: dict = Depends(require_admin) -): +async def delete_setting(key: str, request: Request, db: DbSession, admin: AdminUser): """ Delete a setting from the database (reverts to environment variable or default). Admin only. @@ -182,9 +184,7 @@ async def delete_setting( @router.post("/bulk-update") -async def bulk_update_settings( - updates: list[SettingUpdate], request: Request, db: Session = Depends(get_db), admin: dict = Depends(require_admin) -): +async def bulk_update_settings(updates: list[SettingUpdate], request: Request, db: DbSession, admin: AdminUser): """ Update multiple settings at once. Admin only.