Skip to content

Commit

Permalink
Merge pull request #87 from mash-up-kr/junhyoung/add-myspace-mypick
Browse files Browse the repository at this point in the history
feat: 마이스페이스 내가 받은 픽 API
  • Loading branch information
toychip authored Aug 16, 2024
2 parents e900e82 + bc6c501 commit b37e7d5
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 17 deletions.
5 changes: 5 additions & 0 deletions _endpoint_test/member.http
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,8 @@ Content-Type: application/json
"fromMemberId": "22ee8f4c-c2db-49c5-ad5d-22db7bb67796",
"toMemberId": "71400a62-b535-48c3-967b-5a25a64137ae"
}


### 마이스페이스 내가 받은 픽 조회 API
GET {{host}}/member/my-space/pick
Authorization: {{authorization}}
100 changes: 99 additions & 1 deletion api/src/main/kotlin/com/mashup/dojo/MemberController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import com.mashup.dojo.service.MemberService
import com.mashup.dojo.usecase.MemberUseCase
import io.github.oshai.kotlinlogging.KotlinLogging
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.media.ExampleObject
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.web.bind.annotation.GetMapping
Expand All @@ -23,6 +25,7 @@ import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import java.time.LocalDateTime

private val logger = KotlinLogging.logger { }

Expand Down Expand Up @@ -90,7 +93,12 @@ class MemberController(
fun getProfile(
@PathVariable memberId: String,
): DojoApiResponse<MemberProfileResponse> {
val profileResponse = memberUseCase.findMemberById(MemberId(memberId))
val currentMemberId = MemberPrincipalContextHolder.current().id
val profileResponse =
memberUseCase.findMemberById(
targetMemberId = MemberId(memberId),
currentMemberId = currentMemberId
)

return DojoApiResponse.success(
MemberProfileResponse(
Expand Down Expand Up @@ -184,6 +192,47 @@ class MemberController(
return DojoApiResponse.success(memberUseCase.updateFriendRelation(MemberUseCase.UpdateFriendCommand(request.fromMemberId, request.toMemberId)))
}

@GetMapping("/member/my-space/pick")
@Operation(
summary = "마이 스페이스 내가 받은 픽 API",
description = "마이스페이스 탭 중 내가 받은 픽의 대한 API입니다. 공동 등수를 자동으로 계산하고 반환합니다. Pick이 많은 순서대로 등수를 나누고, 최신순, 내림차순으로 정렬합니다.",
responses = [
ApiResponse(
responseCode = "200",
description = "마이스페이스 - 내가 받은 픽 Response",
content = [
Content(
mediaType = "application/json",
examples = [
ExampleObject(
name = "Example Response",
value = EXAMPLE_VALUE
)
]
)
]
)
]
)
fun myPick(): DojoApiResponse<MySpacePickResponse> {
val memberId = MemberPrincipalContextHolder.current().id
val receivedMySpacePicks = memberUseCase.receivedMySpacePicks(memberId)
val response =
receivedMySpacePicks.map {
MySpacePickDetail(
pickId = it.pickId.value,
rank = it.rank,
pickContent = it.pickContent,
pickCount = it.pickCount,
createdAt = it.createdAt
)
}

return DojoApiResponse.success(
MySpacePickResponse(response)
)
}

data class MemberCreateResponse(
val id: MemberId,
)
Expand All @@ -196,4 +245,53 @@ class MemberController(
val id: MemberId,
val authToken: String,
)

data class MySpacePickDetail(
val pickId: String,
val rank: Int,
val pickContent: String,
val pickCount: Int,
val createdAt: LocalDateTime,
)

data class MySpacePickResponse(
val mySpaceResponses: List<MySpacePickDetail>,
)

companion object {
private const val EXAMPLE_VALUE = """
{
"success": true,
"data": {
"mySpaceResponses": [
{
"pickId": "pickId1",
"rank": 1,
"pickContent": "대충 작업해도 퀄리티 잘 내오는 사람은?",
"pickCount": 999,
"createdAt": "2024-08-12T17:18:52.132Z"
},
{
"pickId": "pickId2",
"rank": 2,
"pickContent": "매쉬업에서 운동 제일 잘할 것 같은 사람은?",
"pickCount": 500,
"createdAt": "2024-08-12T17:18:52.132Z"
},
{
"pickId": "pickId3",
"rank": 3,
"pickContent": "매쉬업에서 이성으로 소개시켜주고 싶은 사람은?",
"pickCount": 300,
"createdAt": "2024-08-12T17:18:52.132Z"
}
]
},
"error": {
"code": "string",
"message": "string"
}
}
"""
}
}
14 changes: 10 additions & 4 deletions api/src/main/kotlin/com/mashup/dojo/PickController.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mashup.dojo

import com.mashup.dojo.common.DojoApiResponse
import com.mashup.dojo.config.security.MemberPrincipalContextHolder
import com.mashup.dojo.domain.MemberId
import com.mashup.dojo.domain.PickId
import com.mashup.dojo.domain.PickOpenItem
Expand Down Expand Up @@ -46,8 +47,14 @@ class PickController(
// todo : add userinfo
@RequestParam(required = false, defaultValue = "LATEST") sort: PickSort,
): DojoApiResponse<ReceivedPickListGetResponse> {
val currentMemberId = MemberPrincipalContextHolder.current().id
val receivedPickList: List<PickUseCase.GetReceivedPick> =
pickUseCase.getReceivedPickList(PickUseCase.GetReceivedPickListCommand(MemberId("1"), sort))
pickUseCase.getReceivedPickList(
PickUseCase.GetReceivedPickListCommand(
memberId = currentMemberId,
sort = sort
)
)

val pickResponseList =
receivedPickList.map {
Expand Down Expand Up @@ -76,10 +83,9 @@ class PickController(
@RequestParam(required = false, defaultValue = "0") pageNumber: Int,
@RequestParam(required = false, defaultValue = "10") pageSize: Int,
): DojoApiResponse<PickPaging> {
// ToDo 추후 실제 사용자로 변경
val currentMember = MemberId("1")
val currentMemberId = MemberPrincipalContextHolder.current().id
val pickPaging: PickUseCase.GetPagingPick =
pickUseCase.getReceivedPickDetailPaging(PickUseCase.GetPagingPickCommand(currentMember, QuestionId(questionId), pageNumber, pageSize))
pickUseCase.getReceivedPickDetailPaging(PickUseCase.GetPagingPickCommand(currentMemberId, QuestionId(questionId), pageNumber, pageSize))

val pickDetails =
pickPaging.picks.map {
Expand Down
3 changes: 2 additions & 1 deletion api/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ dojo:
open-time-2: "23:00:00"
candidate:
size: 8
rank:
size: 3

scheduler:
cron: "0 0 9,21 * * *"
Expand All @@ -22,4 +24,3 @@ cloud:
cloudwatch:
access-key: ${CLOUDWATCH_ACCESS_KEY}
secret-key: ${CLOUDWATCH_SECRET_KEY}

42 changes: 42 additions & 0 deletions entity/src/main/kotlin/com/mashup/dojo/PickRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ interface PickRepositoryCustom {
memberId: String,
questionSetId: String,
): List<PickEntity>

fun findTopRankPicksByMemberId(
memberId: String,
rank: Long,
): List<PickQuestionMapper>
}

class PickRepositoryImpl(
Expand Down Expand Up @@ -188,6 +193,34 @@ class PickRepositoryImpl(
)
.fetch()
}

override fun findTopRankPicksByMemberId(
memberId: String,
rank: Long,
): List<PickQuestionMapper> {
val pickEntity = QPickEntity.pickEntity
val questionEntity = QQuestionEntity.questionEntity

return jpaQueryFactory
.select(
QPickQuestionMapper(
pickEntity.id,
questionEntity.id,
questionEntity.content,
pickEntity.createdAt
)
)
.from(pickEntity)
.join(questionEntity).on(pickEntity.questionId.eq(questionEntity.id))
.where(pickEntity.pickedId.eq(memberId))
.groupBy(pickEntity.questionId)
.orderBy(
Wildcard.count.desc(),
pickEntity.createdAt.desc()
)
.limit(rank)
.fetch()
}
}

data class PickEntityMapper
Expand All @@ -211,3 +244,12 @@ data class PickEntityMapper
val pickerSecondInitialName: String,
val pickerFullName: String,
)

data class PickQuestionMapper
@QueryProjection
constructor(
val pickId: String,
val questionId: String,
val questionContent: String,
val createdAt: LocalDateTime,
)
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.mashup.dojo.domain.PickSort
import com.mashup.dojo.domain.QuestionId
import com.mashup.dojo.domain.QuestionSetId
import com.mashup.dojo.domain.QuestionSheetId
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.domain.PageRequest
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
Expand Down Expand Up @@ -68,6 +69,8 @@ interface PickService {
memberId: MemberId,
): Int

fun getReceivedMySpacePicks(memberId: MemberId): List<MySpacePickDetail>

data class GetPagingPick(
val picks: List<GetReceivedPickDetail>,
val totalPage: Int,
Expand All @@ -91,6 +94,14 @@ interface PickService {
val pickerFullName: String,
val latestPickedAt: LocalDateTime,
)

data class MySpacePickDetail(
val pickId: PickId,
val rank: Int = -1,
val pickContent: String,
val pickCount: Int,
val createdAt: LocalDateTime,
)
}

@Transactional(readOnly = true)
Expand All @@ -99,6 +110,8 @@ class DefaultPickService(
private val pickRepository: PickRepository,
private val memberService: MemberService,
private val pickTimeRepository: PickTimeRepository,
@Value("\${dojo.rank.size}")
private val defaultRankSize: Long,
) : PickService {
override fun getReceivedPickList(
pickedMemberId: MemberId,
Expand Down Expand Up @@ -302,6 +315,18 @@ class DefaultPickService(
return pickRepository.getOpenPickerCount(questionId.value, memberId.value).toInt()
}

override fun getReceivedMySpacePicks(memberId: MemberId): List<PickService.MySpacePickDetail> {
return pickRepository.findTopRankPicksByMemberId(memberId = memberId.value, rank = defaultRankSize).map { pick ->
val pickCount = pickRepository.findPickDetailCount(memberId = memberId.value, questionId = pick.questionId)
PickService.MySpacePickDetail(
pickId = PickId(pick.pickId),
pickCount = pickCount.toInt(),
pickContent = pick.questionContent,
createdAt = pick.createdAt
)
}
}

companion object {
private val ZONE_ID = ZoneId.of("Asia/Seoul")

Expand Down Expand Up @@ -356,3 +381,30 @@ private fun PickEntity.toPick(): Pick {
updatedAt = updatedAt
)
}

fun List<PickService.MySpacePickDetail>.calculateRanks(): List<PickService.MySpacePickDetail> {
if (this.isEmpty()) return this

// 첫 번째 조건: pickCount 내림차순 정렬
// 두 번째 조건: createdAt 내림차순 정렬
val sortedPicks =
this.sortedWith(
compareByDescending<PickService.MySpacePickDetail> { it.pickCount }
.thenByDescending { it.createdAt }
)

var currentRank = 1
var previousRank = 1

return sortedPicks.mapIndexed { index, currentPick ->
if (index > 0) {
val previousPick = sortedPicks[index - 1]
// PickCount가 다르면 현재 등수 업데이트
if (currentPick.pickCount != previousPick.pickCount) {
currentRank = index + 1
}
}
previousRank = currentRank
currentPick.copy(rank = currentRank)
}
}
Loading

0 comments on commit b37e7d5

Please sign in to comment.