Skip to content

Commit bec9153

Browse files
authored
Merge pull request #116 from billilge/refactor/#115
refactor: 알림 발행 이벤트 기반으로 전환 및 관리자 알림 쿼리 오류 수정
2 parents f657947 + 905059f commit bec9153

5 files changed

Lines changed: 146 additions & 103 deletions

File tree

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package site.billilge.api.backend.domain.notification.handler
2+
3+
import org.springframework.scheduling.annotation.Async
4+
import org.springframework.stereotype.Component
5+
import org.springframework.transaction.annotation.Transactional
6+
import org.springframework.transaction.event.TransactionPhase
7+
import org.springframework.transaction.event.TransactionalEventListener
8+
import site.billilge.api.backend.domain.member.service.MemberService
9+
import site.billilge.api.backend.domain.notification.enums.NotificationStatus
10+
import site.billilge.api.backend.domain.notification.service.NotificationService
11+
import site.billilge.api.backend.domain.rental.enums.RentalStatus
12+
import site.billilge.api.backend.domain.rental.event.*
13+
14+
@Component
15+
class NotificationEventHandler(
16+
private val notificationService: NotificationService,
17+
private val memberService: MemberService,
18+
) {
19+
@Async
20+
@Transactional
21+
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
22+
fun handleRentalApplied(event: RentalAppliedEvent) {
23+
val member = memberService.findById(event.memberId)
24+
25+
notificationService.sendNotification(
26+
member,
27+
NotificationStatus.USER_RENTAL_APPLY,
28+
listOf(event.itemName),
29+
needPush = true,
30+
)
31+
32+
if (!event.isDevMode) {
33+
notificationService.sendNotificationToAdmin(
34+
NotificationStatus.ADMIN_RENTAL_APPLY,
35+
listOf(
36+
member.name,
37+
member.studentId,
38+
"%02d:%02d".format(event.rentAt.hour, event.rentAt.minute),
39+
event.itemName,
40+
),
41+
needPush = true,
42+
)
43+
}
44+
}
45+
46+
@Async
47+
@Transactional
48+
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
49+
fun handleRentalCancelled(event: RentalCancelledEvent) {
50+
val member = memberService.findById(event.memberId)
51+
52+
notificationService.sendNotificationToAdmin(
53+
NotificationStatus.ADMIN_RENTAL_CANCEL,
54+
listOf(member.name, member.studentId, event.itemName),
55+
needPush = true,
56+
)
57+
}
58+
59+
@Async
60+
@Transactional
61+
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
62+
fun handleReturnApplied(event: ReturnAppliedEvent) {
63+
val member = memberService.findById(event.memberId)
64+
65+
notificationService.sendNotification(
66+
member,
67+
NotificationStatus.USER_RETURN_APPLY,
68+
listOf(event.itemName),
69+
needPush = true,
70+
)
71+
72+
notificationService.sendNotificationToAdmin(
73+
NotificationStatus.ADMIN_RETURN_APPLY,
74+
listOf(member.name, member.studentId, event.itemName),
75+
needPush = true,
76+
)
77+
}
78+
79+
@Async
80+
@Transactional
81+
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
82+
fun handleRentalStatusChanged(event: RentalStatusChangedEvent) {
83+
val member = memberService.findById(event.memberId)
84+
85+
val (notificationStatus, needPush) = when (event.status) {
86+
RentalStatus.CONFIRMED -> NotificationStatus.USER_RENTAL_APPROVED to true
87+
RentalStatus.REJECTED -> NotificationStatus.USER_RENTAL_REJECTED to true
88+
RentalStatus.RETURN_CONFIRMED -> NotificationStatus.USER_RETURN_APPROVED to true
89+
RentalStatus.RETURNED -> NotificationStatus.USER_RETURN_COMPLETED to false
90+
else -> return
91+
}
92+
93+
notificationService.sendNotification(member, notificationStatus, listOf(event.itemName), needPush)
94+
}
95+
}

src/main/kotlin/site/billilge/api/backend/domain/notification/repository/NotificationRepositoryCustomImpl.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,8 @@ class NotificationRepositoryCustomImpl(
3232
.select(notification)
3333
.from(notification)
3434
.where(
35-
memberIdEquals(notification, memberId)
36-
.and(
37-
notification.status.`in`(ADMIN_TYPE)
38-
)
35+
notification.member.isNull
36+
.and(notification.status.`in`(ADMIN_TYPE))
3937
)
4038
.orderBy(notification.createdAt.desc())
4139
.fetch()
@@ -69,6 +67,7 @@ class NotificationRepositoryCustomImpl(
6967
NotificationStatus.USER_RENTAL_APPROVED,
7068
NotificationStatus.USER_RENTAL_REJECTED,
7169
NotificationStatus.USER_RETURN_APPLY,
70+
NotificationStatus.USER_RETURN_APPROVED,
7271
NotificationStatus.USER_RETURN_COMPLETED
7372
)
7473

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package site.billilge.api.backend.domain.rental.event
2+
3+
import site.billilge.api.backend.domain.rental.enums.RentalStatus
4+
import java.time.LocalDateTime
5+
6+
data class RentalAppliedEvent(
7+
val memberId: Long,
8+
val itemName: String,
9+
val rentAt: LocalDateTime,
10+
val isDevMode: Boolean,
11+
)
12+
13+
data class RentalCancelledEvent(
14+
val memberId: Long,
15+
val itemName: String,
16+
)
17+
18+
data class ReturnAppliedEvent(
19+
val memberId: Long,
20+
val itemName: String,
21+
)
22+
23+
data class RentalStatusChangedEvent(
24+
val memberId: Long,
25+
val itemName: String,
26+
val status: RentalStatus,
27+
)

src/main/kotlin/site/billilge/api/backend/domain/rental/service/RentalService.kt

Lines changed: 14 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package site.billilge.api.backend.domain.rental.service
22

3+
import org.springframework.context.ApplicationEventPublisher
34
import org.springframework.data.domain.Page
45
import org.springframework.data.domain.PageRequest
56
import org.springframework.data.domain.Sort
@@ -12,14 +13,16 @@ import site.billilge.api.backend.domain.item.enums.ItemType
1213
import site.billilge.api.backend.domain.member.entity.Member
1314
import site.billilge.api.backend.domain.member.enums.Role
1415
import site.billilge.api.backend.domain.member.exception.MemberErrorCode
15-
import site.billilge.api.backend.domain.notification.enums.NotificationStatus
16-
import site.billilge.api.backend.domain.notification.service.NotificationService
1716
import site.billilge.api.backend.domain.rental.entity.RentalHistory
17+
import site.billilge.api.backend.domain.rental.entity.RentalStatusWorkerLog
1818
import site.billilge.api.backend.domain.rental.enums.RentalStatus
19+
import site.billilge.api.backend.domain.rental.event.RentalAppliedEvent
20+
import site.billilge.api.backend.domain.rental.event.RentalCancelledEvent
21+
import site.billilge.api.backend.domain.rental.event.RentalStatusChangedEvent
22+
import site.billilge.api.backend.domain.rental.event.ReturnAppliedEvent
1923
import site.billilge.api.backend.domain.rental.exception.RentalErrorCode
2024
import site.billilge.api.backend.domain.rental.repository.RentalRepository
2125
import site.billilge.api.backend.domain.rental.repository.RentalStatusWorkerLogRepository
22-
import site.billilge.api.backend.domain.rental.entity.RentalStatusWorkerLog
2326
import site.billilge.api.backend.global.dto.PageableCondition
2427
import site.billilge.api.backend.global.dto.SearchCondition
2528
import site.billilge.api.backend.global.exception.ApiException
@@ -33,7 +36,7 @@ import java.time.ZoneId
3336
class RentalService(
3437
private val rentalRepository: RentalRepository,
3538
private val rentalStatusWorkerLogRepository: RentalStatusWorkerLogRepository,
36-
private val notificationService: NotificationService,
39+
private val eventPublisher: ApplicationEventPublisher,
3740
private val configValueService: ConfigValueService,
3841
) {
3942
@Transactional
@@ -62,25 +65,7 @@ class RentalService(
6265

6366
rentalRepository.save(newRental)
6467

65-
notificationService.sendNotification(
66-
rentUser,
67-
NotificationStatus.USER_RENTAL_APPLY,
68-
listOf(item.name),
69-
true
70-
)
71-
72-
if (!isDevMode) {
73-
notificationService.sendNotificationToAdmin(
74-
NotificationStatus.ADMIN_RENTAL_APPLY,
75-
listOf(
76-
rentUser.name,
77-
rentUser.studentId,
78-
"${String.format("%02d", rentAt.hour)}:${String.format("%02d", rentAt.minute)}",
79-
item.name
80-
),
81-
true
82-
)
83-
}
68+
eventPublisher.publishEvent(RentalAppliedEvent(rentUser.id!!, item.name, rentAt, isDevMode))
8469
}
8570

8671
@Transactional
@@ -135,15 +120,7 @@ class RentalService(
135120

136121
rentalHistory.updateStatus(RentalStatus.CANCEL)
137122

138-
notificationService.sendNotificationToAdmin(
139-
NotificationStatus.ADMIN_RENTAL_CANCEL,
140-
listOf(
141-
renter.name,
142-
renter.studentId,
143-
rentalHistory.item.name
144-
),
145-
true
146-
)
123+
eventPublisher.publishEvent(RentalCancelledEvent(renter.id!!, rentalHistory.item.name))
147124
}
148125

149126
@Transactional
@@ -154,24 +131,7 @@ class RentalService(
154131

155132
rentalHistory.updateStatus(RentalStatus.RETURN_PENDING)
156133

157-
notificationService.sendNotification(
158-
renter,
159-
NotificationStatus.USER_RETURN_APPLY,
160-
listOf(
161-
rentalHistory.item.name
162-
),
163-
true
164-
)
165-
166-
notificationService.sendNotificationToAdmin(
167-
NotificationStatus.ADMIN_RETURN_APPLY,
168-
listOf(
169-
renter.name,
170-
renter.studentId,
171-
rentalHistory.item.name
172-
),
173-
true
174-
)
134+
eventPublisher.publishEvent(ReturnAppliedEvent(renter.id!!, rentalHistory.item.name))
175135
}
176136

177137
fun getReturnRequiredItems(memberId: Long?): List<RentalHistory> {
@@ -218,65 +178,25 @@ class RentalService(
218178

219179
when (rentalHistory.rentalStatus) {
220180
RentalStatus.CONFIRMED -> {
221-
//승인
222181
if (rentedCount > item.count) {
223182
throw ApiException(RentalErrorCode.ITEM_OUT_OF_STOCK)
224183
}
225-
226184
item.subtractCount(rentalHistory.rentedCount)
227185
rentalHistory.updateWorker(worker)
228-
229-
notificationService.sendNotification(
230-
renter,
231-
NotificationStatus.USER_RENTAL_APPROVED,
232-
listOf(
233-
itemName
234-
),
235-
true
236-
)
237-
}
238-
239-
RentalStatus.REJECTED -> {
240-
//대여 반려
241-
notificationService.sendNotification(
242-
renter,
243-
NotificationStatus.USER_RENTAL_REJECTED,
244-
listOf(
245-
itemName
246-
),
247-
true
248-
)
249-
}
250-
251-
RentalStatus.RETURN_CONFIRMED -> {
252-
//반납 승인
253-
notificationService.sendNotification(
254-
renter,
255-
NotificationStatus.USER_RETURN_APPROVED,
256-
listOf(
257-
itemName
258-
),
259-
true
260-
)
261186
}
262187

263188
RentalStatus.RETURNED -> {
264-
//반납 완료
265189
if (item.type == ItemType.CONSUMPTION) return
266-
267190
item.addCount(rentalHistory.rentedCount)
268-
notificationService.sendNotification(
269-
renter,
270-
NotificationStatus.USER_RETURN_COMPLETED,
271-
listOf(
272-
itemName
273-
)
274-
)
275191
}
276192

193+
RentalStatus.REJECTED, RentalStatus.RETURN_CONFIRMED -> Unit
194+
277195
else -> return
278196
}
279197

198+
eventPublisher.publishEvent(RentalStatusChangedEvent(renter.id!!, itemName, rentalHistory.rentalStatus))
199+
280200
rentalStatusWorkerLogRepository.save(
281201
RentalStatusWorkerLog(
282202
rentalHistory = rentalHistory,

src/main/kotlin/site/billilge/api/backend/global/external/fcm/FCMService.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ class FCMService(
2222
.build()
2323

2424
try {
25-
firebaseMessaging.sendAsync(fcmMessage)
26-
log.info { "(studentId=${studentId}) FCM Message sent." }
27-
} catch(exception: FirebaseMessagingException) {
28-
if (exception.messagingErrorCode == MessagingErrorCode.UNREGISTERED) {
29-
log.error { "(studentId=${studentId}) FCM token is unregistered." }
25+
firebaseMessaging.send(fcmMessage)
26+
log.info { "(studentId=$studentId) FCM Message sent." }
27+
} catch (e: FirebaseMessagingException) {
28+
if (e.messagingErrorCode == MessagingErrorCode.UNREGISTERED) {
29+
log.error { "(studentId=$studentId) FCM token is unregistered." }
30+
} else {
31+
log.error { "(studentId=$studentId) FCM send failed: ${e.message}" }
3032
}
3133
}
3234
}

0 commit comments

Comments
 (0)