- Add scheduler API endpoints for configuration and manual rescan triggers - Add logging API endpoints for config management and log file operations - Add diagnostics API endpoints for network and system information - Extend config API with advanced settings, directory updates, export, and reset - Update FastAPI app to include new routers - Update API reference documentation with all new endpoints - Update infrastructure documentation with endpoint listings - Add comprehensive API implementation summary All new endpoints follow project coding standards with: - Type hints and Pydantic validation - Proper authentication and authorization - Comprehensive error handling and logging - Security best practices (path validation, input sanitization) Test results: 752/802 tests passing (93.8%)
131 lines
3.9 KiB
Python
131 lines
3.9 KiB
Python
"""Scheduler API endpoints for Aniworld.
|
|
|
|
This module provides endpoints for managing scheduled tasks such as
|
|
automatic anime library rescans.
|
|
"""
|
|
import logging
|
|
from typing import Dict, Optional
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
|
|
from src.server.models.config import SchedulerConfig
|
|
from src.server.services.config_service import ConfigServiceError, get_config_service
|
|
from src.server.utils.dependencies import require_auth
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(prefix="/api/scheduler", tags=["scheduler"])
|
|
|
|
|
|
@router.get("/config", response_model=SchedulerConfig)
|
|
def get_scheduler_config(
|
|
auth: Optional[dict] = Depends(require_auth)
|
|
) -> SchedulerConfig:
|
|
"""Get current scheduler configuration.
|
|
|
|
Args:
|
|
auth: Authentication token (optional for read operations)
|
|
|
|
Returns:
|
|
SchedulerConfig: Current scheduler configuration
|
|
|
|
Raises:
|
|
HTTPException: If configuration cannot be loaded
|
|
"""
|
|
try:
|
|
config_service = get_config_service()
|
|
app_config = config_service.load_config()
|
|
return app_config.scheduler
|
|
except ConfigServiceError as e:
|
|
logger.error(f"Failed to load scheduler config: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Failed to load scheduler configuration: {e}",
|
|
) from e
|
|
|
|
|
|
@router.post("/config", response_model=SchedulerConfig)
|
|
def update_scheduler_config(
|
|
scheduler_config: SchedulerConfig,
|
|
auth: dict = Depends(require_auth),
|
|
) -> SchedulerConfig:
|
|
"""Update scheduler configuration.
|
|
|
|
Args:
|
|
scheduler_config: New scheduler configuration
|
|
auth: Authentication token (required)
|
|
|
|
Returns:
|
|
SchedulerConfig: Updated scheduler configuration
|
|
|
|
Raises:
|
|
HTTPException: If configuration update fails
|
|
"""
|
|
try:
|
|
config_service = get_config_service()
|
|
app_config = config_service.load_config()
|
|
|
|
# Update scheduler section
|
|
app_config.scheduler = scheduler_config
|
|
|
|
# Save and return
|
|
config_service.save_config(app_config)
|
|
logger.info(
|
|
f"Scheduler config updated by {auth.get('username', 'unknown')}"
|
|
)
|
|
|
|
return scheduler_config
|
|
except ConfigServiceError as e:
|
|
logger.error(f"Failed to update scheduler config: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Failed to update scheduler configuration: {e}",
|
|
) from e
|
|
|
|
|
|
@router.post("/trigger-rescan", response_model=Dict[str, str])
|
|
async def trigger_rescan(auth: dict = Depends(require_auth)) -> Dict[str, str]:
|
|
"""Manually trigger a library rescan.
|
|
|
|
This endpoint triggers an immediate anime library rescan, bypassing
|
|
the scheduler interval.
|
|
|
|
Args:
|
|
auth: Authentication token (required)
|
|
|
|
Returns:
|
|
Dict with success message
|
|
|
|
Raises:
|
|
HTTPException: If rescan cannot be triggered
|
|
"""
|
|
try:
|
|
# Import here to avoid circular dependency
|
|
from src.server.fastapi_app import get_series_app
|
|
|
|
series_app = get_series_app()
|
|
if not series_app:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
|
detail="SeriesApp not initialized",
|
|
)
|
|
|
|
# Trigger the rescan
|
|
logger.info(
|
|
f"Manual rescan triggered by {auth.get('username', 'unknown')}"
|
|
)
|
|
|
|
# Use existing rescan logic from anime API
|
|
from src.server.api.anime import trigger_rescan as do_rescan
|
|
|
|
return await do_rescan()
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.exception("Failed to trigger manual rescan")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Failed to trigger rescan: {str(e)}",
|
|
) from e
|