Merge pull request #3743 from vector-im/florian14/dm_email_invite

Update Account Data with user matrix id for invited user by email
This commit is contained in:
Benoit Marty 2021-08-23 16:08:39 +02:00 committed by GitHub
commit 4a33fbb635
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 81 additions and 13 deletions

1
changelog.d/3743.bugfix Normal file
View file

@ -0,0 +1 @@
Update the AccountData with the users' matrix Id instead of their email for those invited by email in a direct chat

View file

@ -123,7 +123,7 @@ internal class DefaultCreateRoomTask @Inject constructor(
this.isDirect = true
}
}
val directChats = directChatsHelper.getLocalUserAccount()
val directChats = directChatsHelper.getLocalDirectMessages()
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats))
}

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.EventType
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.sync.SyncResponsePostTreatmentAggregator
import org.matrix.android.sdk.internal.session.user.UserEntityFactory
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) {
return false
}
val userId = event.stateKey ?: return false
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) {
return false
}
@ -45,6 +53,14 @@ internal class RoomMemberEventHandler @Inject constructor() {
val userEntity = UserEntityFactory.create(userId, roomMember)
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
}
}

View file

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

View file

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

View file

@ -16,13 +16,20 @@
package org.matrix.android.sdk.internal.session.sync
import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.internal.session.sync.model.accountdata.toMutable
import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
import javax.inject.Inject
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)
updateDirectUserIds(synResHaResponsePostTreatmentAggregator.directChatsToCheck)
}
private fun cleanupEphemeralFiles(ephemeralFilesToDelete: List<String>) {
@ -30,4 +37,33 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor(
ephemeralTemporaryStore.delete(it)
}
}
private suspend fun updateDirectUserIds(directUserIdsToUpdate: Map<String, String>) {
val directChats = directChatsHelper.getLocalDirectMessages().toMutable()
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))
}
}
}

View file

@ -53,6 +53,7 @@ import org.matrix.android.sdk.internal.session.sync.model.accountdata.Breadcrumb
import org.matrix.android.sdk.internal.session.sync.model.accountdata.DirectMessagesContent
import org.matrix.android.sdk.internal.session.sync.model.accountdata.IgnoredUsersContent
import org.matrix.android.sdk.internal.session.sync.model.accountdata.UserAccountDataSync
import org.matrix.android.sdk.internal.session.sync.model.accountdata.toMutable
import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
import timber.log.Timber
@ -83,7 +84,7 @@ internal class UserAccountDataSyncHandler @Inject constructor(
// If we get some direct chat invites, we synchronize the user account data including those.
suspend fun synchronizeWithServerIfNeeded(invites: Map<String, InvitedRoomSync>) {
if (invites.isNullOrEmpty()) return
val directChats = directChatsHelper.getLocalUserAccount()
val directChats = directChatsHelper.getLocalDirectMessages().toMutable()
var hasUpdate = false
monarchy.doWithRealm { realm ->
invites.forEach { (roomId, _) ->

View file

@ -20,3 +20,12 @@ package org.matrix.android.sdk.internal.session.sync.model.accountdata
* Keys are userIds, values are list of roomIds
*/
internal typealias DirectMessagesContent = Map<String, List<String>>
/**
* Returns a new [MutableMap] with all elements of this collection.
*/
internal fun DirectMessagesContent.toMutable(): MutableMap<String, MutableList<String>> {
return map { it.key to it.value.toMutableList() }
.toMap()
.toMutableMap()
}

View file

@ -21,6 +21,7 @@ import org.matrix.android.sdk.internal.database.query.getDirectRooms
import org.matrix.android.sdk.internal.di.SessionDatabase
import io.realm.Realm
import io.realm.RealmConfiguration
import org.matrix.android.sdk.internal.session.sync.model.accountdata.DirectMessagesContent
import javax.inject.Inject
internal class DirectChatsHelper @Inject constructor(@SessionDatabase
@ -29,7 +30,7 @@ internal class DirectChatsHelper @Inject constructor(@SessionDatabase
/**
* @return a map of userId <-> list of roomId
*/
fun getLocalUserAccount(filterRoomId: String? = null): MutableMap<String, MutableList<String>> {
fun getLocalDirectMessages(filterRoomId: String? = null): DirectMessagesContent {
return Realm.getInstance(realmConfiguration).use { realm ->
// Makes sure we have the latest realm updates, this is important as we sent this information to the server.
realm.refresh()