Skip to content

Commit 983cecd

Browse files
committed
✨ feat(feed) : Feed 조회 기능 추가 및 테스트 완료
1 parent ed4066e commit 983cecd

File tree

21 files changed

+495
-164
lines changed

21 files changed

+495
-164
lines changed

server/src/main/kotlin/com/app/server/challenge/application/repository/ChallengeCategoryRepository.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,18 @@ import com.app.server.challenge.domain.model.ChallengeCategory
44
import org.springframework.data.jpa.repository.JpaRepository
55
import org.springframework.data.jpa.repository.Query
66
import org.springframework.stereotype.Repository
7+
import java.util.*
78

89
@Repository
910
interface ChallengeCategoryRepository : JpaRepository<ChallengeCategory, Long> {
1011

11-
@Query("SELECT cc FROM ChallengeCategory cc JOIN FETCH cc.challenges")
12+
@Query("SELECT cc.title FROM ChallengeCategory cc " +
13+
"WHERE cc.id = :challengeCategoryId " +
14+
"AND cc.deletedAt IS NULL")
15+
fun getTitleById(challengeCategoryId: Long): Optional<String>
16+
17+
@Query("SELECT cc FROM ChallengeCategory cc " +
18+
"JOIN FETCH cc.challenges " +
19+
"WHERE cc.deletedAt IS NULL")
1220
override fun findAll(): List<ChallengeCategory>
1321
}

server/src/main/kotlin/com/app/server/challenge/application/service/ChallengeCategoryService.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,21 @@ package com.app.server.challenge.application.service
22

33
import com.app.server.challenge.application.repository.ChallengeCategoryRepository
44
import com.app.server.challenge.domain.model.ChallengeCategory
5+
import com.app.server.challenge.exception.ChallengeException
6+
import com.app.server.common.exception.NotFoundException
57
import org.springframework.stereotype.Service
68

79
@Service
8-
class ChallengeCategoryService (
10+
class ChallengeCategoryService(
911
private val challengeCategoryRepository: ChallengeCategoryRepository
10-
){
12+
) {
1113

12-
fun findAll() : List<ChallengeCategory> {
14+
fun getNameByCategoryId(challengeCategoryId: Long): String {
15+
return challengeCategoryRepository.getTitleById(challengeCategoryId)
16+
.orElseThrow { NotFoundException(ChallengeException.NOT_FOUND_CHALLENGE_CATEGORY) }
17+
}
18+
19+
fun findAll(): List<ChallengeCategory> {
1320
return challengeCategoryRepository.findAll()
1421
}
1522
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.app.server.challenge.exception
2+
3+
import com.app.server.common.enums.ResultCode
4+
5+
enum class ChallengeException(
6+
override val code: String,
7+
override val message: String
8+
) : ResultCode {
9+
10+
NOT_FOUND_CHALLENGE_CATEGORY("CHA001", "해당하는 챌린지 카테고리를 찾을 수 없습니다."),
11+
}

server/src/main/kotlin/com/app/server/common/exception/ControllerAdvice.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.app.server.common.exception
33
import com.app.server.common.enums.CommonResultCode
44
import com.app.server.common.response.ApiResponse
55
import org.springframework.http.HttpStatus
6+
import org.springframework.web.bind.MethodArgumentNotValidException
67
import org.springframework.web.bind.annotation.ExceptionHandler
78
import org.springframework.web.bind.annotation.ResponseStatus
89
import org.springframework.web.bind.annotation.RestControllerAdvice
@@ -48,6 +49,13 @@ class ControllerAdvice {
4849
)
4950
}
5051

52+
@ExceptionHandler(MethodArgumentNotValidException::class)
53+
@ResponseStatus(HttpStatus.BAD_REQUEST)
54+
fun handleMethodArgumentNotValidException(e: MethodArgumentNotValidException): ApiResponse<*> {
55+
val errorMessage = e.bindingResult.fieldErrors.joinToString(", ") { "${it.field}: ${it.defaultMessage}" }
56+
return ApiResponse.failure<Any>(CommonResultCode.BAD_REQUEST, errorMessage)
57+
}
58+
5159
@ExceptionHandler(Exception::class)
5260
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
5361
fun handleException(e: Exception): ApiResponse<*> {
Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,42 @@
11
package com.app.server.feed.application.repository
22

33
import com.app.server.feed.domain.model.query.FeedProjection
4+
import org.springframework.data.domain.Page
5+
import org.springframework.data.domain.Pageable
46
import org.springframework.data.jpa.repository.JpaRepository
57
import org.springframework.data.jpa.repository.Query
68
import org.springframework.stereotype.Repository
7-
import java.util.Optional
9+
import java.util.*
810

911
@Repository
1012
interface FeedProjectionRepository : JpaRepository<FeedProjection, Long> {
1113

12-
@Query("SELECT fp FROM FeedProjection fp WHERE fp.id = :id AND fp.deletedAt IS NULL")
14+
@Query("SELECT fp FROM FeedProjection fp" +
15+
" WHERE fp.id = :id " +
16+
"AND fp.deletedAt IS NULL")
1317
override fun findById(id: Long): Optional<FeedProjection>
18+
19+
@Query("SELECT fp FROM FeedProjection fp " +
20+
"WHERE fp.id IN :feedIds " +
21+
"AND fp.deletedAt IS NULL " +
22+
"ORDER BY fp.createdAt DESC ")
23+
fun findByIdIn(feedIds: List<Long>, pageable: Pageable) : Page<FeedProjection>
24+
25+
@Query("SELECT fp FROM FeedProjection fp " +
26+
"WHERE fp.deletedAt IS NULL " +
27+
"ORDER BY fp.createdAt DESC ")
28+
override fun findAll(pageable: Pageable) : Page<FeedProjection>
29+
30+
@Query("SELECT fp FROM FeedProjection fp " +
31+
"WHERE fp.challengeCategoryTitle = :categoryName " +
32+
"AND fp.deletedAt IS NULL " +
33+
"ORDER BY fp.createdAt DESC ")
34+
fun findAllByCategoryName(categoryName: String, pageable: Pageable): Page<FeedProjection>
35+
36+
@Query("SELECT fp FROM FeedProjection fp " +
37+
"WHERE fp.userId = :userId " +
38+
"AND fp.challengeCategoryTitle = :categoryName " +
39+
"AND fp.deletedAt IS NULL " +
40+
"ORDER BY fp.createdAt DESC ")
41+
fun findByUserIdAndCategoryName(userId: Long, categoryName: String, pageable: Pageable): Page<FeedProjection>
1442
}

server/src/main/kotlin/com/app/server/feed/application/repository/FeedRepository.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ import java.util.*
99
@Repository
1010
interface FeedRepository : JpaRepository<Feed, Long> {
1111

12-
@Query("SELECT f FROM Feed f WHERE f.id = :id AND f.deletedAt IS NULL")
12+
@Query("SELECT f FROM Feed f " +
13+
"WHERE f.id = :id " +
14+
"AND f.deletedAt IS NULL")
1315
override fun findById(id: Long): Optional<Feed>
16+
17+
@Query("SELECT f.id FROM Feed f " +
18+
"WHERE f.userChallengeId = :userChallengeId " +
19+
"AND f.deletedAt IS NULL")
20+
fun findAllIdsByUserChallengeId(userChallengeId: Long): Optional<List<Long>>
1421
}

server/src/main/kotlin/com/app/server/feed/application/service/FeedProjectionCommandService.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ class FeedProjectionCommandService (
3939
userProfileImageUrl = user.profileImageUrl,
4040
userNowConsecutiveDays = user.nowMaxConsecutiveParticipationDayCount
4141
)
42-
return feedProjection
42+
43+
return feedProjectionService.save(feedProjection)
4344
}
4445

4546
private fun createFeedProjectionEntity(
@@ -69,6 +70,7 @@ class FeedProjectionCommandService (
6970

7071
return feedProjection
7172
}
73+
7274
fun deleteReadOnlyFeed(feed: Feed): FeedProjection {
7375
val feedProjection = feedProjectionRepository.findById(feed.id!!).orElseThrow {
7476
throw NotFoundException(FeedException.NOT_FOUND_FEED_PROJECTION)
Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,107 @@
11
package com.app.server.feed.application.service
22

3+
import com.app.server.challenge.application.service.ChallengeCategoryService
4+
import com.app.server.common.exception.BadRequestException
5+
import com.app.server.feed.domain.model.query.FeedProjection
6+
import com.app.server.feed.enums.EFeedReadRequestState
7+
import com.app.server.feed.enums.EFeedScope
8+
import com.app.server.feed.exception.FeedException
39
import com.app.server.feed.ui.dto.FeedListResponseDto
410
import com.app.server.feed.ui.dto.ReadFeedProjectionCommand
511
import com.app.server.feed.ui.usecase.ReadFeedUseCase
12+
import org.springframework.data.domain.Page
13+
import org.springframework.data.domain.PageRequest
614
import org.springframework.stereotype.Service
715
import org.springframework.transaction.annotation.Transactional
816

917
@Service
1018
@Transactional(readOnly = true)
1119
class FeedProjectionQueryService (
12-
private val feedProjectionService: FeedProjectionService
20+
private val feedProjectionService: FeedProjectionService,
21+
private val feedService: FeedService,
22+
private val challengeCategoryService: ChallengeCategoryService
1323
) : ReadFeedUseCase {
1424

1525
override fun execute(readFeedProjectionCommand: ReadFeedProjectionCommand) : FeedListResponseDto {
16-
TODO("Not yet implemented")
26+
val categoryId = readFeedProjectionCommand.categoryId
27+
val scope = readFeedProjectionCommand.scope
28+
val userChallengeId = readFeedProjectionCommand.userChallengeId
29+
30+
val requestType : EFeedReadRequestState = checkWhichRequestOfType(categoryId, scope, userChallengeId)
31+
32+
val pageable = PageRequest.of(
33+
readFeedProjectionCommand.page!! - 1,
34+
readFeedProjectionCommand.size!!
35+
)
36+
37+
val feedPage : Page<FeedProjection> =
38+
getFeedLists(requestType, readFeedProjectionCommand, categoryId, userChallengeId, pageable)
39+
40+
41+
return FeedListResponseDto.fromPage(
42+
feedProjectionPage = feedPage
43+
)
44+
}
45+
46+
private fun getFeedLists(
47+
requestType: EFeedReadRequestState,
48+
readFeedProjectionCommand: ReadFeedProjectionCommand,
49+
categoryId: Long?,
50+
userChallengeId: Long?,
51+
pageable: PageRequest
52+
): Page<FeedProjection> = when (requestType) {
53+
EFeedReadRequestState.ALL_FEED -> feedProjectionService.getAllFeed(
54+
pageable = pageable
55+
)
56+
57+
EFeedReadRequestState.ALL_CATEGORY_FEED -> {
58+
val categoryName = challengeCategoryService.getNameByCategoryId(
59+
challengeCategoryId = categoryId!!
60+
)
61+
feedProjectionService.getAllCategoryFeed(
62+
categoryName = categoryName,
63+
pageable = pageable
64+
)
65+
}
66+
67+
EFeedReadRequestState.USER_CATEGORY_FEED -> {
68+
val categoryName = challengeCategoryService.getNameByCategoryId(
69+
challengeCategoryId = categoryId!!
70+
)
71+
feedProjectionService.getUserCategoryFeed(
72+
userId = readFeedProjectionCommand.userId,
73+
categoryName = categoryName,
74+
pageable = pageable
75+
)
76+
}
77+
78+
EFeedReadRequestState.SPECIFIC_USER_CHALLENGE_FEED -> {
79+
val feedIds : List<Long> = feedService.findAllIdsByUserChallengeId(
80+
userChallengeId = userChallengeId!!
81+
)
82+
83+
feedProjectionService.getSpecificUserChallengeFeed(
84+
feedIds = feedIds,
85+
pageable = pageable
86+
)
87+
}
88+
}
89+
90+
private fun checkWhichRequestOfType(
91+
categoryName: Long?,
92+
scope: EFeedScope,
93+
userChallengeId: Long?
94+
): EFeedReadRequestState {
95+
return if (categoryName != null && scope == EFeedScope.ALL && userChallengeId == null) {
96+
EFeedReadRequestState.ALL_CATEGORY_FEED
97+
} else if (categoryName != null && scope == EFeedScope.USER && userChallengeId == null) {
98+
EFeedReadRequestState.USER_CATEGORY_FEED
99+
} else if (categoryName == null && scope == EFeedScope.USER && userChallengeId != null) {
100+
EFeedReadRequestState.SPECIFIC_USER_CHALLENGE_FEED
101+
} else if (categoryName == null && scope == EFeedScope.ALL && userChallengeId == null) {
102+
EFeedReadRequestState.ALL_FEED
103+
} else {
104+
throw BadRequestException(FeedException.INVALID_GET_FEED_REQUEST)
105+
}
17106
}
18107
}

server/src/main/kotlin/com/app/server/feed/application/service/FeedProjectionService.kt

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,46 @@ package com.app.server.feed.application.service
22

33
import com.app.server.common.exception.NotFoundException
44
import com.app.server.feed.application.repository.FeedProjectionRepository
5+
import com.app.server.feed.application.repository.FeedRepository
56
import com.app.server.feed.domain.model.query.FeedProjection
67
import com.app.server.feed.exception.FeedException
8+
import org.springframework.data.domain.Page
9+
import org.springframework.data.domain.PageRequest
710
import org.springframework.stereotype.Service
811

912
@Service
1013
class FeedProjectionService (
11-
private val feedProjectionRepository: FeedProjectionRepository
14+
private val feedProjectionRepository: FeedProjectionRepository,
1215
){
1316

17+
fun save(feedProjection: FeedProjection) : FeedProjection {
18+
return feedProjectionRepository.save(feedProjection)
19+
}
20+
1421
fun findById(feedId: Long) : FeedProjection = feedProjectionRepository.findById(feedId).orElseThrow{
1522
throw NotFoundException(FeedException.NOT_FOUND_FEED_PROJECTION)
1623
}
24+
25+
fun getAllFeed(pageable: PageRequest): Page<FeedProjection> {
26+
return feedProjectionRepository.findAll(pageable)
27+
}
28+
fun getAllCategoryFeed(categoryName: String, pageable: PageRequest): Page<FeedProjection> {
29+
return feedProjectionRepository.findAllByCategoryName(categoryName, pageable)
30+
}
31+
fun getUserCategoryFeed(userId: Long, categoryName: String, pageable: PageRequest): Page<FeedProjection> {
32+
return feedProjectionRepository.findByUserIdAndCategoryName(userId, categoryName, pageable)
33+
}
34+
fun getSpecificUserChallengeFeed(
35+
feedIds : List<Long>,
36+
pageable: PageRequest
37+
): Page<FeedProjection> {
38+
return feedProjectionRepository.findByIdIn(
39+
feedIds = feedIds,
40+
pageable = pageable
41+
)
42+
}
43+
44+
fun deleteAll(){
45+
feedProjectionRepository.deleteAll()
46+
}
1747
}

server/src/main/kotlin/com/app/server/feed/application/service/FeedService.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ class FeedService (
1111
private val feedRepository : FeedRepository
1212
){
1313

14+
fun save(feed: Feed) : Feed {
15+
return feedRepository.save(feed)
16+
}
17+
1418
fun saveAndFlush(feed : Feed){
1519
feedRepository.saveAndFlush(feed)
1620
}
@@ -19,4 +23,14 @@ class FeedService (
1923
throw NotFoundException(FeedException.NOT_FOUND_FEED)
2024
}
2125

26+
fun findAllIdsByUserChallengeId(userChallengeId: Long) : List<Long> {
27+
return feedRepository.findAllIdsByUserChallengeId(userChallengeId).orElseThrow {
28+
throw NotFoundException(FeedException.NOT_FOUND_FEED_THIS_USER_CHALLENGE)
29+
}
30+
}
31+
32+
fun deleteAll() {
33+
feedRepository.deleteAll()
34+
}
35+
2236
}

0 commit comments

Comments
 (0)