Skip to content

Commit d2e9a23

Browse files
committed
✨ feat(user_challenge): 나의 챌린지 전체 목록 조회 기능 구현 및 테스트 완료
1 parent 62f18f7 commit d2e9a23

File tree

16 files changed

+366
-88
lines changed

16 files changed

+366
-88
lines changed

server/src/main/kotlin/com/app/server/challenge_certification/ui/CertificationController.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.RestController
1515
import java.time.LocalDate
1616

1717
@RestController
18-
@RequestMapping("/api/v1/challenge/user/{userChallengeId}")
18+
@RequestMapping("/api/v1/challenges/user/{userChallengeId}")
1919
class CertificationController(
2020
private val certificationUseCase: CertificationUseCase,
2121
private val usingIceUseCase: UsingIceUseCase

server/src/main/kotlin/com/app/server/user_challenge/application/repository/UserChallengeRepository.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,9 @@ interface UserChallengeRepository : JpaRepository<UserChallenge, Long> {
3434
"AND uc.deletedAt IS NULL")
3535
override fun findById(userChallengeId: Long): Optional<UserChallenge>
3636

37+
@Query("SELECT uc FROM UserChallenge uc " +
38+
"WHERE uc.userId = :userId " +
39+
"AND uc.deletedAt IS NULL")
40+
fun findAllByUserId(userId: Long): List<UserChallenge>
41+
3742
}

server/src/main/kotlin/com/app/server/user_challenge/application/service/UserChallengeQueryService.kt

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
package com.app.server.user_challenge.application.service
22

3+
import com.app.server.user_challenge.application.usecase.GetTotalUserChallengeUseCase
4+
import com.app.server.user_challenge.domain.model.UserChallenge
5+
import com.app.server.user_challenge.domain.model.UserChallengeHistory
6+
import com.app.server.user_challenge.ui.dto.CertificationData
7+
import com.app.server.user_challenge.ui.dto.GetTotalUserChallengeResponseDto
8+
import com.app.server.user_challenge.ui.dto.UserChallengeQuery
39
import org.springframework.stereotype.Service
10+
import java.time.LocalDate
411

512
@Service
613
class UserChallengeQueryService(
714
private val userChallengeService: UserChallengeService
8-
) {
15+
) : GetTotalUserChallengeUseCase {
916
fun getChallengeCompletedUserPercent(challengeId: Long): Double {
1017

1118
val countCompletedUser : Long = userChallengeService.countCompletedUserBy(challengeId)
@@ -20,4 +27,43 @@ class UserChallengeQueryService(
2027

2128
return String.format("%.2f", countCompletedUser.toDouble() / countAllUser.toDouble()).toDouble()
2229
}
30+
31+
override fun execute(userId: Long): GetTotalUserChallengeResponseDto {
32+
val todayDate = LocalDate.now()
33+
val userTotalChallengeList: List<UserChallenge> = userChallengeService.findAllByUserId(userId)
34+
35+
val mappedList = userTotalChallengeList.map { mapToUserChallengeQuery(it, todayDate) }
36+
37+
return GetTotalUserChallengeResponseDto(userChallenges = mappedList)
38+
}
39+
40+
private fun mapToUserChallengeQuery(userChallenge: UserChallenge, todayDate: LocalDate): UserChallengeQuery {
41+
val histories = userChallenge.getUserChallengeHistoriesBeforeToday(todayDate)
42+
val elapsedDays = userChallenge.calculateElapsedDays(todayDate)
43+
val progress = userChallenge.calculateProgress(todayDate)
44+
val certificationToday = userChallenge.isCertificatedToday(todayDate)
45+
val certificationDataList = mapCertificationDataList(histories)
46+
47+
return UserChallengeQuery(
48+
id = userChallenge.id!!,
49+
title = userChallenge.challenge.title,
50+
category = userChallenge.challenge.challengeCategory.title, // TODO: 캐싱 필요
51+
status = userChallenge.status.content,
52+
totalDays = userChallenge.participantDays,
53+
iceCount = userChallenge.iceCount,
54+
elapsedDays = elapsedDays,
55+
progress = progress,
56+
isCertificatedInToday = certificationToday,
57+
certificationDataList = certificationDataList
58+
)
59+
}
60+
61+
private fun mapCertificationDataList(histories: List<UserChallengeHistory>): List<CertificationData> {
62+
return histories.map {
63+
CertificationData(
64+
date = it.date,
65+
isCertificated = it.status.name
66+
)
67+
}
68+
}
2369
}

server/src/main/kotlin/com/app/server/user_challenge/application/service/UserChallengeService.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ class UserChallengeService (
2222
userChallengeRepository.findById(userChallengeId)
2323
.orElseThrow { NotFoundException(CommonResultCode.NOT_FOUND, "해당 챌린지를 참여하고 있지 않습니다.")
2424
}
25+
fun findAllByUserId(userId: Long): List<UserChallenge> =
26+
userChallengeRepository.findAllByUserId(userId)
2527

2628
fun countCompletedUserBy(challengeId: Long): Long =
2729
userChallengeRepository.countByChallengeIdAndStatusIsCompleted(
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.app.server.user_challenge.application.usecase
2+
3+
import com.app.server.user_challenge.ui.dto.GetTotalUserChallengeResponseDto
4+
5+
interface GetTotalUserChallengeUseCase {
6+
7+
fun execute(userId : Long) : GetTotalUserChallengeResponseDto
8+
}

server/src/main/kotlin/com/app/server/user_challenge/domain/enums/EUserChallengeCertificationStatus.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.app.server.user_challenge.domain.enums
22

33
enum class EUserChallengeCertificationStatus(
4-
private val content: String
4+
val content: String
55
) {
66
FAILED("챌린지 인증 실패"),
77
SUCCESS("챌린지 인증 성공"),
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package com.app.server.user_challenge.domain.enums
22

33
enum class EUserChallengeStatus(
4-
private val content: String
4+
val content: String
55
) {
66
RUNNING("챌린지 진행 중"),
77
PENDING("리포트 확인 대기 중"),
8-
WAITING("챌린지 이어하기 / 종료 결정 기다리는 중"),
8+
WAITING("챌린지 이어하기 또는 종료 결정을 기다리는 중"),
99
COMPLETED("챌린지 완료"),
1010
DEAD("리포트 발급 실패")
1111
}

server/src/main/kotlin/com/app/server/user_challenge/domain/model/UserChallenge.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,20 @@ class UserChallenge(
157157
this.maxConsecutiveParticipationDayCount = day
158158
}
159159

160+
fun calculateElapsedDays(todayDate: LocalDate): Long {
161+
return todayDate.toEpochDay() - userChallengeHistories.first().date.toEpochDay()
162+
}
163+
164+
fun calculateProgress(todayDate: LocalDate): Int {
165+
return ((calculateElapsedDays(todayDate).toDouble() / totalParticipationDayCount) * 100).toInt().coerceIn(0, 100)
166+
}
167+
168+
fun isCertificatedToday(todayDate: LocalDate): Boolean {
169+
return userChallengeHistories.find { it.date.isEqual(todayDate) }?.status!! != EUserChallengeCertificationStatus.FAILED
170+
}
171+
172+
fun getUserChallengeHistoriesBeforeToday(todayDate: LocalDate) : List<UserChallengeHistory> {
173+
return userChallengeHistories.filter { it.date.isBefore(todayDate.plusDays(1)) }
174+
}
175+
160176
}

server/src/main/kotlin/com/app/server/user_challenge/ui/UserChallengeController.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import com.app.server.common.annotation.UserId
44
import com.app.server.common.enums.CommonResultCode
55
import com.app.server.common.enums.ResultCode
66
import com.app.server.common.response.ApiResponse
7+
import com.app.server.user_challenge.application.usecase.GetTotalUserChallengeUseCase
78
import com.app.server.user_challenge.application.usecase.ParticipantChallengeUseCase
89
import com.app.server.user_challenge.ui.dto.ChallengeParticipantRequestDto
10+
import com.app.server.user_challenge.ui.dto.GetTotalUserChallengeResponseDto
11+
import org.springframework.web.bind.annotation.GetMapping
912
import org.springframework.web.bind.annotation.PostMapping
1013
import org.springframework.web.bind.annotation.RequestBody
1114
import org.springframework.web.bind.annotation.RequestMapping
@@ -14,13 +17,20 @@ import org.springframework.web.bind.annotation.RestController
1417
@RestController
1518
@RequestMapping("/api/v1")
1619
class UserChallengeController (
17-
private val participantChallengeUseCase: ParticipantChallengeUseCase
20+
private val participantChallengeUseCase: ParticipantChallengeUseCase,
21+
private val getTotalUserChallengeUseCase: GetTotalUserChallengeUseCase
1822
) {
1923

20-
@PostMapping("/challenge")
24+
@PostMapping("/challenges")
2125
fun participateChallenge(@UserId userId: Long, @RequestBody requestBody: ChallengeParticipantRequestDto) : ApiResponse<ResultCode> {
2226
val challengeParticipantDto = requestBody.toChallengeParticipantDto(userId)
2327
participantChallengeUseCase.execute(challengeParticipantDto)
2428
return ApiResponse.success(CommonResultCode.SUCCESS)
2529
}
30+
31+
@GetMapping("/challenges/user")
32+
fun getTotalUserChallenge(@UserId userId: Long) : ApiResponse<GetTotalUserChallengeResponseDto> {
33+
val totalUserChallenge : GetTotalUserChallengeResponseDto = getTotalUserChallengeUseCase.execute(userId)
34+
return ApiResponse.success(totalUserChallenge)
35+
}
2636
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.app.server.user_challenge.ui.dto
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty
4+
import java.time.LocalDate
5+
6+
data class GetTotalUserChallengeResponseDto (
7+
@JsonProperty("user_challenges")
8+
val userChallenges: List<UserChallengeQuery>
9+
)
10+
11+
data class UserChallengeQuery(
12+
var id: Long,
13+
var title: String,
14+
val category: String,
15+
val status: String,
16+
@JsonProperty("total_days")
17+
val totalDays: Int,
18+
@JsonProperty("elapsed_days")
19+
val elapsedDays: Long,
20+
val progress: Int,
21+
@JsonProperty("ice_count")
22+
val iceCount: Int,
23+
@JsonProperty("is_certificated_in_today")
24+
val isCertificatedInToday: Boolean,
25+
@JsonProperty("certification_data_list")
26+
val certificationDataList: List<CertificationData>
27+
)
28+
29+
data class CertificationData(
30+
val date: LocalDate,
31+
@JsonProperty("is_certificated")
32+
val isCertificated: String
33+
)

0 commit comments

Comments
 (0)