-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from wafflestudio/feature/profile
Feature/profile
- Loading branch information
Showing
8 changed files
with
208 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from typing import Annotated | ||
from pydantic import BaseModel | ||
from pydantic.functional_validators import AfterValidator | ||
from watchapedia.app.movie.dto.requests import validate_url | ||
from watchapedia.app.review.dto.requests import validate_content | ||
|
||
class ParticipantProfileUpdateRequest(BaseModel): | ||
name: str | None = None | ||
profile_url: Annotated[str | None, AfterValidator(validate_url)] = None | ||
biography: Annotated[str | None, AfterValidator(validate_content)] = None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
from pydantic import BaseModel | ||
from watchapedia.app.participant.models import Participant | ||
|
||
class MovieDataResponse(BaseModel): | ||
id: int | ||
title: str | ||
year: int | ||
average_rating: float | None | ||
poster_url: str | None | ||
cast : str | None | ||
|
||
|
||
class ParticipantDataResponse(BaseModel): | ||
role: str | ||
movies: list[MovieDataResponse] | ||
|
||
class ParticipantProfileResponse(BaseModel): | ||
id: int | ||
name: str | ||
profile_url: str | None | ||
roles: list[str] | ||
biography: str | None | ||
|
||
@staticmethod | ||
def from_entity(participant: Participant, roles: list[str]) -> "ParticipantProfileResponse": | ||
return ParticipantProfileResponse( | ||
id=participant.id, | ||
name=participant.name, | ||
profile_url=participant.profile_url, | ||
roles=roles, | ||
biography=participant.biography | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
from typing import Annotated | ||
from fastapi import Depends | ||
from watchapedia.app.participant.repository import ParticipantRepository | ||
from watchapedia.app.participant.errors import ParticipantNotFoundError | ||
from watchapedia.common.errors import InvalidFormatError | ||
from watchapedia.app.participant.dto.responses import ParticipantDataResponse, MovieDataResponse, ParticipantProfileResponse | ||
from watchapedia.app.movie.models import Movie | ||
from watchapedia.app.participant.models import Participant | ||
from collections import defaultdict | ||
|
||
class ParticipantService(): | ||
def __init__(self, | ||
participant_repository: Annotated[ParticipantRepository, Depends()] | ||
): | ||
self.participant_repository = participant_repository | ||
|
||
def get_participant_profile(self, participant_id: int) -> ParticipantProfileResponse: | ||
participant = self.participant_repository.get_participant_by_id(participant_id) | ||
tmp = self.get_participant_roles(participant_id) | ||
# 감독과 배우 구분 | ||
roles = set() | ||
for role in tmp: | ||
if "감독" in role: | ||
roles.add("감독") | ||
elif "주연" in role or "조연" in role or "단역" in role: | ||
roles.add("배우") | ||
if participant is None: | ||
raise ParticipantNotFoundError() | ||
return participant, roles | ||
|
||
def get_participant_movies(self, participant_id: int) -> list[ParticipantDataResponse]: | ||
participant = self.participant_repository.get_participant_by_id(participant_id) | ||
if participant is None: | ||
raise ParticipantNotFoundError() | ||
participant_info = {"감독": [], "출연": []} | ||
roles = self.get_participant_roles(participant_id) | ||
casts = set() | ||
for role in roles: | ||
casts.add(role.split("|")[0].strip()) | ||
for cast in casts: | ||
movies = self.participant_repository.get_participant_movies(participant_id, cast) | ||
if cast == "감독": | ||
participant_info["감독"].extend(self._process_movies(movies, cast)) | ||
elif cast in ["주연", "조연", "단역"]: | ||
participant_info["출연"].extend(self._process_movies(movies, cast)) | ||
participant_info["감독"] = sorted(participant_info["감독"], key=lambda x: x.year, reverse=True) # 연도 내림차순 정렬 | ||
participant_info["출연"] = sorted(participant_info["출연"], key=lambda x: x.year, reverse=True) # 연도 내림차순 정렬 | ||
return [self._process_participants(role=cast, movies=movies) for cast, movies in participant_info.items()] | ||
|
||
|
||
def update_participant(self, participant_id: int, name: str | None, profile_url: str | None, biography: str | None): | ||
participant = self.participant_repository.get_participant_by_id(participant_id) | ||
if participant is None: | ||
raise ParticipantNotFoundError() | ||
if not any([name, profile_url, biography]): | ||
raise InvalidFormatError() | ||
self.participant_repository.update_participant(participant, name, profile_url, biography) | ||
|
||
|
||
def get_participant_roles(self, participant_id: int): | ||
return self.participant_repository.get_participant_roles(participant_id) | ||
|
||
def _process_movies(self, movies: list[Movie], cast: str) -> list[MovieDataResponse]: | ||
return [MovieDataResponse(id=movie.id, | ||
title=movie.title, | ||
year=movie.year, | ||
average_rating=movie.average_rating, | ||
poster_url=movie.poster_url, | ||
cast=cast) | ||
for movie in movies] | ||
|
||
def _process_participants(self, role: str, movies: list[MovieDataResponse]) -> ParticipantDataResponse: | ||
return ParticipantDataResponse(role=role, movies=movies) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
from typing import Annotated | ||
from fastapi import APIRouter, Depends | ||
from watchapedia.app.participant.service import ParticipantService | ||
from watchapedia.app.participant.dto.requests import ParticipantProfileUpdateRequest | ||
from watchapedia.app.participant.dto.responses import ParticipantDataResponse, ParticipantProfileResponse | ||
|
||
participant_router = APIRouter() | ||
|
||
@participant_router.get('/{participant_id}', | ||
status_code=200, | ||
summary="인물 프로필 출력", | ||
description="인물 id를 받아 해당 인물의 정보(이름, 프로필 url, 역할, 바이오그래피)를 반환합니다.", | ||
response_model=ParticipantProfileResponse | ||
) | ||
|
||
def get_participant_profile( | ||
participant_id: int, | ||
participant_service: Annotated[ParticipantService, Depends()], | ||
) -> ParticipantProfileResponse: | ||
profile, roles = participant_service.get_participant_profile(participant_id) | ||
return ParticipantProfileResponse.from_entity(profile, roles) | ||
|
||
@participant_router.get('/{participant_id}/movies', | ||
status_code=200, | ||
summary="인물과 관련된 영화 출력", | ||
description="인물 id를 받아 해당 인물과 관련된 영화들의 정보를 개봉연도가 높은 순서로로 반환합니다.", | ||
response_model=list[ParticipantDataResponse] | ||
) | ||
def get_participant_movie( | ||
participant_id: int, | ||
participant_service: Annotated[ParticipantService, Depends()], | ||
) -> list[ParticipantDataResponse]: | ||
return participant_service.get_participant_movies(participant_id) | ||
|
||
|
||
@participant_router.patch('/{participant_id}', | ||
status_code=200, | ||
summary="인물 정보 수정", | ||
description="인물 id를 받아 해당 인물의 정보(이름, 프로필 url, 바이오그래피)를 수정합니다.", | ||
) | ||
def update_participant_profile( | ||
participant_id: int, | ||
participant_service: Annotated[ParticipantService, Depends()], | ||
profile: ParticipantProfileUpdateRequest | ||
): | ||
participant_service.update_participant( | ||
participant_id, | ||
profile.name, | ||
profile.profile_url, | ||
profile.biography | ||
|
||
) | ||
|
||
return "Success" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters