From 6b274b9529c7a12b6b8f9a8c7e3196a42ef3ef25 Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 5 Mar 2026 15:38:26 +0900 Subject: [PATCH] =?UTF-8?q?feat(admin-member):=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=EC=9E=90=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=B0=A8=EB=8B=A8=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EC=B6=94=EA=B0=80=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/AdminMemberBlockController.kt | 19 +++++ .../admin/member/AdminMemberBlockRequest.kt | 6 ++ .../admin/member/AdminMemberBlockService.kt | 73 +++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/member/AdminMemberBlockController.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/member/AdminMemberBlockRequest.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/member/AdminMemberBlockService.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/member/AdminMemberBlockController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/member/AdminMemberBlockController.kt new file mode 100644 index 00000000..da8a0553 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/member/AdminMemberBlockController.kt @@ -0,0 +1,19 @@ +package kr.co.vividnext.sodalive.admin.member + +import kr.co.vividnext.sodalive.common.ApiResponse +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/admin/member/block") +@PreAuthorize("hasRole('ADMIN')") +class AdminMemberBlockController(private val service: AdminMemberBlockService) { + @PostMapping + fun blockMember(@RequestBody request: AdminMemberBlockRequest) = ApiResponse.ok( + service.blockMember(request), + "차단되었습니다." + ) +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/member/AdminMemberBlockRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/member/AdminMemberBlockRequest.kt new file mode 100644 index 00000000..d3adfe95 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/member/AdminMemberBlockRequest.kt @@ -0,0 +1,6 @@ +package kr.co.vividnext.sodalive.admin.member + +data class AdminMemberBlockRequest( + val memberId: Long, + val reason: String +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/member/AdminMemberBlockService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/member/AdminMemberBlockService.kt new file mode 100644 index 00000000..42d6c1b6 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/member/AdminMemberBlockService.kt @@ -0,0 +1,73 @@ +package kr.co.vividnext.sodalive.admin.member + +import kr.co.vividnext.sodalive.common.SodaException +import kr.co.vividnext.sodalive.member.MemberService +import kr.co.vividnext.sodalive.member.SignOut +import kr.co.vividnext.sodalive.member.SignOutRepository +import kr.co.vividnext.sodalive.member.auth.AuthRepository +import kr.co.vividnext.sodalive.member.auth.BlockAuth +import kr.co.vividnext.sodalive.member.auth.BlockAuthRepository +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class AdminMemberBlockService( + private val adminMemberRepository: AdminMemberRepository, + private val signOutRepository: SignOutRepository, + private val memberService: MemberService, + private val authRepository: AuthRepository, + private val blockAuthRepository: BlockAuthRepository +) { + @Transactional + fun blockMember(request: AdminMemberBlockRequest) { + if (request.reason.isBlank()) { + throw SodaException(messageKey = "member.validation.signout_reason_required") + } + + val member = adminMemberRepository.findByIdAndActive(memberId = request.memberId) + ?: throw SodaException(messageKey = "admin.member.not_found") + + val auth = member.auth + val memberIdsToBlock = if (auth != null) { + authRepository.getActiveMemberIdsByNameAndBirthAndDiAndUniqueCi( + name = auth.name, + birth = auth.birth, + di = auth.di, + uniqueCi = auth.uniqueCi + ) + .ifEmpty { listOf(member.id!!) } + } else { + listOf(member.id!!) + } + + memberIdsToBlock + .distinct() + .forEach { memberId -> + val targetMember = adminMemberRepository.findByIdAndActive(memberId = memberId) + ?: return@forEach + + targetMember.isActive = false + targetMember.nickname = "deleted_${targetMember.nickname}" + + val signOut = SignOut(reason = request.reason) + signOut.member = targetMember + signOutRepository.save(signOut) + + memberService.logoutAll(memberId = targetMember.id!!) + } + + if (auth == null) return + val alreadyBlockedAuthId = blockAuthRepository.findByUniqueCiAndDi(auth.uniqueCi, auth.di) + if (alreadyBlockedAuthId == null || alreadyBlockedAuthId <= 0) { + blockAuthRepository.save( + BlockAuth( + name = auth.name, + birth = auth.birth, + uniqueCi = auth.uniqueCi, + di = auth.di, + gender = auth.gender + ) + ) + } + } +}