Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(mail): implement mail reservation #731

Open
wants to merge 40 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f89b43c
feat: add MailMessage
woowabrie Sep 14, 2023
559f00a
feat: add MailReservation
woowabrie Sep 26, 2023
faa24f5
feat: add MailHistory
woowabrie Oct 4, 2023
81f6188
feat: mapping relationships with mail message and reservation
woowabrie Oct 4, 2023
ad730d6
feat: mapping relationships with mail message and history
woowabrie Oct 4, 2023
742c8a6
feat: using new MailHistory
woowabrie Oct 4, 2023
1d6032b
refactor: delete old MailHistory
woowabrie Oct 4, 2023
d09c01b
feat: Add functionality for scheduling email reservations
woowabrie Oct 4, 2023
b8168e6
feat: add functionality for updating mail messages
woowabrie Oct 4, 2023
f12edfa
feat: add functionality for updating mail's reservation time
woowabrie Oct 4, 2023
f5777a4
feat: add functionality for deleting mail's reservation
woowabrie Oct 4, 2023
9e29d51
feat: add functionality for finding mail's reservation
woowabrie Oct 4, 2023
501928e
refactor: create MailHistory when MailSentEvent is published
woowabrie Oct 5, 2023
e914ed2
feat: add endpoint to send reservation mail
woowabrie Oct 5, 2023
f766d5d
refactor: migrate sql relating with mail tables
woowabrie Oct 5, 2023
3b6cd96
fix: edit searching conditions for mail reservations
woowabrie Oct 7, 2023
ba9d7b0
feat: remove functions relates with updating mail message
woowabrie Oct 7, 2023
16e0a74
feat: remove functions relates with updating reservationTime of mail
woowabrie Oct 7, 2023
e2d7e91
refactor: extract MailReservationStatus into another file
woowabrie Oct 9, 2023
0a673d4
refactor: adjust order of annotation on MailReservationController
woowabrie Oct 9, 2023
ee17685
refactor: rename functions changing status of reservation
woowabrie Oct 9, 2023
1d11f1b
refactor: delete factory method from MailHistory
woowabrie Oct 9, 2023
2c3341f
test: edit typo for creatorId of MailMessage
woowabrie Oct 7, 2023
f0257c5
refactor: delete factory method from MailMessage
woowabrie Oct 9, 2023
fb64635
refactor: make relationships with MailHistory and MailMessage by id r…
woowabrie Oct 9, 2023
237ba8c
refactor: make relationships with MailReservation and MailMessage by …
woowabrie Oct 9, 2023
4bf23cb
refactor: add synchronous function to send mail
woowabrie Oct 9, 2023
19cee58
refactor: delete MailSentEvent and Listener
woowabrie Oct 9, 2023
8bf6500
test: add test for sending reservation mail
woowabrie Oct 10, 2023
f2760b4
refactor: extract functions to get reservation time
woowabrie Oct 10, 2023
49f91f6
refactor: move mails functions into MailMessageService
woowabrie Oct 10, 2023
6f23fa7
feat: use lambda accessor to authenticate API caller
woowabrie Oct 10, 2023
7cdbeda
fix: use mailMessageId for getting MailMessage Information
woowabrie Oct 11, 2023
3e96c58
refactor: rename MailService to SendingMailService
woowabrie Oct 11, 2023
4ba0c6f
refactor: edit searching condition for MailReservation
woowabrie Oct 12, 2023
1c21188
refactor: add accessor key for mail scheduler
woowabrie Oct 12, 2023
56a5115
refactor: edit name of function that send mail
woowabrie Oct 12, 2023
5c5c180
refactor: edit name of function that send reservation mails
woowabrie Oct 12, 2023
dd427ec
refactor: edit name of function that send mail
woowabrie Oct 12, 2023
0fe7829
refactor: change function to send reserved mail
woowabrie Oct 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions src/main/kotlin/apply/application/MailHistoryService.kt

This file was deleted.

22 changes: 18 additions & 4 deletions src/main/kotlin/apply/application/mail/MailData.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package apply.application.mail

import apply.domain.mail.MailHistory
import apply.domain.mail.MailMessage
import org.springframework.core.io.ByteArrayResource
import java.time.LocalDateTime
import javax.validation.constraints.NotEmpty
Expand Down Expand Up @@ -30,12 +31,25 @@ data class MailData(
@field:NotNull
var id: Long = 0L
) {
constructor(mailHistory: MailHistory) : this(
mailHistory.subject,
mailHistory.body,
mailHistory.sender,
constructor(mailMessage: MailMessage) : this(
mailMessage.subject,
mailMessage.body,
mailMessage.sender,
mailMessage.recipients,
id = mailMessage.id
)

constructor(mailMessage: MailMessage, mailHistory: MailHistory) : this(
mailMessage.subject,
mailMessage.body,
mailMessage.sender,
mailHistory.recipients,
mailHistory.sentTime,
id = mailHistory.id
)

fun toMailMessage(): MailMessage {
// TODO: 작성자 ID 바인딩
return MailMessage(subject, body, sender, recipients, 1L)
}
}
65 changes: 65 additions & 0 deletions src/main/kotlin/apply/application/mail/MailDtos.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package apply.application.mail

import apply.domain.mail.MailHistory
import apply.domain.mail.MailMessage
import apply.domain.mail.MailReservation
import apply.domain.mail.MailReservationStatus
import java.time.LocalDateTime

data class MailMessageResponse(
val id: Long,
val subject: String,
val body: String,
val sender: String,
val recipients: List<String>,
val createdDateTime: LocalDateTime,
val sentTime: LocalDateTime?,
val reservation: MailReservationResponse?,
val histories: List<MailHistoryResponse>
) {
constructor(
mailMessage: MailMessage,
mailReservation: MailReservation? = null,
mailHistories: List<MailHistory> = emptyList()
) : this(
mailMessage.id,
mailMessage.subject,
mailMessage.body,
mailMessage.sender,
mailMessage.recipients,
mailMessage.createdDateTime,
mailHistories.firstOrNull()?.sentTime,
mailReservation?.let { MailReservationResponse(it) },
mailHistories.map { MailHistoryResponse(it) }
)
}

data class MailReservationResponse(
val id: Long,
val mailMessageId: Long,
val status: MailReservationStatus,
val reservationTime: LocalDateTime
) {
constructor(mailReservation: MailReservation) : this(
mailReservation.id,
mailReservation.mailMessageId,
mailReservation.status,
mailReservation.reservationTime
)
}

data class MailHistoryResponse(
val id: Long,
val mailMessageId: Long,
val recipients: List<String>,
val success: Boolean,
val sentTime: LocalDateTime
) {
constructor(mailHistory: MailHistory) : this(
mailHistory.id,
mailHistory.mailMessageId,
mailHistory.recipients,
mailHistory.success,
mailHistory.sentTime
)
}
26 changes: 26 additions & 0 deletions src/main/kotlin/apply/application/mail/MailHistoryService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package apply.application.mail

import apply.domain.mail.MailHistoryRepository
import apply.domain.mail.MailMessageRepository
import apply.domain.mail.getOrThrow
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Transactional
@Service
class MailHistoryService(
private val mailHistoryRepository: MailHistoryRepository,
private val mailMessageRepository: MailMessageRepository
) {
fun findAll(): List<MailData> {
val histories = mailHistoryRepository.findAll()
val messagesById = mailMessageRepository.findAllById(histories.map { it.mailMessageId }).associateBy { it.id }
return histories.map { MailData(messagesById.getValue(it.mailMessageId), it) }
}

fun getById(mailHistoryId: Long): MailData {
val mailHistory = mailHistoryRepository.getOrThrow(mailHistoryId)
val mailMessage = mailMessageRepository.getOrThrow(mailHistory.mailMessageId)
return MailData(mailMessage, mailHistory)
}
}
83 changes: 83 additions & 0 deletions src/main/kotlin/apply/application/mail/MailMessageService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
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<MailMessageResponse> {
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<MailMessageResponse> {
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(
MailReservation(mailMessageId = mailMessage.id, reservationTime = request.sentTime)
)
return MailMessageResponse(mailMessage, mailReservation)
}

fun cancelReservation(mailMessageId: Long) {
val mailReservation = mailReservationRepository.findByMailMessageId(mailMessageId)
?: throw IllegalArgumentException("메일 예약이 존재하지 않습니다. email: $mailMessageId")
check(mailReservation.canCancel()) { "예약 취소할 수 없는 메일입니다." }
mailReservationRepository.deleteById(mailReservation.id)
mailMessageRepository.deleteById(mailReservation.mailMessageId)
}

fun sendReservedMail(standardTime: LocalDateTime = LocalDateTime.now()) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r: @ Transactional 을 추가하고 타임아웃을 정해두시죠!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c: 예약된 메일들을 보내는거라 s 붙이는게 좋겠네요

Suggested change
fun sendReservedMail(standardTime: LocalDateTime = LocalDateTime.now()) {
fun sendReservedMails(standardTime: LocalDateTime = LocalDateTime.now()) {

val reservations = mailReservationRepository.findByReservationTimeBetweenAndStatus(
standardTime.minusMinutes(1),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1분 범위에 예약된 메일을 모두 발송하기 위해 1분 추가, 빼기를 한게 맞을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 맞습니다! 트리거가 정확하게 시작하는걸 보장하기 어렵기도 하고, 메일 예약이 15분 단위로 설정되니 다른 시간의 예약을 조회할일은 없어 앞뒤로 1분을 넣었어요.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r: 1시 10분이 예약되어 있다고 했을 때 1시 9분, 1시 10분, 1시 11분에 요청이 안오면 해당 메일은 발송을 못하는 케이스가 존재할 것 같은데요.
standardTime보다 이전에 발송되어야 할 메시지 중 상태가 WAITING인 애들을 조회해서 발송하면 문제가 없어질 것 같은데 어떻게 생각하시나용

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 그렇네요. 아마 이전에 코드를 짤 때 예약시간 수정을 생각하다 보니 사이값을 검색하도록 만들었던 것 같아요.
현재 로직은 예약 시간/내용 수정 대신 기존 예약을 삭제 후 재생성하도록 하고있어서, 말씀주신 것처럼 예약 시간이 현재보다 이전인 대기 상태의 모든 예약을 조회하는게 더 좋을 것 같습니다!

standardTime.plusMinutes(1),
MailReservationStatus.WAITING
)
val messagesById = findMessageMapById(reservations.map { it.mailMessageId })

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MailReservation이랑 MailMessage를 한 번에 불러오면 쿼리 호출 횟수도 줄이고 코드 복잡도도 줄어들거 같아요
아래 예시 쿼리로 작성했어요. JPQL 문법이 맞는지 확인이 필요합니다 ㅎㅎ;

    @Query("select m" +
        " from MailMessage m" +
        " join MailReservation ms on ms.mailMessageId = m.id" +
        " where ms.reservationTime between :from and :to" +
        " and ms.status = :status")
    fun findByReservationTimeBetweenAndStatus(
        from: LocalDateTime,
        to: LocalDateTime,
        status: MailReservationStatus
    ): List<MailMessage>

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 이렇게하면 바로 예약 MailMessage 를 가져올 수 있군요! 넘 좋습니다 ㅎㅎㅎ
한 가지 궁금한게 이 때 조회한 MailReservation도 함께 받을 수 있나요? 메일 전송만 생각하면 MailMessage만 있어도 되는데, 상태 변경이 필요해서요!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

쿼리에서 select에 ms를 추가하면 될거에요. 그런데 MailMessage가 MailReservation를 간접참조 하고 있으면 좀 더 수정해야 해요. dto를 새로 만들거나 객체를 참조하도록 바꾸는 방법이 있겠네요


reservations.forEach { mailReservation ->

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c: 해당 메일 발송 작업이 하나의 트랜잭션으로 묶여야 할 이유가 있을까요? 개별적으로 성공 실패가 나뉘는게 더 자연스럽지 않을까 합니다.

mailReservation.send()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

질문) 지금 트랜잭션으로 묶여 있는데 MailReservation.status가 SENDING로 DB에 존재하는 케이스가 생길 수 있나요?

mailReservationRepository.save(mailReservation)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c: 메일 예약을 개별 저장하는 것보다 한 번에 처리하는건 어떨까요
배치 사이즈를 지정했다면 더 효율적으로 처리할 수 있을 것 같아요

mailReservationRepository.saveAll(reservations)

mailService.sendMailsByBccSynchronous(MailData(messagesById.getValue(mailReservation.id)), emptyMap())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c: MailService를 인프라용 객체가 아닌 도메인용으로 본다면 MailMessage 객체를 전달하는게 나을 것 같아요.

val mailMessage = messagesById.getValue(mailReservation.id)
mailService.sendMailsByBccSynchronous(mailMessage)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어드민에서 직접 사용하는 비동기 방식의 메일 전송 메서드와 맞추긴 했는데, 저도 고민되긴 하더라구요 ㅋㅋ
MailMessage를 만들테고 실제로 전송할 때 MailService(SendingMailService) 를 사용한다면, MailMessage를 전달하는게 좋아보이긴 해요.
이건 변경 여파가 어드민에 미쳐서 작업을 안했었는데, 이부분도 이후에 어드민 작업과 함께 정리해볼게요.

mailReservation.finish()
}
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

회의 시간에 제이슨이 언급하셨던 예약 메일 전송 시 트랜잭션 처리와 관련된 코드입니다.

기존의 메일 전송은 Async로 동작하지만, 이번에는 문제를 단순화하여 동기 방식으로 처리하기로 했어요. (현재 설정 상 초당 300건의 메일 전송이 가능)
설계 시에는 멀티 환경에서의 전송을 생각하고 WATING(대기), SENDING(발송 중), FINISHED(처리 완료) 세 가지의 메일 예약 상태를 가지도록 했는데요.
쓰면서 생각해보니 한 번의 요청으로 하나의 서버에서 동기로 처리를 한다면 중간 상태 변경이 없어도 괜찮지 않나 싶기도 하네요.

혹시 제가 잘못 생각하고 있거나 아니면 더 좋은 동작 아이디어가 있다면 의견 부탁드립니다!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금은 의미가 없어 보이긴 하네요.. 하지만 비동기로 전환할 것을 염두에 두고 남겨둬도 좋을 것 같아요. 다른 메일 발송 기능은 비동기로 처리하고 있기도 하구요.


private fun findMessageMapById(mailMessageIds: List<Long>): Map<Long, MailMessage> {
return mailMessageRepository
.findAllById(mailMessageIds)
.associateBy { it.id }
}
}
52 changes: 41 additions & 11 deletions src/main/kotlin/apply/application/mail/MailService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import apply.application.ApplicationProperties
import apply.domain.applicationform.ApplicationFormSubmittedEvent
import apply.domain.mail.MailHistory
import apply.domain.mail.MailHistoryRepository
import apply.domain.mail.MailMessageRepository
import apply.domain.recruitment.RecruitmentRepository
import apply.domain.recruitment.getOrThrow
import apply.domain.user.PasswordResetEvent
import apply.domain.user.UserRepository
import apply.domain.user.getOrThrow
import org.springframework.boot.autoconfigure.mail.MailProperties
import org.springframework.context.ApplicationEventPublisher
import org.springframework.core.io.ByteArrayResource
import org.springframework.scheduling.annotation.Async
import org.springframework.stereotype.Service
Expand All @@ -24,11 +26,13 @@ private const val MAIL_SENDING_UNIT: Int = 50
class MailService(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c: MailMessageService가 있고 MailService가 있으니까 헷갈리네요;;;
MailService는 실제 메일 발송과 관련된 작업만 존재하니 SedingMailService 같은 이름으로 바꾸는건 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 만들면서 메일 관련 서비스들이 헷갈렸습니다... (MailService, MailHistoryService, MailMessageService)
현재 MailService의 역할에 공감해서 좋은 네이밍 인 것 같아 반영하겠습니다!
MailHistoryService는 현재 어드민에서 사용중이라 이후 어드민 작업 하면서 필요성을 보고 함께 정리할게요.

private val userRepository: UserRepository,
private val recruitmentRepository: RecruitmentRepository,
private val mailMessageRepository: MailMessageRepository,
private val mailHistoryRepository: MailHistoryRepository,
private val applicationProperties: ApplicationProperties,
private val templateEngine: ISpringTemplateEngine,
private val mailSender: MailSender,
private val mailProperties: MailProperties
private val mailProperties: MailProperties,
private val eventPublisher: ApplicationEventPublisher,
) {
@Async
@TransactionalEventListener
Expand Down Expand Up @@ -90,10 +94,10 @@ class MailService(

@Async
fun sendMailsByBcc(request: MailData, files: Map<String, ByteArrayResource>) {
val mailMessage = mailMessageRepository.save(request.toMailMessage())
val body = generateMailBody(request)
val recipients = request.recipients + mailProperties.username

// TODO: 성공과 실패를 분리하여 히스토리 관리
val succeeded = mutableListOf<String>()
val failed = mutableListOf<String>()
for (addresses in recipients.chunked(MAIL_SENDING_UNIT)) {
Expand All @@ -102,15 +106,23 @@ class MailService(
.onFailure { failed.addAll(addresses) }
}

mailHistoryRepository.save(
MailHistory(
request.subject,
request.body,
request.sender,
request.recipients,
request.sentTime
)
)
saveMailHistories(mailMessage.id, succeeded, failed)
}

fun sendMailsByBccSynchronous(request: MailData, files: Map<String, ByteArrayResource>) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 단건으로 보내는 거라 s는 빼는게 맞겠네요.
Suggested change
fun sendMailsByBccSynchronous(request: MailData, files: Map<String, ByteArrayResource>) {
fun sendMailByBccSynchronous(request: MailData, files: Map<String, ByteArrayResource>) {
  1. files도 MailData에 합치는게 좋을 것 같은데 스프링 리소스를 쓰고 있어서 따로 분리했나보네요. 저는 인터페이스 추가해서 하나로 합치는게 나을 것 같은데 다른 분들 어떠신가요. 따로 다루는게 나을까요?

  2. 첨부 파일이 없는 경우가 많을거라 기본값으로 emptyMap()을 설정하는게 좋을 것 같습니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번에는 메일 예약에서 파일 첨부 기능을 지원하지 않기로 해서 크게 신경쓰지는 않았는데, 장기적인 관점으로는 구구 말씀처럼 합치는 방향으로 가는게 좋아보여요 ㅎㅎ

val mailMessage = mailMessageRepository.save(request.toMailMessage())
val body = generateMailBody(request)
val recipients = mailMessage.recipients + mailProperties.username

val succeeded = mutableListOf<String>()
val failed = mutableListOf<String>()
for (addresses in recipients.chunked(MAIL_SENDING_UNIT)) {
runCatching { mailSender.sendBcc(addresses, mailMessage.subject, body, files) }
.onSuccess { succeeded.addAll(addresses) }
.onFailure { failed.addAll(addresses) }
}

saveMailHistories(mailMessage.id, succeeded, failed)
}

fun generateMailBody(mailData: MailData): String {
Expand All @@ -124,4 +136,22 @@ class MailService(
}
return templateEngine.process("mail/common", context)
}

private fun saveMailHistories(
mailMessageId: Long,
succeeded: MutableList<String>,
failed: MutableList<String>
) {
val mailHistories = mutableListOf<MailHistory>()

if (succeeded.isNotEmpty()) {
mailHistories.add(MailHistory(mailMessageId, succeeded, true))
}

if (failed.isNotEmpty()) {
mailHistories.add(MailHistory(mailMessageId, failed, false))
}

mailHistoryRepository.saveAll(mailHistories)
}
}
25 changes: 20 additions & 5 deletions src/main/kotlin/apply/config/DatabaseInitializer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import apply.domain.judgmentitem.JudgmentItemRepository
import apply.domain.judgmentitem.ProgrammingLanguage
import apply.domain.mail.MailHistory
import apply.domain.mail.MailHistoryRepository
import apply.domain.mail.MailMessage
import apply.domain.mail.MailMessageRepository
import apply.domain.mission.Mission
import apply.domain.mission.MissionRepository
import apply.domain.recruitment.Recruitment
Expand Down Expand Up @@ -57,6 +59,7 @@ class DatabaseInitializer(
private val missionRepository: MissionRepository,
private val judgmentItemRepository: JudgmentItemRepository,
private val assignmentRepository: AssignmentRepository,
private val mailMessageRepository: MailMessageRepository,
private val mailHistoryRepository: MailHistoryRepository,
private val database: Database
) : CommandLineRunner {
Expand Down Expand Up @@ -429,13 +432,25 @@ class DatabaseInitializer(
}

private fun populateMailHistories() {
val mailMessage = MailMessage(
subject = "[우아한테크코스] 프리코스를 진행하는 목적과 사전 준비",
body = "안녕하세요.",
sender = "[email protected]",
recipients = listOf("[email protected]", "[email protected]", "[email protected]", "[email protected]"),
creatorId = 1L,
)
mailMessageRepository.save(mailMessage)

val mailHistories = listOf(
MailHistory(
subject = "[우아한테크코스] 프리코스를 진행하는 목적과 사전 준비",
body = "안녕하세요.",
sender = "[email protected]",
recipients = listOf("[email protected]", "[email protected]", "[email protected]", "[email protected]"),
sentTime = createLocalDateTime(2020, 11, 5, 10)
mailMessageId = mailMessage.id,
recipients = mailMessage.recipients.subList(0, 2),
success = true
),
MailHistory(
mailMessageId = mailMessage.id,
recipients = mailMessage.recipients.subList(3, 4),
success = true
)
)
mailHistoryRepository.saveAll(mailHistories)
Expand Down
Loading