From 197d8d067434a3d42e5b8bb6d183d0da8c26b044 Mon Sep 17 00:00:00 2001 From: morecleverer Date: Wed, 8 Jan 2025 17:03:08 +0900 Subject: [PATCH 1/8] =?UTF-8?q?=ED=88=AC=ED=91=9C=EA=B8=80=20=EB=B3=B4?= =?UTF-8?q?=EA=B8=B0=EC=97=90=EC=84=9C=20=EB=82=B4=EA=B0=80=20=EB=A7=8C?= =?UTF-8?q?=EB=93=A0=20=ED=88=AC=ED=91=9C=EC=9D=B8=EC=A7=80=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=ED=95=98=EB=8A=94=20=EC=BD=94=EB=93=9C=EC=99=80=20?= =?UTF-8?q?=EB=82=B4=EA=B0=80=20=EC=84=A0=ED=83=9D=ED=95=9C=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=EC=A7=80=EC=9D=B8=EC=A7=80=20=ED=99=95=EC=9D=B8?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- snuvote/app/vote/dto/responses.py | 13 ++++++++++++- snuvote/app/vote/views.py | 7 ++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/snuvote/app/vote/dto/responses.py b/snuvote/app/vote/dto/responses.py index 77af04c..15aab67 100644 --- a/snuvote/app/vote/dto/responses.py +++ b/snuvote/app/vote/dto/responses.py @@ -40,17 +40,26 @@ class OnGoingVotesListResponse(BaseModel): class ChoiceDetailResponse(BaseModel): choice_id: int choice_content: str + participated: bool choice_num_participants: int|None = None choice_participants_name: List[str]|None = None # Choice를 받아 ChoiceDetailResponse로 변환 @staticmethod - def from_choice(choice: Choice, annonymous_choice, realtime_result) -> "ChoiceDetailResponse": + def from_choice(choice: Choice, user_id, annonymous_choice, realtime_result) -> "ChoiceDetailResponse": id = choice.id content = choice.choice_content num_participants = len(choice.choice_participations) participants_name = [choice_participation.user.name for choice_participation in choice.choice_participations] + + #로그인한 유저가 선택지를 선택했는지 여부 + participated = False + for choice_participation in choice.choice_participations: + if user_id == choice_participation.user_id: + participated = True + break + # 익명 투표인 경우 -> choice_participants_name = None if annonymous_choice: participants_name = None @@ -64,6 +73,7 @@ def from_choice(choice: Choice, annonymous_choice, realtime_result) -> "ChoiceDe return ChoiceDetailResponse( choice_id=id, choice_content=content, + participated=participated, choice_num_participants=num_participants, choice_participants_name=participants_name ) @@ -71,6 +81,7 @@ def from_choice(choice: Choice, annonymous_choice, realtime_result) -> "ChoiceDe class VoteDetailResponse(BaseModel): writer_name: str + is_writer: bool title: str content: str realtime_result: bool diff --git a/snuvote/app/vote/views.py b/snuvote/app/vote/views.py index 25d9335..2c43dc9 100644 --- a/snuvote/app/vote/views.py +++ b/snuvote/app/vote/views.py @@ -70,6 +70,7 @@ def get_ongoing_list( @vote_router.get("/{vote_id}", status_code=HTTP_200_OK) def get_vote( vote_id: int, + user: Annotated[User, Depends(login_with_access_token)], vote_service: Annotated[VoteService, Depends()] ): @@ -78,9 +79,13 @@ def get_vote( # 해당 vote_id에 해당하는 투표글이 없을 경우 404 Not Found if not vote: raise VoteNotFoundError() + + #투표 생성자 아이디와 유저 아이디가 같은 경우 + is_writer = vote.writer_id == user.id return VoteDetailResponse( writer_name = vote.writer.name, + is_writer= is_writer, title = vote.title, content = vote.content, realtime_result = vote.realtime_result, @@ -88,5 +93,5 @@ def get_vote( annonymous_choice = vote.annonymous_choice, create_datetime = vote.create_datetime, end_datetime = vote.end_datetime, - choices= [ChoiceDetailResponse.from_choice(choice, vote.annonymous_choice, vote.realtime_result) for choice in vote.choices] + choices= [ChoiceDetailResponse.from_choice(choice, user.id, vote.annonymous_choice, vote.realtime_result) for choice in vote.choices] ) \ No newline at end of file From a926980778eee9503fa4b1485a198d2eb8ed3192 Mon Sep 17 00:00:00 2001 From: morecleverer Date: Wed, 8 Jan 2025 18:13:51 +0900 Subject: [PATCH 2/8] =?UTF-8?q?=ED=88=AC=ED=91=9C=20=EC=B0=B8=EC=97=AC=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- snuvote/app/vote/dto/requests.py | 13 +++++++++++- snuvote/app/vote/dto/responses.py | 1 + snuvote/app/vote/errors.py | 6 +++++- snuvote/app/vote/service.py | 5 ++++- snuvote/app/vote/store.py | 30 ++++++++++++++++++++++++++-- snuvote/app/vote/views.py | 33 ++++++++++++++++++++++++++++--- 6 files changed, 80 insertions(+), 8 deletions(-) diff --git a/snuvote/app/vote/dto/requests.py b/snuvote/app/vote/dto/requests.py index 1951368..44bc3c6 100644 --- a/snuvote/app/vote/dto/requests.py +++ b/snuvote/app/vote/dto/requests.py @@ -51,6 +51,13 @@ def wrapper(value: T | None) -> T | None: return wrapper +def validate_choice_id_list(value:List[int]) -> List[int]: + if len(value) < 1: + raise ChoicesNotProvidedError() + + return value + + class CreateVoteRequest(BaseModel): ''' 제목 : 1~100자 @@ -66,4 +73,8 @@ class CreateVoteRequest(BaseModel): multiple_choice: bool annonymous_choice: bool end_datetime: datetime - choices: Annotated[List[str], AfterValidator(validate_choices)] \ No newline at end of file + choices: Annotated[List[str], AfterValidator(validate_choices)] + + +class ParticipateVoteRequest(BaseModel): + choice_id_list: Annotated[List[int], AfterValidator(validate_choice_id_list)] \ No newline at end of file diff --git a/snuvote/app/vote/dto/responses.py b/snuvote/app/vote/dto/responses.py index 15aab67..320c4c9 100644 --- a/snuvote/app/vote/dto/responses.py +++ b/snuvote/app/vote/dto/responses.py @@ -80,6 +80,7 @@ def from_choice(choice: Choice, user_id, annonymous_choice, realtime_result) -> class VoteDetailResponse(BaseModel): + vote_id:int writer_name: str is_writer: bool title: str diff --git a/snuvote/app/vote/errors.py b/snuvote/app/vote/errors.py index b14c3ef..361eab4 100644 --- a/snuvote/app/vote/errors.py +++ b/snuvote/app/vote/errors.py @@ -26,4 +26,8 @@ def __init__(self) -> None: class VoteNotFoundError(HTTPException): def __init__(self) -> None: - super().__init__(HTTP_404_NOT_FOUND, "Vote not found") \ No newline at end of file + super().__init__(HTTP_404_NOT_FOUND, "Vote not found") + +class MultipleChoicesError(HTTPException): + def __init__(self) -> None: + super().__init__(HTTP_400_BAD_REQUEST, "You cannot vote multiple times") \ No newline at end of file diff --git a/snuvote/app/vote/service.py b/snuvote/app/vote/service.py index 732ee69..7fc2144 100644 --- a/snuvote/app/vote/service.py +++ b/snuvote/app/vote/service.py @@ -47,4 +47,7 @@ def get_ongoing_list(self) -> List[Vote]: # 투표글 상세 내용 조회 def get_vote_by_vote_id(self, vote_id: int) -> Vote: - return self.vote_store.get_vote_by_vote_id(vote_id=vote_id) \ No newline at end of file + return self.vote_store.get_vote_by_vote_id(vote_id=vote_id) + + def participate_vote(self, vote_id:int, user_id: int, choice_id_list: List[int]) -> None: + return self.vote_store.participate_vote(vote_id=vote_id, user_id=user_id, choice_id_list=choice_id_list) \ No newline at end of file diff --git a/snuvote/app/vote/store.py b/snuvote/app/vote/store.py index 723e8d1..2a0a570 100644 --- a/snuvote/app/vote/store.py +++ b/snuvote/app/vote/store.py @@ -3,7 +3,7 @@ from datetime import datetime, timedelta from fastapi import Depends -from snuvote.database.models import Vote, Choice +from snuvote.database.models import Vote, Choice, ChoiceParticipation from snuvote.database.connection import get_db_session from sqlalchemy import select, delete @@ -60,4 +60,30 @@ def get_ongoing_list(self) -> List[Vote]: # 투표글 상세 내용 조회 def get_vote_by_vote_id(self, vote_id: int) -> Vote: - return self.session.scalar(select(Vote).where(Vote.id == vote_id)) \ No newline at end of file + return self.session.scalar(select(Vote).where(Vote.id == vote_id)) + + + #투표 참여하기 + def participate_vote(self, vote_id: int, user_id: int, choice_id_list: List[int]) -> None: + + #참여하려고 하는 투표에 이미 투표를 한 상태라면 이전 선택지는 제거하기 + vote = self.session.scalar(select(Vote).where(Vote.id == vote_id)) + + for choice in vote.choices: + choice_participation = self.session.scalar( + select(ChoiceParticipation).where((ChoiceParticipation.choice_id == choice.id) & (ChoiceParticipation.user_id == user_id))) + + if choice_participation is not None: + self.session.delete(choice_participation) + + self.session.flush() + + # 선택한 선택지 생성하기 + for choice_id in choice_id_list: + choice_participation = ChoiceParticipation(user_id=user_id, choice_id=choice_id) + + self.session.add(choice_participation) + + self.session.commit() + + return \ No newline at end of file diff --git a/snuvote/app/vote/views.py b/snuvote/app/vote/views.py index 2c43dc9..b5dfd56 100644 --- a/snuvote/app/vote/views.py +++ b/snuvote/app/vote/views.py @@ -5,9 +5,9 @@ from pydantic.functional_validators import AfterValidator from starlette.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_401_UNAUTHORIZED -from snuvote.app.vote.dto.requests import CreateVoteRequest +from snuvote.app.vote.dto.requests import CreateVoteRequest, ParticipateVoteRequest from snuvote.app.vote.dto.responses import OnGoingVotesListResponse, VotesListInfoResponse, VoteDetailResponse, ChoiceDetailResponse -from snuvote.app.vote.errors import VoteNotFoundError +from snuvote.app.vote.errors import VoteNotFoundError, MultipleChoicesError from snuvote.database.models import User from snuvote.app.vote.service import VoteService @@ -84,6 +84,7 @@ def get_vote( is_writer = vote.writer_id == user.id return VoteDetailResponse( + vote_id = vote.id, writer_name = vote.writer.name, is_writer= is_writer, title = vote.title, @@ -94,4 +95,30 @@ def get_vote( create_datetime = vote.create_datetime, end_datetime = vote.end_datetime, choices= [ChoiceDetailResponse.from_choice(choice, user.id, vote.annonymous_choice, vote.realtime_result) for choice in vote.choices] - ) \ No newline at end of file + ) + + +#투표 참여하기 +@vote_router.post("/{vote_id}/participate", status_code=HTTP_201_CREATED) +def paricipate_vote( + vote_id: int, + user: Annotated[User, Depends(login_with_access_token)], + participate_vote_request: ParticipateVoteRequest, + vote_service: Annotated[VoteService, Depends()] +): + + # 해당 vote_id에 해당하는 투표글 조회 + vote = vote_service.get_vote_by_vote_id(vote_id = vote_id) + + # 해당 vote_id에 해당하는 투표글이 없을 경우 404 Not Found + if not vote: + raise VoteNotFoundError() + + # 중복 투표 불가능인데 중복 투표 했을 때 + if not vote.multiple_choice and len(participate_vote_request.choice_id_list) > 1: + raise MultipleChoicesError() + + #투표 참여하기 + vote_service.participate_vote(vote_id, user.id, participate_vote_request.choice_id_list) + + return "Success" \ No newline at end of file From 83d0d83116240ad129ba4f70cbd7b2e65b0e76e0 Mon Sep 17 00:00:00 2001 From: morecleverer Date: Wed, 8 Jan 2025 18:30:04 +0900 Subject: [PATCH 3/8] =?UTF-8?q?=ED=88=AC=ED=91=9C=20=EC=B0=B8=EC=97=AC=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20=EA=B0=92=20=EB=B3=80=EA=B2=BD,=20ChoiceNo?= =?UTF-8?q?tFound=EC=97=90=EB=9F=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- snuvote/app/vote/errors.py | 8 +++++++- snuvote/app/vote/views.py | 26 ++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/snuvote/app/vote/errors.py b/snuvote/app/vote/errors.py index 361eab4..55e4fdc 100644 --- a/snuvote/app/vote/errors.py +++ b/snuvote/app/vote/errors.py @@ -30,4 +30,10 @@ def __init__(self) -> None: class MultipleChoicesError(HTTPException): def __init__(self) -> None: - super().__init__(HTTP_400_BAD_REQUEST, "You cannot vote multiple times") \ No newline at end of file + super().__init__(HTTP_400_BAD_REQUEST, "You cannot vote multiple times") + + ChoiceNotFoundError + +class ChoiceNotFoundError(HTTPException): + def __init__(self) -> None: + super().__init__(HTTP_404_NOT_FOUND, "Choice not found") \ No newline at end of file diff --git a/snuvote/app/vote/views.py b/snuvote/app/vote/views.py index b5dfd56..f2573fa 100644 --- a/snuvote/app/vote/views.py +++ b/snuvote/app/vote/views.py @@ -7,7 +7,7 @@ from snuvote.app.vote.dto.requests import CreateVoteRequest, ParticipateVoteRequest from snuvote.app.vote.dto.responses import OnGoingVotesListResponse, VotesListInfoResponse, VoteDetailResponse, ChoiceDetailResponse -from snuvote.app.vote.errors import VoteNotFoundError, MultipleChoicesError +from snuvote.app.vote.errors import VoteNotFoundError, MultipleChoicesError, ChoiceNotFoundError from snuvote.database.models import User from snuvote.app.vote.service import VoteService @@ -109,6 +109,7 @@ def paricipate_vote( # 해당 vote_id에 해당하는 투표글 조회 vote = vote_service.get_vote_by_vote_id(vote_id = vote_id) + vote_choice_id_list = [choice.id for choice in vote.choices] # 해당 vote_id에 해당하는 투표글이 없을 경우 404 Not Found if not vote: @@ -118,7 +119,28 @@ def paricipate_vote( if not vote.multiple_choice and len(participate_vote_request.choice_id_list) > 1: raise MultipleChoicesError() + # 해당 vote에 Request된 choice_id에 해당하는 선택지가 존재하지 않는 경우 + for choice_id in participate_vote_request.choice_id_list: + if choice_id not in vote_choice_id_list: + raise ChoiceNotFoundError() + #투표 참여하기 vote_service.participate_vote(vote_id, user.id, participate_vote_request.choice_id_list) - return "Success" \ No newline at end of file + + #투표 생성자 아이디와 유저 아이디가 같은 경우 + is_writer = vote.writer_id == user.id + + return VoteDetailResponse( + vote_id = vote.id, + writer_name = vote.writer.name, + is_writer= is_writer, + title = vote.title, + content = vote.content, + realtime_result = vote.realtime_result, + multiple_choice = vote.multiple_choice, + annonymous_choice = vote.annonymous_choice, + create_datetime = vote.create_datetime, + end_datetime = vote.end_datetime, + choices= [ChoiceDetailResponse.from_choice(choice, user.id, vote.annonymous_choice, vote.realtime_result) for choice in vote.choices] + ) \ No newline at end of file From 863811b576806f5729f89ba6d5e71a8024704220 Mon Sep 17 00:00:00 2001 From: odumag99 Date: Wed, 8 Jan 2025 20:00:18 +0900 Subject: [PATCH 4/8] =?UTF-8?q?=ED=88=AC=ED=91=9C=20=EC=B0=B8=EC=97=AC=20?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=96=B4=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- snuvote/app/vote/dto/requests.py | 2 +- snuvote/app/vote/dto/responses.py | 4 ++-- snuvote/app/vote/errors.py | 4 +--- snuvote/app/vote/service.py | 22 ++++++++++++++++++---- snuvote/app/vote/store.py | 10 +++------- snuvote/app/vote/views.py | 16 +++------------- 6 files changed, 28 insertions(+), 30 deletions(-) diff --git a/snuvote/app/vote/dto/requests.py b/snuvote/app/vote/dto/requests.py index 44bc3c6..25a7571 100644 --- a/snuvote/app/vote/dto/requests.py +++ b/snuvote/app/vote/dto/requests.py @@ -77,4 +77,4 @@ class CreateVoteRequest(BaseModel): class ParticipateVoteRequest(BaseModel): - choice_id_list: Annotated[List[int], AfterValidator(validate_choice_id_list)] \ No newline at end of file + participated_choice_ids: Annotated[List[int], AfterValidator(validate_choice_id_list)] \ No newline at end of file diff --git a/snuvote/app/vote/dto/responses.py b/snuvote/app/vote/dto/responses.py index 320c4c9..5532598 100644 --- a/snuvote/app/vote/dto/responses.py +++ b/snuvote/app/vote/dto/responses.py @@ -46,7 +46,7 @@ class ChoiceDetailResponse(BaseModel): # Choice를 받아 ChoiceDetailResponse로 변환 @staticmethod - def from_choice(choice: Choice, user_id, annonymous_choice, realtime_result) -> "ChoiceDetailResponse": + def from_choice(choice: Choice, user: User, annonymous_choice, realtime_result) -> "ChoiceDetailResponse": id = choice.id content = choice.choice_content num_participants = len(choice.choice_participations) @@ -56,7 +56,7 @@ def from_choice(choice: Choice, user_id, annonymous_choice, realtime_result) -> #로그인한 유저가 선택지를 선택했는지 여부 participated = False for choice_participation in choice.choice_participations: - if user_id == choice_participation.user_id: + if user.id == choice_participation.user_id: participated = True break diff --git a/snuvote/app/vote/errors.py b/snuvote/app/vote/errors.py index 55e4fdc..72ea600 100644 --- a/snuvote/app/vote/errors.py +++ b/snuvote/app/vote/errors.py @@ -30,9 +30,7 @@ def __init__(self) -> None: class MultipleChoicesError(HTTPException): def __init__(self) -> None: - super().__init__(HTTP_400_BAD_REQUEST, "You cannot vote multiple times") - - ChoiceNotFoundError + super().__init__(HTTP_400_BAD_REQUEST, "Multiple choices not allowed") class ChoiceNotFoundError(HTTPException): def __init__(self) -> None: diff --git a/snuvote/app/vote/service.py b/snuvote/app/vote/service.py index 7fc2144..307e6f2 100644 --- a/snuvote/app/vote/service.py +++ b/snuvote/app/vote/service.py @@ -1,9 +1,10 @@ from typing import Annotated, List from fastapi import Depends -from snuvote.database.models import Vote +from snuvote.database.models import Vote, User, Choice, ChoiceParticipation from snuvote.app.vote.store import VoteStore -from snuvote.app.vote.errors import InvalidFieldFormatError, ParticipationCodeError +from snuvote.app.vote.errors import ChoiceNotFoundError, InvalidFieldFormatError, MultipleChoicesError, ParticipationCodeError +from snuvote.app.vote.dto.requests import ParticipateVoteRequest from datetime import datetime, timedelta @@ -49,5 +50,18 @@ def get_ongoing_list(self) -> List[Vote]: def get_vote_by_vote_id(self, vote_id: int) -> Vote: return self.vote_store.get_vote_by_vote_id(vote_id=vote_id) - def participate_vote(self, vote_id:int, user_id: int, choice_id_list: List[int]) -> None: - return self.vote_store.participate_vote(vote_id=vote_id, user_id=user_id, choice_id_list=choice_id_list) \ No newline at end of file + def participate_vote(self, vote: Vote, user: User, participate_vote_request: ParticipateVoteRequest) -> None: + # 중복 투표 불가능인데 중복 투표 했을 때 + if not vote.multiple_choice and len(participate_vote_request.participated_choice_ids) > 1: + raise MultipleChoicesError() + + # 해당 vote에 Request된 choice_id에 해당하는 선택지가 존재하지 않는 경우 + vote_choice_id_list = [choice.id for choice in vote.choices] + for choice_id in participate_vote_request.participated_choice_ids: + if choice_id not in vote_choice_id_list: + raise ChoiceNotFoundError() + + user_id = user.id + choice_id_list = participate_vote_request.participated_choice_ids + + return self.vote_store.participate_vote(vote=vote, user_id=user_id, choice_id_list=choice_id_list) \ No newline at end of file diff --git a/snuvote/app/vote/store.py b/snuvote/app/vote/store.py index 2a0a570..7c7e210 100644 --- a/snuvote/app/vote/store.py +++ b/snuvote/app/vote/store.py @@ -64,11 +64,9 @@ def get_vote_by_vote_id(self, vote_id: int) -> Vote: #투표 참여하기 - def participate_vote(self, vote_id: int, user_id: int, choice_id_list: List[int]) -> None: - - #참여하려고 하는 투표에 이미 투표를 한 상태라면 이전 선택지는 제거하기 - vote = self.session.scalar(select(Vote).where(Vote.id == vote_id)) + def participate_vote(self, vote: Vote, user_id: int, choice_id_list: List[int]) -> None: + # 참여하려고 하는 투표에 이미 투표를 한 상태라면 이전 선택지 참여는 제거하기 for choice in vote.choices: choice_participation = self.session.scalar( select(ChoiceParticipation).where((ChoiceParticipation.choice_id == choice.id) & (ChoiceParticipation.user_id == user_id))) @@ -81,9 +79,7 @@ def participate_vote(self, vote_id: int, user_id: int, choice_id_list: List[int] # 선택한 선택지 생성하기 for choice_id in choice_id_list: choice_participation = ChoiceParticipation(user_id=user_id, choice_id=choice_id) - self.session.add(choice_participation) self.session.commit() - - return \ No newline at end of file + return vote \ No newline at end of file diff --git a/snuvote/app/vote/views.py b/snuvote/app/vote/views.py index f2573fa..9534c8f 100644 --- a/snuvote/app/vote/views.py +++ b/snuvote/app/vote/views.py @@ -94,7 +94,7 @@ def get_vote( annonymous_choice = vote.annonymous_choice, create_datetime = vote.create_datetime, end_datetime = vote.end_datetime, - choices= [ChoiceDetailResponse.from_choice(choice, user.id, vote.annonymous_choice, vote.realtime_result) for choice in vote.choices] + choices= [ChoiceDetailResponse.from_choice(choice, user, vote.annonymous_choice, vote.realtime_result) for choice in vote.choices] ) @@ -109,23 +109,13 @@ def paricipate_vote( # 해당 vote_id에 해당하는 투표글 조회 vote = vote_service.get_vote_by_vote_id(vote_id = vote_id) - vote_choice_id_list = [choice.id for choice in vote.choices] # 해당 vote_id에 해당하는 투표글이 없을 경우 404 Not Found if not vote: raise VoteNotFoundError() - # 중복 투표 불가능인데 중복 투표 했을 때 - if not vote.multiple_choice and len(participate_vote_request.choice_id_list) > 1: - raise MultipleChoicesError() - - # 해당 vote에 Request된 choice_id에 해당하는 선택지가 존재하지 않는 경우 - for choice_id in participate_vote_request.choice_id_list: - if choice_id not in vote_choice_id_list: - raise ChoiceNotFoundError() - #투표 참여하기 - vote_service.participate_vote(vote_id, user.id, participate_vote_request.choice_id_list) + vote_service.participate_vote(vote, user, participate_vote_request) #투표 생성자 아이디와 유저 아이디가 같은 경우 @@ -142,5 +132,5 @@ def paricipate_vote( annonymous_choice = vote.annonymous_choice, create_datetime = vote.create_datetime, end_datetime = vote.end_datetime, - choices= [ChoiceDetailResponse.from_choice(choice, user.id, vote.annonymous_choice, vote.realtime_result) for choice in vote.choices] + choices= [ChoiceDetailResponse.from_choice(choice, user, vote.annonymous_choice, vote.realtime_result) for choice in vote.choices] ) \ No newline at end of file From b842980a04f8f9d461c474a068873b124c545913 Mon Sep 17 00:00:00 2001 From: odumag99 Date: Wed, 8 Jan 2025 20:18:16 +0900 Subject: [PATCH 5/8] =?UTF-8?q?=EB=AA=A8=EB=93=A0=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=EC=A7=80=20=EC=B7=A8=EC=86=8C=20=EC=8B=9C=EC=97=90=EB=8F=84=20?= =?UTF-8?q?participate=5Fvote=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- snuvote/app/vote/dto/requests.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/snuvote/app/vote/dto/requests.py b/snuvote/app/vote/dto/requests.py index 25a7571..19c4931 100644 --- a/snuvote/app/vote/dto/requests.py +++ b/snuvote/app/vote/dto/requests.py @@ -51,13 +51,6 @@ def wrapper(value: T | None) -> T | None: return wrapper -def validate_choice_id_list(value:List[int]) -> List[int]: - if len(value) < 1: - raise ChoicesNotProvidedError() - - return value - - class CreateVoteRequest(BaseModel): ''' 제목 : 1~100자 @@ -77,4 +70,4 @@ class CreateVoteRequest(BaseModel): class ParticipateVoteRequest(BaseModel): - participated_choice_ids: Annotated[List[int], AfterValidator(validate_choice_id_list)] \ No newline at end of file + participated_choice_ids: List[int] \ No newline at end of file From 17c0e660e55b6b8c812bc565322e50ac3597f0f7 Mon Sep 17 00:00:00 2001 From: odumag99 Date: Wed, 8 Jan 2025 20:18:46 +0900 Subject: [PATCH 6/8] =?UTF-8?q?create=5Fvote,=20participate=5Fvote?= =?UTF-8?q?=EA=B0=80=20=EB=AA=A8=EB=91=90=20get=5Fvote=EC=99=80=20?= =?UTF-8?q?=EA=B0=99=EC=9D=B4=20=EB=B0=98=ED=99=98=ED=95=A0=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- snuvote/app/vote/views.py | 34 ++++------------------------------ 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/snuvote/app/vote/views.py b/snuvote/app/vote/views.py index 9534c8f..d8e8f8f 100644 --- a/snuvote/app/vote/views.py +++ b/snuvote/app/vote/views.py @@ -39,17 +39,7 @@ def create_vote( choices=create_vote_request.choices ) - return {"id": vote.id, - "title":vote.title, - "content":vote.content, - "choices":vote.choices, - "participation_code":vote.participation_code, - "realtime_result":vote.realtime_result, - "multiple_choice":vote.multiple_choice, - "annonymous_choice":vote.annonymous_choice, - "create_datetime":vote.create_datetime, - "end_datetime":vote.end_datetime - } + return get_vote(vote.id, user, vote_service) # 진행 중인 투표 리스트 조회 @vote_router.get("/ongoing_list", status_code=HTTP_200_OK) @@ -115,22 +105,6 @@ def paricipate_vote( raise VoteNotFoundError() #투표 참여하기 - vote_service.participate_vote(vote, user, participate_vote_request) - - - #투표 생성자 아이디와 유저 아이디가 같은 경우 - is_writer = vote.writer_id == user.id - - return VoteDetailResponse( - vote_id = vote.id, - writer_name = vote.writer.name, - is_writer= is_writer, - title = vote.title, - content = vote.content, - realtime_result = vote.realtime_result, - multiple_choice = vote.multiple_choice, - annonymous_choice = vote.annonymous_choice, - create_datetime = vote.create_datetime, - end_datetime = vote.end_datetime, - choices= [ChoiceDetailResponse.from_choice(choice, user, vote.annonymous_choice, vote.realtime_result) for choice in vote.choices] - ) \ No newline at end of file + vote = vote_service.participate_vote(vote, user, participate_vote_request) + + return get_vote(vote.id, user, vote_service) \ No newline at end of file From 9a40434baa9554b17e0e5bfa4aca4f2f9cbab3bd Mon Sep 17 00:00:00 2001 From: odumag99 Date: Wed, 8 Jan 2025 20:35:09 +0900 Subject: [PATCH 7/8] =?UTF-8?q?get=5Fvote=EC=97=90=EC=84=9C=20participatio?= =?UTF-8?q?n=5Fcode=5Frequired=EB=8F=84=20=EB=B0=98=ED=99=98=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- snuvote/app/vote/dto/responses.py | 1 + snuvote/app/vote/views.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/snuvote/app/vote/dto/responses.py b/snuvote/app/vote/dto/responses.py index 5532598..46465b2 100644 --- a/snuvote/app/vote/dto/responses.py +++ b/snuvote/app/vote/dto/responses.py @@ -85,6 +85,7 @@ class VoteDetailResponse(BaseModel): is_writer: bool title: str content: str + participation_code_required: bool realtime_result: bool multiple_choice: bool annonymous_choice: bool diff --git a/snuvote/app/vote/views.py b/snuvote/app/vote/views.py index d8e8f8f..34ad526 100644 --- a/snuvote/app/vote/views.py +++ b/snuvote/app/vote/views.py @@ -79,6 +79,7 @@ def get_vote( is_writer= is_writer, title = vote.title, content = vote.content, + participation_code_required = vote.participation_code_required, realtime_result = vote.realtime_result, multiple_choice = vote.multiple_choice, annonymous_choice = vote.annonymous_choice, @@ -106,5 +107,5 @@ def paricipate_vote( #투표 참여하기 vote = vote_service.participate_vote(vote, user, participate_vote_request) - + return get_vote(vote.id, user, vote_service) \ No newline at end of file From 5e986be55ee42360c91e8bdc3a5fc8c7024922c2 Mon Sep 17 00:00:00 2001 From: odumag99 Date: Wed, 8 Jan 2025 20:50:15 +0900 Subject: [PATCH 8/8] =?UTF-8?q?participate=5Fvote=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=B0=B8=EC=97=AC=20=EC=BD=94=EB=93=9C=20=ED=99=95=EC=9D=B8=20?= =?UTF-8?q?=EC=A0=88=EC=B0=A8=EB=8F=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- snuvote/app/vote/dto/requests.py | 3 ++- snuvote/app/vote/errors.py | 10 +++++++++- snuvote/app/vote/service.py | 12 +++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/snuvote/app/vote/dto/requests.py b/snuvote/app/vote/dto/requests.py index 19c4931..09965ab 100644 --- a/snuvote/app/vote/dto/requests.py +++ b/snuvote/app/vote/dto/requests.py @@ -70,4 +70,5 @@ class CreateVoteRequest(BaseModel): class ParticipateVoteRequest(BaseModel): - participated_choice_ids: List[int] \ No newline at end of file + participated_choice_ids: List[int] + participation_code: str | None \ No newline at end of file diff --git a/snuvote/app/vote/errors.py b/snuvote/app/vote/errors.py index 72ea600..fe70a9a 100644 --- a/snuvote/app/vote/errors.py +++ b/snuvote/app/vote/errors.py @@ -34,4 +34,12 @@ def __init__(self) -> None: class ChoiceNotFoundError(HTTPException): def __init__(self) -> None: - super().__init__(HTTP_404_NOT_FOUND, "Choice not found") \ No newline at end of file + super().__init__(HTTP_404_NOT_FOUND, "Choice not found") + +class ParticipationCodeNotProvidedError(HTTPException): + def __init__(self) -> None: + super().__init__(HTTP_403_FORBIDDEN, "Participation code not provided") + +class WrongParticipationCodeError(HTTPException): + def __init__(self) -> None: + super().__init__(HTTP_403_FORBIDDEN, "Wrong participation code") \ No newline at end of file diff --git a/snuvote/app/vote/service.py b/snuvote/app/vote/service.py index 307e6f2..7313e40 100644 --- a/snuvote/app/vote/service.py +++ b/snuvote/app/vote/service.py @@ -3,7 +3,7 @@ from fastapi import Depends from snuvote.database.models import Vote, User, Choice, ChoiceParticipation from snuvote.app.vote.store import VoteStore -from snuvote.app.vote.errors import ChoiceNotFoundError, InvalidFieldFormatError, MultipleChoicesError, ParticipationCodeError +from snuvote.app.vote.errors import ChoiceNotFoundError, InvalidFieldFormatError, MultipleChoicesError, ParticipationCodeError, ParticipationCodeNotProvidedError, WrongParticipationCodeError from snuvote.app.vote.dto.requests import ParticipateVoteRequest from datetime import datetime, timedelta @@ -51,6 +51,16 @@ def get_vote_by_vote_id(self, vote_id: int) -> Vote: return self.vote_store.get_vote_by_vote_id(vote_id=vote_id) def participate_vote(self, vote: Vote, user: User, participate_vote_request: ParticipateVoteRequest) -> None: + + # 참여코드가 필요한 투표글인 경우 + if vote.participation_code_required: + # 프론트에서 제공되지 않은 경우 + if not participate_vote_request.participation_code: + raise ParticipationCodeNotProvidedError() + # 참여코드가 불일치하는 경우 + if vote.participation_code != participate_vote_request.participation_code: + raise WrongParticipationCodeError() + # 중복 투표 불가능인데 중복 투표 했을 때 if not vote.multiple_choice and len(participate_vote_request.participated_choice_ids) > 1: raise MultipleChoicesError()