diff --git a/user-api/src/main/kotlin/com/sns/user/component/authcode/application/AuthCodeCommand.kt b/user-api/src/main/kotlin/com/sns/user/component/authcode/application/AuthCodeCommandService.kt similarity index 97% rename from user-api/src/main/kotlin/com/sns/user/component/authcode/application/AuthCodeCommand.kt rename to user-api/src/main/kotlin/com/sns/user/component/authcode/application/AuthCodeCommandService.kt index e3a467f..16daf34 100644 --- a/user-api/src/main/kotlin/com/sns/user/component/authcode/application/AuthCodeCommand.kt +++ b/user-api/src/main/kotlin/com/sns/user/component/authcode/application/AuthCodeCommandService.kt @@ -10,7 +10,7 @@ import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service @Service -class AuthCodeCommand( +class AuthCodeCommandService( val authCodeRepository: AuthCodeRepository, val mailService: MailService, val userRepository: DefaultUserRepository, diff --git a/user-api/src/main/kotlin/com/sns/user/component/authcode/domain/AuthCode.kt b/user-api/src/main/kotlin/com/sns/user/component/authcode/domain/AuthCode.kt index 2646ed6..c534470 100644 --- a/user-api/src/main/kotlin/com/sns/user/component/authcode/domain/AuthCode.kt +++ b/user-api/src/main/kotlin/com/sns/user/component/authcode/domain/AuthCode.kt @@ -10,10 +10,9 @@ import org.springframework.jdbc.core.RowMapper data class AuthCode( @Id - val id: Int? = null, - // TODO 복합키 구현가능한지 확인. @NotBlank val purpose: Purpose, + @Id @NotBlank val userId: String, @NotBlank @@ -40,7 +39,6 @@ data class AuthCode( class AuthCodeRowMapper : RowMapper { override fun mapRow(rs: ResultSet, rowNum: Int): AuthCode? { return AuthCode( - id = rs.getInt("id"), purpose = Purpose.valueOf(rs.getString("purpose")), userId = rs.getString("user_id"), code = rs.getString("code"), diff --git a/user-api/src/main/kotlin/com/sns/user/component/authcode/repositories/AuthCodeCrudRepository.kt b/user-api/src/main/kotlin/com/sns/user/component/authcode/repositories/AuthCodeCrudRepository.kt deleted file mode 100644 index 93ccf0f..0000000 --- a/user-api/src/main/kotlin/com/sns/user/component/authcode/repositories/AuthCodeCrudRepository.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.sns.user.component.authcode.repositories - -import com.sns.user.component.authcode.domain.AuthCode -import org.springframework.data.repository.CrudRepository -import org.springframework.stereotype.Repository - -@Repository -interface AuthCodeCrudRepository : CrudRepository { -} diff --git a/user-api/src/main/kotlin/com/sns/user/component/authcode/repositories/AuthCodeRepository.kt b/user-api/src/main/kotlin/com/sns/user/component/authcode/repositories/AuthCodeRepository.kt index f87fd46..1e12dc1 100644 --- a/user-api/src/main/kotlin/com/sns/user/component/authcode/repositories/AuthCodeRepository.kt +++ b/user-api/src/main/kotlin/com/sns/user/component/authcode/repositories/AuthCodeRepository.kt @@ -2,10 +2,10 @@ package com.sns.user.component.authcode.repositories import com.sns.user.component.authcode.domain.AuthCode import com.sns.user.component.authcode.domain.Purpose -import org.springframework.data.repository.CrudRepository import org.springframework.data.repository.NoRepositoryBean @NoRepositoryBean -interface AuthCodeRepository : CrudRepository { +interface AuthCodeRepository { + fun save(authCode: AuthCode): AuthCode fun findByUserIdAndPurpose(userId: String, purpose: Purpose): AuthCode? } diff --git a/user-api/src/main/kotlin/com/sns/user/component/authcode/repositories/DefaultAuthCodeRepository.kt b/user-api/src/main/kotlin/com/sns/user/component/authcode/repositories/DefaultAuthCodeRepository.kt index b319b3f..734bdbe 100644 --- a/user-api/src/main/kotlin/com/sns/user/component/authcode/repositories/DefaultAuthCodeRepository.kt +++ b/user-api/src/main/kotlin/com/sns/user/component/authcode/repositories/DefaultAuthCodeRepository.kt @@ -2,24 +2,40 @@ package com.sns.user.component.authcode.repositories import com.sns.user.component.authcode.domain.AuthCode import com.sns.user.component.authcode.domain.Purpose -import org.springframework.data.repository.CrudRepository -import org.springframework.jdbc.core.JdbcTemplate +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate import org.springframework.stereotype.Repository @Repository class DefaultAuthCodeRepository( - val jdbcTemplate: JdbcTemplate, - val authCodeCrudRepository: AuthCodeCrudRepository -) : AuthCodeRepository, CrudRepository by authCodeCrudRepository { + val jdbcTemplate: NamedParameterJdbcTemplate, +) : AuthCodeRepository { override fun findByUserIdAndPurpose(userId: String, purpose: Purpose): AuthCode? = jdbcTemplate.queryForObject( """ - SELECT id,user_id,`code`,created_at,purpose - FROM auth_code - WHERE user_id = ? AND purpose = ? - ORDER BY id DESC + SELECT user_id,`code`,created_at,purpose + FROM auth_code + WHERE user_id = :userId AND purpose = :purpose LIMIT 1 """.trimIndent(), - AuthCode.MAPPER, userId, purpose.name, + mutableMapOf( + "userId" to userId, + "purpose" to purpose.name, + ), + AuthCode.MAPPER, ) + + override fun save(authCode: AuthCode): AuthCode { + jdbcTemplate.update( + """ + REPLACE INTO auth_code (user_id, `code`, created_at, purpose) + VALUES (:userId, :code, NOW(), :purpose) + """.trimIndent(), + mutableMapOf( + "userId" to authCode.userId, + "purpose" to authCode.purpose.name, + "code" to authCode.code, + ), + ) + return authCode + } } diff --git a/user-api/src/main/kotlin/com/sns/user/component/user/listeners/UserStatusListener.kt b/user-api/src/main/kotlin/com/sns/user/component/user/listeners/UserStatusListener.kt index 0590b8f..8507d3b 100644 --- a/user-api/src/main/kotlin/com/sns/user/component/user/listeners/UserStatusListener.kt +++ b/user-api/src/main/kotlin/com/sns/user/component/user/listeners/UserStatusListener.kt @@ -1,16 +1,16 @@ package com.sns.user.component.user.listeners import com.sns.commons.annotation.CustomEventListener -import com.sns.user.component.authcode.application.AuthCodeCommand +import com.sns.user.component.authcode.application.AuthCodeCommandService import com.sns.user.component.user.events.UserActivatedEvent import com.sns.user.component.user.events.UserCreatedEvent @CustomEventListener -class UserStatusListener(val authCodeCommand: AuthCodeCommand) { +class UserStatusListener(val authCodeCommandService: AuthCodeCommandService) { // 인증 전, 기초 가입만 마친 상태 fun onCreated(createdEvent: UserCreatedEvent) { val user = createdEvent.user - authCodeCommand.create(user.id) + authCodeCommandService.create(user.id) } fun onActivated(activatedEvent: UserActivatedEvent) { diff --git a/user-api/src/main/kotlin/com/sns/user/endpoints/user/SignUpController.kt b/user-api/src/main/kotlin/com/sns/user/endpoints/user/SignUpController.kt index db92dd7..9323441 100644 --- a/user-api/src/main/kotlin/com/sns/user/endpoints/user/SignUpController.kt +++ b/user-api/src/main/kotlin/com/sns/user/endpoints/user/SignUpController.kt @@ -1,7 +1,7 @@ package com.sns.user.endpoints.user import com.sns.commons.utils.ifTrue -import com.sns.user.component.authcode.application.AuthCodeCommand +import com.sns.user.component.authcode.application.AuthCodeCommandService import com.sns.user.component.authcode.domain.Purpose import com.sns.user.component.user.application.UserCommandService import com.sns.user.component.user.application.UserQueryService @@ -29,7 +29,7 @@ import org.springframework.web.bind.annotation.RestController @Tag(name = SwaggerTag.SIGN_UP) @RequestMapping("/api") class SignUpController( - val authCodeCommand: AuthCodeCommand, + val authCodeCommandService: AuthCodeCommandService, val userQueryService: UserQueryService, val userCommandService: UserCommandService ) { @@ -56,7 +56,7 @@ class SignUpController( @ResponseStatus(HttpStatus.CREATED) @PutMapping("/v1/sign-up/verifications/auth-code/ids/{userId}") fun createAuthenticationCode(@PathVariable userId: String) { - authCodeCommand.create(userId) + authCodeCommandService.create(userId) } @ApiResponse( @@ -66,7 +66,7 @@ class SignUpController( @ResponseStatus(HttpStatus.OK) @PostMapping("/v1/sign-up/verifications/auth-code/ids/{userId}") fun verifyAuthenticationCode(@PathVariable userId: String, @RequestBody code: String): ResponseEntity { - return authCodeCommand.verify(userId, Purpose.SIGN_UP, code) + return authCodeCommandService.verify(userId, Purpose.SIGN_UP, code) .ifTrue { userCommandService.activate(userId) } .let { ResponseEntity.ok(it) diff --git a/user-api/src/test/kotlin/com/sns/user/component/authcode/application/AuthCodeCommandMockTest.kt b/user-api/src/test/kotlin/com/sns/user/component/authcode/application/AuthCodeCommandServiceMockTest.kt similarity index 84% rename from user-api/src/test/kotlin/com/sns/user/component/authcode/application/AuthCodeCommandMockTest.kt rename to user-api/src/test/kotlin/com/sns/user/component/authcode/application/AuthCodeCommandServiceMockTest.kt index 9af8f3e..585b11c 100644 --- a/user-api/src/test/kotlin/com/sns/user/component/authcode/application/AuthCodeCommandMockTest.kt +++ b/user-api/src/test/kotlin/com/sns/user/component/authcode/application/AuthCodeCommandServiceMockTest.kt @@ -17,7 +17,7 @@ import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.springframework.data.repository.findByIdOrNull -class AuthCodeCommandMockTest() { +class AuthCodeCommandServiceMockTest() { @MockK private lateinit var authCodeRepository: AuthCodeRepository @@ -28,7 +28,7 @@ class AuthCodeCommandMockTest() { private lateinit var userRepository: DefaultUserRepository @InjectMockKs - private lateinit var authCodeCommand: AuthCodeCommand + private lateinit var authCodeCommandService: AuthCodeCommandService @BeforeEach internal fun setUp() { @@ -40,7 +40,7 @@ class AuthCodeCommandMockTest() { @Test fun create() { - val authCode = authCodeCommand.create("id") + val authCode = authCodeCommandService.create("id") verify { authCodeRepository.save(eq(authCode)) } verify { mailService.sendSignUpAuthCodeMail(any(), any()) } @@ -51,7 +51,7 @@ class AuthCodeCommandMockTest() { fun verify_null() { every { authCodeRepository.findByUserIdAndPurpose(ofType(String::class), ofType(Purpose::class)) } returns null - authCodeCommand.verify("userId", Purpose.SIGN_UP, "123") isEqualTo false + authCodeCommandService.verify("userId", Purpose.SIGN_UP, "123") isEqualTo false } @DisplayName("정상 케이스인 경우, 인증에 성공해야한다.") @@ -60,7 +60,7 @@ class AuthCodeCommandMockTest() { val authCode = AuthCode.createSignUp("userId") every { authCodeRepository.findByUserIdAndPurpose(ofType(String::class), ofType(Purpose::class)) } returns authCode - authCodeCommand.verify("userId", Purpose.SIGN_UP, authCode.code) isEqualTo true + authCodeCommandService.verify("userId", Purpose.SIGN_UP, authCode.code) isEqualTo true } @DisplayName("인증 코드가 다른 경우, 인증에 실패해야한다.") @@ -69,6 +69,6 @@ class AuthCodeCommandMockTest() { val authCode = AuthCode.createSignUp("userId") every { authCodeRepository.findByUserIdAndPurpose(ofType(String::class), ofType(Purpose::class)) } returns authCode - authCodeCommand.verify("userId", Purpose.SIGN_UP, "different") isEqualTo false + authCodeCommandService.verify("userId", Purpose.SIGN_UP, "different") isEqualTo false } } diff --git a/user-api/src/test/resources/application.yml b/user-api/src/test/resources/application.yml index 9b8b3b5..9fd2e82 100644 --- a/user-api/src/test/resources/application.yml +++ b/user-api/src/test/resources/application.yml @@ -10,7 +10,7 @@ spring: active: test datasource: driver-class-name: org.h2.Driver - url: jdbc:h2:mem:testdb + url: jdbc:h2:mem:testdb;MODE=MYSQL username: root password: test sql: diff --git a/user-api/src/test/resources/db/users/schema.sql b/user-api/src/test/resources/db/users/schema.sql index fc85420..23a1fa0 100644 --- a/user-api/src/test/resources/db/users/schema.sql +++ b/user-api/src/test/resources/db/users/schema.sql @@ -12,9 +12,9 @@ CREATE TABLE IF NOT EXISTS `user` CREATE TABLE IF NOT EXISTS `auth_code` ( - id INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT 'user.id', user_id VARCHAR(50) NOT NULL COMMENT 'user.id', purpose VARCHAR(50) NOT NULL COMMENT '사용 목적', code VARCHAR(50) NOT NULL COMMENT '인증 코드', - created_at DATETIME NOT NULL COMMENT '생성 시각' + created_at DATETIME NOT NULL COMMENT '생성 시각', + PRIMARY KEY (`user_id`, purpose) );