diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index e807bdf..e49d58e 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -256,7 +256,7 @@ exceptions: active: true ignoreLabeled: false SwallowedException: - active: true + active: false ignoredExceptionTypes: - 'InterruptedException' - 'MalformedURLException' @@ -283,7 +283,7 @@ exceptions: ThrowingNewInstanceOfSameException: active: true TooGenericExceptionCaught: - active: true + active: false excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ] exceptionNames: - 'ArrayIndexOutOfBoundsException' diff --git a/gradle.properties b/gradle.properties index c3052f8..028b076 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ kotlin.code.style=official # Determines whether this project should use hardcoded mocks or Supabase-CLI. # See https://github.com/PPartisan/Roky/wiki/Project-Setup -USE_LOCAL_MOCKS=true +USE_LOCAL_MOCKS=false diff --git a/src/main/kotlin/authentication/Auth.kt b/src/main/kotlin/authentication/Auth.kt index 9fcb8f3..83be45d 100644 --- a/src/main/kotlin/authentication/Auth.kt +++ b/src/main/kotlin/authentication/Auth.kt @@ -1,6 +1,8 @@ package authentication import Secrets +import io.github.jan.supabase.SupabaseClient +import kotlinx.coroutines.CoroutineScope interface Auth { suspend fun login( @@ -12,7 +14,10 @@ interface Auth { suspend fun isLoggedIn(): Boolean - class Factory { - fun create(): Auth = if (Secrets.USE_LOCAL_MOCKS) LocalAuth else RemoteAuth + class Factory( + private val client: SupabaseClient, + private val coroutineScope: CoroutineScope, + ) { + fun create(): Auth = if (Secrets.USE_LOCAL_MOCKS) LocalAuth else RemoteAuth(client, coroutineScope) } } diff --git a/src/main/kotlin/authentication/Authentication.kt b/src/main/kotlin/authentication/Authentication.kt index e190163..3c7e7d5 100644 --- a/src/main/kotlin/authentication/Authentication.kt +++ b/src/main/kotlin/authentication/Authentication.kt @@ -1,9 +1,12 @@ package authentication +import arch.RokyDispatchers +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob import org.koin.dsl.module val authenticationModule = module { - factory { Auth.Factory() } + factory { Auth.Factory(get(), CoroutineScope(SupervisorJob() + get().io)) } factory { get().create() } } diff --git a/src/main/kotlin/authentication/RemoteAuth.kt b/src/main/kotlin/authentication/RemoteAuth.kt index f9a567c..959b38a 100644 --- a/src/main/kotlin/authentication/RemoteAuth.kt +++ b/src/main/kotlin/authentication/RemoteAuth.kt @@ -1,32 +1,75 @@ package authentication -import kotlinx.coroutines.delay -import kotlin.time.Duration.Companion.seconds +import io.github.jan.supabase.SupabaseClient +import io.github.jan.supabase.auth.auth +import io.github.jan.supabase.auth.providers.builtin.Email +import io.github.jan.supabase.auth.status.SessionStatus +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch -// SUPABASEEEE -object RemoteAuth : Auth { - private var isLoggedIn: Boolean = false +class RemoteAuth( + private val client: SupabaseClient, + private val scope: CoroutineScope, +) : Auth { + private val _state: MutableStateFlow = MutableStateFlow(AuthState.InitState) + val state: StateFlow = _state.asStateFlow() + + init { + scope.launch { + client.auth.sessionStatus.collect { + _state.value = it.toRokyState() + println("Current State: ${state.value}") + } + } + } override suspend fun login( email: String, password: String, ) { - println("Remote Auth login") - delay(3.seconds) - isLoggedIn = (email in validUsers && password == PASSWORD) + _state.value = AuthState.Authenticating + try { + client.auth.signInWith(Email) { + this.email = email + this.password = password + } + } catch (e: Exception) { + _state.value = AuthState.InvalidCredentials + } } override suspend fun logout() { println("Remote Auth logout") - isLoggedIn = false } override suspend fun isLoggedIn(): Boolean { println("Remote Auth is logged in") - return isLoggedIn + return state.value is AuthState.SignIn + } + + companion object { + fun SessionStatus.toRokyState(): AuthState = + when (this) { + is SessionStatus.Authenticated -> AuthState.SignIn(session.user?.id ?: "Unknown User") + is SessionStatus.NotAuthenticated -> AuthState.InvalidCredentials + else -> { + println("Unrecognised State: $this") + AuthState.InvalidCredentials + } + } } +} + +sealed interface AuthState { + data class SignIn(val user: String) : AuthState + + data object InvalidCredentials : AuthState + + data object Authenticating : AuthState - private val validUsers = - listOf("Robert", "Dunia", "Tom", "Max", "Casper", "Ed", "Kai", "Laura", "Niamh", "Sofia") - private const val PASSWORD = "ILoveRoky" + data object InitState : AuthState }