-
Notifications
You must be signed in to change notification settings - Fork 101
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
woowabrie
wants to merge
40
commits into
develop
Choose a base branch
from
feature/mail-reservation
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
f89b43c
feat: add MailMessage
woowabrie 559f00a
feat: add MailReservation
woowabrie faa24f5
feat: add MailHistory
woowabrie 81f6188
feat: mapping relationships with mail message and reservation
woowabrie ad730d6
feat: mapping relationships with mail message and history
woowabrie 742c8a6
feat: using new MailHistory
woowabrie 1d6032b
refactor: delete old MailHistory
woowabrie d09c01b
feat: Add functionality for scheduling email reservations
woowabrie b8168e6
feat: add functionality for updating mail messages
woowabrie f12edfa
feat: add functionality for updating mail's reservation time
woowabrie f5777a4
feat: add functionality for deleting mail's reservation
woowabrie 9e29d51
feat: add functionality for finding mail's reservation
woowabrie 501928e
refactor: create MailHistory when MailSentEvent is published
woowabrie e914ed2
feat: add endpoint to send reservation mail
woowabrie f766d5d
refactor: migrate sql relating with mail tables
woowabrie 3b6cd96
fix: edit searching conditions for mail reservations
woowabrie ba9d7b0
feat: remove functions relates with updating mail message
woowabrie 16e0a74
feat: remove functions relates with updating reservationTime of mail
woowabrie e2d7e91
refactor: extract MailReservationStatus into another file
woowabrie 0a673d4
refactor: adjust order of annotation on MailReservationController
woowabrie ee17685
refactor: rename functions changing status of reservation
woowabrie 1d11f1b
refactor: delete factory method from MailHistory
woowabrie 2c3341f
test: edit typo for creatorId of MailMessage
woowabrie f0257c5
refactor: delete factory method from MailMessage
woowabrie fb64635
refactor: make relationships with MailHistory and MailMessage by id r…
woowabrie 237ba8c
refactor: make relationships with MailReservation and MailMessage by …
woowabrie 4bf23cb
refactor: add synchronous function to send mail
woowabrie 19cee58
refactor: delete MailSentEvent and Listener
woowabrie 8bf6500
test: add test for sending reservation mail
woowabrie f2760b4
refactor: extract functions to get reservation time
woowabrie 49f91f6
refactor: move mails functions into MailMessageService
woowabrie 6f23fa7
feat: use lambda accessor to authenticate API caller
woowabrie 7cdbeda
fix: use mailMessageId for getting MailMessage Information
woowabrie 3e96c58
refactor: rename MailService to SendingMailService
woowabrie 4ba0c6f
refactor: edit searching condition for MailReservation
woowabrie 1c21188
refactor: add accessor key for mail scheduler
woowabrie 56a5115
refactor: edit name of function that send mail
woowabrie 5c5c180
refactor: edit name of function that send reservation mails
woowabrie dd427ec
refactor: edit name of function that send mail
woowabrie 0fe7829
refactor: change function to send reserved mail
woowabrie File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
26
src/main/kotlin/apply/application/mail/MailHistoryService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
82 changes: 82 additions & 0 deletions
82
src/main/kotlin/apply/application/mail/MailMessageService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
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 | ||
|
||
@Service | ||
class MailMessageService( | ||
private val sendingMailService: SendingMailService, | ||
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 | ||
) | ||
} | ||
} | ||
|
||
@Transactional | ||
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) | ||
} | ||
|
||
@Transactional | ||
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 sendReservedMails(standardTime: LocalDateTime = LocalDateTime.now()) { | ||
val reservations = mailReservationRepository.findByReservationTimeBeforeAndStatus( | ||
standardTime, | ||
MailReservationStatus.WAITING | ||
) | ||
val messagesById = findMessageMapById(reservations.map { it.mailMessageId }) | ||
|
||
reservations.forEach { mailReservation -> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. c: 해당 메일 발송 작업이 하나의 트랜잭션으로 묶여야 할 이유가 있을까요? 개별적으로 성공 실패가 나뉘는게 더 자연스럽지 않을까 합니다. |
||
sendingMailService.sendMailByBccSynchronous(MailData(messagesById.getValue(mailReservation.mailMessageId))) | ||
mailReservation.finish() | ||
mailReservationRepository.save(mailReservation) | ||
} | ||
} | ||
|
||
private fun findMessageMapById(mailMessageIds: List<Long>): Map<Long, MailMessage> { | ||
return mailMessageRepository | ||
.findAllById(mailMessageIds) | ||
.associateBy { it.id } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MailReservation이랑 MailMessage를 한 번에 불러오면 쿼리 호출 횟수도 줄이고 코드 복잡도도 줄어들거 같아요
아래 예시 쿼리로 작성했어요. JPQL 문법이 맞는지 확인이 필요합니다 ㅎㅎ;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오 이렇게하면 바로 예약 MailMessage 를 가져올 수 있군요! 넘 좋습니다 ㅎㅎㅎ
한 가지 궁금한게 이 때 조회한 MailReservation도 함께 받을 수 있나요? 메일 전송만 생각하면 MailMessage만 있어도 되는데, 상태 변경이 필요해서요!
There was a problem hiding this comment.
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를 새로 만들거나 객체를 참조하도록 바꾸는 방법이 있겠네요