diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..4bec4ea8 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,117 @@ + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..a55e7a17 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/dictionaries/jaino.xml b/.idea/dictionaries/jaino.xml new file mode 100644 index 00000000..8bf92705 --- /dev/null +++ b/.idea/dictionaries/jaino.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4aae73fa..7a8fccfd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ - + - \ No newline at end of file + diff --git a/core/data/src/main/java/com/wap/wapp/core/data/repository/di/AuthRepositoryModule.kt b/core/data/src/main/java/com/wap/wapp/core/data/di/AuthRepositoryModule.kt similarity index 92% rename from core/data/src/main/java/com/wap/wapp/core/data/repository/di/AuthRepositoryModule.kt rename to core/data/src/main/java/com/wap/wapp/core/data/di/AuthRepositoryModule.kt index 799eddcb..4b8f157e 100644 --- a/core/data/src/main/java/com/wap/wapp/core/data/repository/di/AuthRepositoryModule.kt +++ b/core/data/src/main/java/com/wap/wapp/core/data/di/AuthRepositoryModule.kt @@ -1,4 +1,4 @@ -package com.wap.wapp.core.data.repository.di +package com.wap.wapp.core.data.di import com.wap.wapp.core.data.repository.auth.AuthRepository import com.wap.wapp.core.data.repository.auth.AuthRepositoryImpl diff --git a/core/data/src/main/java/com/wap/wapp/core/data/di/DataModule.kt b/core/data/src/main/java/com/wap/wapp/core/data/di/DataModule.kt new file mode 100644 index 00000000..2ebbd53d --- /dev/null +++ b/core/data/src/main/java/com/wap/wapp/core/data/di/DataModule.kt @@ -0,0 +1,19 @@ +package com.wap.wapp.core.data.di + +import com.wap.wapp.core.data.repository.user.UserRepository +import com.wap.wapp.core.data.repository.user.UserRepositoryImpl +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class DataModule { + @Binds + @Singleton + abstract fun providesUserRepository( + userRepositoryImpl: UserRepositoryImpl, + ): UserRepository +} diff --git a/core/data/src/main/java/com/wap/wapp/core/data/repository/auth/AuthRepository.kt b/core/data/src/main/java/com/wap/wapp/core/data/repository/auth/AuthRepository.kt index 20c718ec..1c423020 100644 --- a/core/data/src/main/java/com/wap/wapp/core/data/repository/auth/AuthRepository.kt +++ b/core/data/src/main/java/com/wap/wapp/core/data/repository/auth/AuthRepository.kt @@ -4,4 +4,8 @@ interface AuthRepository { suspend fun hasPendingResult(): Boolean suspend fun signIn(email: String): Result + + suspend fun signOut(): Result + + suspend fun deleteUser(): Result } diff --git a/core/data/src/main/java/com/wap/wapp/core/data/repository/auth/AuthRepositoryImpl.kt b/core/data/src/main/java/com/wap/wapp/core/data/repository/auth/AuthRepositoryImpl.kt index 01146642..e7b7815f 100644 --- a/core/data/src/main/java/com/wap/wapp/core/data/repository/auth/AuthRepositoryImpl.kt +++ b/core/data/src/main/java/com/wap/wapp/core/data/repository/auth/AuthRepositoryImpl.kt @@ -13,4 +13,12 @@ class AuthRepositoryImpl @Inject constructor( override suspend fun signIn(email: String): Result { return authDataSource.signIn(email) } + + override suspend fun signOut(): Result { + return authDataSource.signOut() + } + + override suspend fun deleteUser(): Result { + return authDataSource.deleteUser() + } } diff --git a/core/data/src/main/java/com/wap/wapp/core/data/repository/user/UserRepository.kt b/core/data/src/main/java/com/wap/wapp/core/data/repository/user/UserRepository.kt new file mode 100644 index 00000000..f5039061 --- /dev/null +++ b/core/data/src/main/java/com/wap/wapp/core/data/repository/user/UserRepository.kt @@ -0,0 +1,14 @@ +package com.wap.wapp.core.data.repository.user + +import com.wap.wapp.core.model.user.UserProfile + +interface UserRepository { + suspend fun getUserProfile(userId: String): Result + + suspend fun postUserProfile( + userId: String, + userName: String, + studentId: String, + registeredAt: String, + ): Result +} diff --git a/core/data/src/main/java/com/wap/wapp/core/data/repository/user/UserRepositoryImpl.kt b/core/data/src/main/java/com/wap/wapp/core/data/repository/user/UserRepositoryImpl.kt new file mode 100644 index 00000000..0490832c --- /dev/null +++ b/core/data/src/main/java/com/wap/wapp/core/data/repository/user/UserRepositoryImpl.kt @@ -0,0 +1,32 @@ +package com.wap.wapp.core.data.repository.user + +import com.wap.wapp.core.model.user.UserProfile +import com.wap.wapp.core.network.model.user.UserProfileRequest +import com.wap.wapp.core.network.source.user.UserDataSource +import javax.inject.Inject + +class UserRepositoryImpl @Inject constructor( + private val userDataSource: UserDataSource, +) : UserRepository { + override suspend fun getUserProfile(userId: String): Result { + return userDataSource.getUserProfile(userId).mapCatching { response -> + response.toDomain() + } + } + + override suspend fun postUserProfile( + userId: String, + userName: String, + studentId: String, + registeredAt: String, + ): Result { + return userDataSource.postUserProfile( + UserProfileRequest( + userId = userId, + userName = userName, + studentId = studentId, + registeredAt = registeredAt, + ), + ) + } +} diff --git a/core/domain/src/main/java/com/wap/wapp/core/domain/auth/SignInUseCase.kt b/core/domain/src/main/java/com/wap/wapp/core/domain/auth/SignInUseCase.kt deleted file mode 100644 index 5677fe94..00000000 --- a/core/domain/src/main/java/com/wap/wapp/core/domain/auth/SignInUseCase.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.wap.wapp.core.domain.auth - -import com.wap.wapp.core.data.repository.auth.AuthRepository -import dagger.hilt.android.scopes.ActivityScoped -import javax.inject.Inject - -@ActivityScoped -class SignInUseCase @Inject constructor( - private val repository: AuthRepository, -) { - suspend operator fun invoke(email: String): Result = - repository.signIn(email) -} diff --git a/core/domain/src/main/java/com/wap/wapp/core/domain/model/AuthState.kt b/core/domain/src/main/java/com/wap/wapp/core/domain/model/AuthState.kt new file mode 100644 index 00000000..e603e17d --- /dev/null +++ b/core/domain/src/main/java/com/wap/wapp/core/domain/model/AuthState.kt @@ -0,0 +1,5 @@ +package com.wap.wapp.core.domain.model + +enum class AuthState { + SIGN_IN, SIGN_UP +} diff --git a/core/domain/src/main/java/com/wap/wapp/core/domain/usecase/auth/DeleteUserUseCase.kt b/core/domain/src/main/java/com/wap/wapp/core/domain/usecase/auth/DeleteUserUseCase.kt new file mode 100644 index 00000000..3c08f196 --- /dev/null +++ b/core/domain/src/main/java/com/wap/wapp/core/domain/usecase/auth/DeleteUserUseCase.kt @@ -0,0 +1,13 @@ +package com.wap.wapp.core.domain.usecase.auth + +import com.wap.wapp.core.data.repository.auth.AuthRepository +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class DeleteUserUseCase @Inject constructor( + private val authRepository: AuthRepository, +) { + suspend operator fun invoke(): Result = + authRepository.deleteUser() +} diff --git a/core/domain/src/main/java/com/wap/wapp/core/domain/usecase/auth/SignInUseCase.kt b/core/domain/src/main/java/com/wap/wapp/core/domain/usecase/auth/SignInUseCase.kt new file mode 100644 index 00000000..04df5309 --- /dev/null +++ b/core/domain/src/main/java/com/wap/wapp/core/domain/usecase/auth/SignInUseCase.kt @@ -0,0 +1,38 @@ +package com.wap.wapp.core.domain.usecase.auth + +import com.wap.wapp.core.data.repository.auth.AuthRepository +import com.wap.wapp.core.data.repository.user.UserRepository +import com.wap.wapp.core.domain.model.AuthState +import com.wap.wapp.core.domain.model.AuthState.SIGN_IN +import com.wap.wapp.core.domain.model.AuthState.SIGN_UP +import dagger.hilt.android.scopes.ActivityScoped +import javax.inject.Inject + +@ActivityScoped +class SignInUseCase @Inject constructor( + private val authRepository: AuthRepository, + private val userRepository: UserRepository, +) { + suspend operator fun invoke(email: String): Result { + return runCatching { + val userId = authRepository.signIn(email) + .getOrThrow() + + userRepository.getUserProfile(userId) + .fold( + onFailure = { exception -> + // 사용자를 조회할 수 없는 예외인 경우 + val userNotFoundException = IllegalStateException() + if (exception == userNotFoundException) { + SIGN_UP + } + // 이외의 예외라면, + throw (exception) + }, + onSuccess = { + SIGN_IN + }, + ) + } + } +} diff --git a/core/domain/src/main/java/com/wap/wapp/core/domain/usecase/auth/SignOutUseCase.kt b/core/domain/src/main/java/com/wap/wapp/core/domain/usecase/auth/SignOutUseCase.kt new file mode 100644 index 00000000..eae7758b --- /dev/null +++ b/core/domain/src/main/java/com/wap/wapp/core/domain/usecase/auth/SignOutUseCase.kt @@ -0,0 +1,13 @@ +package com.wap.wapp.core.domain.usecase.auth + +import com.wap.wapp.core.data.repository.auth.AuthRepository +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class SignOutUseCase @Inject constructor( + private val authRepository: AuthRepository, +) { + suspend operator fun invoke(): Result = + authRepository.signOut() +} diff --git a/core/domain/src/main/java/com/wap/wapp/core/domain/usecase/user/PostUserProfileUseCase.kt b/core/domain/src/main/java/com/wap/wapp/core/domain/usecase/user/PostUserProfileUseCase.kt new file mode 100644 index 00000000..136b9ddc --- /dev/null +++ b/core/domain/src/main/java/com/wap/wapp/core/domain/usecase/user/PostUserProfileUseCase.kt @@ -0,0 +1,24 @@ +package com.wap.wapp.core.domain.usecase.user + +import com.wap.wapp.core.data.repository.user.UserRepository +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class PostUserProfileUseCase @Inject constructor( + private val userRepository: UserRepository, +) { + suspend operator fun invoke( + userId: String, + userName: String, + studentId: String, + registeredAt: String, + ): Result { + return userRepository.postUserProfile( + userId = userId, + userName = userName, + studentId = studentId, + registeredAt = registeredAt, + ) + } +} diff --git a/core/network/src/main/java/com/wap/wapp/core/network/model/auth/SignUpRequest.kt b/core/model/src/main/java/com/wap/wapp/core/model/user/UserProfile.kt similarity index 60% rename from core/network/src/main/java/com/wap/wapp/core/network/model/auth/SignUpRequest.kt rename to core/model/src/main/java/com/wap/wapp/core/model/user/UserProfile.kt index ea92c9a2..dfa5cd61 100644 --- a/core/network/src/main/java/com/wap/wapp/core/network/model/auth/SignUpRequest.kt +++ b/core/model/src/main/java/com/wap/wapp/core/model/user/UserProfile.kt @@ -1,6 +1,6 @@ -package com.wap.wapp.core.network.model.auth +package com.wap.wapp.core.model.user -data class SignUpRequest( +data class UserProfile( val userId: String, val userName: String, val studentId: String, diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index e9672135..ac30dff5 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -23,6 +23,7 @@ android { } dependencies { + implementation(project(":core:model")) implementation(platform(libs.firebase.bom)) implementation(libs.firebase.auth) implementation(libs.firebase.firestore) diff --git a/core/network/src/main/java/com/wap/wapp/core/network/constant/FirebaseConstant.kt b/core/network/src/main/java/com/wap/wapp/core/network/constant/FirebaseConstant.kt new file mode 100644 index 00000000..e41885d6 --- /dev/null +++ b/core/network/src/main/java/com/wap/wapp/core/network/constant/FirebaseConstant.kt @@ -0,0 +1,6 @@ +package com.wap.wapp.core.network.constant + +/* +파이어스토어 유저 컬렉션 +*/ +const val USER_COLLECTION = "users" diff --git a/core/network/src/main/java/com/wap/wapp/core/network/model/user/UserProfileRequest.kt b/core/network/src/main/java/com/wap/wapp/core/network/model/user/UserProfileRequest.kt new file mode 100644 index 00000000..59968fd6 --- /dev/null +++ b/core/network/src/main/java/com/wap/wapp/core/network/model/user/UserProfileRequest.kt @@ -0,0 +1,15 @@ +package com.wap.wapp.core.network.model.user + +data class UserProfileRequest( + val userId: String, + val userName: String, + val studentId: String, + val registeredAt: String, +) { + constructor() : this( + "", + "", + "", + "", + ) +} diff --git a/core/network/src/main/java/com/wap/wapp/core/network/model/user/UserProfileResponse.kt b/core/network/src/main/java/com/wap/wapp/core/network/model/user/UserProfileResponse.kt index 9d77518b..deb0f61f 100644 --- a/core/network/src/main/java/com/wap/wapp/core/network/model/user/UserProfileResponse.kt +++ b/core/network/src/main/java/com/wap/wapp/core/network/model/user/UserProfileResponse.kt @@ -1,8 +1,24 @@ package com.wap.wapp.core.network.model.user +import com.wap.wapp.core.model.user.UserProfile + data class UserProfileResponse( val userId: String, val userName: String, val studentId: String, val registeredAt: String, -) +) { + constructor() : this( + "", + "", + "", + "", + ) + + fun toDomain(): UserProfile = UserProfile( + userId = userId, + userName = userName, + studentId = studentId, + registeredAt = registeredAt, + ) +} diff --git a/core/network/src/main/java/com/wap/wapp/core/network/source/auth/AuthDataSource.kt b/core/network/src/main/java/com/wap/wapp/core/network/source/auth/AuthDataSource.kt index 8a8009bf..d728e538 100644 --- a/core/network/src/main/java/com/wap/wapp/core/network/source/auth/AuthDataSource.kt +++ b/core/network/src/main/java/com/wap/wapp/core/network/source/auth/AuthDataSource.kt @@ -5,9 +5,7 @@ interface AuthDataSource { suspend fun signIn(email: String): Result - suspend fun signUp(): Result - suspend fun signOut(): Result - suspend fun resign(): Result + suspend fun deleteUser(): Result } diff --git a/core/network/src/main/java/com/wap/wapp/core/network/source/auth/AuthDataSourceImpl.kt b/core/network/src/main/java/com/wap/wapp/core/network/source/auth/AuthDataSourceImpl.kt index 30c73bc4..09b5a1d6 100644 --- a/core/network/src/main/java/com/wap/wapp/core/network/source/auth/AuthDataSourceImpl.kt +++ b/core/network/src/main/java/com/wap/wapp/core/network/source/auth/AuthDataSourceImpl.kt @@ -33,15 +33,18 @@ class AuthDataSourceImpl @Inject constructor( } } - override suspend fun signUp(): Result { - TODO("Not yet implemented") - } - override suspend fun signOut(): Result { - TODO("Not yet implemented") + return runCatching { + firebaseAuth.signOut() + } } - override suspend fun resign(): Result { - TODO("Not yet implemented") + override suspend fun deleteUser(): Result { + return runCatching { + val user = checkNotNull(firebaseAuth.currentUser) + + user.delete() + .await() + } } } diff --git a/core/network/src/main/java/com/wap/wapp/core/network/source/user/UserDataSource.kt b/core/network/src/main/java/com/wap/wapp/core/network/source/user/UserDataSource.kt index 749533b3..4b261118 100644 --- a/core/network/src/main/java/com/wap/wapp/core/network/source/user/UserDataSource.kt +++ b/core/network/src/main/java/com/wap/wapp/core/network/source/user/UserDataSource.kt @@ -1,7 +1,10 @@ package com.wap.wapp.core.network.source.user +import com.wap.wapp.core.network.model.user.UserProfileRequest import com.wap.wapp.core.network.model.user.UserProfileResponse interface UserDataSource { + suspend fun postUserProfile(userProfileRequest: UserProfileRequest): Result + suspend fun getUserProfile(userId: String): Result } diff --git a/core/network/src/main/java/com/wap/wapp/core/network/source/user/UserDataSourceImpl.kt b/core/network/src/main/java/com/wap/wapp/core/network/source/user/UserDataSourceImpl.kt index c40fc34c..093318d1 100644 --- a/core/network/src/main/java/com/wap/wapp/core/network/source/user/UserDataSourceImpl.kt +++ b/core/network/src/main/java/com/wap/wapp/core/network/source/user/UserDataSourceImpl.kt @@ -1,3 +1,44 @@ package com.wap.wapp.core.network.source.user -class UserDataSourceImpl +import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.firestore.SetOptions +import com.wap.wapp.core.network.constant.USER_COLLECTION +import com.wap.wapp.core.network.model.user.UserProfileRequest +import com.wap.wapp.core.network.model.user.UserProfileResponse +import com.wap.wapp.core.network.utils.await +import javax.inject.Inject + +class UserDataSourceImpl @Inject constructor( + private val firebaseFirestore: FirebaseFirestore, +) : UserDataSource { + override suspend fun postUserProfile( + userProfileRequest: UserProfileRequest, + ): Result { + return runCatching { + val userId = userProfileRequest.userId + val setOption = SetOptions.merge() + + firebaseFirestore.collection(USER_COLLECTION) + .document(userId) + .set( + userProfileRequest, + setOption, + ) + .await() + } + } + + override suspend fun getUserProfile( + userId: String, + ): Result { + return runCatching { + val result = firebaseFirestore.collection(USER_COLLECTION) + .document(userId) + .get() + .await() + + val userProfile = result.toObject(UserProfileResponse::class.java) + checkNotNull(userProfile) + } + } +} diff --git a/core/network/src/main/java/com/wap/wapp/core/network/utils/FirebaseUtils.kt b/core/network/src/main/java/com/wap/wapp/core/network/utils/SuspendCoroutine.kt similarity index 100% rename from core/network/src/main/java/com/wap/wapp/core/network/utils/FirebaseUtils.kt rename to core/network/src/main/java/com/wap/wapp/core/network/utils/SuspendCoroutine.kt