Merge pull request '이벤트 배너, 충전 이벤트 - 기간 설정에 시간 추가' (#285) from test into main

Reviewed-on: #285
This commit was merged in pull request #285.
This commit is contained in:
2025-03-14 03:40:07 +00:00
10 changed files with 76 additions and 75 deletions
@@ -2,10 +2,13 @@ package kr.co.vividnext.sodalive.admin.event.banner
import com.querydsl.core.types.dsl.DateTimePath import com.querydsl.core.types.dsl.DateTimePath
import com.querydsl.core.types.dsl.Expressions import com.querydsl.core.types.dsl.Expressions
import com.querydsl.core.types.dsl.StringExpression
import com.querydsl.core.types.dsl.StringPath
import com.querydsl.core.types.dsl.StringTemplate import com.querydsl.core.types.dsl.StringTemplate
import com.querydsl.jpa.impl.JPAQueryFactory import com.querydsl.jpa.impl.JPAQueryFactory
import kr.co.vividnext.sodalive.event.Event import kr.co.vividnext.sodalive.event.Event
import kr.co.vividnext.sodalive.event.QEvent.event import kr.co.vividnext.sodalive.event.QEvent.event
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.JpaRepository
import java.time.LocalDateTime import java.time.LocalDateTime
@@ -16,12 +19,13 @@ interface AdminEventBannerQueryRepository {
} }
class AdminEventBannerQueryRepositoryImpl( class AdminEventBannerQueryRepositoryImpl(
private val queryFactory: JPAQueryFactory private val queryFactory: JPAQueryFactory,
@Value("\${cloud.aws.cloud-front.host}")
private val cloudFrontHost: String
) : AdminEventBannerQueryRepository { ) : AdminEventBannerQueryRepository {
override fun getEventList(): List<GetAdminEventResponse> { override fun getEventList(): List<GetAdminEventResponse> {
val now = LocalDateTime.now() val now = LocalDateTime.now()
val where = event.isActive.isTrue val where = event.isActive.isTrue
.and(event.startDate.loe(now))
.and(event.endDate.goe(now)) .and(event.endDate.goe(now))
return queryFactory return queryFactory
@@ -29,9 +33,9 @@ class AdminEventBannerQueryRepositoryImpl(
QGetAdminEventResponse( QGetAdminEventResponse(
event.id, event.id,
event.title, event.title,
event.thumbnailImage, getProcessedUrlExpression(event.thumbnailImage),
event.detailImage, getProcessedUrlExpression(event.detailImage),
event.popupImage, getProcessedUrlExpression(event.popupImage),
getFormattedDate(event.startDate), getFormattedDate(event.startDate),
getFormattedDate(event.endDate), getFormattedDate(event.endDate),
event.link, event.link,
@@ -55,7 +59,14 @@ class AdminEventBannerQueryRepositoryImpl(
"UTC", "UTC",
"Asia/Seoul" "Asia/Seoul"
), ),
"%Y-%m-%d" "%Y-%m-%d %H:%i"
)
}
private fun getProcessedUrlExpression(path: StringPath): StringExpression {
return Expressions.stringTemplate(
"CASE WHEN {0} LIKE '$cloudFrontHost%' THEN {0} ELSE CONCAT('$cloudFrontHost/', {0}) END",
path
) )
} }
} }
@@ -10,7 +10,7 @@ import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional import org.springframework.transaction.annotation.Transactional
import org.springframework.web.multipart.MultipartFile import org.springframework.web.multipart.MultipartFile
import java.time.LocalDate import java.time.LocalDateTime
import java.time.ZoneId import java.time.ZoneId
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@@ -20,9 +20,7 @@ class AdminEventBannerService(
private val s3Uploader: S3Uploader, private val s3Uploader: S3Uploader,
@Value("\${cloud.aws.s3.bucket}") @Value("\${cloud.aws.s3.bucket}")
private val bucket: String, private val bucket: String
@Value("\${cloud.aws.cloud-front.host}")
private val cloudFrontHost: String
) { ) {
@Transactional @Transactional
fun save( fun save(
@@ -38,13 +36,13 @@ class AdminEventBannerService(
): Long { ): Long {
if (detail == null && link.isNullOrBlank()) throw SodaException("상세이미지 혹은 링크를 등록하세요") if (detail == null && link.isNullOrBlank()) throw SodaException("상세이미지 혹은 링크를 등록하세요")
val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
val startDate = LocalDate.parse(startDateString, dateTimeFormatter).atTime(0, 0) val startDate = LocalDateTime.parse(startDateString, dateTimeFormatter)
.atZone(ZoneId.of("Asia/Seoul")) .atZone(ZoneId.of("Asia/Seoul"))
.withZoneSameInstant(ZoneId.of("UTC")) .withZoneSameInstant(ZoneId.of("UTC"))
.toLocalDateTime() .toLocalDateTime()
val endDate = LocalDate.parse(endDateString, dateTimeFormatter).atTime(23, 59, 59) val endDate = LocalDateTime.parse(endDateString, dateTimeFormatter).withSecond(59)
.atZone(ZoneId.of("Asia/Seoul")) .atZone(ZoneId.of("Asia/Seoul"))
.withZoneSameInstant(ZoneId.of("UTC")) .withZoneSameInstant(ZoneId.of("UTC"))
.toLocalDateTime() .toLocalDateTime()
@@ -174,16 +172,16 @@ class AdminEventBannerService(
event.isAdult = isAdult event.isAdult = isAdult
} }
val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
if (startDateString != null) { if (startDateString != null) {
event.startDate = LocalDate.parse(startDateString, dateTimeFormatter).atTime(0, 0) event.startDate = LocalDateTime.parse(startDateString, dateTimeFormatter)
.atZone(ZoneId.of("Asia/Seoul")) .atZone(ZoneId.of("Asia/Seoul"))
.withZoneSameInstant(ZoneId.of("UTC")) .withZoneSameInstant(ZoneId.of("UTC"))
.toLocalDateTime() .toLocalDateTime()
} }
if (endDateString != null) { if (endDateString != null) {
event.endDate = LocalDate.parse(endDateString, dateTimeFormatter).atTime(23, 59, 59) event.endDate = LocalDateTime.parse(endDateString, dateTimeFormatter).withSecond(59)
.atZone(ZoneId.of("Asia/Seoul")) .atZone(ZoneId.of("Asia/Seoul"))
.withZoneSameInstant(ZoneId.of("UTC")) .withZoneSameInstant(ZoneId.of("UTC"))
.toLocalDateTime() .toLocalDateTime()
@@ -201,22 +199,5 @@ class AdminEventBannerService(
fun getEventList(): List<GetAdminEventResponse> { fun getEventList(): List<GetAdminEventResponse> {
return repository.getEventList() return repository.getEventList()
.asSequence()
.map {
if (!it.thumbnailImageUrl.startsWith("https://")) {
it.thumbnailImageUrl = "$cloudFrontHost/${it.thumbnailImageUrl}"
}
if (it.detailImageUrl != null && !it.detailImageUrl!!.startsWith("https://")) {
it.detailImageUrl = "$cloudFrontHost/${it.detailImageUrl}"
}
if (it.popupImageUrl != null && !it.popupImageUrl!!.startsWith("https://")) {
it.popupImageUrl = "$cloudFrontHost/${it.popupImageUrl}"
}
it
}
.toList()
} }
} }
@@ -5,11 +5,11 @@ import com.querydsl.core.annotations.QueryProjection
data class GetAdminEventResponse @QueryProjection constructor( data class GetAdminEventResponse @QueryProjection constructor(
val id: Long, val id: Long,
val title: String? = null, val title: String? = null,
var thumbnailImageUrl: String, val thumbnailImageUrl: String,
var detailImageUrl: String? = null, val detailImageUrl: String? = null,
var popupImageUrl: String? = null, val popupImageUrl: String? = null,
var startDate: String, val startDate: String,
var endDate: String, val endDate: String,
val link: String? = null, val link: String? = null,
val isAdult: Boolean? = null, val isAdult: Boolean? = null,
val isPopup: Boolean val isPopup: Boolean
@@ -1,22 +1,51 @@
package kr.co.vividnext.sodalive.admin.event.charge package kr.co.vividnext.sodalive.admin.event.charge
import com.querydsl.core.types.dsl.DateTimePath
import com.querydsl.core.types.dsl.Expressions
import com.querydsl.core.types.dsl.StringTemplate
import com.querydsl.jpa.impl.JPAQueryFactory import com.querydsl.jpa.impl.JPAQueryFactory
import kr.co.vividnext.sodalive.admin.event.charge.QChargeEvent.chargeEvent import kr.co.vividnext.sodalive.admin.event.charge.QChargeEvent.chargeEvent
import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
import java.time.LocalDateTime
@Repository @Repository
interface AdminChargeEventRepository : JpaRepository<ChargeEvent, Long>, AdminChargeEventQueryRepository interface AdminChargeEventRepository : JpaRepository<ChargeEvent, Long>, AdminChargeEventQueryRepository
interface AdminChargeEventQueryRepository { interface AdminChargeEventQueryRepository {
fun getChargeEventList(): List<ChargeEvent> fun getChargeEventList(): List<GetChargeEventListResponse>
} }
class AdminChargeEventQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : AdminChargeEventQueryRepository { class AdminChargeEventQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : AdminChargeEventQueryRepository {
override fun getChargeEventList(): List<ChargeEvent> { override fun getChargeEventList(): List<GetChargeEventListResponse> {
return queryFactory return queryFactory
.selectFrom(chargeEvent) .select(
QGetChargeEventListResponse(
chargeEvent.id,
chargeEvent.title,
getFormattedDate(chargeEvent.startDate),
getFormattedDate(chargeEvent.endDate),
chargeEvent.availableCount,
chargeEvent.addPercent.multiply(100).castToNum(Int::class.java),
chargeEvent.isActive
)
)
.from(chargeEvent)
.orderBy(chargeEvent.createdAt.desc()) .orderBy(chargeEvent.createdAt.desc())
.fetch() .fetch()
} }
private fun getFormattedDate(dateTimePath: DateTimePath<LocalDateTime>): StringTemplate {
return Expressions.stringTemplate(
"DATE_FORMAT({0}, {1})",
Expressions.dateTimeTemplate(
LocalDateTime::class.java,
"CONVERT_TZ({0},{1},{2})",
dateTimePath,
"UTC",
"Asia/Seoul"
),
"%Y-%m-%d %H:%i"
)
}
} }
@@ -4,7 +4,7 @@ import kr.co.vividnext.sodalive.common.SodaException
import org.springframework.data.repository.findByIdOrNull import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional import org.springframework.transaction.annotation.Transactional
import java.time.LocalDate import java.time.LocalDateTime
import java.time.ZoneId import java.time.ZoneId
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@@ -13,13 +13,13 @@ import java.time.format.DateTimeFormatter
class AdminChargeEventService(private val repository: AdminChargeEventRepository) { class AdminChargeEventService(private val repository: AdminChargeEventRepository) {
@Transactional @Transactional
fun createChargeEvent(request: CreateChargeEventRequest): Long { fun createChargeEvent(request: CreateChargeEventRequest): Long {
val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
val startDate = LocalDate.parse(request.startDateString, dateTimeFormatter).atTime(0, 0) val startDate = LocalDateTime.parse(request.startDateString, dateTimeFormatter)
.atZone(ZoneId.of("Asia/Seoul")) .atZone(ZoneId.of("Asia/Seoul"))
.withZoneSameInstant(ZoneId.of("UTC")) .withZoneSameInstant(ZoneId.of("UTC"))
.toLocalDateTime() .toLocalDateTime()
val endDate = LocalDate.parse(request.endDateString, dateTimeFormatter).atTime(23, 59, 59) val endDate = LocalDateTime.parse(request.endDateString, dateTimeFormatter).withSecond(59)
.atZone(ZoneId.of("Asia/Seoul")) .atZone(ZoneId.of("Asia/Seoul"))
.withZoneSameInstant(ZoneId.of("UTC")) .withZoneSameInstant(ZoneId.of("UTC"))
.toLocalDateTime() .toLocalDateTime()
@@ -44,16 +44,16 @@ class AdminChargeEventService(private val repository: AdminChargeEventRepository
chargeEvent.title = request.title chargeEvent.title = request.title
} }
val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
if (request.startDateString != null) { if (request.startDateString != null) {
chargeEvent.startDate = LocalDate.parse(request.startDateString, dateTimeFormatter).atTime(0, 0) chargeEvent.startDate = LocalDateTime.parse(request.startDateString, dateTimeFormatter)
.atZone(ZoneId.of("Asia/Seoul")) .atZone(ZoneId.of("Asia/Seoul"))
.withZoneSameInstant(ZoneId.of("UTC")) .withZoneSameInstant(ZoneId.of("UTC"))
.toLocalDateTime() .toLocalDateTime()
} }
if (request.endDateString != null) { if (request.endDateString != null) {
chargeEvent.endDate = LocalDate.parse(request.endDateString, dateTimeFormatter).atTime(23, 59, 59) chargeEvent.endDate = LocalDateTime.parse(request.endDateString, dateTimeFormatter).withSecond(59)
.atZone(ZoneId.of("Asia/Seoul")) .atZone(ZoneId.of("Asia/Seoul"))
.withZoneSameInstant(ZoneId.of("UTC")) .withZoneSameInstant(ZoneId.of("UTC"))
.toLocalDateTime() .toLocalDateTime()
@@ -74,27 +74,5 @@ class AdminChargeEventService(private val repository: AdminChargeEventRepository
fun getChargeEventList(): List<GetChargeEventListResponse> { fun getChargeEventList(): List<GetChargeEventListResponse> {
return repository.getChargeEventList() return repository.getChargeEventList()
.map {
val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
val startDate = it.startDate
.atZone(ZoneId.of("UTC"))
.withZoneSameInstant(ZoneId.of("Asia/Seoul"))
.format(dateTimeFormatter)
val endDate = it.endDate
.atZone(ZoneId.of("UTC"))
.withZoneSameInstant(ZoneId.of("Asia/Seoul"))
.format(dateTimeFormatter)
GetChargeEventListResponse(
id = it.id!!,
title = it.title,
startDate = startDate,
endDate = endDate,
availableCount = it.availableCount,
addPercent = (it.addPercent * 100).toInt(),
isActive = it.isActive
)
}
} }
} }
@@ -1,6 +1,8 @@
package kr.co.vividnext.sodalive.admin.event.charge package kr.co.vividnext.sodalive.admin.event.charge
data class GetChargeEventListResponse( import com.querydsl.core.annotations.QueryProjection
data class GetChargeEventListResponse @QueryProjection constructor(
val id: Long, val id: Long,
val title: String, val title: String,
val startDate: String, val startDate: String,
@@ -1,4 +1,4 @@
package kr.co.vividnext.sodalive.admin.marketing.statistics package kr.co.vividnext.sodalive.admin.statistics.ad
import kr.co.vividnext.sodalive.common.ApiResponse import kr.co.vividnext.sodalive.common.ApiResponse
import org.springframework.data.domain.Pageable import org.springframework.data.domain.Pageable
@@ -1,4 +1,4 @@
package kr.co.vividnext.sodalive.admin.marketing.statistics package kr.co.vividnext.sodalive.admin.statistics.ad
import com.querydsl.core.types.dsl.CaseBuilder import com.querydsl.core.types.dsl.CaseBuilder
import com.querydsl.core.types.dsl.DateTimePath import com.querydsl.core.types.dsl.DateTimePath
@@ -1,4 +1,4 @@
package kr.co.vividnext.sodalive.admin.marketing.statistics package kr.co.vividnext.sodalive.admin.statistics.ad
import kr.co.vividnext.sodalive.extensions.convertLocalDateTime import kr.co.vividnext.sodalive.extensions.convertLocalDateTime
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@@ -1,4 +1,4 @@
package kr.co.vividnext.sodalive.admin.marketing.statistics package kr.co.vividnext.sodalive.admin.statistics.ad
import com.querydsl.core.annotations.QueryProjection import com.querydsl.core.annotations.QueryProjection