saves endpoint refactor as RESTful

This commit is contained in:
Zurdi
2024-01-15 14:12:55 +01:00
parent 3c33d46ff2
commit 2604426970
7 changed files with 162 additions and 107 deletions

View File

@@ -3,7 +3,7 @@ from decorators.auth import protected_route
from endpoints.responses import MessageResponse
from endpoints.responses.assets import UploadedSavesResponse
from fastapi import APIRouter, File, HTTPException, Request, UploadFile, status
from handler import dbh, fsasseth, fsromh
from handler import dbsaveh, fsasseth, dbromh
from handler.scan_handler import scan_save
from logger.logger import log
@@ -14,7 +14,7 @@ router = APIRouter()
def add_saves(
request: Request, rom_id: int, saves: list[UploadFile] = File(...)
) -> UploadedSavesResponse:
rom = dbh.get_rom(rom_id)
rom = dbromh.get_roms(id=rom_id)
log.info(f"Uploading saves to {rom.name}")
if saves is None:
log.error("No saves were uploaded")
@@ -23,7 +23,7 @@ def add_saves(
detail="No saves were uploaded",
)
saves_path = fsromh.build_upload_file_path(
saves_path = fsasseth.build_upload_file_path(
rom.platform.fs_slug, folder=cm.config.SAVES_FOLDER_NAME
)
@@ -32,18 +32,16 @@ def add_saves(
# Scan or update save
scanned_save = scan_save(rom.platform, save.filename)
db_save = dbh.get_save_by_filename(rom.platform_slug, save.filename)
db_save = dbsaveh.get_save(rom.id, save.filename)
if db_save:
dbh.update_save(
dbsaveh.update_save(
db_save.id, {"file_size_bytes": scanned_save.file_size_bytes}
)
continue
scanned_save.rom_id = rom.id
scanned_save.platform_slug = rom.platform_slug
dbh.add_save(scanned_save)
dbsaveh.add_save(scanned_save)
rom = dbh.get_rom(rom_id)
return {"uploaded": len(saves), "saves": rom.saves}
@@ -74,19 +72,19 @@ async def delete_saves(request: Request) -> MessageResponse:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=error)
for save_id in save_ids:
save = dbh.get_save(save_id)
save = dbsaveh.get_save(save_id)
if not save:
error = f"Save with ID {save_id} not found"
log.error(error)
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=error)
dbh.delete_save(save_id)
dbsaveh.delete_save(save_id)
if delete_from_fs:
log.info(f"Deleting {save.file_name} from filesystem")
try:
fsromh.remove_file(file_name=save.file_name, file_path=save.file_path)
fsasseth.remove_file(file_name=save.file_name, file_path=save.file_path)
except FileNotFoundError:
error = f"Save file {save.file_name} not found for platform {save.platform_slug}"
log.error(error)

View File

@@ -1,6 +1,7 @@
from handler.auth_handler.auth_handler import AuthHandler, OAuthHandler
from handler.db_handler.db_platforms_handler import DBPlatformsHandler
from handler.db_handler.db_roms_handler import DBRomsHandler
from handler.db_handler.db_saves_handler import DBSavesHandler
from handler.fs_handler.fs_assets_handler import FSAssetsHandler
from handler.fs_handler.fs_platforms_handler import FSPlatformsHandler
from handler.fs_handler.fs_resources_handler import FSResourceHandler
@@ -18,11 +19,13 @@ oauthh = OAuthHandler()
socketh = SocketHandler()
dbplatformh = DBPlatformsHandler()
dbromh = DBRomsHandler()
dbsaveh = DBSavesHandler()
fsplatformh = FSPlatformsHandler()
fsromh = FSRomsHandler()
fsasseth = FSAssetsHandler()
fsresourceh = FSResourceHandler()
from handler.db_handler.db_handler import DBHandler
from handler.db_handler.db_handler import DBHandler
dbh = DBHandler()

View File

@@ -10,51 +10,6 @@ class DBHandler:
self.engine = create_engine(ConfigManager.get_db_engine(), pool_pre_ping=True)
self.session = sessionmaker(bind=self.engine, expire_on_commit=False)
# ========= Roms =========
@begin_session
def add_rom(self, rom: Rom, session: Session = None):
return session.merge(rom)
def get_roms(self, platform_slug: str):
return (
select(Rom)
.filter_by(platform_slug=platform_slug)
.order_by(func.lower(Rom.name).asc())
)
@begin_session
def get_rom(self, id: int, session: Session = None):
return session.get(Rom, id)
@begin_session
def get_recent_roms(self, session: Session = None):
return session.scalars(select(Rom).order_by(Rom.id.desc()).limit(15)).all()
@begin_session
def update_rom(self, id: int, data: dict, session: Session = None):
return session.execute(
update(Rom)
.where(Rom.id == id)
.values(**data)
.execution_options(synchronize_session="evaluate")
)
@begin_session
def delete_rom(self, id: int, session: Session = None):
return session.execute(
delete(Rom)
.where(Rom.id == id)
.execution_options(synchronize_session="evaluate")
)
@begin_session
def purge_roms(self, platform_id: int, roms: list[str], session: Session = None):
return session.execute(
delete(Rom)
.where(and_(Rom.platform_id == platform_id, Rom.file_name.not_in(roms)))
.execution_options(synchronize_session="evaluate")
)
# ==== Utils ======
@begin_session
def get_rom_by_filename(
@@ -73,48 +28,7 @@ class DBHandler:
).first()
# ========= Saves =========
@begin_session
def add_save(self, save: Save, session: Session = None):
return session.merge(save)
@begin_session
def get_save(self, id, session: Session = None):
return session.get(Save, id)
@begin_session
def get_save_by_filename(
self, platform_slug: str, file_name: str, session: Session = None
):
return session.scalars(
select(Save)
.filter_by(platform_slug=platform_slug, file_name=file_name)
.limit(1)
).first()
@begin_session
def update_save(self, id: int, data: dict, session: Session = None):
session.execute(
update(Save)
.where(Save.id == id)
.values(**data)
.execution_options(synchronize_session="evaluate")
)
@begin_session
def delete_save(self, id: int, session: Session = None):
return session.execute(
delete(Save)
.where(Save.id == id)
.execution_options(synchronize_session="evaluate")
)
@begin_session
def purge_saves(self, platform_id: int, saves: list[str], session: Session = None):
return session.execute(
delete(Save)
.where(and_(Save.platform_id == platform_id, Save.file_name.not_in(saves)))
.execution_options(synchronize_session="evaluate")
)
# ========= States =========
@begin_session

View File

@@ -0,0 +1,64 @@
from decorators.database import begin_session
from handler.db_handler.db_handler import DBHandler
from models import Save, Rom
from sqlalchemy import and_, delete, func, select, update
from sqlalchemy.orm import Session
class DBSavesHandler(DBHandler):
# @staticmethod
# def _filter(data, platform_id, search_term):
# if platform_id:
# data = data.filter_by(platform_id=platform_id)
# if search_term:
# data = data.filter(Rom.file_name.ilike(f"%{search_term}%"))
# return data
# @staticmethod
# def _order(data, order_by, order_dir):
# if order_by == "name":
# _column = func.lower(Rom.name)
# elif order_by == "id":
# _column = Rom.id
# else:
# _column = func.lower(Rom.name)
# if order_dir == "asc":
# return data.order_by(_column.asc())
# elif order_dir == "desc":
# return data.order_by(_column.desc())
# else:
# return data.order_by(_column.asc())
@begin_session
def add_save(self, save: Save, session: Session = None):
return session.merge(save)
@begin_session
def get_save(self, id: int, session: Session = None):
return session.get(Save, id)
@begin_session
def update_save(self, id: int, data: dict, session: Session = None):
session.execute(
update(Save)
.where(Save.id == id)
.values(**data)
.execution_options(synchronize_session="evaluate")
)
@begin_session
def delete_save(self, id: int, session: Session = None):
return session.execute(
delete(Save)
.where(Save.id == id)
.execution_options(synchronize_session="evaluate")
)
@begin_session
def purge_saves(self, platform_id: int, saves: list[str], session: Session = None):
return session.execute(
delete(Save)
.where(and_(Save.platform_id == platform_id, Save.file_name.not_in(saves)))
.execution_options(synchronize_session="evaluate")
)

View File

@@ -0,0 +1,76 @@
from decorators.database import begin_session
from handler.db_handler.db_handler import DBHandler
from models import Rom
from sqlalchemy import and_, delete, func, select, update
from sqlalchemy.orm import Session
class DBRomsHandler(DBHandler):
@staticmethod
def _filter(data, platform_id, search_term):
if platform_id:
data = data.filter_by(platform_id=platform_id)
if search_term:
data = data.filter(Rom.file_name.ilike(f"%{search_term}%"))
return data
@staticmethod
def _order(data, order_by, order_dir):
if order_by == "name":
_column = func.lower(Rom.name)
elif order_by == "id":
_column = Rom.id
else:
_column = func.lower(Rom.name)
if order_dir == "asc":
return data.order_by(_column.asc())
elif order_dir == "desc":
return data.order_by(_column.desc())
else:
return data.order_by(_column.asc())
@begin_session
def get_roms(
self,
id: int = None,
platform_id: int = None,
search_term: str = "",
order_by: str = "name",
order_dir: str = "asc",
session: Session = None,
):
return (
session.get(Rom, id)
if id
else self._order(
self._filter(select(Rom), platform_id, search_term),
order_by,
order_dir,
)
)
@begin_session
def update_rom(self, id: int, data: dict, session: Session = None):
return session.execute(
update(Rom)
.where(Rom.id == id)
.values(**data)
.execution_options(synchronize_session="evaluate")
)
@begin_session
def delete_rom(self, id: int, session: Session = None):
return session.execute(
delete(Rom)
.where(Rom.id == id)
.execution_options(synchronize_session="evaluate")
)
@begin_session
def purge_roms(self, platform_id: int, roms: list[str], session: Session = None):
return session.execute(
delete(Rom)
.where(and_(Rom.platform_id == platform_id, Rom.file_name.not_in(roms)))
.execution_options(synchronize_session="evaluate")
)

View File

@@ -1,5 +1,6 @@
import os
import re
import shutil
from abc import ABC
from config import LIBRARY_BASE_PATH
@@ -38,3 +39,10 @@ class FSHandler(ABC):
):
rom_path = self.get_fs_structure(fs_slug, folder=folder)
return f"{LIBRARY_BASE_PATH}/{rom_path}"
@staticmethod
def remove_file(file_name: str, file_path: str):
try:
os.remove(f"{LIBRARY_BASE_PATH}/{file_path}/{file_name}")
except IsADirectoryError:
shutil.rmtree(f"{LIBRARY_BASE_PATH}/{file_path}/{file_name}")

View File

@@ -1,7 +1,6 @@
import fnmatch
import os
import re
import shutil
from pathlib import Path
from models.platform import Platform
@@ -191,10 +190,3 @@ class FSRomsHandler(FSHandler):
f"{LIBRARY_BASE_PATH}/{file_path}/{old_name}",
f"{LIBRARY_BASE_PATH}/{file_path}/{new_name}",
)
@staticmethod
def remove_file(file_name: str, file_path: str):
try:
os.remove(f"{LIBRARY_BASE_PATH}/{file_path}/{file_name}")
except IsADirectoryError:
shutil.rmtree(f"{LIBRARY_BASE_PATH}/{file_path}/{file_name}")