From 49f91f6a19668ea3c34f0886ad27c9b8aa0a96aa Mon Sep 17 00:00:00 2001 From: woowabrie Date: Tue, 10 Oct 2023 11:49:52 +0900 Subject: [PATCH] refactor: move mails functions into MailMessageService --- .../kotlin/apply/application/mail/MailDtos.kt | 31 +++++++++-- .../application/mail/MailMessageService.kt | 53 +++++++++++++++++++ .../mail/MailReservationService.kt | 39 -------------- .../ui/api/MailReservationRestController.kt | 23 -------- .../kotlin/apply/ui/api/MailRestController.kt | 12 ++++- .../mail/MailMessageIntegrationTest.kt | 19 +++++++ .../mail/MailReservationIntegrationTest.kt | 45 ---------------- 7 files changed, 111 insertions(+), 111 deletions(-) delete mode 100644 src/main/kotlin/apply/application/mail/MailReservationService.kt delete mode 100644 src/main/kotlin/apply/ui/api/MailReservationRestController.kt delete mode 100644 src/test/kotlin/apply/application/mail/MailReservationIntegrationTest.kt diff --git a/src/main/kotlin/apply/application/mail/MailDtos.kt b/src/main/kotlin/apply/application/mail/MailDtos.kt index 9ccbb6917..b09bc05d8 100644 --- a/src/main/kotlin/apply/application/mail/MailDtos.kt +++ b/src/main/kotlin/apply/application/mail/MailDtos.kt @@ -1,5 +1,6 @@ package apply.application.mail +import apply.domain.mail.MailHistory import apply.domain.mail.MailMessage import apply.domain.mail.MailReservation import apply.domain.mail.MailReservationStatus @@ -12,16 +13,24 @@ data class MailMessageResponse( val sender: String, val recipients: List, val createdDateTime: LocalDateTime, - val reservation: MailReservationResponse? + val sentTime: LocalDateTime?, + val reservation: MailReservationResponse?, + val histories: List ) { - constructor(mailMessage: MailMessage, mailReservation: MailReservation? = null) : this( + constructor( + mailMessage: MailMessage, + mailReservation: MailReservation? = null, + mailHistories: List = emptyList() + ) : this( mailMessage.id, mailMessage.subject, mailMessage.body, mailMessage.sender, mailMessage.recipients, mailMessage.createdDateTime, - mailReservation?.let { MailReservationResponse(it) } + mailHistories.firstOrNull()?.sentTime, + mailReservation?.let { MailReservationResponse(it) }, + mailHistories.map { MailHistoryResponse(it) } ) } @@ -38,3 +47,19 @@ data class MailReservationResponse( mailReservation.reservationTime ) } + +data class MailHistoryResponse( + val id: Long, + val mailMessageId: Long, + val recipients: List, + val success: Boolean, + val sentTime: LocalDateTime +) { + constructor(mailHistory: MailHistory) : this( + mailHistory.id, + mailHistory.mailMessageId, + mailHistory.recipients, + mailHistory.success, + mailHistory.sentTime + ) +} diff --git a/src/main/kotlin/apply/application/mail/MailMessageService.kt b/src/main/kotlin/apply/application/mail/MailMessageService.kt index c27796d01..b7a8a3856 100644 --- a/src/main/kotlin/apply/application/mail/MailMessageService.kt +++ b/src/main/kotlin/apply/application/mail/MailMessageService.kt @@ -1,17 +1,48 @@ package apply.application.mail +import apply.domain.mail.MailHistoryRepository +import apply.domain.mail.MailMessage import apply.domain.mail.MailMessageRepository import apply.domain.mail.MailReservation import apply.domain.mail.MailReservationRepository +import apply.domain.mail.MailReservationStatus import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional +import java.time.LocalDateTime @Transactional @Service class MailMessageService( + private val mailService: MailService, private val mailMessageRepository: MailMessageRepository, private val mailReservationRepository: MailReservationRepository, + private val mailHistoryRepository: MailHistoryRepository ) { + fun findSentMails(): List { + val histories = mailHistoryRepository.findAll() + val messagesById = findMessageMapById(histories.map { it.mailMessageId }) + return messagesById.map { (id, message) -> + MailMessageResponse( + mailMessage = message, + mailHistories = histories.filter { it.mailMessageId == id } + ) + } + } + + fun findReservedMails(): List { + val reservations = mailReservationRepository.findByStatus(MailReservationStatus.WAITING) + val messagesById = findMessageMapById(reservations.map { it.mailMessageId }) + + return reservations + .filter { messagesById.contains(it.mailMessageId) } + .map { + MailMessageResponse( + mailMessage = messagesById.getValue(it.mailMessageId), + mailReservation = it + ) + } + } + fun reserve(request: MailData): MailMessageResponse { val mailMessage = mailMessageRepository.save(request.toMailMessage()) val mailReservation = mailReservationRepository.save( @@ -27,4 +58,26 @@ class MailMessageService( mailReservationRepository.deleteById(mailReservation.id) mailMessageRepository.deleteById(mailReservation.mailMessageId) } + + fun sendReservedMail(standardTime: LocalDateTime = LocalDateTime.now()) { + val reservations = mailReservationRepository.findByReservationTimeBetweenAndStatus( + standardTime.minusMinutes(1), + standardTime.plusMinutes(1), + MailReservationStatus.WAITING + ) + val messagesById = findMessageMapById(reservations.map { it.mailMessageId }) + + reservations.forEach { mailReservation -> + mailReservation.send() + mailReservationRepository.save(mailReservation) + mailService.sendMailsByBccSynchronous(MailData(messagesById.getValue(mailReservation.id)), emptyMap()) + mailReservation.finish() + } + } + + private fun findMessageMapById(mailMessageIds: List): Map { + return mailMessageRepository + .findAllById(mailMessageIds) + .associateBy { it.id } + } } diff --git a/src/main/kotlin/apply/application/mail/MailReservationService.kt b/src/main/kotlin/apply/application/mail/MailReservationService.kt deleted file mode 100644 index e7619318f..000000000 --- a/src/main/kotlin/apply/application/mail/MailReservationService.kt +++ /dev/null @@ -1,39 +0,0 @@ -package apply.application.mail - -import apply.domain.mail.MailMessageRepository -import apply.domain.mail.MailReservationRepository -import apply.domain.mail.MailReservationStatus -import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Transactional -import java.time.LocalDateTime - -@Transactional -@Service -class MailReservationService( - private val mailService: MailService, - private val mailReservationRepository: MailReservationRepository, - private val mailMessageRepository: MailMessageRepository -) { - fun findByWaitingStatus(): List { - return mailReservationRepository.findByStatus(MailReservationStatus.WAITING) - .map { MailReservationResponse(it) } - } - - fun sendMail(standardTime: LocalDateTime = LocalDateTime.now()) { - val reservations = mailReservationRepository.findByReservationTimeBetweenAndStatus( - standardTime.minusMinutes(1), - standardTime.plusMinutes(1), - MailReservationStatus.WAITING - ) - val messagesById = mailMessageRepository - .findAllById(reservations.map { it.mailMessageId }) - .associateBy { it.id } - - reservations.forEach { mailReservation -> - mailReservation.send() - mailReservationRepository.save(mailReservation) - mailService.sendMailsByBccSynchronous(MailData(messagesById.getValue(mailReservation.id)), emptyMap()) - mailReservation.finish() - } - } -} diff --git a/src/main/kotlin/apply/ui/api/MailReservationRestController.kt b/src/main/kotlin/apply/ui/api/MailReservationRestController.kt deleted file mode 100644 index 66a0daaab..000000000 --- a/src/main/kotlin/apply/ui/api/MailReservationRestController.kt +++ /dev/null @@ -1,23 +0,0 @@ -package apply.ui.api - -import apply.application.mail.MailReservationService -import apply.domain.user.User -import apply.security.LoginUser -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.PostMapping -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController - -@RequestMapping("/api/mail-reservation") -@RestController -class MailReservationRestController( - private val mailReservationService: MailReservationService -) { - @PostMapping - fun sendMail( - @LoginUser(administrator = true) user: User - ): ResponseEntity { - mailReservationService.sendMail() - return ResponseEntity.noContent().build() - } -} diff --git a/src/main/kotlin/apply/ui/api/MailRestController.kt b/src/main/kotlin/apply/ui/api/MailRestController.kt index 4feefaebe..496ad0723 100644 --- a/src/main/kotlin/apply/ui/api/MailRestController.kt +++ b/src/main/kotlin/apply/ui/api/MailRestController.kt @@ -1,6 +1,7 @@ package apply.ui.api import apply.application.mail.MailData +import apply.application.mail.MailMessageService import apply.application.mail.MailService import apply.domain.user.User import apply.security.LoginUser @@ -15,7 +16,8 @@ import org.springframework.web.multipart.MultipartFile @RestController @RequestMapping("/api/mail") class MailRestController( - private val mailService: MailService + private val mailService: MailService, + private val mailMessageService: MailMessageService ) { @PostMapping fun sendMail( @@ -27,4 +29,12 @@ class MailRestController( mailService.sendMailsByBcc(request, inputStreamFiles) return ResponseEntity.noContent().build() } + + @PostMapping("/reserved") + fun sendMail( + @LoginUser(administrator = true) user: User + ): ResponseEntity { + mailMessageService.sendReservedMail() + return ResponseEntity.noContent().build() + } } diff --git a/src/test/kotlin/apply/application/mail/MailMessageIntegrationTest.kt b/src/test/kotlin/apply/application/mail/MailMessageIntegrationTest.kt index cc6e07af7..3f6a42485 100644 --- a/src/test/kotlin/apply/application/mail/MailMessageIntegrationTest.kt +++ b/src/test/kotlin/apply/application/mail/MailMessageIntegrationTest.kt @@ -6,6 +6,7 @@ import apply.createMailMessage import apply.createMailReservation import apply.domain.mail.MailMessageRepository import apply.domain.mail.MailReservationRepository +import apply.domain.mail.MailReservationStatus import apply.domain.mail.getOrThrow import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.BehaviorSpec @@ -90,4 +91,22 @@ class MailMessageIntegrationTest( } } } + + Given("특정 시간에 발송할 예약 메일이 있는 경우") { + val reservationTime = createAvailableReservationTime() + val mailMessage1 = mailMessageRepository.save(createMailMessage()) + val mailMessage2 = mailMessageRepository.save(createMailMessage()) + + mailReservationRepository.save(createMailReservation(mailMessage1.id, reservationTime)) + mailReservationRepository.save(createMailReservation(mailMessage2.id, reservationTime.plusHours(3))) + + When("해당 시간에 메일 발송 요청을 하면") { + mailMessageService.sendReservedMail(reservationTime) + + Then("메일 전송이 완료된다") { + val actual = mailReservationRepository.findByStatus(MailReservationStatus.FINISHED) + actual.size shouldBe 1 + } + } + } }) diff --git a/src/test/kotlin/apply/application/mail/MailReservationIntegrationTest.kt b/src/test/kotlin/apply/application/mail/MailReservationIntegrationTest.kt deleted file mode 100644 index e4fbb0bc0..000000000 --- a/src/test/kotlin/apply/application/mail/MailReservationIntegrationTest.kt +++ /dev/null @@ -1,45 +0,0 @@ -package apply.application.mail - -import apply.config.TestMailConfiguration -import apply.createAvailableReservationTime -import apply.createMailMessage -import apply.createMailReservation -import apply.domain.mail.MailMessageRepository -import apply.domain.mail.MailReservationRepository -import apply.domain.mail.MailReservationStatus -import io.kotest.core.spec.style.BehaviorSpec -import io.kotest.extensions.spring.SpringTestExtension -import io.kotest.extensions.spring.SpringTestLifecycleMode -import io.kotest.matchers.shouldBe -import org.springframework.context.annotation.Import -import org.springframework.transaction.annotation.Transactional -import support.test.IntegrationTest - -@Import(TestMailConfiguration::class) -@Transactional -@IntegrationTest -class MailReservationIntegrationTest( - private val mailReservationService: MailReservationService, - private val mailReservationRepository: MailReservationRepository, - private val mailMessageRepository: MailMessageRepository -) : BehaviorSpec({ - extensions(SpringTestExtension(SpringTestLifecycleMode.Root)) - - Given("특정 시간에 발송할 예약 메일이 있는 경우") { - val reservationTime = createAvailableReservationTime() - val mailMessage1 = mailMessageRepository.save(createMailMessage()) - val mailMessage2 = mailMessageRepository.save(createMailMessage()) - - mailReservationRepository.save(createMailReservation(mailMessage1.id, reservationTime)) - mailReservationRepository.save(createMailReservation(mailMessage2.id, reservationTime.plusHours(3))) - - When("해당 시간에 메일 발송 요청을 하면") { - mailReservationService.sendMail(reservationTime) - - Then("메일 전송이 완료된다") { - val actual = mailReservationRepository.findByStatus(MailReservationStatus.FINISHED) - actual.size shouldBe 1 - } - } - } -})