#44 first try at firebase use-cases
This commit is contained in:
		
							parent
							
								
									27c45842f2
								
							
						
					
					
						commit
						46824f4498
					
				
					 16 changed files with 294 additions and 7 deletions
				
			
		| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
package be.ugent.sel.studeez.data.local.models
 | 
			
		||||
 | 
			
		||||
data class User(val id: String = "", val isAnonymous: Boolean = true)
 | 
			
		||||
							
								
								
									
										27
									
								
								app/src/main/java/be/ugent/sel/studeez/domain/Performance.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								app/src/main/java/be/ugent/sel/studeez/domain/Performance.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2022 Google LLC
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package be.ugent.sel.studeez.domain
 | 
			
		||||
 | 
			
		||||
import com.google.firebase.perf.ktx.trace
 | 
			
		||||
import com.google.firebase.perf.metrics.Trace
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Trace a block with Firebase performance.
 | 
			
		||||
 *
 | 
			
		||||
 * Supports both suspend and regular methods.
 | 
			
		||||
 */
 | 
			
		||||
inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2022 Google LLC
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package be.ugent.sel.studeez.domain.account
 | 
			
		||||
 | 
			
		||||
import be.ugent.sel.studeez.data.local.models.User
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
 | 
			
		||||
interface AccountService {
 | 
			
		||||
    val currentUserId: String
 | 
			
		||||
    val hasUser: Boolean
 | 
			
		||||
 | 
			
		||||
    val currentUser: Flow<User>
 | 
			
		||||
 | 
			
		||||
    suspend fun authenticate(email: String, password: String)
 | 
			
		||||
    suspend fun sendRecoveryEmail(email: String)
 | 
			
		||||
    suspend fun createAnonymousAccount()
 | 
			
		||||
    suspend fun linkAccount(email: String, password: String)
 | 
			
		||||
    suspend fun deleteAccount()
 | 
			
		||||
    suspend fun signOut()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,84 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2022 Google LLC
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package be.ugent.sel.studeez.domain.account
 | 
			
		||||
 | 
			
		||||
import be.ugent.sel.studeez.data.local.models.User
 | 
			
		||||
import be.ugent.sel.studeez.domain.trace
 | 
			
		||||
import com.google.firebase.auth.EmailAuthProvider
 | 
			
		||||
import com.google.firebase.auth.FirebaseAuth
 | 
			
		||||
import kotlinx.coroutines.channels.awaitClose
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
import kotlinx.coroutines.flow.callbackFlow
 | 
			
		||||
import kotlinx.coroutines.tasks.await
 | 
			
		||||
import javax.inject.Inject
 | 
			
		||||
 | 
			
		||||
class AccountServiceImpl @Inject constructor(
 | 
			
		||||
    private val auth: FirebaseAuth
 | 
			
		||||
) : AccountService {
 | 
			
		||||
 | 
			
		||||
    override val currentUserId: String
 | 
			
		||||
        get() = auth.currentUser?.uid.orEmpty()
 | 
			
		||||
 | 
			
		||||
    override val hasUser: Boolean
 | 
			
		||||
        get() = auth.currentUser != null
 | 
			
		||||
 | 
			
		||||
    override val currentUser: Flow<User>
 | 
			
		||||
        get() = callbackFlow {
 | 
			
		||||
            val listener =
 | 
			
		||||
                FirebaseAuth.AuthStateListener { auth ->
 | 
			
		||||
                    this.trySend(auth.currentUser?.let { User(it.uid, it.isAnonymous) } ?: User())
 | 
			
		||||
                }
 | 
			
		||||
            auth.addAuthStateListener(listener)
 | 
			
		||||
            awaitClose { auth.removeAuthStateListener(listener) }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override suspend fun authenticate(email: String, password: String) {
 | 
			
		||||
        auth.signInWithEmailAndPassword(email, password).await()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun sendRecoveryEmail(email: String) {
 | 
			
		||||
        auth.sendPasswordResetEmail(email).await()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun createAnonymousAccount() {
 | 
			
		||||
        auth.signInAnonymously().await()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun linkAccount(email: String, password: String): Unit =
 | 
			
		||||
        trace(LINK_ACCOUNT_TRACE) {
 | 
			
		||||
            val credential = EmailAuthProvider.getCredential(email, password)
 | 
			
		||||
            auth.currentUser!!.linkWithCredential(credential).await()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override suspend fun deleteAccount() {
 | 
			
		||||
        auth.currentUser!!.delete().await()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun signOut() {
 | 
			
		||||
        if (auth.currentUser!!.isAnonymous) {
 | 
			
		||||
            auth.currentUser!!.delete()
 | 
			
		||||
        }
 | 
			
		||||
        auth.signOut()
 | 
			
		||||
 | 
			
		||||
        // Sign the user back in anonymously.
 | 
			
		||||
        createAnonymousAccount()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        private const val LINK_ACCOUNT_TRACE = "linkAccount"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
package be.ugent.sel.studeez.domain.account
 | 
			
		||||
 | 
			
		||||
import com.google.firebase.auth.FirebaseAuth
 | 
			
		||||
import kotlinx.coroutines.tasks.await
 | 
			
		||||
import javax.inject.Inject
 | 
			
		||||
 | 
			
		||||
class AuthenticateUseCase @Inject constructor(
 | 
			
		||||
    private val auth: FirebaseAuth,
 | 
			
		||||
) {
 | 
			
		||||
    suspend operator fun invoke(email: String, password: String) {
 | 
			
		||||
        auth.signInWithEmailAndPassword(email, password).await()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
package be.ugent.sel.studeez.domain.account
 | 
			
		||||
 | 
			
		||||
import com.google.firebase.auth.FirebaseAuth
 | 
			
		||||
import kotlinx.coroutines.tasks.await
 | 
			
		||||
import javax.inject.Inject
 | 
			
		||||
 | 
			
		||||
class CreateAnonymousAccountUseCase @Inject constructor(
 | 
			
		||||
    private val auth: FirebaseAuth,
 | 
			
		||||
) {
 | 
			
		||||
    suspend operator fun invoke() {
 | 
			
		||||
        auth.signInAnonymously().await()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
package be.ugent.sel.studeez.domain.account
 | 
			
		||||
 | 
			
		||||
import com.google.firebase.auth.FirebaseAuth
 | 
			
		||||
import kotlinx.coroutines.tasks.await
 | 
			
		||||
import javax.inject.Inject
 | 
			
		||||
 | 
			
		||||
class DeleteAccountUseCase @Inject constructor(
 | 
			
		||||
    private val auth: FirebaseAuth,
 | 
			
		||||
) {
 | 
			
		||||
    suspend operator fun invoke() {
 | 
			
		||||
        auth.currentUser!!.delete().await()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
package be.ugent.sel.studeez.domain.account
 | 
			
		||||
 | 
			
		||||
import be.ugent.sel.studeez.domain.trace
 | 
			
		||||
import com.google.firebase.auth.EmailAuthProvider
 | 
			
		||||
import com.google.firebase.auth.FirebaseAuth
 | 
			
		||||
import kotlinx.coroutines.tasks.await
 | 
			
		||||
import javax.inject.Inject
 | 
			
		||||
 | 
			
		||||
class LinkAccountUseCase @Inject constructor(
 | 
			
		||||
    private val auth: FirebaseAuth,
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    suspend operator fun invoke(email: String, password: String): Unit =
 | 
			
		||||
        trace(LINK_ACCOUNT_TRACE) {
 | 
			
		||||
            val credential = EmailAuthProvider.getCredential(email, password)
 | 
			
		||||
            auth.currentUser!!.linkWithCredential(credential).await()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        private const val LINK_ACCOUNT_TRACE = "linkAccount"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
package be.ugent.sel.studeez.domain.account
 | 
			
		||||
 | 
			
		||||
import com.google.firebase.auth.FirebaseAuth
 | 
			
		||||
import kotlinx.coroutines.tasks.await
 | 
			
		||||
import javax.inject.Inject
 | 
			
		||||
 | 
			
		||||
class SendRecoveryEmailUseCase @Inject constructor(
 | 
			
		||||
    private val auth: FirebaseAuth,
 | 
			
		||||
) {
 | 
			
		||||
    suspend operator fun invoke(email: String) {
 | 
			
		||||
        auth.sendPasswordResetEmail(email).await()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
package be.ugent.sel.studeez.domain.account
 | 
			
		||||
 | 
			
		||||
import com.google.firebase.auth.FirebaseAuth
 | 
			
		||||
import javax.inject.Inject
 | 
			
		||||
 | 
			
		||||
class SignOutUseCase @Inject constructor(
 | 
			
		||||
    private val auth: FirebaseAuth,
 | 
			
		||||
    private val createAnonymousAccountUseCase: CreateAnonymousAccountUseCase,
 | 
			
		||||
) {
 | 
			
		||||
    suspend operator fun invoke() {
 | 
			
		||||
        if (auth.currentUser!!.isAnonymous) {
 | 
			
		||||
            auth.currentUser!!.delete()
 | 
			
		||||
        }
 | 
			
		||||
        auth.signOut()
 | 
			
		||||
 | 
			
		||||
        createAnonymousAccountUseCase()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in a new issue