Fix architecture issues from todolist

- Add documentation warnings for in-memory rate limiting and failed login attempts
- Consolidate duplicate health endpoints into api/health.py
- Fix CLI to use correct async rescan method names
- Update download.py and anime.py to use custom exception classes
- Add WebSocket room validation and rate limiting
This commit is contained in:
2025-12-15 14:23:41 +01:00
parent 54790a7ebb
commit 27108aacda
13 changed files with 303 additions and 255 deletions

View File

@@ -4,9 +4,10 @@ This module provides REST API endpoints for managing the anime download queue,
including adding episodes, removing items, controlling queue processing, and
retrieving queue status and statistics.
"""
from fastapi import APIRouter, Depends, HTTPException, Path, status
from fastapi import APIRouter, Depends, Path, status
from fastapi.responses import JSONResponse
from src.server.exceptions import BadRequestError, NotFoundError, ServerError
from src.server.models.download import (
DownloadRequest,
QueueOperationRequest,
@@ -52,9 +53,8 @@ async def get_queue_status(
return response
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to retrieve queue status: {str(e)}",
raise ServerError(
message=f"Failed to retrieve queue status: {str(e)}"
)
@@ -91,9 +91,8 @@ async def add_to_queue(
try:
# Validate request
if not request.episodes:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="At least one episode must be specified",
raise BadRequestError(
message="At least one episode must be specified"
)
# Add to queue
@@ -122,16 +121,12 @@ async def add_to_queue(
)
except DownloadServiceError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
)
except HTTPException:
raise BadRequestError(message=str(e))
except (BadRequestError, NotFoundError, ServerError):
raise
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to add episodes to queue: {str(e)}",
raise ServerError(
message=f"Failed to add episodes to queue: {str(e)}"
)
@@ -163,9 +158,8 @@ async def clear_completed(
}
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to clear completed items: {str(e)}",
raise ServerError(
message=f"Failed to clear completed items: {str(e)}"
)
@@ -197,9 +191,8 @@ async def clear_failed(
}
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to clear failed items: {str(e)}",
raise ServerError(
message=f"Failed to clear failed items: {str(e)}"
)
@@ -231,9 +224,8 @@ async def clear_pending(
}
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to clear pending items: {str(e)}",
raise ServerError(
message=f"Failed to clear pending items: {str(e)}"
)
@@ -262,22 +254,19 @@ async def remove_from_queue(
removed_ids = await download_service.remove_from_queue([item_id])
if not removed_ids:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Download item {item_id} not found in queue",
raise NotFoundError(
message=f"Download item {item_id} not found in queue",
resource_type="download_item",
resource_id=item_id
)
except DownloadServiceError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
)
except HTTPException:
raise BadRequestError(message=str(e))
except (BadRequestError, NotFoundError, ServerError):
raise
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to remove item from queue: {str(e)}",
raise ServerError(
message=f"Failed to remove item from queue: {str(e)}"
)
@@ -307,22 +296,18 @@ async def remove_multiple_from_queue(
)
if not removed_ids:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="No matching items found in queue",
raise NotFoundError(
message="No matching items found in queue",
resource_type="download_items"
)
except DownloadServiceError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
)
except HTTPException:
raise BadRequestError(message=str(e))
except (BadRequestError, NotFoundError, ServerError):
raise
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to remove items from queue: {str(e)}",
raise ServerError(
message=f"Failed to remove items from queue: {str(e)}"
)
@@ -354,9 +339,8 @@ async def start_queue(
result = await download_service.start_queue_processing()
if result is None:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="No pending downloads in queue",
raise BadRequestError(
message="No pending downloads in queue"
)
return {
@@ -365,16 +349,12 @@ async def start_queue(
}
except DownloadServiceError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
)
except HTTPException:
raise BadRequestError(message=str(e))
except (BadRequestError, NotFoundError, ServerError):
raise
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to start queue processing: {str(e)}",
raise ServerError(
message=f"Failed to start queue processing: {str(e)}"
)
@@ -408,9 +388,8 @@ async def stop_queue(
}
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to stop queue processing: {str(e)}",
raise ServerError(
message=f"Failed to stop queue processing: {str(e)}"
)
@@ -442,9 +421,8 @@ async def pause_queue(
}
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to pause queue processing: {str(e)}",
raise ServerError(
message=f"Failed to pause queue processing: {str(e)}"
)
@@ -480,9 +458,8 @@ async def reorder_queue(
}
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to reorder queue: {str(e)}",
raise ServerError(
message=f"Failed to reorder queue: {str(e)}"
)
@@ -522,7 +499,6 @@ async def retry_failed(
}
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to retry downloads: {str(e)}",
raise ServerError(
message=f"Failed to retry downloads: {str(e)}"
)