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:
@@ -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)}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user