Draft MSC3912

This commit is contained in:
yostyle 2023-01-20 21:29:24 +01:00 committed by Florian Renaud
parent 1e951cd838
commit 781b9954d1
12 changed files with 77 additions and 13 deletions

View file

@ -75,6 +75,11 @@ data class HomeServerCapabilities(
* True if the home server supports remote toggle of Pusher for a given device.
*/
val canRemotelyTogglePushNotificationsOfDevices: Boolean = false,
/**
* True if the home server supports event redaction with relations.
*/
var canRedactEventWithRelations: Boolean = false,
) {
enum class RoomCapabilitySupport {

View file

@ -58,6 +58,8 @@ private const val FEATURE_QR_CODE_LOGIN = "org.matrix.msc3882"
private const val FEATURE_THREADS_MSC3771 = "org.matrix.msc3771"
private const val FEATURE_THREADS_MSC3773 = "org.matrix.msc3773"
private const val FEATURE_REMOTE_TOGGLE_PUSH_NOTIFICATIONS_MSC3881 = "org.matrix.msc3881"
private const val FEATURE_EVENT_REDACTION_WITH_RELATIONS = "org.matrix.msc3912"
private const val FEATURE_EVENT_REDACTION_WITH_RELATIONS_STABLE = "org.matrix.msc3912.stable"
/**
* Return true if the SDK supports this homeserver version.
@ -153,3 +155,13 @@ private fun Versions.getMaxVersion(): HomeServerVersion {
internal fun Versions.doesServerSupportRemoteToggleOfPushNotifications(): Boolean {
return unstableFeatures?.get(FEATURE_REMOTE_TOGGLE_PUSH_NOTIFICATIONS_MSC3881).orFalse()
}
/**
* Indicate if the server supports MSC3912: https://github.com/matrix-org/matrix-spec-proposals/pull/3912.
*
* @return true if event redaction with relations is supported
*/
internal fun Versions.doesServerSupportRedactEventWithRelations(): Boolean {
return unstableFeatures?.get(FEATURE_EVENT_REDACTION_WITH_RELATIONS).orFalse() ||
unstableFeatures?.get(FEATURE_EVENT_REDACTION_WITH_RELATIONS_STABLE).orFalse()
}

View file

@ -15,8 +15,10 @@
*/
package org.matrix.android.sdk.internal.crypto.tasks
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.session.room.EventRedactBody
import org.matrix.android.sdk.internal.session.room.RoomAPI
import org.matrix.android.sdk.internal.task.Task
import javax.inject.Inject
@ -26,22 +28,31 @@ internal interface RedactEventTask : Task<RedactEventTask.Params, String> {
val txID: String,
val roomId: String,
val eventId: String,
val reason: String?
val reason: String?,
val withRelations: List<String>?
)
}
internal class DefaultRedactEventTask @Inject constructor(
private val roomAPI: RoomAPI,
private val globalErrorReceiver: GlobalErrorReceiver
private val globalErrorReceiver: GlobalErrorReceiver,
private val homeServerCapabilitiesService: HomeServerCapabilitiesService,
) : RedactEventTask {
override suspend fun execute(params: RedactEventTask.Params): String {
val withRelations = if (homeServerCapabilitiesService.getHomeServerCapabilities().canRedactEventWithRelations &&
!params.withRelations.isNullOrEmpty()) {
params.withRelations
} else {
null
}
val response = executeRequest(globalErrorReceiver) {
roomAPI.redactEvent(
txId = params.txID,
roomId = params.roomId,
eventId = params.eventId,
reason = if (params.reason == null) emptyMap() else mapOf("reason" to params.reason)
body = EventRedactBody(params.reason, withRelations)
)
}
return response.eventId

View file

@ -47,6 +47,7 @@ internal object HomeServerCapabilitiesMapper {
canLoginWithQrCode = entity.canLoginWithQrCode,
canUseThreadReadReceiptsAndNotifications = entity.canUseThreadReadReceiptsAndNotifications,
canRemotelyTogglePushNotificationsOfDevices = entity.canRemotelyTogglePushNotificationsOfDevices,
canRedactEventWithRelations = entity.canRedactEventWithRelations,
)
}

View file

@ -34,6 +34,7 @@ internal open class HomeServerCapabilitiesEntity(
var canLoginWithQrCode: Boolean = false,
var canUseThreadReadReceiptsAndNotifications: Boolean = false,
var canRemotelyTogglePushNotificationsOfDevices: Boolean = false,
var canRedactEventWithRelations: Boolean = false,
) : RealmObject() {
companion object

View file

@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
import org.matrix.android.sdk.internal.auth.version.Versions
import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices
import org.matrix.android.sdk.internal.auth.version.doesServerSupportQrCodeLogin
import org.matrix.android.sdk.internal.auth.version.doesServerSupportRedactEventWithRelations
import org.matrix.android.sdk.internal.auth.version.doesServerSupportRemoteToggleOfPushNotifications
import org.matrix.android.sdk.internal.auth.version.doesServerSupportThreadUnreadNotifications
import org.matrix.android.sdk.internal.auth.version.doesServerSupportThreads
@ -154,6 +155,8 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
getVersionResult.doesServerSupportQrCodeLogin()
homeServerCapabilitiesEntity.canRemotelyTogglePushNotificationsOfDevices =
getVersionResult.doesServerSupportRemoteToggleOfPushNotifications()
homeServerCapabilitiesEntity.canRedactEventWithRelations =
getVersionResult.doesServerSupportRedactEventWithRelations()
}
if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) {

View file

@ -0,0 +1,29 @@
/*
* Copyright 2021 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
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class EventRedactBody(
@Json(name = "reason")
val reason: String? = null,
@Json(name = "with_relations")
val withRelations: List<String>? = null
)

View file

@ -350,14 +350,14 @@ internal interface RoomAPI {
* @param txId the transaction Id
* @param roomId the room id
* @param eventId the event to delete
* @param reason json containing reason key {"reason": "Indecent material"}
* @param body body containing reason key {"reason": "Indecent material"} and with_relations
*/
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/redact/{eventId}/{txnId}")
suspend fun redactEvent(
@Path("txnId") txId: String,
@Path("roomId") roomId: String,
@Path("eventId") eventId: String,
@Body reason: Map<String, String>
@Body body: EventRedactBody
): SendResponse
/**

View file

@ -26,9 +26,9 @@ internal interface EventSenderProcessor : SessionLifecycleObserver {
fun postEvent(event: Event, encrypt: Boolean): Cancelable
fun postRedaction(redactionLocalEcho: Event, reason: String?): Cancelable
fun postRedaction(redactionLocalEcho: Event, reason: String?, withRelations: List<String>?): Cancelable
fun postRedaction(redactionLocalEchoId: String, eventToRedactId: String, roomId: String, reason: String?): Cancelable
fun postRedaction(redactionLocalEchoId: String, eventToRedactId: String, roomId: String, reason: String?, withRelations: List<String>?): Cancelable
fun postTask(task: QueuedTask): Cancelable

View file

@ -101,12 +101,12 @@ internal class EventSenderProcessorCoroutine @Inject constructor(
return postTask(task)
}
override fun postRedaction(redactionLocalEcho: Event, reason: String?): Cancelable {
return postRedaction(redactionLocalEcho.eventId!!, redactionLocalEcho.redacts!!, redactionLocalEcho.roomId!!, reason)
override fun postRedaction(redactionLocalEcho: Event, reason: String?, withRelations: List<String>?): Cancelable {
return postRedaction(redactionLocalEcho.eventId!!, redactionLocalEcho.redacts!!, redactionLocalEcho.roomId!!, reason, withRelations)
}
override fun postRedaction(redactionLocalEchoId: String, eventToRedactId: String, roomId: String, reason: String?): Cancelable {
val task = queuedTaskFactory.createRedactTask(redactionLocalEchoId, eventToRedactId, roomId, reason)
override fun postRedaction(redactionLocalEchoId: String, eventToRedactId: String, roomId: String, reason: String?, withRelations: List<String>?): Cancelable {
val task = queuedTaskFactory.createRedactTask(redactionLocalEchoId, eventToRedactId, roomId, reason, withRelations)
return postTask(task)
}

View file

@ -43,12 +43,13 @@ internal class QueuedTaskFactory @Inject constructor(
)
}
fun createRedactTask(redactionLocalEcho: String, eventId: String, roomId: String, reason: String?): QueuedTask {
fun createRedactTask(redactionLocalEcho: String, eventId: String, roomId: String, reason: String?, withRelations: List<String>?): QueuedTask {
return RedactQueuedTask(
redactionLocalEchoId = redactionLocalEcho,
toRedactEventId = eventId,
roomId = roomId,
reason = reason,
withRelations = withRelations,
redactEventTask = redactEventTask,
localEchoRepository = localEchoRepository,
cancelSendTracker = cancelSendTracker

View file

@ -26,13 +26,14 @@ internal class RedactQueuedTask(
val redactionLocalEchoId: String,
private val roomId: String,
private val reason: String?,
private val withRelations: List<String>?,
private val redactEventTask: RedactEventTask,
private val localEchoRepository: LocalEchoRepository,
private val cancelSendTracker: CancelSendTracker
) : QueuedTask(queueIdentifier = roomId, taskIdentifier = redactionLocalEchoId) {
override suspend fun doExecute() {
redactEventTask.execute(RedactEventTask.Params(redactionLocalEchoId, roomId, toRedactEventId, reason))
redactEventTask.execute(RedactEventTask.Params(redactionLocalEchoId, roomId, toRedactEventId, reason, withRelations))
}
override fun onTaskFailed() {