Skip to content

Commit

Permalink
feat: notification 조회 paging
Browse files Browse the repository at this point in the history
  • Loading branch information
rlaisqls committed Jul 7, 2023
2 parents 9ea5cb5 + 3d279a4 commit 5a5b73d
Show file tree
Hide file tree
Showing 25 changed files with 222 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package team.aliens.dms.domain.notification.dto

import team.aliens.dms.domain.notification.model.OperatingSystem

class RemoveDeviceTokenRequest(
val deviceId: String,
val operatingSystem: OperatingSystem
)
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package team.aliens.dms.domain.notification.dto

import team.aliens.dms.domain.notification.model.DeviceToken
import team.aliens.dms.domain.notification.model.OperatingSystem
import team.aliens.dms.domain.user.model.User

class SetDeviceTokenRequest(
val deviceId: String,
val operatingSystem: OperatingSystem,
val token: String
) {
fun toDeviceToken(user: User) = DeviceToken(
userId = user.id,
schoolId = user.schoolId,
token = token
token = token,
operatingSystem = operatingSystem,
deviceId = deviceId
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ data class DeviceToken(
val id: UUID = UUID(0, 0),
val userId: UUID,
val schoolId: UUID,
val token: String
val token: String,
val operatingSystem: OperatingSystem,
val deviceId: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package team.aliens.dms.domain.notification.model

enum class OperatingSystem {
IOS,
ANDROID
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import java.util.UUID

interface CommandNotificationService {

fun saveDeviceToken(deviceToken: DeviceToken)
fun createOrUpdateDeviceToken(deviceToken: DeviceToken)

fun deleteDeviceTokenById(deviceTokenId: UUID)

fun deleteNotificationOfUserByUserIdAndId(userId: UUID, notificationOfUserId: UUID)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,44 @@ import team.aliens.dms.domain.notification.model.DeviceToken
import team.aliens.dms.domain.notification.spi.CommandDeviceTokenPort
import team.aliens.dms.domain.notification.spi.CommandNotificationOfUserPort
import team.aliens.dms.domain.notification.spi.NotificationPort
import team.aliens.dms.domain.notification.spi.QueryDeviceTokenPort
import team.aliens.dms.domain.notification.spi.QueryNotificationOfUserPort
import team.aliens.dms.domain.notification.spi.QueryTopicSubscriptionPort
import java.util.UUID

@Service
class CommandNotificationServiceImpl(
private val deviceTokenPort: CommandDeviceTokenPort,
private val commandDeviceTokenPort: CommandDeviceTokenPort,
private val queryDeviceTokenPort: QueryDeviceTokenPort,
private val notificationPort: NotificationPort,
private val queryTopicSubscriptionPort: QueryTopicSubscriptionPort,
private val queryNotificationOfUserPort: QueryNotificationOfUserPort,
private val commandNotificationOfUserPort: CommandNotificationOfUserPort
private val commandNotificationOfUserPort: CommandNotificationOfUserPort,
private val notificationServiceImpl: NotificationServiceImpl
) : CommandNotificationService {

override fun saveDeviceToken(deviceToken: DeviceToken) {
deviceTokenPort.saveDeviceToken(deviceToken)
notificationPort.subscribeAllTopics(
token = deviceToken.token
)
override fun createOrUpdateDeviceToken(deviceToken: DeviceToken) {
val savedDeviceToken = queryDeviceTokenPort.queryDeviceTokenByOSAndDeviceId(deviceToken.operatingSystem, deviceToken.deviceId)

if (savedDeviceToken == null) {
commandDeviceTokenPort.saveDeviceToken(deviceToken)
notificationPort.subscribeAllTopics(
token = deviceToken.token
)
} else {
commandDeviceTokenPort.saveDeviceToken(
deviceToken.copy(id = savedDeviceToken.id)
)
notificationServiceImpl.updateSubscribes(
token = deviceToken.token,
topicsToSubscribe = queryTopicSubscriptionPort.queryTopicSubscriptionsByDeviceTokenId(deviceToken.id)
.map { it.topic to it.isSubscribed }
)
}
}

override fun deleteDeviceTokenById(deviceTokenId: UUID) {
commandDeviceTokenPort.deleteDeviceTokenById(deviceTokenId)
}

override fun deleteNotificationOfUserByUserIdAndId(userId: UUID, notificationOfUserId: UUID) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package team.aliens.dms.domain.notification.service

import team.aliens.dms.common.dto.PageData
import team.aliens.dms.domain.notification.model.DeviceToken
import team.aliens.dms.domain.notification.model.NotificationOfUser
import team.aliens.dms.domain.notification.model.OperatingSystem
import team.aliens.dms.domain.notification.model.TopicSubscription
import java.util.UUID

interface GetNotificationService {

fun getNotificationOfUsersByUserId(userId: UUID): List<NotificationOfUser>
fun getNotificationOfUsersByUserId(userId: UUID, pageData: PageData): List<NotificationOfUser>

fun getTopicSubscriptionsByToken(token: String): List<TopicSubscription>

fun getDeviceTokenByOSAndDeviceIdAndUserId(operatingSystem: OperatingSystem, deviceId: String, userId: UUID): DeviceToken

fun getDeviceTokenByToken(token: String): DeviceToken
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package team.aliens.dms.domain.notification.service

import team.aliens.dms.common.annotation.Service
import team.aliens.dms.common.dto.PageData
import team.aliens.dms.domain.notification.exception.DeviceTokenNotFoundException
import team.aliens.dms.domain.notification.model.OperatingSystem
import team.aliens.dms.domain.notification.model.TopicSubscription
import team.aliens.dms.domain.notification.spi.QueryDeviceTokenPort
import team.aliens.dms.domain.notification.spi.QueryNotificationOfUserPort
Expand All @@ -10,19 +12,31 @@ import java.util.UUID

@Service
class GetNotificationServiceImpl(
private val deviceTokenPort: QueryDeviceTokenPort,
private val notificationOfUserPort: QueryNotificationOfUserPort,
private val topicSubscriptionPort: QueryTopicSubscriptionPort
private val queryDeviceTokenPort: QueryDeviceTokenPort,
private val queryNotificationOfUserPort: QueryNotificationOfUserPort,
private val queryTopicSubscriptionPort: QueryTopicSubscriptionPort
) : GetNotificationService {

override fun getNotificationOfUsersByUserId(userId: UUID) =
notificationOfUserPort.queryNotificationOfUserByUserId(userId)
override fun getNotificationOfUsersByUserId(userId: UUID, pageData: PageData) =
queryNotificationOfUserPort.queryNotificationOfUserByUserId(userId, pageData)

override fun getTopicSubscriptionsByToken(token: String): List<TopicSubscription> {
val savedToken = getDeviceTokenByToken(token)
return topicSubscriptionPort.queryTopicSubscriptionsByDeviceTokenId(savedToken.id)
return queryTopicSubscriptionPort.queryTopicSubscriptionsByDeviceTokenId(savedToken.id)
}

override fun getDeviceTokenByOSAndDeviceIdAndUserId(
operatingSystem: OperatingSystem,
deviceId: String,
userId: UUID
) = queryDeviceTokenPort.queryDeviceTokenByOSAndDeviceId(
operatingSystem = operatingSystem,
deviceId = deviceId
).run {
if (this == null || this.userId != userId) throw DeviceTokenNotFoundException
return@run this
}

override fun getDeviceTokenByToken(token: String) =
deviceTokenPort.queryDeviceTokenByToken(token) ?: throw DeviceTokenNotFoundException
queryDeviceTokenPort.queryDeviceTokenByToken(token) ?: throw DeviceTokenNotFoundException
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ interface CommandDeviceTokenPort {
fun saveDeviceToken(deviceToken: DeviceToken): DeviceToken

fun deleteDeviceTokenByUserId(userId: UUID)

fun deleteDeviceTokenById(deviceTokenId: UUID)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package team.aliens.dms.domain.notification.spi

import team.aliens.dms.domain.notification.model.DeviceToken
import team.aliens.dms.domain.notification.model.OperatingSystem
import java.util.UUID

interface QueryDeviceTokenPort {

fun queryDeviceTokenByUserId(userId: UUID): DeviceToken?

fun queryDeviceTokenByToken(token: String): DeviceToken?

fun queryDeviceTokenByOSAndDeviceId(operatingSystem: OperatingSystem, deviceId: String): DeviceToken?
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package team.aliens.dms.domain.notification.spi

import team.aliens.dms.common.dto.PageData
import team.aliens.dms.domain.notification.model.NotificationOfUser
import java.util.UUID

interface QueryNotificationOfUserPort {

fun queryNotificationOfUserByUserId(userId: UUID): List<NotificationOfUser>
fun queryNotificationOfUserByUserId(userId: UUID, pageData: PageData): List<NotificationOfUser>

fun queryNotificationOfUserById(notificationOfUserId: UUID): NotificationOfUser?
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package team.aliens.dms.domain.notification.usecase

import team.aliens.dms.common.annotation.ReadOnlyUseCase
import team.aliens.dms.common.dto.PageData
import team.aliens.dms.domain.notification.dto.NotificationsResponse
import team.aliens.dms.domain.notification.service.NotificationService
import team.aliens.dms.domain.user.service.UserService
Expand All @@ -11,10 +12,13 @@ class QueryMyNotificationsUseCase(
private val notificationService: NotificationService
) {

fun execute(): NotificationsResponse {
fun execute(pageData: PageData): NotificationsResponse {
val user = userService.getCurrentUser()
return NotificationsResponse.of(
notificationService.getNotificationOfUsersByUserId(user.id)
notificationService.getNotificationOfUsersByUserId(
userId = user.id,
pageData = pageData
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package team.aliens.dms.domain.notification.usecase

import team.aliens.dms.common.annotation.UseCase
import team.aliens.dms.domain.notification.dto.RemoveDeviceTokenRequest
import team.aliens.dms.domain.notification.service.NotificationService
import team.aliens.dms.domain.user.service.UserService

@UseCase
class RemoveDeviceTokenUseCase(
private val userService: UserService,
private val notificationService: NotificationService
) {
fun execute(request: RemoveDeviceTokenRequest) {
val user = userService.getCurrentUser()

val deviceToken = notificationService.getDeviceTokenByOSAndDeviceIdAndUserId(
operatingSystem = request.operatingSystem,
deviceId = request.deviceId,
userId = user.id
)
notificationService.deleteDeviceTokenById(deviceToken.id)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ class SetDeviceTokenUseCase(

fun execute(request: SetDeviceTokenRequest) {
val user = userService.getCurrentUser()

notificationService.saveDeviceToken(
notificationService.createOrUpdateDeviceToken(
request.toDeviceToken(user)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,37 @@ import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Configuration
import java.io.File
import java.io.IOException
import java.net.URL
import java.nio.file.Files
import java.nio.file.Paths
import javax.annotation.PostConstruct

@Configuration
class FCMConfig(
@Value("\${fcm.path}")
private val path: String
@Value("\${fcm.file-url}")
private val url: String
) {

@PostConstruct
fun initialize() {
try {
if (FirebaseApp.getApps().isEmpty()) {
val options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.fromStream(File(path).inputStream()))
.build()
FirebaseApp.initializeApp(options)
URL(url).openStream().use { inputStream ->
Files.copy(inputStream, 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()
}
} catch (e: IOException) {
e.printStackTrace()
}
}

companion object {
private const val PATH = "./credentials.json"
}
}
2 changes: 1 addition & 1 deletion dms-infrastructure/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ spring:
max-request-size: 20MB

fcm:
path: ${FCM_PATH}
file-url: ${FCM_FILE_URL}

secret:
secret-key: ${SECRET_KEY:asdfghgfds}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package team.aliens.dms.persistence.notification

import org.springframework.stereotype.Component
import team.aliens.dms.domain.notification.model.DeviceToken
import team.aliens.dms.domain.notification.model.OperatingSystem
import team.aliens.dms.domain.notification.spi.DeviceTokenPort
import team.aliens.dms.persistence.notification.mapper.DeviceTokenMapper
import team.aliens.dms.persistence.notification.repository.DeviceTokenJpaRepository
Expand All @@ -27,7 +28,15 @@ class DeviceTokenPersistenceAdapter(
deviceTokenRepository.findByToken(token)
)

override fun queryDeviceTokenByOSAndDeviceId(operatingSystem: OperatingSystem, deviceId: String) = notificationMapper.toDomain(
deviceTokenRepository.findByOperatingSystemAndDeviceId(operatingSystem, deviceId)
)

override fun deleteDeviceTokenByUserId(userId: UUID) {
deviceTokenRepository.deleteByUserId(userId)
}

override fun deleteDeviceTokenById(deviceTokenId: UUID) {
deviceTokenRepository.deleteById(deviceTokenId)
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package team.aliens.dms.persistence.notification

import com.querydsl.jpa.impl.JPAQueryFactory
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Component
import team.aliens.dms.common.dto.PageData
import team.aliens.dms.domain.notification.model.NotificationOfUser
import team.aliens.dms.domain.notification.spi.NotificationOfUserPort
import team.aliens.dms.persistence.notification.entity.QNotificationOfUserJpaEntity.notificationOfUserJpaEntity
import team.aliens.dms.persistence.notification.mapper.NotificationOfUserMapper
import team.aliens.dms.persistence.notification.repository.NotificationOfUserJpaRepository
import java.util.UUID

@Component
class NotificationOfPersistenceAdapterOfUser(
private val notificationOfUserMapper: NotificationOfUserMapper,
private val notificationOfUserRepository: NotificationOfUserJpaRepository
private val notificationOfUserRepository: NotificationOfUserJpaRepository,
private val queryFactory: JPAQueryFactory
) : NotificationOfUserPort {

override fun saveNotificationOfUser(notificationOfUser: NotificationOfUser) =
Expand All @@ -29,9 +33,13 @@ class NotificationOfPersistenceAdapterOfUser(
)
}

override fun queryNotificationOfUserByUserId(userId: UUID) =
notificationOfUserRepository.findByUserId(userId)
.map { notificationOfUserMapper.toDomain(it)!! }
override fun queryNotificationOfUserByUserId(userId: UUID, pageData: PageData) =
queryFactory
.selectFrom(notificationOfUserJpaEntity)
.where(notificationOfUserJpaEntity.user.id.eq(userId))
.offset(pageData.offset)
.limit(pageData.size)
.fetch().map { notificationOfUserMapper.toDomain(it)!! }

override fun queryNotificationOfUserById(notificationOfUserId: UUID) = notificationOfUserMapper.toDomain(
notificationOfUserRepository.findByIdOrNull(notificationOfUserId)
Expand Down
Loading

0 comments on commit 5a5b73d

Please sign in to comment.