Retrieve ThreePids from homeserver

This commit is contained in:
Benoit Marty 2020-05-07 02:27:20 +02:00
parent 784918350b
commit a75242c79d
10 changed files with 234 additions and 0 deletions

View File

@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo
import im.vector.matrix.android.api.session.group.GroupSummaryQueryParams
import im.vector.matrix.android.api.session.group.model.GroupSummary
import im.vector.matrix.android.api.session.identity.ThreePid
import im.vector.matrix.android.api.session.pushers.Pusher
import im.vector.matrix.android.api.session.room.RoomSummaryQueryParams
import im.vector.matrix.android.api.session.room.model.RoomSummary
@ -94,6 +95,11 @@ class RxSession(private val session: Session) {
return session.getPagedUsersLive(filter, excludedUserIds).asObservable()
}
fun liveThreePIds(): Observable<List<ThreePid>> {
return session.getThreePidsLive().asObservable()
.startWithCallable { session.getThreePids() }
}
fun createRoom(roomParams: CreateRoomParams): Single<String> = singleBuilder {
session.createRoom(roomParams, it)
}

View File

@ -17,7 +17,9 @@
package im.vector.matrix.android.api.session.profile
import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.identity.ThreePid
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.api.util.Optional
@ -53,4 +55,14 @@ interface ProfileService {
*
*/
fun getProfile(userId: String, matrixCallback: MatrixCallback<JsonDict>): Cancelable
/**
* Get the current user 3Pids
*/
fun getThreePids(): List<ThreePid>
/**
* Get the current user 3Pids Live
*/
fun getThreePidsLive(): LiveData<List<ThreePid>>
}

View File

@ -37,6 +37,7 @@ import io.realm.annotations.RealmModule
UserEntity::class,
IgnoredUserEntity::class,
BreadcrumbsEntity::class,
UserThreePidEntity::class,
EventAnnotationsSummaryEntity::class,
ReactionAggregatedSummaryEntity::class,
EditAggregatedSummaryEntity::class,

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* 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 im.vector.matrix.android.internal.database.model
import io.realm.RealmObject
internal open class UserThreePidEntity(
var medium: String = "",
var address: String = "",
var validatedAt: Long = 0,
var addedAt: Long = 0
) : RealmObject()

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* 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 im.vector.matrix.android.internal.session.profile
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
/**
* Class representing the ThreePids response
*/
@JsonClass(generateAdapter = true)
internal data class AccountThreePidsResponse(
@Json(name = "threepids")
val threePids: List<ThirdPartyIdentifier>? = null
)

View File

@ -17,16 +17,23 @@
package im.vector.matrix.android.internal.session.profile
import androidx.lifecycle.LiveData
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.identity.ThreePid
import im.vector.matrix.android.api.session.profile.ProfileService
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.internal.database.model.UserThreePidEntity
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import io.realm.kotlin.where
import javax.inject.Inject
internal class DefaultProfileService @Inject constructor(private val taskExecutor: TaskExecutor,
private val monarchy: Monarchy,
private val refreshUserThreePidsTask: RefreshUserThreePidsTask,
private val getProfileInfoTask: GetProfileInfoTask) : ProfileService {
override fun getDisplayName(userId: String, matrixCallback: MatrixCallback<Optional<String>>): Cancelable {
@ -73,4 +80,31 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
}
.executeBy(taskExecutor)
}
override fun getThreePids(): List<ThreePid> {
return monarchy.fetchAllMappedSync(
{ it.where<UserThreePidEntity>() },
{ it.asDomain() }
)
}
override fun getThreePidsLive(): LiveData<List<ThreePid>> {
// Force a refresh of the values
refreshUserThreePidsTask
.configureWith()
.executeBy(taskExecutor)
return monarchy.findAllMappedWithChanges(
{ it.where<UserThreePidEntity>() },
{ it.asDomain() }
)
}
}
private fun UserThreePidEntity.asDomain(): ThreePid {
return when (medium) {
ThirdPartyIdentifier.MEDIUM_EMAIL -> ThreePid.Email(address)
ThirdPartyIdentifier.MEDIUM_MSISDN -> ThreePid.Msisdn(address)
else -> error("Invalid medium type")
}
}

View File

@ -33,4 +33,10 @@ interface ProfileAPI {
*/
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}")
fun getProfile(@Path("userId") userId: String): Call<JsonDict>
/**
* List all 3PIDs linked to the Matrix user account.
*/
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "account/3pid")
fun getThreePIDs(): Call<AccountThreePidsResponse>
}

View File

@ -42,4 +42,7 @@ internal abstract class ProfileModule {
@Binds
abstract fun bindGetProfileTask(task: DefaultGetProfileInfoTask): GetProfileInfoTask
@Binds
abstract fun bindRefreshUserThreePidsTask(task: DefaultRefreshUserThreePidsTask): RefreshUserThreePidsTask
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* 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 im.vector.matrix.android.internal.session.profile
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.UserThreePidEntity
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction
import org.greenrobot.eventbus.EventBus
import timber.log.Timber
import javax.inject.Inject
internal abstract class RefreshUserThreePidsTask : Task<Unit, Unit>
internal class DefaultRefreshUserThreePidsTask @Inject constructor(private val profileAPI: ProfileAPI,
private val monarchy: Monarchy,
private val eventBus: EventBus) : RefreshUserThreePidsTask() {
override suspend fun execute(params: Unit) {
val accountThreePidsResponse = executeRequest<AccountThreePidsResponse>(eventBus) {
apiCall = profileAPI.getThreePIDs()
}
Timber.d("Get ${accountThreePidsResponse.threePids?.size} threePids")
// Store the list in DB
monarchy.awaitTransaction { realm ->
realm.where(UserThreePidEntity::class.java).findAll().deleteAllFromRealm()
accountThreePidsResponse.threePids?.forEach {
val entity = UserThreePidEntity(
it.medium?.takeIf { med -> med in ThirdPartyIdentifier.SUPPORTED_MEDIUM } ?: return@forEach,
it.address ?: return@forEach,
it.validatedAt.toLong(),
it.addedAt.toLong())
realm.insertOrUpdate(entity)
}
}
}
}
private fun Any?.toLong(): Long {
return when (this) {
null -> 0L
is Long -> this
is Double -> this.toLong()
else -> 0L
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* 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 im.vector.matrix.android.internal.session.profile
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class ThirdPartyIdentifier(
/**
* Required. The medium of the third party identifier. One of: ["email", "msisdn"]
*/
@Json(name = "medium")
val medium: String? = null,
/**
* Required. The third party identifier address.
*/
@Json(name = "address")
val address: String? = null,
/**
* Required. The timestamp in milliseconds when this 3PID has been validated.
* Define as Object because it should be Long and it is a Double.
* So, it might change.
*/
@Json(name = "validated_at")
val validatedAt: Any? = null,
/**
* Required. The timestamp in milliseconds when this 3PID has been added to the user account.
* Define as Object because it should be Long and it is a Double.
* So, it might change.
*/
@Json(name = "added_at")
val addedAt: Any? = null
) {
companion object {
const val MEDIUM_EMAIL = "email"
const val MEDIUM_MSISDN = "msisdn"
val SUPPORTED_MEDIUM = listOf(MEDIUM_EMAIL, MEDIUM_MSISDN)
}
}