Skip to content

Commit

Permalink
Merge pull request #155 from mash-up-kr/feature/#153-user-vote-place-…
Browse files Browse the repository at this point in the history
…get-api

feature: 유저가 투표한 장소 조회 api
  • Loading branch information
thguss authored Aug 16, 2024
2 parents b079688 + 79ca39d commit cf0e856
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import com.piikii.application.port.input.VoteUseCase
import com.piikii.application.port.input.dto.response.VotePlaceResponse
import com.piikii.application.port.input.dto.response.VoteResultByScheduleResponse
import com.piikii.application.port.input.dto.response.VoteResultResponse
import com.piikii.application.port.input.dto.response.VotedPlaceResponse
import com.piikii.application.port.input.dto.response.VotedPlacesResponse
import com.piikii.application.port.output.persistence.PlaceQueryPort
import com.piikii.application.port.output.persistence.RoomQueryPort
import com.piikii.application.port.output.persistence.ScheduleQueryPort
Expand Down Expand Up @@ -86,6 +88,26 @@ class VoteService(
)
}

override fun retrieveVotedPlaceByUser(
roomUid: UuidTypeId,
userUid: UuidTypeId,
): VotedPlacesResponse {
val votes = voteQueryPort.findAllByUserUid(userUid)
val placeIdByVote = votes.associateBy { it.placeId }
val votedPlaces = placeQueryPort.findAllByPlaceIds(votes.map { it.placeId }).filter { it.roomUid == roomUid }
return VotedPlacesResponse(
votedPlaces.map { place ->
val vote =
placeIdByVote[place.id]
?: throw PiikiiException(
exceptionCode = ExceptionCode.ACCESS_DENIED,
detailMessage = "$VOTE_NOT_FOUND (Place ID: ${place.id.getValue()})",
)
VotedPlaceResponse(place, vote)
},
)
}

private fun getVoteCount(
placeId: LongTypeId,
votesGroupByPlaceId: Map<LongTypeId, List<Vote>>,
Expand All @@ -99,5 +121,6 @@ class VoteService(
companion object {
const val VOTE_UNAVAILABLE = "투표가 시작되지 않았거나, 마감되었습니다"
const val VOTE_NOT_STARTED = "투표가 시작되지 않았습니다"
const val VOTE_NOT_FOUND = "장소에 해당하는 투표 결과가 없습니다"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.piikii.application.port.input
import com.piikii.application.domain.generic.UuidTypeId
import com.piikii.application.domain.vote.Vote
import com.piikii.application.port.input.dto.response.VoteResultResponse
import com.piikii.application.port.input.dto.response.VotedPlacesResponse

interface VoteUseCase {
fun vote(
Expand All @@ -13,4 +14,9 @@ interface VoteUseCase {
fun isVoteFinished(roomUid: UuidTypeId): Boolean

fun getVoteResultOfRoom(roomUid: UuidTypeId): VoteResultResponse

fun retrieveVotedPlaceByUser(
roomUid: UuidTypeId,
userUid: UuidTypeId,
): VotedPlacesResponse
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package com.piikii.application.port.input.dto.response
import com.piikii.application.domain.generic.ThumbnailLinks
import com.piikii.application.domain.place.Origin
import com.piikii.application.domain.place.Place
import com.piikii.application.domain.vote.Vote
import com.piikii.application.domain.vote.VoteResult
import io.swagger.v3.oas.annotations.media.Schema

@Schema(description = "투표 상태 응답")
Expand Down Expand Up @@ -72,3 +74,49 @@ data class VotePlaceResponse(
countOfVote = countOfAgree + countOfDisagree,
)
}

@Schema(description = "유저가 투표한 장소 목록 응답")
data class VotedPlacesResponse(
@field:Schema(description = "투표한 장소 목록")
val places: List<VotedPlaceResponse>,
)

@Schema(description = "유저가 투표한 장소 정보")
data class VotedPlaceResponse(
@field:Schema(description = "장소 ID", example = "1")
val placeId: Long?,
@field:Schema(description = "장소 이름", example = "궁내 최고의 김치찌개")
val name: String,
@field:Schema(description = "장소 URL", example = "https://example.com/restaurant")
val url: String?,
@field:Schema(description = "장소 이미지 URL 목록")
val thumbnailLinks: ThumbnailLinks,
@field:Schema(description = "주소", example = "서울시 강남구 테헤란로 123")
val address: String?,
@field:Schema(description = "전화번호", example = "02-1234-5678")
val phoneNumber: String?,
@field:Schema(description = "별점 (0-5)", example = "4.5")
val starGrade: Float?,
@field:Schema(
description = "장소 정보 제공처",
example = "MANUAL",
)
val origin: Origin,
@field:Schema(description = "메모", example = "여기 괜춘")
val memo: String?,
@field:Schema(description = "투표한 상태", example = "AGREE")
val voteResult: VoteResult,
) {
constructor(place: Place, vote: Vote) : this(
placeId = place.id.getValue(),
name = place.name,
url = place.url,
thumbnailLinks = place.thumbnailLinks,
address = place.address,
phoneNumber = place.phoneNumber,
starGrade = place.starGrade,
origin = place.origin,
memo = place.memo,
voteResult = vote.result,
)
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.piikii.application.port.output.persistence

import com.piikii.application.domain.generic.LongTypeId
import com.piikii.application.domain.generic.UuidTypeId
import com.piikii.application.domain.vote.Vote

interface VoteQueryPort {
fun findAgreeCountByPlaceId(votes: List<Vote>): Map<Long, Int>

fun findAllByPlaceIds(placeIds: List<LongTypeId>): List<Vote>

fun findAllByUserUid(userUid: UuidTypeId): List<Vote>
}

interface VoteCommandPort {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.piikii.application.port.input.dto.request.VoteDeadlineSetRequest
import com.piikii.application.port.input.dto.request.VoteSaveRequest
import com.piikii.application.port.input.dto.response.VoteResultResponse
import com.piikii.application.port.input.dto.response.VoteStatusResponse
import com.piikii.application.port.input.dto.response.VotedPlacesResponse
import com.piikii.input.http.controller.docs.VoteApiDocs
import com.piikii.input.http.controller.dto.ResponseForm
import jakarta.validation.Valid
Expand Down Expand Up @@ -67,4 +68,14 @@ class VoteApi(
val voteResult = voteUseCase.getVoteResultOfRoom(UuidTypeId(roomUid))
return ResponseForm(data = voteResult)
}

@ResponseStatus(HttpStatus.OK)
@GetMapping("/user/{userUid}")
override fun retrieveVotedPlaceByUser(
@NotNull @PathVariable roomUid: UUID,
@NotNull @PathVariable userUid: UUID,
): ResponseForm<VotedPlacesResponse> {
val votedResult = voteUseCase.retrieveVotedPlaceByUser(UuidTypeId(roomUid), UuidTypeId(userUid))
return ResponseForm(data = votedResult)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.piikii.application.port.input.dto.request.VoteDeadlineSetRequest
import com.piikii.application.port.input.dto.request.VoteSaveRequest
import com.piikii.application.port.input.dto.response.VoteResultResponse
import com.piikii.application.port.input.dto.response.VoteStatusResponse
import com.piikii.application.port.input.dto.response.VotedPlacesResponse
import com.piikii.input.http.controller.dto.ResponseForm
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
Expand All @@ -23,6 +24,8 @@ interface VoteApiDocs {

class SuccessVoteResultResponse : ResponseForm<VoteResultResponse>()

class SuccessVotedPlacesResponse : ResponseForm<VotedPlacesResponse>()

@Operation(summary = "방 투표 마감일 설정 API", description = "방(Room)의 투표 마감일을 설정합니다.")
@ApiResponses(
value = [
Expand Down Expand Up @@ -118,4 +121,29 @@ interface VoteApiDocs {
`in` = ParameterIn.PATH,
) @NotNull roomUid: UUID,
): ResponseForm<VoteResultResponse>

@Operation(summary = "투표한 장소 조회 API", description = "유저가 투표한 장소 목록을 조회합니다")
@ApiResponses(
value = [
ApiResponse(
responseCode = "200",
description = "Vote result",
content = [Content(schema = Schema(implementation = SuccessVotedPlacesResponse::class))],
),
],
)
fun retrieveVotedPlaceByUser(
@Parameter(
name = "roomUid",
description = "조회하고자 하는 방 id",
required = true,
`in` = ParameterIn.PATH,
) @NotNull roomUid: UUID,
@Parameter(
name = "userUid",
description = "조회하고자 하는 유저 id",
required = true,
`in` = ParameterIn.PATH,
) @NotNull userUid: UUID,
): ResponseForm<VotedPlacesResponse>
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.piikii.output.persistence.postgresql.adapter

import com.piikii.application.domain.generic.LongTypeId
import com.piikii.application.domain.generic.UuidTypeId
import com.piikii.application.domain.vote.Vote
import com.piikii.application.domain.vote.VoteResult
import com.piikii.application.port.output.persistence.VoteCommandPort
Expand All @@ -24,6 +25,10 @@ class VoteAdapter(
return voteRepository.findAllByPlaceIdIn(placeIds.map { it.getValue() }).map { it.toDomain() }
}

override fun findAllByUserUid(userUid: UuidTypeId): List<Vote> {
return voteRepository.findAllByUserUid(userUid.getValue()).map { it.toDomain() }
}

override fun findAgreeCountByPlaceId(votes: List<Vote>): Map<Long, Int> {
return votes
.filter { it.result == VoteResult.AGREE }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package com.piikii.output.persistence.postgresql.persistence.repository

import com.piikii.output.persistence.postgresql.persistence.entity.VoteEntity
import org.springframework.data.jpa.repository.JpaRepository
import java.util.UUID

interface VoteRepository : JpaRepository<VoteEntity, Long> {
fun findAllByPlaceIdIn(placeIds: Collection<Long>): List<VoteEntity>

fun findAllByUserUid(userUid: UUID): List<VoteEntity>
}

0 comments on commit cf0e856

Please sign in to comment.