Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@ data class CafeCategoryItemDetailPayloadResponse(
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
)
val mapUrl: String?,
@field:Schema(
description = "์—ฐ๊ฒฐ๋œ ๋ฒš๊ฝƒ๊ธธ ID",
example = "15",
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
)
val flowerSpotId: Long?,
@field:Schema(
description = "์ตœ๊ทผ ๋ฐฉ๋ฌธ ํšŸ์ˆ˜",
example = "12",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ data class MapCategoryItemDetailResponse(
CafeCategoryItemDetailPayloadResponse(
thumbnailUrl = item.thumbnailUrl,
mapUrl = item.mapUrl,
flowerSpotId = item.flowerSpotId,
recentlyVisitedCount = item.recentlyVisitedCount,
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ data class MapCategoryItemResponse(
)
val endDate: LocalDate?,
@field:Schema(
description = "๋ฒš๊ฝƒ๊ธธ ID (CAFE์ธ ๊ฒฝ์šฐ์—๋งŒ ํฌํ•จ)",
description = "๋ฒš๊ฝƒ๊ธธ ID (FLOWER_SPOT์ธ ๊ฒฝ์šฐ์—๋งŒ ํฌํ•จ)",
example = "15",
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import io.swagger.v3.oas.annotations.media.Schema

@Schema(description = "๊ฝƒ ๋ช…์†Œ ์นดํŽ˜ ์ƒ์„ฑ ์š”์ฒญ")
data class FlowerSpotCafeCreateRequest(
@Schema(description = "๊ฝƒ ๋ช…์†Œ ID", example = "1")
val flowerSpotId: Long,
@Schema(description = "์นดํŽ˜ ์ด๋ฆ„", example = "๋ฒš๊ฝƒ ์นดํŽ˜")
val name: String,
@Schema(description = "์ฃผ์†Œ", example = "์„œ์šธํŠน๋ณ„์‹œ ์˜๋“ฑํฌ๊ตฌ ์—ฌ์˜๋„๋™", required = false)
Expand All @@ -33,7 +31,6 @@ data class FlowerSpotCafeCreateRequest(

fun toNewFlowerSpotCafe(): NewFlowerSpotCafe =
NewFlowerSpotCafe(
flowerSpotId = flowerSpotId,
name = name,
address = address,
description = description,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ data class Blooming(
val userId: Long,
val flowerSpotId: Long?,
val flowerEventId: Long?,
val flowerSpotCafeId: Long?,
val createdAt: LocalDateTime,
) {
init {
require((flowerSpotId == null) != (flowerEventId == null))
val nonNullCount = listOfNotNull(flowerSpotId, flowerEventId, flowerSpotCafeId).size
require(nonNullCount == 1)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,31 @@ class BloomingFacade(
suspend fun readBloomingDetails(
flowerSpotId: Long? = null,
flowerEventId: Long? = null,
flowerSpotCafeId: Long? = null,
): BloomingDetails =
when {
flowerSpotId != null && flowerEventId == null -> readBloomingDetailsBySpotId(flowerSpotId)
flowerSpotId == null && flowerEventId != null -> readBloomingDetailsByEventId(flowerEventId)
flowerSpotId != null && flowerEventId == null && flowerSpotCafeId == null -> readBloomingDetailsBySpotId(flowerSpotId)
flowerSpotId == null && flowerEventId != null && flowerSpotCafeId == null -> readBloomingDetailsByEventId(flowerEventId)
flowerSpotId == null && flowerEventId == null && flowerSpotCafeId != null -> readBloomingDetailsByCafeId(flowerSpotCafeId)
else -> throw ErrorException(ErrorType.INVALID_REQUEST)
}

private suspend fun readBloomingDetailsByCafeId(flowerSpotCafeId: Long): BloomingDetails =
coroutineScope {
val bloomings = bloomingService.recentlyBloomingByCafeId(flowerSpotCafeId)
val latestBlooming = bloomings.maxByOrNull { it.createdAt }
val userProfileDeferred =
async {
latestBlooming?.userId?.let { userService.getProfile(it) }
}

return@coroutineScope buildBloomingDetails(
bloomings = bloomings,
nickname = userProfileDeferred.await()?.nickname,
updatedAt = latestBlooming?.createdAt,
)
}

private suspend fun readBloomingDetailsByEventId(flowerEventId: Long): BloomingDetails =
coroutineScope {
val bloomings = bloomingService.recentlyBloomingByEventId(flowerEventId)
Expand All @@ -105,6 +123,7 @@ class BloomingFacade(
when (newBlooming) {
is NewBlooming.FlowerSpot -> ImagePrefix.FLOWERSPOT.value to newBlooming.flowerSpotId
is NewBlooming.FlowerEvent -> ImagePrefix.FLOWEREVENT.value to newBlooming.flowerEventId
is NewBlooming.FlowerSpotCafe -> ImagePrefix.FLOWERSPOT.value to newBlooming.flowerSpotCafeId
}

return BloomingImageUploadUrl.from(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ class BloomingFinder(
flowerEventId: Long,
): Blooming? = bloomingRepository.findTopByUserIdAndEventIdDesc(userId, flowerEventId)

suspend fun readTopByUserIdAndFlowerSpotCafeIdDesc(
userId: Long,
flowerSpotCafeId: Long,
): Blooming? = bloomingRepository.findTopByUserIdAndCafeIdDesc(userId, flowerSpotCafeId)

suspend fun readAllByUserId(userId: Long): List<Blooming> = bloomingRepository.findAllByUserId(userId)

suspend fun readAllByFlowerSpotId(flowerSpotId: Long): List<Blooming> = bloomingRepository.findAllByFlowerSpotId(flowerSpotId)
Expand All @@ -24,10 +29,14 @@ class BloomingFinder(

suspend fun readRecentlyBloomingByEventId(eventId: Long): List<Blooming> = bloomingRepository.findRecentlyByEventId(eventId)

suspend fun readRecentlyBloomingByCafeId(cafeId: Long): List<Blooming> = bloomingRepository.findRecentlyByCafeId(cafeId)

fun recentlyBloomingBySpotIds(spotIds: List<Long>): List<Blooming> = bloomingRepository.findRecentBySpotIds(spotIds)

fun recentlyBloomingByEventIds(eventIds: List<Long>): List<Blooming> = bloomingRepository.findRecentByEventIds(eventIds)

fun recentlyBloomingByCafeIds(cafeIds: List<Long>): List<Blooming> = bloomingRepository.findRecentByCafeIds(cafeIds)

fun readTodayBloomingByUserId(
userId: Long,
flowerSpotId: Long,
Expand All @@ -37,4 +46,9 @@ class BloomingFinder(
userId: Long,
flowerEventId: Long,
): Blooming? = bloomingRepository.findTodayEventBloomingByUserId(userId, flowerEventId)

fun readTodayBloomingByUserIdAndFlowerSpotCafeId(
userId: Long,
flowerSpotCafeId: Long,
): Blooming? = bloomingRepository.findTodayCafeBloomingByUserId(userId, flowerSpotCafeId)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ interface BloomingRepository {
flowerEventId: Long,
): Blooming?

suspend fun findTopByUserIdAndCafeIdDesc(
userId: Long,
flowerSpotCafeId: Long,
): Blooming?

suspend fun findAllByUserId(userId: Long): List<Blooming>

suspend fun findAllByFlowerSpotId(flowerSpotId: Long): List<Blooming>
Expand All @@ -24,10 +29,14 @@ interface BloomingRepository {

suspend fun findRecentlyByEventId(eventId: Long): List<Blooming>

suspend fun findRecentlyByCafeId(cafeId: Long): List<Blooming>

fun findRecentBySpotIds(spotIds: List<Long>): List<Blooming>

fun findRecentByEventIds(eventIds: List<Long>): List<Blooming>

fun findRecentByCafeIds(cafeIds: List<Long>): List<Blooming>

fun findTodayBloomingByUserId(
userId: Long,
flowerSpotId: Long,
Expand All @@ -38,6 +47,11 @@ interface BloomingRepository {
flowerEventId: Long,
): Blooming?

fun findTodayCafeBloomingByUserId(
userId: Long,
flowerSpotCafeId: Long,
): Blooming?

fun findBloomedSpotIdsByFlowerSpotIds(spotIds: List<Long>): List<Long>

fun findBloomedEventIdsByFlowerEventIds(eventIds: List<Long>): List<Long>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class BloomingService(
companion object {
const val BLOOMING_SPOT_KEY = "blooming:spot"
const val BLOOMING_EVENT_KEY = "blooming:event"
const val BLOOMING_CAFE_KEY = "blooming:cafe"
const val BLOOMING_TTL = 30L
}

Expand All @@ -29,6 +30,11 @@ class BloomingService(
newBlooming.userId,
newBlooming.flowerEventId,
)
is NewBlooming.FlowerSpotCafe ->
bloomingFinder.readTopByUserIdAndFlowerSpotCafeIdDesc(
newBlooming.userId,
newBlooming.flowerSpotCafeId,
)
}
bloomingValidator.addValidate(blooming)

Expand All @@ -41,12 +47,17 @@ class BloomingService(

suspend fun recentlyBloomingByEventId(eventId: Long): List<Blooming> = bloomingFinder.readRecentlyBloomingByEventId(eventId)

suspend fun recentlyBloomingByCafeId(cafeId: Long): List<Blooming> = bloomingFinder.readRecentlyBloomingByCafeId(cafeId)

fun recentlyBloomingBySpotIds(spotIds: List<Long>): List<Blooming> =
spotIds.flatMap { spotId -> cachedRecentlyBloomingBySpotId(spotId) }

fun recentlyBloomingByEventIds(eventIds: List<Long>): List<Blooming> =
eventIds.flatMap { eventId -> cachedRecentlyBloomingByEventId(eventId) }

fun recentlyBloomingByCafeIds(cafeIds: List<Long>): List<Blooming> =
cafeIds.flatMap { cafeId -> cachedRecentlyBloomingByCafeId(cafeId) }

private fun cachedRecentlyBloomingBySpotId(spotId: Long): List<Blooming> =
Cache.cacheBlocking(
ttl = BLOOMING_TTL,
Expand All @@ -65,20 +76,29 @@ class BloomingService(
bloomingFinder.recentlyBloomingByEventIds(listOf(eventId))
}

private fun cachedRecentlyBloomingByCafeId(cafeId: Long): List<Blooming> =
Cache.cacheBlocking(
ttl = BLOOMING_TTL,
key = "$BLOOMING_CAFE_KEY:$cafeId",
typeReference = object : TypeReference<List<Blooming>>() {},
) {
bloomingFinder.recentlyBloomingByCafeIds(listOf(cafeId))
}

fun verifyTodayBlooming(
userId: Long,
flowerSpotId: Long? = null,
flowerEventId: Long? = null,
flowerSpotCafeId: Long? = null,
): Boolean {
val blooming =
when {
flowerSpotId != null && flowerEventId == null -> bloomingFinder.readTodayBloomingByUserId(userId, flowerSpotId)
flowerSpotId == null && flowerEventId != null ->
bloomingFinder.readTodayBloomingByUserIdAndFlowerEventId(
userId,
flowerEventId,
)

flowerSpotId != null && flowerEventId == null && flowerSpotCafeId == null ->
bloomingFinder.readTodayBloomingByUserId(userId, flowerSpotId)
flowerSpotId == null && flowerEventId != null && flowerSpotCafeId == null ->
bloomingFinder.readTodayBloomingByUserIdAndFlowerEventId(userId, flowerEventId)
flowerSpotId == null && flowerEventId == null && flowerSpotCafeId != null ->
bloomingFinder.readTodayBloomingByUserIdAndFlowerSpotCafeId(userId, flowerSpotCafeId)
else -> throw ErrorException(ErrorType.INVALID_REQUEST)
}

Expand All @@ -89,6 +109,7 @@ class BloomingService(
when (newBlooming) {
is NewBlooming.FlowerSpot -> cacheRepository.delete("$BLOOMING_SPOT_KEY:${newBlooming.flowerSpotId}")
is NewBlooming.FlowerEvent -> cacheRepository.delete("$BLOOMING_EVENT_KEY:${newBlooming.flowerEventId}")
is NewBlooming.FlowerSpotCafe -> cacheRepository.delete("$BLOOMING_CAFE_KEY:${newBlooming.flowerSpotCafeId}")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ sealed class NewBlooming {
abstract val status: BloomingStatus
abstract val flowerSpotId: Long?
abstract val flowerEventId: Long?
abstract val flowerSpotCafeId: Long?

data class FlowerSpot(
override val userId: Long,
override val flowerSpotId: Long,
override val status: BloomingStatus,
) : NewBlooming() {
override val flowerEventId: Long? = null
override val flowerSpotCafeId: Long? = null
}

data class FlowerEvent(
Expand All @@ -20,5 +22,15 @@ sealed class NewBlooming {
override val status: BloomingStatus,
) : NewBlooming() {
override val flowerSpotId: Long? = null
override val flowerSpotCafeId: Long? = null
}

data class FlowerSpotCafe(
override val userId: Long,
override val flowerSpotCafeId: Long,
override val status: BloomingStatus,
) : NewBlooming() {
override val flowerSpotId: Long? = null
override val flowerEventId: Long? = null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class CafeCategoryItemDetailReadStrategy(
itemId: Long,
): MapCategoryItemDetail {
val cafe = flowerSpotCafeFinder.readBy(itemId)
val bloomingDetails = bloomingFacade.readBloomingDetails(flowerSpotId = cafe.flowerSpotId)
val bloomingDetails = bloomingFacade.readBloomingDetails(flowerSpotCafeId = cafe.id)
val representativeBloomingStatus = bloomingDetails.representativeBloomingStatus()
val badges =
mapCategoryBadgeFinder.findAllGroupedByTarget(
Expand All @@ -45,7 +45,6 @@ class CafeCategoryItemDetailReadStrategy(
pinPoint = cafe.pinPoint,
region = cafe.region,
mapUrl = cafe.mapUrl,
flowerSpotId = cafe.flowerSpotId,
recentlyVisitedCount = bloomingDetails.totalCount,
bloomingStatus = representativeBloomingStatus,
badges =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,18 @@ class CafeCategoryItemReadStrategy(
}.let { items ->
region?.let { targetRegion -> items.filter { it.region == targetRegion } } ?: items
}
val recentBloomingBySpotId =
val recentBloomingByCafeId =
bloomingService
.recentlyBloomingBySpotIds(cafes.map { it.flowerSpotId })
.groupBy { it.flowerSpotId }
.recentlyBloomingByCafeIds(cafes.map { it.id })
.groupBy { it.flowerSpotCafeId }
val badgesByCafeId =
mapCategoryBadgeFinder.findAllGroupedByTarget(
targetType = MapCategoryBadgeTargetType.FLOWER_SPOT_CAFE,
targetIds = cafes.map { it.id },
)

return cafes.map { cafe ->
val recentBloomings = recentBloomingBySpotId[cafe.flowerSpotId] ?: emptyList()
val recentBloomings = recentBloomingByCafeId[cafe.id] ?: emptyList()
val representativeBloomingStatus =
recentBloomings
.groupBy { it.status }
Expand All @@ -65,7 +65,6 @@ class CafeCategoryItemReadStrategy(
pinPoint = cafe.pinPoint,
region = cafe.region,
mapUrl = cafe.mapUrl,
flowerSpotId = cafe.flowerSpotId,
recentlyVisitedCount = recentBloomings.size.toLong(),
bloomingStatus = representativeBloomingStatus,
badges =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import java.time.LocalDateTime

data class FlowerSpotCafe(
val id: Long,
val flowerSpotId: Long,
val name: String,
val address: String?,
val description: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,4 @@ class FlowerSpotCafeFinder(
suspend fun readAll(): List<FlowerSpotCafe> = flowerSpotCafeRepository.findAll()

suspend fun readAllByLocation(location: FlowerSpotLocation): List<FlowerSpotCafe> = flowerSpotCafeRepository.findAllByLocation(location)

suspend fun readAllByFlowerSpotId(flowerSpotId: Long): List<FlowerSpotCafe> =
flowerSpotCafeRepository.findAllByFlowerSpotId(flowerSpotId)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ interface FlowerSpotCafeRepository {

suspend fun findAllByLocation(location: FlowerSpotLocation): List<FlowerSpotCafe>

suspend fun findAllByFlowerSpotId(flowerSpotId: Long): List<FlowerSpotCafe>

suspend fun save(cafe: FlowerSpotCafe): FlowerSpotCafe

suspend fun updateThumbnailUrl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import com.pida.support.geo.GeoJson
import com.pida.support.geo.Region

data class NewFlowerSpotCafe(
val flowerSpotId: Long,
val name: String,
val address: String?,
val description: String?,
Expand All @@ -16,7 +15,6 @@ data class NewFlowerSpotCafe(
fun toDomain(): FlowerSpotCafe =
FlowerSpotCafe(
id = 0,
flowerSpotId = flowerSpotId,
name = name,
address = address,
description = description,
Expand Down
Loading
Loading