Skip to content

Commit

Permalink
[feat] #8 회원가입 뷰 - 유저 등록 API 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
HAJIEUN02 committed Nov 5, 2024
1 parent cd5e05e commit a0d3380
Show file tree
Hide file tree
Showing 11 changed files with 179 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.sopt.and.data.datasource.remote

import org.sopt.and.data.model.request.RequestUserLoginDto
import org.sopt.and.data.model.request.RequestUserRegisterDto
import org.sopt.and.data.model.response.ResponseLoginTokenDto
import org.sopt.and.data.model.response.ResponseRegisterNumberDto
import org.sopt.and.presentation.util.BaseResponse

interface AuthRemoteDataSource {
suspend fun register(requestUserRegisterDto: RequestUserRegisterDto): BaseResponse<ResponseRegisterNumberDto>

suspend fun login(requestUserLoginDto: RequestUserLoginDto): BaseResponse<ResponseLoginTokenDto>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.sopt.and.data.datasourceImpl.remote

import org.sopt.and.data.datasource.remote.AuthRemoteDataSource
import org.sopt.and.data.model.request.RequestUserLoginDto
import org.sopt.and.data.model.request.RequestUserRegisterDto
import org.sopt.and.data.model.response.ResponseLoginTokenDto
import org.sopt.and.data.model.response.ResponseRegisterNumberDto
import org.sopt.and.data.service.AuthService
import org.sopt.and.presentation.util.BaseResponse
import javax.inject.Inject

class AuthRemoteDataSourceImpl @Inject constructor(
private val authService: AuthService
) : AuthRemoteDataSource {
override suspend fun register(requestUserRegisterDto: RequestUserRegisterDto): BaseResponse<ResponseRegisterNumberDto> =
authService.postRegister(requestUserRegisterDto)

override suspend fun login(requestUserLoginDto: RequestUserLoginDto): BaseResponse<ResponseLoginTokenDto> =
authService.postLogin(requestUserLoginDto)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.sopt.and.data.repositoryImpl

import org.sopt.and.data.datasource.remote.AuthRemoteDataSource
import org.sopt.and.domain.model.UserIdEntity
import org.sopt.and.domain.model.UserRegisterEntity
import org.sopt.and.domain.repository.AuthRepository
import javax.inject.Inject

class AuthRepositoryImpl @Inject constructor(
private val authRemoteDataSource: AuthRemoteDataSource
) : AuthRepository {
override suspend fun postRegister(userRegisterEntity: UserRegisterEntity): Result<UserIdEntity> =
runCatching {
authRemoteDataSource.register(requestUserRegisterDto = userRegisterEntity.toRequestUserRegisterDto()).result.toUserIdEntity()
}
}
26 changes: 26 additions & 0 deletions app/src/main/java/org/sopt/and/data/service/AuthService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.sopt.and.data.service

import org.sopt.and.data.model.request.RequestUserLoginDto
import org.sopt.and.data.model.request.RequestUserRegisterDto
import org.sopt.and.data.model.response.ResponseLoginTokenDto
import org.sopt.and.data.model.response.ResponseRegisterNumberDto
import org.sopt.and.presentation.util.BaseResponse
import retrofit2.http.Body
import retrofit2.http.POST

interface AuthService {
@POST("/$USER")
suspend fun postRegister(
@Body body: RequestUserRegisterDto
): BaseResponse<ResponseRegisterNumberDto>

@POST("/$LOGIN")
suspend fun postLogin(
@Body body: RequestUserLoginDto
): BaseResponse<ResponseLoginTokenDto>

companion object {
const val USER = "user"
const val LOGIN = "login"
}
}
6 changes: 6 additions & 0 deletions app/src/main/java/org/sopt/and/di/DataSourceModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.sopt.and.data.datasource.local.WaveLocalDataSource
import org.sopt.and.data.datasource.remote.AuthRemoteDataSource
import org.sopt.and.data.datasourceImpl.local.WaveLocalDataSourceImpl
import org.sopt.and.data.datasourceImpl.remote.AuthRemoteDataSourceImpl
import javax.inject.Singleton

@Module
Expand All @@ -14,4 +16,8 @@ abstract class DataSourceModule {
@Binds
@Singleton
abstract fun bindsWaveLocalDataSource(waveLocalDataSourceImpl: WaveLocalDataSourceImpl): WaveLocalDataSource

@Binds
@Singleton
abstract fun bindsAuthRemoteDataSource(authRemoteDataSourceImpl: AuthRemoteDataSourceImpl): AuthRemoteDataSource
}
17 changes: 17 additions & 0 deletions app/src/main/java/org/sopt/and/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.sopt.and.di

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.sopt.and.data.repositoryImpl.AuthRepositoryImpl
import org.sopt.and.domain.repository.AuthRepository
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
@Binds
@Singleton
abstract fun bindsAuthRepository(authRepositoryImpl: AuthRepositoryImpl): AuthRepository
}
18 changes: 18 additions & 0 deletions app/src/main/java/org/sopt/and/di/ServiceModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.sopt.and.di

import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.sopt.and.data.service.AuthService
import retrofit2.Retrofit
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object ServiceModule {
@Provides
@Singleton
fun providesAuthService(@Wave retrofit: Retrofit): AuthService =
retrofit.create(AuthService::class.java)
}
18 changes: 18 additions & 0 deletions app/src/main/java/org/sopt/and/di/UseCaseModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.sopt.and.di

import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.sopt.and.domain.repository.AuthRepository
import org.sopt.and.domain.usecase.PostUserRegisterUseCase
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
class UseCaseModule {
@Provides
@Singleton
fun providesUserRegisterUseCase(authRepository: AuthRepository): PostUserRegisterUseCase =
PostUserRegisterUseCase(authRepository = authRepository)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.sopt.and.domain.repository

import org.sopt.and.domain.model.UserIdEntity
import org.sopt.and.domain.model.UserRegisterEntity

interface AuthRepository {
suspend fun postRegister(userRegisterEntity: UserRegisterEntity): Result<UserIdEntity>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.sopt.and.domain.usecase

import org.sopt.and.domain.model.UserIdEntity
import org.sopt.and.domain.model.UserRegisterEntity
import org.sopt.and.domain.repository.AuthRepository

class PostUserRegisterUseCase(
private val authRepository: AuthRepository
) {
suspend operator fun invoke(userRegisterEntity: UserRegisterEntity): Result<UserIdEntity> =
authRepository.postRegister(userRegisterEntity = userRegisterEntity)
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package org.sopt.and.presentation.ui.auth.register

import dagger.hilt.android.lifecycle.HiltViewModel
import org.sopt.and.data.datasource.local.WaveLocalDataSource
import org.sopt.and.domain.model.UserRegisterEntity
import org.sopt.and.domain.usecase.PostUserRegisterUseCase
import org.sopt.and.presentation.util.BaseViewModel
import timber.log.Timber
import javax.inject.Inject

@HiltViewModel
class RegisterViewModel @Inject constructor(
private val localDataStorage: WaveLocalDataSource
) : BaseViewModel<RegisterContract.RegisterEvent, RegisterContract.RegisterState, RegisterContract.RegisterEffect>() {
private val postUserRegisterUseCase: PostUserRegisterUseCase
) :
BaseViewModel<RegisterContract.RegisterEvent, RegisterContract.RegisterState, RegisterContract.RegisterEffect>() {

override fun createInitialState(): RegisterContract.RegisterState {
return RegisterContract.RegisterState()
Expand All @@ -23,25 +25,35 @@ class RegisterViewModel @Inject constructor(

override suspend fun handleEvent(event: RegisterContract.RegisterEvent) {
when (event) {
is RegisterContract.RegisterEvent.EmailChanged -> {
setState(currentUiState.copy(email = event.email))
Timber.tag("[회원가입]").d("이메일 변경 :${event.email}")
is RegisterContract.RegisterEvent.UsernameChanged -> {
setState(currentUiState.copy(username = event.username))
Timber.tag("[회원가입]").d("이름 변경 :${event.username}")
}

is RegisterContract.RegisterEvent.PasswordChanged -> {
setState(currentUiState.copy(password = event.password))
Timber.tag("[회원가입]").d("비밀번호 변경 : ${event.password}")
}

is RegisterContract.RegisterEvent.HobbyChanged -> {
setState(currentUiState.copy(hobby = event.hobby))
Timber.tag("[회원가입]").d("취미 변경 : ${event.hobby}")
}

is RegisterContract.RegisterEvent.PasswordVisibilityChanged -> {
setState(currentUiState.copy(showPassword = !currentUiState.showPassword))
Timber.tag("[회원가입]").d("showPassword 변경 : ${currentUiState.showPassword}")
}

is RegisterContract.RegisterEvent.OnRegisterBtnClicked -> {
if (checkIsValidEmail() && checkIsValidPassword()) {
setLocalUserEmail()
setLocalUserPassword()
if (checkIsValidUsername() && checkIsValidPassword() && checkIsValidHobby()) {
postUserRegisterUseCase(
userRegisterEntity = UserRegisterEntity(
username = currentUiState.username,
userPassword = currentUiState.password,
userHobby = currentUiState.hobby
)
)
setState(currentUiState.copy(registerStatus = RegisterContract.RegisterStatus.Success))
} else {
setEffect(RegisterContract.RegisterEffect.ShowToast(message = event.message))
Expand All @@ -51,29 +63,13 @@ class RegisterViewModel @Inject constructor(
}
}

private fun checkIsValidEmail(): Boolean {
Timber.tag("[회원가입]").d("Email 검사 ${currentUiState.email}")
return currentUiState.email.matches(REGEX_EMAIL.toRegex())
}
private fun checkIsValidUsername(): Boolean = (currentUiState.username.length <= MAX_LENGTH)

private fun checkIsValidPassword(): Boolean {
Timber.tag("[회원가입]").d("비밀번호 검사 ${currentUiState.password}")
return currentUiState.password.matches(REGEX_PASSWORD.toRegex())
}
private fun checkIsValidPassword(): Boolean = (currentUiState.password.length <= MAX_LENGTH)

private fun setLocalUserEmail() {
localDataStorage.userEmail = currentUiState.email
Timber.tag("[회원가입]").d("이메일 저장 : ${localDataStorage.userEmail}")
}

private fun setLocalUserPassword() {
localDataStorage.userPassword = currentUiState.password
Timber.tag("[회원가입]").d("비밀번호 저장 : ${localDataStorage.userPassword}")
}
private fun checkIsValidHobby(): Boolean = (currentUiState.hobby.length <= MAX_LENGTH)

companion object {
const val REGEX_EMAIL = "[0-9a-zA-Z]+(.[_a-z0-9-]+)*@(?:\\w+\\.)+\\w+$"
const val REGEX_PASSWORD =
"^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@$!%*#?&.])[A-Za-z[0-9]$@$!%*#?&.]{8,20}$"
const val MAX_LENGTH = 8
}
}

0 comments on commit a0d3380

Please sign in to comment.