189 lines
7.2 KiB
Kotlin
189 lines
7.2 KiB
Kotlin
package kr.co.vividnext.sodalive.useraction
|
|
|
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
|
import kotlinx.coroutines.CoroutineScope
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.cancel
|
|
import kotlinx.coroutines.launch
|
|
import kotlinx.coroutines.withContext
|
|
import kr.co.vividnext.sodalive.content.order.Order
|
|
import kr.co.vividnext.sodalive.content.order.OrderRepository
|
|
import kr.co.vividnext.sodalive.member.auth.AuthRepository
|
|
import kr.co.vividnext.sodalive.point.MemberPoint
|
|
import kr.co.vividnext.sodalive.point.MemberPointRepository
|
|
import kr.co.vividnext.sodalive.point.PointGrantLog
|
|
import kr.co.vividnext.sodalive.point.PointGrantLogRepository
|
|
import kr.co.vividnext.sodalive.point.PointRewardPolicyRepository
|
|
import org.slf4j.LoggerFactory
|
|
import org.springframework.stereotype.Service
|
|
import org.springframework.transaction.support.TransactionTemplate
|
|
import java.time.LocalDateTime
|
|
import javax.annotation.PreDestroy
|
|
|
|
@Service
|
|
class UserActionService(
|
|
private val repository: UserActionLogRepository,
|
|
private val orderRepository: OrderRepository,
|
|
private val policyRepository: PointRewardPolicyRepository,
|
|
private val grantLogRepository: PointGrantLogRepository,
|
|
private val memberPointRepository: MemberPointRepository,
|
|
private val transactionTemplate: TransactionTemplate,
|
|
private val authRepository: AuthRepository
|
|
) {
|
|
|
|
private val coroutineScope = CoroutineScope(
|
|
Dispatchers.IO + CoroutineExceptionHandler { _, e ->
|
|
logger.error("포인트 지급 또는 알림 실패: ${e.message}")
|
|
}
|
|
)
|
|
|
|
fun recordAction(
|
|
memberId: Long,
|
|
isAuth: Boolean,
|
|
actionType: ActionType,
|
|
contentId: Long? = null,
|
|
contentCommentId: Long? = null
|
|
) {
|
|
coroutineScope.launch {
|
|
var actionCount = 0
|
|
var grantedCount = 0
|
|
|
|
val order: Order?
|
|
var orderId: Long? = null
|
|
var point = 0
|
|
|
|
val now = LocalDateTime.now()
|
|
val policy = policyRepository.findByActionTypeAndIsActiveTrue(actionType, now)
|
|
if (policy != null) {
|
|
val policyType = policy.policyType
|
|
val todayAt15 = now.toLocalDate().atTime(15, 0)
|
|
val policyTypeDailyStartDate = if (now.toLocalTime().isBefore(todayAt15.toLocalTime())) {
|
|
now.toLocalDate().minusDays(1).atTime(15, 0)
|
|
} else {
|
|
todayAt15
|
|
}
|
|
|
|
val isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate =
|
|
policyType == PolicyType.DAILY && policyTypeDailyStartDate >= policy.startDate
|
|
order = if (contentId != null) {
|
|
orderRepository.findByMemberIdAndContentId(
|
|
memberId = memberId,
|
|
contentId = contentId,
|
|
createdAt = if (isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate) {
|
|
policyTypeDailyStartDate
|
|
} else {
|
|
policy.startDate
|
|
}
|
|
)
|
|
} else {
|
|
null
|
|
}
|
|
|
|
orderId = order?.id
|
|
if (actionType == ActionType.ORDER_CONTENT_COMMENT && order == null) return@launch
|
|
|
|
point = if (actionType == ActionType.ORDER_CONTENT_COMMENT && order != null) {
|
|
order.can
|
|
} else {
|
|
policy.pointAmount
|
|
}
|
|
|
|
actionCount = repository.countByMemberIdAndActionTypeAndCreatedAtBetween(
|
|
memberId = memberId,
|
|
actionType = actionType,
|
|
startDate = if (isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate) {
|
|
policyTypeDailyStartDate
|
|
} else {
|
|
policy.startDate
|
|
},
|
|
endDate = policy.endDate ?: LocalDateTime.now()
|
|
)
|
|
|
|
grantedCount = grantLogRepository.countByMemberIdAndPolicyIdAndStartDate(
|
|
memberId,
|
|
policy.id!!,
|
|
startDate = if (isValidPolicyTypeDailyAndDailyStartDateAfterPolicyStartDate) {
|
|
policyTypeDailyStartDate
|
|
} else {
|
|
policy.startDate
|
|
},
|
|
orderId = order?.id
|
|
)
|
|
}
|
|
|
|
withContext(Dispatchers.IO) {
|
|
transactionTemplate.execute {
|
|
repository.save(
|
|
UserActionLog(
|
|
memberId = memberId,
|
|
actionType = actionType,
|
|
contentCommentId = contentCommentId
|
|
)
|
|
)
|
|
repository.flush()
|
|
}
|
|
}
|
|
|
|
withContext(Dispatchers.IO) {
|
|
if (isAuth) {
|
|
try {
|
|
transactionTemplate.execute {
|
|
if (policy != null) {
|
|
if (actionCount + 1 < policy.threshold) return@execute
|
|
if (grantedCount >= policy.availableCount) return@execute
|
|
|
|
if (point > 0) {
|
|
grantLogRepository.save(
|
|
PointGrantLog(
|
|
memberId = memberId,
|
|
point = point,
|
|
actionType = actionType,
|
|
policyId = policy.id!!,
|
|
orderId = orderId
|
|
)
|
|
)
|
|
|
|
memberPointRepository.save(
|
|
MemberPoint(
|
|
memberId = memberId,
|
|
point = point,
|
|
actionType = actionType,
|
|
expiresAt = now.plusDays(3)
|
|
)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
} catch (e: Exception) {
|
|
logger.warn("포인트 지급 또는 알림 실패: ${e.message}")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun recordAction(
|
|
memberId: Long,
|
|
actionType: ActionType,
|
|
contentId: Long? = null,
|
|
contentCommentId: Long? = null
|
|
) {
|
|
recordAction(
|
|
memberId = memberId,
|
|
isAuth = authRepository.getAuthIdByMemberId(memberId) != null,
|
|
actionType = actionType,
|
|
contentId = contentId,
|
|
contentCommentId = contentCommentId
|
|
)
|
|
}
|
|
|
|
@PreDestroy
|
|
fun onDestroy() {
|
|
coroutineScope.cancel("UserActionService 종료")
|
|
}
|
|
|
|
companion object {
|
|
private val logger = LoggerFactory.getLogger(UserActionService::class.java)
|
|
}
|
|
}
|