diff --git a/src/domain/schemas/book_schemas.py b/src/domain/schemas/book_schemas.py index 0986618a..df507a99 100644 --- a/src/domain/schemas/book_schemas.py +++ b/src/domain/schemas/book_schemas.py @@ -48,6 +48,7 @@ class DomainReqAdminPostBook(BaseModel): version: Optional[str] = Field(title="version", description="판본", default=None) major: bool = Field(title="major", description="전공 책 여부", default=False) language: str = Field(title="language", description="언어", default="KOREAN") + book_status: bool = Field(title="book_status", description="도서 상태", default=True) donor_name: Optional[str] = Field(title="donor_name", description="기부자명", default=None) class DomainResAdminPostBook(BaseModel): @@ -63,12 +64,14 @@ class DomainResAdminPostBook(BaseModel): version: Optional[str] = Field(title="version", description="판본", default=None) major: bool = Field(title="major", description="전공 책 여부", default=False) language: str = Field(title="language", description="언어", default="KOREAN") - book_status : bool = Field(title="book_status", description="도서 상태", default=True) + book_status: bool = Field(title="book_status", description="도서 상태", default=True) + donor_name: Optional[str] = Field(title="donor_name", description="기부자명", default=None) created_at: datetime = Field(title="create_at", description="생성일시", example=datetime.now()) updated_at: datetime = Field(title="update_at", description="수정일시", example=datetime.now()) class DomainReqAdminPutBook(BaseModel): + book_id: int = Field(title="book_id", description="책 ID", gt=0) book_title: str = Field(title="book_title", description="책 제목", example="FastAPI Tutorial") code: str = Field(title="code", description="책 코드", examples="A3") category_name: str = Field(title="category_name", description="카테고리명", examples="웹") @@ -80,6 +83,7 @@ class DomainReqAdminPutBook(BaseModel): version: Optional[str] = Field(title="version", description="판본", default=None) major: bool = Field(title="major", description="전공 책 여부", default=False) language: str = Field(title="language", description="언어", default="KOREAN") + book_status: bool = Field(title="book_status", description="도서 상태", default=True) donor_name: Optional[str] = Field(title="donor_name", description="기부자명", default=None) class DomainResAdminPutBook(BaseModel): @@ -95,7 +99,10 @@ class DomainResAdminPutBook(BaseModel): version: Optional[str] = Field(title="version", description="판본", default=None) major: bool = Field(title="major", description="전공 책 여부", default=False) language: str = Field(title="language", description="언어", default="KOREAN") - book_status : bool = Field(title="book_status", description="도서 상태", default=True) + book_status: bool = Field(title="book_status", description="도서 상태", default=True) donor_name: Optional[str] = Field(title="donor_name", description="기부자명", default=None) created_at: datetime = Field(title="create_at", description="생성일시", example=datetime.now()) updated_at: datetime = Field(title="update_at", description="수정일시", example=datetime.now()) + +class DomainReqAdminDelBook(BaseModel): + book_id: int = Field(title="book_id", description="책 ID", gt=0) diff --git a/src/domain/services/admin/book_service.py b/src/domain/services/admin/book_service.py index 36c7d5f0..9ad965f0 100644 --- a/src/domain/services/admin/book_service.py +++ b/src/domain/services/admin/book_service.py @@ -5,8 +5,15 @@ from sqlalchemy.orm import Session from domain.enums.book_category import BookCategoryStatus -from domain.schemas.book_schemas import DomainReqAdminPostBook, DomainResAdminPostBook +from domain.schemas.book_schemas import ( + DomainReqAdminDelBook, + DomainReqAdminPostBook, + DomainReqAdminPutBook, + DomainResAdminPostBook, + DomainResAdminPutBook, +) from repositories.models import Book +from utils.crud_utils import delete_item async def service_admin_create_book(request: DomainReqAdminPostBook, db: Session): @@ -34,7 +41,7 @@ async def service_admin_create_book(request: DomainReqAdminPostBook, db: Session image_url = request.image_url, version = request.version, major = request.major, - book_status = True, + book_status = request.book_status, donor_name = request.donor_name, created_at = datetime.now(), updated_at = datetime.now(), @@ -69,3 +76,69 @@ async def service_admin_create_book(request: DomainReqAdminPostBook, db: Session updated_at=new_book.updated_at ) return domain_res + +async def service_admin_update_book(request: DomainReqAdminPutBook, db: Session): + stmt = select(Book).where(Book.id == request.book_id) + request_book = db.execute(stmt).scalar_one_or_none() + + if not request_book: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, + detail="Requested Book Not Found") + if request.code[0] not in {category.name for category in BookCategoryStatus}: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, + detail="Invalid Category") + if request.category_name not in {category.category for category in BookCategoryStatus}: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, + detail="Invalid Category") + + requested_book = request_book.__dict__ + updated_book = request.__dict__ + + try: + for key, value in updated_book.items(): + if value is not None and key in requested_book: + if isinstance(value, type(requested_book[key])): + setattr(request_book, key, value) + else: + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail=f"Invalid value type for column {key}. \ + Expected {type(request_book[key])}, got {type(value)}." + ) + request_book.updated_at = datetime.now() + db.add(request_book) + db.flush() + except Exception as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Unexpected error occurred during update: {str(e)}", + ) from e + else: + db.commit() + db.refresh(request_book) + + domain_res = DomainResAdminPutBook( + book_id=request_book.id, + book_title=request_book.book_title, + code=request_book.code, + category_name=request_book.category_name, + subtitle=request_book.subtitle, + author=request_book.author, + publisher=request_book.publisher, + publication_year=request_book.publication_year, + image_url=request_book.image_url, + version=request_book.version, + major=request_book.major, + language=request_book.language, + book_status=request_book.book_status, + donor_name=request_book.donor_name, + created_at=request_book.created_at, + updated_at=request_book.updated_at + ) + + return domain_res + +async def service_admin_delete_book(request: DomainReqAdminDelBook, db: Session): + delete_item(Book, request.book_id, db) + return diff --git a/src/routes/admin/admin_books_route.py b/src/routes/admin/admin_books_route.py index 2a6ce563..98e331d8 100644 --- a/src/routes/admin/admin_books_route.py +++ b/src/routes/admin/admin_books_route.py @@ -2,10 +2,14 @@ from sqlalchemy.orm import Session from dependencies import get_current_admin, get_db -from domain.schemas.book_schemas import DomainReqAdminPostBook -from domain.services.admin.book_service import service_admin_create_book -from routes.admin.request.book_request import RouteReqAdminPostBook -from routes.admin.response.book_response import RouteResAdminPostBook +from domain.schemas.book_schemas import DomainReqAdminDelBook, DomainReqAdminPostBook, DomainReqAdminPutBook +from domain.services.admin.book_service import ( + service_admin_create_book, + service_admin_delete_book, + service_admin_update_book, +) +from routes.admin.request.book_request import RouteReqAdminPostBook, RouteReqAdminPutBook +from routes.admin.response.book_response import RouteResAdminPostBook, RouteResAdminPutBook router = APIRouter( prefix="/admin/books", @@ -17,6 +21,7 @@ @router.post( "/", summary="관리자 도서 정보 등록", + response_model=RouteResAdminPostBook, status_code=status.HTTP_201_CREATED ) async def create_admin_book( @@ -35,11 +40,61 @@ async def create_admin_book( version = request.version, major = request.major, language=request.language, + book_status=request.book_status, donor_name = request.donor_name ) domain_res = await service_admin_create_book(domain_req, db) result = RouteResAdminPostBook( - book_id=domain_res.id, + book_id=domain_res.book_id, + book_title=domain_res.book_title, + code=domain_res.code, + category_name=domain_res.category_name, + subtitle=domain_res.subtitle, + author=domain_res.author, + publisher=domain_res.publisher, + publication_year=domain_res.publication_year, + image_url=domain_res.image_url, + version=domain_res.version, + major=domain_res.major, + language=domain_res.language, + book_status=domain_res.book_status, + donor_name=domain_res.donor_name, + created_at=domain_res.created_at, + updated_at=domain_res.updated_at + ) + return result + + +@router.put( + "/{book_id}", + summary="관리자 도서 정보 수정", + response_model=RouteResAdminPutBook, + status_code=status.HTTP_200_OK +) +async def update_admin_book( + book_id: int, + request: RouteReqAdminPutBook, + db: Session = Depends(get_db), +): + domain_req = DomainReqAdminPutBook( + book_id= book_id, + book_title = request.book_title, + code=request.code, + category_name = request.category_name, + subtitle=request.subtitle, + author=request.author, + publisher=request.publisher, + publication_year=request.publication_year, + image_url = request.image_url, + version = request.version, + major = request.major, + language=request.language, + book_status=request.book_status, + donor_name = request.donor_name + ) + domain_res = await service_admin_update_book(domain_req, db) + result = RouteResAdminPutBook( + book_id=domain_res.book_id, book_title=domain_res.book_title, code=domain_res.code, category_name=domain_res.category_name, @@ -57,3 +112,18 @@ async def create_admin_book( updated_at=domain_res.updated_at ) return result + +@router.delete( + "/{book_id}", + summary="관리자 도서 정보 등록", + status_code=status.HTTP_204_NO_CONTENT +) +async def delete_admin_book( + book_id: int, + db: Session = Depends(get_db), +): + domain_req = DomainReqAdminDelBook( + book_id=book_id + ) + await service_admin_delete_book(domain_req, db) + return diff --git a/src/routes/admin/request/book_request.py b/src/routes/admin/request/book_request.py index c97ce86e..2bfe16eb 100644 --- a/src/routes/admin/request/book_request.py +++ b/src/routes/admin/request/book_request.py @@ -15,4 +15,20 @@ class RouteReqAdminPostBook(BaseModel): version: Optional[str] = Field(title="version", description="판본", default=None) major: bool = Field(title="major", description="전공 책 여부", default=False) language: str = Field(title="language", description="언어", default="KOREAN") + book_status: bool = Field(title="book_status", description="도서 상태", default=True) + donor_name: Optional[str] = Field(title="donor_name", description="기부자명", default=None) + +class RouteReqAdminPutBook(BaseModel): + book_title: str = Field(title="book_title", description="책 제목", example="FastAPI Tutorial") + code: str = Field(title="code", description="책 코드", example="A3") + category_name: str = Field(title="category_name", description="카테고리명", example="웹") + subtitle: Optional[str] = Field(title="subtitle", description="책 부제", default=None) + author : str = Field(title="author", description="저자") + publisher: str = Field(title="publisher", description="출판사") + publication_year: int = Field(title="publication_year", description="출판연도", gt=0) + image_url: Optional[str] = Field(title="image_url", description="책 표지", default=None) + version: Optional[str] = Field(title="version", description="판본", default=None) + major: bool = Field(title="major", description="전공 책 여부", default=False) + language: str = Field(title="language", description="언어", default="KOREAN") + book_status: bool = Field(title="book_status", description="도서 상태", default=True) donor_name: Optional[str] = Field(title="donor_name", description="기부자명", default=None) diff --git a/src/routes/admin/response/book_response.py b/src/routes/admin/response/book_response.py index e162ada6..6839ce89 100644 --- a/src/routes/admin/response/book_response.py +++ b/src/routes/admin/response/book_response.py @@ -7,8 +7,8 @@ class RouteResAdminPostBook(BaseModel): book_id: int = Field(title="book_id", description="책 ID", gt=0) book_title: str = Field(title="book_title", description="책 제목", example="FastAPI Tutorial") - code: str = Field(title="code", description="책 코드", examples="A3") - category_name: str = Field(title="category_name", description="카테고리명", examples="웹") + code: str = Field(title="code", description="책 코드", example="A3") + category_name: str = Field(title="category_name", description="카테고리명", example="웹") subtitle: Optional[str] = Field(title="subtitle", description="책 부제", default=None) author : str = Field(title="author", description="저자") publisher: str = Field(title="publisher", description="출판사") @@ -17,7 +17,25 @@ class RouteResAdminPostBook(BaseModel): version: Optional[str] = Field(title="version", description="판본", default=None) major: bool = Field(title="major", description="전공 책 여부", default=False) language: str = Field(title="language", description="언어", default="KOREAN") - book_status : bool = Field(title="book_status", description="도서 상태", default=True) + book_status: bool = Field(title="book_status", description="도서 상태", default=True) + donor_name: Optional[str] = Field(title="donor_name", description="기부자명", default=None) + created_at: datetime = Field(title="create_at", description="생성일시", example=datetime.now()) + updated_at: datetime = Field(title="update_at", description="수정일시", example=datetime.now()) + +class RouteResAdminPutBook(BaseModel): + book_id: int = Field(title="book_id", description="책 ID", gt=0) + book_title: str = Field(title="book_title", description="책 제목", example="FastAPI Tutorial") + code: str = Field(title="code", description="책 코드", example="A3") + category_name: str = Field(title="category_name", description="카테고리명", example="웹") + subtitle: Optional[str] = Field(title="subtitle", description="책 부제", default=None) + author : str = Field(title="author", description="저자") + publisher: str = Field(title="publisher", description="출판사") + publication_year: int = Field(title="publication_year", description="출판연도", gt=0) + image_url: Optional[str] = Field(title="image_url", description="책 표지", default=None) + version: Optional[str] = Field(title="version", description="판본", default=None) + major: bool = Field(title="major", description="전공 책 여부", default=False) + language: str = Field(title="language", description="언어", default="KOREAN") + book_status: bool = Field(title="book_status", description="도서 상태", default=True) donor_name: Optional[str] = Field(title="donor_name", description="기부자명", default=None) created_at: datetime = Field(title="create_at", description="생성일시", example=datetime.now()) updated_at: datetime = Field(title="update_at", description="수정일시", example=datetime.now())