Skip to content

Commit

Permalink
Merge branch 'dev' into feat/#412_belljun3395
Browse files Browse the repository at this point in the history
  • Loading branch information
belljun3395 authored Sep 27, 2024
2 parents 5450509 + 0694864 commit cea90e7
Show file tree
Hide file tree
Showing 14 changed files with 170 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class SubscriptionDao(
dslContext.insertInto(SUBSCRIPTION)
.set(SUBSCRIPTION.MEMBER_ID, command.memberId)
.set(SUBSCRIPTION.TARGET_WORKBOOK_ID, command.workbookId)
.set(SUBSCRIPTION.SEND_DAY, command.sendDay)
.set(SUBSCRIPTION.SEND_TIME, command.sendTime)

fun reSubscribeWorkbookSubscription(command: InsertWorkbookSubscriptionCommand) {
reSubscribeWorkBookSubscriptionCommand(command)
Expand All @@ -53,6 +55,8 @@ class SubscriptionDao(
.set(SUBSCRIPTION.DELETED_AT, null as LocalDateTime?)
.set(SUBSCRIPTION.UNSUBS_OPINION, null as String?)
.set(SUBSCRIPTION.MODIFIED_AT, LocalDateTime.now())
.set(SUBSCRIPTION.SEND_DAY, command.sendDay)
.set(SUBSCRIPTION.SEND_TIME, command.sendTime)
.where(SUBSCRIPTION.MEMBER_ID.eq(command.memberId))
.and(SUBSCRIPTION.TARGET_WORKBOOK_ID.eq(command.workbookId))

Expand Down Expand Up @@ -282,4 +286,20 @@ class SubscriptionDao(
.from(SUBSCRIPTION)
.where(SUBSCRIPTION.MEMBER_ID.eq(query.memberId))
.and(SUBSCRIPTION.TARGET_WORKBOOK_ID.eq(query.workbookId))

fun selectSubscriptionSendStatus(query: SelectSubscriptionSendStatusQuery): List<SubscriptionSendStatus> {
return selectSubscriptionSendStatusQuery(query)
.fetchInto(SubscriptionSendStatus::class.java)
}

fun selectSubscriptionSendStatusQuery(query: SelectSubscriptionSendStatusQuery) =
dslContext.select(
SUBSCRIPTION.MEMBER_ID,
SUBSCRIPTION.TARGET_WORKBOOK_ID,
SUBSCRIPTION.SEND_TIME,
SUBSCRIPTION.SEND_DAY
)
.from(SUBSCRIPTION)
.where(SUBSCRIPTION.MEMBER_ID.eq(query.memberId))
.and(SUBSCRIPTION.DELETED_AT.isNull)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package com.few.api.repo.dao.subscription.command

import com.few.data.common.code.DayCode
import java.time.LocalTime

data class InsertWorkbookSubscriptionCommand(
val workbookId: Long,
val memberId: Long,
val sendDay: String? = DayCode.MON_TUE_WED_THU_FRI.code,
val sendTime: LocalTime? = LocalTime.of(8, 0),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.few.api.repo.dao.subscription.query

data class SelectSubscriptionSendStatusQuery(
val memberId: Long,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.few.api.repo.dao.subscription.record

import java.time.LocalTime

data class SubscriptionSendStatus(
val memberId: Long,
val workbookId: Long,
val sendDay: String,
val sendTime: LocalTime,
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.few.api.domain.subscription.usecase.model.WorkbookSubscriptionStatus
import com.few.api.exception.common.NotFoundException
import com.few.api.exception.subscribe.SubscribeIllegalArgumentException
import com.few.api.repo.dao.subscription.query.CountWorkbookMappedArticlesQuery
import com.few.api.repo.dao.subscription.query.SelectSubscriptionSendStatusQuery
import org.springframework.context.ApplicationEventPublisher
import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Transactional
Expand All @@ -28,10 +29,28 @@ class SubscribeWorkbookUseCase(
fun execute(useCaseIn: SubscribeWorkbookUseCaseIn) {
val subTargetWorkbookId = useCaseIn.workbookId
val memberId = useCaseIn.memberId
val command = InsertWorkbookSubscriptionCommand(
memberId = memberId,
workbookId = subTargetWorkbookId
)

val command = subscriptionDao.selectSubscriptionSendStatus(
SelectSubscriptionSendStatusQuery(
memberId = memberId
)
).takeIf {
it.isNotEmpty()
}?.let {
/** 현재 구독 중인 정보가 있다면 해당 정보를 통해 구독 정보를 생성 */
InsertWorkbookSubscriptionCommand(
memberId = memberId,
workbookId = subTargetWorkbookId,
sendDay = it[0].sendDay,
sendTime = it[0].sendTime
)
} ?: run {
/** 현재 구독 중인 정보가 없다면 기본 정보로 구독 정보를 생성 */
InsertWorkbookSubscriptionCommand(
memberId = memberId,
workbookId = subTargetWorkbookId
)
}

val workbookSubscriptionHistory = subscriptionDao.selectTopWorkbookSubscriptionStatus(
SelectAllWorkbookSubscriptionStatusNotConsiderDeletedAtQuery(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class SaveMemberUseCaseTest : BehaviorSpec({
val token = "encryptedToken"
every { idEncryption.encrypt(any()) } returns token

every { sendAuthEmailService.send(any()) } returns Unit
every { sendAuthEmailService.send(any()) } returns "messageId"

then("인증 이메일 발송 성공 응답을 반환한다") {
val useCaseOut = useCase.execute(useCaseIn)
Expand All @@ -64,7 +64,7 @@ class SaveMemberUseCaseTest : BehaviorSpec({
val token = "encryptedToken"
every { idEncryption.encrypt(any()) } returns token

every { sendAuthEmailService.send(any()) } returns Unit
every { sendAuthEmailService.send(any()) } returns "messageId"

then("인증 이메일 발송 성공 응답을 반환한다") {
val useCaseOut = useCase.execute(useCaseIn)
Expand All @@ -90,7 +90,7 @@ class SaveMemberUseCaseTest : BehaviorSpec({
val token = "encryptedToken"
every { idEncryption.encrypt(any()) } returns token

every { sendAuthEmailService.send(any()) } returns Unit
every { sendAuthEmailService.send(any()) } returns "messageId"

then("인증 이메일 발송 성공 응답을 반환한다") {
val useCaseOut = useCase.execute(useCaseIn)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package com.few.api.domain.subscription.usecase
import com.few.api.domain.subscription.event.dto.WorkbookSubscriptionEvent
import com.few.api.domain.subscription.usecase.dto.SubscribeWorkbookUseCaseIn
import com.few.api.repo.dao.subscription.SubscriptionDao
import com.few.api.repo.dao.subscription.record.SubscriptionSendStatus
import com.few.api.repo.dao.subscription.record.WorkbookSubscriptionStatus
import com.few.data.common.code.DayCode
import io.github.oshai.kotlinlogging.KotlinLogging
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.BehaviorSpec
Expand All @@ -13,6 +15,7 @@ import io.mockk.verify
import io.mockk.just
import io.mockk.Runs
import org.springframework.context.ApplicationEventPublisher
import java.time.LocalTime

class SubscribeWorkbookUseCaseTest : BehaviorSpec({
val log = KotlinLogging.logger {}
Expand All @@ -33,6 +36,15 @@ class SubscribeWorkbookUseCaseTest : BehaviorSpec({
val useCaseIn = SubscribeWorkbookUseCaseIn(workbookId = workbookId, memberId = memberId)

`when`("멤버의 구독 히스토리가 없는 경우") {
every { subscriptionDao.selectSubscriptionSendStatus(any()) } returns listOf(
SubscriptionSendStatus(
workbookId = workbookId,
memberId = memberId,
sendDay = DayCode.MON_TUE_WED_THU_FRI.code,
sendTime = LocalTime.of(8, 0)
)
)

every { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) } returns null

every { subscriptionDao.insertWorkbookSubscription(any()) } just Runs
Expand All @@ -45,6 +57,7 @@ class SubscribeWorkbookUseCaseTest : BehaviorSpec({
then("구독한다") {
useCase.execute(useCaseIn)

verify(exactly = 1) { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) }
verify(exactly = 1) { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) }
verify(exactly = 1) { subscriptionDao.insertWorkbookSubscription(any()) }
verify(exactly = 0) { subscriptionDao.countWorkbookMappedArticles(any()) }
Expand All @@ -54,6 +67,15 @@ class SubscribeWorkbookUseCaseTest : BehaviorSpec({
}

`when`("이미 구독한 히스토리가 있고 구독이 취소된 경우") {
every { subscriptionDao.selectSubscriptionSendStatus(any()) } returns listOf(
SubscriptionSendStatus(
workbookId = workbookId,
memberId = memberId,
sendDay = DayCode.MON_TUE_WED_THU_FRI.code,
sendTime = LocalTime.of(8, 0)
)
)

val day = 2
every { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) } returns WorkbookSubscriptionStatus(
workbookId = workbookId,
Expand All @@ -74,6 +96,7 @@ class SubscribeWorkbookUseCaseTest : BehaviorSpec({
then("재구독한다") {
useCase.execute(useCaseIn)

verify(exactly = 1) { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) }
verify(exactly = 1) { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) }
verify(exactly = 0) { subscriptionDao.insertWorkbookSubscription(any()) }
verify(exactly = 1) { subscriptionDao.countWorkbookMappedArticles(any()) }
Expand All @@ -83,6 +106,15 @@ class SubscribeWorkbookUseCaseTest : BehaviorSpec({
}

`when`("이미 구독한 히스토리가 있고 구독을 완료한 경우") {
every { subscriptionDao.selectSubscriptionSendStatus(any()) } returns listOf(
SubscriptionSendStatus(
workbookId = workbookId,
memberId = memberId,
sendDay = DayCode.MON_TUE_WED_THU_FRI.code,
sendTime = LocalTime.of(8, 0)
)
)

val day = 3
every { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) } returns WorkbookSubscriptionStatus(
workbookId = workbookId,
Expand All @@ -103,6 +135,7 @@ class SubscribeWorkbookUseCaseTest : BehaviorSpec({
then("예외가 발생한다") {
shouldThrow<Exception> { useCase.execute(useCaseIn) }

verify(exactly = 1) { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) }
verify(exactly = 1) { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) }
verify(exactly = 0) { subscriptionDao.insertWorkbookSubscription(any()) }
verify(exactly = 1) { subscriptionDao.countWorkbookMappedArticles(any()) }
Expand All @@ -112,12 +145,22 @@ class SubscribeWorkbookUseCaseTest : BehaviorSpec({
}

`when`("구독 중인 경우") {
every { subscriptionDao.selectSubscriptionSendStatus(any()) } returns listOf(
SubscriptionSendStatus(
workbookId = workbookId,
memberId = memberId,
sendDay = DayCode.MON_TUE_WED_THU_FRI.code,
sendTime = LocalTime.of(8, 0)
)
)

val day = 2
every { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) } returns WorkbookSubscriptionStatus(workbookId = workbookId, isActiveSub = true, day)

then("예외가 발생한다") {
shouldThrow<Exception> { useCase.execute(useCaseIn) }

verify(exactly = 1) { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) }
verify(exactly = 1) { subscriptionDao.selectTopWorkbookSubscriptionStatus(any()) }
verify(exactly = 0) { subscriptionDao.insertWorkbookSubscription(any()) }
verify(exactly = 0) { subscriptionDao.countWorkbookMappedArticles(any()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,19 @@ class WorkBookSubscriberReader(
}

private fun sendDayCondition(sendDayField: TableField<SubscriptionRecord, String>, sendDayCode: BatchDayCode): Condition {
return if (sendDayCode == BatchDayCode.MON_TUE_WED_THU_FRI_SAT_SUN) {
sendDayField.eq(BatchDayCode.MON_TUE_WED_THU_FRI.code).or(sendDayField.eq(BatchDayCode.MON_TUE_WED_THU_FRI_SAT_SUN.code))
} else {
sendDayField.eq(sendDayCode.code)
return when (sendDayCode) {
/** 평일인 경우 매일을 포함하여 전송한다 */
BatchDayCode.MON_TUE_WED_THU_FRI -> {
sendDayField.eq(BatchDayCode.MON_TUE_WED_THU_FRI.code)
.or(sendDayField.eq(BatchDayCode.MON_TUE_WED_THU_FRI_SAT_SUN.code))
}
/** 매일의 경우 매일만 전송한다 */
BatchDayCode.MON_TUE_WED_THU_FRI_SAT_SUN -> {
sendDayField.eq(BatchDayCode.MON_TUE_WED_THU_FRI_SAT_SUN.code)
}
else -> {
throw IllegalArgumentException("Invalid sendDayCode: $sendDayCode")
}
}
}
}
14 changes: 11 additions & 3 deletions email/src/main/kotlin/com/few/email/sender/EmailSender.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,23 @@ import org.springframework.boot.autoconfigure.mail.MailProperties

abstract class EmailSender<T : SendMailArgs<*, *>>(
private val mailProperties: MailProperties,
private val emailSendProvider: EmailSendProvider,
private val defaultEmailSendProvider: EmailSendProvider,
) {

fun send(args: T) {
fun send(args: T, emailSendProvider: EmailSendProvider? = null): String {
val from = mailProperties.username
val to = args.to
val subject = args.subject
val message = getHtml(args)
emailSendProvider.sendEmail("FEW Letter <$from>", to, subject, message)
return emailSendProvider?.sendEmail("FEW Letter <$from>", to, subject, message)
?: run {
defaultEmailSendProvider.sendEmail(
"FEW Letter <$from>",
to,
subject,
message
)
}
}

abstract fun getHtml(args: T): String
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.few.email.sender.provider

import com.amazonaws.services.simpleemail.AmazonSimpleEmailService
import org.springframework.stereotype.Component

@Component
class ArticleAwsSESEmailSendProvider(
amazonSimpleEmailService: AmazonSimpleEmailService,
javaEmailSendProvider: JavaEmailSendProvider,
) : AwsSESEmailSendProvider(
amazonSimpleEmailService,
javaEmailSendProvider
) {
override fun getWithConfigurationSetName(): String {
return "few-article-configuration-set"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import com.amazonaws.services.simpleemail.AmazonSimpleEmailService
import com.amazonaws.services.simpleemail.model.*
import io.github.oshai.kotlinlogging.KotlinLogging
import org.springframework.context.annotation.Primary
import org.springframework.context.annotation.Profile
import org.springframework.stereotype.Component

@Primary
@Profile("prd")
@Component
class AwsSESEmailSendProvider(
private val amazonSimpleEmailService: AmazonSimpleEmailService,
Expand All @@ -19,7 +17,7 @@ class AwsSESEmailSendProvider(
private const val UTF_8 = "utf-8"
}

override fun sendEmail(from: String, to: String, subject: String, message: String) {
override fun sendEmail(from: String, to: String, subject: String, message: String): String {
val destination = Destination().withToAddresses(to)
val sendMessage = Message()
.withSubject(Content().withCharset(UTF_8).withData(subject))
Expand All @@ -29,10 +27,10 @@ class AwsSESEmailSendProvider(
.withSource(from)
.withDestination(destination)
.withMessage(sendMessage)
.withConfigurationSetName("few-configuration-set")
.withConfigurationSetName(getWithConfigurationSetName())

runCatching {
amazonSimpleEmailService.sendEmail(sendEmailRequest)
amazonSimpleEmailService.sendEmail(sendEmailRequest).messageId
}.onFailure {
log.warn {
"Failed to send email using AWS SES. Falling back to JavaMailSender. Error: $it"
Expand All @@ -48,6 +46,15 @@ class AwsSESEmailSendProvider(
}
throw it
}
}.let {
return it.getOrThrow()
}
}

/**
* Default configuration set name is "few-configuration-set"
*/
fun getWithConfigurationSetName(): String {
return "few-configuration-set"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.few.email.sender.provider

interface EmailSendProvider {
fun sendEmail(from: String, to: String, subject: String, message: String)
/**
* @return 전송한 이메일 식벽을 위한 값
*/
fun sendEmail(from: String, to: String, subject: String, message: String): String
}
Loading

0 comments on commit cea90e7

Please sign in to comment.