Skip to content

Commit

Permalink
Merge pull request #47 from wafflestudio/modify_vote_list
Browse files Browse the repository at this point in the history
Modify vote list
  • Loading branch information
morecleverer authored Jan 30, 2025
2 parents 7b8e7b0 + 00ab127 commit 8ba9a20
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 51 deletions.
3 changes: 2 additions & 1 deletion snuvote/app/vote/dto/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ def from_vote_user(vote: Vote, user: User, participant_count: int) -> "VotesList
class OnGoingVotesListResponse(BaseModel):
votes_list: List[VotesListInfoResponse]
has_next: bool
next_cursor: datetime|None = None
next_cursor_time: datetime|None = None
netx_cursor_id: int|None = None

class ChoiceDetailResponse(BaseModel):
choice_id: int
Expand Down
7 changes: 6 additions & 1 deletion snuvote/app/vote/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,9 @@ def __init__(self) -> None:

class InvalidVoteListCategoryError(HTTPException):
def __init__(self) -> None:
super().__init__(HTTP_400_BAD_REQUEST, "Invalid vote list category")
super().__init__(HTTP_400_BAD_REQUEST, "Invalid vote list category")


class CursorError(HTTPException):
def __init__(self) -> None:
super().__init__(HTTP_400_BAD_REQUEST, "Invalid cursor field")
11 changes: 6 additions & 5 deletions snuvote/app/vote/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,22 +87,23 @@ def add_vote(self,


# 진행 중인 투표 리스트 조회
def get_ongoing_list(self, start_cursor: datetime|None) -> tuple[List[tuple[Vote,int]], bool, datetime|None]:
def get_ongoing_list(self, start_cursor: tuple[datetime, int]) -> tuple[List[tuple[Vote,int]], bool, tuple[datetime, int]|None]:
return self.vote_store.get_ongoing_list(start_cursor)

# 완료된 투표글 리스트 조회
def get_ended_votes_list(self, start_cursor: datetime|None) -> tuple[List[tuple[Vote,int]], bool, datetime|None]:
def get_ended_votes_list(self, start_cursor: tuple[datetime, int]) -> tuple[List[tuple[Vote,int]], bool, tuple[datetime, int]|None]:
return self.vote_store.get_ended_votes_list(start_cursor)

# HOT 투표글 리스트 조회
def get_hot_votes_list(self, start_cursor: datetime|None) -> tuple[List[tuple[Vote,int]], bool, datetime|None]:
def get_hot_votes_list(self, start_cursor: tuple[datetime, int]) -> tuple[List[tuple[Vote,int]], bool, tuple[datetime, int]|None]:
return self.vote_store.get_hot_votes_list(start_cursor)

# 내가 만든 투표 리스트 조회
def get_my_votes_list(self, user: User, start_cursor: datetime|None) -> tuple[List[tuple[Vote,int]], bool, datetime|None]:
def get_my_votes_list(self, user: User, start_cursor: tuple[datetime, int]) -> tuple[List[tuple[Vote,int]], bool, tuple[datetime, int]|None]:
return self.vote_store.get_my_votes_list(user.id, start_cursor)

def get_participated_votes_list(self, user: User, start_cursor: datetime|None) -> tuple[List[tuple[Vote,int]], bool, datetime|None]:
#내가 참여한 투표 리스트 조회
def get_participated_votes_list(self, user: User, start_cursor: tuple[datetime, int]) -> tuple[List[tuple[Vote,int]], bool, tuple[datetime, int]|None]:
return self.vote_store.get_participated_votes_list(user.id, start_cursor)

# 투표글 상세 내용 조회
Expand Down
78 changes: 52 additions & 26 deletions snuvote/app/vote/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from fastapi import Depends
from snuvote.database.models import Vote, Choice, ChoiceParticipation, Comment, VoteImage
import sys

from snuvote.database.connection import get_db_session
from sqlalchemy import func, select
Expand Down Expand Up @@ -66,17 +67,22 @@ def add_vote_image(self, vote_id: int, image_order: int, image_src: str):
self.session.flush()

# 진행 중인 투표 리스트 조회
def get_ongoing_list(self, start_cursor: datetime|None) -> tuple[List[tuple[Vote,int]], bool, datetime|None]:
def get_ongoing_list(self, start_cursor: tuple[datetime,int] |None) -> tuple[List[tuple[Vote,int]], bool, tuple[datetime, int]|None]:

#커서가 none이면 가장 최신 것부터 self.pagination_size개
if start_cursor is None:
start_cursor = datetime.now(timezone.utc)
start_cursor = tuple(datetime.now(timezone.utc), 0)

# 생성 시간이 커서보다 최신인 것부터 오름차순(최신순)으로 self.pagination_size개 리턴
# 먼저 진행 중인 투표글의 Vote.id만 반환
filtered_votes = (
select(Vote.id)
.where(Vote.create_datetime < start_cursor)
.where(
(Vote.create_datetime < start_cursor[0]) # 생성 시간이 커서보다 과거이거나
| (
(Vote.create_datetime == start_cursor[0]) & (Vote.id > start_cursor[1]) # 생성 시간이 커서와 같은데 id가 더 큰 경우
)
)
.where(Vote.end_datetime > datetime.now(timezone.utc))
.subquery()
)
Expand All @@ -97,7 +103,7 @@ def get_ongoing_list(self, start_cursor: datetime|None) -> tuple[List[tuple[Vote
query = (
select(Vote, subquery.c.participant_count)
.join(subquery, Vote.id == subquery.c.vote_id) # filtered_votes의 vote 정보와 참여자 수만 표시되어야 하므로 inner join
.order_by(Vote.create_datetime.desc())
.order_by(Vote.create_datetime.desc(), Vote.id.asc())
.limit(self.pagination_size)
)

Expand All @@ -107,26 +113,32 @@ def get_ongoing_list(self, start_cursor: datetime|None) -> tuple[List[tuple[Vote
has_next = len(results) == self.pagination_size

#다음 커서는 self.pagination_size개 중 가장 과거에 생성된 것
next_cursor = results[-1][0].create_datetime if has_next else None
next_cursor = (results[-1][0].create_datetime, results[-1][0].id) if has_next else None

return results, has_next, next_cursor


# 완료된 투표글 리스트 조회
def get_ended_votes_list(self, start_cursor: datetime|None) -> tuple[List[tuple[Vote,int]], bool, datetime|None]:
def get_ended_votes_list(self, start_cursor: tuple[datetime,int] |None) -> tuple[List[tuple[Vote,int]], bool, tuple[datetime, int]|None]:

# 필터 쿼리: 완료된 투표글의 Vote.id만 반환
# 커서가 none이면 가장 최근에 끝난 투표부터 최근에 끝난 순으로 self.pagination_size개
if start_cursor is None:
filtered_votes = (
select(Vote.id)
.where(Vote.end_datetime <= datetime.now(timezone.utc))
.where(Vote.end_datetime < datetime.now(timezone.utc))
.subquery()
)
else: # 커서가 None이 아니면 커서보다 과거에 끝난 투표부터 최근에 끝난 순으로 self.pagination_size개
filtered_votes = (
select(Vote.id)
.where(Vote.end_datetime <= datetime.now(timezone.utc))
.where(Vote.end_datetime < start_cursor)
.where(
(Vote.end_datetime < start_cursor) # 종료시간이 커서 시간보다 과거이거나
| (
(Vote.end_datetime == start_cursor[0]) & (Vote.id > start_cursor[1]) # 종료시간이 커서와 같은데 id가 더 큰 경우
)
)
.subquery()
)

Expand All @@ -146,7 +158,7 @@ def get_ended_votes_list(self, start_cursor: datetime|None) -> tuple[List[tuple[
query = (
select(Vote, subquery.c.participant_count)
.join(subquery, Vote.id == subquery.c.vote_id) # filtered_votes의 vote 정보와 참여자 수만 표시되어야 하므로 inner join
.order_by(Vote.end_datetime.desc())
.order_by(Vote.end_datetime.desc(), Vote.id.asc())
.limit(self.pagination_size)
)

Expand All @@ -156,23 +168,27 @@ def get_ended_votes_list(self, start_cursor: datetime|None) -> tuple[List[tuple[
has_next = len(results) == self.pagination_size

# 다음 커서는 self.pagination_size개 중 가장 과거에 완료된 것
next_cursor = results[-1][0].end_datetime if has_next else None
next_cursor = (results[-1][0].end_datetime, results[-1][0].id) if has_next else None

return results, has_next, next_cursor


def get_hot_votes_list(self, start_cursor:datetime|None) -> tuple[List[tuple[Vote,int]], bool, datetime|None]:
def get_hot_votes_list(self, start_cursor: tuple[datetime,int] |None) -> tuple[List[tuple[Vote,int]], bool, tuple[datetime, int]|None]:

#커서가 none이면 가장 최신 것부터 self.pagination_size개
if start_cursor is None:
start_cursor = datetime.now(timezone.utc)
start_cursor = tuple(datetime.now(timezone.utc), 0)


# 먼저 필요한 Vote만 필터링
filtered_votes = (
select(Vote.id)
.where(Vote.create_datetime < start_cursor)
.where(Vote.end_datetime > datetime.now(timezone.utc))
.where(
(Vote.create_datetime < start_cursor[0]) # 생성 시간이 커서보다 과거이거나
| (
(Vote.create_datetime == start_cursor[0]) & (Vote.id > start_cursor[1]) # 생성 시간이 커서와 같은데 id가 더 큰 경우
)
)
.subquery()
)

Expand All @@ -193,7 +209,7 @@ def get_hot_votes_list(self, start_cursor:datetime|None) -> tuple[List[tuple[Vo
select(Vote, subquery.c.participant_count)
.join(subquery, Vote.id == subquery.c.vote_id)
.where(subquery.c.participant_count >= 5) # 참여자 수 5명 이상 조건
.order_by(Vote.create_datetime.desc())
.order_by(Vote.create_datetime.desc(), Vote.id.asc())
.limit(self.pagination_size)
)

Expand All @@ -204,23 +220,28 @@ def get_hot_votes_list(self, start_cursor:datetime|None) -> tuple[List[tuple[Vo
has_next = len(results) == self.pagination_size

#다음 커서는 self.pagination_size개 중 가장 과거에 생성된 것
next_cursor = results[-1][0].create_datetime if has_next else None
next_cursor = (results[-1][0].create_datetime, results[-1][0].id) if has_next else None

return results, has_next, next_cursor


#내가 만든 투표글 리스트
def get_my_votes_list(self, user_id: int, start_cursor:datetime|None) -> tuple[List[tuple[Vote,int]], bool, datetime|None]:
def get_my_votes_list(self, user_id: int, start_cursor: tuple[datetime,int] |None) -> tuple[List[tuple[Vote,int]], bool, tuple[datetime, int]|None]:

#커서가 none이면 가장 최신 것부터 self.pagination_size개
if start_cursor is None:
start_cursor = datetime.now(timezone.utc)
start_cursor = tuple(datetime.now(timezone.utc), 0)


# 먼저 내가 만든 Vote만 필터링
filtered_votes = (
select(Vote.id)
.where(Vote.create_datetime < start_cursor)
.where(
(Vote.create_datetime < start_cursor[0]) # 생성 시간이 커서보다 과거이거나
| (
(Vote.create_datetime == start_cursor[0]) & (Vote.id > start_cursor[1]) # 생성 시간이 커서와 같은데 id가 더 큰 경우
)
)
.where(Vote.writer_id == user_id)
.subquery()
)
Expand All @@ -241,7 +262,7 @@ def get_my_votes_list(self, user_id: int, start_cursor:datetime|None) -> tuple[
query = (
select(Vote, subquery.c.participant_count)
.join(subquery, Vote.id == subquery.c.vote_id) # filtered_votes의 vote 정보와 참여자 수만 표시되어야 하므로 inner join
.order_by(Vote.create_datetime.desc())
.order_by(Vote.create_datetime.desc(), Vote.id.asc())
.limit(self.pagination_size)
)

Expand All @@ -252,17 +273,17 @@ def get_my_votes_list(self, user_id: int, start_cursor:datetime|None) -> tuple[
has_next = len(results) == self.pagination_size

#다음 커서는 self.pagination_size개 중 생성 시간이 가장 과거인 것
next_cursor = results[-1][0].create_datetime if has_next else None
next_cursor = (results[-1][0].create_datetime, results[-1][0].id) if has_next else None

return results, has_next, next_cursor


#내가 참여한 투표글 리스트
def get_participated_votes_list(self, user_id: int, start_cursor:datetime|None) -> tuple[List[tuple[Vote,int]], bool, datetime|None]:
def get_participated_votes_list(self, user_id: int, start_cursor: tuple[datetime,int] |None) -> tuple[List[tuple[Vote,int]], bool, tuple[datetime, int]|None]:

#커서가 none이면 가장 최신 것부터 self.pagination_size개
if start_cursor is None:
start_cursor = datetime.now(timezone.utc)
start_cursor = tuple(datetime.now(timezone.utc), 0)


# 먼저 내가 참여한 Vote만 필터링
Expand All @@ -271,7 +292,12 @@ def get_participated_votes_list(self, user_id: int, start_cursor:datetime|None)
.join(ChoiceParticipation, ChoiceParticipation.choice_id == Choice.id)
.join(Choice, Choice.vote_id == Vote.id)
.where(ChoiceParticipation.user_id == user_id)
.where(Vote.create_datetime < start_cursor)
.where(
(Vote.create_datetime < start_cursor[0]) # 생성 시간이 커서보다 과거이거나
| (
(Vote.create_datetime == start_cursor[0]) & (Vote.id > start_cursor[1]) # 생성 시간이 커서와 같은데 id가 더 큰 경우
)
)
.subquery()
)

Expand All @@ -291,7 +317,7 @@ def get_participated_votes_list(self, user_id: int, start_cursor:datetime|None)
query = (
select(Vote, subquery.c.participant_count)
.join(subquery, Vote.id == subquery.c.vote_id) # filtered_votes의 vote 정보와 참여자 수만 표시되어야 하므로 inner join
.order_by(Vote.create_datetime.desc())
.order_by(Vote.create_datetime.desc(), Vote.id.asc())
.limit(self.pagination_size)
)

Expand All @@ -302,7 +328,7 @@ def get_participated_votes_list(self, user_id: int, start_cursor:datetime|None)
has_next = len(results) == self.pagination_size

#다음 커서는 self.pagination_size개 중 생성 시간이 가장 과거인 것
next_cursor = results[-1][0].create_datetime if has_next else None
next_cursor = (results[-1][0].create_datetime, results[-1][0].id) if has_next else None

return results, has_next, next_cursor

Expand Down
32 changes: 14 additions & 18 deletions snuvote/app/vote/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from snuvote.app.vote.dto.requests import CreateVoteRequest, ParticipateVoteRequest, CommentRequest
from snuvote.app.vote.dto.responses import OnGoingVotesListResponse, VotesListInfoResponse, VoteDetailResponse, ChoiceDetailResponse, CommentDetailResponse
from snuvote.app.vote.errors import VoteNotFoundError, ChoiceNotFoundError, CommentNotFoundError, InvalidVoteListCategoryError
from snuvote.app.vote.errors import VoteNotFoundError, ChoiceNotFoundError, CommentNotFoundError, InvalidVoteListCategoryError, CursorError
from datetime import datetime, timedelta, timezone

from snuvote.database.models import User
Expand Down Expand Up @@ -48,21 +48,7 @@ def create_vote(

return get_vote(vote.id, user, vote_service)

# 진행 중인 투표 리스트 조회
#아직 프론트에서 list API 변경이 안되어서 남겨둠
#함수는 지울 예정
@vote_router.get("/ongoing_list", status_code=HTTP_200_OK)
def get_ongoing_list(
user: Annotated[User, Depends(login_with_access_token)],
vote_service: Annotated[VoteService, Depends()],
start_cursor: datetime|None = None
):
results, has_next, next_cursor = vote_service.get_ongoing_list(start_cursor)
return OnGoingVotesListResponse(
votes_list = [ VotesListInfoResponse.from_vote_user(vote, user, participant_count) for vote, participant_count in results ],
has_next = has_next,
next_cursor = next_cursor
)



# 완료된/진행중인/hot 투표글 조회
Expand All @@ -71,8 +57,17 @@ def get_votes_list(
user: Annotated[User, Depends(login_with_access_token)],
vote_service: Annotated[VoteService, Depends()],
category: str,
start_cursor: datetime|None = None
start_cursor_time: datetime|None = None,
start_cursor_id: int|None = None
):
start_cursor: tuple[datetime, int]|None = None

if start_cursor_time is not None and start_cursor_id is not None:
start_cursor = (start_cursor_time, start_cursor_id)
elif start_cursor_time is not None or start_cursor_id is not None:
raise CursorError()


if category == "ended":
results, has_next, next_cursor = vote_service.get_ended_votes_list(start_cursor)
elif category == "ongoing":
Expand All @@ -88,7 +83,8 @@ def get_votes_list(
return OnGoingVotesListResponse(
votes_list = [ VotesListInfoResponse.from_vote_user(vote, user, participant_count) for vote, participant_count in results ],
has_next = has_next,
next_cursor = next_cursor
next_cursor_time = next_cursor[0] if next_cursor else None,
next_cursor_id = next_cursor[1] if next_cursor else None
)

# 특정 투표글 정보 조회
Expand Down

0 comments on commit 8ba9a20

Please sign in to comment.