Skip to content

Commit

Permalink
Merge pull request #64 from GSM-MSG/57-feat/withdraw-user
Browse files Browse the repository at this point in the history
# 57 회원 탈퇴 로직
  • Loading branch information
JuuuuHong authored Oct 24, 2023
2 parents 4abeab4 + b9d16e2 commit 8c73d80
Show file tree
Hide file tree
Showing 38 changed files with 259 additions and 69 deletions.
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,7 @@
package team.msg.domain.admin.exception.constant

enum class AdminErrorCode(
val status: Int
) {
ADMIN_NOT_FOUND(404)
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package team.msg.domain.auth.exception.constant

enum class AuthErrorCode(
val message: String,
val status: Int
) {
ALREADY_EXIST_EMAIL("이미 가입된 이메일입니다.", 409),
ALREADY_EXIST_PHONE_NUMBER("이미 가입된 전화번호입니다.", 409),
MISMATCH_PASSWORD("일치하지 않는 비밀번호입니다.", 401),
UNAPPROVED_USER("아직 회원가입 대기 상태입니다.", 403),
INVALID_TOKEN("유효하지 않은 토큰입니다.", 401),
REFRESH_TOKEN_NOT_FOUND("존재하지 않는 리프레시 토큰입니다.", 404)
ALREADY_EXIST_EMAIL(409),
ALREADY_EXIST_PHONE_NUMBER(409),
MISMATCH_PASSWORD(401),
UNAPPROVED_USER(403),
INVALID_TOKEN(401),
REFRESH_TOKEN_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,18 @@ class AuthServiceImpl(
refreshTokenRepository.delete(token)
}

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

applicationEventPublisher.publishEvent(WithdrawUserEvent(user))

userRepository.delete(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,7 @@
package team.msg.domain.bbozzak.exception.constant

enum class BbozzakErrorCode(
val status: Int
) {
BBOZZAK_NOT_FOUND(404)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package team.msg.domain.club.exception.constant

enum class ClubErrorCode(
val message: String,
val status: Int
) {
CLUB_NOT_FOUND("존재하지 않는 동아리입니다.", 404)
CLUB_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,7 @@
package team.msg.domain.company.exception.constant

enum class CompanyErrorCode(
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,7 @@
package team.msg.domain.government.exception.constant

enum class GovernmentErrorCode(
val status: Int
) {
GOVERNMENT_NOT_FOUND(404)
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package team.msg.domain.lecture.exception.constant

enum class LectureErrorCode(
val message: String,
val status: Int
){
INVALID_LECTURE_TYPE("유효하지 않은 강의 구분입니다.", 400),

LECTURE_NOT_FOUND("존재하지 않는 강의입니다.", 404),

ALREADY_APPROVED_LECTURE("이미 개설 신청이 승인된 강의입니다.",409)
INVALID_LECTURE_TYPE(400),
LECTURE_NOT_FOUND(404),
ALREADY_APPROVED_LECTURE(409)
}
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,7 @@
package team.msg.domain.professor.exception.constant

enum class ProfessorErrorCode(
val status: Int
) {
PROFESSOR_NOT_FOUND(404)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package team.msg.domain.school.exception.constant

enum class SchoolErrorCode(
val message: String,
val status: Int
) {
SCHOOL_NOT_FOUND("이미 가입된 정보입니다.", 403)
SCHOOL_NOT_FOUND(403)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package team.msg.domain.student.exception.constant

enum class StudentActivityErrorCode(
val message: String,
val status: Int
) {
STUDENT_ACTIVITY_NOT_FOUND("학생 활동을 찾을 수 없습니다", 404)
STUDENT_ACTIVITY_NOT_FOUND(404)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package team.msg.domain.student.exception.constant

enum class StudentErrorCode(
val message: String,
val status: Int
) {
STUDENT_NOT_FOUND("학생을 찾을 수 없습니다.", 404)
STUDENT_NOT_FOUND(404)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@ import team.msg.global.error.exception.BitgouelException

class TeacherNotFoundException(
message: String
) : BitgouelException(message, TeacherErrorCode.TEACHER_NOT_FOUND.status) {
}
) : BitgouelException(message, TeacherErrorCode.TEACHER_NOT_FOUND.status)
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package team.msg.domain.teacher.exception.constant

enum class TeacherErrorCode(
val message: String,
val status: Int
) {
TEACHER_NOT_FOUND("취업 동아리 선생님을 찾을 수 없습니다.", 404)
TEACHER_NOT_FOUND(404)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package team.msg.domain.user.exception.constant

enum class UserErrorCode(
val message: String,
val status: Int
) {
USER_NOT_FOUND("존재하지 않는 유저입니다.", 404)
USER_NOT_FOUND(404)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
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} ]")

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} ]")
}
}
}
Loading

0 comments on commit 8c73d80

Please sign in to comment.