Skip to content

Commit

Permalink
Merge pull request #107 from TeamPINGLE/feat-logout-and-withdraw-api-…
Browse files Browse the repository at this point in the history
…connection

[feat] 로그아웃, 회원탈퇴 api 연동
  • Loading branch information
Dan2dani authored Jan 11, 2024
2 parents bd27bfb + c9022d6 commit 1bcb0e0
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ interface PingleLocalDataSource {
var userName: String
var accessToken: String
var refreshToken: String
fun clear(): Unit
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package org.sopt.pingle.data.datasource.remote

import org.sopt.pingle.data.model.remote.request.RequestAuthDto
import org.sopt.pingle.data.model.remote.response.ResponseAuthDto
import org.sopt.pingle.util.base.NullableBaseResponse

interface AuthRemoteDataSource {
suspend fun login(kakaoAccessToken: String, requestAuthDto: RequestAuthDto): ResponseAuthDto
suspend fun logout(): NullableBaseResponse<String>
suspend fun withDraw(): NullableBaseResponse<String>
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ class PingleLocalDataSourceImpl @Inject constructor(
get() = pref.getString(REFRESH_TOKEN, "") ?: ""
set(value) = pref.edit { putString(REFRESH_TOKEN, value) }

override fun clear() {
pref.edit {
clear()
}
}

companion object {
const val FILE_NAME = "AuthSharedPreferences"
const val AUTO_LOGIN = "AutoLogin"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.sopt.pingle.data.datasource.remote.AuthRemoteDataSource
import org.sopt.pingle.data.model.remote.request.RequestAuthDto
import org.sopt.pingle.data.model.remote.response.ResponseAuthDto
import org.sopt.pingle.data.service.AuthService
import org.sopt.pingle.util.base.NullableBaseResponse

class AuthRemoteDataSourceImpl @Inject constructor(
private val authService: AuthService
Expand All @@ -14,4 +15,10 @@ class AuthRemoteDataSourceImpl @Inject constructor(
requestAuthDto: RequestAuthDto
): ResponseAuthDto =
authService.postLogin(kakaoAccessToken, requestAuthDto).data

override suspend fun logout(): NullableBaseResponse<String> =
authService.logout()

override suspend fun withDraw(): NullableBaseResponse<String> =
authService.withDraw()
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,14 @@ class AuthRepositoryImpl @Inject constructor(
runCatching {
authRemoteDataSource.login(kakaoAccessToken, requestAuthDto).toAuthModel()
}

override suspend fun logout(): Result<Int> =
runCatching {
authRemoteDataSource.logout().code
}

override suspend fun withDraw(): Result<Int> =
runCatching {
authRemoteDataSource.withDraw().code
}
}
8 changes: 8 additions & 0 deletions app/src/main/java/org/sopt/pingle/data/service/AuthService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package org.sopt.pingle.data.service
import org.sopt.pingle.data.model.remote.request.RequestAuthDto
import org.sopt.pingle.data.model.remote.response.ResponseAuthDto
import org.sopt.pingle.util.base.BaseResponse
import org.sopt.pingle.util.base.NullableBaseResponse
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.Header
import retrofit2.http.POST

Expand All @@ -13,4 +15,10 @@ interface AuthService {
@Header("X-Provider-Token") header: String,
@Body body: RequestAuthDto
): BaseResponse<ResponseAuthDto>

@POST("/v1/auth/logout")
suspend fun logout(): NullableBaseResponse<String>

@DELETE("/v1/users/leave")
suspend fun withDraw(): NullableBaseResponse<String>
}
23 changes: 23 additions & 0 deletions app/src/main/java/org/sopt/pingle/data/service/KakaoAuthService.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.sopt.pingle.data.service

import android.content.ContentValues.TAG
import android.content.Context
import com.kakao.sdk.auth.model.OAuthToken
import com.kakao.sdk.user.UserApiClient
Expand Down Expand Up @@ -52,6 +53,28 @@ class KakaoAuthService @Inject constructor(
}
}

fun logoutKakao(logoutListener: () -> Unit) {
UserApiClient.instance.logout { error ->
if (error != null) {
Timber.tag(TAG).e(error, "카카오 로그아웃 실패. SDK에서 토큰 삭제됨")
} else {
logoutListener()
Timber.tag(TAG).i("카카오 로그아웃 성공. SDK에서 토큰 삭제됨")
}
}
}

fun withdrawKakao(withdrawListener: () -> Unit) {
UserApiClient.instance.unlink { error ->
if (error != null) {
Timber.tag(TAG).e(error, "카카오 회원 탈퇴 실패")
} else {
withdrawListener()
Timber.tag(TAG).i("카카오 회원 탈퇴 성공. SDK에서 토큰 삭제 됨")
}
}
}

companion object {
const val KAKAO_TALK = "카카오톡"
const val KAKAO_ACCOUNT = "카카오계정"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,11 @@ import org.sopt.pingle.data.model.remote.request.RequestAuthDto
import org.sopt.pingle.domain.model.AuthEntity

interface AuthRepository {
suspend fun postLogin(kakaoAccessToken: String, requestAuthDto: RequestAuthDto): Result<AuthEntity>
suspend fun postLogin(
kakaoAccessToken: String,
requestAuthDto: RequestAuthDto
): Result<AuthEntity>

suspend fun logout(): Result<Int>
suspend fun withDraw(): Result<Int>
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
package org.sopt.pingle.presentation.ui.main.more

import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.fragment.app.viewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.sopt.pingle.BuildConfig
import org.sopt.pingle.R
import org.sopt.pingle.data.service.KakaoAuthService
import org.sopt.pingle.databinding.FragmentMoreBinding
import org.sopt.pingle.presentation.ui.auth.AuthActivity
import org.sopt.pingle.util.base.BindingFragment
import org.sopt.pingle.util.component.AllModalDialogFragment
import org.sopt.pingle.util.view.UiState
import timber.log.Timber

@AndroidEntryPoint
class MoreFragment : BindingFragment<FragmentMoreBinding>(R.layout.fragment_more) {
@Inject
lateinit var kakaoAuthService: KakaoAuthService
private val moreViewModel: MoreViewModel by viewModels()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

initLayout()
addListeners()
collectData()
}

private fun initLayout() {
Expand All @@ -31,6 +47,43 @@ class MoreFragment : BindingFragment<FragmentMoreBinding>(R.layout.fragment_more
}
}

private fun collectData() {
moreViewModel.logoutState.flowWithLifecycle(lifecycle).onEach { logoutState ->
when (logoutState) {
is UiState.Success -> {
moveToSign()
}

is UiState.Error -> {
Timber.d("로그아웃 실패")
}

else -> {}
}
}.launchIn(lifecycleScope)

moreViewModel.withDrawState.flowWithLifecycle(lifecycle).onEach { withDrawState ->
when (withDrawState) {
is UiState.Success -> {
moveToSign()
}

is UiState.Error -> {
Timber.d("로그아웃 실패")
}

else -> {}
}
}.launchIn(lifecycleScope)
}

private fun moveToSign() {
val intent = Intent(requireContext(), AuthActivity::class.java)
intent.flags =
Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
}

private fun showLogoutDialogFragment() {
AllModalDialogFragment(
title = getString(R.string.setting_logout_modal_title),
Expand All @@ -39,7 +92,7 @@ class MoreFragment : BindingFragment<FragmentMoreBinding>(R.layout.fragment_more
textButtonText = getString(R.string.setting_logout_modal_btn_text),
clickBtn = {},
clickTextBtn = {
// TODO 로그아웃 서버통신
kakaoAuthService.logoutKakao(moreViewModel::logout)
},
onDialogClosed = {}
).show(parentFragmentManager, LOGOUT_MODAL)
Expand All @@ -53,7 +106,7 @@ class MoreFragment : BindingFragment<FragmentMoreBinding>(R.layout.fragment_more
textButtonText = getString(R.string.setting_withdraw_modal_btn_text),
clickBtn = { },
clickTextBtn = {
// TODO 회원탈퇴 서버통신
kakaoAuthService.withdrawKakao(moreViewModel::withDraw)
},
onDialogClosed = {}
).show(parentFragmentManager, WITHDRAW_MODAL)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package org.sopt.pingle.presentation.ui.main.more

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import org.sopt.pingle.data.datasource.local.PingleLocalDataSource
import org.sopt.pingle.domain.repository.AuthRepository
import org.sopt.pingle.util.view.UiState

@HiltViewModel
class MoreViewModel @Inject constructor(
private val authRepository: AuthRepository,
private val pingleLocalDataSource: PingleLocalDataSource
) : ViewModel() {
private val _logoutState = MutableStateFlow<UiState<Boolean>>(UiState.Empty)
val logoutState get() = _logoutState.asStateFlow()

private val _withDrawState = MutableStateFlow<UiState<Boolean>>(UiState.Empty)
val withDrawState get() = _withDrawState.asStateFlow()

fun logout() {
viewModelScope.launch {
authRepository.logout()
.onSuccess { code ->
if (code == SUCCESS_CODE) {
_logoutState.value = UiState.Success(true)
pingleLocalDataSource.clear()
} else {
_logoutState.value = UiState.Error(null)
}
}.onFailure { throwable ->
_logoutState.value = UiState.Error(throwable.message)
}
}
}

fun withDraw() {
viewModelScope.launch {
authRepository.withDraw()
.onSuccess { code ->
if (code == SUCCESS_CODE) {
_withDrawState.value = UiState.Success(true)
pingleLocalDataSource.clear()
} else {
_withDrawState.value = UiState.Error(null)
}
}.onFailure { throwable ->
_withDrawState.value = UiState.Error(throwable.message)
}
}
}

companion object {
const val SUCCESS_CODE = 200
}
}

0 comments on commit 1bcb0e0

Please sign in to comment.