Skip to content

Commit 535f7b8

Browse files
authored
회원탈퇴 API를 구현한다. (#109)
* feat: withdrawal * test: withdrawal * fix: naming
1 parent be9659e commit 535f7b8

File tree

15 files changed

+93
-17
lines changed

15 files changed

+93
-17
lines changed

api/src/main/kotlin/com/gotchai/api/presentation/v1/auth/AuthController.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import com.gotchai.api.presentation.v1.auth.request.KakaoLoginRequest
66
import com.gotchai.api.presentation.v1.auth.request.RefreshRequest
77
import com.gotchai.api.presentation.v1.auth.response.RefreshResponse
88
import com.gotchai.api.presentation.v1.auth.response.SocialLoginResponse
9+
import com.gotchai.api.presentation.v1.auth.response.WithdrawalResponse
910
import com.gotchai.domain.auth.port.`in`.AuthCommandUseCase
1011
import org.springframework.security.core.annotation.AuthenticationPrincipal
12+
import org.springframework.web.bind.annotation.DeleteMapping
1113
import org.springframework.web.bind.annotation.PostMapping
1214
import org.springframework.web.bind.annotation.RequestBody
1315
import org.springframework.web.bind.annotation.RequestHeader
@@ -56,4 +58,13 @@ class AuthController(
5658
authCommandUseCase
5759
.refresh(deviceId, request.toCommand())
5860
.let { RefreshResponse.from(it) }
61+
62+
@DeleteMapping("/auth/withdrawal")
63+
fun withdrawal(
64+
@AuthenticationPrincipal
65+
userId: Long
66+
): WithdrawalResponse =
67+
authCommandUseCase
68+
.withdrawal(userId)
69+
.let { WithdrawalResponse("회원탈퇴가 완료되었습니다.") }
5970
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.gotchai.api.presentation.v1.auth.response
2+
3+
data class WithdrawalResponse(
4+
val message: String
5+
)

api/src/main/kotlin/com/gotchai/api/presentation/v1/user/UserController.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.GetMapping
1010
class UserController(
1111
private val userQueryUseCase: UserQueryUseCase
1212
) {
13-
@GetMapping("/users/ranking")
13+
@GetMapping("/users/me/ranking")
1414
fun getUserRanking(
1515
@AuthenticationPrincipal
1616
userId: Long

api/src/test/kotlin/com/gotchai/api/presentation/v1/auth/AuthControllerTest.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.gotchai.api.fixture.createRefreshRequest
88
import com.gotchai.api.global.dto.ApiResponse
99
import com.gotchai.api.presentation.v1.auth.response.RefreshResponse
1010
import com.gotchai.api.presentation.v1.auth.response.SocialLoginResponse
11+
import com.gotchai.api.presentation.v1.auth.response.WithdrawalResponse
1112
import com.gotchai.api.util.document
1213
import com.gotchai.api.util.expectError
1314
import com.gotchai.domain.auth.exception.InvalidOAuthTokenException
@@ -233,5 +234,24 @@ class AuthControllerTest : ControllerTest() {
233234
}
234235
}
235236
}
237+
238+
describe("withdrawal()은") {
239+
context("로그인한 유저인 경우") {
240+
every { authCommandUseCase.withdrawal(any()) } just runs
241+
242+
it("상태 코드 200과 WithdrawalResponse를 반환한다.") {
243+
webClient
244+
.delete()
245+
.uri("/api/v1/auth/withdrawal")
246+
.exchange()
247+
.expectStatus()
248+
.isOk
249+
.expectBody<ApiResponse<WithdrawalResponse>>()
250+
.document("회원탈퇴 성공(200)") {
251+
responseBody(withdrawalResponseFields)
252+
}
253+
}
254+
}
255+
}
236256
}
237257
}

api/src/testFixtures/kotlin/com/gotchai/api/docs/AuthDocs.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.gotchai.api.presentation.v1.auth.request.KakaoLoginRequest
55
import com.gotchai.api.presentation.v1.auth.request.RefreshRequest
66
import com.gotchai.api.presentation.v1.auth.response.RefreshResponse
77
import com.gotchai.api.presentation.v1.auth.response.SocialLoginResponse
8+
import com.gotchai.api.presentation.v1.auth.response.WithdrawalResponse
89
import com.gotchai.api.util.desc
910
import com.gotchai.api.util.fieldsOf
1011

@@ -28,3 +29,6 @@ val socialLoginResponseFields =
2829
SocialLoginResponse::accessToken desc "액세스 토큰",
2930
SocialLoginResponse::refreshToken desc "리프레시 토큰"
3031
)
32+
33+
val withdrawalResponseFields =
34+
fieldsOf(WithdrawalResponse::message desc "회원탈퇴 메시지")

domain/src/main/kotlin/com/gotchai/domain/auth/adapter/in/AuthCommandService.kt

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,12 @@ class AuthCommandService(
123123
)
124124
)
125125

126-
val profile =
127-
profileCommandPort.createProfile(
128-
Profile.Creation(
129-
userId = user.id,
130-
nickname = nickname
131-
)
126+
profileCommandPort.createProfile(
127+
Profile.Creation(
128+
userId = user.id,
129+
nickname = nickname
132130
)
131+
)
133132

134133
return user
135134
}
@@ -163,6 +162,14 @@ class AuthCommandService(
163162
refreshTokenCommandPort.deleteRefreshTokenByUserId(userId)
164163
}
165164

165+
@Transactional
166+
override fun withdrawal(userId: Long) {
167+
userCommandPort.deleteByUserId(userId)
168+
userSocialCommandPort.deleteByUserId(userId)
169+
profileCommandPort.deleteByUserId(userId)
170+
refreshTokenCommandPort.deleteRefreshTokenByUserId(userId)
171+
}
172+
166173
private fun createAccessAndRefreshToken(
167174
deviceId: String?,
168175
authentication: GotchaiAuthentication

domain/src/main/kotlin/com/gotchai/domain/auth/port/in/AuthCommandUseCase.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,6 @@ interface AuthCommandUseCase {
2828
): RefreshResult
2929

3030
fun logout(userId: Long)
31+
32+
fun withdrawal(userId: Long)
3133
}

domain/src/main/kotlin/com/gotchai/domain/user/port/out/ProfileCommandPort.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ import com.gotchai.domain.user.entity.Profile
44

55
interface ProfileCommandPort {
66
fun createProfile(creation: Profile.Creation): Profile
7+
8+
fun deleteByUserId(userId: Long)
79
}

domain/src/main/kotlin/com/gotchai/domain/user/port/out/UserCommandPort.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ import com.gotchai.domain.user.entity.User
44

55
interface UserCommandPort {
66
fun createUser(creation: User.Creation): User
7+
8+
fun deleteByUserId(userId: Long)
79
}

domain/src/main/kotlin/com/gotchai/domain/user/port/out/UserSocialCommandPort.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ import com.gotchai.domain.user.entity.UserSocial
44

55
interface UserSocialCommandPort {
66
fun createUserSocial(creation: UserSocial.Creation): UserSocial
7+
8+
fun deleteByUserId(userId: Long)
79
}

0 commit comments

Comments
 (0)