Merge pull request 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 this.isDirect = true
} }
} }
val directChats = directChatsHelper.getLocalUserAccount() val directChats = directChatsHelper.getLocalDirectMessages()
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats)) 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.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,20 @@
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.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 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 +37,33 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor(
ephemeralTemporaryStore.delete(it) 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.DirectMessagesContent
import org.matrix.android.sdk.internal.session.sync.model.accountdata.IgnoredUsersContent 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.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.DirectChatsHelper
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
import timber.log.Timber 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. // If we get some direct chat invites, we synchronize the user account data including those.
suspend fun synchronizeWithServerIfNeeded(invites: Map<String, InvitedRoomSync>) { suspend fun synchronizeWithServerIfNeeded(invites: Map<String, InvitedRoomSync>) {
if (invites.isNullOrEmpty()) return if (invites.isNullOrEmpty()) return
val directChats = directChatsHelper.getLocalUserAccount() val directChats = directChatsHelper.getLocalDirectMessages().toMutable()
var hasUpdate = false var hasUpdate = false
monarchy.doWithRealm { realm -> monarchy.doWithRealm { realm ->
invites.forEach { (roomId, _) -> 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 * Keys are userIds, values are list of roomIds
*/ */
internal typealias DirectMessagesContent = Map<String, List<String>> 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 org.matrix.android.sdk.internal.di.SessionDatabase
import io.realm.Realm import io.realm.Realm
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import org.matrix.android.sdk.internal.session.sync.model.accountdata.DirectMessagesContent
import javax.inject.Inject import javax.inject.Inject
internal class DirectChatsHelper @Inject constructor(@SessionDatabase internal class DirectChatsHelper @Inject constructor(@SessionDatabase
@ -29,7 +30,7 @@ internal class DirectChatsHelper @Inject constructor(@SessionDatabase
/** /**
* @return a map of userId <-> list of roomId * @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 -> 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. // Makes sure we have the latest realm updates, this is important as we sent this information to the server.
realm.refresh() realm.refresh()