Skip to content

Commit

Permalink
Merge pull request #323 from team-haribo/322-app-to-server-fcm
Browse files Browse the repository at this point in the history
🔁 FCM 외출제 전 알림 추가
  • Loading branch information
enbraining authored Dec 10, 2024
2 parents 70cc8f3 + 30cb040 commit 03fbd21
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import org.springframework.stereotype.Component
class NotificationScheduler(
private val sendNotificationUseCase: SendNotificationUseCase
) {
@Scheduled(cron = "0 30 17 ? * 1,3") // 매주 월요일, 수요일 5시 30분에 미리 공지한다. (1시간 10분 전)
fun sendFirstNotification() =
sendNotificationUseCase.execute(NotificationType.FIRST_NOTIFICATION)

@Scheduled(cron = "0 20 18 ? * 3") // 매주 수요일 6시 20분에 외출 여부 notification을 보낸다.
fun sendNotificationAtBeforeOuting() = sendNotificationUseCase.execute(NotificationType.BEFORE_OUTING)

@Scheduled(cron = "0 20 19 ? * 3") // 매주 수요일 7시 20분에 외출 여부 notification을 보낸다.
fun sendNotificationAtAfterOuting() = sendNotificationUseCase.execute(NotificationType.AFTER_OUTING)

@Scheduled(cron = "0 35 18 ? * 1,3") // 매주 월요일, 수요일 6시 35분에 공지한다. (5분 전)
fun sendSecondNotification() =
sendNotificationUseCase.execute(NotificationType.FINAL_NOTIFICATION)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,82 +7,54 @@ import com.goms.v2.domain.notification.spi.NotificationPort
import com.goms.v2.repository.notification.DeviceTokenRepository
import com.goms.v2.repository.outing.OutingBlackListRepository
import com.goms.v2.repository.outing.OutingRepository
import com.goms.v2.repository.outingDate.DeniedOutingDateRepository
import java.time.LocalDate
import java.util.*

@UseCaseWithReadOnlyTransaction
class SendNotificationUseCase(
private val notificationPort: NotificationPort,
private val deviceTokenRepository: DeviceTokenRepository,
private val outingRepository: OutingRepository,
private val outingBlackListRepository: OutingBlackListRepository
private val deniedOutingDateRepository: DeniedOutingDateRepository,
) {

fun execute(notificationType: NotificationType) {
val isExistTodayOutingDate = deniedOutingDateRepository.existsByOutingDate(LocalDate.now())

when (notificationType) {
// 외출 전 지난주 지각자 수에 따라서 외출 알림 발송
NotificationType.BEFORE_OUTING -> {
NotificationType.FIRST_NOTIFICATION -> {
runCatching {
val outingBlackList = outingBlackListRepository.findAll()
if (outingBlackList.isEmpty()) {
notificationPort.sendNotification(
deviceTokens = deviceTokenRepository.findAll().map { it.token },
notification = Notification(
title = Topic.BEFORE_OUTING.title,
content = Topic.BEFORE_OUTING.content,
writer = Writer.GOMS
)
)
} else {
val outingBlackListToken = outingBlackList.map { findDeviceTokenByAccountIdx(it.accountIdx) }.map { it.token }

notificationPort.sendNotification(
deviceTokens = outingBlackListToken,
notification = Notification(
title = Topic.GROUNDED.title,
content = Topic.GROUNDED.content,
notificationPort.sendNotification(
deviceTokens = deviceTokenRepository.findAll().map { it.token },
notification = Notification(
title = if(isExistTodayOutingDate) Topic.DENIED_NOTIFICATION.title
else Topic.FIRST_NOTIFICATION.title,
content = if(isExistTodayOutingDate) Topic.DENIED_NOTIFICATION.content
else Topic.FIRST_NOTIFICATION.content,
writer = Writer.GOMS
)
)
}.onFailure {
it.printStackTrace()
}
}

NotificationType.FINAL_NOTIFICATION -> {
if(!isExistTodayOutingDate){
runCatching {
notificationPort.sendNotification(
deviceTokens = deviceTokenRepository.findAll().filter { !outingBlackListToken.contains(it.token) }.map { it.token },
deviceTokens = deviceTokenRepository.findAll().map { it.token },
notification = Notification(
title = Topic.BEFORE_OUTING.title,
content = Topic.BEFORE_OUTING.content,
title = Topic.FINAL_NOTIFICATION.title,
content = Topic.FINAL_NOTIFICATION.content,
writer = Writer.GOMS
)
)
}.onFailure {
it.printStackTrace()
}
}.onFailure {
it.printStackTrace()
}

}

// 외출 5분 전 아직 복귀하지 않은 학생들에게 알림 발송
NotificationType.AFTER_OUTING -> {
runCatching {
val outingList = outingRepository.findAll()
// 외출자가 없으면 반환하고 끝낸다.
if (outingList.isEmpty()) return

notificationPort.sendNotification(
deviceTokens = outingList.map { findDeviceTokenByAccountIdx(it.account.idx) }.map { it.token },
notification = Notification(
title = Topic.AFTER_OUTING.title,
content = Topic.AFTER_OUTING.content,
writer = Writer.GOMS
)
)
}.onFailure {
it.stackTrace
}
}
}
}

private fun findDeviceTokenByAccountIdx(accountIdx: UUID): DeviceToken =
deviceTokenRepository.findByIdxOrNull(accountIdx)
?: throw DeviceTokenNotFoundException()

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,5 @@ import com.goms.v2.common.annotation.Aggregate

@Aggregate
enum class NotificationType {

BEFORE_OUTING, AFTER_OUTING

FIRST_NOTIFICATION, FINAL_NOTIFICATION
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,22 @@ enum class Topic(
val content: String
) {

BEFORE_OUTING(
title = "오늘 수요 외출제 시행합니다!",
content = "꼭 나가기 전 후로 GOMS 앱을 통해 QR을 찍어주세요! \n"
FIRST_NOTIFICATION(
title = "[GOMS] 개발팀",
content = "✅ㅣ오늘 외출제 시행합니다!\n" +
"추가사항은 GSM 디스코드를 확인해주세요."
),

GROUNDED(
title = "외출제 금지",
content = "저번주 외출제 지각생이므로 외출 금지 대상입니다. \n"
FINAL_NOTIFICATION(
title = "[GOMS] 개발팀",
content = "⌛ㅣ잠시 후 외출제가 시작됩니다!\n" +
"신발을 꼭 착용해주세요. (크록스 X)"
),

AFTER_OUTING(
title = "금일 외출 시간이 5분 남았습니다.",
content = "외출중이신 분들은 빠르게 학교로 복귀해주세요\n! \n"
);

DENIED_NOTIFICATION(
title = "[GOMS] 개발팀",
content = "❌ㅣ오늘 외출제는 시행하지 않습니다!\n" +
"외출 시 무단 외출 처리됩니다."
),
}

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class FcmAdapter: NotificationPort {
val message = getMulticastMassageBuilderByNotification(notification)
.addAllTokens(deviceTokens)
.build()
firebaseInstance.sendMulticastAsync(message)
firebaseInstance.sendMulticast(message)
}

private fun getMulticastMassageBuilderByNotification(notification: Notification) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,15 @@ private val log = KotlinLogging.logger { }
class FcmConfig(
private val fcmProperties: FcmProperties
) {

companion object {
const val PATH = "./credentials.json"
}

@PostConstruct
fun init() {
log.info("init start")
runCatching {
URL(fcmProperties.fileUrl).openStream().use {
Files.copy(it, Paths.get(PATH))
val file = File(PATH)
if (FirebaseApp.getApps().isEmpty()) {
val options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.fromStream(file.inputStream()))
.build()
FirebaseApp.initializeApp(options)
}
file.delete()
if (FirebaseApp.getApps().isEmpty()) {
val options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.fromStream(fcmProperties.credential.byteInputStream()))
.build()
FirebaseApp.initializeApp(options)
}
}.onFailure {
it.printStackTrace()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ import org.springframework.boot.context.properties.ConstructorBinding
@ConstructorBinding
@ConfigurationProperties("fcm")
class FcmProperties(
val fileUrl: String
val credential: String
)
2 changes: 1 addition & 1 deletion goms-infrastructure/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ outing:
expiredAt: ${OUTING_EXP}

fcm:
fileUrl: ${FCM_FILE_URL}
credential: ${FCM_CREDENTIAL}

cloud:
aws:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,4 @@ class NotificationController(
fun deleteDeviceToken(): ResponseEntity<Void> =
deleteDeviceTokenUseCase.execute()
.run { ResponseEntity.status(HttpStatus.NO_CONTENT).build() }

@GetMapping("outing/before")
fun beforeOutingTestApi(): ResponseEntity<Map<String, String>> =
sendNotificationUseCase.execute(NotificationType.BEFORE_OUTING)
.run { ResponseEntity.ok(mapOf("message" to "success")) }

@GetMapping("outing/after")
fun afterOutingTestApi(): ResponseEntity<Map<String, String>> =
sendNotificationUseCase.execute(NotificationType.AFTER_OUTING)
.run { ResponseEntity.ok(mapOf("message" to "success")) }

}

0 comments on commit 03fbd21

Please sign in to comment.