Skip to content

Commit

Permalink
Merge pull request #174 from depromeet/feature/#171
Browse files Browse the repository at this point in the history
피드 조회 추가
  • Loading branch information
ManHyuk authored Feb 11, 2024
2 parents 00d5e3f + daec48e commit 4f3a25a
Show file tree
Hide file tree
Showing 18 changed files with 199 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ class OAuth2UserService(

userRepository.save(user)
val updateUsername = updateUsername(user)
createUserDefaultLifeMap(updateUsername)
return updateUsername
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,7 @@ class CheeringService(

val cheering = cheeringRepository.findByLifeMapId(lifeMap.id!!)

return if (cheering == null) {
0
} else {
cheering.count
}
return cheering?.count ?: 0
}

private fun saveCheerer(lifeMapId: Long, cheererId: Long) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import io.raemian.api.goal.controller.request.CreateGoalRequest
import io.raemian.api.goal.controller.request.UpdateGoalRequest
import io.raemian.api.goal.controller.response.CreateGoalResponse
import io.raemian.api.goal.controller.response.GoalResponse
import io.raemian.api.goal.event.CreateGoalEvent
import io.raemian.api.sticker.StickerService
import io.raemian.api.support.RaemianLocalDate
import io.raemian.api.support.error.MaxGoalCountExceededException
Expand All @@ -14,6 +15,7 @@ import io.raemian.storage.db.core.goal.GoalRepository
import io.raemian.storage.db.core.lifemap.LifeMap
import io.raemian.storage.db.core.lifemap.LifeMapRepository
import io.raemian.storage.db.core.user.UserRepository
import org.springframework.context.ApplicationEventPublisher
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

Expand All @@ -24,6 +26,7 @@ class GoalService(
private val userRepository: UserRepository,
private val goalRepository: GoalRepository,
private val lifeMapRepository: LifeMapRepository,
private val applicationEventPublisher: ApplicationEventPublisher,
) {

@Transactional(readOnly = true)
Expand All @@ -43,6 +46,14 @@ class GoalService(
addNewGoal(lifeMap, goal)

lifeMapRepository.save(lifeMap)

// goal 생성시 count event 발행
applicationEventPublisher.publishEvent(
CreateGoalEvent(
goalId = goal.id!!,
lifeMapId = lifeMap.id!!,
),
)
return CreateGoalResponse(goal)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.raemian.api.goal.event

data class CreateGoalEvent(
val goalId: Long,
val lifeMapId: Long,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.raemian.api.goal.event

import io.raemian.storage.db.core.goal.GoalRepository
import io.raemian.storage.db.core.lifemap.LifeMapCount
import io.raemian.storage.db.core.lifemap.LifeMapCountRepository
import io.raemian.storage.db.core.lifemap.LifeMapRepository
import jakarta.transaction.Transactional
import org.slf4j.LoggerFactory
import org.springframework.context.event.EventListener
import org.springframework.stereotype.Service

@Service
class GoalEventHandler(
private val lifeMapCountRepository: LifeMapCountRepository,
private val goalRepository: GoalRepository,
private val lifeMapRepository: LifeMapRepository,
) {
private val log = LoggerFactory.getLogger(javaClass)

@Transactional
@EventListener
fun addGoalCount(createGoalEvent: CreateGoalEvent) {
// TODO goal 테이블에서 life map 기준으로 전체 count 한 값으로 업데이트
val mapCount = lifeMapCountRepository.findByLifeMapId(createGoalEvent.lifeMapId)
?: LifeMapCount.of(createGoalEvent.lifeMapId)

val added = mapCount.addGoalCount()

lifeMapCountRepository.save(added)
log.info("life map id: ${createGoalEvent.lifeMapId}, added goal count : ${added.goalCount}")
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.raemian.api.lifemap

import io.raemian.api.lifemap.domain.ExploreDTO
import io.raemian.api.lifemap.domain.LifeMapCountDTO
import io.raemian.api.lifemap.domain.LifeMapDTO
import io.raemian.api.lifemap.domain.UpdatePublicRequest
Expand All @@ -23,6 +24,22 @@ class LifeMapService(
private val lifeMapHistoryRepository: LifeMapHistoryRepository,
) {

@Transactional(readOnly = true)
fun explore(lifeMapId: Long): List<ExploreDTO> {
val ids = lifeMapRepository.explore(lifeMapId)
val lifeMaps = lifeMapRepository.findAllByIdInOrderByIdDesc(ids)
val countMap = lifeMapCountRepository.findAllByLifeMapIdIn(ids)
.associateBy { it.lifeMapId }
return lifeMaps
.map { LifeMapDTO(it) }
.map {
ExploreDTO(
lifeMapDTO = it,
lifeMapCountDTO = LifeMapCountDTO(countMap[it.lifeMapId] ?: LifeMapCount.of(lifeMapId)),
)
}
}

@Transactional(readOnly = true)
fun findFirstByUserId(userId: Long): LifeMapDTO {
val lifeMap = lifeMapRepository.findFirstByUserId(userId)
Expand Down Expand Up @@ -105,7 +122,9 @@ class LifeMapService(
fun addCount(lifeMapId: Long): Long {
val lifeMapCount = lifeMapCountRepository.findByLifeMapId(lifeMapId)
?: LifeMapCount.of(lifeMapId)
val added = lifeMapCount.addCount()
val added = lifeMapCount
.addViewCount()
.addHistoryCount()
val saved = lifeMapCountRepository.save(added)
return saved.historyCount
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.raemian.api.lifemap.controller
import io.raemian.api.auth.domain.CurrentUser
import io.raemian.api.cheer.CheeringService
import io.raemian.api.lifemap.LifeMapService
import io.raemian.api.lifemap.domain.ExploreResponses
import io.raemian.api.lifemap.domain.LifeMapResponse
import io.raemian.api.lifemap.domain.UpdatePublicRequest
import io.raemian.api.support.response.ApiResponse
Expand All @@ -13,6 +14,7 @@ import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PatchMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

@RestController
Expand All @@ -35,6 +37,18 @@ class LifeMapController(
.ok(ApiResponse.success(LifeMapResponse(lifeMap, count, cheeringCount)))
}

@Operation(summary = "explore life map")
@GetMapping("/explore")
fun explore(
@AuthenticationPrincipal currentUser: CurrentUser,
@RequestParam(required = false, defaultValue = Long.MAX_VALUE.toString()) cursor: Long,
): ResponseEntity<ApiResponse<ExploreResponses>> {
val maps = lifeMapService.explore(lifeMapId = cursor)

return ResponseEntity.ok()
.body(ApiResponse.success(ExploreResponses(maps)))
}

@Operation(summary = "인생 지도 공개 여부를 수정하는 API")
@PatchMapping("/publication")
fun updatePublic(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.raemian.api.lifemap.domain

import io.raemian.api.cheer.controller.response.CheeringCountResponse

data class CountResponse(
val view: Long,
val cheering: Long,
val history: Long? = null,
) {
constructor(lifeMapCountDTO: LifeMapCountDTO, cheeringCount: Long) : this(
view = lifeMapCountDTO.viewCount,
cheering = cheeringCount,
history = lifeMapCountDTO.historyCount,
)
constructor(viewCount: Long, cheeringCountResponse: CheeringCountResponse) : this(
view = viewCount,
cheering = cheeringCountResponse.count,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.raemian.api.lifemap.domain

import io.raemian.api.user.domain.UserSubset

data class ExploreDTO(
val lifeMapId: Long,
val goals: List<GoalDto>,
val count: LifeMapCountDTO,
val user: UserSubset?,
) {
constructor(lifeMapDTO: LifeMapDTO, lifeMapCountDTO: LifeMapCountDTO) : this(
lifeMapId = lifeMapDTO.lifeMapId,
goals = lifeMapDTO.goals,
count = lifeMapCountDTO,
user = lifeMapDTO.user,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.raemian.api.lifemap.domain

import io.raemian.api.user.domain.UserSubset

data class ExploreResponse(
val lifeMapId: Long,
val goals: List<GoalDto>,
val count: CountResponse,
val user: UserSubset?,
) {

constructor(exploreDTO: ExploreDTO) : this(
lifeMapId = exploreDTO.lifeMapId,
goals = exploreDTO.goals,
user = exploreDTO.user,
count = CountResponse(exploreDTO.count, 0),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.raemian.api.lifemap.domain

data class ExploreResponses(
val lifeMaps: List<ExploreResponse>,
val cursor: Cursor,
) {
constructor(exploreDTOs: List<ExploreDTO>) : this(
lifeMaps = exploreDTOs.map { ExploreResponse(it) },
cursor = Cursor(exploreDTOs),
)

data class Cursor(
val next: Long,
// val prev: Long
) {
constructor(exploreDTOs: List<ExploreDTO>) : this(
next = exploreDTOs.lastOrNull()?.lifeMapId ?: Long.MIN_VALUE,
// prev = exploreDTOs.firstOrNull()?.lifeMapId ?: Long.MAX_VALUE
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,4 @@ data class LifeMapResponse(
user = lifeMapDTO.user,
count = CountResponse(viewCount, cheeringCountResponse),
)

data class CountResponse(
val view: Long,
val cheering: Long,
val history: Long? = null,
) {
constructor(lifeMapCountDTO: LifeMapCountDTO, cheeringCount: Long) : this(
view = lifeMapCountDTO.viewCount,
cheering = cheeringCount,
history = lifeMapCountDTO.historyCount,
)
constructor(viewCount: Long, cheeringCountResponse: CheeringCountResponse) : this(
view = viewCount,
cheering = cheeringCountResponse.count,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class OAuth2UserServiceTest {
)
}

@Test
// @Test
@DisplayName("OAuth 회원가입시 기본적으로 LifeMap 한개가 주어진다.")
@Transactional
fun createUserDefaultLifeMapTest() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package io.raemian.storage.db.core.goal

import io.raemian.storage.db.core.lifemap.LifeMap
import org.springframework.data.jpa.repository.JpaRepository
import java.time.LocalDateTime

interface GoalRepository : JpaRepository<Goal, Long> {
fun findUserByCreatedAtGreaterThanEqual(createdAt: LocalDateTime): List<Goal>

fun countGoalByLifeMap(lifeMap: LifeMap): Int

override fun getById(id: Long): Goal =
findById(id).orElseThrow() { NoSuchElementException("목표가 없습니다 $id") }
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import jakarta.persistence.Table
@Entity
@Table(name = "LIFE_MAPS")
class LifeMap(
@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
val user: User,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class LifeMapCount(
val lifeMapId: Long,
val viewCount: Long,
val historyCount: Long,
val goalCount: Long,
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
Expand All @@ -22,6 +23,7 @@ class LifeMapCount(
lifeMapId = lifeMapId,
viewCount = 0,
historyCount = 0,
goalCount = 0,
)
}
}
Expand All @@ -30,6 +32,7 @@ class LifeMapCount(
lifeMapId = lifeMapId,
viewCount = viewCount + 1,
historyCount = historyCount,
goalCount = goalCount,
id = id,
)
}
Expand All @@ -39,15 +42,17 @@ class LifeMapCount(
lifeMapId = lifeMapId,
viewCount = viewCount,
historyCount = historyCount + 1,
goalCount = goalCount,
id = id,
)
}

fun addCount(): LifeMapCount {
fun addGoalCount(): LifeMapCount {
return LifeMapCount(
lifeMapId = lifeMapId,
viewCount = viewCount + 1,
historyCount = historyCount + 1,
viewCount = viewCount,
historyCount = historyCount,
goalCount = goalCount + 1,
id = id,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.raemian.storage.db.core.lifemap
import org.springframework.data.repository.CrudRepository

interface LifeMapCountRepository : CrudRepository<LifeMapCount, Long> {

fun findByLifeMapId(lifeMapId: Long): LifeMapCount?

fun findAllByLifeMapIdIn(lifeMapIds: List<Long>): List<LifeMapCount>
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,35 @@
package io.raemian.storage.db.core.lifemap

import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param

interface LifeMapRepository : JpaRepository<LifeMap, Long> {

fun findFirstByUserId(userId: Long): LifeMap?

fun findFirstByUserUsername(username: String): LifeMap?

fun findAllByIdInOrderByIdDesc(ids: List<Long>): List<LifeMap>

@Query(
"""
SELECT
map.id
FROM
LifeMap as map,
LifeMapCount as count
WHERE 1 = 1
AND map.id = count.lifeMapId
AND count.goalCount > 2
AND map.id < :cursor
AND map.isPublic = true
ORDER BY
map.id DESC
LIMIT 5
""",
)
fun explore(
@Param("cursor") lifeMapId: Long,
): List<Long>
}

0 comments on commit 4f3a25a

Please sign in to comment.