From 80ba69e2e006bff0af2730ffa8d04e5f7bfada83 Mon Sep 17 00:00:00 2001 From: Sim-km Date: Thu, 27 Feb 2025 21:20:18 +0900 Subject: [PATCH] =?UTF-8?q?ASAP-423=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=20=ED=83=88=ED=87=B4=20=EC=82=AC=EC=9C=A0=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=20=EC=BB=AC=EB=9F=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/port/in/DeleteUserUsecase.kt | 1 + .../user/service/UserCommandService.kt | 2 +- .../asap/bootstrap/web/user/api/UserApi.kt | 1 + .../web/user/controller/UserController.kt | 3 +- .../web/user/dto/UnregisterUserRequest.kt | 6 ++ .../user/UserApiIntegrationTest.kt | 59 ++++++++++++++----- .../com/asap/domain/user/entity/User.kt | 4 +- .../asap/persistence/jpa/user/UserMapper.kt | 2 + .../persistence/jpa/user/entity/UserEntity.kt | 6 ++ ...alter_user_table_add_unregister_reason.sql | 1 + 10 files changed, 68 insertions(+), 17 deletions(-) create mode 100644 Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/user/dto/UnregisterUserRequest.kt create mode 100644 Infrastructure-Module/Persistence/src/main/resources/db/V1_19__alter_user_table_add_unregister_reason.sql diff --git a/Application-Module/src/main/kotlin/com/asap/application/user/port/in/DeleteUserUsecase.kt b/Application-Module/src/main/kotlin/com/asap/application/user/port/in/DeleteUserUsecase.kt index e6c94d74..c9d33da3 100644 --- a/Application-Module/src/main/kotlin/com/asap/application/user/port/in/DeleteUserUsecase.kt +++ b/Application-Module/src/main/kotlin/com/asap/application/user/port/in/DeleteUserUsecase.kt @@ -5,5 +5,6 @@ interface DeleteUserUsecase { data class Command( val userId: String, + val reason: String = "" ) } diff --git a/Application-Module/src/main/kotlin/com/asap/application/user/service/UserCommandService.kt b/Application-Module/src/main/kotlin/com/asap/application/user/service/UserCommandService.kt index 18add50d..b3951f32 100644 --- a/Application-Module/src/main/kotlin/com/asap/application/user/service/UserCommandService.kt +++ b/Application-Module/src/main/kotlin/com/asap/application/user/service/UserCommandService.kt @@ -69,7 +69,7 @@ class UserCommandService( userManagementPort .getUserNotNull(DomainId(command.userId)) .apply { - this.delete() + this.delete(command.reason) userManagementPort.save(this) }.also { userAuthManagementPort.getNotNull(it.id).apply { diff --git a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/user/api/UserApi.kt b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/user/api/UserApi.kt index 2c4c4068..8fae12b3 100644 --- a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/user/api/UserApi.kt +++ b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/user/api/UserApi.kt @@ -68,6 +68,7 @@ interface UserApi { ) fun deleteUser( @AccessUser userId: String, + @RequestBody(required = false) request: UnregisterUserRequest?, ) @Operation(summary = "내 정보 조회") diff --git a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/user/controller/UserController.kt b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/user/controller/UserController.kt index 00275a0c..33e7c3f7 100644 --- a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/user/controller/UserController.kt +++ b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/user/controller/UserController.kt @@ -40,10 +40,11 @@ class UserController( ) } - override fun deleteUser(userId: String) { + override fun deleteUser(userId: String, request: UnregisterUserRequest?) { deleteUserUsecase.delete( DeleteUserUsecase.Command( userId = userId, + reason = request?.reason.orEmpty(), ), ) } diff --git a/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/user/dto/UnregisterUserRequest.kt b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/user/dto/UnregisterUserRequest.kt new file mode 100644 index 00000000..fc71619b --- /dev/null +++ b/Bootstrap-Module/src/main/kotlin/com/asap/bootstrap/web/user/dto/UnregisterUserRequest.kt @@ -0,0 +1,6 @@ +package com.asap.bootstrap.web.user.dto + +data class UnregisterUserRequest( + val reason: String? = null +) { +} \ No newline at end of file diff --git a/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/integration/user/UserApiIntegrationTest.kt b/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/integration/user/UserApiIntegrationTest.kt index 0f9f97f2..8a68e0ac 100644 --- a/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/integration/user/UserApiIntegrationTest.kt +++ b/Bootstrap-Module/src/test/kotlin/com/asap/bootstrap/integration/user/UserApiIntegrationTest.kt @@ -5,9 +5,12 @@ import com.asap.application.user.port.out.UserManagementPort import com.asap.bootstrap.IntegrationSupporter import com.asap.bootstrap.web.user.dto.LogoutRequest import com.asap.bootstrap.web.user.dto.RegisterUserRequest +import com.asap.bootstrap.web.user.dto.UnregisterUserRequest import com.asap.bootstrap.web.user.dto.UpdateBirthdayRequest import com.asap.domain.common.DomainId import io.kotest.matchers.comparables.shouldBeGreaterThan +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.springframework.http.MediaType @@ -189,23 +192,51 @@ class UserApiIntegrationTest( } } - @Test - fun deleteUser() { - // given - val userId = userMockManager.settingUser() - userMockManager.settingUserAuth(userId = userId) - val accessToken = jwtMockManager.generateAccessToken(userId) + @Nested + @DisplayName("deleteUser") + inner class DeleteUser{ + @Test + fun deleteUser() { + // given + val userId = userMockManager.settingUser() + userMockManager.settingUserAuth(userId = userId) + val accessToken = jwtMockManager.generateAccessToken(userId) - // when - val response = - mockMvc.delete("/api/v1/users") { - contentType = MediaType.APPLICATION_JSON - header("Authorization", "Bearer $accessToken") + // when + val response = + mockMvc.delete("/api/v1/users") { + contentType = MediaType.APPLICATION_JSON + header("Authorization", "Bearer $accessToken") + } + + // then + response.andExpect { + status { isOk() } } + } - // then - response.andExpect { - status { isOk() } + @Test + fun deleteUser_with_reason(){ + // given + val userId = userMockManager.settingUser() + userMockManager.settingUserAuth(userId = userId) + val accessToken = jwtMockManager.generateAccessToken(userId) + val request = UnregisterUserRequest("reason") + + // when + val response = + mockMvc.delete("/api/v1/users") { + contentType = MediaType.APPLICATION_JSON + content = objectMapper.writeValueAsString(request) + header("Authorization", "Bearer $accessToken") + } + + // then + response.andExpect { + status { isOk() } + } + val user = userManagementPort.findById(DomainId(userId)) + user!!.unregisterReason shouldBe request.reason } } diff --git a/Domain-Module/src/main/kotlin/com/asap/domain/user/entity/User.kt b/Domain-Module/src/main/kotlin/com/asap/domain/user/entity/User.kt index 7de6b249..2208fa73 100644 --- a/Domain-Module/src/main/kotlin/com/asap/domain/user/entity/User.kt +++ b/Domain-Module/src/main/kotlin/com/asap/domain/user/entity/User.kt @@ -17,6 +17,7 @@ class User( var onboardingAt: LocalDateTime?, createdAt: LocalDateTime, updatedAt: LocalDateTime, + var unregisterReason: String? = null, ) : Aggregate(id, createdAt, updatedAt) { companion object { fun create( @@ -34,9 +35,10 @@ class User( } } - fun delete() { + fun delete(reason: String) { this.profileImage = "UNKNOWN" this.birthday = null + this.unregisterReason = reason registerEvent(UserEvent.UserDeletedEvent(this)) updateTime() diff --git a/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/user/UserMapper.kt b/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/user/UserMapper.kt index ce459607..67cd50cd 100644 --- a/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/user/UserMapper.kt +++ b/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/user/UserMapper.kt @@ -28,6 +28,7 @@ object UserMapper { onboardingAt = user.onboardingAt, createdAt = user.createdAt, updatedAt = user.updatedAt, + unregisterReason = user.unregisterReason, ) fun toUser(userEntity: UserEntity): User = @@ -46,6 +47,7 @@ object UserMapper { onboardingAt = userEntity.onboardingAt, createdAt = userEntity.createdAt, updatedAt = userEntity.updatedAt, + unregisterReason = userEntity.unregisterReason, ) fun toUserAuthEntity(userAuth: UserAuth): UserAuthEntity = diff --git a/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/user/entity/UserEntity.kt b/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/user/entity/UserEntity.kt index 5c569ca4..cc95b484 100644 --- a/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/user/entity/UserEntity.kt +++ b/Infrastructure-Module/Persistence/src/main/kotlin/com/asap/persistence/jpa/user/entity/UserEntity.kt @@ -17,6 +17,7 @@ class UserEntity( onboardingAt: LocalDateTime?, createdAt: LocalDateTime, updatedAt: LocalDateTime, + unregisterReason: String? = null, ) : AggregateRoot(id, createdAt, updatedAt) { @Column(nullable = false) val username: String = username @@ -35,4 +36,9 @@ class UserEntity( val birthday: LocalDate? = birthday val onboardingAt: LocalDateTime? = onboardingAt + + @Column( + columnDefinition = "varchar(1000)", + ) + val unregisterReason: String? = unregisterReason } diff --git a/Infrastructure-Module/Persistence/src/main/resources/db/V1_19__alter_user_table_add_unregister_reason.sql b/Infrastructure-Module/Persistence/src/main/resources/db/V1_19__alter_user_table_add_unregister_reason.sql new file mode 100644 index 00000000..cd966272 --- /dev/null +++ b/Infrastructure-Module/Persistence/src/main/resources/db/V1_19__alter_user_table_add_unregister_reason.sql @@ -0,0 +1 @@ +alter table user add column unregister_reason varchar(1000); \ No newline at end of file