Update account data for invited users by email

When an user has been invited by email to a DM, account data entry was stuck on the user email after the user account creation.
When the user has joined element, an event m.room.member is triggered for each room attached to the user, containing a third party invite with the user matrix id. We use this event to update the user account with the matrix id.
This commit is contained in:
Florian Renaud 2021-07-28 10:28:19 +02:00
parent 6d47fdf3d3
commit ac56b1ef3e
4 changed files with 65 additions and 10 deletions

View File

@ -20,22 +20,30 @@ import io.realm.Realm
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.events.getFixedRoomMemberContent import org.matrix.android.sdk.internal.session.events.getFixedRoomMemberContent
import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator
import org.matrix.android.sdk.internal.session.user.UserEntityFactory import org.matrix.android.sdk.internal.session.user.UserEntityFactory
import javax.inject.Inject import javax.inject.Inject
internal class RoomMemberEventHandler @Inject constructor() { internal class RoomMemberEventHandler @Inject constructor(
@UserId private val myUserId: String
) {
fun handle(realm: Realm, roomId: String, event: Event): Boolean { fun handle(realm: Realm, roomId: String, event: Event, aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean {
if (event.type != EventType.STATE_ROOM_MEMBER) { if (event.type != EventType.STATE_ROOM_MEMBER) {
return false return false
} }
val userId = event.stateKey ?: return false val userId = event.stateKey ?: return false
val roomMember = event.getFixedRoomMemberContent() val roomMember = event.getFixedRoomMemberContent()
return handle(realm, roomId, userId, roomMember) return handle(realm, roomId, userId, roomMember, aggregator)
} }
fun handle(realm: Realm, roomId: String, userId: String, roomMember: RoomMemberContent?): Boolean { fun handle(realm: Realm,
roomId: String,
userId: String,
roomMember: RoomMemberContent?,
aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean {
if (roomMember == null) { if (roomMember == null) {
return false return false
} }
@ -45,6 +53,14 @@ internal class RoomMemberEventHandler @Inject constructor() {
val userEntity = UserEntityFactory.create(userId, roomMember) val userEntity = UserEntityFactory.create(userId, roomMember)
realm.insertOrUpdate(userEntity) realm.insertOrUpdate(userEntity)
} }
// check whether this new room member event may be used to update the directs dictionary in account data
// this is required to handle correctly invite by email in DM
val mxId = roomMember.thirdPartyInvite?.signed?.mxid
if (mxId != null && mxId != myUserId) {
aggregator?.directChatsToCheck?.put(roomId, mxId)
}
return true return true
} }
} }

View File

@ -221,7 +221,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
} }
// Give info to crypto module // Give info to crypto module
cryptoService.onStateEvent(roomId, event) cryptoService.onStateEvent(roomId, event)
roomMemberEventHandler.handle(realm, roomId, event) roomMemberEventHandler.handle(realm, roomId, event, aggregator)
} }
} }
if (roomSync.timeline?.events?.isNotEmpty() == true) { if (roomSync.timeline?.events?.isNotEmpty() == true) {
@ -233,7 +233,8 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
roomSync.timeline.prevToken, roomSync.timeline.prevToken,
roomSync.timeline.limited, roomSync.timeline.limited,
insertType, insertType,
syncLocalTimestampMillis syncLocalTimestampMillis,
aggregator
) )
roomEntity.addIfNecessary(chunkEntity) roomEntity.addIfNecessary(chunkEntity)
} }
@ -337,7 +338,8 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
prevToken: String? = null, prevToken: String? = null,
isLimited: Boolean = true, isLimited: Boolean = true,
insertType: EventInsertType, insertType: EventInsertType,
syncLocalTimestampMillis: Long): ChunkEntity { syncLocalTimestampMillis: Long,
aggregator: SyncResponsePostTreatmentAggregator): ChunkEntity {
val lastChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomEntity.roomId) val lastChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomEntity.roomId)
val chunkEntity = if (!isLimited && lastChunk != null) { val chunkEntity = if (!isLimited && lastChunk != null) {
lastChunk lastChunk
@ -371,7 +373,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
if (event.type == EventType.STATE_ROOM_MEMBER) { if (event.type == EventType.STATE_ROOM_MEMBER) {
val fixedContent = event.getFixedRoomMemberContent() val fixedContent = event.getFixedRoomMemberContent()
roomMemberContentsByUser[event.stateKey] = fixedContent roomMemberContentsByUser[event.stateKey] = fixedContent
roomMemberEventHandler.handle(realm, roomEntity.roomId, event.stateKey, fixedContent) roomMemberEventHandler.handle(realm, roomEntity.roomId, event.stateKey, fixedContent, aggregator)
} }
} }
roomMemberContentsByUser.getOrPut(event.senderId) { roomMemberContentsByUser.getOrPut(event.senderId) {

View File

@ -19,4 +19,6 @@ package org.matrix.android.sdk.internal.session.sync
internal class SyncResponsePostTreatmentAggregator { internal class SyncResponsePostTreatmentAggregator {
// List of RoomId // List of RoomId
val ephemeralFilesToDelete = mutableListOf<String>() val ephemeralFilesToDelete = mutableListOf<String>()
// Map of roomId to directUserId
val directChatsToCheck = mutableMapOf<String, String>()
} }

View File

@ -16,13 +16,19 @@
package org.matrix.android.sdk.internal.session.sync package org.matrix.android.sdk.internal.session.sync
import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
import javax.inject.Inject import javax.inject.Inject
internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor( internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor(
private val ephemeralTemporaryStore: RoomSyncEphemeralTemporaryStore private val directChatsHelper: DirectChatsHelper,
private val ephemeralTemporaryStore: RoomSyncEphemeralTemporaryStore,
private val updateUserAccountDataTask: UpdateUserAccountDataTask
) { ) {
fun handle(synResHaResponsePostTreatmentAggregator: SyncResponsePostTreatmentAggregator) { suspend fun handle(synResHaResponsePostTreatmentAggregator: SyncResponsePostTreatmentAggregator) {
cleanupEphemeralFiles(synResHaResponsePostTreatmentAggregator.ephemeralFilesToDelete) cleanupEphemeralFiles(synResHaResponsePostTreatmentAggregator.ephemeralFilesToDelete)
updateDirectUserIds(synResHaResponsePostTreatmentAggregator.directChatsToCheck)
} }
private fun cleanupEphemeralFiles(ephemeralFilesToDelete: List<String>) { private fun cleanupEphemeralFiles(ephemeralFilesToDelete: List<String>) {
@ -30,4 +36,33 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor(
ephemeralTemporaryStore.delete(it) ephemeralTemporaryStore.delete(it)
} }
} }
private suspend fun updateDirectUserIds(directUserIdsToUpdate: Map<String, String>) {
val directChats = directChatsHelper.getLocalDirectMessages()
var hasUpdate = false
directUserIdsToUpdate.forEach { (roomId, candidateUserId) ->
// consider room is a DM if referenced in the DM dictionary
val currentDirectUserId = directChats.firstNotNullOfOrNull { (userId, roomIds) -> userId.takeIf { roomId in roomIds } }
// update directUserId with the given candidateUserId if it mismatches the current one
if (currentDirectUserId != null && !MatrixPatterns.isUserId(currentDirectUserId)) {
// link roomId with the matrix id
directChats
.getOrPut(candidateUserId) { arrayListOf() }
.apply {
if (!contains(roomId)) {
hasUpdate = true
add(roomId)
}
}
// remove roomId from currentDirectUserId entry
hasUpdate = hasUpdate or(directChats[currentDirectUserId]?.remove(roomId) == true)
// remove currentDirectUserId entry if there is no attached room anymore
hasUpdate = hasUpdate or(directChats.takeIf { it[currentDirectUserId].isNullOrEmpty() }?.remove(currentDirectUserId) != null)
}
}
if (hasUpdate) {
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats))
}
}
} }