Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,36 @@ import com.core.dataapi.repository.LoginRepository
import com.core.datastore.datasource.DataStoreDataSource
import com.core.exception.NoDataException
import com.youthtalk.data.LoginService
import com.youthtalk.dto.MemberId
import com.youthtalk.dto.login.LoginRequest
import com.youthtalk.dto.login.SignRequest
import com.youthtalk.model.typeenum.toRegion
import com.youthtalk.utils.ErrorUtils.throwableError
import com.youthtalk.utils.ErrorUtils.createResult
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import timber.log.Timber

class LoginRepositoryImpl @Inject constructor(
private val loginService: LoginService,
private val dataStoreDataSource: DataStoreDataSource
) : LoginRepository {
override fun postLogin(socialId: String): Flow<Long> = flow {
Timber.e("LoginRepositoryImpl postLogin start")
runCatching { loginService.postLogin(LoginRequest(socialType = "kakao", socialId = socialId).toRequestBody()) }
.onSuccess { token ->
Timber.e("LoginRepositoryImpl postLogin Success $token")
token.data?.let { data ->
emit(data.memberId)
} ?: throw NoDataException()
}
.onFailure { error ->
Timber.e("LoginRepositoryImpl postLogin error : $error")
throwableError<MemberId>(error)
}
override suspend fun postLogin(socialId: String): Result<Long> = createResult {
loginService.postLogin(LoginRequest(socialType = "kakao", socialId = socialId).toRequestBody()).data?.memberId ?: throw NoDataException()
}.onFailure { error ->
Timber.e("error : $error")
}

override fun hasToken(): Flow<Boolean> = dataStoreDataSource.hasToken()

override fun postSign(id: String, nickname: String, region: String): Flow<Int> = flow {
Timber.e("LoginRepositoryImpl start")
runCatching {
loginService.postSignUp(
SignRequest(
socialType = "kakao",
socialId = id,
nickname = nickname,
region = region.toRegion().region
).toRequestBody()
)
}
.onSuccess { response ->
Timber.e("LoginRepositoryImpl Success $response")
response.data?.let {
emit(it)
} ?: throw NoDataException()
}
.onFailure { error ->
Timber.e("LoginRepositoryImpl error : $error")
throwableError<Int>(error)
}
override suspend fun postSign(id: String, nickname: String, region: String): Result<Int> = createResult {
loginService.postSignUp(
SignRequest(
socialType = "kakao",
socialId = id,
nickname = nickname,
region = region.toRegion().region
).toRequestBody()
).data ?: throw NoDataException()
}.onFailure { error ->
Timber.e("error : $error")
}
}
3 changes: 2 additions & 1 deletion core/data/src/main/java/com/youthtalk/utils/ErrorUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.core.exception.NotPermissionMethod
import com.core.exception.UnAuthorizedException
import com.youthtalk.dto.CommonResponse
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import retrofit2.HttpException
import timber.log.Timber

Expand Down Expand Up @@ -48,7 +49,7 @@ object ErrorUtils {

inline fun <reified T> mapToCustomException(it: HttpException): Exception {
val error = it.response()?.errorBody()?.string() ?: throw InvalidValueException(it.message)
val response = Json.decodeFromString<CommonResponse<T>>(error)
val response = Json.decodeFromString<CommonResponse<JsonElement?>>(error)
return when (it.code()) {
401 -> UnAuthorizedException(response.message)
404 -> NotFoundResource(response.message)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package com.youthtalk.repository

import com.core.datastore.datasource.DataStoreDataSource
import com.core.exception.BadRequestException
import com.core.exception.UnAuthorizedException
import com.youthtalk.data.LoginService
import com.youthtalk.dto.CommonResponse
import com.youthtalk.dto.MemberId
import com.youthtalk.dto.login.LoginRequest
import com.youthtalk.dto.login.SignRequest
import com.youthtalk.dto.toResponseBody
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.Assert
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.any
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import retrofit2.HttpException
import retrofit2.Response

@RunWith(MockitoJUnitRunner::class)
class LoginRepositoryTest {

@InjectMocks
private lateinit var sut: LoginRepositoryImpl

@Mock
private lateinit var loginService: LoginService

@Mock
private lateinit var dataStoreDataSource: DataStoreDataSource

@Test
fun givenSocialId_whenLogin_thenReturnsMemberId() {
runTest {
// given
val socialId = "88888"
val memberId = 23L
val loginRequest = LoginRequest(socialType = "kakao", socialId = socialId)

whenever(loginService.postLogin(any())).thenReturn(CommonResponse(200, "요청에 성공하였습니다", "S01", MemberId(memberId)))

// when
val result = sut.postLogin(socialId).getOrThrow()

// then
assertEquals(memberId, result)
verify(loginService).postLogin(any())
}
}

@Test
fun givenWrongSocialId_whenLogin_thenThrowsNull() {
runTest {
// given
val socialId = "xxxxxx"
val memberId = null
val loginRequest = LoginRequest(socialType = "kakao", socialId = socialId)

whenever(loginService.postLogin(any())).thenThrow(
HttpException(
Response.error<Any>(
401,
toResponseBody(CommonResponse<Unit?>(401, "회원이 아닙니다.", "F01", memberId))
)
)
)

// when
Assert.assertThrows(UnAuthorizedException::class.java) {
runBlocking {
sut.postLogin(socialId).getOrThrow()
}
}

// then
verify(loginService).postLogin(any())
}
}

@Test
fun givenSignInfo_whenSignUp_thenReturnsMemberId() {
runTest {
val socialId = "666666"
val socialType = "kakao"
val nickname = "압도적도적"
val region = "서울"
val memberId = 23

val signUpRequest = SignRequest(socialType, socialId, nickname, region)
whenever(loginService.postSignUp(any())).thenReturn(CommonResponse(200, "요청에 성공하였습니다", "S01", memberId))

// when
val result = sut.postSign(socialId, nickname, region).getOrThrow()

// then
assertEquals(memberId, result)
verify(loginService).postSignUp(any())
}
}

@Test
fun givenWrongRegion_whenSignUp_thenThrows400Exception() {
runTest {
val socialId = "666666"
val socialType = "kakao"
val nickname = "압도적도적"
val region = "없는지역"
val memberId = 23

whenever(loginService.postSignUp(any())).thenThrow(
HttpException(
Response.error<Any>(
400,
toResponseBody(CommonResponse<ArrayList<String>>(400, "유효하지 않은 값을 입력하였습니다.", "F01", arrayListOf("지역이 유효하지 않습니다.")))
)
)
)

// when
Assert.assertThrows(BadRequestException::class.java) {
runBlocking {
sut.postSign(socialId, nickname, region).getOrThrow()
}
}

// then
verify(loginService).postSignUp(any())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package com.core.dataapi.repository
import kotlinx.coroutines.flow.Flow

interface LoginRepository {
fun postLogin(socialId: String): Flow<Long>
suspend fun postLogin(socialId: String): Result<Long>

fun hasToken(): Flow<Boolean>

fun postSign(id: String, nickname: String, region: String): Flow<Int>
suspend fun postSign(id: String, nickname: String, region: String): Result<Int>
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ import javax.inject.Inject
class PostLoginUseCase @Inject constructor(
private val loginRepository: LoginRepository
) {
operator fun invoke(socialId: String) = loginRepository.postLogin(socialId)
suspend operator fun invoke(socialId: String) = loginRepository.postLogin(socialId)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package com.core.domain.usercase.user

import com.core.dataapi.repository.LoginRepository
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flatMapMerge

class PostSignUseCase @Inject constructor(
private val loginRepository: LoginRepository
) {
@OptIn(ExperimentalCoroutinesApi::class)
operator fun invoke(id: String, nickname: String, region: String) = loginRepository.postSign(id, nickname, region)
.flatMapMerge { loginRepository.postLogin(id) }
suspend operator fun invoke(id: String, nickname: String, region: String): Result<Long> {
val signResult = loginRepository.postSign(id, nickname, region)
if (signResult.isFailure) return Result.failure(signResult.exceptionOrNull()!!)

return loginRepository.postLogin(id)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
package com.core.exception

class BadRequestException(
override val message: String?
): Exception()
class BadRequestException(override val message: String?) : RuntimeException()
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
package com.core.exception

class InvalidValueException(
private val m: String? = "InvalidValueException"
): Exception() {
override val message: String?
get() = m
}
class InvalidValueException(override val message: String? = "InvalidValueException") : RuntimeException()
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
package com.core.exception

class NetworkErrorException(
private val m: String? = "NetworkErrorException"
) : Exception() {
override val message: String?
get() = m
}
class NetworkErrorException(override val message: String? = "NetworkErrorException") : RuntimeException()
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
package com.core.exception

class NoDataException(
private val m: String? = "NoDataException"
): Exception() {
override val message: String?
get() = m
}
class NoDataException(override val message: String? = "NoDataException") : RuntimeException()
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
package com.core.exception

class NotFoundResource(
private val m: String? = "NotFoundResource"
): Exception() {
override val message: String?
get() = m
}
class NotFoundResource(override val message: String? = "NotFoundResource") : RuntimeException()
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
package com.core.exception

class NotPermissionMethod(
private val m: String? = "NotPermissionMethod"
): Exception() {
override val message: String?
get() = m
}
class NotPermissionMethod(override val message: String? = "NotPermissionMethod") : RuntimeException()
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
package com.core.exception

//401 에러 Exception
class UnAuthorizedException(
private val errorMessage : String? = "UnAuthorizedException"
) : Exception() {
override val message: String?
get() = errorMessage
}
class UnAuthorizedException(override val message: String? = "UnAuthorizedException") : RuntimeException()
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ fun CommunityDetailScreen(
is CommunityDetailUiEffect.ShowSnackBarReportFail -> {
showSnackBar(it.message.toString())
}

is CommunityDetailUiEffect.InitError -> {
showSnackBar(it.message)
onBack()
Expand All @@ -154,7 +154,6 @@ fun CommunityDetailScreen(
showSnackBar(context.getString(R.string.block_user_snackbar_message, it.userName))
onBack()
}

}
}
}
Expand Down Expand Up @@ -259,7 +258,6 @@ fun CommunityDetailScreen(
}
)
}

}

@OptIn(ExperimentalMaterial3Api::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ class CommunityDetailViewModel @Inject constructor(
}
}
}

private fun initData(postId: Long) {
viewModelScope.launch {
combine(
Expand Down
Loading