mirror of
https://github.com/vector-im/riotX-android
synced 2025-10-05 15:52:47 +02:00
Realm: migrate identity db to realm-kotlin
This commit is contained in:
@@ -32,7 +32,7 @@ interface IdentityService {
|
||||
/**
|
||||
* Return the current identity server URL used by this account. Returns null if no identity server is configured.
|
||||
*/
|
||||
fun getCurrentIdentityServerUrl(): String?
|
||||
suspend fun getCurrentIdentityServerUrl(): String?
|
||||
|
||||
/**
|
||||
* Check if the identity server is valid.
|
||||
@@ -105,7 +105,7 @@ interface IdentityService {
|
||||
* @return the value stored using [setUserConsent] or false if [setUserConsent] has never been called, or if the identity server
|
||||
* has been changed
|
||||
*/
|
||||
fun getUserConsent(): Boolean
|
||||
suspend fun getUserConsent(): Boolean
|
||||
|
||||
/**
|
||||
* Set the user consent to the provided value. Application MUST explicitly ask for the user consent to send their private data
|
||||
@@ -113,7 +113,7 @@ interface IdentityService {
|
||||
* Please see https://support.google.com/googleplay/android-developer/answer/9888076?hl=en for more details.
|
||||
* @param newValue true if the user explicitly give their consent, false if the user wants to revoke their consent.
|
||||
*/
|
||||
fun setUserConsent(newValue: Boolean)
|
||||
suspend fun setUserConsent(newValue: Boolean)
|
||||
|
||||
/**
|
||||
* Get the status of the current user's threePid.
|
||||
|
@@ -51,7 +51,7 @@ internal class RealmInstance(
|
||||
|
||||
suspend fun open() {
|
||||
coroutineScope.launch {
|
||||
realm.join()
|
||||
realm.await()
|
||||
}.join()
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.network
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import org.matrix.android.sdk.internal.network.token.AccessTokenProvider
|
||||
@@ -26,12 +27,13 @@ internal class AccessTokenInterceptor(private val accessTokenProvider: AccessTok
|
||||
var request = chain.request()
|
||||
|
||||
// Add the access token to all requests if it is set
|
||||
accessTokenProvider.getToken()?.let { token ->
|
||||
runBlocking {
|
||||
accessTokenProvider.getToken()
|
||||
}?.let { token ->
|
||||
val newRequestBuilder = request.newBuilder()
|
||||
newRequestBuilder.header(HttpHeaders.Authorization, "Bearer $token")
|
||||
request = newRequestBuilder.build()
|
||||
}
|
||||
|
||||
return chain.proceed(request)
|
||||
}
|
||||
}
|
||||
|
@@ -17,5 +17,5 @@
|
||||
package org.matrix.android.sdk.internal.network.token
|
||||
|
||||
internal interface AccessTokenProvider {
|
||||
fun getToken(): String?
|
||||
suspend fun getToken(): String?
|
||||
}
|
||||
|
@@ -24,5 +24,5 @@ internal class HomeserverAccessTokenProvider @Inject constructor(
|
||||
@SessionId private val sessionId: String,
|
||||
private val sessionParamsStore: SessionParamsStore
|
||||
) : AccessTokenProvider {
|
||||
override fun getToken() = sessionParamsStore.get(sessionId)?.credentials?.accessToken
|
||||
override suspend fun getToken() = sessionParamsStore.get(sessionId)?.credentials?.accessToken
|
||||
}
|
||||
|
@@ -90,7 +90,6 @@ internal class DefaultSession @Inject constructor(
|
||||
override val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
@SessionDatabase private val realmConfiguration: RealmConfiguration,
|
||||
@CryptoDatabase private val realmConfigurationCrypto: RealmConfiguration,
|
||||
@IdentityDatabase private val realmConfigurationIdentity: RealmConfiguration,
|
||||
@ContentScannerDatabase private val realmConfigurationContentScanner: RealmConfiguration,
|
||||
private val lifecycleObservers: Set<@JvmSuppressWildcards SessionLifecycleObserver>,
|
||||
private val sessionListeners: SessionListeners,
|
||||
@@ -266,7 +265,7 @@ internal class DefaultSession @Inject constructor(
|
||||
override fun logDbUsageInfo() {
|
||||
RealmDebugTools(realmConfiguration).logInfo("Session")
|
||||
RealmDebugTools(realmConfigurationCrypto).logInfo("Crypto")
|
||||
RealmDebugTools(realmConfigurationIdentity).logInfo("Identity")
|
||||
//RealmDebugTools(realmConfigurationIdentity).logInfo("Identity")
|
||||
RealmDebugTools(realmConfigurationContentScanner).logInfo("ContentScanner")
|
||||
}
|
||||
|
||||
@@ -274,7 +273,7 @@ internal class DefaultSession @Inject constructor(
|
||||
return listOf(
|
||||
realmConfiguration,
|
||||
realmConfigurationCrypto,
|
||||
realmConfigurationIdentity,
|
||||
//realmConfigurationIdentity,
|
||||
realmConfigurationContentScanner,
|
||||
)
|
||||
}
|
||||
|
@@ -20,6 +20,8 @@ import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LifecycleRegistry
|
||||
import dagger.Lazy
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.OkHttpClient
|
||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||
@@ -41,6 +43,7 @@ import org.matrix.android.sdk.api.session.identity.SharedState
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.api.session.identity.model.SignInvitationResult
|
||||
import org.matrix.android.sdk.internal.di.AuthenticatedIdentity
|
||||
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
|
||||
import org.matrix.android.sdk.internal.extensions.observeNotNull
|
||||
import org.matrix.android.sdk.internal.network.RetrofitFactory
|
||||
@@ -81,7 +84,8 @@ internal class DefaultIdentityService @Inject constructor(
|
||||
private val accountDataDataSource: UserAccountDataDataSource,
|
||||
private val homeServerCapabilitiesService: HomeServerCapabilitiesService,
|
||||
private val sign3pidInvitationTask: Sign3pidInvitationTask,
|
||||
private val sessionParams: SessionParams
|
||||
private val sessionParams: SessionParams,
|
||||
@SessionCoroutineScope private val coroutineScope: CoroutineScope,
|
||||
) : IdentityService, SessionLifecycleObserver {
|
||||
|
||||
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry }
|
||||
@@ -95,14 +99,17 @@ internal class DefaultIdentityService @Inject constructor(
|
||||
accountDataDataSource
|
||||
.getLiveAccountDataEvent(UserAccountDataTypes.TYPE_IDENTITY_SERVER)
|
||||
.observeNotNull(lifecycleOwner) {
|
||||
notifyIdentityServerUrlChange(it.getOrNull()?.content?.toModel<IdentityServerContent>()?.baseUrl)
|
||||
coroutineScope.notifyIdentityServerUrlChange(it.getOrNull()?.content?.toModel<IdentityServerContent>()?.baseUrl)
|
||||
}
|
||||
|
||||
// Init identityApi
|
||||
updateIdentityAPI(identityStore.getIdentityData()?.identityServerUrl)
|
||||
coroutineScope.launch {
|
||||
val url = identityStore.getIdentityData()?.identityServerUrl
|
||||
updateIdentityAPI(url)
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyIdentityServerUrlChange(baseUrl: String?) {
|
||||
private fun CoroutineScope.notifyIdentityServerUrlChange(baseUrl: String?) = launch {
|
||||
// This is maybe not a real change (echo of account data we are just setting)
|
||||
if (identityStore.getIdentityData()?.identityServerUrl == baseUrl) {
|
||||
Timber.d("Echo of local identity server url change, or no change")
|
||||
@@ -129,7 +136,7 @@ internal class DefaultIdentityService @Inject constructor(
|
||||
?: homeServerCapabilitiesService.getHomeServerCapabilities().defaultIdentityServerUrl
|
||||
}
|
||||
|
||||
override fun getCurrentIdentityServerUrl(): String? {
|
||||
override suspend fun getCurrentIdentityServerUrl(): String? {
|
||||
return identityStore.getIdentityData()?.identityServerUrl
|
||||
}
|
||||
|
||||
@@ -225,11 +232,11 @@ internal class DefaultIdentityService @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
override fun getUserConsent(): Boolean {
|
||||
override suspend fun getUserConsent(): Boolean {
|
||||
return identityStore.getIdentityData()?.userConsent.orFalse()
|
||||
}
|
||||
|
||||
override fun setUserConsent(newValue: Boolean) {
|
||||
override suspend fun setUserConsent(newValue: Boolean) {
|
||||
identityStore.setUserConsent(newValue)
|
||||
}
|
||||
|
||||
|
@@ -23,5 +23,5 @@ import javax.inject.Inject
|
||||
internal class IdentityAccessTokenProvider @Inject constructor(
|
||||
private val identityStore: IdentityStore
|
||||
) : AccessTokenProvider {
|
||||
override fun getToken() = identityStore.getIdentityData()?.token
|
||||
override suspend fun getToken() = identityStore.getIdentityData()?.token
|
||||
}
|
||||
|
@@ -19,13 +19,17 @@ package org.matrix.android.sdk.internal.session.identity
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.RealmConfiguration
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import okhttp3.OkHttpClient
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||
import org.matrix.android.sdk.api.session.identity.IdentityService
|
||||
import org.matrix.android.sdk.internal.database.RealmInstance
|
||||
import org.matrix.android.sdk.internal.database.RealmKeysUtils
|
||||
import org.matrix.android.sdk.internal.di.AuthenticatedIdentity
|
||||
import org.matrix.android.sdk.internal.di.IdentityDatabase
|
||||
import org.matrix.android.sdk.internal.di.MatrixCoroutineScope
|
||||
import org.matrix.android.sdk.internal.di.SessionFilesDirectory
|
||||
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
|
||||
import org.matrix.android.sdk.internal.di.UserMd5
|
||||
@@ -35,7 +39,7 @@ import org.matrix.android.sdk.internal.network.token.AccessTokenProvider
|
||||
import org.matrix.android.sdk.internal.session.SessionModule
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.session.identity.data.IdentityStore
|
||||
import org.matrix.android.sdk.internal.session.identity.db.IdentityRealmModule
|
||||
import org.matrix.android.sdk.internal.session.identity.db.IDENTITY_REALM_SCHEMA
|
||||
import org.matrix.android.sdk.internal.session.identity.db.RealmIdentityStore
|
||||
import org.matrix.android.sdk.internal.session.identity.db.RealmIdentityStoreMigration
|
||||
import java.io.File
|
||||
@@ -64,25 +68,38 @@ internal abstract class IdentityModule {
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@IdentityDatabase
|
||||
@SessionScope
|
||||
fun providesIdentityRealmConfiguration(
|
||||
fun providesRealmConfiguration(
|
||||
realmKeysUtils: RealmKeysUtils,
|
||||
realmIdentityStoreMigration: RealmIdentityStoreMigration,
|
||||
identityStoreMigration: RealmIdentityStoreMigration,
|
||||
@SessionFilesDirectory directory: File,
|
||||
@UserMd5 userMd5: String
|
||||
): RealmConfiguration {
|
||||
return RealmConfiguration.Builder()
|
||||
.directory(directory)
|
||||
.name("matrix-sdk-identity.realm")
|
||||
return RealmConfiguration.Builder(IDENTITY_REALM_SCHEMA)
|
||||
.directory(directory.path)
|
||||
.apply {
|
||||
realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5))
|
||||
}
|
||||
.schemaVersion(realmIdentityStoreMigration.schemaVersion)
|
||||
.migration(realmIdentityStoreMigration)
|
||||
.allowWritesOnUiThread(true)
|
||||
.modules(IdentityRealmModule())
|
||||
.name("matrix-sdk-global.realm")
|
||||
.schemaVersion(identityStoreMigration.schemaVersion)
|
||||
.migration(identityStoreMigration)
|
||||
.build()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@IdentityDatabase
|
||||
@SessionScope
|
||||
fun providesRealmInstance(
|
||||
@IdentityDatabase realmConfiguration: RealmConfiguration,
|
||||
@MatrixCoroutineScope matrixCoroutineScope: CoroutineScope,
|
||||
matrixCoroutineDispatchers: MatrixCoroutineDispatchers
|
||||
): RealmInstance {
|
||||
return RealmInstance(
|
||||
coroutineScope = matrixCoroutineScope,
|
||||
realmConfiguration = realmConfiguration,
|
||||
coroutineDispatcher = matrixCoroutineDispatchers.io
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Binds
|
||||
|
@@ -21,26 +21,26 @@ import org.matrix.android.sdk.internal.session.identity.model.IdentityHashDetail
|
||||
|
||||
internal interface IdentityStore {
|
||||
|
||||
fun getIdentityData(): IdentityData?
|
||||
suspend fun getIdentityData(): IdentityData?
|
||||
|
||||
fun setUrl(url: String?)
|
||||
suspend fun setUrl(url: String?)
|
||||
|
||||
fun setToken(token: String?)
|
||||
suspend fun setToken(token: String?)
|
||||
|
||||
fun setUserConsent(consent: Boolean)
|
||||
suspend fun setUserConsent(consent: Boolean)
|
||||
|
||||
fun setHashDetails(hashDetailResponse: IdentityHashDetailResponse)
|
||||
suspend fun setHashDetails(hashDetailResponse: IdentityHashDetailResponse)
|
||||
|
||||
/**
|
||||
* Store details about a current binding.
|
||||
*/
|
||||
fun storePendingBinding(threePid: ThreePid, data: IdentityPendingBinding)
|
||||
suspend fun storePendingBinding(threePid: ThreePid, data: IdentityPendingBinding)
|
||||
|
||||
fun getPendingBinding(threePid: ThreePid): IdentityPendingBinding?
|
||||
suspend fun getPendingBinding(threePid: ThreePid): IdentityPendingBinding?
|
||||
|
||||
fun deletePendingBinding(threePid: ThreePid)
|
||||
suspend fun deletePendingBinding(threePid: ThreePid)
|
||||
}
|
||||
|
||||
internal fun IdentityStore.getIdentityServerUrlWithoutProtocol(): String? {
|
||||
internal suspend fun IdentityStore.getIdentityServerUrlWithoutProtocol(): String? {
|
||||
return getIdentityData()?.identityServerUrl?.substringAfter("://")
|
||||
}
|
||||
|
@@ -16,18 +16,14 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.session.identity.db
|
||||
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmModel
|
||||
import io.realm.annotations.RealmClass
|
||||
import io.realm.kotlin.ext.realmListOf
|
||||
import io.realm.kotlin.types.RealmList
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
|
||||
@RealmClass
|
||||
internal open class IdentityDataEntity(
|
||||
var identityServerUrl: String? = null,
|
||||
var token: String? = null,
|
||||
var hashLookupPepper: String? = null,
|
||||
var hashLookupAlgorithm: RealmList<String> = RealmList(),
|
||||
var userConsent: Boolean = false
|
||||
) : RealmModel {
|
||||
|
||||
companion object
|
||||
internal class IdentityDataEntity : RealmObject {
|
||||
var identityServerUrl: String? = null
|
||||
var token: String? = null
|
||||
var hashLookupPepper: String? = null
|
||||
var hashLookupAlgorithm: RealmList<String> = realmListOf()
|
||||
var userConsent: Boolean = false
|
||||
}
|
||||
|
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 org.matrix.android.sdk.internal.session.identity.db
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmList
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
|
||||
/**
|
||||
* Only one object can be stored at a time.
|
||||
*/
|
||||
internal fun IdentityDataEntity.Companion.get(realm: Realm): IdentityDataEntity? {
|
||||
return realm.where<IdentityDataEntity>().findFirst()
|
||||
}
|
||||
|
||||
private fun IdentityDataEntity.Companion.getOrCreate(realm: Realm): IdentityDataEntity {
|
||||
return get(realm) ?: realm.createObject()
|
||||
}
|
||||
|
||||
internal fun IdentityDataEntity.Companion.setUrl(
|
||||
realm: Realm,
|
||||
url: String?
|
||||
) {
|
||||
realm.where<IdentityDataEntity>().findAll().deleteAllFromRealm()
|
||||
// Delete all pending binding if any
|
||||
IdentityPendingBindingEntity.deleteAll(realm)
|
||||
|
||||
if (url != null) {
|
||||
getOrCreate(realm).apply {
|
||||
identityServerUrl = url
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun IdentityDataEntity.Companion.setToken(
|
||||
realm: Realm,
|
||||
newToken: String?
|
||||
) {
|
||||
get(realm)?.apply {
|
||||
token = newToken
|
||||
}
|
||||
}
|
||||
|
||||
internal fun IdentityDataEntity.Companion.setUserConsent(
|
||||
realm: Realm,
|
||||
newConsent: Boolean
|
||||
) {
|
||||
get(realm)?.apply {
|
||||
userConsent = newConsent
|
||||
}
|
||||
}
|
||||
|
||||
internal fun IdentityDataEntity.Companion.setHashDetails(
|
||||
realm: Realm,
|
||||
pepper: String,
|
||||
algorithms: List<String>
|
||||
) {
|
||||
get(realm)?.apply {
|
||||
hashLookupPepper = pepper
|
||||
hashLookupAlgorithm = RealmList<String>().apply { addAll(algorithms) }
|
||||
}
|
||||
}
|
@@ -16,22 +16,22 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.session.identity.db
|
||||
|
||||
import io.realm.RealmModel
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import io.realm.annotations.RealmClass
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.api.session.identity.toMedium
|
||||
|
||||
@RealmClass
|
||||
internal open class IdentityPendingBindingEntity(
|
||||
@PrimaryKey var threePid: String = "",
|
||||
/* Managed by Riot */
|
||||
var clientSecret: String = "",
|
||||
/* Managed by Riot */
|
||||
var sendAttempt: Int = 0,
|
||||
/* Provided by the identity server */
|
||||
var sid: String = ""
|
||||
) : RealmModel {
|
||||
internal class IdentityPendingBindingEntity : RealmObject {
|
||||
@PrimaryKey var threePid: String = ""
|
||||
|
||||
/* Managed by Riot */
|
||||
var clientSecret: String = ""
|
||||
|
||||
/* Managed by Riot */
|
||||
var sendAttempt: Int = 0
|
||||
|
||||
/* Provided by the identity server */
|
||||
var sid: String = ""
|
||||
|
||||
companion object {
|
||||
fun ThreePid.toPrimaryKey() = "${toMedium()}_$value"
|
||||
|
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 org.matrix.android.sdk.internal.session.identity.db
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.deleteFromRealm
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
|
||||
internal fun IdentityPendingBindingEntity.Companion.get(realm: Realm, threePid: ThreePid): IdentityPendingBindingEntity? {
|
||||
return realm.where<IdentityPendingBindingEntity>()
|
||||
.equalTo(IdentityPendingBindingEntityFields.THREE_PID, threePid.toPrimaryKey())
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
internal fun IdentityPendingBindingEntity.Companion.getOrCreate(realm: Realm, threePid: ThreePid): IdentityPendingBindingEntity {
|
||||
return get(realm, threePid) ?: realm.createObject(threePid.toPrimaryKey())
|
||||
}
|
||||
|
||||
internal fun IdentityPendingBindingEntity.Companion.delete(realm: Realm, threePid: ThreePid) {
|
||||
get(realm, threePid)?.deleteFromRealm()
|
||||
}
|
||||
|
||||
internal fun IdentityPendingBindingEntity.Companion.deleteAll(realm: Realm) {
|
||||
realm.where<IdentityPendingBindingEntity>()
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
}
|
@@ -16,16 +16,7 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.session.identity.db
|
||||
|
||||
import io.realm.annotations.RealmModule
|
||||
|
||||
/**
|
||||
* Realm module for identity server classes.
|
||||
*/
|
||||
@RealmModule(
|
||||
library = true,
|
||||
classes = [
|
||||
IdentityDataEntity::class,
|
||||
IdentityPendingBindingEntity::class
|
||||
]
|
||||
internal val IDENTITY_REALM_SCHEMA = setOf(
|
||||
IdentityDataEntity::class,
|
||||
IdentityPendingBindingEntity::class,
|
||||
)
|
||||
internal class IdentityRealmModule
|
||||
|
@@ -16,84 +16,102 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.session.identity.db
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.UpdatePolicy
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.internal.database.RealmInstance
|
||||
import org.matrix.android.sdk.internal.database.await
|
||||
import org.matrix.android.sdk.internal.di.IdentityDatabase
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.session.identity.data.IdentityData
|
||||
import org.matrix.android.sdk.internal.session.identity.data.IdentityPendingBinding
|
||||
import org.matrix.android.sdk.internal.session.identity.data.IdentityStore
|
||||
import org.matrix.android.sdk.internal.session.identity.db.IdentityPendingBindingEntity.Companion.toPrimaryKey
|
||||
import org.matrix.android.sdk.internal.session.identity.model.IdentityHashDetailResponse
|
||||
import javax.inject.Inject
|
||||
|
||||
@SessionScope
|
||||
internal class RealmIdentityStore @Inject constructor(
|
||||
@IdentityDatabase
|
||||
private val realmConfiguration: RealmConfiguration
|
||||
private val realmInstance: RealmInstance,
|
||||
) : IdentityStore {
|
||||
|
||||
override fun getIdentityData(): IdentityData? {
|
||||
return Realm.getInstance(realmConfiguration).use { realm ->
|
||||
IdentityDataEntity.get(realm)?.let { IdentityMapper.map(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun setUrl(url: String?) {
|
||||
Realm.getInstance(realmConfiguration).use {
|
||||
it.executeTransaction { realm ->
|
||||
IdentityDataEntity.setUrl(realm, url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setToken(token: String?) {
|
||||
Realm.getInstance(realmConfiguration).use {
|
||||
it.executeTransaction { realm ->
|
||||
IdentityDataEntity.setToken(realm, token)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setUserConsent(consent: Boolean) {
|
||||
Realm.getInstance(realmConfiguration).use {
|
||||
it.executeTransaction { realm ->
|
||||
IdentityDataEntity.setUserConsent(realm, consent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setHashDetails(hashDetailResponse: IdentityHashDetailResponse) {
|
||||
Realm.getInstance(realmConfiguration).use {
|
||||
it.executeTransaction { realm ->
|
||||
IdentityDataEntity.setHashDetails(realm, hashDetailResponse.pepper, hashDetailResponse.algorithms)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun storePendingBinding(threePid: ThreePid, data: IdentityPendingBinding) {
|
||||
Realm.getInstance(realmConfiguration).use {
|
||||
it.executeTransaction { realm ->
|
||||
IdentityPendingBindingEntity.getOrCreate(realm, threePid).let { entity ->
|
||||
entity.clientSecret = data.clientSecret
|
||||
entity.sendAttempt = data.sendAttempt
|
||||
entity.sid = data.sid
|
||||
override suspend fun getIdentityData(): IdentityData? {
|
||||
return getIdentityDataEntity()
|
||||
?.let {
|
||||
IdentityMapper.map(it)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setUrl(url: String?) {
|
||||
val identityData = getIdentityDataEntity() ?: return
|
||||
realmInstance.write {
|
||||
findLatest(identityData)?.identityServerUrl = url
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setToken(token: String?) {
|
||||
val identityData = getIdentityDataEntity() ?: return
|
||||
realmInstance.write {
|
||||
findLatest(identityData)?.token = token
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setUserConsent(consent: Boolean) {
|
||||
val identityData = getIdentityDataEntity() ?: return
|
||||
realmInstance.write {
|
||||
findLatest(identityData)?.userConsent = consent
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setHashDetails(hashDetailResponse: IdentityHashDetailResponse) {
|
||||
val identityData = getIdentityDataEntity() ?: return
|
||||
realmInstance.write {
|
||||
findLatest(identityData)?.apply {
|
||||
hashLookupAlgorithm.clear()
|
||||
hashLookupAlgorithm.addAll(hashDetailResponse.algorithms)
|
||||
hashLookupPepper = hashDetailResponse.pepper
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPendingBinding(threePid: ThreePid): IdentityPendingBinding? {
|
||||
return Realm.getInstance(realmConfiguration).use { realm ->
|
||||
IdentityPendingBindingEntity.get(realm, threePid)?.let { IdentityMapper.map(it) }
|
||||
override suspend fun storePendingBinding(threePid: ThreePid, data: IdentityPendingBinding) {
|
||||
realmInstance.write {
|
||||
val pendingBindingEntity = IdentityPendingBindingEntity().apply {
|
||||
this.threePid = threePid.toPrimaryKey()
|
||||
clientSecret = data.clientSecret
|
||||
sendAttempt = data.sendAttempt
|
||||
sid = data.sid
|
||||
}
|
||||
copyToRealm(pendingBindingEntity, updatePolicy = UpdatePolicy.ALL)
|
||||
}
|
||||
}
|
||||
|
||||
override fun deletePendingBinding(threePid: ThreePid) {
|
||||
Realm.getInstance(realmConfiguration).use {
|
||||
it.executeTransaction { realm ->
|
||||
IdentityPendingBindingEntity.delete(realm, threePid)
|
||||
override suspend fun getPendingBinding(threePid: ThreePid): IdentityPendingBinding? {
|
||||
return getPendingBindingEntity(threePid)?.let {
|
||||
IdentityMapper.map(it)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deletePendingBinding(threePid: ThreePid) {
|
||||
val pendingBindingEntity = getPendingBindingEntity(threePid) ?: return
|
||||
realmInstance.write {
|
||||
findLatest(pendingBindingEntity)?.also {
|
||||
delete(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getPendingBindingEntity(threePid: ThreePid): IdentityPendingBindingEntity? {
|
||||
return realmInstance.getRealm()
|
||||
.query(IdentityPendingBindingEntity::class, "threePid == $0", threePid.toPrimaryKey())
|
||||
.first()
|
||||
.await()
|
||||
}
|
||||
|
||||
private suspend fun getIdentityDataEntity(): IdentityDataEntity? {
|
||||
return realmInstance.getRealm()
|
||||
.query(IdentityDataEntity::class)
|
||||
.first()
|
||||
.await()
|
||||
}
|
||||
}
|
||||
|
@@ -16,15 +16,16 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.session.identity.db
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.MatrixAutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.session.identity.db.migration.MigrateIdentityTo001
|
||||
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class RealmIdentityStoreMigration @Inject constructor() : MatrixRealmMigration(
|
||||
internal class RealmIdentityStoreMigration @Inject constructor() : MatrixAutomaticSchemaMigration(
|
||||
dbName = "Identity",
|
||||
schemaVersion = 1L,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Forces all RealmIdentityStoreMigration instances to be equal.
|
||||
* Avoids Realm throwing when multiple instances of the migration are set.
|
||||
@@ -32,7 +33,7 @@ internal class RealmIdentityStoreMigration @Inject constructor() : MatrixRealmMi
|
||||
override fun equals(other: Any?) = other is RealmIdentityStoreMigration
|
||||
override fun hashCode() = 3000
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm, oldVersion: Long) {
|
||||
if (oldVersion < 1) MigrateIdentityTo001(realm).perform()
|
||||
override fun doMigrate(oldVersion: Long, migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
if (oldVersion < 1) MigrateIdentityTo001(migrationContext).perform()
|
||||
}
|
||||
}
|
||||
|
@@ -16,16 +16,13 @@
|
||||
|
||||
package org.matrix.android.sdk.internal.session.identity.db.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.session.identity.db.IdentityDataEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MigrateIdentityTo001(realm: DynamicRealm) : RealmMigrator(realm, 1) {
|
||||
internal class MigrateIdentityTo001(migrationContext: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(migrationContext, 1) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||
Timber.d("Add field userConsent (Boolean) and set the value to false")
|
||||
realm.schema.get("IdentityDataEntity")
|
||||
?.addField(IdentityDataEntityFields.USER_CONSENT, Boolean::class.java)
|
||||
}
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@ import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.discovery.fetchIdentityServerWithTerms
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.identity.IdentityServiceError
|
||||
@@ -63,15 +64,19 @@ class ContactsBookViewModel @AssistedInject constructor(
|
||||
}
|
||||
|
||||
private fun loadContacts() {
|
||||
setState {
|
||||
copy(
|
||||
mappedContacts = Loading(),
|
||||
identityServerUrl = session.identityService().getCurrentIdentityServerUrl(),
|
||||
userConsent = session.identityService().getUserConsent()
|
||||
)
|
||||
}
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
|
||||
val identityServerUrl = session.identityService().getCurrentIdentityServerUrl()
|
||||
val userConsent = session.identityService().getUserConsent()
|
||||
|
||||
setState {
|
||||
copy(
|
||||
mappedContacts = Loading(),
|
||||
identityServerUrl = identityServerUrl,
|
||||
userConsent = userConsent
|
||||
)
|
||||
}
|
||||
|
||||
allContacts = contactsDataSource.getContacts(
|
||||
withEmails = true,
|
||||
// Do not handle phone numbers for the moment
|
||||
@@ -90,57 +95,55 @@ class ContactsBookViewModel @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun performLookup(contacts: List<MappedContact>) {
|
||||
private suspend fun performLookup(contacts: List<MappedContact>) = coroutineScope {
|
||||
if (!session.identityService().getUserConsent()) {
|
||||
return
|
||||
return@coroutineScope
|
||||
}
|
||||
val threePids = contacts.flatMap { contact ->
|
||||
contact.emails.map { ThreePid.Email(it.email) } +
|
||||
contact.msisdns.map { ThreePid.Msisdn(it.phoneNumber) }
|
||||
}
|
||||
viewModelScope.launch {
|
||||
val threePids = contacts.flatMap { contact ->
|
||||
contact.emails.map { ThreePid.Email(it.email) } +
|
||||
contact.msisdns.map { ThreePid.Msisdn(it.phoneNumber) }
|
||||
}
|
||||
|
||||
val data = try {
|
||||
session.identityService().lookUp(threePids)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.w(failure, "Unable to perform the lookup")
|
||||
val data = try {
|
||||
session.identityService().lookUp(threePids)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.w(failure, "Unable to perform the lookup")
|
||||
|
||||
// Should not happen, but just to be sure
|
||||
if (failure is IdentityServiceError.UserConsentNotProvided) {
|
||||
setState {
|
||||
copy(userConsent = false)
|
||||
}
|
||||
// Should not happen, but just to be sure
|
||||
if (failure is IdentityServiceError.UserConsentNotProvided) {
|
||||
setState {
|
||||
copy(userConsent = false)
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
|
||||
mappedContacts = allContacts.map { contactModel ->
|
||||
contactModel.copy(
|
||||
emails = contactModel.emails.map { email ->
|
||||
email.copy(
|
||||
matrixId = data
|
||||
.firstOrNull { foundThreePid -> foundThreePid.threePid.value == email.email }
|
||||
?.matrixId
|
||||
)
|
||||
},
|
||||
msisdns = contactModel.msisdns.map { msisdn ->
|
||||
msisdn.copy(
|
||||
matrixId = data
|
||||
.firstOrNull { foundThreePid -> foundThreePid.threePid.value == msisdn.phoneNumber }
|
||||
?.matrixId
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
setState {
|
||||
copy(
|
||||
isBoundRetrieved = true
|
||||
)
|
||||
}
|
||||
|
||||
updateFilteredMappedContacts()
|
||||
return@coroutineScope
|
||||
}
|
||||
|
||||
mappedContacts = allContacts.map { contactModel ->
|
||||
contactModel.copy(
|
||||
emails = contactModel.emails.map { email ->
|
||||
email.copy(
|
||||
matrixId = data
|
||||
.firstOrNull { foundThreePid -> foundThreePid.threePid.value == email.email }
|
||||
?.matrixId
|
||||
)
|
||||
},
|
||||
msisdns = contactModel.msisdns.map { msisdn ->
|
||||
msisdn.copy(
|
||||
matrixId = data
|
||||
.firstOrNull { foundThreePid -> foundThreePid.threePid.value == msisdn.phoneNumber }
|
||||
?.matrixId
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
setState {
|
||||
copy(
|
||||
isBoundRetrieved = true
|
||||
)
|
||||
}
|
||||
|
||||
updateFilteredMappedContacts()
|
||||
}
|
||||
|
||||
private fun updateFilteredMappedContacts() = withState { state ->
|
||||
@@ -159,6 +162,7 @@ class ContactsBookViewModel @AssistedInject constructor(
|
||||
}
|
||||
|
||||
override fun handle(action: ContactsBookAction) {
|
||||
|
||||
when (action) {
|
||||
is ContactsBookAction.FilterWith -> handleFilterWith(action)
|
||||
is ContactsBookAction.OnlyBoundContacts -> handleOnlyBoundContacts(action)
|
||||
@@ -180,14 +184,14 @@ class ContactsBookViewModel @AssistedInject constructor(
|
||||
}
|
||||
|
||||
private fun handleUserConsentGranted() {
|
||||
session.identityService().setUserConsent(true)
|
||||
|
||||
setState {
|
||||
copy(userConsent = true)
|
||||
viewModelScope.launch {
|
||||
session.identityService().setUserConsent(true)
|
||||
setState {
|
||||
copy(userConsent = true)
|
||||
}
|
||||
// Perform the lookup
|
||||
performLookup(allContacts)
|
||||
}
|
||||
|
||||
// Perform the lookup
|
||||
performLookup(allContacts)
|
||||
}
|
||||
|
||||
private fun handleOnlyBoundContacts(action: ContactsBookAction.OnlyBoundContacts) {
|
||||
|
@@ -60,10 +60,11 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
||||
runCatching { fetchIdentityServerWithTerms() }.fold(
|
||||
onSuccess = {
|
||||
val currentIS = state.identityServer()
|
||||
val userConsent = identityService.getUserConsent()
|
||||
setState {
|
||||
copy(
|
||||
identityServer = Success(it),
|
||||
userConsent = identityService.getUserConsent()
|
||||
userConsent = userConsent
|
||||
)
|
||||
}
|
||||
if (currentIS != it) retrieveBinding()
|
||||
@@ -75,16 +76,24 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
||||
}
|
||||
|
||||
init {
|
||||
setState {
|
||||
copy(
|
||||
identityServer = Success(identityService.getCurrentIdentityServerUrl()?.let { ServerAndPolicies(it, emptyList()) }),
|
||||
userConsent = identityService.getUserConsent()
|
||||
)
|
||||
}
|
||||
loadInitialState()
|
||||
startListenToIdentityManager()
|
||||
observeThreePids()
|
||||
}
|
||||
|
||||
private fun loadInitialState() {
|
||||
viewModelScope.launch {
|
||||
val identityServer = identityService.getCurrentIdentityServerUrl()?.let { ServerAndPolicies(it, emptyList()) }
|
||||
val userConsent = identityService.getUserConsent()
|
||||
setState {
|
||||
copy(
|
||||
identityServer = Success(identityServer),
|
||||
userConsent = userConsent
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeThreePids() {
|
||||
session.flow()
|
||||
.liveThreePIds(true)
|
||||
@@ -116,13 +125,14 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
||||
}
|
||||
|
||||
private fun handleUpdateUserConsent(action: DiscoverySettingsAction.UpdateUserConsent) {
|
||||
identityService.setUserConsent(action.newConsent)
|
||||
setState { copy(userConsent = action.newConsent) }
|
||||
viewModelScope.launch {
|
||||
identityService.setUserConsent(action.newConsent)
|
||||
setState { copy(userConsent = action.newConsent) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun disconnectIdentityServer() {
|
||||
setState { copy(identityServer = Loading()) }
|
||||
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
session.identityService().disconnect()
|
||||
|
@@ -293,10 +293,12 @@ class VectorSettingsGeneralFragment @Inject constructor(
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
// Refresh identity server summary
|
||||
mIdentityServerPreference.summary = session.identityService().getCurrentIdentityServerUrl() ?: getString(R.string.identity_server_not_defined)
|
||||
refreshIntegrationManagerSettings()
|
||||
session.integrationManagerService().addListener(integrationServiceListener)
|
||||
viewLifecycleOwner.lifecycleScope.launchWhenResumed {
|
||||
// Refresh identity server summary
|
||||
mIdentityServerPreference.summary = session.identityService().getCurrentIdentityServerUrl() ?: getString(R.string.identity_server_not_defined)
|
||||
refreshIntegrationManagerSettings()
|
||||
session.integrationManagerService().addListener(integrationServiceListener)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
|
@@ -52,14 +52,17 @@ class LegalsViewModel @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadData() = withState { state ->
|
||||
loadHomeserver(state)
|
||||
val url = session.identityService().getCurrentIdentityServerUrl()
|
||||
if (url.isNullOrEmpty()) {
|
||||
setState { copy(hasIdentityServer = false) }
|
||||
} else {
|
||||
setState { copy(hasIdentityServer = true) }
|
||||
loadIdentityServer(state)
|
||||
private fun loadData() {
|
||||
viewModelScope.launch {
|
||||
val state = awaitState()
|
||||
loadHomeserver(state)
|
||||
val url = session.identityService().getCurrentIdentityServerUrl()
|
||||
if (url.isNullOrEmpty()) {
|
||||
setState { copy(hasIdentityServer = false) }
|
||||
} else {
|
||||
setState { copy(hasIdentityServer = true) }
|
||||
loadIdentityServer(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -53,23 +53,19 @@ class CreateSpaceViewModel @AssistedInject constructor(
|
||||
|
||||
private val identityServerManagerListener = object : IdentityServiceListener {
|
||||
override fun onIdentityServerChange() {
|
||||
val identityServerUrl = identityService.getCurrentIdentityServerUrl()
|
||||
setState {
|
||||
copy(
|
||||
canInviteByMail = identityServerUrl != null
|
||||
)
|
||||
viewModelScope.launch {
|
||||
val identityServerUrl = identityService.getCurrentIdentityServerUrl()
|
||||
setState {
|
||||
copy(
|
||||
canInviteByMail = identityServerUrl != null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
val identityServerUrl = identityService.getCurrentIdentityServerUrl()
|
||||
setState {
|
||||
copy(
|
||||
homeServerName = session.myUserId.getServerName(),
|
||||
canInviteByMail = identityServerUrl != null
|
||||
)
|
||||
}
|
||||
loadInitialState()
|
||||
startListenToIdentityManager()
|
||||
}
|
||||
|
||||
@@ -78,6 +74,18 @@ class CreateSpaceViewModel @AssistedInject constructor(
|
||||
override fun create(initialState: CreateSpaceState): CreateSpaceViewModel
|
||||
}
|
||||
|
||||
private fun loadInitialState() {
|
||||
viewModelScope.launch {
|
||||
val identityServerUrl = identityService.getCurrentIdentityServerUrl()
|
||||
setState {
|
||||
copy(
|
||||
homeServerName = session.myUserId.getServerName(),
|
||||
canInviteByMail = identityServerUrl != null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun startListenToIdentityManager() {
|
||||
identityService.addListener(identityServerManagerListener)
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@ import im.vector.app.core.extensions.toggle
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.discovery.fetchIdentityServerWithTerms
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.filter
|
||||
@@ -73,26 +74,32 @@ class UserListViewModel @AssistedInject constructor(
|
||||
|
||||
private val identityServerListener = object : IdentityServiceListener {
|
||||
override fun onIdentityServerChange() {
|
||||
withState {
|
||||
identityServerUsersSearch.tryEmit(UserSearch(it.searchTerm))
|
||||
val identityServerURL = cleanISURL(session.identityService().getCurrentIdentityServerUrl())
|
||||
setState {
|
||||
copy(configuredIdentityServer = identityServerURL)
|
||||
}
|
||||
viewModelScope.launch {
|
||||
identityServerUsersSearch.tryEmit(UserSearch(awaitState().searchTerm))
|
||||
updateConfiguredIdentityServer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
loadInitialState()
|
||||
observeUsers()
|
||||
setState {
|
||||
copy(
|
||||
configuredIdentityServer = cleanISURL(session.identityService().getCurrentIdentityServerUrl())
|
||||
)
|
||||
}
|
||||
session.identityService().addListener(identityServerListener)
|
||||
}
|
||||
|
||||
private fun loadInitialState() {
|
||||
viewModelScope.launch {
|
||||
updateConfiguredIdentityServer()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateConfiguredIdentityServer() = coroutineScope {
|
||||
val identityServerURL = cleanISURL(session.identityService().getCurrentIdentityServerUrl())
|
||||
setState {
|
||||
copy(configuredIdentityServer = identityServerURL)
|
||||
}
|
||||
}
|
||||
|
||||
private fun cleanISURL(url: String?): String? {
|
||||
return url?.removePrefix("https://")
|
||||
}
|
||||
@@ -128,9 +135,11 @@ class UserListViewModel @AssistedInject constructor(
|
||||
}
|
||||
|
||||
private fun handleISUpdateConsent(action: UserListAction.UpdateUserConsent) {
|
||||
session.identityService().setUserConsent(action.consent)
|
||||
withState {
|
||||
retryUserSearch(it)
|
||||
viewModelScope.launch {
|
||||
session.identityService().setUserConsent(action.consent)
|
||||
withState {
|
||||
retryUserSearch(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user