-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: implements participant signup - 참여자 회원가입 API 구현 - 구글 OAuth 에외처리 로직 일부 수정 * test: add test codes for SignupMapper and ParticipantSignupUseCase - 테스트 커버리지 충족을 위해 테스트 코드 추가 - `SignupMapperTest` 코드 추가 - `ParticipantSignupUseCase` 코드 추가 * fix: resolve duplicate requested authentication - 실험자 회원가입 시, Authentication 중복 생성 코드 제거 * refact: move DB Transaction to seperate responsibility to satisfy clean architecture principal - DB 트랜잭션 책임 관련: UseCase → Service 계층으로 위임 * refact: Applay automatic Component Scan for UseCase classes - UseCase 클래스가 비즈니스 로직의 핵심 계층: 자동으로 컴포넌트 스캔 대상에 포함되도록 어노테이션 제거 - 관리와 확장성을 고려하여 클린 아키텍처를 적용한 구현 방식 * style: rename API endpoint signup to meet the convention rule - 회원가입 API endpoint 관련하여 기존 `/join` → `/signup` 으로 개선 - 코드 컨벤션을 위한 API endpoint 개선 * refact: update annotations to validate DateTime Format - 생년월일 데이터 포맷 관련: 기존: `@NotBlank` → `@NotNull` `@Past` `@DateTimeFormat` * refact: rename mapper function to match its usecase - dto → entity 변환하는 용례에 따라, 기존: `toAddressInfoDto` → `toAddressInfo` 로 리네이밍 * fix: reflect updated codes to test code - dto 함수 리네이밍 반영한 `SingupMapperTest` 버그 해결 * feat: implement researcher member signup - 연구자 회원가입 기본 로직 초안 구현 - `emailVerified` 필드 값이 false이면, `EmailNotValidateException` 반환하도록 구현 * test: update test codes for adjust additional logic - 세부 조정사항: 기존 MemberEntity에 있던 `birthDate` → ParticipantEntity 에 추가 - 이에 따른 기존 test code 수정하여 반영 * test: add test codes for AuthenticationUtils - `AuthenticationUtils` 에 대한 test code 작성 * test: add test codes to UseCases and Service related to signup logic - `SignupService`에 대한 test code 작성 - `CreateResearcherUsecase`,`ParticipantSignupUsecase` test code 작성&수정 * feat: add verification entity - `VerificationEntity`, `VerificationStatus` 도메인 엔티티 추가 - `VerificationRepository` 레포지토리 추가 * feat: implement Email Send Code and Verification using SMTP - SMTP 활용하여 메일 인증 코드 발송 로직 구현 - 유효한 이메일 도메인인지 확인(실제 존재하는지 여부) - 학교 이메일 여부 확인 로직 구현 - 학교 이메일 코드 전송 로직 구현 * fix: add exception codes for Email Verification logic - 인증코드 만료 시에도 재요청 가능하도록 로직 수정 - 이미 승인된 대학 이메일에 대해서는 '이미 승인 완료'라고 예외 처리 * docs: add application-yml file to .gitignore * fix: resolve merge conflicts with dev branch * chore: move packages structure - `usecase/SignUpUseCase/email` 패키지 밑에 메일 인증 관련 UseCase 재배ġ * fix: adjust test codes for non-failed test configuration - 테스트가 Fail하는 현상을 막기 위해, 몇 가지 조치를 취했습니다. * test: add test codes for Email send verification logic - `application/usecase/email/` 패키지 하위 UseCase에 대한 테스트 코드 작성 * feat: add email verification condition to researcherSignup - 연구자 회원가입 전 인증된 학교 메일에 대해서만 가입 가능하게끔 변경 - `ResearcherSignupRequest` 에서 `emailVerified=false` 인 경우, 예외 반환 * fix: add test codes for SignupServiceTest to meet the code coverage * refact: reflect updation from the code review - `/v1/email`→ `/v1/emails` 로 엔드포인트 조정 - 이메일 도메인 검증 중 getter 삭제 후 인덱싱 방법으로 재조정 - MemberResponse 필드값 `isSuccess` typo 수정 - 기존 검증 로직 EmailUtils 패키지로 구조 조정
- Loading branch information
Showing
64 changed files
with
1,106 additions
and
250 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,3 +42,4 @@ application-local.yml | |
|
||
### Kotlin ### | ||
.kotlin | ||
/src/main/resources/application.yml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
src/main/kotlin/com/dobby/backend/application/mapper/VerificationMapper.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.dobby.backend.application.mapper | ||
|
||
import com.dobby.backend.infrastructure.database.entity.VerificationEntity | ||
import com.dobby.backend.infrastructure.database.entity.enum.VerificationStatus | ||
import com.dobby.backend.presentation.api.dto.request.signup.EmailSendRequest | ||
import com.dobby.backend.presentation.api.dto.response.signup.EmailSendResponse | ||
import com.dobby.backend.presentation.api.dto.response.signup.EmailVerificationResponse | ||
|
||
object VerificationMapper { | ||
fun toEntity(req: EmailSendRequest, code : String): VerificationEntity { | ||
return VerificationEntity( | ||
id= 0, | ||
univMail = req.univEmail, | ||
verificationCode = code, | ||
status = VerificationStatus.HOLD, | ||
expiresAt = null | ||
) | ||
} | ||
|
||
fun toSendResDto() : EmailSendResponse{ | ||
return EmailSendResponse( | ||
isSuccess = true, | ||
message = "해당 학교 이메일로 성공적으로 코드를 전송했습니다. 10분 이내로 인증을 완료해주세요." | ||
) | ||
} | ||
|
||
fun toVerifyResDto() : EmailVerificationResponse { | ||
return EmailVerificationResponse( | ||
isSuccess = true, | ||
message = "학교 메일 인증이 완료되었습니다." | ||
) | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
src/main/kotlin/com/dobby/backend/application/service/EmailService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.dobby.backend.application.service | ||
|
||
import com.dobby.backend.application.usecase.SignupUseCase.email.EmailCodeSendUseCase | ||
import com.dobby.backend.application.usecase.SignupUseCase.email.EmailVerificationUseCase | ||
import com.dobby.backend.presentation.api.dto.request.signup.EmailSendRequest | ||
import com.dobby.backend.presentation.api.dto.request.signup.EmailVerificationRequest | ||
import com.dobby.backend.presentation.api.dto.response.signup.EmailSendResponse | ||
import com.dobby.backend.presentation.api.dto.response.signup.EmailVerificationResponse | ||
import jakarta.transaction.Transactional | ||
import org.springframework.stereotype.Service | ||
|
||
@Service | ||
class EmailService( | ||
private val emailCodeSendUseCase: EmailCodeSendUseCase, | ||
private val emailVerificationUseCase: EmailVerificationUseCase | ||
) { | ||
@Transactional | ||
fun sendEmail(req: EmailSendRequest) : EmailSendResponse{ | ||
return emailCodeSendUseCase.execute(req) | ||
} | ||
|
||
@Transactional | ||
fun verifyCode(req: EmailVerificationRequest) : EmailVerificationResponse { | ||
return emailVerificationUseCase.execute(req) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 21 additions & 4 deletions
25
src/main/kotlin/com/dobby/backend/application/service/SignupService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,34 @@ | ||
package com.dobby.backend.application.service | ||
|
||
import com.dobby.backend.application.usecase.ParticipantSignupUseCase | ||
import com.dobby.backend.application.usecase.SignupUseCase.CreateResearcherUseCase | ||
import com.dobby.backend.application.usecase.SignupUseCase.ParticipantSignupUseCase | ||
import com.dobby.backend.application.usecase.SignupUseCase.VerifyResearcherEmailUseCase | ||
import com.dobby.backend.domain.exception.EmailNotValidateException | ||
import com.dobby.backend.presentation.api.dto.request.signup.ParticipantSignupRequest | ||
import com.dobby.backend.presentation.api.dto.request.signup.ResearcherSignupRequest | ||
import com.dobby.backend.presentation.api.dto.response.signup.SignupResponse | ||
import jakarta.transaction.Transactional | ||
import org.springframework.stereotype.Service | ||
|
||
@Service | ||
class SignupService( | ||
private val participantSignupUseCase: ParticipantSignupUseCase | ||
private val participantSignupUseCase: ParticipantSignupUseCase, | ||
private val createResearcherUseCase: CreateResearcherUseCase, | ||
private val verifyResearcherEmailUseCase: VerifyResearcherEmailUseCase | ||
) { | ||
@Transactional | ||
fun participantSignup(input: ParticipantSignupRequest): SignupResponse { | ||
return participantSignupUseCase.execute(input) | ||
return participantSignupUseCase.execute(input) | ||
} | ||
} | ||
|
||
@Transactional | ||
fun researcherSignup(input: ResearcherSignupRequest) : SignupResponse{ | ||
if(!input.emailVerified) { | ||
throw EmailNotValidateException() | ||
} | ||
verifyResearcherEmailUseCase.execute(input.univEmail) | ||
|
||
return createResearcherUseCase.execute(input) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
...ain/kotlin/com/dobby/backend/application/usecase/SignupUseCase/CreateResearcherUseCase.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.dobby.backend.application.usecase.SignupUseCase | ||
|
||
import com.dobby.backend.application.mapper.SignupMapper | ||
import com.dobby.backend.application.usecase.UseCase | ||
import com.dobby.backend.infrastructure.database.repository.ResearcherRepository | ||
import com.dobby.backend.infrastructure.token.JwtTokenProvider | ||
import com.dobby.backend.presentation.api.dto.request.signup.ResearcherSignupRequest | ||
import com.dobby.backend.presentation.api.dto.response.MemberResponse | ||
import com.dobby.backend.presentation.api.dto.response.signup.SignupResponse | ||
import com.dobby.backend.util.AuthenticationUtils | ||
|
||
class CreateResearcherUseCase( | ||
private val researcherRepository: ResearcherRepository, | ||
private val jwtTokenProvider: JwtTokenProvider | ||
) : UseCase<ResearcherSignupRequest, SignupResponse> { | ||
override fun execute(input: ResearcherSignupRequest): SignupResponse { | ||
val memberEntity = SignupMapper.toResearcherMember(input) | ||
val newResearcher = SignupMapper.toResearcher(memberEntity, input) | ||
researcherRepository.save(newResearcher) | ||
|
||
val authentication = AuthenticationUtils.createAuthentication(memberEntity) | ||
val accessToken = jwtTokenProvider.generateAccessToken(authentication) | ||
val refreshToken = jwtTokenProvider.generateRefreshToken(authentication) | ||
|
||
return SignupResponse( | ||
accessToken = accessToken, | ||
refreshToken = refreshToken, | ||
memberInfo = MemberResponse.fromDomain(newResearcher.member.toDomain()) | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
...otlin/com/dobby/backend/application/usecase/SignupUseCase/VerifyResearcherEmailUseCase.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.dobby.backend.application.usecase.SignupUseCase | ||
|
||
import com.dobby.backend.application.usecase.UseCase | ||
import com.dobby.backend.domain.exception.EmailNotValidateException | ||
import com.dobby.backend.domain.exception.VerifyInfoNotFoundException | ||
import com.dobby.backend.infrastructure.database.entity.VerificationEntity | ||
import com.dobby.backend.infrastructure.database.entity.enum.VerificationStatus | ||
import com.dobby.backend.infrastructure.database.repository.VerificationRepository | ||
|
||
class VerifyResearcherEmailUseCase( | ||
private val verificationRepository: VerificationRepository | ||
) : UseCase<String, VerificationEntity> { | ||
override fun execute(input: String): VerificationEntity { | ||
val verificationEntity = verificationRepository.findByUnivMail(input) | ||
?: throw VerifyInfoNotFoundException() | ||
|
||
if (verificationEntity.status != VerificationStatus.VERIFIED) { | ||
throw EmailNotValidateException() | ||
} | ||
return verificationEntity | ||
} | ||
} |
71 changes: 71 additions & 0 deletions
71
.../kotlin/com/dobby/backend/application/usecase/SignupUseCase/email/EmailCodeSendUseCase.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package com.dobby.backend.application.usecase.SignupUseCase.email | ||
|
||
import com.dobby.backend.application.mapper.VerificationMapper | ||
import com.dobby.backend.application.usecase.UseCase | ||
import com.dobby.backend.domain.exception.* | ||
import com.dobby.backend.domain.gateway.EmailGateway | ||
import com.dobby.backend.infrastructure.database.entity.enum.VerificationStatus | ||
import com.dobby.backend.infrastructure.database.repository.VerificationRepository | ||
import com.dobby.backend.presentation.api.dto.request.signup.EmailSendRequest | ||
import com.dobby.backend.presentation.api.dto.response.signup.EmailSendResponse | ||
import com.dobby.backend.util.EmailUtils | ||
import java.time.LocalDateTime | ||
|
||
class EmailCodeSendUseCase( | ||
private val verificationRepository: VerificationRepository, | ||
private val emailGateway: EmailGateway | ||
) : UseCase<EmailSendRequest, EmailSendResponse> { | ||
override fun execute(input: EmailSendRequest): EmailSendResponse { | ||
validateEmail(input.univEmail) | ||
|
||
val code = EmailUtils.generateCode() | ||
reflectVerification(input, code) | ||
|
||
sendVerificationEmail(input, code) | ||
return VerificationMapper.toSendResDto() | ||
} | ||
|
||
private fun validateEmail(email : String){ | ||
if(!EmailUtils.isDomainExists(email)) throw EmailDomainNotFoundException() | ||
if(!EmailUtils.isUnivMail(email)) throw EmailNotUnivException() | ||
} | ||
|
||
private fun reflectVerification(input: EmailSendRequest, code: String) { | ||
val existingInfo = verificationRepository.findByUnivMail(input.univEmail) | ||
|
||
if (existingInfo != null) { | ||
when (existingInfo.status) { | ||
VerificationStatus.HOLD -> { | ||
existingInfo.verificationCode = code | ||
existingInfo.expiresAt = LocalDateTime.now().plusMinutes(10) | ||
verificationRepository.save(existingInfo) | ||
} | ||
|
||
VerificationStatus.VERIFIED -> { | ||
throw EmailAlreadyVerifiedException() | ||
} | ||
} | ||
} else { | ||
val newVerificationInfo = VerificationMapper.toEntity(input, code) | ||
verificationRepository.save(newVerificationInfo) | ||
} | ||
} | ||
|
||
private fun sendVerificationEmail(input: EmailSendRequest, code: String) { | ||
val content = EMAIL_CONTENT_TEMPLATE.format(code) | ||
emailGateway.sendEmail(input.univEmail, EMAIL_SUBJECT, content) | ||
} | ||
|
||
companion object { | ||
private const val EMAIL_SUBJECT = "그라밋 - 이메일 인증 코드 입니다." | ||
private const val EMAIL_CONTENT_TEMPLATE = """ | ||
안녕하세요, 그라밋입니다. | ||
아래의 코드는 이메일 인증을 위한 코드입니다: | ||
%s | ||
10분 이내에 인증을 완료해주세요. | ||
""" | ||
} | ||
} |
Oops, something went wrong.