Skip to content

Commit

Permalink
Api-v0.0.4-5
Browse files Browse the repository at this point in the history
  • Loading branch information
kdomo authored Jul 20, 2023
2 parents 15eb066 + 97fff30 commit 968cde9
Show file tree
Hide file tree
Showing 14 changed files with 158 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.depromeet.whatnow.api.notification.dto

import com.depromeet.whatnow.domains.notification.domain.ArrivalNotification
import com.depromeet.whatnow.domains.notification.domain.NotificationType
import java.time.LocalDateTime

class ArrivalNotificationResponse(
val promiseId: Long,
val senderUserId: Long,
override val createdAt: LocalDateTime,
) : NotificationAbstract(NotificationType.START_SHARING, createdAt) {
companion object {
fun from(notification: ArrivalNotification): ArrivalNotificationResponse {
return ArrivalNotificationResponse(
notification.promiseId,
notification.senderUserId,
notification.createdAt,
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.depromeet.whatnow.api.notification.usecase

import com.depromeet.whatnow.annotation.UseCase
import com.depromeet.whatnow.api.notification.dto.ArrivalNotificationResponse
import com.depromeet.whatnow.api.notification.dto.EndSharingNotificationResponse
import com.depromeet.whatnow.api.notification.dto.ImageNotificationResponse
import com.depromeet.whatnow.api.notification.dto.InteractionAttainmentNotificationResponse
Expand All @@ -9,6 +10,7 @@ import com.depromeet.whatnow.api.notification.dto.NotificationResponse
import com.depromeet.whatnow.api.notification.dto.StartSharingNotificationResponse
import com.depromeet.whatnow.api.notification.dto.TimeOverNotificationResponse
import com.depromeet.whatnow.config.security.SecurityUtils
import com.depromeet.whatnow.domains.notification.domain.ArrivalNotification
import com.depromeet.whatnow.domains.notification.domain.EndSharingNotification
import com.depromeet.whatnow.domains.notification.domain.ImageNotification
import com.depromeet.whatnow.domains.notification.domain.InteractionAttainmentNotification
Expand Down Expand Up @@ -46,6 +48,9 @@ class NotificationReadUseCase(
is TimeOverNotification -> {
TimeOverNotificationResponse.from(notification)
}
is ArrivalNotification -> {
ArrivalNotificationResponse.from(notification)
}
else -> throw UnknownNotificationTypeException.EXCEPTION
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,9 @@ class PromiseReadUseCase(

when (promise?.promiseType) {
PromiseType.BEFORE, PromiseType.END -> {
val promiseType = promise.promiseType
val promiseFindDto = PromiseFindDto.of(promise, participant)

promiseSplitByPromiseTypeDto.getOrPut(promiseType) { mutableListOf() }
promiseSplitByPromiseTypeDto.getOrPut(promise.promiseType) { mutableListOf() }
.add(promiseFindDto)
}

Expand Down Expand Up @@ -97,14 +96,14 @@ class PromiseReadUseCase(
promise = promise,
users = participants,
)
}.sortedByDescending { it.endTime }
}.sortedBy { it.endTime }
}

fun findPromiseDetailByStatus(promiseType: PromiseType): List<PromiseDetailDto> {
val userId: Long = SecurityUtils.currentUserId
val promiseUsersByPromiseId = promiseUserAdaptor.findByUserId(userId)
val promiseIds = promiseUsersByPromiseId.map { it.promiseId }
val promises = promiseAdaptor.queryPromises(promiseIds)
val promises = promiseAdaptor.queryPromises(promiseIds).filter { it.promiseType == promiseType }
val uniqueUsers = promiseUsersByPromiseId.distinctBy { it.userId }
val users = userAdapter.queryUsers(uniqueUsers.map { it.userId })
val result = mutableListOf<PromiseDetailDto>()
Expand All @@ -125,7 +124,7 @@ class PromiseReadUseCase(
}

val promiseImagesUrls = promiseImageAdapter.findAllByPromiseId(promise.id!!)
.sortedBy { it.createdAt }
.sortedByDescending { it.createdAt }
.map { it.uri }

val timeOverLocations = promiseUsers.mapNotNull { promiseUser ->
Expand All @@ -144,7 +143,7 @@ class PromiseReadUseCase(
)
}

return result.sortedByDescending { it.endTime }
return result.sortedBy { it.endTime }
}

fun findPromiseActive(promiseId: Long): Boolean {
Expand All @@ -162,7 +161,7 @@ class PromiseReadUseCase(

private fun findPromisesByUserId(userId: Long): List<Promise> {
val promiseUsers = promiseUserAdaptor.findByUserId(userId)
return promiseUsers.map { promiseAdaptor.queryPromise(it.promiseId) }.sortedByDescending { it.endTime }
return promiseUsers.map { promiseAdaptor.queryPromise(it.promiseId) }
}

fun findByPromiseId(promiseId: Long): PromiseFindDto {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,25 @@ class PromiseReadUseCaseTest {
),
Promise(
id = 2,
title = "Promise A",
endTime = promiseTime1,
mainUserId = 1L,
meetPlace = PlaceVo(
CoordinateVo(352.1, 167.2),
"서울시 강남구",
),
promiseType = PromiseType.BEFORE,
),
Promise(
id = 3,
title = "Promise 2",
endTime = promiseTime2,
mainUserId = 2L,
meetPlace = PlaceVo(
CoordinateVo(123.4, 234.2),
"전라북도 남원시",
),
promiseType = PromiseType.DELETED,
promiseType = PromiseType.END,
),
)
val users = listOf(
Expand Down Expand Up @@ -148,17 +159,13 @@ class PromiseReadUseCaseTest {
// Then
Assertions.assertEquals(2, result.size)

Assertions.assertEquals("Promise 2", result[0].title)
Assertions.assertEquals(promiseTime1, result[1].endTime)
Assertions.assertEquals("Promise 1", result[0].title)
Assertions.assertEquals(promiseTime1, result[0].endTime)
Assertions.assertEquals(1, result[1].promiseUsers.size)

Assertions.assertEquals("Promise 1", result[1].title)
Assertions.assertEquals(promiseTime2, result[0].endTime)
Assertions.assertEquals(1, result[0].promiseUsers.size)

// 약속 1번
Assertions.assertEquals(1234, result[1].promiseUsers[0].interactions[0].count)
Assertions.assertEquals(1234, result[0].promiseUsers[0].interactions[0].count)
// 약속 2번
Assertions.assertEquals(2934, result[0].promiseUsers[0].interactions[0].count)
Assertions.assertEquals(2934, result[1].promiseUsers[0].interactions[0].count)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.depromeet.whatnow.domains.notification.domain

import javax.persistence.DiscriminatorValue
import javax.persistence.Entity

@Entity
@DiscriminatorValue("ARRIVAL")
class ArrivalNotification(
var promiseId: Long,

var senderUserId: Long,

override var targetUserId: Long,
) : Notification(targetUserId)
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.depromeet.whatnow.domains.notification.service

import com.depromeet.whatnow.domains.interaction.domain.InteractionType
import com.depromeet.whatnow.domains.notification.adapter.NotificationAdapter
import com.depromeet.whatnow.domains.notification.domain.ArrivalNotification
import com.depromeet.whatnow.domains.notification.domain.EndSharingNotification
import com.depromeet.whatnow.domains.notification.domain.ImageNotification
import com.depromeet.whatnow.domains.notification.domain.InteractionAttainmentNotification
Expand Down Expand Up @@ -49,6 +50,10 @@ class NotificationDomainService(
notificationAdapter.save(InteractionAttainmentNotification(promiseId, senderUserId, interactionType, targetUserId))
}

fun saveForArrival(promiseId: Long, senderUserId: Long, targetUserId: Long) {
notificationAdapter.save(ArrivalNotification(promiseId, senderUserId, targetUserId))
}

@Transactional(readOnly = true)
fun getMyNotifications(userId: Long, pageable: Pageable): Slice<Notification> {
return notificationAdapter.getMyNotifications(userId, pageable)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ import com.depromeet.whatnow.common.aop.event.DomainEvent
class PromiseUserUpdateLocationEvent(
val promiseId: Long,
val userId: Long,
val id: Long,
val promiseUserId: Long,
) : DomainEvent()
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class ImageRegisterEventHandler(

// 앱 알람 허용한 유저
val appAlarmPermitUsers = usersExcludingSelf.filter { user ->
user.fcmNotification.fcmToken != null && user.fcmNotification.appAlarm
user.fcmNotification.fcmToken != "" && user.fcmNotification.appAlarm
}

val data: MutableMap<String, String> = mutableMapOf()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ class PromiseActivationEventHandler(

val now = LocalDateTime.now()

// 약속 시작 시간까지 남은 시간(초)
val promiseStartAndTrackingStartTime = Duration.between(now, promise.endTime.minusMinutes(30)).seconds
// 현재 시간부터 약속 트래킹 시작까지 남은 시간 (= 현재시간 - 약속시간 - 1시간)
val promiseStartAndTrackingStartTime = Duration.between(now, promise.endTime.minusHours(1)).seconds

// 약속 종료 시간까지 남은 시간(초)
// 현재 시간부터 약속 종료까지 남은시간 (= 현재시간 - 약속시간)
val promiseEndTime = Duration.between(now, promise.endTime).seconds

// 트래킹 종료 시간까지 남은 시간(초)
// 현재 시간부터 트래킹 종료까지 남은시간 (= 현재시간 - 약속시간 + 30분)
val trackingEndTime = Duration.between(now, promise.endTime.plusMinutes(30)).seconds

promiseActiveAdapter.save(PromiseActiveRedisEntity("EXPIRE_EVENT_PROMISE_TIME_START_${promise.id}", promiseStartAndTrackingStartTime))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class PromiseTimeEndEventHandler(

// 앱 알람 허용한 유저
val appAlarmPermitUsers = users
.filter { user -> user.fcmNotification.fcmToken != null && user.fcmNotification.appAlarm }
.filter { user -> user.fcmNotification.fcmToken != "" && user.fcmNotification.appAlarm }

val lateData: MutableMap<String, String> = mutableMapOf()
lateData["notificationType"] = NotificationType.TIMEOVER.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class PromiseTimeStartEventHandler(

// 앱 알람 허용한 유저
val appAlarmPermitUsers = users
.filter { user -> user.fcmNotification.fcmToken != null && user.fcmNotification.appAlarm }
.filter { user -> user.fcmNotification.fcmToken != "" && user.fcmNotification.appAlarm }

val data: MutableMap<String, String> = mutableMapOf()
data["notificationType"] = NotificationType.START_SHARING.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class PromiseTrackingTimeEndEventHandler(

// 앱 알람 허용한 유저
val appAlarmPermitUsers = users
.filter { user -> user.fcmNotification.fcmToken != null && user.fcmNotification.appAlarm }
.filter { user -> user.fcmNotification.fcmToken != "" && user.fcmNotification.appAlarm }

val data: MutableMap<String, String> = mutableMapOf()
data["notificationType"] = NotificationType.END_SHARING.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@ package com.depromeet.whatnow.events.handler

import ch.hsr.geohash.GeoHash
import com.depromeet.whatnow.common.vo.CoordinateVo
import com.depromeet.whatnow.config.fcm.FcmService
import com.depromeet.whatnow.consts.RADIUS_CONVERT_METER
import com.depromeet.whatnow.domains.district.repository.DistrictRepository
import com.depromeet.whatnow.domains.notification.domain.NotificationType
import com.depromeet.whatnow.domains.notification.service.NotificationDomainService
import com.depromeet.whatnow.domains.promise.adaptor.PromiseAdaptor
import com.depromeet.whatnow.domains.promiseuser.adaptor.PromiseUserAdaptor
import com.depromeet.whatnow.domains.promiseuser.service.PromiseUserDomainService
import com.depromeet.whatnow.domains.user.adapter.UserAdapter
import com.depromeet.whatnow.events.domainEvent.PromiseUserUpdateLocationEvent
import com.mongodb.client.model.geojson.Point
import com.mongodb.client.model.geojson.Position
import org.springframework.scheduling.annotation.Async
import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Propagation
Expand All @@ -18,6 +25,10 @@ class PromiseUserUpdateLocationEventHandler(
val promiseAdaptor: PromiseAdaptor,
val promiseUserAdaptor: PromiseUserAdaptor,
val promiseUserDomainService: PromiseUserDomainService,
val userAdapter: UserAdapter,
val fcmService: FcmService,
val notificationDomainService: NotificationDomainService,
val districtRepository: DistrictRepository,
) {
// logger

Expand All @@ -26,14 +37,59 @@ class PromiseUserUpdateLocationEventHandler(
@TransactionalEventListener(classes = [PromiseUserUpdateLocationEvent::class], phase = TransactionPhase.AFTER_COMMIT)
fun handlerPromiseUserUpdateLocationEventHandler(promiseUserUpdateLocationEvent: PromiseUserUpdateLocationEvent) {
val promiseId = promiseUserUpdateLocationEvent.promiseId
val userId = promiseUserUpdateLocationEvent.userId
val promiseUserId = promiseUserUpdateLocationEvent.promiseUserId

val promise = promiseAdaptor.queryPromise(promiseId)
val promiseUser = promiseUserAdaptor.findByPromiseIdAndUserId(promiseUserUpdateLocationEvent.promiseId, promiseUserUpdateLocationEvent.userId)
val promiseUser = promiseUserAdaptor.findByPromiseIdAndUserId(promiseId, userId)
// if (promiseUserDomainService.isArrived(promiseUser, promise.meetPlace!!.coordinate)) {
if (isArrived(promiseUser.userLocation, promise.meetPlace!!.coordinate)) {
// 활성화된 약속이 종료되기 전일 때
if (promise.isBeforePromiseEndTime() && promise.isActive()) {
// 약속유저 상태 도착 상태(WAIT)로 변경
promiseUser.updatePromiseUserTypeToWait()

val promiseUsers = promiseUserAdaptor.findByPromiseId(promiseId)

// 약속에 참여한 유저들 조회 (자기 자신 제외)
val users = promiseUsers
.map { promiseUser -> userAdapter.queryUser(promiseUser.userId) }
.filter { user -> user.id != userId }

// 도착한 유저
val arrivalUser = userAdapter.queryUser(userId)

// 앱 알람 허용한 유저
val appAlarmPermitUsers = users
.filter { user -> user.fcmNotification.fcmToken != "" && user.fcmNotification.appAlarm }

val data: MutableMap<String, String> = mutableMapOf()
data["notificationType"] = NotificationType.ARRIVAL.name
data["promiseId"] = promiseId.toString()
data["senderUserId"] = promiseUserUpdateLocationEvent.userId.toString()

// 행정동 조회
val intersects = districtRepository.findByLocationIntersects(
Point(
Position(promise.meetPlace!!.coordinate.longitude, promise.meetPlace!!.coordinate.latitude),
),
)
val district = intersects.properties.adm_nm

// 앱 알람 허용한 유저에게 알람 보내기
if (appAlarmPermitUsers.isNotEmpty()) {
fcmService.sendGroupMessageAsync(
tokenList = appAlarmPermitUsers.map { user -> user.fcmNotification.fcmToken!! },
title = "${arrivalUser.nickname} 도착완료",
content = "\uD83C\uDFC1 $district",
data = data,
)
}

// notification 저장
users.forEach { user ->
notificationDomainService.saveForArrival(promiseId, arrivalUser.id!!, user.id!!)
}
}
// 활성화된 약속이 종료되고 나서 도착 시 사전에 LATE처리를 해서 별도의 처리가 필요 없음
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ package com.depromeet.whatnow.events.handler

import com.depromeet.whatnow.common.vo.CoordinateVo
import com.depromeet.whatnow.config.DomainIntegrateSpringBootTest
import com.depromeet.whatnow.config.fcm.FcmService
import com.depromeet.whatnow.domains.district.repository.DistrictRepository
import com.depromeet.whatnow.domains.notification.service.NotificationDomainService
import com.depromeet.whatnow.domains.promise.adaptor.PromiseAdaptor
import com.depromeet.whatnow.domains.promiseuser.adaptor.PromiseUserAdaptor
import com.depromeet.whatnow.domains.promiseuser.domain.PromiseUser
import com.depromeet.whatnow.domains.promiseuser.domain.PromiseUserType
import com.depromeet.whatnow.domains.promiseuser.service.PromiseUserDomainService
import com.depromeet.whatnow.domains.user.adapter.UserAdapter
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
Expand All @@ -24,12 +28,32 @@ class PromiseUserUpdateLocationEventHandlerTest {
@Mock
lateinit var promiseUserDomainService: PromiseUserDomainService

@Mock
lateinit var userAdapter: UserAdapter

@Mock
lateinit var fcmService: FcmService

@Mock
lateinit var notificationDomainService: NotificationDomainService

@Mock
lateinit var districtRepository: DistrictRepository

@Autowired
lateinit var promiseUserUpdateLocationEventHandler: PromiseUserUpdateLocationEventHandler

@BeforeEach
fun setUp() {
promiseUserUpdateLocationEventHandler = PromiseUserUpdateLocationEventHandler(promiseAdaptor, promiseUserAdaptor, promiseUserDomainService)
promiseUserUpdateLocationEventHandler = PromiseUserUpdateLocationEventHandler(
promiseAdaptor,
promiseUserAdaptor,
promiseUserDomainService,
userAdapter,
fcmService,
notificationDomainService,
districtRepository,
)
}

@Test
Expand Down

0 comments on commit 968cde9

Please sign in to comment.