mirror of
https://github.com/rommapp/romm.git
synced 2026-05-04 00:01:30 +08:00
144 lines
4.2 KiB
Python
144 lines
4.2 KiB
Python
from typing import Annotated
|
|
|
|
from fastapi import Header, HTTPException
|
|
from fastapi import Path as PathVar
|
|
from fastapi import Request, status
|
|
from fastapi.responses import Response
|
|
from starlette.requests import ClientDisconnect
|
|
from streaming_form_data import StreamingFormDataParser
|
|
from streaming_form_data.targets import FileTarget, NullTarget
|
|
|
|
from decorators.auth import protected_route
|
|
from exceptions.endpoint_exceptions import RomNotFoundInDatabaseException
|
|
from handler.auth.constants import Scope
|
|
from handler.database import db_rom_handler
|
|
from handler.filesystem import fs_resource_handler
|
|
from logger.formatter import BLUE
|
|
from logger.formatter import highlight as hl
|
|
from logger.logger import log
|
|
from utils.router import APIRouter
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@protected_route(
|
|
router.post,
|
|
"/{id}/manuals",
|
|
[Scope.ROMS_WRITE],
|
|
status_code=status.HTTP_201_CREATED,
|
|
responses={status.HTTP_404_NOT_FOUND: {}},
|
|
)
|
|
async def add_rom_manuals(
|
|
request: Request,
|
|
id: Annotated[int, PathVar(description="Rom internal id.", ge=1)],
|
|
filename: Annotated[
|
|
str,
|
|
Header(
|
|
description="The name of the file being uploaded.",
|
|
alias="x-upload-filename",
|
|
),
|
|
],
|
|
) -> Response:
|
|
"""Upload manuals for a rom."""
|
|
|
|
rom = db_rom_handler.get_rom(id)
|
|
if not rom:
|
|
raise RomNotFoundInDatabaseException(id)
|
|
|
|
manuals_path = f"{rom.fs_resources_path}/manual"
|
|
file_location = fs_resource_handler.validate_path(f"{manuals_path}/{rom.id}.pdf")
|
|
log.info(f"Uploading manual to {hl(str(file_location))}")
|
|
|
|
await fs_resource_handler.make_directory(manuals_path)
|
|
|
|
parser = StreamingFormDataParser(headers=request.headers)
|
|
parser.register("x-upload-platform", NullTarget())
|
|
parser.register(filename, FileTarget(str(file_location)))
|
|
|
|
def cleanup_partial_file():
|
|
if file_location.exists():
|
|
file_location.unlink()
|
|
|
|
try:
|
|
async for chunk in request.stream():
|
|
parser.data_received(chunk)
|
|
|
|
db_rom_handler.update_rom(
|
|
id,
|
|
{
|
|
"path_manual": f"{manuals_path}/{rom.id}.pdf",
|
|
},
|
|
)
|
|
except ClientDisconnect:
|
|
log.error("Client disconnected during upload")
|
|
cleanup_partial_file()
|
|
except Exception as exc:
|
|
log.error("Error uploading files", exc_info=exc)
|
|
cleanup_partial_file()
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail="There was an error uploading the manual",
|
|
) from exc
|
|
|
|
return Response()
|
|
|
|
|
|
@protected_route(
|
|
router.delete,
|
|
"/{id}/manuals",
|
|
[Scope.ROMS_WRITE],
|
|
responses={status.HTTP_404_NOT_FOUND: {}},
|
|
)
|
|
async def delete_rom_manuals(
|
|
request: Request,
|
|
id: Annotated[int, PathVar(description="Rom internal id.", ge=1)],
|
|
) -> Response:
|
|
"""Delete manuals for a rom."""
|
|
|
|
rom = db_rom_handler.get_rom(id)
|
|
if not rom:
|
|
raise RomNotFoundInDatabaseException(id)
|
|
|
|
if not fs_resource_handler.manual_exists(rom):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="No manual found for this ROM",
|
|
)
|
|
|
|
try:
|
|
await fs_resource_handler.remove_manual(rom)
|
|
db_rom_handler.update_rom(
|
|
id,
|
|
{
|
|
"path_manual": "",
|
|
"url_manual": "",
|
|
},
|
|
)
|
|
|
|
log.info(
|
|
f"Deleted manual for {hl(rom.name or 'ROM', color=BLUE)} [{hl(rom.fs_name)}]"
|
|
)
|
|
except FileNotFoundError:
|
|
log.warning(
|
|
f"Manual file not found for {hl(rom.name or 'ROM', color=BLUE)} [{hl(rom.fs_name)}]"
|
|
)
|
|
# Still update the database even if file doesn't exist
|
|
db_rom_handler.update_rom(
|
|
id,
|
|
{
|
|
"path_manual": "",
|
|
"url_manual": "",
|
|
},
|
|
)
|
|
except Exception as exc:
|
|
log.error(
|
|
f"Error deleting manual for {hl(rom.name or 'ROM', color=BLUE)} [{hl(rom.fs_name)}]",
|
|
exc_info=exc,
|
|
)
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail="There was an error deleting the manual",
|
|
) from exc
|
|
|
|
return Response()
|