Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge: (#286) AuthCode, AuthCodeLimit 도메인 리팩토링 #292

Merged
merged 8 commits into from
Jan 9, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import team.comit.simtong.global.annotation.UseCase
* @author Chokyunghyeon
* @author kimbeomjin
* @date 2022/09/24
* @version 1.0.0
* @version 1.2.5
**/
@UseCase
class CheckAuthCodeUseCase(
Expand All @@ -22,15 +22,15 @@ class CheckAuthCodeUseCase(
) {

fun execute(email: String, code: String) {
val authCode = queryAuthCodePort.queryAuthCodeByEmail(email) ?: throw AuthExceptions.RequiredNewEmailAuthentication()
val authCode = queryAuthCodePort.queryAuthCodeByEmail(email)
?: throw AuthExceptions.RequiredNewEmailAuthentication()

if (authCode.code != code) {
if (!authCode.code.match(code)) {
throw AuthExceptions.DifferentAuthCode()
}

commandAuthCodeLimitPort.save(
AuthCodeLimit.certified(email)
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ import team.comit.simtong.global.annotation.UseCase
* @author Chokyunghyeon
* @author kimbeomjin
* @date 2022/09/18
* @version 1.0.0
* @version 1.2.5
**/
@UseCase
class ReissueTokenUseCase(
private val jwtPort: JwtPort,
private val queryRefreshTokenPort: QueryRefreshTokenPort
) {

fun execute(request: String): TokenResponse {
val token = queryRefreshTokenPort.queryRefreshTokenByToken(request)
fun execute(token: String): TokenResponse {
val refreshToken = queryRefreshTokenPort.queryRefreshTokenByToken(token)
?: throw AuthExceptions.RefreshTokenNotFound()

return jwtPort.receiveToken(
userId = token.userId,
authority = token.authority
userId = refreshToken.userId,
authority = refreshToken.authority
)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package team.comit.simtong.domain.auth.usecase

import team.comit.simtong.domain.auth.exception.AuthExceptions
import team.comit.simtong.domain.auth.model.AuthCode
import team.comit.simtong.domain.auth.model.AuthCodeLimit
import team.comit.simtong.domain.auth.spi.CommandAuthCodeLimitPort
Expand All @@ -15,7 +14,7 @@ import team.comit.simtong.global.annotation.UseCase
*
* @author Chokyunghyeon
* @date 2022/09/24
* @version 1.0.0
* @version 1.2.5
**/
@UseCase
class SendAuthCodeUseCase(
Expand All @@ -27,17 +26,16 @@ class SendAuthCodeUseCase(

fun execute(email: String) {
val authCodeLimit = queryAuthCodeLimitPort.queryAuthCodeLimitByEmail(email)
?: AuthCodeLimit(email)
?: AuthCodeLimit.issue(email)

if (authCodeLimit.verified) {
throw AuthExceptions.AlreadyCertifiedEmail()
}
commandAuthCodeLimitPort.save(
authCodeLimit.increaseCount()
)

commandAuthCodeLimitPort.save(authCodeLimit.increaseCount())
val authCode = commandAuthCodePort.save(
AuthCode.issue(email)
)

val authCode = commandAuthCodePort.save(AuthCode(email))

sendEmailPort.sendAuthCode(authCode.code, email)
sendEmailPort.sendAuthCode(authCode.code.value, email)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.mockito.BDDMockito.given
import org.springframework.boot.test.mock.mockito.MockBean
import team.comit.simtong.domain.auth.exception.AuthExceptions
import team.comit.simtong.domain.auth.model.AuthCode
import team.comit.simtong.domain.auth.model.Code
import team.comit.simtong.domain.auth.spi.CommandAuthCodeLimitPort
import team.comit.simtong.domain.auth.spi.QueryAuthCodePort
import team.comit.simtong.global.annotation.SimtongTest
Expand All @@ -30,15 +31,15 @@ class CheckAuthCodeUseCaseTests {
private val authCodeStub: AuthCode by lazy {
AuthCode(
key = email,
code = code,
code = Code.of(code),
expirationTime = AuthCode.EXPIRED
)
}

private val differentAuthCodeStub by lazy {
AuthCode(
key = email,
code = "654321",
code = Code.of("654321"),
expirationTime = AuthCode.EXPIRED
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import org.springframework.boot.test.mock.mockito.MockBean
import team.comit.simtong.domain.auth.exception.AuthExceptions
import team.comit.simtong.domain.auth.model.AuthCode
import team.comit.simtong.domain.auth.model.AuthCodeLimit
import team.comit.simtong.domain.auth.model.Code
import team.comit.simtong.domain.auth.spi.CommandAuthCodeLimitPort
import team.comit.simtong.domain.auth.spi.CommandAuthCodePort
import team.comit.simtong.domain.auth.spi.QueryAuthCodeLimitPort
Expand Down Expand Up @@ -59,7 +60,7 @@ class SendAuthCodeUseCaseTests {
private val authCodeStub by lazy {
AuthCode(
key = email,
code = code,
code = Code.of(code),
expirationTime = AuthCode.EXPIRED
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class ChangeEmailUseCaseTests {
}

private val uncertifiedAuthCodeLimit: AuthCodeLimit by lazy {
AuthCodeLimit(
AuthCodeLimit.issue(
email = "[email protected]"
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class ResetPasswordUseCaseTests {
}

private val uncertifiedAuthCodeLimit: AuthCodeLimit by lazy {
AuthCodeLimit(
AuthCodeLimit.issue(
email = email
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,63 @@ import net.bytebuddy.utility.RandomString
import team.comit.simtong.global.DomainProperties.getProperty
import team.comit.simtong.global.DomainPropertiesPrefix
import team.comit.simtong.global.annotation.Aggregate
import team.comit.simtong.global.annotation.Default

/**
*
* AuthCodeAggregate Root를 담당하는 AuthCode
* AuthCode Aggregate Root를 담당하는 AuthCode
*
* @author Chokyunghyeon
* @author kimbeomjin
* @date 2022/09/24
* @version 1.0.0
* @version 1.2.5
**/
@Aggregate
data class AuthCode @Default constructor(
data class AuthCode(
val key: String,

val code: String,
val code: Code,

val expirationTime: Int
) {

constructor(email: String) : this(
key = email,
code = RandomString(6).nextString(),
expirationTime = EXPIRED
)

companion object {
@JvmField
val EXPIRED = getProperty(DomainPropertiesPrefix.AUTHCODE_EXP).toInt()

fun of(key: String, code: Code, expirationTime: Int) = AuthCode(
key = key,
code = code,
expirationTime = expirationTime
)

fun issue(email: String) = AuthCode(
key = email,
code = Code.defaultValue(),
expirationTime = EXPIRED
)
}
}

/**
*
* AuthCode Aggregate 중 인증코드를 담당하는 Code
*
* @author kimbeomjin
* @date 2023/01/09
* @version 1.2.5
**/
@JvmInline
value class Code private constructor(
val value: String
) {

fun match(code: String): Boolean {
return this.value == code
}

companion object {
fun of(value: String) = Code(value)

fun defaultValue() = Code(RandomString(6).nextString())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import team.comit.simtong.domain.auth.exception.AuthExceptions
import team.comit.simtong.global.DomainProperties.getProperty
import team.comit.simtong.global.DomainPropertiesPrefix
import team.comit.simtong.global.annotation.Aggregate
import team.comit.simtong.global.annotation.Default

/**
*
Expand All @@ -13,10 +12,10 @@ import team.comit.simtong.global.annotation.Default
* @author Chokyunghyeon
* @author kimbeomjin
* @date 2022/09/11
* @version 1.0.0
* @version 1.2.5
**/
@Aggregate
data class AuthCodeLimit @Default constructor(
data class AuthCodeLimit(
val key: String,

val expirationTime: Int,
Expand All @@ -25,14 +24,6 @@ data class AuthCodeLimit @Default constructor(

val verified: Boolean
) {

constructor(email: String) : this(
key = email,
expirationTime = EXPIRED,
attemptCount = 0,
verified = false
)

companion object {
@JvmField
val MAX_ATTEMPT_COUNT: Short = getProperty(DomainPropertiesPrefix.AUTHCODELIMIT_MAX_ATTEMPT_COUNT).toShort()
Expand All @@ -43,6 +34,13 @@ data class AuthCodeLimit @Default constructor(
@JvmField
val VERIFIED_EXPIRED: Int = getProperty(DomainPropertiesPrefix.AUTHCODELIMIT_VERIFIED_EXP).toInt()

fun issue(email: String) = AuthCodeLimit(
key = email,
expirationTime = EXPIRED,
attemptCount = 0,
verified = false
)

fun certified(email: String) = AuthCodeLimit(
key = email,
expirationTime = VERIFIED_EXPIRED,
Expand All @@ -52,9 +50,8 @@ data class AuthCodeLimit @Default constructor(
}

fun increaseCount(): AuthCodeLimit {
if (attemptCount >= MAX_ATTEMPT_COUNT) {
throw AuthExceptions.ExceededSendAuthCodeRequest()
}
checkNotYetVerified()
checkNotExceededAttemptCount()

return AuthCodeLimit(
key = key,
Expand All @@ -64,4 +61,15 @@ data class AuthCodeLimit @Default constructor(
)
}

private fun checkNotYetVerified() {
if (verified) {
throw AuthExceptions.AlreadyCertifiedEmail()
}
}

private fun checkNotExceededAttemptCount() {
if (attemptCount >= MAX_ATTEMPT_COUNT) {
throw AuthExceptions.ExceededSendAuthCodeRequest()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package team.comit.simtong.persistence.auth.mapper

import org.mapstruct.Mapper
import org.springframework.stereotype.Component
import team.comit.simtong.domain.auth.model.AuthCode
import team.comit.simtong.domain.auth.model.Code
import team.comit.simtong.persistence.GenericMapper
import team.comit.simtong.persistence.auth.entity.AuthCodeEntity

Expand All @@ -10,9 +11,36 @@ import team.comit.simtong.persistence.auth.entity.AuthCodeEntity
* AuthCodeEntity와 DomainAuthCode를 변환하는 AuthCodeMapper
*
* @author Chokyunghyeon
* @author kimbeomjin
* @date 2022/09/25
* @version 1.0.0
* @version 1.2.5
**/
@Mapper
abstract class AuthCodeMapper : GenericMapper<AuthCodeEntity, AuthCode> {
@Component
class AuthCodeMapper : GenericMapper<AuthCodeEntity, AuthCode> {

override fun toEntity(model: AuthCode): AuthCodeEntity {
return AuthCodeEntity(
key = model.key,
code = model.code.value,
expirationTime = model.expirationTime
)
}

override fun toDomain(entity: AuthCodeEntity?): AuthCode? {
return entity?.let {
AuthCode.of(
key = it.key,
code = Code.of(it.code),
expirationTime = it.expirationTime
)
}
}

override fun toDomainNotNull(entity: AuthCodeEntity): AuthCode {
return AuthCode.of(
key = entity.key,
code = Code.of(entity.code),
expirationTime = entity.expirationTime
)
}
}