Adding task to redact live location share related events

This commit is contained in:
Maxime NATUREL 2022-07-05 15:26:42 +02:00
parent c404454cd7
commit c9273dd067
7 changed files with 308 additions and 18 deletions

View File

@ -23,6 +23,14 @@ import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEnt
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity 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.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.where(
realm: Realm,
eventId: String,
): RealmQuery<LiveLocationShareAggregatedSummaryEntity> {
return realm.where<LiveLocationShareAggregatedSummaryEntity>()
.equalTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, eventId)
}
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.where( internal fun LiveLocationShareAggregatedSummaryEntity.Companion.where(
realm: Realm, realm: Realm,
roomId: String, roomId: String,
@ -72,6 +80,13 @@ internal fun LiveLocationShareAggregatedSummaryEntity.Companion.get(
return LiveLocationShareAggregatedSummaryEntity.where(realm, roomId, eventId).findFirst() return LiveLocationShareAggregatedSummaryEntity.where(realm, roomId, eventId).findFirst()
} }
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.get(
realm: Realm,
eventId: String,
): LiveLocationShareAggregatedSummaryEntity? {
return LiveLocationShareAggregatedSummaryEntity.where(realm, eventId).findFirst()
}
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.findActiveLiveInRoomForUser( internal fun LiveLocationShareAggregatedSummaryEntity.Companion.findActiveLiveInRoomForUser(
realm: Realm, realm: Realm,
roomId: String, roomId: String,

View File

@ -58,11 +58,13 @@ import org.matrix.android.sdk.internal.session.room.directory.SetRoomDirectoryVi
import org.matrix.android.sdk.internal.session.room.location.CheckIfExistingActiveLiveTask import org.matrix.android.sdk.internal.session.room.location.CheckIfExistingActiveLiveTask
import org.matrix.android.sdk.internal.session.room.location.DefaultCheckIfExistingActiveLiveTask import org.matrix.android.sdk.internal.session.room.location.DefaultCheckIfExistingActiveLiveTask
import org.matrix.android.sdk.internal.session.room.location.DefaultGetActiveBeaconInfoForUserTask import org.matrix.android.sdk.internal.session.room.location.DefaultGetActiveBeaconInfoForUserTask
import org.matrix.android.sdk.internal.session.room.location.DefaultRedactLiveLocationShareTask
import org.matrix.android.sdk.internal.session.room.location.DefaultSendLiveLocationTask import org.matrix.android.sdk.internal.session.room.location.DefaultSendLiveLocationTask
import org.matrix.android.sdk.internal.session.room.location.DefaultSendStaticLocationTask import org.matrix.android.sdk.internal.session.room.location.DefaultSendStaticLocationTask
import org.matrix.android.sdk.internal.session.room.location.DefaultStartLiveLocationShareTask import org.matrix.android.sdk.internal.session.room.location.DefaultStartLiveLocationShareTask
import org.matrix.android.sdk.internal.session.room.location.DefaultStopLiveLocationShareTask import org.matrix.android.sdk.internal.session.room.location.DefaultStopLiveLocationShareTask
import org.matrix.android.sdk.internal.session.room.location.GetActiveBeaconInfoForUserTask import org.matrix.android.sdk.internal.session.room.location.GetActiveBeaconInfoForUserTask
import org.matrix.android.sdk.internal.session.room.location.RedactLiveLocationShareTask
import org.matrix.android.sdk.internal.session.room.location.SendLiveLocationTask import org.matrix.android.sdk.internal.session.room.location.SendLiveLocationTask
import org.matrix.android.sdk.internal.session.room.location.SendStaticLocationTask import org.matrix.android.sdk.internal.session.room.location.SendStaticLocationTask
import org.matrix.android.sdk.internal.session.room.location.StartLiveLocationShareTask import org.matrix.android.sdk.internal.session.room.location.StartLiveLocationShareTask
@ -339,4 +341,7 @@ internal abstract class RoomModule {
@Binds @Binds
abstract fun bindCheckIfExistingActiveLiveTask(task: DefaultCheckIfExistingActiveLiveTask): CheckIfExistingActiveLiveTask abstract fun bindCheckIfExistingActiveLiveTask(task: DefaultCheckIfExistingActiveLiveTask): CheckIfExistingActiveLiveTask
@Binds
abstract fun bindRedactLiveLocationShareTask(task: DefaultRedactLiveLocationShareTask): RedactLiveLocationShareTask
} }

View File

@ -0,0 +1,79 @@
/*
* 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.realm.RealmConfiguration
import org.matrix.android.sdk.internal.database.awaitTransaction
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.di.SessionDatabase
import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor
import org.matrix.android.sdk.internal.task.Task
import timber.log.Timber
import javax.inject.Inject
internal interface RedactLiveLocationShareTask : Task<RedactLiveLocationShareTask.Params, Unit> {
data class Params(
val roomId: String,
val beaconInfoEventId: String,
val reason: String?
)
}
internal class DefaultRedactLiveLocationShareTask @Inject constructor(
@SessionDatabase private val realmConfiguration: RealmConfiguration,
private val localEchoEventFactory: LocalEchoEventFactory,
private val eventSenderProcessor: EventSenderProcessor,
) : RedactLiveLocationShareTask {
override suspend fun execute(params: RedactLiveLocationShareTask.Params) {
val relatedEventIds = getRelatedEventIdsOfLive(params.beaconInfoEventId)
Timber.d("beacon with id ${params.beaconInfoEventId} has related event ids: ${relatedEventIds.joinToString(", ")}")
relatedEventIds.forEach { eventId ->
redactEvent(
eventId = eventId,
roomId = params.roomId,
reason = params.reason
)
}
redactEvent(
eventId = params.beaconInfoEventId,
roomId = params.roomId,
reason = params.reason
)
}
private suspend fun getRelatedEventIdsOfLive(beaconInfoEventId: String): List<String> {
return awaitTransaction(realmConfiguration) { realm ->
val aggregatedSummaryEntity = LiveLocationShareAggregatedSummaryEntity.get(
realm = realm,
eventId = beaconInfoEventId
)
aggregatedSummaryEntity?.relatedEventIds?.toList() ?: emptyList()
}
}
private fun redactEvent(eventId: String, roomId: String, reason: String?) {
Timber.d("redacting event of id $eventId")
val redactionEcho = localEchoEventFactory.createRedactEvent(roomId, eventId, reason)
localEchoEventFactory.createLocalEcho(redactionEcho)
eventSenderProcessor.postRedaction(redactionEcho, reason)
}
}

View File

@ -0,0 +1,116 @@
/*
* 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.unmockkAll
import io.realm.RealmList
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Test
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.FakeEventSenderProcessor
import org.matrix.android.sdk.test.fakes.FakeLocalEchoEventFactory
import org.matrix.android.sdk.test.fakes.FakeRealm
import org.matrix.android.sdk.test.fakes.FakeRealmConfiguration
import org.matrix.android.sdk.test.fakes.givenEqualTo
import org.matrix.android.sdk.test.fakes.givenFindFirst
private const val A_ROOM_ID = "room-id"
private const val AN_EVENT_ID = "event-id"
private const val AN_EVENT_ID_1 = "event-id-1"
private const val AN_EVENT_ID_2 = "event-id-2"
private const val AN_EVENT_ID_3 = "event-id-3"
private const val A_REASON = "reason"
@ExperimentalCoroutinesApi
class DefaultRedactLiveLocationShareTaskTest {
private val fakeRealmConfiguration = FakeRealmConfiguration()
private val fakeLocalEchoEventFactory = FakeLocalEchoEventFactory()
private val fakeEventSenderProcessor = FakeEventSenderProcessor()
private val fakeRealm = FakeRealm()
private val defaultRedactLiveLocationShareTask = DefaultRedactLiveLocationShareTask(
realmConfiguration = fakeRealmConfiguration.instance,
localEchoEventFactory = fakeLocalEchoEventFactory.instance,
eventSenderProcessor = fakeEventSenderProcessor
)
@After
fun tearDown() {
unmockkAll()
}
@Test
fun `given parameters when calling the task then it is correctly executed`() = runTest {
val params = RedactLiveLocationShareTask.Params(
roomId = A_ROOM_ID,
beaconInfoEventId = AN_EVENT_ID,
reason = A_REASON
)
fakeRealmConfiguration.givenAwaitTransaction<List<String>>(fakeRealm.instance)
val relatedEventIds = listOf(AN_EVENT_ID_1, AN_EVENT_ID_2, AN_EVENT_ID_3)
val aggregatedSummaryEntity = LiveLocationShareAggregatedSummaryEntity(
eventId = AN_EVENT_ID,
relatedEventIds = RealmList(*relatedEventIds.toTypedArray()),
)
fakeRealm.givenWhere<LiveLocationShareAggregatedSummaryEntity>()
.givenEqualTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, AN_EVENT_ID)
.givenFindFirst(aggregatedSummaryEntity)
val redactedEvent = fakeLocalEchoEventFactory.givenCreateRedactEvent(
eventId = AN_EVENT_ID,
withLocalEcho = true
)
fakeEventSenderProcessor.givenPostRedaction(event = redactedEvent, reason = A_REASON)
val redactedEvent1 = fakeLocalEchoEventFactory.givenCreateRedactEvent(
eventId = AN_EVENT_ID_1,
withLocalEcho = true
)
fakeEventSenderProcessor.givenPostRedaction(event = redactedEvent1, reason = A_REASON)
val redactedEvent2 = fakeLocalEchoEventFactory.givenCreateRedactEvent(
eventId = AN_EVENT_ID_2,
withLocalEcho = true
)
fakeEventSenderProcessor.givenPostRedaction(event = redactedEvent2, reason = A_REASON)
val redactedEvent3 = fakeLocalEchoEventFactory.givenCreateRedactEvent(
eventId = AN_EVENT_ID_3,
withLocalEcho = true
)
fakeEventSenderProcessor.givenPostRedaction(event = redactedEvent3, reason = A_REASON)
defaultRedactLiveLocationShareTask.execute(params)
fakeLocalEchoEventFactory.verifyCreateRedactEvent(
roomId = A_ROOM_ID,
eventId = AN_EVENT_ID,
reason = A_REASON
)
fakeLocalEchoEventFactory.verifyCreateLocalEcho(redactedEvent)
relatedEventIds.forEach { eventId ->
fakeLocalEchoEventFactory.verifyCreateRedactEvent(
roomId = A_ROOM_ID,
eventId = eventId,
reason = A_REASON
)
}
fakeLocalEchoEventFactory.verifyCreateLocalEcho(redactedEvent1)
fakeLocalEchoEventFactory.verifyCreateLocalEcho(redactedEvent2)
fakeLocalEchoEventFactory.verifyCreateLocalEcho(redactedEvent3)
}
}

View File

@ -27,4 +27,8 @@ internal class FakeEventSenderProcessor : EventSenderProcessor by mockk() {
fun givenPostEventReturns(event: Event, cancelable: Cancelable) { fun givenPostEventReturns(event: Event, cancelable: Cancelable) {
every { postEvent(event) } returns cancelable every { postEvent(event) } returns cancelable
} }
fun givenPostRedaction(event: Event, reason: String?) {
every { postRedaction(event, reason) } returns mockk()
}
} }

View File

@ -46,24 +46,6 @@ internal class FakeLocalEchoEventFactory {
return event return event
} }
fun givenCreateLiveLocationEvent(withLocalEcho: Boolean): Event {
val event = Event()
every {
instance.createLiveLocationEvent(
beaconInfoEventId = any(),
roomId = any(),
latitude = any(),
longitude = any(),
uncertainty = any()
)
} returns event
if (withLocalEcho) {
every { instance.createLocalEcho(event) } just runs
}
return event
}
fun verifyCreateStaticLocationEvent( fun verifyCreateStaticLocationEvent(
roomId: String, roomId: String,
latitude: Double, latitude: Double,
@ -82,6 +64,24 @@ internal class FakeLocalEchoEventFactory {
} }
} }
fun givenCreateLiveLocationEvent(withLocalEcho: Boolean): Event {
val event = Event()
every {
instance.createLiveLocationEvent(
beaconInfoEventId = any(),
roomId = any(),
latitude = any(),
longitude = any(),
uncertainty = any()
)
} returns event
if (withLocalEcho) {
every { instance.createLocalEcho(event) } just runs
}
return event
}
fun verifyCreateLiveLocationEvent( fun verifyCreateLiveLocationEvent(
roomId: String, roomId: String,
beaconInfoEventId: String, beaconInfoEventId: String,
@ -100,6 +100,36 @@ internal class FakeLocalEchoEventFactory {
} }
} }
fun givenCreateRedactEvent(eventId: String, withLocalEcho: Boolean): Event {
val event = Event()
every {
instance.createRedactEvent(
roomId = any(),
eventId = eventId,
reason = any()
)
} returns event
if (withLocalEcho) {
every { instance.createLocalEcho(event) } just runs
}
return event
}
fun verifyCreateRedactEvent(
roomId: String,
eventId: String,
reason: String?
) {
verify {
instance.createRedactEvent(
roomId = roomId,
eventId = eventId,
reason = reason
)
}
}
fun verifyCreateLocalEcho(event: Event) { fun verifyCreateLocalEcho(event: Event) {
verify { instance.createLocalEcho(event) } verify { instance.createLocalEcho(event) }
} }

View File

@ -0,0 +1,41 @@
/*
* 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.test.fakes
import io.mockk.coEvery
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.slot
import io.realm.Realm
import io.realm.RealmConfiguration
import org.matrix.android.sdk.internal.database.awaitTransaction
internal class FakeRealmConfiguration {
init {
mockkStatic("org.matrix.android.sdk.internal.database.AsyncTransactionKt")
}
val instance = mockk<RealmConfiguration>()
fun <T> givenAwaitTransaction(realm: Realm) {
val transaction = slot<suspend (Realm) -> T>()
coEvery { awaitTransaction(instance, capture(transaction)) } coAnswers {
secondArg<suspend (Realm) -> T>().invoke(realm)
}
}
}