Skip to content
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

๐Ÿ”€ :: FCM ํ† ํฐ ์ €์žฅ API ๊ตฌํ˜„ #101

Merged
merged 11 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,24 @@ import andreas311.miso.common.annotation.RequestController
import andreas311.miso.domain.notification.adapter.input.data.DetailNotificationResponse
import andreas311.miso.domain.notification.adapter.input.mapper.NotificationDataMapper
import andreas311.miso.domain.notification.application.port.input.DetailNotificationUseCase
import andreas311.miso.domain.notification.application.port.input.SaveDeviceTokenUseCase
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping

@RequestController("/notification")
class NotificationAdapter(
private val notificationDataMapper: NotificationDataMapper,
private val detailNotificationUseCase: DetailNotificationUseCase
private val saveDeviceTokenUseCase: SaveDeviceTokenUseCase,
private val detailNotificationUseCase: DetailNotificationUseCase,
) {
@PostMapping("/save/{token}")
fun save(@PathVariable(name = "token") deviceToken: String): ResponseEntity<Void> =
saveDeviceTokenUseCase.execute(deviceToken)
.let { ResponseEntity.status(HttpStatus.CREATED).build() }

@GetMapping("/{id}")
fun detail(@PathVariable id: Long): ResponseEntity<DetailNotificationResponse> =
detailNotificationUseCase.execute(id)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package andreas311.miso.domain.notification.adapter.output.persistence

import andreas311.miso.domain.notification.adapter.output.persistence.mapper.DeviceTokenMapper
import andreas311.miso.domain.notification.adapter.output.persistence.repository.DeviceTokenRepository
import andreas311.miso.domain.notification.application.port.output.CommandDeviceTokenPort
import andreas311.miso.domain.notification.domain.DeviceToken
import org.springframework.stereotype.Component

@Component
class CommandDeviceTokenPersistenceAdapter(
private val deviceTokenMapper: DeviceTokenMapper,
private val deviceTokenRepository: DeviceTokenRepository
) : CommandDeviceTokenPort {
override fun saveDeviceToken(deviceToken: DeviceToken): DeviceToken {
val deviceTokenEntity = deviceTokenRepository.save(deviceTokenMapper toEntity deviceToken)
return deviceTokenMapper.toDomain(deviceTokenEntity)!!
}

override fun deleteDeviceToken(deviceToken: DeviceToken) {
val deviceTokenEntity = deviceTokenMapper toEntity deviceToken
return deviceTokenRepository.delete(deviceTokenEntity)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package andreas311.miso.domain.notification.adapter.output.persistence

import andreas311.miso.domain.notification.adapter.output.persistence.mapper.DeviceTokenMapper
import andreas311.miso.domain.notification.adapter.output.persistence.repository.DeviceTokenRepository
import andreas311.miso.domain.notification.application.port.output.QueryDeviceTokenPort
import andreas311.miso.domain.notification.domain.DeviceToken
import org.springframework.stereotype.Component
import java.util.*

@Component
class QueryDeviceTokenPersistenceAdapter(
private val deviceTokenMapper: DeviceTokenMapper,
private val deviceTokenRepository: DeviceTokenRepository
) : QueryDeviceTokenPort {
override fun findByUserIdOrNull(id: UUID): DeviceToken? {
val deviceTokenEntity = deviceTokenRepository.findByUserId(id)
return deviceTokenMapper toDomain deviceTokenEntity
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package andreas311.miso.domain.notification.adapter.output.persistence.entity

import org.springframework.data.annotation.Id
import org.springframework.data.redis.core.RedisHash
import org.springframework.data.redis.core.index.Indexed
import java.util.*

@RedisHash(value = "deviceToken")
data class DeviceTokenEntity(
@Indexed
val userId: UUID,

@Id
@Indexed
val deviceToken: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package andreas311.miso.domain.notification.adapter.output.persistence.mapper

import andreas311.miso.domain.notification.adapter.output.persistence.entity.DeviceTokenEntity
import andreas311.miso.domain.notification.domain.DeviceToken
import org.springframework.stereotype.Component

@Component
class DeviceTokenMapper {
infix fun toEntity(domain: DeviceToken): DeviceTokenEntity =
DeviceTokenEntity(
userId = domain.userId,
deviceToken = domain.deviceToken
)

infix fun toDomain(entity: DeviceTokenEntity?): DeviceToken? =
entity?.let {
DeviceToken(
userId = entity.userId,
deviceToken = entity.deviceToken
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package andreas311.miso.domain.notification.adapter.output.persistence.repository

import andreas311.miso.domain.notification.adapter.output.persistence.entity.DeviceTokenEntity
import org.springframework.data.repository.CrudRepository
import java.util.UUID

interface DeviceTokenRepository : CrudRepository<DeviceTokenEntity, String> {
fun findByUserId(userId: UUID): DeviceTokenEntity?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package andreas311.miso.domain.notification.application.port.input

interface SaveDeviceTokenUseCase {
fun execute(token: String)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package andreas311.miso.domain.notification.application.port.output

import andreas311.miso.domain.notification.domain.DeviceToken

interface CommandDeviceTokenPort {
fun saveDeviceToken(deviceToken: DeviceToken): DeviceToken
fun deleteDeviceToken(deviceToken: DeviceToken)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package andreas311.miso.domain.notification.application.port.output

import andreas311.miso.domain.notification.domain.DeviceToken
import java.util.UUID

interface QueryDeviceTokenPort {
fun findByUserIdOrNull(id: UUID): DeviceToken?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package andreas311.miso.domain.notification.application.service

import andreas311.miso.common.annotation.RollbackService
import andreas311.miso.domain.auth.application.port.output.UserSecurityPort
import andreas311.miso.domain.notification.application.port.input.SaveDeviceTokenUseCase
import andreas311.miso.domain.notification.application.port.output.CommandDeviceTokenPort
import andreas311.miso.domain.notification.application.port.output.QueryDeviceTokenPort
import andreas311.miso.domain.notification.domain.DeviceToken

@RollbackService
class SaveDeviceTokenService(
private val userSecurityPort: UserSecurityPort,
private val queryDeviceTokenPort: QueryDeviceTokenPort,
private val commandDeviceTokenPort: CommandDeviceTokenPort
) : SaveDeviceTokenUseCase {
override fun execute(token: String) {
val user = userSecurityPort.currentUser()

val deviceToken = queryDeviceTokenPort.findByUserIdOrNull(user.id)

deviceToken?.let {
commandDeviceTokenPort.deleteDeviceToken(deviceToken)
}

commandDeviceTokenPort.saveDeviceToken(
DeviceToken(
userId = user.id,
deviceToken = token
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package andreas311.miso.domain.notification.domain

import java.util.UUID

data class DeviceToken(
val userId: UUID,
val deviceToken: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class SecurityConfig(
.antMatchers(HttpMethod.PATCH, "/recyclables/{id}").hasAuthority("ROLE_ADMIN")
.antMatchers(HttpMethod.DELETE, "/recyclables/{id}").hasAuthority("ROLE_ADMIN")

.antMatchers(HttpMethod.POST, "/notification/save/{deviceToken}").authenticated()
.antMatchers(HttpMethod.POST, "/notification/save/{token}").authenticated()
.antMatchers(HttpMethod.GET, "/notification/{id}").authenticated()

.antMatchers(HttpMethod.GET, "/environment").authenticated()
Expand Down
Loading