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

# 57 회원 탈퇴 로직 #64

Merged
merged 12 commits into from
Oct 24, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package team.msg.domain.admin.exception

import team.msg.domain.admin.exception.constant.AdminErrorCode
import team.msg.global.error.exception.BitgouelException

class AdminNotFoundException(
message: String
) : BitgouelException(message, AdminErrorCode.ADMIN_NOT_FOUND.status)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package team.msg.domain.admin.exception.constant

enum class AdminErrorCode(
val message: String,
val status: Int
) {
ADMIN_NOT_FOUND("존재하지 않는 어드민 입니다.", 404)
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,10 @@ class AuthController(
authService.logout(refreshToken)
return ResponseEntity.status(HttpStatus.NO_CONTENT).build()
}

@DeleteMapping("/withdraw")
fun withdraw(): ResponseEntity<Void> {
authService.withdraw()
return ResponseEntity.status(HttpStatus.NO_CONTENT).build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ interface AuthService {
fun login(request: LoginRequest): TokenResponse
fun reissueToken(refreshToken: String): TokenResponse
fun logout(refreshToken: String)
fun withdraw()
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package team.msg.domain.auth.service

import org.springframework.context.ApplicationEventPublisher
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import team.msg.common.enum.ApproveStatus
import team.msg.common.util.SecurityUtil
import team.msg.common.util.UserUtil
import team.msg.domain.auth.exception.AlreadyExistEmailException
import team.msg.domain.auth.exception.AlreadyExistPhoneNumberException
import team.msg.domain.auth.exception.InvalidRefreshTokenException
import team.msg.domain.auth.exception.MisMatchPasswordException
import team.msg.domain.auth.exception.RefreshTokenNotFoundException
import team.msg.domain.auth.exception.UnApprovedUserException
import team.msg.domain.auth.exception.*
import team.msg.domain.auth.presentation.data.request.*
import team.msg.domain.auth.presentation.data.response.TokenResponse
import team.msg.domain.auth.repository.RefreshTokenRepository
Expand All @@ -33,6 +29,7 @@ import team.msg.domain.student.repository.StudentRepository
import team.msg.domain.teacher.model.Teacher
import team.msg.domain.teacher.repository.TeacherRepository
import team.msg.domain.user.enums.Authority
import team.msg.domain.user.event.WithdrawUserEvent
import team.msg.domain.user.exception.UserNotFoundException
import team.msg.domain.user.model.User
import team.msg.domain.user.repository.UserRepository
Expand All @@ -54,7 +51,8 @@ class AuthServiceImpl(
private val jwtTokenGenerator: JwtTokenGenerator,
private val jwtTokenParser: JwtTokenParser,
private val refreshTokenRepository: RefreshTokenRepository,
private val userUtil: UserUtil
private val userUtil: UserUtil,
private val applicationEventPublisher: ApplicationEventPublisher
) : AuthService {

/**
Expand Down Expand Up @@ -213,6 +211,7 @@ class AuthServiceImpl(
val user = userRepository.findByIdOrNull(token.userId)
?: throw UserNotFoundException("존재하지 않는 유저입니다. info : [ userId = ${token.userId} ]")

refreshTokenRepository.deleteById(refreshToken)
return jwtTokenGenerator.generateToken(user.id, user.authority)
}

Expand All @@ -236,6 +235,16 @@ class AuthServiceImpl(
refreshTokenRepository.delete(token)
}

/**
* 회원탈퇴를 처리하는 메서드입니다.
*/
@Transactional(rollbackFor = [Exception::class])
override fun withdraw() {
val user = userUtil.queryCurrentUser()

applicationEventPublisher.publishEvent(WithdrawUserEvent(user))
}

/**
* 유저 생성과 검증을 처리하는 private 메서드입니다.
* @param 유저 생성 및 검증하기 위한 email, name, phoneNumber, password, authority 입니다.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package team.msg.domain.bbozzak.exception

import team.msg.domain.bbozzak.exception.constant.BbozzakErrorCode
import team.msg.global.error.exception.BitgouelException

class BbozzakNotFoundException(
message: String
) : BitgouelException(message, BbozzakErrorCode.BBOZZAK_NOT_FOUND.status)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package team.msg.domain.bbozzak.exception.constant

enum class BbozzakErrorCode(
val message: String,
val status: Int
) {
BBOZZAK_NOT_FOUND("존재하지 않는 뽀짝샘입니다.", 404)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package team.msg.domain.company.exception

import team.msg.domain.company.exception.constant.CompanyErrorCode
import team.msg.global.error.exception.BitgouelException

class CompanyNotFoundException(
message: String
) : BitgouelException(message, CompanyErrorCode.COMPANY_NOT_FOUND.status)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package team.msg.domain.company.exception.constant

enum class CompanyErrorCode(
val message: String,
val status: Int
) {
COMPANY_NOT_FOUND("존재하지 않는 기업 강사 입니다.", 404)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package team.msg.domain.government

import team.msg.domain.government.exception.constant.GovernmentErrorCode
import team.msg.global.error.exception.BitgouelException

class GovernmentNotFoundException(
message: String
) : BitgouelException(message, GovernmentErrorCode.GOVERNMENT_NOT_FOUND.status)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package team.msg.domain.government.exception.constant

enum class GovernmentErrorCode(
val message: String,
val status: Int
) {
GOVERNMENT_NOT_FOUND("존재하지 않는 유관 기관 입니다.", 404)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package team.msg.domain.professor.exception

import team.msg.domain.professor.exception.constant.ProfessorErrorCode
import team.msg.global.error.exception.BitgouelException

class ProfessorNotFoundException(
message: String
) : BitgouelException(message, ProfessorErrorCode.PROFESSOR_NOT_FOUND.status)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package team.msg.domain.professor.exception.constant

enum class ProfessorErrorCode(
val message: String,
val status: Int
) {
PROFESSOR_NOT_FOUND("존재하지 않는 대학 교수입니다.", 404)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package team.msg.domain.user.handler

import org.springframework.stereotype.Component
import org.springframework.transaction.event.TransactionPhase
import org.springframework.transaction.event.TransactionalEventListener
import team.msg.domain.admin.exception.AdminNotFoundException
import team.msg.domain.admin.repository.AdminRepository
import team.msg.domain.auth.exception.UnApprovedUserException
import team.msg.domain.bbozzak.exception.BbozzakNotFoundException
import team.msg.domain.bbozzak.repository.BbozzakRepository
import team.msg.domain.company.exception.CompanyNotFoundException
import team.msg.domain.company.repository.CompanyInstructorRepository
import team.msg.domain.government.GovernmentNotFoundException
import team.msg.domain.government.repository.GovernmentRepository
import team.msg.domain.lecture.repository.RegisteredLectureRepository
import team.msg.domain.professor.exception.ProfessorNotFoundException
import team.msg.domain.professor.repository.ProfessorRepository
import team.msg.domain.student.exception.StudentNotFoundException
import team.msg.domain.student.repository.StudentActivityRepository
import team.msg.domain.student.repository.StudentRepository
import team.msg.domain.teacher.exception.TeacherNotFoundException
import team.msg.domain.teacher.repository.TeacherRepository
import team.msg.domain.user.enums.Authority.*
import team.msg.domain.user.event.WithdrawUserEvent
import team.msg.domain.user.repository.UserRepository

@Component
class UserEventHandler(
private val userRepository: UserRepository,
private val studentRepository: StudentRepository,
private val studentActivityRepository: StudentActivityRepository,
private val bbozzakRepository: BbozzakRepository,
private val teacherRepository: TeacherRepository,
private val professorRepository: ProfessorRepository,
private val companyInstructorRepository: CompanyInstructorRepository,
private val governmentRepository: GovernmentRepository,
private val registeredLectureRepository: RegisteredLectureRepository,
private val adminRepository: AdminRepository
) {

/**
* User 의 delete 이벤트가 발행되면 User 를 삭제하는 핸들입니다.
* @param user delete 이벤트
*/
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
fun withdrawUserHandler(event: WithdrawUserEvent) {
val user = event.user

when (user.authority) {
ROLE_STUDENT -> {
val student = studentRepository.findByUser(user)
?: throw StudentNotFoundException("존재하지 않는 학생 입니다. info : [ userId = ${user.id} ]")
val studentActivity = studentActivityRepository.findAllByStudent(student)
val registeredLecture = registeredLectureRepository.findAllByStudent(student)

studentActivityRepository.deleteAll(studentActivity)
registeredLectureRepository.deleteAll(registeredLecture)
studentRepository.delete(student)
}
ROLE_ADMIN -> {
val admin = adminRepository.findByUser(user)
?: throw AdminNotFoundException("존재하지 않는 어드민 입니다. info : [ userId = ${user.id} ]")

adminRepository.delete(admin)
}
ROLE_BBOZZAK -> {
val bbozzak = bbozzakRepository.findByUser(user)
?: throw BbozzakNotFoundException("존재하지 않는 뽀짝샘 입니다. info : [ userId = ${user.id} ]")

bbozzakRepository.delete(bbozzak)
}
ROLE_TEACHER -> {
val teacher = teacherRepository.findByUser(user)
?: throw TeacherNotFoundException("존재하지 않는 선생님 입니다. info : [ userId = ${user.id} ]")
ani2689 marked this conversation as resolved.
Show resolved Hide resolved

teacherRepository.delete(teacher)
}
ROLE_PROFESSOR -> {
val professor = professorRepository.findByUser(user)
?: throw ProfessorNotFoundException("존재하지 않는 대학 교수 입니다. info : [ userId = ${user.id} ]")

professorRepository.delete(professor)
}
ROLE_COMPANY_INSTRUCTOR -> {
val companyInstructor = companyInstructorRepository.findByUser(user)
?: throw CompanyNotFoundException("존재하지 않는 기업 강사 입니다. info : [ userId = ${user.id} ]")

companyInstructorRepository.delete(companyInstructor)
}
ROLE_GOVERNMENT -> {
val government = governmentRepository.findByUser(user)
?: throw GovernmentNotFoundException("존재하지 않는 유관 기관 입니다. info : [ userId = ${user.id} ]")

governmentRepository.delete(government)
}

else -> throw UnApprovedUserException("회원가입 승인 대기 중인 유저입니다. info : [ userId = ${user.id} ]")
}

userRepository.delete(user)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

user delete는 서비스에 놔두는게 나을 것 같아요

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8ea9ecf 변경했습니다.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class SecurityConfig(
.mvcMatchers(HttpMethod.POST, "/auth/login").permitAll()
.mvcMatchers(HttpMethod.PATCH, "/auth").permitAll()
.mvcMatchers(HttpMethod.DELETE, "/auth").authenticated()
.mvcMatchers(HttpMethod.DELETE, "/auth/withdraw").authenticated()

// activity
.mvcMatchers(HttpMethod.POST, "/activity").hasRole(STUDENT)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package team.msg.common.entity

import javax.persistence.Column
import javax.persistence.GeneratedValue
import javax.persistence.Id
import javax.persistence.MappedSuperclass
import javax.persistence.PostLoad
import javax.persistence.PostPersist
import org.hibernate.annotations.GenericGenerator
import org.hibernate.proxy.HibernateProxy
import org.springframework.data.domain.Persistable
import team.msg.common.ulid.ULIDGenerator
import java.io.Serializable
import java.util.*
import javax.persistence.Column
import javax.persistence.GeneratedValue
import javax.persistence.Id
import javax.persistence.MappedSuperclass

@MappedSuperclass
abstract class BaseUUIDEntity(
Expand All @@ -24,7 +20,6 @@ abstract class BaseUUIDEntity(
open var id: UUID = UUID(0, 0)
) : BaseTimeEntity(), Persistable<UUID> {


@Column(name = "ulid", updatable = false, unique = true)
var ulid: String? = ULIDGenerator.generateULID()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package team.msg.domain.admin.repository

import org.springframework.data.repository.CrudRepository
import team.msg.domain.admin.model.Admin
import team.msg.domain.user.model.User
import java.util.UUID

interface AdminRepository : CrudRepository<Admin, UUID>
interface AdminRepository : CrudRepository<Admin,UUID> {
fun findByUser(user: User): Admin?
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package team.msg.domain.bbozzak.repository

import org.springframework.data.repository.CrudRepository
import team.msg.domain.bbozzak.model.Bbozzak
import team.msg.domain.user.model.User
import java.util.UUID

interface BbozzakRepository : CrudRepository<Bbozzak, UUID>
interface BbozzakRepository : CrudRepository<Bbozzak,UUID> {
fun findByUser(user: User): Bbozzak?
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,4 @@ class CompanyInstructor(
@Column(columnDefinition = "VARCHAR(20)", nullable = false)
val company: String

) : BaseUUIDEntity(id) {

}
) : BaseUUIDEntity(id)
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package team.msg.domain.company.repository

import org.springframework.data.repository.CrudRepository
import team.msg.domain.company.model.CompanyInstructor
import team.msg.domain.user.model.User
import java.util.UUID

interface CompanyInstructorRepository : CrudRepository<CompanyInstructor, UUID> {
fun findByUser(user: User): CompanyInstructor?
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package team.msg.domain.government.repository

import org.springframework.data.repository.CrudRepository
import team.msg.domain.government.model.Government
import team.msg.domain.user.model.User
import java.util.UUID

interface GovernmentRepository : CrudRepository<Government, UUID> {

fun findByUser(user: User): Government?
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package team.msg.domain.lecture.repository

import org.springframework.data.repository.CrudRepository
import team.msg.domain.lecture.model.RegisteredLecture
import team.msg.domain.student.model.Student
import java.util.UUID

interface RegisteredLectureRepository : CrudRepository<RegisteredLecture, UUID>
interface RegisteredLectureRepository : CrudRepository<RegisteredLecture,UUID> {
fun findAllByStudent(student: Student): List<RegisteredLecture>
}
Loading