Skip to content

Commit

Permalink
feat: merge dev
Browse files Browse the repository at this point in the history
  • Loading branch information
Ji-soo708 committed Jan 8, 2025
2 parents b6dcffe + 1f89fb3 commit 2a482c8
Show file tree
Hide file tree
Showing 64 changed files with 1,090 additions and 246 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ application-local.yml

### Kotlin ###
.kotlin
/src/main/resources/application.yml
10 changes: 8 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,27 @@ configurations {

repositories {
mavenCentral()
maven{url = uri("https://jitpack.io") }
}

dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-data-jpa") {
exclude(group = "org.hibernate", module = "hibernate-core")
}
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-mail")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("com.github.f4b6a3:ulid-creator:5.2.3")
implementation("org.mariadb.jdbc:mariadb-java-client:2.7.3")
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.springframework.cloud:spring-cloud-starter-openfeign")
implementation ("io.awspring.cloud:spring-cloud-starter-aws:2.4.4")
implementation("com.github.in-seo:univcert:master-SNAPSHOT") {
exclude(group = "org.hamcrest", module= "harmcest-core")
}
compileOnly("org.projectlombok:lombok")
runtimeOnly("com.mysql:mysql-connector-j")
runtimeOnly("com.h2database:h2")
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/com/dobby/backend/DobbyBackendApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.cloud.openfeign.EnableFeignClients
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.FilterType
import org.springframework.data.jpa.repository.config.EnableJpaAuditing

@ComponentScan(
includeFilters = [ComponentScan.Filter(
Expand All @@ -17,6 +18,7 @@ import org.springframework.context.annotation.FilterType
@SpringBootApplication
@ConfigurationPropertiesScan
@EnableFeignClients
@EnableJpaAuditing
class DobbyBackendApplication

fun main(args: Array<String>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import com.dobby.backend.infrastructure.database.entity.enum.MemberStatus
import com.dobby.backend.infrastructure.database.entity.enum.RoleType
import com.dobby.backend.presentation.api.dto.request.signup.ParticipantSignupRequest
import com.dobby.backend.infrastructure.database.entity.member.AddressInfo
import com.dobby.backend.infrastructure.database.entity.member.ResearcherEntity
import com.dobby.backend.presentation.api.dto.request.signup.ResearcherSignupRequest
import com.dobby.backend.presentation.api.dto.request.signup.AddressInfo as DtoAddressInfo

object SignupMapper {
Expand All @@ -15,16 +17,27 @@ object SignupMapper {
dto.area
)
}
fun toMember(req: ParticipantSignupRequest): MemberEntity {
fun toParticipantMember(req: ParticipantSignupRequest): MemberEntity {
return MemberEntity(
id = 0, // Auto-generated
oauthEmail = req.oauthEmail,
provider = req.provider,
status = MemberStatus.ACTIVE,
role = RoleType.PARTICIPANT,
contactEmail = req.contactEmail,
name = req.name
)
}

fun toResearcherMember(req: ResearcherSignupRequest): MemberEntity {
return MemberEntity(
id = 0, // Auto-generated
oauthEmail = req.oauthEmail,
provider = req.provider,
status = MemberStatus.ACTIVE,
role = RoleType.RESEARCHER,
contactEmail = req.contactEmail,
name = req.name,
birthDate = req.birthDate
)
}
fun toParticipant(
Expand All @@ -36,7 +49,22 @@ object SignupMapper {
basicAddressInfo = toAddressInfo(req.basicAddressInfo),
additionalAddressInfo = req.additionalAddressInfo?.let { toAddressInfo(it) },
preferType = req.preferType,
gender = req.gender
gender = req.gender,
birthDate = req.birthDate
)
}

fun toResearcher(
member: MemberEntity,
req: ResearcherSignupRequest
): ResearcherEntity {
return ResearcherEntity(
member = member,
univEmail = req.univEmail,
emailVerified = req.emailVerified,
univName = req.univName,
major = req.major,
labInfo = req.labInfo
)
}
}
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 = "학교 메일 인증이 완료되었습니다."
)
}
}
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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.dobby.backend.application.service

import com.dobby.backend.application.usecase.FetchGoogleUserInfoUseCase
import com.dobby.backend.application.usecase.FetchNaverUserInfoUseCase
import com.dobby.backend.presentation.api.dto.request.auth.GoogleOauthLoginRequest
import com.dobby.backend.presentation.api.dto.request.auth.google.GoogleOauthLoginRequest
import com.dobby.backend.presentation.api.dto.request.auth.NaverOauthLoginRequest
import com.dobby.backend.presentation.api.dto.response.auth.OauthLoginResponse
import org.springframework.stereotype.Service
Expand Down
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)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import com.dobby.backend.infrastructure.database.repository.MemberRepository
import com.dobby.backend.infrastructure.feign.google.GoogleAuthFeignClient
import com.dobby.backend.infrastructure.feign.google.GoogleUserInfoFeginClient
import com.dobby.backend.infrastructure.token.JwtTokenProvider
import com.dobby.backend.presentation.api.dto.request.auth.GoogleOauthLoginRequest
import com.dobby.backend.presentation.api.dto.request.auth.GoogleTokenRequest
import com.dobby.backend.presentation.api.dto.response.auth.GoogleTokenResponse
import com.dobby.backend.presentation.api.dto.request.auth.google.GoogleTokenRequest
import com.dobby.backend.presentation.api.dto.request.auth.google.GoogleOauthLoginRequest
import com.dobby.backend.presentation.api.dto.response.auth.google.GoogleTokenResponse
import com.dobby.backend.presentation.api.dto.response.auth.OauthLoginResponse
import com.dobby.backend.util.AuthenticationUtils

Expand Down
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())
)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.dobby.backend.application.usecase
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.ParticipantRepository
import com.dobby.backend.infrastructure.token.JwtTokenProvider
import com.dobby.backend.presentation.api.dto.request.signup.ParticipantSignupRequest
Expand All @@ -11,10 +12,10 @@ import com.dobby.backend.util.AuthenticationUtils
class ParticipantSignupUseCase (
private val participantRepository: ParticipantRepository,
private val jwtTokenProvider: JwtTokenProvider
):UseCase<ParticipantSignupRequest, SignupResponse>
): UseCase<ParticipantSignupRequest, SignupResponse>
{
override fun execute(input: ParticipantSignupRequest): SignupResponse {
val memberEntity = SignupMapper.toMember(input)
val memberEntity = SignupMapper.toParticipantMember(input)
val participantEntity = SignupMapper.toParticipant(memberEntity, input)

val newParticipant = participantRepository.save(participantEntity)
Expand All @@ -28,4 +29,4 @@ class ParticipantSignupUseCase (
refreshToken = refreshToken
)
}
}
}
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
}
}
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분 이내에 인증을 완료해주세요.
"""
}
}
Loading

0 comments on commit 2a482c8

Please sign in to comment.