Files
romm/backend/endpoints/platform.py
Georges-Antoine Assi 7fba92588d get rid of delete response
2025-08-02 14:39:33 -04:00

216 lines
6.7 KiB
Python

from datetime import datetime, timezone
from typing import Annotated
from decorators.auth import protected_route
from endpoints.responses.platform import PlatformSchema
from exceptions.endpoint_exceptions import PlatformNotFoundInDatabaseException
from exceptions.fs_exceptions import PlatformAlreadyExistsException
from fastapi import Body
from fastapi import Path as PathVar
from fastapi import Request, status
from handler.auth.constants import Scope
from handler.database import db_platform_handler
from handler.filesystem import fs_platform_handler
from handler.metadata import (
meta_hasheous_handler,
meta_igdb_handler,
meta_launchbox_handler,
meta_moby_handler,
meta_ra_handler,
meta_ss_handler,
meta_tgdb_handler,
)
from handler.metadata.base_hander import UniversalPlatformSlug as UPS
from handler.scan_handler import scan_platform
from logger.formatter import BLUE
from logger.formatter import highlight as hl
from logger.logger import log
from models.platform import DEFAULT_COVER_ASPECT_RATIO, Platform
from utils.router import APIRouter
router = APIRouter(
prefix="/platforms",
tags=["platforms"],
)
@protected_route(
router.post,
"",
[Scope.PLATFORMS_WRITE],
status_code=status.HTTP_201_CREATED,
)
async def add_platform(
request: Request,
fs_slug: Annotated[str, Body(description="Platform slug.", embed=True)],
) -> PlatformSchema:
"""Create a platform."""
try:
await fs_platform_handler.add_platform(fs_slug=fs_slug)
except PlatformAlreadyExistsException:
log.info(f"Detected platform: {hl(fs_slug)}")
scanned_platform = await scan_platform(fs_slug, [fs_slug])
return PlatformSchema.model_validate(
db_platform_handler.add_platform(scanned_platform)
)
@protected_route(router.get, "", [Scope.PLATFORMS_READ])
def get_platforms(request: Request) -> list[PlatformSchema]:
"""Retrieve platforms."""
return [
PlatformSchema.model_validate(p) for p in db_platform_handler.get_platforms()
]
@protected_route(router.get, "/supported", [Scope.PLATFORMS_READ])
def get_supported_platforms(request: Request) -> list[PlatformSchema]:
"""Retrieve the list of supported platforms."""
db_platforms = db_platform_handler.get_platforms()
db_platforms_map = {p.slug: p for p in db_platforms}
now = datetime.now(timezone.utc)
supported_platforms = []
for upslug in UPS:
slug = upslug.value
db_platform = db_platforms_map.get(slug, None)
if db_platform:
supported_platforms.append(
PlatformSchema.model_validate(db_platform).model_dump()
)
continue
igdb_platform = meta_igdb_handler.get_platform(slug)
moby_platform = meta_moby_handler.get_platform(slug)
ss_platform = meta_ss_handler.get_platform(slug)
ra_platform = meta_ra_handler.get_platform(slug)
launchbox_platform = meta_launchbox_handler.get_platform(slug)
hasheous_platform = meta_hasheous_handler.get_platform(slug)
tgdb_platform = meta_tgdb_handler.get_platform(slug)
platform_attrs = {
"id": -1,
"name": slug.replace("-", " ").title(),
"fs_slug": slug,
"slug": slug,
"roms": [],
"rom_count": 0,
"created_at": now,
"updated_at": now,
"fs_size_bytes": 0,
"missing_from_fs": False,
"aspect_ratio": DEFAULT_COVER_ASPECT_RATIO,
}
platform_attrs.update(
{
**hasheous_platform,
**tgdb_platform,
**launchbox_platform,
**ra_platform,
**moby_platform,
**ss_platform,
**igdb_platform,
"igdb_id": igdb_platform.get("igdb_id")
or hasheous_platform.get("igdb_id")
or None,
"ra_id": ra_platform.get("ra_id")
or hasheous_platform.get("ra_id")
or None,
"tgdb_id": moby_platform.get("tgdb_id")
or hasheous_platform.get("tgdb_id")
or None,
"name": igdb_platform.get("name")
or ss_platform.get("name")
or moby_platform.get("name")
or ra_platform.get("name")
or launchbox_platform.get("name")
or hasheous_platform.get("name")
or tgdb_platform.get("name")
or slug.replace("-", " ").title(),
"url_logo": igdb_platform.get("url_logo")
or tgdb_platform.get("url_logo")
or "",
}
)
platform = Platform(**platform_attrs)
supported_platforms.append(PlatformSchema.model_validate(platform).model_dump())
return supported_platforms
@protected_route(
router.get,
"/{id}",
[Scope.PLATFORMS_READ],
responses={status.HTTP_404_NOT_FOUND: {}},
)
def get_platform(
request: Request,
id: Annotated[int, PathVar(description="Platform id.", ge=1)],
) -> PlatformSchema:
"""Retrieve a platform by ID."""
platform = db_platform_handler.get_platform(id)
if not platform:
raise PlatformNotFoundInDatabaseException(id)
return PlatformSchema.model_validate(platform)
@protected_route(
router.put,
"/{id}",
[Scope.PLATFORMS_WRITE],
responses={status.HTTP_404_NOT_FOUND: {}},
)
async def update_platform(
request: Request,
id: Annotated[int, PathVar(description="Platform id.", ge=1)],
aspect_ratio: Annotated[str | None, Body(description="Cover aspect ratio.")] = None,
custom_name: Annotated[
str | None, Body(description="Custom platform name.")
] = None,
) -> PlatformSchema:
"""Update a platform."""
platform_db = db_platform_handler.get_platform(id)
if not platform_db:
raise PlatformNotFoundInDatabaseException(id)
if aspect_ratio is not None:
platform_db.aspect_ratio = aspect_ratio
if custom_name is not None:
platform_db.custom_name = custom_name
platform_db = db_platform_handler.add_platform(platform_db)
return PlatformSchema.model_validate(platform_db)
@protected_route(
router.delete,
"/{id}",
[Scope.PLATFORMS_WRITE],
responses={status.HTTP_404_NOT_FOUND: {}},
)
async def delete_platform(
request: Request,
id: Annotated[int, PathVar(description="Platform id.", ge=1)],
) -> None:
"""Delete a platform."""
platform = db_platform_handler.get_platform(id)
if not platform:
raise PlatformNotFoundInDatabaseException(id)
log.info(
f"Deleting {hl(platform.name, color=BLUE)} [{hl(platform.fs_slug)}] from database"
)
db_platform_handler.delete_platform(id)