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

Reviewed-on: #285
This commit is contained in:
klaus 2025-03-14 03:40:07 +00:00
commit c26680de84
10 changed files with 76 additions and 75 deletions

View File

@ -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
) )
} }
} }

View File

@ -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()
} }
} }

View File

@ -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

View File

@ -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"
)
}
} }

View File

@ -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
)
}
} }
} }

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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