From f6415b0a5d4641be639db20800b1db9e0f411ab0 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 6 Jul 2022 15:02:23 +0200 Subject: [PATCH] Deleting summaries related to a redacted live location sharing --- .../EventAnnotationsSummaryEntityQuery.kt | 9 ++ .../sdk/internal/session/SessionModule.kt | 5 + ...iveLocationShareRedactionEventProcessor.kt | 65 +++++++++++ ...ocationShareRedactionEventProcessorTest.kt | 106 ++++++++++++++++++ .../android/sdk/test/fakes/FakeRealm.kt | 10 ++ 5 files changed, 195 insertions(+) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/LiveLocationShareRedactionEventProcessor.kt create mode 100644 matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/location/LiveLocationShareRedactionEventProcessorTest.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt index 6caa832110..1c19c21de2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt @@ -23,6 +23,11 @@ import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEnt import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntityFields import org.matrix.android.sdk.internal.database.model.TimelineEventEntity +internal fun EventAnnotationsSummaryEntity.Companion.where(realm: Realm, eventId: String): RealmQuery { + return realm.where() + .equalTo(EventAnnotationsSummaryEntityFields.EVENT_ID, eventId) +} + internal fun EventAnnotationsSummaryEntity.Companion.where(realm: Realm, roomId: String, eventId: String): RealmQuery { return realm.where() .equalTo(EventAnnotationsSummaryEntityFields.ROOM_ID, roomId) @@ -44,3 +49,7 @@ internal fun EventAnnotationsSummaryEntity.Companion.getOrCreate(realm: Realm, r return EventAnnotationsSummaryEntity.where(realm, roomId, eventId).findFirst() ?: EventAnnotationsSummaryEntity.create(realm, roomId, eventId) } + +internal fun EventAnnotationsSummaryEntity.Companion.get(realm: Realm, eventId: String): EventAnnotationsSummaryEntity? { + return EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt index f8a52f0b7e..b9f56cbc9f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt @@ -88,6 +88,7 @@ import org.matrix.android.sdk.internal.session.room.EventRelationsAggregationPro import org.matrix.android.sdk.internal.session.room.aggregation.poll.DefaultPollAggregationProcessor import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollAggregationProcessor import org.matrix.android.sdk.internal.session.room.create.RoomCreateEventProcessor +import org.matrix.android.sdk.internal.session.room.location.LiveLocationShareRedactionEventProcessor import org.matrix.android.sdk.internal.session.room.prune.RedactionEventProcessor import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessorCoroutine @@ -321,6 +322,10 @@ internal abstract class SessionModule { @IntoSet abstract fun bindEventRedactionProcessor(processor: RedactionEventProcessor): EventInsertLiveProcessor + @Binds + @IntoSet + abstract fun bindLiveLocationShareRedactionEventProcessor(processor: LiveLocationShareRedactionEventProcessor): EventInsertLiveProcessor + @Binds @IntoSet abstract fun bindEventRelationsAggregationProcessor(processor: EventRelationsAggregationProcessor): EventInsertLiveProcessor diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/LiveLocationShareRedactionEventProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/LiveLocationShareRedactionEventProcessor.kt new file mode 100644 index 0000000000..fa3479ed3c --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/LiveLocationShareRedactionEventProcessor.kt @@ -0,0 +1,65 @@ +/* + * 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.session.room.location + +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.events.model.LocalEcho +import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity +import org.matrix.android.sdk.internal.database.model.EventEntity +import org.matrix.android.sdk.internal.database.model.EventInsertType +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity +import org.matrix.android.sdk.internal.database.query.get +import org.matrix.android.sdk.internal.database.query.where +import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor +import timber.log.Timber +import javax.inject.Inject + +/** + * Listens to the database for the insertion of any redaction event. + * Delete specifically the aggregated summary related to a redacted live location share event. + */ +internal class LiveLocationShareRedactionEventProcessor @Inject constructor() : EventInsertLiveProcessor { + + override fun shouldProcess(eventId: String, eventType: String, insertType: EventInsertType): Boolean { + return eventType == EventType.REDACTION && insertType != EventInsertType.LOCAL_ECHO + } + + override suspend fun process(realm: Realm, event: Event) { + if (event.redacts.isNullOrBlank() || LocalEcho.isLocalEchoId(event.eventId.orEmpty())) { + return + } + + val redactedEvent = EventEntity.where(realm, eventId = event.redacts).findFirst() + ?: return + + if (redactedEvent.type in EventType.STATE_ROOM_BEACON_INFO) { + val liveSummary = LiveLocationShareAggregatedSummaryEntity.get(realm, eventId = redactedEvent.eventId) + + if (liveSummary != null) { + Timber.d("deleting live summary with id: ${liveSummary.eventId}") + liveSummary.deleteFromRealm() + val annotationsSummary = EventAnnotationsSummaryEntity.get(realm, eventId = redactedEvent.eventId) + if (annotationsSummary != null) { + Timber.d("deleting annotation summary with id: ${annotationsSummary.eventId}") + annotationsSummary.deleteFromRealm() + } + } + } + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/location/LiveLocationShareRedactionEventProcessorTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/location/LiveLocationShareRedactionEventProcessorTest.kt new file mode 100644 index 0000000000..24d9c30039 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/location/LiveLocationShareRedactionEventProcessorTest.kt @@ -0,0 +1,106 @@ +/* + * Copyright (c) 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.session.room.location + +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.amshove.kluent.shouldBe +import org.junit.Test +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.internal.database.model.EventAnnotationsSummaryEntity +import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntityFields +import org.matrix.android.sdk.internal.database.model.EventEntity +import org.matrix.android.sdk.internal.database.model.EventEntityFields +import org.matrix.android.sdk.internal.database.model.EventInsertType +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields +import org.matrix.android.sdk.test.fakes.FakeRealm +import org.matrix.android.sdk.test.fakes.givenDelete +import org.matrix.android.sdk.test.fakes.givenEqualTo +import org.matrix.android.sdk.test.fakes.givenFindFirst + +private const val AN_EVENT_ID = "event-id" +private const val A_REDACTED_EVENT_ID = "redacted-event-id" + +@ExperimentalCoroutinesApi +class LiveLocationShareRedactionEventProcessorTest { + + private val liveLocationShareRedactionEventProcessor = LiveLocationShareRedactionEventProcessor() + private val fakeRealm = FakeRealm() + + @Test + fun `given an event when checking if it should be processed then only event of type REDACTED is processed`() { + val eventId = AN_EVENT_ID + val eventType = EventType.REDACTION + val insertType = EventInsertType.INCREMENTAL_SYNC + + val result = liveLocationShareRedactionEventProcessor.shouldProcess( + eventId = eventId, + eventType = eventType, + insertType = insertType + ) + + result shouldBe true + } + + @Test + fun `given an event when checking if it should be processed then local echo is not processed`() { + val eventId = AN_EVENT_ID + val eventType = EventType.REDACTION + val insertType = EventInsertType.LOCAL_ECHO + + val result = liveLocationShareRedactionEventProcessor.shouldProcess( + eventId = eventId, + eventType = eventType, + insertType = insertType + ) + + result shouldBe false + } + + @Test + fun `given a redacted live location share event when processing it then related summaries are deleted from database`() = runTest { + val event = Event(eventId = AN_EVENT_ID, redacts = A_REDACTED_EVENT_ID) + val redactedEventEntity = EventEntity(eventId = A_REDACTED_EVENT_ID, type = EventType.STATE_ROOM_BEACON_INFO.first()) + fakeRealm.givenWhere() + .givenEqualTo(EventEntityFields.EVENT_ID, A_REDACTED_EVENT_ID) + .givenFindFirst(redactedEventEntity) + val liveSummary = mockk() + every { liveSummary.eventId } returns A_REDACTED_EVENT_ID + liveSummary.givenDelete() + fakeRealm.givenWhere() + .givenEqualTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, A_REDACTED_EVENT_ID) + .givenFindFirst(liveSummary) + val annotationsSummary = mockk() + every { annotationsSummary.eventId } returns A_REDACTED_EVENT_ID + annotationsSummary.givenDelete() + fakeRealm.givenWhere() + .givenEqualTo(EventAnnotationsSummaryEntityFields.EVENT_ID, A_REDACTED_EVENT_ID) + .givenFindFirst(annotationsSummary) + + liveLocationShareRedactionEventProcessor.process(fakeRealm.instance, event = event) + + verify { + liveSummary.deleteFromRealm() + annotationsSummary.deleteFromRealm() + } + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRealm.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRealm.kt index 0ebff87278..cb40889fb7 100644 --- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRealm.kt +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRealm.kt @@ -18,10 +18,13 @@ package org.matrix.android.sdk.test.fakes import io.mockk.MockKVerificationScope import io.mockk.every +import io.mockk.just import io.mockk.mockk +import io.mockk.runs import io.mockk.verify import io.realm.Realm import io.realm.RealmModel +import io.realm.RealmObject import io.realm.RealmQuery import io.realm.RealmResults import io.realm.kotlin.where @@ -97,3 +100,10 @@ inline fun RealmQuery.givenIsNotNull( every { isNotNull(fieldName) } returns this return this } + +/** + * Should be called on a mocked RealmObject and not on a real RealmObject so that the underlying final method is mocked. + */ +fun RealmObject.givenDelete() { + every { deleteFromRealm() } just runs +}