diff --git a/docker-compose.yml b/docker-compose.yml index 1f1b42e..6035554 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ services: env_file: - .env ports: - - "5432:5432" + - "5433:5432" volumes: - ./init.sql:/docker-entrypoint-initdb.d/init.sql - postgres_theater_data:/var/lib/postgresql/data/ diff --git a/src/routes/movies.py b/src/routes/movies.py index e44678a..57603c0 100644 --- a/src/routes/movies.py +++ b/src/routes/movies.py @@ -1,12 +1,78 @@ -from fastapi import APIRouter, Depends, HTTPException, Query -from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import Session, joinedload +import math + +from fastapi import APIRouter, Depends, HTTPException, Query, Path + +from sqlalchemy.orm import Session + +from crud.movies import get_movies, create_movie, get_movie, delete_movie, update_movie from database import get_db from database.models import MovieModel, CountryModel, GenreModel, ActorModel, LanguageModel +from schemas.movies import MovieListSchema, MovieCreateSchema, MovieDetailSchema, MovieUpdateSchema, MoviePageSchema + router = APIRouter() -# Write your code here +@router.get("/movies/", response_model=MoviePageSchema) +async def list_movies( + page: int = Query(1, ge=1), + per_page: int = Query(10, ge=1, le=20), + db: Session = Depends(get_db) +): + offset = (page - 1) * per_page + movies_data = get_movies(db, offset, per_page) + + if movies_data: + + total_items = db.query(MovieModel).count() + total_pages = math.ceil(total_items / per_page) + + prev_page = f"/theater/movies/?page={page - 1}&per_page={per_page}" if page > 1 else None + next_page = f"/theater/movies/?page={page + 1}&per_page={per_page}" if page < total_pages else None + + return { + "movies": movies_data, + "prev_page": prev_page, + "next_page": next_page, + "total_pages": total_pages, + "total_items": total_items + } + raise HTTPException(status_code=404, detail="No movies found.") + + +@router.get("/movies/{movie_id}/", response_model=MovieDetailSchema) +async def get_movie_detail( + movie_id: int = Path(..., gt=0), + db: Session = Depends(get_db) +): + movie = get_movie(db, movie_id) + if movie: + return movie + raise HTTPException(status_code=404, detail="Movie with the given ID was not found.") + + +@router.post("/movies/", response_model=MovieDetailSchema, status_code=201) +def add_movie(movie: MovieCreateSchema, db: Session = Depends(get_db)): + movies = db.query(MovieModel).filter( + MovieModel.name == movie.name, + MovieModel.date == movie.date + ).all() + if not movies: + return create_movie(db, movie) + raise HTTPException( + status_code=409, + detail=f"A movie with the name '{movie.name}' and release date '{movie.date}' already exists." + ) + + +@router.delete("/movies/{movie_id}/", status_code=204) +def remove_movie(movie_id: int, db: Session = Depends(get_db)): + delete_movie(db, movie_id) + + +@router.patch("/movies/{movie_id}/") +def patch_movie(movie_id: int, movie: MovieUpdateSchema, db: Session = Depends(get_db)): + update_movie(db, movie_id, movie) + return HTTPException(status_code=200, detail="Movie updated successfully.") diff --git a/src/schemas/movies.py b/src/schemas/movies.py index fabb9be..d3967bb 100644 --- a/src/schemas/movies.py +++ b/src/schemas/movies.py @@ -1 +1,89 @@ -# Write your code here +from datetime import date as date_module, timedelta +from enum import Enum +from typing import Optional, List + +from pydantic import BaseModel, Field + + +class CountrySchema(BaseModel): + id: int + code: str + name: str | None +class GenresSchema(BaseModel): + id: int + name: str + + +class ActorsSchema(BaseModel): + id: int + name: str + + +class LanguagesSchema(BaseModel): + id: int + name: str + + +class MovieStatus(str, Enum): + released = "Released" + post_production = "Post Production" + in_production = "In Production" + + +class MovieListSchema(BaseModel): + id: int + name: str + date: date_module + score: float + overview: str + + +class MoviePageSchema(BaseModel): + movies: List[MovieListSchema] + prev_page: Optional[str] = None + next_page: Optional[str] = None + total_pages: int + total_items: int + + +class MovieDetailSchema(BaseModel): + id: int + name: str + date: date_module + score: float = Field(ge=0, le=100) + overview: str + status: MovieStatus + budget: float = Field(ge=0) + revenue: float = Field(ge=0) + country: CountrySchema + genres: List[GenresSchema] + actors: List[ActorsSchema] + languages: List[LanguagesSchema] + + +class MovieCreateSchema(BaseModel): + name: str = Field(..., max_length=255) + date: date_module = Field(..., le=(date_module.today() + timedelta(days=365))) + score: float = Field(ge=0, le=100) + overview: str + status: MovieStatus + budget: float = Field(ge=0) + revenue: float = Field(ge=0) + country: str + genres: List[str] + actors: List[str] + languages: List[str] + + +class MovieUpdateSchema(BaseModel): + name: Optional[str] = Field(None, max_length=255) + date: Optional[date_module] = Field(None, le=(date_module.today() + timedelta(days=365))) + score: Optional[float] = Field(None, ge=0, le=100) + overview: Optional[str] = None + status: Optional[MovieStatus] = None + budget: Optional[float] = Field(None, ge=0) + revenue: Optional[float] = Field(None, ge=0) + country: Optional[str] = None + genres: Optional[List[str]] = None + actors: Optional[List[str]] = None + languages: Optional[List[str]] = None