diff --git a/changelog.d/7740.feature b/changelog.d/7740.feature new file mode 100644 index 0000000000..6cd2b6c776 --- /dev/null +++ b/changelog.d/7740.feature @@ -0,0 +1 @@ +Handle account data removal diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomEntityQueries.kt index 08bb9e7ff3..0489fe690f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomEntityQueries.kt @@ -21,6 +21,7 @@ import io.realm.RealmQuery import io.realm.kotlin.where import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.internal.database.model.EventEntity +import org.matrix.android.sdk.internal.database.model.RoomAccountDataEntityFields import org.matrix.android.sdk.internal.database.model.RoomEntity import org.matrix.android.sdk.internal.database.model.RoomEntityFields @@ -44,3 +45,11 @@ internal fun RoomEntity.Companion.where(realm: Realm, membership: Membership? = internal fun RoomEntity.fastContains(eventId: String): Boolean { return EventEntity.where(realm, eventId = eventId).findFirst() != null } + +internal fun RoomEntity.removeAccountData(type: String) { + accountData + .where() + .equalTo(RoomAccountDataEntityFields.TYPE, type) + .findFirst() + ?.deleteFromRealm() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/UserAccountDataEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/UserAccountDataEntityQueries.kt new file mode 100644 index 0000000000..b28965aeca --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/UserAccountDataEntityQueries.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.internal.database.query + +import io.realm.Realm +import io.realm.kotlin.where +import org.matrix.android.sdk.internal.database.model.UserAccountDataEntity +import org.matrix.android.sdk.internal.database.model.UserAccountDataEntityFields + +/** + * Delete an account_data event. + */ +internal fun UserAccountDataEntity.Companion.delete(realm: Realm, type: String) { + realm + .where() + .equalTo(UserAccountDataEntityFields.TYPE, type) + .findFirst() + ?.deleteFromRealm() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt index 31bed90b62..4e55b2c40a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt @@ -427,6 +427,19 @@ internal interface RoomAPI { @Body content: JsonDict ) + /** + * Remove an account_data event from the room. + * @param userId the user id + * @param roomId the room id + * @param type the type + */ + @DELETE(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "org.matrix.msc3391/user/{userId}/rooms/{roomId}/account_data/{type}") + suspend fun deleteRoomAccountData( + @Path("userId") userId: String, + @Path("roomId") roomId: String, + @Path("type") type: String + ) + /** * Upgrades the given room to a particular room version. * Errors: diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt index 0f296ded5d..92ebb41ad9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt @@ -45,6 +45,7 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.model.UserAccountDataEntity import org.matrix.android.sdk.internal.database.model.UserAccountDataEntityFields import org.matrix.android.sdk.internal.database.model.deleteOnCascade +import org.matrix.android.sdk.internal.database.query.delete import org.matrix.android.sdk.internal.database.query.findAllFrom import org.matrix.android.sdk.internal.database.query.getDirectRooms import org.matrix.android.sdk.internal.database.query.getOrCreate @@ -94,7 +95,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 + if (invites.isEmpty()) return val directChats = directChatsHelper.getLocalDirectMessages().toMutable() var hasUpdate = false monarchy.doWithRealm { realm -> @@ -252,9 +253,17 @@ internal class UserAccountDataSyncHandler @Inject constructor( } fun handleGenericAccountData(realm: Realm, type: String, content: Content?) { + if (content.isNullOrEmpty()) { + // This is a response for a deleted account data according to + // https://github.com/ShadowJonathan/matrix-doc/blob/account-data-delete/proposals/3391-account-data-delete.md#sync + UserAccountDataEntity.delete(realm, type) + return + } + val existing = realm.where() .equalTo(UserAccountDataEntityFields.TYPE, type) .findFirst() + if (existing != null) { // Update current value existing.contentStr = ContentMapper.map(content) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/parsing/RoomSyncAccountDataHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/parsing/RoomSyncAccountDataHandler.kt index b1b2bfef33..9da12a2c4a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/parsing/RoomSyncAccountDataHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/parsing/RoomSyncAccountDataHandler.kt @@ -27,6 +27,7 @@ import org.matrix.android.sdk.internal.database.model.RoomAccountDataEntity import org.matrix.android.sdk.internal.database.model.RoomAccountDataEntityFields import org.matrix.android.sdk.internal.database.model.RoomEntity import org.matrix.android.sdk.internal.database.query.getOrCreate +import org.matrix.android.sdk.internal.database.query.removeAccountData import org.matrix.android.sdk.internal.session.room.read.FullyReadContent import org.matrix.android.sdk.internal.session.sync.handler.room.RoomFullyReadHandler import org.matrix.android.sdk.internal.session.sync.handler.room.RoomTagHandler @@ -56,6 +57,13 @@ internal class RoomSyncAccountDataHandler @Inject constructor( } private fun handleGeneric(roomEntity: RoomEntity, content: JsonDict?, eventType: String) { + if (content.isNullOrEmpty()) { + // This is a response for a deleted account data according to + // https://github.com/ShadowJonathan/matrix-doc/blob/account-data-delete/proposals/3391-account-data-delete.md#sync + roomEntity.removeAccountData(eventType) + return + } + val existing = roomEntity.accountData.where().equalTo(RoomAccountDataEntityFields.TYPE, eventType).findFirst() if (existing != null) { existing.contentStr = ContentMapper.map(content) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataAPI.kt index b283d51845..1b3d59ac66 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataAPI.kt @@ -18,13 +18,14 @@ package org.matrix.android.sdk.internal.session.user.accountdata import org.matrix.android.sdk.internal.network.NetworkConstants import retrofit2.http.Body +import retrofit2.http.DELETE import retrofit2.http.PUT import retrofit2.http.Path internal interface AccountDataAPI { /** - * Set some account_data for the client. + * Set some account_data for the user. * * @param userId the user id * @param type the type @@ -36,4 +37,16 @@ internal interface AccountDataAPI { @Path("type") type: String, @Body params: Any ) + + /** + * Remove an account_data for the user. + * + * @param userId the user id + * @param type the type + */ + @DELETE(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "org.matrix.msc3391/user/{userId}/account_data/{type}") + suspend fun deleteAccountData( + @Path("userId") userId: String, + @Path("type") type: String + ) }