Code refactoring. Add support genres and actors to routes

This commit is contained in:
2024-06-26 23:13:47 +04:00
parent fc3bcc343d
commit b9e22fcc4c
28 changed files with 545 additions and 250 deletions

View File

@@ -2,14 +2,14 @@
from asyncio import run as aiorun
import typer
import database
from database import Database
cli = typer.Typer()
@cli.command(name="create")
def create_database(): aiorun(database.create_all())
def create_database(): aiorun(Database.create_all())
@cli.command(name="drop")
def drop_database(): aiorun(database.drop_all())
def drop_database(): aiorun(Database.drop_all())
@cli.command(name="recreate")
def recreate_database(): aiorun(database.recreate_all())
def recreate_database(): aiorun(Database.recreate_all())

View File

@@ -1,7 +1,4 @@
from .crud import *
from .schemas import *
from .database import get_session as get_session, \
drop_all as drop_all, \
create_all as create_all, \
recreate_all as recreate_all
from .database import Database
from .crud import *

View File

@@ -1,4 +1,11 @@
from .games import *
from .movies import *
from .audiobooks import *
from .users import *
from .games import GamesCRUD as GamesCRUD
from .game_genres import GameGenresCRUD as GameGenresCRUD
from .movies import MoviesCRUD as MoviesCRUD
from .movie_actors import MovieActorsCRUD as MovieActorsCRUD
from .movie_genres import MovieGenresCRUD as MovieGenresCRUD
from .audiobooks import AudiobooksCRUD as AudiobooksCRUD
from .audiobook_genres import AudiobookGenresCRUD as AudiobookGenresCRUD
from .users import UsersCRUD as UsersCRUD

View File

@@ -0,0 +1,19 @@
from time import strftime
from sqlalchemy.ext.asyncio import AsyncSession
from database.database import Database, EntityCRUD
from .. import models as mdl
from .. import schemas as sch
class AudiobookGenresCRUD(EntityCRUD[mdl.AudiobookGenre]):
@staticmethod
async def get_all(db: AsyncSession):
return await Database.get_all(db, mdl.AudiobookGenre)
@staticmethod
async def add(db: AsyncSession,
info: sch.AudiobookGenreCreate):
audiobook_genre = mdl.AudiobookGenre(**info.model_dump())
return await Database.add(db, audiobook_genre)

View File

@@ -1,45 +1,46 @@
from time import strftime
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from database.crud.audiobook_genres import AudiobookGenresCRUD
from database.database import Database, EntityCRUD
from .. import models as mdl
from .. import schemas as sch
from ..database import add_transaction
async def get_audiobooks(db: AsyncSession):
return (await db.execute(select(mdl.Audiobook))).scalars().all()
class AudiobooksCRUD(EntityCRUD[mdl.Audiobook]):
@staticmethod
async def get(db: AsyncSession, id: int):
return await Database.get(db, mdl.Audiobook, id)
@staticmethod
async def get_all(db: AsyncSession):
return await Database.get_all(db, mdl.Audiobook)
async def get_audiobook(db: AsyncSession, audiobook_id: int):
return await db.get(mdl.Audiobook, audiobook_id)
@staticmethod
async def change_genres(db: AsyncSession, audiobook: mdl.Audiobook, info: sch.AudiobookCreate):
audiobook_genres = await AudiobookGenresCRUD.get_all(db)
if (info.genres):
audiobook.genres = [
genre for genre in audiobook_genres if genre.id in info.genres]
async def add_audiobook(db: AsyncSession,
audiobook_info: sch.AudiobookCreate,
user_id: int):
audiobook = mdl.Audiobook(**audiobook_info.model_dump(),
@staticmethod
async def add(db: AsyncSession,
info: sch.AudiobookCreate,
owner_id: int):
audiobook = mdl.Audiobook(**info.model_dump(),
update_date=strftime("%Y-%m-%d %H:%M:%S"),
upload_date=strftime("%Y-%m-%d %H:%M:%S"),
owner_id=user_id)
return await add_transaction(db, audiobook)
owner_id=owner_id)
await AudiobooksCRUD.change_genres(db, audiobook, info)
return await Database.add(db, audiobook)
@staticmethod
async def change(db: AsyncSession,
id: int,
info: sch.AudiobookCreate):
return await Database.change(db, mdl.Audiobook, id, info, AudiobooksCRUD.change_genres)
async def edit_audiobook(db: AsyncSession,
audiobook_id: int,
audiobook_info: sch.AudiobookCreate):
audiobook = await db.get(mdl.Audiobook, audiobook_id)
for key, value in vars(audiobook_info).items():
if (getattr(audiobook, key) != value):
setattr(audiobook, key, value)
setattr(audiobook, "update_date", strftime("%Y-%m-%d %H:%M:%S"))
await db.commit()
return audiobook
async def delete_audiobook(db: AsyncSession,
audiobook_id: int):
audiobook = await get_audiobook(db, audiobook_id)
await db.delete(audiobook)
await db.commit()
return audiobook
@staticmethod
async def delete(db: AsyncSession,
id: int):
return await Database.delete(db, mdl.Audiobook, id)

View File

@@ -0,0 +1,20 @@
from time import strftime
from sqlalchemy.ext.asyncio import AsyncSession
from database.database import Database, EntityCRUD
from .. import models as mdl
from .. import schemas as sch
class GameGenresCRUD(EntityCRUD[mdl.GameGenre]):
@staticmethod
async def get_all(db: AsyncSession):
return await Database.get_all(db, mdl.GameGenre)
@staticmethod
async def add(db: AsyncSession,
info: sch.GameGenreCreate):
game_genre = mdl.GameGenre(**info.model_dump())
return await Database.add(db, game_genre)

View File

@@ -1,46 +1,46 @@
from time import strftime
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from sqlalchemy.orm import selectinload
from database.crud.game_genres import GameGenresCRUD
from database.database import Database, EntityCRUD
from .. import models as mdl
from .. import schemas as sch
from ..database import add_transaction
async def get_games(db: AsyncSession):
return (await db.execute(select(mdl.Game))).scalars().all()
class GamesCRUD(EntityCRUD[mdl.Game]):
@staticmethod
async def get(db: AsyncSession, id: int):
return await Database.get(db, mdl.Game, id)
@staticmethod
async def get_all(db: AsyncSession):
return await Database.get_all(db, mdl.Game)
async def get_game(db: AsyncSession, game_id: int):
return await db.get(mdl.Game, game_id)
@staticmethod
async def change_genres(db: AsyncSession, game: mdl.Game, info: sch.GameCreate):
game_genres = await GameGenresCRUD.get_all(db)
if (info.genres):
game.genres = [
genre for genre in game_genres if genre.id in info.genres]
async def add_game(db: AsyncSession,
game_info: sch.GameCreate,
user_id: int):
game = mdl.Game(**game_info.model_dump(),
@staticmethod
async def add(db: AsyncSession,
info: sch.GameCreate,
owner_id: int):
game = mdl.Game(**info.model_dump(),
update_date=strftime("%Y-%m-%d %H:%M:%S"),
upload_date=strftime("%Y-%m-%d %H:%M:%S"),
owner_id=user_id)
return await add_transaction(db, game)
owner_id=owner_id)
await GamesCRUD.change_genres(db, game, info)
return await Database.add(db, game)
@staticmethod
async def change(db: AsyncSession,
id: int,
info: sch.GameCreate):
return await Database.change(db, mdl.Game, id, info, GamesCRUD.change_genres)
async def edit_game(db: AsyncSession,
game_id: int,
game_info: sch.GameCreate):
game = await db.get(mdl.Game, game_id)
for key, value in vars(game_info).items():
if (getattr(game, key) != value):
setattr(game, key, value)
setattr(game, "update_date", strftime("%Y-%m-%d %H:%M:%S"))
await db.commit()
return game
async def delete_game(db: AsyncSession,
game_id: int):
game = await get_game(db, game_id)
await db.delete(game)
await db.commit()
return game
@staticmethod
async def delete(db: AsyncSession,
id: int):
return await Database.delete(db, mdl.Game, id)

View File

@@ -0,0 +1,19 @@
from time import strftime
from sqlalchemy.ext.asyncio import AsyncSession
from database.database import Database, EntityCRUD
from .. import models as mdl
from .. import schemas as sch
class MovieActorsCRUD(EntityCRUD[mdl.MovieActor]):
@staticmethod
async def get_all(db: AsyncSession):
return await Database.get_all(db, mdl.MovieActor)
@staticmethod
async def add(db: AsyncSession,
info: sch.MovieActorCreate):
movie_actor = mdl.MovieActor(**info.model_dump())
return await Database.add(db, movie_actor)

View File

@@ -0,0 +1,19 @@
from time import strftime
from sqlalchemy.ext.asyncio import AsyncSession
from database.database import Database, EntityCRUD
from .. import models as mdl
from .. import schemas as sch
class MovieGenresCRUD(EntityCRUD[mdl.MovieGenre]):
@staticmethod
async def get_all(db: AsyncSession):
return await Database.get_all(db, mdl.MovieGenre)
@staticmethod
async def add(db: AsyncSession,
info: sch.MovieGenreCreate):
movie_genre = mdl.MovieGenre(**info.model_dump())
return await Database.add(db, movie_genre)

View File

@@ -1,45 +1,58 @@
from time import strftime
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from database.crud.movie_actors import MovieActorsCRUD
from database.crud.movie_genres import MovieGenresCRUD
from database.database import Database, EntityCRUD
from .. import models as mdl
from .. import schemas as sch
from ..database import add_transaction
async def get_movies(db: AsyncSession):
return (await db.execute(select(mdl.Movie))).scalars().all()
class MoviesCRUD(EntityCRUD[mdl.Movie]):
@staticmethod
async def get(db: AsyncSession, id: int):
return await Database.get(db, mdl.Movie, id)
@staticmethod
async def get_all(db: AsyncSession):
return await Database.get_all(db, mdl.Movie)
async def get_movie(db: AsyncSession, movie_id: int):
return await db.get(mdl.Movie, movie_id)
@staticmethod
async def change_actors(db: AsyncSession, movie: mdl.Movie, info: sch.MovieCreate):
movie_actors = await MovieActorsCRUD.get_all(db)
if (info.actors):
movie.actors = [
actor for actor in movie_actors if actor.id in info.actors]
@staticmethod
async def change_genres(db: AsyncSession, movie: mdl.Movie, info: sch.MovieCreate):
movie_genres = await MovieGenresCRUD.get_all(db)
if (info.genres):
movie.genres = [
genre for genre in movie_genres if genre.id in info.genres]
async def add_movie(db: AsyncSession,
movie_info: sch.MovieCreate,
user_id: int):
movie = mdl.Movie(**movie_info.model_dump(),
@staticmethod
async def add(db: AsyncSession,
info: sch.MovieCreate,
owner_id: int):
movie = mdl.Movie(**info.model_dump(),
update_date=strftime("%Y-%m-%d %H:%M:%S"),
upload_date=strftime("%Y-%m-%d %H:%M:%S"),
owner_id=user_id)
return await add_transaction(db, movie)
owner_id=owner_id)
await MoviesCRUD.change_genres(db, movie, info)
await MoviesCRUD.change_actors(db, movie, info)
return await Database.add(db, movie)
@staticmethod
async def change(db: AsyncSession,
id: int,
info: sch.MovieCreate):
async def additional_change(db: AsyncSession, movie: mdl.Movie, info: sch.MovieCreate):
await MoviesCRUD.change_genres(db, movie, info)
await MoviesCRUD.change_actors(db, movie, info)
return await Database.change(db, mdl.Movie, id, info, additional_change)
async def edit_movie(db: AsyncSession,
movie_id: int,
movie_info: sch.MovieCreate):
movie = await db.get(mdl.Movie, movie_id)
for key, value in vars(movie_info).items():
if (getattr(movie, key) != value):
setattr(movie, key, value)
setattr(movie, "update_date", strftime("%Y-%m-%d %H:%M:%S"))
await db.commit()
return movie
async def delete_movie(db: AsyncSession,
movie_id: int):
movie = await get_movie(db, movie_id)
await db.delete(movie)
await db.commit()
return movie
@staticmethod
async def delete(db: AsyncSession,
id: int):
return await Database.delete(db, mdl.Movie, id)

View File

@@ -1,25 +1,44 @@
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from database.database import Database, EntityCRUD
from .. import models as mdl
from .. import schemas as sch
from ..database import add_transaction
async def get_user(db: AsyncSession, username: str):
class UsersCRUD(EntityCRUD[mdl.User]):
@staticmethod
async def get(db: AsyncSession, username: str):
return (await db.execute(select(mdl.User).where(mdl.User.name == username))).scalar()
@staticmethod
async def get_all(db: AsyncSession):
return await Database.get_all(db, mdl.User)
async def add_user(db: AsyncSession,
user_data: sch.UserCreate, hash_of_password: str):
@staticmethod
async def add(db: AsyncSession,
info: sch.UserCreate,
hash_of_password: str):
user_data_db = \
{k: v for k, v in user_data.model_dump().items()
{k: v for k, v in info.model_dump().items()
if k != "password"}
user = mdl.User(**user_data_db,
hash_of_password=hash_of_password)
return await add_transaction(db, user)
return await Database.add(db, user)
@staticmethod
async def change(db: AsyncSession,
id: int,
info: sch.UserCreate):
return await Database.change(db, mdl.User, id, info)
@staticmethod
async def delete_user(db: AsyncSession,
id: int):
return await Database.delete(db, mdl.User, id)
@staticmethod
async def check_email(db: AsyncSession, email: str):
users = (await db.execute(select(mdl.User)
.where(mdl.User.email == email))).scalars().all()

View File

@@ -1,4 +1,8 @@
from abc import ABC, abstractmethod
from time import strftime
from typing import Any, Callable, Coroutine, Generic, Type
from sqlalchemy.orm import sessionmaker
from sqlalchemy.future import select
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
@@ -15,27 +19,37 @@ async_session = sessionmaker( # type: ignore
Base = declarative_base()
class Database:
@staticmethod
async def get_session() -> AsyncSession: # type: ignore
async with async_session() as session: # type: ignore
yield session # type: ignore
@staticmethod
async def drop_all():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
@staticmethod
async def create_all():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
@staticmethod
async def recreate_all():
await drop_all()
await create_all()
await Database.drop_all()
await Database.create_all()
@staticmethod
async def get[T](db: AsyncSession, typeof_entity: Type[T], entity_id: int) -> T | None:
return await db.get(typeof_entity, entity_id)
async def add_transaction[T](db: AsyncSession, entity: T) -> T:
@staticmethod
async def get_all[T](db: AsyncSession, typeof_entity: Type[T]) -> list[T]:
return list((await db.execute(select(typeof_entity))).scalars().all())
@staticmethod
async def add[T](db: AsyncSession, entity: T) -> T:
try:
db.add(entity)
await db.commit()
@@ -44,3 +58,64 @@ async def add_transaction[T](db: AsyncSession, entity: T) -> T:
except Exception as ex:
await db.rollback()
raise ex
@staticmethod
async def change[T, U](db: AsyncSession, typeof_entity: Type[T],
entity_id: int, info: U,
additional_change: Callable[[AsyncSession, T, U], Coroutine[Any, Any, None]] | None = None) -> T:
try:
entity = await db.get(typeof_entity, entity_id)
if (entity is None):
raise ValueError(f"Can't change entity. " +
f"{str(typeof_entity)} with id={entity_id} not found")
for key, value in vars(info).items():
try:
if (getattr(entity, key) != value):
setattr(entity, key, value)
except:
...
setattr(entity, "update_date", strftime("%Y-%m-%d %H:%M:%S"))
if (additional_change):
await additional_change(db, entity, info)
await db.commit()
return entity
except Exception as ex:
await db.rollback()
raise ex
@staticmethod
async def delete[T](db: AsyncSession, typeof_entity: Type[T], entity_id: int) -> T:
try:
entity = await db.get(typeof_entity, entity_id)
if (entity is None):
raise ValueError(f"Can't delete entity. " +
f"{str(typeof_entity)} with id={entity_id} not found")
await db.delete(entity)
await db.commit()
return entity
except Exception as ex:
await db.rollback()
raise ex
class EntityCRUD[T](ABC):
@staticmethod
@abstractmethod
async def get(db: AsyncSession, id: int) -> T | None: ...
@staticmethod
@abstractmethod
async def get_all(db: AsyncSession) -> list[T]: ...
@staticmethod
@abstractmethod
async def add(db: AsyncSession, entity: T,
owner_id: int | None = None) -> T: ...
@staticmethod
@abstractmethod
async def change(db: AsyncSession, entity_id: int, info: object) -> T: ...
@staticmethod
@abstractmethod
async def delete(db: AsyncSession, entity_id: int) -> T: ...

View File

@@ -11,7 +11,7 @@ class AudiobookGenre(Base):
genre = Column(String, nullable=False, unique=True)
audiobooks = relationship("Audiobook", secondary="audiobook_to_genre",
lazy="selectin")
lazy="selectin", viewonly=True)
class AudiobookToGenre(Base):

View File

@@ -27,3 +27,4 @@ class Audiobook(Base):
lazy="selectin")
owner_id = Column(Integer, ForeignKey("users.id"))
owner = relationship("User", lazy="selectin", viewonly=True)

View File

@@ -11,7 +11,7 @@ class GameGenre(Base):
genre = Column(String, nullable=False, unique=True)
games = relationship("Game", secondary="game_to_genre",
lazy="selectin")
lazy="selectin", viewonly=True)
class GameToGenre(Base):

View File

@@ -10,8 +10,8 @@ class MovieActor(Base):
id = Column(Integer, primary_key=True)
actor = Column(String, nullable=False, unique=True)
movies = relationship("Movies", secondary="movie_to_actor",
lazy="selectin")
movies = relationship("Movie", secondary="movie_to_actor",
lazy="selectin", viewonly=True)
class MovieToActor(Base):

View File

@@ -10,8 +10,8 @@ class MovieGenre(Base):
id = Column(Integer, primary_key=True)
genre = Column(String, nullable=False, unique=True)
movies = relationship("Movies", secondary="movie_to_genre",
lazy="selectin")
movies = relationship("Movie", secondary="movie_to_genre",
lazy="selectin", viewonly=True)
class MovieToGenre(Base):

View File

@@ -32,3 +32,4 @@ class Movie(Base):
lazy="selectin")
owner_id = Column(Integer, ForeignKey("users.id"))
owner = relationship("User", lazy="selectin", viewonly=True)

View File

@@ -13,10 +13,19 @@ app = FastAPI(
"url": "https://github.com/StepanovPlaton"
},
)
app.include_router(startup_router)
app.include_router(games_router)
app.include_router(game_genres_router)
app.include_router(movies_router)
app.include_router(movie_actors_router)
app.include_router(movie_genres_router)
app.include_router(audiobooks_router)
app.include_router(audiobook_genres_router)
app.include_router(files_router)
app.include_router(auth_router)
app.mount("/content", StaticFiles(directory="content"), name="content")

View File

@@ -1,6 +1,13 @@
from .games import games_router as games_router
from .game_genres import game_genres_router as game_genres_router
from .movies import movies_router as movies_router
from .movie_actors import movie_actors_router as movie_actors_router
from .movie_genres import movie_genres_router as movie_genres_router
from .audiobooks import audiobooks_router as audiobooks_router
from .audiobook_genres import audiobook_genres_router as audiobook_genres_router
from .files import files_router as files_router
from .startup import startup_router as startup_router
from .auth import auth_router as auth_router

View File

@@ -0,0 +1,22 @@
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import APIRouter, Depends, HTTPException, status
from database import *
from file_handler import *
from routes.auth import get_user
audiobook_genres_router = APIRouter(
prefix="/genres/audiobooks", tags=["Audiobooks", "Genres"])
@audiobook_genres_router.get("", response_model=list[AudiobookGenre])
async def get_audiobook_genres(db_session: AsyncSession = Depends(Database.get_session)):
return await AudiobookGenresCRUD.get_all(db_session)
@audiobook_genres_router.post("", response_model=AudiobookGenre)
async def add_audiobook_genre(genre: AudiobookGenreCreate,
user: User = Depends(get_user),
db_session: AsyncSession = Depends(Database.get_session)):
return await AudiobookGenresCRUD.add(db_session, genre)

View File

@@ -1,41 +1,41 @@
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import APIRouter, Depends, HTTPException, status
import database as db
from database import *
from file_handler import *
from routes.auth import get_user
audiobooks_router = APIRouter(prefix="/audiobooks", tags=["Audiobooks"])
@audiobooks_router.get("", response_model=list[db.Audiobook])
async def get_audiobooks(db_session: AsyncSession = Depends(db.get_session)):
return await db.get_audiobooks(db_session)
@audiobooks_router.get("/{audiobook_id}", response_model=Audiobook)
async def get_audiobook(audiobook_id: int, db_session: AsyncSession = Depends(Database.get_session)):
return await AudiobooksCRUD.get(db_session, audiobook_id)
@audiobooks_router.post("", response_model=db.Audiobook)
async def add_audiobook(audiobook: db.AudiobookCreate,
user: db.User = Depends(get_user),
db_session: AsyncSession = Depends(db.get_session)):
return await db.add_audiobook(db_session, audiobook, user.id)
@audiobooks_router.get("/cards", response_model=list[AudiobookCard])
async def get_audiobooks_cards(db_session: AsyncSession = Depends(Database.get_session)):
return await AudiobooksCRUD.get_all(db_session)
@audiobooks_router.get("/cards", response_model=list[db.AudiobookCard])
async def get_audiobooks_cards(db_session: AsyncSession = Depends(db.get_session)):
return await db.get_audiobooks(db_session)
@audiobooks_router.get("", response_model=list[Audiobook])
async def get_audiobooks(db_session: AsyncSession = Depends(Database.get_session)):
return await AudiobooksCRUD.get_all(db_session)
@audiobooks_router.get("/{audiobook_id}", response_model=db.Audiobook)
async def get_audiobook(audiobook_id: int, db_session: AsyncSession = Depends(db.get_session)):
return await db.get_audiobook(db_session, audiobook_id)
@audiobooks_router.post("", response_model=Audiobook)
async def add_audiobook(audiobook: AudiobookCreate,
user: User = Depends(get_user),
db_session: AsyncSession = Depends(Database.get_session)):
return await AudiobooksCRUD.add(db_session, audiobook, user.id)
@audiobooks_router.put("/{audiobook_id}", response_model=db.Audiobook)
@audiobooks_router.put("/{audiobook_id}", response_model=Audiobook)
async def edit_audiobook(audiobook_id: int,
audiobook: db.AudiobookCreate,
user: db.User = Depends(get_user),
db_session: AsyncSession = Depends(db.get_session)):
audiobook_db = await db.get_audiobook(db_session, audiobook_id)
audiobook: AudiobookCreate,
user: User = Depends(get_user),
db_session: AsyncSession = Depends(Database.get_session)):
audiobook_db = await AudiobooksCRUD.get(db_session, audiobook_id)
if (audiobook_db is None):
raise HTTPException(status.HTTP_404_NOT_FOUND,
detail=f"Audiobook with id={audiobook_id} not found")
@@ -43,14 +43,14 @@ async def edit_audiobook(audiobook_id: int,
raise HTTPException(status.HTTP_401_UNAUTHORIZED,
detail=f"Audiobook can only be edited "
"by the owner (creator)")
return await db.edit_audiobook(db_session, audiobook_id, audiobook)
return await AudiobooksCRUD.change(db_session, audiobook_id, audiobook)
@audiobooks_router.delete("/{audiobook_id}", response_model=db.Audiobook)
@audiobooks_router.delete("/{audiobook_id}", response_model=Audiobook)
async def delete_audiobook(audiobook_id: int,
user: db.User = Depends(get_user),
db_session: AsyncSession = Depends(db.get_session)):
audiobook_db = await db.get_audiobook(db_session, audiobook_id)
user: User = Depends(get_user),
db_session: AsyncSession = Depends(Database.get_session)):
audiobook_db = await AudiobooksCRUD.get(db_session, audiobook_id)
if (audiobook_db is None):
raise HTTPException(status.HTTP_404_NOT_FOUND,
detail=f"Audiobook with id={audiobook_id} not found")
@@ -58,4 +58,4 @@ async def delete_audiobook(audiobook_id: int,
raise HTTPException(status.HTTP_401_UNAUTHORIZED,
detail=f"Audiobook can only be deleted "
"by the owner (creator)")
return await db.delete_audiobook(db_session, audiobook_id)
return await AudiobooksCRUD.delete(db_session, audiobook_id)

View File

@@ -1,13 +1,12 @@
from typing import Annotated, Any
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from passlib.context import CryptContext
from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, Depends, status, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from pydantic import BaseModel
from jose import JWTError, jwt
from jose import jwt
import database as db
from database import *
from env import Env
SECRET_KEY = Env.get_strict("JWT_SECRET_KEY", str)
@@ -36,7 +35,7 @@ def get_hash(password): return crypt.hash(password)
async def get_user(token: str = Depends(oauth2_scheme),
db_session: AsyncSession = Depends(db.get_session)):
db_session: AsyncSession = Depends(Database.get_session)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
@@ -48,13 +47,13 @@ async def get_user(token: str = Depends(oauth2_scheme),
except Exception as e:
print(e)
raise credentials_exception
user = await db.get_user(db_session, token_data.username)
user = await UsersCRUD.get(db_session, token_data.username)
if user is None:
raise credentials_exception
return user
def create_token(user: db.User):
def create_token(user: User):
access_token_expires = \
timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
expire = datetime.now(timezone.utc) + access_token_expires
@@ -70,23 +69,23 @@ def create_token(user: db.User):
@auth_router.post("/registration")
async def registration_user(
user_data: db.UserCreate,
db_session: AsyncSession = Depends(db.get_session)
user_data: UserCreate,
db_session: AsyncSession = Depends(Database.get_session)
) -> Token:
if (not await db.check_email(db_session, user_data.email)):
if (not await UsersCRUD.check_email(db_session, user_data.email)):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="This email is occupied by another user",
headers={"WWW-Authenticate": "Bearer"},
)
elif (await db.get_user(db_session, user_data.name) is not None):
elif (await UsersCRUD.get(db_session, user_data.name) is not None):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User with the same name already exists",
headers={"WWW-Authenticate": "Bearer"},
)
else:
user = await db.add_user(db_session, user_data,
user = await UsersCRUD.add(db_session, user_data,
get_hash(user_data.password))
return create_token(user)
@@ -94,9 +93,9 @@ async def registration_user(
@auth_router.post("")
async def login_user(
auth_data: OAuth2PasswordRequestForm = Depends(),
db_session: AsyncSession = Depends(db.get_session)
db_session: AsyncSession = Depends(Database.get_session)
) -> Token:
user = await db.get_user(db_session, auth_data.username)
user = await UsersCRUD.get(db_session, auth_data.username)
if (user is None):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
@@ -112,6 +111,6 @@ async def login_user(
return create_token(user)
@auth_router.get("/me", response_model=db.UserOpenData)
async def read_me(user: db.User = Depends(get_user)):
@auth_router.get("/me", response_model=UserOpenData)
async def read_me(user: User = Depends(get_user)):
return user

22
routes/game_genres.py Normal file
View File

@@ -0,0 +1,22 @@
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import APIRouter, Depends, HTTPException, status
from database import *
from file_handler import *
from routes.auth import get_user
game_genres_router = APIRouter(
prefix="/genres/games", tags=["Games", "Genres"])
@game_genres_router.get("", response_model=list[GameGenre])
async def get_game_genres(db_session: AsyncSession = Depends(Database.get_session)):
return await GameGenresCRUD.get_all(db_session)
@game_genres_router.post("", response_model=GameGenre)
async def add_game_genre(genre: GameGenreCreate,
user: User = Depends(get_user),
db_session: AsyncSession = Depends(Database.get_session)):
return await GameGenresCRUD.add(db_session, genre)

View File

@@ -1,41 +1,42 @@
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import APIRouter, Depends, HTTPException, status
import database as db
from database import *
from file_handler import *
from routes.auth import get_user
games_router = APIRouter(prefix="/games", tags=["Games"])
@games_router.get("", response_model=list[db.Game])
async def get_games(db_session: AsyncSession = Depends(db.get_session)):
return await db.get_games(db_session)
@games_router.get("/{game_id}", response_model=Game)
async def get_game(game_id: int, db_session: AsyncSession = Depends(Database.get_session)):
return await GamesCRUD.get(db_session, game_id)
@games_router.post("", response_model=db.Game)
async def add_game(game: db.GameCreate,
user: db.User = Depends(get_user),
db_session: AsyncSession = Depends(db.get_session)):
return await db.add_game(db_session, game, user.id)
@games_router.get("/cards", response_model=list[GameCard])
async def get_games_cards(db_session: AsyncSession = Depends(Database.get_session)):
return await GamesCRUD.get_all(db_session)
@games_router.get("/cards", response_model=list[db.GameCard])
async def get_games_cards(db_session: AsyncSession = Depends(db.get_session)):
return await db.get_games(db_session)
@games_router.get("", response_model=list[Game])
async def get_games(db_session: AsyncSession = Depends(Database.get_session)):
return await GamesCRUD.get_all(db_session)
@games_router.get("/{game_id}", response_model=db.Game)
async def get_game(game_id: int, db_session: AsyncSession = Depends(db.get_session)):
return await db.get_game(db_session, game_id)
@games_router.post("", response_model=Game)
async def add_game(game: GameCreate,
user: User = Depends(get_user),
db_session: AsyncSession = Depends(Database.get_session)):
return await GamesCRUD.add(db_session, game, user.id)
@games_router.put("/{game_id}", response_model=db.Game)
@games_router.put("/{game_id}", response_model=Game)
async def edit_game(game_id: int,
game: db.GameCreate,
user: db.User = Depends(get_user),
db_session: AsyncSession = Depends(db.get_session)):
game_db = await db.get_game(db_session, game_id)
game: GameCreate,
user: User = Depends(get_user),
db_session: AsyncSession = Depends(Database.get_session)):
game_db = await GamesCRUD.get(db_session, game_id)
if (game_db is None):
raise HTTPException(status.HTTP_404_NOT_FOUND,
detail=f"Game with id={game_id} not found")
@@ -43,14 +44,14 @@ async def edit_game(game_id: int,
raise HTTPException(status.HTTP_401_UNAUTHORIZED,
detail=f"Game can only be edited "
"by the owner (creator)")
return await db.edit_game(db_session, game_id, game)
return await GamesCRUD.change(db_session, game_id, game)
@games_router.delete("/{game_id}", response_model=db.Game)
@games_router.delete("/{game_id}", response_model=Game)
async def delete_game(game_id: int,
user: db.User = Depends(get_user),
db_session: AsyncSession = Depends(db.get_session)):
game_db = await db.get_game(db_session, game_id)
user: User = Depends(get_user),
db_session: AsyncSession = Depends(Database.get_session)):
game_db = await GamesCRUD.get(db_session, game_id)
if (game_db is None):
raise HTTPException(status.HTTP_404_NOT_FOUND,
detail=f"Game with id={game_id} not found")
@@ -58,4 +59,4 @@ async def delete_game(game_id: int,
raise HTTPException(status.HTTP_401_UNAUTHORIZED,
detail=f"Game can only be deleted "
"by the owner (creator)")
return await db.delete_game(db_session, game_id)
return await GamesCRUD.delete(db_session, game_id)

22
routes/movie_actors.py Normal file
View File

@@ -0,0 +1,22 @@
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import APIRouter, Depends, HTTPException, status
from database import *
from file_handler import *
from routes.auth import get_user
movie_actors_router = APIRouter(
prefix="/actors", tags=["Movies", "Actors"])
@movie_actors_router.get("", response_model=list[MovieActor])
async def get_movie_actors(db_session: AsyncSession = Depends(Database.get_session)):
return await MovieActorsCRUD.get_all(db_session)
@movie_actors_router.post("", response_model=MovieActor)
async def add_movie_actor(actor: MovieActorCreate,
user: User = Depends(get_user),
db_session: AsyncSession = Depends(Database.get_session)):
return await MovieActorsCRUD.add(db_session, actor)

22
routes/movie_genres.py Normal file
View File

@@ -0,0 +1,22 @@
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import APIRouter, Depends, HTTPException, status
from database import *
from file_handler import *
from routes.auth import get_user
movie_genres_router = APIRouter(
prefix="/genres/movies", tags=["Movies", "Genres"])
@movie_genres_router.get("", response_model=list[MovieGenre])
async def get_movie_genres(db_session: AsyncSession = Depends(Database.get_session)):
return await MovieGenresCRUD.get_all(db_session)
@movie_genres_router.post("", response_model=MovieGenre)
async def add_movie_genre(genre: MovieGenreCreate,
user: User = Depends(get_user),
db_session: AsyncSession = Depends(Database.get_session)):
return await MovieGenresCRUD.add(db_session, genre)

View File

@@ -1,41 +1,41 @@
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import APIRouter, Depends, HTTPException, status
import database as db
from database import *
from file_handler import *
from routes.auth import get_user
movies_router = APIRouter(prefix="/movies", tags=["Movies"])
@movies_router.get("", response_model=list[db.Movie])
async def get_movies(db_session: AsyncSession = Depends(db.get_session)):
return await db.get_movies(db_session)
@movies_router.get("/{movie_id}", response_model=Movie)
async def get_movie(movie_id: int, db_session: AsyncSession = Depends(Database.get_session)):
return await MoviesCRUD.get(db_session, movie_id)
@movies_router.post("", response_model=db.Movie)
async def add_movie(movie: db.MovieCreate,
user: db.User = Depends(get_user),
db_session: AsyncSession = Depends(db.get_session)):
return await db.add_movie(db_session, movie, user.id)
@movies_router.get("/cards", response_model=list[MovieCard])
async def get_movies_cards(db_session: AsyncSession = Depends(Database.get_session)):
return await MoviesCRUD.get_all(db_session)
@movies_router.get("/cards", response_model=list[db.MovieCard])
async def get_movies_cards(db_session: AsyncSession = Depends(db.get_session)):
return await db.get_movies(db_session)
@movies_router.get("", response_model=list[Movie])
async def get_movies(db_session: AsyncSession = Depends(Database.get_session)):
return await MoviesCRUD.get_all(db_session)
@movies_router.get("/{movie_id}", response_model=db.Movie)
async def get_movie(movie_id: int, db_session: AsyncSession = Depends(db.get_session)):
return await db.get_movie(db_session, movie_id)
@movies_router.post("", response_model=Movie)
async def add_movie(movie: MovieCreate,
user: User = Depends(get_user),
db_session: AsyncSession = Depends(Database.get_session)):
return await MoviesCRUD.add(db_session, movie, user.id)
@movies_router.put("/{movie_id}", response_model=db.Movie)
@movies_router.put("/{movie_id}", response_model=Movie)
async def edit_movie(movie_id: int,
movie: db.MovieCreate,
user: db.User = Depends(get_user),
db_session: AsyncSession = Depends(db.get_session)):
movie_db = await db.get_movie(db_session, movie_id)
movie: MovieCreate,
user: User = Depends(get_user),
db_session: AsyncSession = Depends(Database.get_session)):
movie_db = await MoviesCRUD.get(db_session, movie_id)
if (movie_db is None):
raise HTTPException(status.HTTP_404_NOT_FOUND,
detail=f"Movie with id={movie_id} not found")
@@ -43,14 +43,14 @@ async def edit_movie(movie_id: int,
raise HTTPException(status.HTTP_401_UNAUTHORIZED,
detail=f"Movie can only be edited "
"by the owner (creator)")
return await db.edit_movie(db_session, movie_id, movie)
return await MoviesCRUD.change(db_session, movie_id, movie)
@movies_router.delete("/{movie_id}", response_model=db.Movie)
@movies_router.delete("/{movie_id}", response_model=Movie)
async def delete_movie(movie_id: int,
user: db.User = Depends(get_user),
db_session: AsyncSession = Depends(db.get_session)):
movie_db = await db.get_movie(db_session, movie_id)
user: User = Depends(get_user),
db_session: AsyncSession = Depends(Database.get_session)):
movie_db = await MoviesCRUD.get(db_session, movie_id)
if (movie_db is None):
raise HTTPException(status.HTTP_404_NOT_FOUND,
detail=f"Movie with id={movie_id} not found")
@@ -58,4 +58,4 @@ async def delete_movie(movie_id: int,
raise HTTPException(status.HTTP_401_UNAUTHORIZED,
detail=f"Movie can only be deleted "
"by the owner (creator)")
return await db.delete_movie(db_session, movie_id)
return await MoviesCRUD.delete(db_session, movie_id)