From 51af0670a2c73ed073066451805b94394bfafc5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9D=B8=EC=A4=80?= <54973090+dlswns2480@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:16:40 +0900 Subject: [PATCH] =?UTF-8?q?[feat=20#71]=20=EC=95=8C=EB=A6=BC=20=EA=B8=B0?= =?UTF-8?q?=EC=B4=88=20=EC=9E=91=EC=97=85=20(#73)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore : Firebase 라이브러리 추가 * feat : Alert 도메인모델, 엔티티 * feat : 알림 전송 로직 구현 * remove : 기존에 있던 파베 설정클래스 제거 * edit : Content 응답 통일 (categpry 관련) * feat : CategoryInfo 생성 --- .../content/dto/response/ContentsResponse.kt | 1 + .../persistence/alert/persist/AlertEntity.kt | 52 +++++++++++++++++++ .../alert/persist/NotificationEntity.kt | 23 -------- adapters/out-web/build.gradle.kts | 1 + .../common/config/FirebaseConfig.kt | 9 ++-- .../kotlin/com/pokit/alert/impl/FcmSender.kt | 42 +++++++++++++++ .../com/pokit/alert/port/out/AlertSender.kt | 7 +++ .../kotlin/com/pokit/alert/model/Alert.kt | 11 ++++ .../content/dto/response/ContentsResult.kt | 1 + .../kotlin/com/pokit/content/model/Content.kt | 13 ++++- 10 files changed, 131 insertions(+), 29 deletions(-) create mode 100644 adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/alert/persist/AlertEntity.kt delete mode 100644 adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/alert/persist/NotificationEntity.kt rename adapters/out-web/src/main/kotlin/com/pokit/{auth => alert}/common/config/FirebaseConfig.kt (77%) create mode 100644 adapters/out-web/src/main/kotlin/com/pokit/alert/impl/FcmSender.kt create mode 100644 application/src/main/kotlin/com/pokit/alert/port/out/AlertSender.kt create mode 100644 domain/src/main/kotlin/com/pokit/alert/model/Alert.kt diff --git a/adapters/in-web/src/main/kotlin/com/pokit/content/dto/response/ContentsResponse.kt b/adapters/in-web/src/main/kotlin/com/pokit/content/dto/response/ContentsResponse.kt index e13b2c96..5ccb8afa 100644 --- a/adapters/in-web/src/main/kotlin/com/pokit/content/dto/response/ContentsResponse.kt +++ b/adapters/in-web/src/main/kotlin/com/pokit/content/dto/response/ContentsResponse.kt @@ -1,5 +1,6 @@ package com.pokit.content.dto.response + import com.pokit.category.model.RemindCategory import java.time.format.DateTimeFormatter diff --git a/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/alert/persist/AlertEntity.kt b/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/alert/persist/AlertEntity.kt new file mode 100644 index 00000000..62a9f63f --- /dev/null +++ b/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/alert/persist/AlertEntity.kt @@ -0,0 +1,52 @@ +package com.pokit.out.persistence.alert.persist + +import com.pokit.alert.model.Alert +import com.pokit.content.model.ContentInfo +import com.pokit.out.persistence.BaseEntity +import jakarta.persistence.* + +@Table(name = "ALERT") +@Entity +class AlertEntity( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + val id: Long = 0L, + + @Column(name = "user_id") + val userId: Long, + + @Column(name = "content_id") + val contentId: Long, + + @Column(name = "content_thumb_nail") + val contentThumbNail: String, + + @Column(name = "title") + val title: String, + + @Column(name = "body") + val body: String, + + @Column(name = "is_deleted") + val deleted: Boolean = false + +) : BaseEntity() { + companion object { + fun of(alert: Alert) = AlertEntity( + userId = alert.userId, + contentId = alert.content.contentId, + contentThumbNail = alert.content.contentThumbNail, + title = alert.title, + body = alert.body, + ) + } +} + +fun AlertEntity.toDomain() = Alert( + id = this.id, + userId = this.userId, + content = ContentInfo(this.contentId, this.contentThumbNail), + title = this.title, + body = this.body, +) diff --git a/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/alert/persist/NotificationEntity.kt b/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/alert/persist/NotificationEntity.kt deleted file mode 100644 index 390b920e..00000000 --- a/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/alert/persist/NotificationEntity.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.pokit.out.persistence.alert.persist - -import jakarta.persistence.* -import java.time.LocalDateTime - -@Table(name = "NOTIFICATION") -@Entity -class NotificationEntity( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id") - val id: Long = 0L, - - @Column(name = "notification_time") - val notificationTime: LocalDateTime, - - @Column(name = "content_id") - val contentId: Long, - - @Column(name = "data") - val data: String, -) { -} diff --git a/adapters/out-web/build.gradle.kts b/adapters/out-web/build.gradle.kts index 7f26e5e8..e7f4998b 100644 --- a/adapters/out-web/build.gradle.kts +++ b/adapters/out-web/build.gradle.kts @@ -20,6 +20,7 @@ dependencies { runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.12.5") implementation("org.bouncycastle:bcpkix-jdk15on:1.69") implementation("org.springframework.cloud:spring-cloud-starter-openfeign:4.1.3") + implementation("com.google.firebase:firebase-admin:8.1.0") } diff --git a/adapters/out-web/src/main/kotlin/com/pokit/auth/common/config/FirebaseConfig.kt b/adapters/out-web/src/main/kotlin/com/pokit/alert/common/config/FirebaseConfig.kt similarity index 77% rename from adapters/out-web/src/main/kotlin/com/pokit/auth/common/config/FirebaseConfig.kt rename to adapters/out-web/src/main/kotlin/com/pokit/alert/common/config/FirebaseConfig.kt index e894b648..dcda7933 100644 --- a/adapters/out-web/src/main/kotlin/com/pokit/auth/common/config/FirebaseConfig.kt +++ b/adapters/out-web/src/main/kotlin/com/pokit/alert/common/config/FirebaseConfig.kt @@ -1,4 +1,4 @@ -package com.pokit.auth.common.config +package com.pokit.alert.common.config import com.google.auth.oauth2.GoogleCredentials import com.google.firebase.FirebaseApp @@ -15,10 +15,9 @@ class FirebaseConfig { val resource = ClassPathResource("google-services.json") val serviceAccount = resource.inputStream - val options = - FirebaseOptions.builder() - .setCredentials(GoogleCredentials.fromStream(serviceAccount)) - .build() + val options = FirebaseOptions.builder() + .setCredentials(GoogleCredentials.fromStream(serviceAccount)) + .build() return FirebaseApp.initializeApp(options) } diff --git a/adapters/out-web/src/main/kotlin/com/pokit/alert/impl/FcmSender.kt b/adapters/out-web/src/main/kotlin/com/pokit/alert/impl/FcmSender.kt new file mode 100644 index 00000000..fe522a05 --- /dev/null +++ b/adapters/out-web/src/main/kotlin/com/pokit/alert/impl/FcmSender.kt @@ -0,0 +1,42 @@ +package com.pokit.alert.impl + +import com.google.firebase.messaging.FirebaseMessaging +import com.google.firebase.messaging.FirebaseMessagingException +import com.google.firebase.messaging.Message +import com.google.firebase.messaging.Notification +import com.pokit.alert.model.Alert +import com.pokit.alert.port.out.AlertSender +import io.github.oshai.kotlinlogging.KotlinLogging +import org.springframework.stereotype.Component + +@Component +class FcmSender : AlertSender { + private val logger = KotlinLogging.logger { } + + companion object { + const val IMAGE_PATH = "https://pokit-storage.s3.ap-northeast-2.amazonaws.com/logo/pokit.png" // 앱 로고 + } + + override fun sendMessage(tokens: List, alert: Alert) { + val notification = Notification.builder() + .setTitle(alert.title) + .setBody(alert.body) + .setImage(IMAGE_PATH) + .build() + + val messages = tokens.map { + Message.builder() + .setNotification(notification) + .setToken(it) + .build() + } + + try { + messages.forEach { + FirebaseMessaging.getInstance().sendAsync(it) + } + } catch (e: FirebaseMessagingException) { + logger.warn { "Failed To Send Message : ${e.message}" } + } + } +} diff --git a/application/src/main/kotlin/com/pokit/alert/port/out/AlertSender.kt b/application/src/main/kotlin/com/pokit/alert/port/out/AlertSender.kt new file mode 100644 index 00000000..689593c4 --- /dev/null +++ b/application/src/main/kotlin/com/pokit/alert/port/out/AlertSender.kt @@ -0,0 +1,7 @@ +package com.pokit.alert.port.out + +import com.pokit.alert.model.Alert + +interface AlertSender { + fun sendMessage(tokens: List, alert: Alert) +} diff --git a/domain/src/main/kotlin/com/pokit/alert/model/Alert.kt b/domain/src/main/kotlin/com/pokit/alert/model/Alert.kt new file mode 100644 index 00000000..95c984da --- /dev/null +++ b/domain/src/main/kotlin/com/pokit/alert/model/Alert.kt @@ -0,0 +1,11 @@ +package com.pokit.alert.model + +import com.pokit.content.model.ContentInfo + +data class Alert( + val id: Long, + val userId: Long, + val content: ContentInfo, + val title: String, + val body: String +) diff --git a/domain/src/main/kotlin/com/pokit/content/dto/response/ContentsResult.kt b/domain/src/main/kotlin/com/pokit/content/dto/response/ContentsResult.kt index f11071d9..f473d237 100644 --- a/domain/src/main/kotlin/com/pokit/content/dto/response/ContentsResult.kt +++ b/domain/src/main/kotlin/com/pokit/content/dto/response/ContentsResult.kt @@ -2,6 +2,7 @@ package com.pokit.content.dto.response import com.pokit.category.model.RemindCategory import com.pokit.content.model.Content +import com.pokit.content.model.CategoryInfo import java.time.LocalDateTime data class ContentsResult( diff --git a/domain/src/main/kotlin/com/pokit/content/model/Content.kt b/domain/src/main/kotlin/com/pokit/content/model/Content.kt index 899125fc..a5505673 100644 --- a/domain/src/main/kotlin/com/pokit/content/model/Content.kt +++ b/domain/src/main/kotlin/com/pokit/content/model/Content.kt @@ -14,7 +14,8 @@ data class Content( var memo: String, var alertYn: String, val createdAt: LocalDateTime = LocalDateTime.now(), - var domain: String = data + var domain: String = data, + val thumbNail: String = "https://pokit-storage.s3.ap-northeast-2.amazonaws.com/category-image/-3+1.png" ) { fun modify(contentCommand: ContentCommand) { this.categoryId = contentCommand.categoryId @@ -36,3 +37,13 @@ data class Content( } } } + +data class ContentInfo( + val contentId: Long, + val contentThumbNail: String +) + +data class CategoryInfo( + val categoryId: Long, + val categoryName: String +)