Skip to content

Commit

Permalink
[Feature/367] 매칭 활성/비활성화 API를 구현한다 (#373)
Browse files Browse the repository at this point in the history
* feat: 매칭 활성/비활성화 기능 구현

* feat: 내 프로필 조회 시 매칭 활성화 여부 내려주기

* feat: 매칭 활성화된 유저에게만 매칭 푸시 알림 보내기

* feat: 자기소개 등록 실패시 이벤트 발행되지 않도록 TransactionalEventListener 로 변경
  • Loading branch information
miseongk authored Sep 13, 2024
1 parent a809863 commit 381273f
Show file tree
Hide file tree
Showing 11 changed files with 47 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ package com.nexters.bottles.api.user.controller
import com.nexters.bottles.api.global.interceptor.AuthRequired
import com.nexters.bottles.api.global.resolver.AuthUserId
import com.nexters.bottles.api.user.facade.UserProfileFacade
import com.nexters.bottles.api.user.facade.dto.*
import com.nexters.bottles.api.user.facade.dto.ActivateMatchingRequest
import com.nexters.bottles.api.user.facade.dto.ExistIntroductionResponse
import com.nexters.bottles.api.user.facade.dto.ProfileChoiceResponse
import com.nexters.bottles.api.user.facade.dto.RegisterIntroductionRequest
import com.nexters.bottles.api.user.facade.dto.RegisterProfileRequest
import com.nexters.bottles.api.user.facade.dto.UserInfoResponse
import com.nexters.bottles.api.user.facade.dto.UserProfileResponse
import com.nexters.bottles.api.user.facade.dto.UserProfileStatusResponse
import io.swagger.annotations.ApiOperation
import mu.KotlinLogging
import org.springframework.web.bind.annotation.GetMapping
Expand All @@ -19,7 +26,7 @@ import org.springframework.web.multipart.MultipartFile
class UserProfileController(
private val profileFacade: UserProfileFacade,
) {

private val log = KotlinLogging.logger {}

@ApiOperation("온보딩 프로필 등록하기")
Expand Down Expand Up @@ -81,4 +88,11 @@ class UserProfileController(
fun findStatus(@AuthUserId userId: Long): UserProfileStatusResponse {
return profileFacade.findUserProfileStatus(userId)
}

@ApiOperation("매칭 활성/비활성화")
@PostMapping("/activate/matching")
@AuthRequired
fun activateAccount(@AuthUserId userId: Long, @RequestBody activateMatchingRequest: ActivateMatchingRequest) {
profileFacade.activateMatching(userId, activateMatchingRequest)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ class UserFacade(
private val alimyService: UserAlimyService,
) {


fun reportUser(userId: Long, reportUserRequest: ReportUserRequest) {
userReportService.saveReport(
UserReport(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.nexters.bottles.api.user.facade

import com.nexters.bottles.api.user.facade.dto.ActivateMatchingRequest
import com.nexters.bottles.api.user.facade.dto.ExistIntroductionResponse
import com.nexters.bottles.api.user.facade.dto.ProfileChoiceResponse
import com.nexters.bottles.api.user.facade.dto.RegisterIntroductionRequest
Expand Down Expand Up @@ -72,15 +73,15 @@ class UserProfileFacade(
}

fun getMyProfile(userId: Long): UserProfileResponse {

val userProfile = profileService.findUserProfile(userId)
val user = userProfile?.user ?: userService.findByIdAndNotDeleted(userId)
return UserProfileResponse(
userName = user.name,
age = user.getKoreanAge(),
imageUrl = userProfile?.imageUrl,
introduction = userProfile?.introduction ?: emptyList(),
profileSelect = userProfile?.profileSelect
profileSelect = userProfile?.profileSelect,
isMatchActivated = user.isMatchActivated
)
}

Expand Down Expand Up @@ -173,6 +174,10 @@ class UserProfileFacade(
}
}

fun activateMatching(userId: Long, activateMatchingRequest: ActivateMatchingRequest) {
userService.activateMatching(userId, activateMatchingRequest.activate)
}

companion object {
private const val FILE_NAME_DELIMITER = "_"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.nexters.bottles.api.user.facade.dto

data class ActivateMatchingRequest(
val activate: Boolean
) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ data class UserProfileResponse(
val imageUrl: String? = null,
val introduction: List<QuestionAndAnswer>,
val profileSelect: UserProfileSelect? = null,
val isMatchActivated: Boolean? = true
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class FcmNotificationScheduler(

@Scheduled(cron = "0 0 18 * * *")
fun notifyMatching() {
val userIds = userService.findAllByNotDeleted().map { it.id }
val userIds = userService.findAllByDeletedFalseAndMatchActivatedTrue().map { it.id }
val fcmTokens = fcmTokenService.findAllByUserIdsAndTokenNotBlank(userIds)
val tokens = fcmTokens.map { it.token }

Expand All @@ -25,4 +25,6 @@ class FcmNotificationScheduler(
)
fcmClient.sendNotificationAll(userTokens = tokens, fcmNotification = fcmNotification)
}

// TODO 매칭 비활성화 된 유저에게 푸시 알림 보내기
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import com.nexters.bottles.app.bottle.service.BottleHistoryService
import com.nexters.bottles.app.bottle.service.BottleService
import com.nexters.bottles.app.user.component.event.dto.IntroductionSaveEventDto
import com.nexters.bottles.app.user.service.UserService
import org.springframework.context.event.EventListener
import org.springframework.scheduling.annotation.Async
import org.springframework.stereotype.Component
import org.springframework.transaction.event.TransactionalEventListener

@Component
class UserProfileApplicationEventListener(
Expand All @@ -16,7 +16,7 @@ class UserProfileApplicationEventListener(
) {

@Async
@EventListener
@TransactionalEventListener
fun handleCustomEvent(event: IntroductionSaveEventDto) {
val user = userService.findByIdAndNotDeleted(event.userId)
bottleService.matchFirstRandomBottle(user)?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface UserRepository : JpaRepository<User, Long> {

fun findByIdAndDeletedFalse(id: Long): User?

fun findAllByDeletedFalse(): List<User>
fun findAllByDeletedFalseAndIsMatchActivatedTrue(): List<User>

fun findByPhoneNumber(phoneNumber: String): User?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ class UserProfileService(
profileRepository.findByUserId(user.id)?.let {
val isFirstRegisterIntroduction = it.introduction.isEmpty()
it.introduction = introduction
// TODO introduction 저장 실패시 이벤트 처리 수정
if (isFirstRegisterIntroduction) {
applicationEventPublisher.publishEvent(
IntroductionSaveEventDto(userId = userId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ class UserService(
}

@Transactional(readOnly = true)
fun findAllByNotDeleted(): List<User> {
return userRepository.findAllByDeletedFalse()
fun findAllByDeletedFalseAndMatchActivatedTrue(): List<User> {
return userRepository.findAllByDeletedFalseAndIsMatchActivatedTrue()
}

@Transactional
Expand Down Expand Up @@ -159,4 +159,11 @@ class UserService(
it.deletedAt = null
}
}

@Transactional
fun activateMatching(userId: Long, activate: Boolean) {
userRepository.findByIdAndDeletedFalse(userId)?.let { user ->
user.isMatchActivated = activate
} ?: throw IllegalStateException("회원가입 상태를 문의해주세요")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class FcmNotificationScheduler(

@Scheduled(cron = "0 0 18 * * *")
fun notifyMatching() {
val userIds = userService.findAllByNotDeleted().map { it.id }
val userIds = userService.findAllByDeletedFalseAndMatchActivatedTrue().map { it.id }
val fcmTokens = fcmTokenService.findAllByUserIdsAndTokenNotBlank(userIds)
val tokens = fcmTokens.map { it.token }

Expand Down

0 comments on commit 381273f

Please sign in to comment.