diff --git a/cli_commands.py b/cli_commands.py index 1a0b3a1..a17ee80 100644 --- a/cli_commands.py +++ b/cli_commands.py @@ -6,6 +6,7 @@ import database cli = typer.Typer() + @cli.command(name="create") def create_database(): aiorun(database.create_all()) @cli.command(name="drop") diff --git a/database/__init__.py b/database/__init__.py index 6757f87..d9ce308 100644 --- a/database/__init__.py +++ b/database/__init__.py @@ -1,4 +1,7 @@ from .crud import * from .schemas import * -from .database import get_session, drop_all, create_all, recreate_all +from .database import get_session as get_session, \ + drop_all as drop_all, \ + create_all as create_all, \ + recreate_all as recreate_all from .crud import * \ No newline at end of file diff --git a/database/crud/__init__.py b/database/crud/__init__.py index 97dd736..f1d38aa 100644 --- a/database/crud/__init__.py +++ b/database/crud/__init__.py @@ -1 +1 @@ -from .games import * \ No newline at end of file +from .games import * diff --git a/database/crud/games.py b/database/crud/games.py index 088f906..1feeeb5 100644 --- a/database/crud/games.py +++ b/database/crud/games.py @@ -5,14 +5,17 @@ from .. import models as mdl from .. import schemas as sch from ..database import add_transaction -async def add_game(db: AsyncSession, - game_info: sch.GameCreate, + +async def add_game(db: AsyncSession, + game_info: sch.GameCreate, user_id: int): game = mdl.Game(**game_info.model_dump(), owner_id=user_id) return await add_transaction(db, game) + async def get_games(db: AsyncSession): return (await db.execute(select(mdl.Game))).scalars().all() + async def get_game(db: AsyncSession, game_id: int): - return await db.get(mdl.Game, game_id) \ No newline at end of file + return await db.get(mdl.Game, game_id) diff --git a/database/database.py b/database/database.py index 12928f1..8e37b57 100644 --- a/database/database.py +++ b/database/database.py @@ -1,7 +1,6 @@ -from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker -from sqlalchemy.ext.asyncio import AsyncSession -from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine DATABASE_URL = "sqlite+aiosqlite:///./dev_database.db" # DATABASE_URL = "postgresql://user:password@postgresserver/db" @@ -9,27 +8,31 @@ DATABASE_URL = "sqlite+aiosqlite:///./dev_database.db" engine = create_async_engine( DATABASE_URL, connect_args={"check_same_thread": False}, echo=True ) -async_session = sessionmaker( - engine, class_=AsyncSession, expire_on_commit=False) +async_session = sessionmaker( # type: ignore + engine, class_=AsyncSession, expire_on_commit=False) # type: ignore Base = declarative_base() async def get_session() -> AsyncSession: # type: ignore - # Dependency async with async_session() as session: # type: ignore yield session + async def drop_all(): async with engine.begin() as conn: await conn.run_sync(Base.metadata.drop_all) + + async def create_all(): async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) + async def recreate_all(): await drop_all() await create_all() - + + async def add_transaction[T](db: AsyncSession, entity: T) -> T: try: db.add(entity) @@ -38,4 +41,4 @@ async def add_transaction[T](db: AsyncSession, entity: T) -> T: return entity except Exception as ex: await db.rollback() - raise ex \ No newline at end of file + raise ex diff --git a/file_handler.py b/file_handler.py index 8c37f11..0fd2efb 100644 --- a/file_handler.py +++ b/file_handler.py @@ -7,36 +7,51 @@ import aiofiles from fastapi import UploadFile from PIL import Image + def create_hash_name(filename: str): return str(hashlib.sha1(filename.encode()).hexdigest()) + async def save_torrent_file(torrent: UploadFile): + if(torrent.filename is None): raise ValueError("Filename not found") hash_filename = create_hash_name(torrent.filename)+".torrent" - async with aiofiles.open(Path() / "content" / "torrent" - / hash_filename, 'wb') as file: - await file.write(await torrent.read()) + async with aiofiles.open(Path() / "content" / "torrent" + / hash_filename, 'wb') as file: + torrent_data = await torrent.read() + if (isinstance(torrent_data, str)): + raise ValueError("Invalid torrent file") + await file.write(torrent_data) return hash_filename + async def save_image(cover: UploadFile, type: Literal["cover", "screenshot"]): - hash_filename = create_hash_name(cover.filename) \ - + mimetypes.guess_extension(cover.content_type) - async with aiofiles.open(Path() / "content" / "images" / type / "full_size" - / hash_filename, 'wb') as full_size_file, \ - aiofiles.open(Path() / "content" / "images" / type / - "preview" / hash_filename, 'wb') as preview_file: + if(cover.filename is None): raise ValueError("Filename not found") + if(cover.content_type is None): raise ValueError("File content type unknown") + + hash_filename = create_hash_name(cover.filename) + file_extension = mimetypes.guess_extension(cover.content_type) + if (file_extension is None): raise NameError("File extension not found") + else: hash_filename += file_extension + + async with aiofiles.open(Path() / "content" / "images" / type / "full_size" + / hash_filename, 'wb') as full_size_file, \ + aiofiles.open(Path() / "content" / "images" / type / + "preview" / hash_filename, 'wb') as preview_file: cover_data = await cover.read() + if (isinstance(cover_data, str)): + raise ValueError("Invalid image file") await full_size_file.write(cover_data) image = Image.open(BytesIO(cover_data)) compressed_coefficient = (image.size[0] * image.size[1]) / (1280*720/4) - if(compressed_coefficient < 1): compressed_coefficient = 1 + if (compressed_coefficient < 1): + compressed_coefficient = 1 compressed_image = image.resize( - ( int(image.size[0] / compressed_coefficient), - int(image.size[1] / compressed_coefficient) ) + (int(image.size[0] / compressed_coefficient), + int(image.size[1] / compressed_coefficient)) ) buf = BytesIO() - compressed_image.save(buf, format= - cover.content_type.upper().replace("IMAGE/", "")) + compressed_image.save( + buf, format=cover.content_type.upper().replace("IMAGE/", "")) await preview_file.write(buf.getbuffer()) - return hash_filename - \ No newline at end of file + return hash_filename diff --git a/main.py b/main.py index b0ac94c..32cbe13 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,4 @@ -from fastapi import Depends, FastAPI, HTTPException -from sqlalchemy.ext.asyncio import AsyncSession +from fastapi import FastAPI import typer import cli_commands @@ -13,4 +12,5 @@ app.include_router(files_router) cli = typer.Typer() cli.add_typer(cli_commands.cli, name="database") -if(__name__ == "__main__"): cli() \ No newline at end of file +if (__name__ == "__main__"): + cli() diff --git a/requirements.txt b/requirements.txt index 401e5c7..5893404 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ pydantic==2.7.1 SQLAlchemy==2.0.30 aiosqlite==0.20.0 typer==0.12.3 -aiofiles==23.2.1 \ No newline at end of file +aiofiles==23.2.1 +Pillow==10.3.0 \ No newline at end of file diff --git a/routes/__init__.py b/routes/__init__.py index c74089f..faaef3d 100644 --- a/routes/__init__.py +++ b/routes/__init__.py @@ -1,3 +1,3 @@ -from .games import router as games_router -from .files import router as files_router -from .startup import router as startup_router \ No newline at end of file +from .games import games_router as games_router +from .files import files_router as files_router +from .startup import startup_router as startup_router diff --git a/routes/files.py b/routes/files.py index 6ef7e2c..123b849 100644 --- a/routes/files.py +++ b/routes/files.py @@ -1,20 +1,24 @@ -from fastapi import APIRouter, Depends, HTTPException, UploadFile +from fastapi import APIRouter, HTTPException, UploadFile from database import * from file_handler import * -router = APIRouter(prefix="/files", tags=["Files"]) +files_router = APIRouter(prefix="/files", tags=["Files"]) -@router.post("/torrent", response_model=str) + +@files_router.post("/torrent", response_model=str) async def upload_torrent(torrent: UploadFile): - try: return await save_torrent_file(torrent) - except Exception as ex: + try: + return await save_torrent_file(torrent) + except Exception as ex: print(ex) raise HTTPException(500) -@router.post("/cover", response_model=str) + +@files_router.post("/cover", response_model=str) async def upload_cover(cover: UploadFile): - try: return await save_image(cover, "cover") - except Exception as ex: + try: + return await save_image(cover, "cover") + except Exception as ex: print(ex) raise HTTPException(500) diff --git a/routes/games.py b/routes/games.py index bdbb622..289c7f2 100644 --- a/routes/games.py +++ b/routes/games.py @@ -1,27 +1,29 @@ -from fastapi import APIRouter, Depends, HTTPException, UploadFile +from fastapi import APIRouter, Depends, HTTPException from database import * from file_handler import * -router = APIRouter(prefix="/games", tags=["Games"]) +games_router = APIRouter(prefix="/games", tags=["Games"]) -@router.get("/", response_model=list[Game]) + +@games_router.get("/", response_model=list[Game]) async def get_games(db: AsyncSession = Depends(get_session)): - try: return await crud.get_games(db) - except Exception as ex: raise HTTPException(500) + try: + return await crud.get_games(db) + except Exception: + raise HTTPException(500) -@router.get("/{game_id}", response_model=Game) + +@games_router.get("/{game_id}", response_model=Game) async def get_game(game_id: int, db: AsyncSession = Depends(get_session)): return await crud.get_game(db, game_id) -@router.post("/", response_model=Game) -async def add_game(game: GameCreate, - user_id: int, - db:AsyncSession = Depends(get_session)): + +@games_router.post("/", response_model=Game) +async def add_game(game: GameCreate, + user_id: int, + db: AsyncSession = Depends(get_session)): try: - torrent_filename = save_torrent_file(torrent, game.title) - cover_filename = save_image(cover, game.title, "cover") return await crud.add_game(db, game, user_id) - except Exception as ex: + except Exception: raise HTTPException(500) - \ No newline at end of file diff --git a/routes/startup.py b/routes/startup.py index f28ef95..d35aae2 100644 --- a/routes/startup.py +++ b/routes/startup.py @@ -1,9 +1,10 @@ from fastapi import APIRouter from pathlib import Path -router = APIRouter() +startup_router = APIRouter() -@router.on_event("startup") + +@startup_router.on_event("startup") def startup(): need_paths = [ Path() / "content" / "images" / "cover" / "full_size", @@ -13,4 +14,4 @@ def startup(): Path() / "content" / "torrent" ] for path in need_paths: - path.mkdir(parents=True, exist_ok=True) \ No newline at end of file + path.mkdir(parents=True, exist_ok=True)