캔 사용 시 국가 코드 기록 기능 추가 #374
@@ -14,6 +14,7 @@ import kr.co.vividnext.sodalive.can.use.UseCanCalculateRepository
|
|||||||
import kr.co.vividnext.sodalive.can.use.UseCanCalculateStatus
|
import kr.co.vividnext.sodalive.can.use.UseCanCalculateStatus
|
||||||
import kr.co.vividnext.sodalive.can.use.UseCanRepository
|
import kr.co.vividnext.sodalive.can.use.UseCanRepository
|
||||||
import kr.co.vividnext.sodalive.chat.character.image.CharacterImage
|
import kr.co.vividnext.sodalive.chat.character.image.CharacterImage
|
||||||
|
import kr.co.vividnext.sodalive.common.CountryContext
|
||||||
import kr.co.vividnext.sodalive.common.SodaException
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
import kr.co.vividnext.sodalive.content.AudioContent
|
import kr.co.vividnext.sodalive.content.AudioContent
|
||||||
import kr.co.vividnext.sodalive.content.order.Order
|
import kr.co.vividnext.sodalive.content.order.Order
|
||||||
@@ -35,7 +36,8 @@ class CanPaymentService(
|
|||||||
private val useCanRepository: UseCanRepository,
|
private val useCanRepository: UseCanRepository,
|
||||||
private val useCanCalculateRepository: UseCanCalculateRepository,
|
private val useCanCalculateRepository: UseCanCalculateRepository,
|
||||||
private val messageSource: SodaMessageSource,
|
private val messageSource: SodaMessageSource,
|
||||||
private val langContext: LangContext
|
private val langContext: LangContext,
|
||||||
|
private val countryContext: CountryContext
|
||||||
) {
|
) {
|
||||||
@Transactional
|
@Transactional
|
||||||
fun spendCan(
|
fun spendCan(
|
||||||
@@ -76,7 +78,8 @@ class CanPaymentService(
|
|||||||
canUsage = canUsage,
|
canUsage = canUsage,
|
||||||
can = useChargeCan?.total ?: 0,
|
can = useChargeCan?.total ?: 0,
|
||||||
rewardCan = useRewardCan.total,
|
rewardCan = useRewardCan.total,
|
||||||
isSecret = isSecret
|
isSecret = isSecret,
|
||||||
|
countryCode = countryContext.countryCode
|
||||||
)
|
)
|
||||||
|
|
||||||
var recipientId: Long? = null
|
var recipientId: Long? = null
|
||||||
@@ -378,7 +381,8 @@ class CanPaymentService(
|
|||||||
canUsage = CanUsage.CHARACTER_IMAGE_PURCHASE,
|
canUsage = CanUsage.CHARACTER_IMAGE_PURCHASE,
|
||||||
can = useChargeCan?.total ?: 0,
|
can = useChargeCan?.total ?: 0,
|
||||||
rewardCan = useRewardCan.total,
|
rewardCan = useRewardCan.total,
|
||||||
isSecret = false
|
isSecret = false,
|
||||||
|
countryCode = countryContext.countryCode
|
||||||
)
|
)
|
||||||
useCan.member = member
|
useCan.member = member
|
||||||
useCan.characterImage = image
|
useCan.characterImage = image
|
||||||
@@ -424,7 +428,8 @@ class CanPaymentService(
|
|||||||
canUsage = CanUsage.CHAT_MESSAGE_PURCHASE,
|
canUsage = CanUsage.CHAT_MESSAGE_PURCHASE,
|
||||||
can = useChargeCan?.total ?: 0,
|
can = useChargeCan?.total ?: 0,
|
||||||
rewardCan = useRewardCan.total,
|
rewardCan = useRewardCan.total,
|
||||||
isSecret = false
|
isSecret = false,
|
||||||
|
countryCode = countryContext.countryCode
|
||||||
)
|
)
|
||||||
useCan.member = member
|
useCan.member = member
|
||||||
useCan.chatMessage = message
|
useCan.chatMessage = message
|
||||||
|
|||||||
@@ -34,7 +34,10 @@ data class UseCan(
|
|||||||
|
|
||||||
// 채팅 연동을 위한 식별자 (옵션)
|
// 채팅 연동을 위한 식별자 (옵션)
|
||||||
var chatRoomId: Long? = null,
|
var chatRoomId: Long? = null,
|
||||||
var characterId: Long? = null
|
var characterId: Long? = null,
|
||||||
|
|
||||||
|
// ISO 3166-1 alpha-2 국가 코드
|
||||||
|
var countryCode: String? = null
|
||||||
) : BaseEntity() {
|
) : BaseEntity() {
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "member_id", nullable = false)
|
@JoinColumn(name = "member_id", nullable = false)
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package kr.co.vividnext.sodalive.common
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import org.springframework.web.context.annotation.RequestScope
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequestScope
|
||||||
|
class CountryContext {
|
||||||
|
var countryCode: String? = null
|
||||||
|
internal set
|
||||||
|
|
||||||
|
fun setCountryCode(code: String?) {
|
||||||
|
this.countryCode = code
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package kr.co.vividnext.sodalive.common
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor
|
||||||
|
import javax.servlet.http.HttpServletRequest
|
||||||
|
import javax.servlet.http.HttpServletResponse
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class CountryInterceptor(
|
||||||
|
private val countryContext: CountryContext
|
||||||
|
) : HandlerInterceptor {
|
||||||
|
override fun preHandle(
|
||||||
|
request: HttpServletRequest,
|
||||||
|
response: HttpServletResponse,
|
||||||
|
handler: Any
|
||||||
|
): Boolean {
|
||||||
|
val countryCode = request.getHeader("CloudFront-Viewer-Country")
|
||||||
|
countryContext.setCountryCode(countryCode)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package kr.co.vividnext.sodalive.configs
|
package kr.co.vividnext.sodalive.configs
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.common.CountryInterceptor
|
||||||
import kr.co.vividnext.sodalive.i18n.LangInterceptor
|
import kr.co.vividnext.sodalive.i18n.LangInterceptor
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry
|
import org.springframework.web.servlet.config.annotation.CorsRegistry
|
||||||
@@ -8,10 +9,12 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
class WebConfig(
|
class WebConfig(
|
||||||
private val langInterceptor: LangInterceptor
|
private val langInterceptor: LangInterceptor,
|
||||||
|
private val countryInterceptor: CountryInterceptor
|
||||||
) : WebMvcConfigurer {
|
) : WebMvcConfigurer {
|
||||||
override fun addInterceptors(registry: InterceptorRegistry) {
|
override fun addInterceptors(registry: InterceptorRegistry) {
|
||||||
registry.addInterceptor(langInterceptor).addPathPatterns("/**")
|
registry.addInterceptor(langInterceptor).addPathPatterns("/**")
|
||||||
|
registry.addInterceptor(countryInterceptor).addPathPatterns("/**")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addCorsMappings(registry: CorsRegistry) {
|
override fun addCorsMappings(registry: CorsRegistry) {
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ interface AudioContentQueryRepository {
|
|||||||
fun findByIdAndCreatorId(contentId: Long, creatorId: Long): AudioContent?
|
fun findByIdAndCreatorId(contentId: Long, creatorId: Long): AudioContent?
|
||||||
fun findByCreatorId(
|
fun findByCreatorId(
|
||||||
creatorId: Long,
|
creatorId: Long,
|
||||||
|
isCreator: Boolean = false,
|
||||||
coverImageHost: String,
|
coverImageHost: String,
|
||||||
isAdult: Boolean = false,
|
isAdult: Boolean = false,
|
||||||
contentType: ContentType = ContentType.ALL,
|
contentType: ContentType = ContentType.ALL,
|
||||||
@@ -55,6 +56,7 @@ interface AudioContentQueryRepository {
|
|||||||
|
|
||||||
fun findTotalCountByCreatorId(
|
fun findTotalCountByCreatorId(
|
||||||
creatorId: Long,
|
creatorId: Long,
|
||||||
|
isCreator: Boolean = false,
|
||||||
isAdult: Boolean = false,
|
isAdult: Boolean = false,
|
||||||
categoryId: Long = 0,
|
categoryId: Long = 0,
|
||||||
contentType: ContentType = ContentType.ALL
|
contentType: ContentType = ContentType.ALL
|
||||||
@@ -230,6 +232,7 @@ class AudioContentQueryRepositoryImpl(
|
|||||||
|
|
||||||
override fun findByCreatorId(
|
override fun findByCreatorId(
|
||||||
creatorId: Long,
|
creatorId: Long,
|
||||||
|
isCreator: Boolean,
|
||||||
coverImageHost: String,
|
coverImageHost: String,
|
||||||
isAdult: Boolean,
|
isAdult: Boolean,
|
||||||
contentType: ContentType,
|
contentType: ContentType,
|
||||||
@@ -246,11 +249,18 @@ class AudioContentQueryRepositoryImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var where = audioContent.member.id.eq(creatorId)
|
var where = audioContent.member.id.eq(creatorId)
|
||||||
.and(
|
|
||||||
|
where = if (isCreator) {
|
||||||
|
where.and(
|
||||||
|
audioContent.releaseDate.isNotNull
|
||||||
|
.and(audioContent.duration.isNotNull)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
where.and(
|
||||||
audioContent.isActive.isTrue
|
audioContent.isActive.isTrue
|
||||||
.and(audioContent.duration.isNotNull)
|
.and(audioContent.duration.isNotNull)
|
||||||
.or(audioContent.releaseDate.isNotNull.and(audioContent.duration.isNotNull))
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (!isAdult) {
|
if (!isAdult) {
|
||||||
where = where.and(audioContent.isAdult.isFalse)
|
where = where.and(audioContent.isAdult.isFalse)
|
||||||
@@ -332,16 +342,24 @@ class AudioContentQueryRepositoryImpl(
|
|||||||
|
|
||||||
override fun findTotalCountByCreatorId(
|
override fun findTotalCountByCreatorId(
|
||||||
creatorId: Long,
|
creatorId: Long,
|
||||||
|
isCreator: Boolean,
|
||||||
isAdult: Boolean,
|
isAdult: Boolean,
|
||||||
categoryId: Long,
|
categoryId: Long,
|
||||||
contentType: ContentType
|
contentType: ContentType
|
||||||
): Int {
|
): Int {
|
||||||
var where = audioContent.member.id.eq(creatorId)
|
var where = audioContent.member.id.eq(creatorId)
|
||||||
.and(
|
|
||||||
|
where = if (isCreator) {
|
||||||
|
where.and(
|
||||||
|
audioContent.releaseDate.isNotNull
|
||||||
|
.and(audioContent.duration.isNotNull)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
where.and(
|
||||||
audioContent.isActive.isTrue
|
audioContent.isActive.isTrue
|
||||||
.and(audioContent.duration.isNotNull)
|
.and(audioContent.duration.isNotNull)
|
||||||
.or(audioContent.releaseDate.isNotNull.and(audioContent.duration.isNotNull))
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (!isAdult) {
|
if (!isAdult) {
|
||||||
where = where.and(audioContent.isAdult.isFalse)
|
where = where.and(audioContent.isAdult.isFalse)
|
||||||
|
|||||||
@@ -979,9 +979,11 @@ class AudioContentService(
|
|||||||
limit: Long
|
limit: Long
|
||||||
): GetAudioContentListResponse {
|
): GetAudioContentListResponse {
|
||||||
val isAdult = member.auth != null && isAdultContentVisible
|
val isAdult = member.auth != null && isAdultContentVisible
|
||||||
|
val isCreator = member.id == creatorId
|
||||||
|
|
||||||
val totalCount = repository.findTotalCountByCreatorId(
|
val totalCount = repository.findTotalCountByCreatorId(
|
||||||
creatorId = creatorId,
|
creatorId = creatorId,
|
||||||
|
isCreator = isCreator,
|
||||||
isAdult = isAdult,
|
isAdult = isAdult,
|
||||||
categoryId = categoryId,
|
categoryId = categoryId,
|
||||||
contentType = contentType
|
contentType = contentType
|
||||||
@@ -989,6 +991,7 @@ class AudioContentService(
|
|||||||
|
|
||||||
val audioContentList = repository.findByCreatorId(
|
val audioContentList = repository.findByCreatorId(
|
||||||
creatorId = creatorId,
|
creatorId = creatorId,
|
||||||
|
isCreator = isCreator,
|
||||||
coverImageHost = coverImageHost,
|
coverImageHost = coverImageHost,
|
||||||
isAdult = isAdult,
|
isAdult = isAdult,
|
||||||
contentType = contentType,
|
contentType = contentType,
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import kr.co.vividnext.sodalive.member.tag.QCreatorTag.creatorTag
|
|||||||
import kr.co.vividnext.sodalive.member.tag.QMemberCreatorTag.memberCreatorTag
|
import kr.co.vividnext.sodalive.member.tag.QMemberCreatorTag.memberCreatorTag
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
|
import java.math.BigDecimal
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
@@ -651,6 +652,18 @@ class ExplorerQueryRepository(
|
|||||||
.fetchFirst()
|
.fetchFirst()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getPaidContentCount(creatorId: Long): Long? {
|
||||||
|
return queryFactory
|
||||||
|
.select(audioContent.id.count())
|
||||||
|
.from(audioContent)
|
||||||
|
.where(
|
||||||
|
audioContent.isActive.isTrue
|
||||||
|
.and(audioContent.member.id.eq(creatorId))
|
||||||
|
.and(audioContent.price.gt(BigDecimal.ZERO))
|
||||||
|
)
|
||||||
|
.fetchFirst()
|
||||||
|
}
|
||||||
|
|
||||||
fun getOwnedContentCount(creatorId: Long, memberId: Long): Long {
|
fun getOwnedContentCount(creatorId: Long, memberId: Long): Long {
|
||||||
// 활성 주문 + 대여의 경우 유효기간 내 주문만 포함, 동일 콘텐츠 중복 구매는 1개로 카운트
|
// 활성 주문 + 대여의 경우 유효기간 내 주문만 포함, 동일 콘텐츠 중복 구매는 1개로 카운트
|
||||||
return queryFactory
|
return queryFactory
|
||||||
|
|||||||
@@ -287,9 +287,9 @@ class ExplorerService(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
// 크리에이터의 전체 콘텐츠 개수
|
// 크리에이터의 전체 유료 콘텐츠 개수
|
||||||
val totalContentCount = if (isCreator) {
|
val totalContentCount = if (isCreator) {
|
||||||
queryRepository.getContentCount(creatorId) ?: 0
|
queryRepository.getPaidContentCount(creatorId) ?: 0
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user