From cef8d33bf020d4f68d7bde8cf573babf655cf400 Mon Sep 17 00:00:00 2001 From: Haebin Date: Wed, 20 Mar 2024 05:48:51 +0900 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20VacgomId=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/auth/constants/Role.kt | 12 --------- .../vacgom/backend/domain/member/Member.kt | 14 ++++++++++ .../vacgom/backend/domain/member/VacgomId.kt | 27 +++++++++++++++++++ .../backend/domain/member/constants/Sex.kt | 6 +++++ .../backend/exception/member/MemberError.kt | 2 +- .../backend/exception/member/VacgomIdError.kt | 15 +++++++++++ 6 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt create mode 100644 src/main/kotlin/com/vacgom/backend/domain/member/constants/Sex.kt create mode 100644 src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt diff --git a/src/main/kotlin/com/vacgom/backend/domain/auth/constants/Role.kt b/src/main/kotlin/com/vacgom/backend/domain/auth/constants/Role.kt index 47cd7a0..412b84e 100644 --- a/src/main/kotlin/com/vacgom/backend/domain/auth/constants/Role.kt +++ b/src/main/kotlin/com/vacgom/backend/domain/auth/constants/Role.kt @@ -4,16 +4,4 @@ enum class Role { ROLE_GUEST, ROLE_TEMP_USER, ROLE_USER; - - fun isGuest(role: Role): Boolean { - return role == ROLE_GUEST - } - - fun isTempUser(role: Role): Boolean { - return role == ROLE_TEMP_USER - } - - fun isUser(role: Role): Boolean { - return role == ROLE_USER - } } diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt b/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt index 686f3ed..06e4611 100644 --- a/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt +++ b/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt @@ -2,9 +2,11 @@ package com.vacgom.backend.domain.member import com.vacgom.backend.domain.auth.constants.Role import com.vacgom.backend.domain.auth.oauth.constants.ProviderType +import com.vacgom.backend.domain.member.constants.Sex import com.vacgom.backend.global.auditing.BaseEntity import jakarta.persistence.* import org.hibernate.annotations.GenericGenerator +import java.time.LocalDate import java.util.* @Entity @@ -22,4 +24,16 @@ class Member( val id: UUID? = null var name: String? = null + private set + + var birthday: LocalDate? = null + private set + + @Enumerated(EnumType.STRING) + var sex: Sex? = null + private set + + @Embedded + var vacgomId: VacgomId? = null + private set } diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt b/src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt new file mode 100644 index 0000000..48a6fb8 --- /dev/null +++ b/src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt @@ -0,0 +1,27 @@ +package com.vacgom.backend.domain.member + +import com.vacgom.backend.exception.member.VacgomIdError +import com.vacgom.backend.global.exception.error.BusinessException +import jakarta.persistence.Embeddable + +@Embeddable +class VacgomId( + var vacgomId: String +) { + init { + validatePattern(vacgomId) + validateConsecutiveUnderscores(vacgomId) + } + + private fun validatePattern(id: String) { + require(id.matches("[a-z0-9_]+".toRegex())) { + throw BusinessException(VacgomIdError.INVALID_VACGOM_ID_PATTERN) + } + } + + private fun validateConsecutiveUnderscores(id: String) { + require(id.matches("[a-z0-9_]+".toRegex())) { + throw BusinessException(VacgomIdError.CONSECUTIVE_UNDERSCORES) + } + } +} diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/constants/Sex.kt b/src/main/kotlin/com/vacgom/backend/domain/member/constants/Sex.kt new file mode 100644 index 0000000..d61ebf3 --- /dev/null +++ b/src/main/kotlin/com/vacgom/backend/domain/member/constants/Sex.kt @@ -0,0 +1,6 @@ +package com.vacgom.backend.domain.member.constants + +enum class Sex { + MALE, + FEMALE +} diff --git a/src/main/kotlin/com/vacgom/backend/exception/member/MemberError.kt b/src/main/kotlin/com/vacgom/backend/exception/member/MemberError.kt index 04bab5e..1f8dcd1 100644 --- a/src/main/kotlin/com/vacgom/backend/exception/member/MemberError.kt +++ b/src/main/kotlin/com/vacgom/backend/exception/member/MemberError.kt @@ -9,5 +9,5 @@ enum class MemberError( override val status: HttpStatus, override val code: String ) : ErrorCode { - NOT_FOUND("사용자를 찾을 수 없습니다.", HttpStatus.NOT_FOUND, "M_001"), + NOT_FOUND("사용자를 찾을 수 없습니다.", HttpStatus.NOT_FOUND, "M_001") } diff --git a/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt b/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt new file mode 100644 index 0000000..11eee78 --- /dev/null +++ b/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt @@ -0,0 +1,15 @@ +package com.vacgom.backend.exception.member + +import com.vacgom.backend.global.exception.error.ErrorCode +import org.springframework.http.HttpStatus + + +internal enum class VacgomIdError( + override val message: String, + override val status: HttpStatus, + override val code: String +) : ErrorCode { + INVALID_VACGOM_ID_PATTERN("백곰 아이디는 영문 소문자와 숫자, 언더바(_)로 구성되어야 합니다.", HttpStatus.BAD_REQUEST, "VI_001"), + CONSECUTIVE_UNDERSCORES("언더바(_)는 최대 3개 까지 연속으로 사용할 수 있습니다.", HttpStatus.BAD_REQUEST, "VI_002"); +} + From 02fbf9f74b285ec3ee6ec2683788a9e93874b74b Mon Sep 17 00:00:00 2001 From: Haebin Date: Wed, 20 Mar 2024 06:47:32 +0900 Subject: [PATCH 2/9] feat: vacgomId validation checker API --- .../auth/dto/ResourceIdResponse.kt | 2 +- .../application/member/MemberService.kt | 18 ++++++++++++++++ .../vacgom/backend/domain/member/VacgomId.kt | 21 ++++++++++++------- .../backend/exception/member/VacgomIdError.kt | 4 +++- .../security/matcher/CustomRequestMatcher.kt | 5 +++-- .../member/persistence/MemberRepository.kt | 3 +++ .../presentation/member/MemberController.kt | 20 ++++++++++++++++++ 7 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt create mode 100644 src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt diff --git a/src/main/kotlin/com/vacgom/backend/application/auth/dto/ResourceIdResponse.kt b/src/main/kotlin/com/vacgom/backend/application/auth/dto/ResourceIdResponse.kt index dd023ee..cf7d3e2 100644 --- a/src/main/kotlin/com/vacgom/backend/application/auth/dto/ResourceIdResponse.kt +++ b/src/main/kotlin/com/vacgom/backend/application/auth/dto/ResourceIdResponse.kt @@ -1,5 +1,5 @@ package com.vacgom.backend.application.auth.dto data class ResourceIdResponse( - var id: Long + val id: Long ) diff --git a/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt b/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt new file mode 100644 index 0000000..0f8a761 --- /dev/null +++ b/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt @@ -0,0 +1,18 @@ +package com.vacgom.backend.application.member + +import com.vacgom.backend.domain.member.VacgomId +import com.vacgom.backend.exception.member.VacgomIdError +import com.vacgom.backend.global.exception.error.BusinessException +import com.vacgom.backend.infrastructure.member.persistence.MemberRepository +import org.springframework.stereotype.Service + +@Service +class MemberService( + private val memberRepository: MemberRepository +) { + fun validateVacgomId(id: String) { + val vacgomId = VacgomId(id) + if (memberRepository.existsMemberByVacgomId(vacgomId)) + throw BusinessException(VacgomIdError.DUPLICATED) + } +} diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt b/src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt index 48a6fb8..1e26618 100644 --- a/src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt +++ b/src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt @@ -2,26 +2,33 @@ package com.vacgom.backend.domain.member import com.vacgom.backend.exception.member.VacgomIdError import com.vacgom.backend.global.exception.error.BusinessException +import jakarta.persistence.Column import jakarta.persistence.Embeddable @Embeddable class VacgomId( - var vacgomId: String + @Column(unique = true) var vacgomId: String ) { + companion object { + private const val VACGOM_ID_REGEX = "[a-z0-9_]+" + private const val CONSECUTIVE_UNDERSCORES = "____" + private const val MINIMUM_LENGTH = 1 + private const val MAXIMUM_LENGTH = 20 + } + init { validatePattern(vacgomId) - validateConsecutiveUnderscores(vacgomId) } private fun validatePattern(id: String) { - require(id.matches("[a-z0-9_]+".toRegex())) { + require(id.matches(VACGOM_ID_REGEX.toRegex())) { throw BusinessException(VacgomIdError.INVALID_VACGOM_ID_PATTERN) } - } - - private fun validateConsecutiveUnderscores(id: String) { - require(id.matches("[a-z0-9_]+".toRegex())) { + require(CONSECUTIVE_UNDERSCORES !in id) { throw BusinessException(VacgomIdError.CONSECUTIVE_UNDERSCORES) } + require(id.length in MINIMUM_LENGTH..MAXIMUM_LENGTH) { + throw BusinessException(VacgomIdError.INVALID_LENGTH) + } } } diff --git a/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt b/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt index 11eee78..069a41c 100644 --- a/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt +++ b/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt @@ -10,6 +10,8 @@ internal enum class VacgomIdError( override val code: String ) : ErrorCode { INVALID_VACGOM_ID_PATTERN("백곰 아이디는 영문 소문자와 숫자, 언더바(_)로 구성되어야 합니다.", HttpStatus.BAD_REQUEST, "VI_001"), - CONSECUTIVE_UNDERSCORES("언더바(_)는 최대 3개 까지 연속으로 사용할 수 있습니다.", HttpStatus.BAD_REQUEST, "VI_002"); + CONSECUTIVE_UNDERSCORES("언더바(_)는 최대 3개 까지 연속으로 사용할 수 있습니다.", HttpStatus.BAD_REQUEST, "VI_002"), + DUPLICATED("이미 사용중인 백곰 아이디입니다.", HttpStatus.BAD_REQUEST, "VI_003"), + INVALID_LENGTH("백곰 아이디는 20자 이하여야 합니다.", HttpStatus.BAD_REQUEST, "VI_004"), } diff --git a/src/main/kotlin/com/vacgom/backend/global/security/matcher/CustomRequestMatcher.kt b/src/main/kotlin/com/vacgom/backend/global/security/matcher/CustomRequestMatcher.kt index 6a944f6..4c5dcd1 100644 --- a/src/main/kotlin/com/vacgom/backend/global/security/matcher/CustomRequestMatcher.kt +++ b/src/main/kotlin/com/vacgom/backend/global/security/matcher/CustomRequestMatcher.kt @@ -10,8 +10,9 @@ class CustomRequestMatcher { fun authEndpoints(): RequestMatcher { return OrRequestMatcher( - AntPathRequestMatcher("/"), - AntPathRequestMatcher("/api/v1/oauth/**") + AntPathRequestMatcher("/"), // Actuator Health Checker + AntPathRequestMatcher("/api/v1/oauth/**"), // Oauth Login + AntPathRequestMatcher("/api/v1/member/validation") // VacgomId Validation Checker ) } diff --git a/src/main/kotlin/com/vacgom/backend/infrastructure/member/persistence/MemberRepository.kt b/src/main/kotlin/com/vacgom/backend/infrastructure/member/persistence/MemberRepository.kt index 77d6a1b..2a3d629 100644 --- a/src/main/kotlin/com/vacgom/backend/infrastructure/member/persistence/MemberRepository.kt +++ b/src/main/kotlin/com/vacgom/backend/infrastructure/member/persistence/MemberRepository.kt @@ -2,6 +2,7 @@ package com.vacgom.backend.infrastructure.member.persistence import com.vacgom.backend.domain.auth.oauth.constants.ProviderType import com.vacgom.backend.domain.member.Member +import com.vacgom.backend.domain.member.VacgomId import org.springframework.data.jpa.repository.JpaRepository import java.util.* @@ -10,4 +11,6 @@ interface MemberRepository : JpaRepository { providerId: Long, providerType: ProviderType ): Member? + + fun existsMemberByVacgomId(vacgomId: VacgomId): Boolean } diff --git a/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt b/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt new file mode 100644 index 0000000..435800f --- /dev/null +++ b/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt @@ -0,0 +1,20 @@ +package com.vacgom.backend.presentation.member + +import com.vacgom.backend.application.member.MemberService +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/api/v1/member") +class MemberController( + private val memberService: MemberService +) { + @PostMapping("/validation") + fun validateVacgomId(@RequestParam vacgomId: String): ResponseEntity { + memberService.validateVacgomId(vacgomId) + return ResponseEntity.ok().build() + } +} From afb39815efe9a8d492a59ea36da6a4ae2f5e0305 Mon Sep 17 00:00:00 2001 From: Haebin Date: Wed, 20 Mar 2024 07:42:44 +0900 Subject: [PATCH 3/9] =?UTF-8?q?feat:=20=EB=B0=B1=EA=B3=B0=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EB=94=94=20=EC=98=81=EB=AC=B8=20=EC=86=8C=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=EB=A1=9C=20=EC=8B=9C=EC=9E=91=20Regex?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/vacgom/backend/domain/member/VacgomId.kt | 4 ++++ .../com/vacgom/backend/exception/member/VacgomIdError.kt | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt b/src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt index 1e26618..5c8728c 100644 --- a/src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt +++ b/src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt @@ -11,6 +11,7 @@ class VacgomId( ) { companion object { private const val VACGOM_ID_REGEX = "[a-z0-9_]+" + private const val START_WITH_LOWER_CASE_REGEX = "^[a-z].*" private const val CONSECUTIVE_UNDERSCORES = "____" private const val MINIMUM_LENGTH = 1 private const val MAXIMUM_LENGTH = 20 @@ -21,6 +22,9 @@ class VacgomId( } private fun validatePattern(id: String) { + require(id.matches(START_WITH_LOWER_CASE_REGEX.toRegex())) { + throw BusinessException(VacgomIdError.NOT_START_WITH_LOWER_CASE) + } require(id.matches(VACGOM_ID_REGEX.toRegex())) { throw BusinessException(VacgomIdError.INVALID_VACGOM_ID_PATTERN) } diff --git a/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt b/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt index 069a41c..bcff849 100644 --- a/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt +++ b/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt @@ -10,8 +10,9 @@ internal enum class VacgomIdError( override val code: String ) : ErrorCode { INVALID_VACGOM_ID_PATTERN("백곰 아이디는 영문 소문자와 숫자, 언더바(_)로 구성되어야 합니다.", HttpStatus.BAD_REQUEST, "VI_001"), - CONSECUTIVE_UNDERSCORES("언더바(_)는 최대 3개 까지 연속으로 사용할 수 있습니다.", HttpStatus.BAD_REQUEST, "VI_002"), - DUPLICATED("이미 사용중인 백곰 아이디입니다.", HttpStatus.BAD_REQUEST, "VI_003"), - INVALID_LENGTH("백곰 아이디는 20자 이하여야 합니다.", HttpStatus.BAD_REQUEST, "VI_004"), + NOT_START_WITH_LOWER_CASE("백곰 아이디는 영문 소문자로 시작해야 합니다", HttpStatus.BAD_REQUEST, "VI_002"), + CONSECUTIVE_UNDERSCORES("언더바(_)는 최대 3개 까지 연속으로 사용할 수 있습니다.", HttpStatus.BAD_REQUEST, "VI_003"), + DUPLICATED("이미 사용중인 백곰 아이디입니다.", HttpStatus.BAD_REQUEST, "VI_004"), + INVALID_LENGTH("백곰 아이디는 20자 이하여야 합니다.", HttpStatus.BAD_REQUEST, "VI_005"), } From 15090dc238ca084b4b4e689769a29333e782022f Mon Sep 17 00:00:00 2001 From: Haebin Date: Wed, 20 Mar 2024 07:55:18 +0900 Subject: [PATCH 4/9] =?UTF-8?q?feat:=20Security=20Logger=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/global/security/filter/JwtAuthFilter.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/vacgom/backend/global/security/filter/JwtAuthFilter.kt b/src/main/kotlin/com/vacgom/backend/global/security/filter/JwtAuthFilter.kt index 8ea2dca..f16f9c8 100644 --- a/src/main/kotlin/com/vacgom/backend/global/security/filter/JwtAuthFilter.kt +++ b/src/main/kotlin/com/vacgom/backend/global/security/filter/JwtAuthFilter.kt @@ -6,6 +6,7 @@ import com.vacgom.backend.global.security.model.CustomUser import jakarta.servlet.FilterChain import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse +import org.slf4j.Logger import org.springframework.security.authentication.AnonymousAuthenticationToken import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.security.core.context.SecurityContextHolder @@ -15,7 +16,8 @@ import org.springframework.web.filter.OncePerRequestFilter @Component class JwtAuthFilter( - private val jwtService: JwtService + private val jwtService: JwtService, + private val log: Logger ) : OncePerRequestFilter() { companion object { private const val HEADER_AUTHORIZATION = "Authorization" @@ -37,12 +39,12 @@ class JwtAuthFilter( val authenticationToken = AnonymousAuthenticationToken("guest", principal, setOf(authority)) SecurityContextHolder.getContext().authentication = authenticationToken chain.doFilter(request, response) - println("principal = ${principal}") + log.info("{}({}) - ({}) {}", principal.username, principal.authorities, request.method, request.requestURL) return } val authentication = jwtService.getAuthentication(token) SecurityContextHolder.getContext().authentication = authentication - println("authentication = ${authentication}") + log.info("{}", SecurityContextHolder.getContext()) chain.doFilter(request, response) } From 78181a6d5e1b66033fcbc9734e254d6600982d70 Mon Sep 17 00:00:00 2001 From: Haebin Date: Wed, 20 Mar 2024 09:29:11 +0900 Subject: [PATCH 5/9] feat: Init HealthProfile Entity --- .../backend/domain/member/HealthProfile.kt | 23 +++++++++++++++++++ .../vacgom/backend/domain/member/Member.kt | 13 ++++++----- .../member/constants/HealthCondition.kt | 22 ++++++++++++++++++ 3 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/com/vacgom/backend/domain/member/HealthProfile.kt create mode 100644 src/main/kotlin/com/vacgom/backend/domain/member/constants/HealthCondition.kt diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/HealthProfile.kt b/src/main/kotlin/com/vacgom/backend/domain/member/HealthProfile.kt new file mode 100644 index 0000000..6b51ae6 --- /dev/null +++ b/src/main/kotlin/com/vacgom/backend/domain/member/HealthProfile.kt @@ -0,0 +1,23 @@ +package com.vacgom.backend.domain.member + +import com.vacgom.backend.domain.member.constants.HealthCondition +import jakarta.persistence.* +import org.hibernate.annotations.GenericGenerator +import java.util.* + +@Entity +@Table(name = "t_health_profile") +class HealthProfile( + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + var member: Member, + + @Enumerated(value = EnumType.STRING) + var healthCondition: HealthCondition +) { + @Id + @GeneratedValue(generator = "uuid2") + @GenericGenerator(name = "uuid2", strategy = "uuid2") + @Column(columnDefinition = "BINARY(16)", name = "health_profile_id") + val id: UUID? = null +} diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt b/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt index 06e4611..3aee739 100644 --- a/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt +++ b/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt @@ -1,5 +1,6 @@ package com.vacgom.backend.domain.member +import com.fasterxml.jackson.annotation.JsonFormat import com.vacgom.backend.domain.auth.constants.Role import com.vacgom.backend.domain.auth.oauth.constants.ProviderType import com.vacgom.backend.domain.member.constants.Sex @@ -18,22 +19,22 @@ class Member( ) : BaseEntity() { @Id - @GeneratedValue(generator = "uuid2") @GenericGenerator(name = "uuid2", strategy = "uuid2") @Column(columnDefinition = "BINARY(16)", name = "member_id") - val id: UUID? = null + val id: UUID? = UUID.randomUUID() + @Column(nullable = false) var name: String? = null - private set + @JsonFormat( + shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd" + ) var birthday: LocalDate? = null - private set @Enumerated(EnumType.STRING) var sex: Sex? = null - private set @Embedded var vacgomId: VacgomId? = null - private set } diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/constants/HealthCondition.kt b/src/main/kotlin/com/vacgom/backend/domain/member/constants/HealthCondition.kt new file mode 100644 index 0000000..5de376d --- /dev/null +++ b/src/main/kotlin/com/vacgom/backend/domain/member/constants/HealthCondition.kt @@ -0,0 +1,22 @@ +package com.vacgom.backend.domain.member.constants + +enum class HealthCondition( + val code: Long, + val description: String +) { + DIABETES(1, "당뇨병"), + CHRONIC_CARDIOVASCULAR_DISEASE(2, "만성 심혈관질환"), + CHRONIC_PULMONARY_DISEASE(3, "만성 폐질환"), + CHRONIC_RENAL_DISEASE(4, "만성 신질환"), + CHRONIC_LIVER_DISEASE(5, "만성 간질환"), + SOLID_TUMOR_UNDERGOING_ANTINEOPLASTIC_THERAPY(6, "항암치료중인 고형암"), + IMMUNOSUPPRESSIVE_AGENTS_EXCLUDING_TRANSPLANT(7, "이식 이외 면역 억제제 사용"), + HEMATOPOIETIC_STEM_CELL_TRANSPLANTATION(8, "조혈모"), + CELL_TRANSPLANTATION(9, "세포이식"), + SICKLE_CELL_DISEASE(10, "무비증"), + HIV_INFECTION_CD4_ABOVE_200(11, "HIV 감염:CD4>=200/mm3"), + HIV_INFECTION_CD4_BELOW_200(11, "HIV 감염:CD4<200/mm3"), + PREGNANCY(12, "임신"), + MEDICAL_WORKER(13, "의료기관 종사자"), + ORGAN_TRANSPLANTATION(14, "장기 이식 경험") +} From 578f1e7cb7160bdedfe9f18dcc815fdc4a0f96a4 Mon Sep 17 00:00:00 2001 From: Haebin Date: Wed, 20 Mar 2024 09:29:21 +0900 Subject: [PATCH 6/9] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/auth/RefreshToken.kt | 24 ------------------- 1 file changed, 24 deletions(-) delete mode 100644 src/main/kotlin/com/vacgom/backend/domain/auth/RefreshToken.kt diff --git a/src/main/kotlin/com/vacgom/backend/domain/auth/RefreshToken.kt b/src/main/kotlin/com/vacgom/backend/domain/auth/RefreshToken.kt deleted file mode 100644 index 9cb0c5c..0000000 --- a/src/main/kotlin/com/vacgom/backend/domain/auth/RefreshToken.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.vacgom.backend.domain.auth - -import com.vacgom.backend.domain.member.Member -import com.vacgom.backend.global.auditing.BaseEntity -import jakarta.persistence.* -import java.time.LocalDateTime - - -@Entity -@Table(name = "t_refresh_token") -class RefreshToken( - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id", nullable = false) - var member: Member, - var token: String, - var userAgent: String, - var expiredAt: LocalDateTime -) : BaseEntity() { - @Id - @GeneratedValue - @Column(name = "rt_id") - private val id: Long? = null -} - From d07a305491bb888dc051877a153f70b298bb4280 Mon Sep 17 00:00:00 2001 From: Haebin Date: Wed, 20 Mar 2024 11:31:43 +0900 Subject: [PATCH 7/9] =?UTF-8?q?feat:=20=EC=9C=A0=EC=A0=80=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EA=B0=80=EC=9E=85=20=ED=94=8C=EB=A1=9C=EC=9A=B0(TEMP?= =?UTF-8?q?=5FUSER=20->=20USER)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/application/auth/AuthService.kt | 12 +++--- .../dto/{LoginResponse.kt => AuthResponse.kt} | 2 +- .../application/member/MemberService.kt | 37 ++++++++++++++++++- .../member/dto/request/SignUpRequest.kt | 11 ++++++ .../vacgom/backend/domain/member/Member.kt | 24 +++++------- .../backend/domain/member/MemberDetails.kt | 33 +++++++++++++++++ .../backend/global/config/SecurityConfig.kt | 4 +- .../global/security/filter/JwtAuthFilter.kt | 6 +-- .../jwt/{JwtService.kt => JwtFactory.kt} | 8 ++-- .../security/matcher/CustomRequestMatcher.kt | 2 +- .../persistence/HealthProfileRepository.kt | 7 ++++ .../presentation/auth/OAuthController.kt | 4 +- .../presentation/member/MemberController.kt | 18 +++++++-- 13 files changed, 129 insertions(+), 39 deletions(-) rename src/main/kotlin/com/vacgom/backend/application/auth/dto/{LoginResponse.kt => AuthResponse.kt} (82%) create mode 100644 src/main/kotlin/com/vacgom/backend/application/member/dto/request/SignUpRequest.kt create mode 100644 src/main/kotlin/com/vacgom/backend/domain/member/MemberDetails.kt rename src/main/kotlin/com/vacgom/backend/global/security/jwt/{JwtService.kt => JwtFactory.kt} (97%) create mode 100644 src/main/kotlin/com/vacgom/backend/infrastructure/member/persistence/HealthProfileRepository.kt diff --git a/src/main/kotlin/com/vacgom/backend/application/auth/AuthService.kt b/src/main/kotlin/com/vacgom/backend/application/auth/AuthService.kt index 526530e..b11ff11 100644 --- a/src/main/kotlin/com/vacgom/backend/application/auth/AuthService.kt +++ b/src/main/kotlin/com/vacgom/backend/application/auth/AuthService.kt @@ -1,12 +1,12 @@ package com.vacgom.backend.application.auth -import com.vacgom.backend.application.auth.dto.LoginResponse +import com.vacgom.backend.application.auth.dto.AuthResponse import com.vacgom.backend.application.auth.dto.MemberResponse import com.vacgom.backend.application.auth.dto.TokenResponse import com.vacgom.backend.domain.auth.constants.Role.ROLE_TEMP_USER import com.vacgom.backend.domain.auth.oauth.constants.ProviderType import com.vacgom.backend.domain.member.Member -import com.vacgom.backend.global.security.jwt.JwtService +import com.vacgom.backend.global.security.jwt.JwtFactory import com.vacgom.backend.infrastructure.member.persistence.MemberRepository import jakarta.transaction.Transactional import org.springframework.http.HttpHeaders @@ -16,7 +16,7 @@ import java.net.URI @Component class AuthService( private val authFactory: AuthFactory, - private val jwtService: JwtService, + private val jwtFactory: JwtFactory, private val memberRepository: MemberRepository ) { fun createRedirectHeaders(redirectUri: URI): HttpHeaders { @@ -33,16 +33,16 @@ class AuthService( fun login( providerType: String, code: String - ): LoginResponse { + ): AuthResponse { val authConnector = authFactory.getAuthConnector(providerType) val oauthToken = authConnector.fetchOauthToken(code) val memberInfo = authConnector.fetchMemberInfo(oauthToken.accessToken) val member = findOrCreateMember(memberInfo.id, ProviderType.from(providerType)) val memberResponse = MemberResponse(member.id!!, member.role) - val tokenResponse = TokenResponse(jwtService.createAccessToken(member)) + val tokenResponse = TokenResponse(jwtFactory.createAccessToken(member)) - return LoginResponse(memberResponse, tokenResponse) + return AuthResponse(memberResponse, tokenResponse) } private fun findOrCreateMember( diff --git a/src/main/kotlin/com/vacgom/backend/application/auth/dto/LoginResponse.kt b/src/main/kotlin/com/vacgom/backend/application/auth/dto/AuthResponse.kt similarity index 82% rename from src/main/kotlin/com/vacgom/backend/application/auth/dto/LoginResponse.kt rename to src/main/kotlin/com/vacgom/backend/application/auth/dto/AuthResponse.kt index f1c3e1c..88c21f4 100644 --- a/src/main/kotlin/com/vacgom/backend/application/auth/dto/LoginResponse.kt +++ b/src/main/kotlin/com/vacgom/backend/application/auth/dto/AuthResponse.kt @@ -1,6 +1,6 @@ package com.vacgom.backend.application.auth.dto -data class LoginResponse( +data class AuthResponse( val member: MemberResponse, val token: TokenResponse ) diff --git a/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt b/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt index 0f8a761..2eccc3b 100644 --- a/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt +++ b/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt @@ -1,18 +1,53 @@ package com.vacgom.backend.application.member +import com.vacgom.backend.application.auth.dto.AuthResponse +import com.vacgom.backend.application.auth.dto.MemberResponse +import com.vacgom.backend.application.auth.dto.TokenResponse +import com.vacgom.backend.application.member.dto.request.SignUpRequest +import com.vacgom.backend.domain.auth.constants.Role +import com.vacgom.backend.domain.member.HealthProfile import com.vacgom.backend.domain.member.VacgomId +import com.vacgom.backend.exception.member.MemberError import com.vacgom.backend.exception.member.VacgomIdError import com.vacgom.backend.global.exception.error.BusinessException +import com.vacgom.backend.global.security.jwt.JwtFactory +import com.vacgom.backend.infrastructure.member.persistence.HealthProfileRepository import com.vacgom.backend.infrastructure.member.persistence.MemberRepository import org.springframework.stereotype.Service +import java.util.* @Service class MemberService( - private val memberRepository: MemberRepository + private val memberRepository: MemberRepository, + private val healthProfileRepository: HealthProfileRepository, + private val jwtFactory: JwtFactory ) { fun validateVacgomId(id: String) { val vacgomId = VacgomId(id) if (memberRepository.existsMemberByVacgomId(vacgomId)) throw BusinessException(VacgomIdError.DUPLICATED) } + + fun signUpVacgom( + memberId: UUID, + request: SignUpRequest + ): AuthResponse { + val member = memberRepository.findById(memberId).orElseThrow { BusinessException(MemberError.NOT_FOUND) } + val vacgomId = VacgomId(request.vacgomId) + + member.memberDetails?.updateMemberInfo(request.name, request.birthday, request.sex) + member.updateVacgomId(vacgomId) + member.updateRole(Role.ROLE_USER) + + val healthConditions = request.healthConditions.stream() + .map { condition -> + HealthProfile(member, condition) + }.toList() + healthProfileRepository.saveAll(healthConditions) + + val memberResponse = MemberResponse(member.id!!, member.role) + val tokenResponse = TokenResponse(jwtFactory.createAccessToken(member)) + + return AuthResponse(memberResponse, tokenResponse) + } } diff --git a/src/main/kotlin/com/vacgom/backend/application/member/dto/request/SignUpRequest.kt b/src/main/kotlin/com/vacgom/backend/application/member/dto/request/SignUpRequest.kt new file mode 100644 index 0000000..6393881 --- /dev/null +++ b/src/main/kotlin/com/vacgom/backend/application/member/dto/request/SignUpRequest.kt @@ -0,0 +1,11 @@ +package com.vacgom.backend.application.member.dto.request + +import com.vacgom.backend.domain.member.constants.HealthCondition + +data class SignUpRequest( + val name: String, + val birthday: String, + val sex: String, + val healthConditions: MutableList, + val vacgomId: String +) diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt b/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt index 3aee739..19a9a0d 100644 --- a/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt +++ b/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt @@ -1,13 +1,10 @@ package com.vacgom.backend.domain.member -import com.fasterxml.jackson.annotation.JsonFormat import com.vacgom.backend.domain.auth.constants.Role import com.vacgom.backend.domain.auth.oauth.constants.ProviderType -import com.vacgom.backend.domain.member.constants.Sex import com.vacgom.backend.global.auditing.BaseEntity import jakarta.persistence.* import org.hibernate.annotations.GenericGenerator -import java.time.LocalDate import java.util.* @Entity @@ -23,18 +20,17 @@ class Member( @Column(columnDefinition = "BINARY(16)", name = "member_id") val id: UUID? = UUID.randomUUID() - @Column(nullable = false) - var name: String? = null - - @JsonFormat( - shape = JsonFormat.Shape.STRING, - pattern = "yyyy-MM-dd" - ) - var birthday: LocalDate? = null - - @Enumerated(EnumType.STRING) - var sex: Sex? = null + @Embedded + var memberDetails: MemberDetails? = null @Embedded var vacgomId: VacgomId? = null + + fun updateVacgomId(vacgomId: VacgomId) { + this.vacgomId = vacgomId + } + + fun updateRole(role: Role) { + this.role = role + } } diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/MemberDetails.kt b/src/main/kotlin/com/vacgom/backend/domain/member/MemberDetails.kt new file mode 100644 index 0000000..9bd1338 --- /dev/null +++ b/src/main/kotlin/com/vacgom/backend/domain/member/MemberDetails.kt @@ -0,0 +1,33 @@ +package com.vacgom.backend.domain.member + +import com.fasterxml.jackson.annotation.JsonFormat +import com.vacgom.backend.domain.member.constants.Sex +import jakarta.persistence.Embeddable +import jakarta.persistence.EnumType +import jakarta.persistence.Enumerated +import java.time.LocalDate +import java.time.format.DateTimeFormatter + +@Embeddable +class MemberDetails { + var name: String? = null + + @JsonFormat( + shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd" + ) + var birthday: LocalDate? = null + + @Enumerated(EnumType.STRING) + var sex: Sex? = null + + fun updateMemberInfo( + name: String, + birthday: String, + sex: String + ) { + this.name = name + this.birthday = LocalDate.parse(birthday, DateTimeFormatter.ISO_LOCAL_DATE) + this.sex = Sex.valueOf(sex.uppercase()) + } +} diff --git a/src/main/kotlin/com/vacgom/backend/global/config/SecurityConfig.kt b/src/main/kotlin/com/vacgom/backend/global/config/SecurityConfig.kt index 700f1d3..b930097 100644 --- a/src/main/kotlin/com/vacgom/backend/global/config/SecurityConfig.kt +++ b/src/main/kotlin/com/vacgom/backend/global/config/SecurityConfig.kt @@ -39,12 +39,10 @@ class SecurityConfig( @Order(1) fun anyRequestFilterChain(http: HttpSecurity): SecurityFilterChain { http.authorizeRequests { auth -> - auth.requestMatchers(customRequestMatcher.tempUserEndpoints()).hasRole("TEMP_USER") - .anyRequest().hasRole("USER") + auth.requestMatchers(customRequestMatcher.tempUserEndpoints()).hasRole("TEMP_USER").anyRequest().hasRole("USER") } .addFilterAfter(jwtAuthFilter, UsernamePasswordAuthenticationFilter::class.java) .addFilterBefore(apiExceptionHandlingFilter, UsernamePasswordAuthenticationFilter::class.java) - return commonHttpSecurity(http).build() } diff --git a/src/main/kotlin/com/vacgom/backend/global/security/filter/JwtAuthFilter.kt b/src/main/kotlin/com/vacgom/backend/global/security/filter/JwtAuthFilter.kt index f16f9c8..c5935fd 100644 --- a/src/main/kotlin/com/vacgom/backend/global/security/filter/JwtAuthFilter.kt +++ b/src/main/kotlin/com/vacgom/backend/global/security/filter/JwtAuthFilter.kt @@ -1,7 +1,7 @@ package com.vacgom.backend.global.security.filter import com.vacgom.backend.domain.auth.constants.Role.ROLE_GUEST -import com.vacgom.backend.global.security.jwt.JwtService +import com.vacgom.backend.global.security.jwt.JwtFactory import com.vacgom.backend.global.security.model.CustomUser import jakarta.servlet.FilterChain import jakarta.servlet.http.HttpServletRequest @@ -16,7 +16,7 @@ import org.springframework.web.filter.OncePerRequestFilter @Component class JwtAuthFilter( - private val jwtService: JwtService, + private val jwtFactory: JwtFactory, private val log: Logger ) : OncePerRequestFilter() { companion object { @@ -42,7 +42,7 @@ class JwtAuthFilter( log.info("{}({}) - ({}) {}", principal.username, principal.authorities, request.method, request.requestURL) return } - val authentication = jwtService.getAuthentication(token) + val authentication = jwtFactory.getAuthentication(token) SecurityContextHolder.getContext().authentication = authentication log.info("{}", SecurityContextHolder.getContext()) chain.doFilter(request, response) diff --git a/src/main/kotlin/com/vacgom/backend/global/security/jwt/JwtService.kt b/src/main/kotlin/com/vacgom/backend/global/security/jwt/JwtFactory.kt similarity index 97% rename from src/main/kotlin/com/vacgom/backend/global/security/jwt/JwtService.kt rename to src/main/kotlin/com/vacgom/backend/global/security/jwt/JwtFactory.kt index 9f58d27..3d12f5c 100644 --- a/src/main/kotlin/com/vacgom/backend/global/security/jwt/JwtService.kt +++ b/src/main/kotlin/com/vacgom/backend/global/security/jwt/JwtFactory.kt @@ -13,13 +13,13 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.security.core.Authentication import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.security.core.userdetails.User -import org.springframework.stereotype.Service +import org.springframework.stereotype.Component import java.security.Key import java.util.* -@Service -class JwtService( +@Component +class JwtFactory( @Value("\${jwt.secret.key}") secret: String, @Value("\${jwt.access-token-validity}") private val accessTokenValidity: Long ) { @@ -56,7 +56,7 @@ class JwtService( throw BusinessException(AuthError.UNSUPPORTED_JWT_TOKEN) } } - + fun getAuthentication(token: String): Authentication? { val claims: Claims = getTokenClaims(token).body val authorities = Arrays.stream(arrayOf(claims["role"].toString())) diff --git a/src/main/kotlin/com/vacgom/backend/global/security/matcher/CustomRequestMatcher.kt b/src/main/kotlin/com/vacgom/backend/global/security/matcher/CustomRequestMatcher.kt index 4c5dcd1..81594f8 100644 --- a/src/main/kotlin/com/vacgom/backend/global/security/matcher/CustomRequestMatcher.kt +++ b/src/main/kotlin/com/vacgom/backend/global/security/matcher/CustomRequestMatcher.kt @@ -18,7 +18,7 @@ class CustomRequestMatcher { fun tempUserEndpoints(): RequestMatcher { return OrRequestMatcher( - AntPathRequestMatcher("/api/v1/api/main") + AntPathRequestMatcher("/api/v1/member/signup") ) } } diff --git a/src/main/kotlin/com/vacgom/backend/infrastructure/member/persistence/HealthProfileRepository.kt b/src/main/kotlin/com/vacgom/backend/infrastructure/member/persistence/HealthProfileRepository.kt new file mode 100644 index 0000000..c493f1c --- /dev/null +++ b/src/main/kotlin/com/vacgom/backend/infrastructure/member/persistence/HealthProfileRepository.kt @@ -0,0 +1,7 @@ +package com.vacgom.backend.infrastructure.member.persistence + +import com.vacgom.backend.domain.member.HealthProfile +import org.springframework.data.jpa.repository.JpaRepository +import java.util.* + +interface HealthProfileRepository : JpaRepository diff --git a/src/main/kotlin/com/vacgom/backend/presentation/auth/OAuthController.kt b/src/main/kotlin/com/vacgom/backend/presentation/auth/OAuthController.kt index a55e022..36fba15 100644 --- a/src/main/kotlin/com/vacgom/backend/presentation/auth/OAuthController.kt +++ b/src/main/kotlin/com/vacgom/backend/presentation/auth/OAuthController.kt @@ -1,7 +1,7 @@ package com.vacgom.backend.presentation.auth import com.vacgom.backend.application.auth.AuthService -import com.vacgom.backend.application.auth.dto.LoginResponse +import com.vacgom.backend.application.auth.dto.AuthResponse import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* @@ -24,7 +24,7 @@ class OAuthController(private val authService: AuthService) { fun login( @PathVariable provider: String, @RequestParam code: String - ): ResponseEntity { + ): ResponseEntity { val loginResponse = authService.login(provider, code) return ResponseEntity.ok(loginResponse) } diff --git a/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt b/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt index 435800f..8990e3f 100644 --- a/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt +++ b/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt @@ -1,11 +1,12 @@ package com.vacgom.backend.presentation.member +import com.vacgom.backend.application.auth.dto.AuthResponse import com.vacgom.backend.application.member.MemberService +import com.vacgom.backend.application.member.dto.request.SignUpRequest +import com.vacgom.backend.global.security.annotation.AuthId import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.PostMapping -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RequestParam -import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.* +import java.util.* @RestController @RequestMapping("/api/v1/member") @@ -17,4 +18,13 @@ class MemberController( memberService.validateVacgomId(vacgomId) return ResponseEntity.ok().build() } + + @PostMapping("/signup") + fun signUpVacgom( + @AuthId memberId: UUID, + @RequestBody request: SignUpRequest + ): ResponseEntity { + val authResponse = memberService.signUpVacgom(memberId, request) + return ResponseEntity.ok(authResponse) + } } From e4f13aca5d1366ed58aee7b8427f8d3307e52388 Mon Sep 17 00:00:00 2001 From: Haebin Date: Wed, 20 Mar 2024 13:49:39 +0900 Subject: [PATCH 8/9] =?UTF-8?q?feat:=20=EB=B0=B1=EA=B3=B0=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EB=94=94=20->=20=EB=8B=89=EB=84=A4=EC=9E=84=20?= =?UTF-8?q?=EB=AA=85=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/member/MemberService.kt | 16 ++++++------ .../member/dto/request/SignUpRequest.kt | 2 +- .../vacgom/backend/domain/member/Member.kt | 6 ++--- .../member/{VacgomId.kt => Nickname.kt} | 25 +++++++++++-------- .../backend/exception/member/NicknameError.kt | 19 ++++++++++++++ .../backend/exception/member/VacgomIdError.kt | 18 ------------- .../member/persistence/MemberRepository.kt | 4 +-- .../presentation/member/MemberController.kt | 4 +-- 8 files changed, 50 insertions(+), 44 deletions(-) rename src/main/kotlin/com/vacgom/backend/domain/member/{VacgomId.kt => Nickname.kt} (53%) create mode 100644 src/main/kotlin/com/vacgom/backend/exception/member/NicknameError.kt delete mode 100644 src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt diff --git a/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt b/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt index 2eccc3b..68dcbd0 100644 --- a/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt +++ b/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt @@ -6,9 +6,9 @@ import com.vacgom.backend.application.auth.dto.TokenResponse import com.vacgom.backend.application.member.dto.request.SignUpRequest import com.vacgom.backend.domain.auth.constants.Role import com.vacgom.backend.domain.member.HealthProfile -import com.vacgom.backend.domain.member.VacgomId +import com.vacgom.backend.domain.member.Nickname import com.vacgom.backend.exception.member.MemberError -import com.vacgom.backend.exception.member.VacgomIdError +import com.vacgom.backend.exception.member.NicknameError import com.vacgom.backend.global.exception.error.BusinessException import com.vacgom.backend.global.security.jwt.JwtFactory import com.vacgom.backend.infrastructure.member.persistence.HealthProfileRepository @@ -22,10 +22,10 @@ class MemberService( private val healthProfileRepository: HealthProfileRepository, private val jwtFactory: JwtFactory ) { - fun validateVacgomId(id: String) { - val vacgomId = VacgomId(id) - if (memberRepository.existsMemberByVacgomId(vacgomId)) - throw BusinessException(VacgomIdError.DUPLICATED) + fun validateNickname(id: String) { + val nickname = Nickname(id) + if (memberRepository.existsMemberByNickname(nickname)) + throw BusinessException(NicknameError.DUPLICATED) } fun signUpVacgom( @@ -33,10 +33,10 @@ class MemberService( request: SignUpRequest ): AuthResponse { val member = memberRepository.findById(memberId).orElseThrow { BusinessException(MemberError.NOT_FOUND) } - val vacgomId = VacgomId(request.vacgomId) + val nickname = Nickname(request.nickname) member.memberDetails?.updateMemberInfo(request.name, request.birthday, request.sex) - member.updateVacgomId(vacgomId) + member.updateNickname(nickname) member.updateRole(Role.ROLE_USER) val healthConditions = request.healthConditions.stream() diff --git a/src/main/kotlin/com/vacgom/backend/application/member/dto/request/SignUpRequest.kt b/src/main/kotlin/com/vacgom/backend/application/member/dto/request/SignUpRequest.kt index 6393881..9459c7f 100644 --- a/src/main/kotlin/com/vacgom/backend/application/member/dto/request/SignUpRequest.kt +++ b/src/main/kotlin/com/vacgom/backend/application/member/dto/request/SignUpRequest.kt @@ -7,5 +7,5 @@ data class SignUpRequest( val birthday: String, val sex: String, val healthConditions: MutableList, - val vacgomId: String + val nickname: String ) diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt b/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt index 19a9a0d..83d2587 100644 --- a/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt +++ b/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt @@ -24,10 +24,10 @@ class Member( var memberDetails: MemberDetails? = null @Embedded - var vacgomId: VacgomId? = null + var nickname: Nickname? = null - fun updateVacgomId(vacgomId: VacgomId) { - this.vacgomId = vacgomId + fun updateNickname(nickname: Nickname) { + this.nickname = nickname } fun updateRole(role: Role) { diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt b/src/main/kotlin/com/vacgom/backend/domain/member/Nickname.kt similarity index 53% rename from src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt rename to src/main/kotlin/com/vacgom/backend/domain/member/Nickname.kt index 5c8728c..03b0ac3 100644 --- a/src/main/kotlin/com/vacgom/backend/domain/member/VacgomId.kt +++ b/src/main/kotlin/com/vacgom/backend/domain/member/Nickname.kt @@ -1,38 +1,43 @@ package com.vacgom.backend.domain.member -import com.vacgom.backend.exception.member.VacgomIdError +import com.vacgom.backend.exception.member.NicknameError import com.vacgom.backend.global.exception.error.BusinessException import jakarta.persistence.Column import jakarta.persistence.Embeddable @Embeddable -class VacgomId( - @Column(unique = true) var vacgomId: String +class Nickname( + @Column(unique = true) var nickname: String ) { companion object { private const val VACGOM_ID_REGEX = "[a-z0-9_]+" private const val START_WITH_LOWER_CASE_REGEX = "^[a-z].*" private const val CONSECUTIVE_UNDERSCORES = "____" - private const val MINIMUM_LENGTH = 1 - private const val MAXIMUM_LENGTH = 20 + private const val MINIMUM_LENGTH = 4 + private const val MAXIMUM_LENGTH = 10 } init { - validatePattern(vacgomId) + validatePattern(nickname) } private fun validatePattern(id: String) { require(id.matches(START_WITH_LOWER_CASE_REGEX.toRegex())) { - throw BusinessException(VacgomIdError.NOT_START_WITH_LOWER_CASE) + throw BusinessException(NicknameError.NOT_START_WITH_LOWER_CASE) } require(id.matches(VACGOM_ID_REGEX.toRegex())) { - throw BusinessException(VacgomIdError.INVALID_VACGOM_ID_PATTERN) + throw BusinessException(NicknameError.INVALID_VACGOM_ID_PATTERN) } require(CONSECUTIVE_UNDERSCORES !in id) { - throw BusinessException(VacgomIdError.CONSECUTIVE_UNDERSCORES) + throw BusinessException(NicknameError.CONSECUTIVE_UNDERSCORES) } require(id.length in MINIMUM_LENGTH..MAXIMUM_LENGTH) { - throw BusinessException(VacgomIdError.INVALID_LENGTH) + throw BusinessException(NicknameError.INVALID_LENGTH) + } + + val lowerCaseCount = id.count { it.isLowerCase() } + require(lowerCaseCount >= 4) { + throw BusinessException(NicknameError.MINIMUM_LOWERCASE_REQUIRED) } } } diff --git a/src/main/kotlin/com/vacgom/backend/exception/member/NicknameError.kt b/src/main/kotlin/com/vacgom/backend/exception/member/NicknameError.kt new file mode 100644 index 0000000..1a18ddc --- /dev/null +++ b/src/main/kotlin/com/vacgom/backend/exception/member/NicknameError.kt @@ -0,0 +1,19 @@ +package com.vacgom.backend.exception.member + +import com.vacgom.backend.global.exception.error.ErrorCode +import org.springframework.http.HttpStatus + + +enum class NicknameError( + override val message: String, + override val status: HttpStatus, + override val code: String +) : ErrorCode { + INVALID_VACGOM_ID_PATTERN("닉네임은 영문 소문자, 숫자, 언더바(_)로만 구성되어야 합니다.", HttpStatus.BAD_REQUEST, "VI_001"), + NOT_START_WITH_LOWER_CASE("닉네임은 영문 소문자로 시작해야 합니다", HttpStatus.BAD_REQUEST, "VI_002"), + CONSECUTIVE_UNDERSCORES("언더바(_)는 최대 3개 까지 연속으로 사용할 수 있습니다.", HttpStatus.BAD_REQUEST, "VI_003"), + DUPLICATED("이미 사용중인 닉네임입니다.", HttpStatus.BAD_REQUEST, "VI_004"), + INVALID_LENGTH("닉네임은 4 ~ 20자 이하여야 합니다.", HttpStatus.BAD_REQUEST, "VI_005"), + MINIMUM_LOWERCASE_REQUIRED("최소 4개의 소문자 영어를 포함해야 합니다.", HttpStatus.BAD_REQUEST, "VI_006"), +} + diff --git a/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt b/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt deleted file mode 100644 index bcff849..0000000 --- a/src/main/kotlin/com/vacgom/backend/exception/member/VacgomIdError.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.vacgom.backend.exception.member - -import com.vacgom.backend.global.exception.error.ErrorCode -import org.springframework.http.HttpStatus - - -internal enum class VacgomIdError( - override val message: String, - override val status: HttpStatus, - override val code: String -) : ErrorCode { - INVALID_VACGOM_ID_PATTERN("백곰 아이디는 영문 소문자와 숫자, 언더바(_)로 구성되어야 합니다.", HttpStatus.BAD_REQUEST, "VI_001"), - NOT_START_WITH_LOWER_CASE("백곰 아이디는 영문 소문자로 시작해야 합니다", HttpStatus.BAD_REQUEST, "VI_002"), - CONSECUTIVE_UNDERSCORES("언더바(_)는 최대 3개 까지 연속으로 사용할 수 있습니다.", HttpStatus.BAD_REQUEST, "VI_003"), - DUPLICATED("이미 사용중인 백곰 아이디입니다.", HttpStatus.BAD_REQUEST, "VI_004"), - INVALID_LENGTH("백곰 아이디는 20자 이하여야 합니다.", HttpStatus.BAD_REQUEST, "VI_005"), -} - diff --git a/src/main/kotlin/com/vacgom/backend/infrastructure/member/persistence/MemberRepository.kt b/src/main/kotlin/com/vacgom/backend/infrastructure/member/persistence/MemberRepository.kt index 2a3d629..362dfb4 100644 --- a/src/main/kotlin/com/vacgom/backend/infrastructure/member/persistence/MemberRepository.kt +++ b/src/main/kotlin/com/vacgom/backend/infrastructure/member/persistence/MemberRepository.kt @@ -2,7 +2,7 @@ package com.vacgom.backend.infrastructure.member.persistence import com.vacgom.backend.domain.auth.oauth.constants.ProviderType import com.vacgom.backend.domain.member.Member -import com.vacgom.backend.domain.member.VacgomId +import com.vacgom.backend.domain.member.Nickname import org.springframework.data.jpa.repository.JpaRepository import java.util.* @@ -12,5 +12,5 @@ interface MemberRepository : JpaRepository { providerType: ProviderType ): Member? - fun existsMemberByVacgomId(vacgomId: VacgomId): Boolean + fun existsMemberByNickname(nickname: Nickname): Boolean } diff --git a/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt b/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt index 8990e3f..ab5da6b 100644 --- a/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt +++ b/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt @@ -14,8 +14,8 @@ class MemberController( private val memberService: MemberService ) { @PostMapping("/validation") - fun validateVacgomId(@RequestParam vacgomId: String): ResponseEntity { - memberService.validateVacgomId(vacgomId) + fun validateNickname(@RequestParam nickname: String): ResponseEntity { + memberService.validateNickname(nickname) return ResponseEntity.ok().build() } From b3d2bdb3f98c71a981b523ac326fb4d67f505fe4 Mon Sep 17 00:00:00 2001 From: Haebin Date: Wed, 20 Mar 2024 14:15:25 +0900 Subject: [PATCH 9/9] =?UTF-8?q?fix:=20=EC=9D=B4=EB=A6=84,=20=EC=83=9D?= =?UTF-8?q?=EC=9D=BC,=20=EC=84=B1=EB=B3=84=20=EC=A0=80=EC=9E=A5=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/application/auth/AuthService.kt | 2 +- .../application/member/MemberService.kt | 6 +++- .../vacgom/backend/domain/member/Member.kt | 4 +++ .../backend/domain/member/MemberDetails.kt | 31 +++++++------------ .../presentation/member/MemberController.kt | 1 + 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/main/kotlin/com/vacgom/backend/application/auth/AuthService.kt b/src/main/kotlin/com/vacgom/backend/application/auth/AuthService.kt index b11ff11..8b43055 100644 --- a/src/main/kotlin/com/vacgom/backend/application/auth/AuthService.kt +++ b/src/main/kotlin/com/vacgom/backend/application/auth/AuthService.kt @@ -14,6 +14,7 @@ import org.springframework.stereotype.Component import java.net.URI @Component +@Transactional class AuthService( private val authFactory: AuthFactory, private val jwtFactory: JwtFactory, @@ -29,7 +30,6 @@ class AuthService( return authFactory.getAuthUriGenerator(provider).generate() } - @Transactional fun login( providerType: String, code: String diff --git a/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt b/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt index 68dcbd0..a9dfeff 100644 --- a/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt +++ b/src/main/kotlin/com/vacgom/backend/application/member/MemberService.kt @@ -6,6 +6,7 @@ import com.vacgom.backend.application.auth.dto.TokenResponse import com.vacgom.backend.application.member.dto.request.SignUpRequest import com.vacgom.backend.domain.auth.constants.Role import com.vacgom.backend.domain.member.HealthProfile +import com.vacgom.backend.domain.member.MemberDetails import com.vacgom.backend.domain.member.Nickname import com.vacgom.backend.exception.member.MemberError import com.vacgom.backend.exception.member.NicknameError @@ -13,10 +14,12 @@ import com.vacgom.backend.global.exception.error.BusinessException import com.vacgom.backend.global.security.jwt.JwtFactory import com.vacgom.backend.infrastructure.member.persistence.HealthProfileRepository import com.vacgom.backend.infrastructure.member.persistence.MemberRepository +import jakarta.transaction.Transactional import org.springframework.stereotype.Service import java.util.* @Service +@Transactional class MemberService( private val memberRepository: MemberRepository, private val healthProfileRepository: HealthProfileRepository, @@ -34,9 +37,10 @@ class MemberService( ): AuthResponse { val member = memberRepository.findById(memberId).orElseThrow { BusinessException(MemberError.NOT_FOUND) } val nickname = Nickname(request.nickname) + val memberDetails = MemberDetails(request.name, request.birthday, request.sex) - member.memberDetails?.updateMemberInfo(request.name, request.birthday, request.sex) member.updateNickname(nickname) + member.updateMemberDetails(memberDetails) member.updateRole(Role.ROLE_USER) val healthConditions = request.healthConditions.stream() diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt b/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt index 83d2587..bc6d8f7 100644 --- a/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt +++ b/src/main/kotlin/com/vacgom/backend/domain/member/Member.kt @@ -26,6 +26,10 @@ class Member( @Embedded var nickname: Nickname? = null + fun updateMemberDetails(memberDetails: MemberDetails) { + this.memberDetails = memberDetails + } + fun updateNickname(nickname: Nickname) { this.nickname = nickname } diff --git a/src/main/kotlin/com/vacgom/backend/domain/member/MemberDetails.kt b/src/main/kotlin/com/vacgom/backend/domain/member/MemberDetails.kt index 9bd1338..42bcf73 100644 --- a/src/main/kotlin/com/vacgom/backend/domain/member/MemberDetails.kt +++ b/src/main/kotlin/com/vacgom/backend/domain/member/MemberDetails.kt @@ -9,25 +9,18 @@ import java.time.LocalDate import java.time.format.DateTimeFormatter @Embeddable -class MemberDetails { - var name: String? = null +class MemberDetails( + var name: String, - @JsonFormat( - shape = JsonFormat.Shape.STRING, - pattern = "yyyy-MM-dd" - ) - var birthday: LocalDate? = null - - @Enumerated(EnumType.STRING) - var sex: Sex? = null + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + var birthday: LocalDate, - fun updateMemberInfo( - name: String, - birthday: String, - sex: String - ) { - this.name = name - this.birthday = LocalDate.parse(birthday, DateTimeFormatter.ISO_LOCAL_DATE) - this.sex = Sex.valueOf(sex.uppercase()) - } + @Enumerated(EnumType.STRING) + var sex: Sex +) { + constructor(name: String, birthday: String, sex: String) : this( + name, + LocalDate.parse(birthday, DateTimeFormatter.ofPattern("yyyy-MM-dd")), + Sex.valueOf(sex) + ) } diff --git a/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt b/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt index ab5da6b..537b5cd 100644 --- a/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt +++ b/src/main/kotlin/com/vacgom/backend/presentation/member/MemberController.kt @@ -8,6 +8,7 @@ import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* import java.util.* + @RestController @RequestMapping("/api/v1/member") class MemberController(