diff --git a/changelog.d/3743.bugfix b/changelog.d/3743.bugfix new file mode 100644 index 00000000000..87baf628343 --- /dev/null +++ b/changelog.d/3743.bugfix @@ -0,0 +1 @@ +Update the AccountData with the users' matrix Id instead of their email for those invited by email in a direct chat \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt index de6a71e5815..518f0a0a6df 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt @@ -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)) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt index 2ecacf335b0..7528f80cc2e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt @@ -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 } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt index c3586bcea7a..830e666c950 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt @@ -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) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt index ea10a32f3ee..9bb2bfc9b17 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt @@ -19,4 +19,6 @@ package org.matrix.android.sdk.internal.session.sync internal class SyncResponsePostTreatmentAggregator { // List of RoomId val ephemeralFilesToDelete = mutableListOf() + // Map of roomId to directUserId + val directChatsToCheck = mutableMapOf() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregatorHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregatorHandler.kt index 12b77c706b3..db1100d76c5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregatorHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregatorHandler.kt @@ -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) { @@ -30,4 +37,33 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor( ephemeralTemporaryStore.delete(it) } } + + private suspend fun updateDirectUserIds(directUserIdsToUpdate: Map) { + 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)) + } + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/UserAccountDataSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/UserAccountDataSyncHandler.kt index b8d987d5009..110e77813d1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/UserAccountDataSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/UserAccountDataSyncHandler.kt @@ -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) { if (invites.isNullOrEmpty()) return - val directChats = directChatsHelper.getLocalUserAccount() + val directChats = directChatsHelper.getLocalDirectMessages().toMutable() var hasUpdate = false monarchy.doWithRealm { realm -> invites.forEach { (roomId, _) -> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/accountdata/DirectMessagesContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/accountdata/DirectMessagesContent.kt index 41173dea96b..7c73f1fed07 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/accountdata/DirectMessagesContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/accountdata/DirectMessagesContent.kt @@ -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> + +/** + * Returns a new [MutableMap] with all elements of this collection. + */ +internal fun DirectMessagesContent.toMutable(): MutableMap> { + return map { it.key to it.value.toMutableList() } + .toMap() + .toMutableMap() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/DirectChatsHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/DirectChatsHelper.kt index a9e50897740..37030576439 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/DirectChatsHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/DirectChatsHelper.kt @@ -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> { + 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()