From b1c95e32eb58b1fc5fd8230390e6933fa9849454 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 8 Sep 2021 13:55:22 +0200 Subject: [PATCH] Better room preview, use room Summary API if available --- changelog.d/3946.bugfix | 1 + .../session/room/model/RoomStrippedState.kt | 111 ++++++++++++++++++ .../session/room/GetRoomSummaryTask.kt | 42 +++++++ .../sdk/internal/session/room/RoomAPI.kt | 13 +- .../sdk/internal/session/room/RoomModule.kt | 3 + .../session/room/peeking/PeekRoomTask.kt | 21 ++++ 6 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 changelog.d/3946.bugfix create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomStrippedState.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/GetRoomSummaryTask.kt diff --git a/changelog.d/3946.bugfix b/changelog.d/3946.bugfix new file mode 100644 index 0000000000..ba9603da24 --- /dev/null +++ b/changelog.d/3946.bugfix @@ -0,0 +1 @@ + Restricted Room previews aren't working \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomStrippedState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomStrippedState.kt new file mode 100644 index 0000000000..dc0c00b282 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomStrippedState.kt @@ -0,0 +1,111 @@ +/* + * 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.api.session.room.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +/** + * These are the same fields as those returned by /publicRooms, with a few additions: room_type, membership and is_encrypted. + */ +@JsonClass(generateAdapter = true) +data class RoomStrippedState( + /** + * Aliases of the room. May be empty. + */ + @Json(name = "aliases") + val aliases: List? = null, + + /** + * The canonical alias of the room, if any. + */ + @Json(name = "canonical_alias") + val canonicalAlias: String? = null, + + /** + * The name of the room, if any. + */ + @Json(name = "name") + val name: String? = null, + + /** + * Required. The number of members joined to the room. + */ + @Json(name = "num_joined_members") + val numJoinedMembers: Int = 0, + + /** + * Required. The ID of the room. + */ + @Json(name = "room_id") + val roomId: String, + + /** + * The topic of the room, if any. + */ + @Json(name = "topic") + val topic: String? = null, + + /** + * Required. Whether the room may be viewed by guest users without joining. + */ + @Json(name = "world_readable") + val worldReadable: Boolean = false, + + /** + * Required. Whether guest users may join the room and participate in it. If they can, + * they will be subject to ordinary power level rules like any other user. + */ + @Json(name = "guest_can_join") + val guestCanJoin: Boolean = false, + + /** + * The URL for the room's avatar, if one is set. + */ + @Json(name = "avatar_url") + val avatarUrl: String? = null, + + /** + * Undocumented item + */ + @Json(name = "m.federate") + val isFederated: Boolean = false, + + /** + * Optional. If the room is encrypted. This is already accessible as stripped state. + */ + @Json(name = "is_encrypted") + val isEncrypted: Boolean?, + + /** + * Optional. Type of the room, if any, i.e. m.space + */ + @Json(name = "room_type") + val roomType: String?, + + /** + * The current membership of this user in the room. Usually leave if the room is fetched over federation. + */ + @Json(name = "membership") + val membership: String? +) { + /** + * Return the canonical alias, or the first alias from the list of aliases, or null + */ + fun getPrimaryAlias(): String? { + return canonicalAlias ?: aliases?.firstOrNull() + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/GetRoomSummaryTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/GetRoomSummaryTask.kt new file mode 100644 index 0000000000..d9547d9e3a --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/GetRoomSummaryTask.kt @@ -0,0 +1,42 @@ +/* + * 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 org.matrix.android.sdk.api.session.room.model.RoomStrippedState +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver +import org.matrix.android.sdk.internal.network.executeRequest +import org.matrix.android.sdk.internal.task.Task +import javax.inject.Inject + +internal interface GetRoomSummaryTask : Task { + data class Params( + val roomId: String, + val viaServers: List? + ) +} + +internal class DefaultGetRoomSummaryTask @Inject constructor( + private val roomAPI: RoomAPI, + private val globalErrorReceiver: GlobalErrorReceiver +) : GetRoomSummaryTask { + + override suspend fun execute(params: GetRoomSummaryTask.Params): RoomStrippedState { + return executeRequest(globalErrorReceiver) { + roomAPI.getRoomSummary(params.roomId, params.viaServers) + } + } +} 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 535fa9df71..9d226555b4 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 @@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.room import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.model.RoomStrippedState import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse import org.matrix.android.sdk.api.util.JsonDict @@ -254,7 +255,7 @@ internal interface RoomAPI { @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "join/{roomIdOrAlias}") suspend fun join(@Path("roomIdOrAlias") roomIdOrAlias: String, @Query("server_name") viaServers: List, - @Body params: JsonDict): JoinRoomResponse + @Body params: JsonDict): JoinRoomResponse /** * Leave the given room. @@ -381,4 +382,14 @@ internal interface RoomAPI { @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/upgrade") suspend fun upgradeRoom(@Path("roomId") roomId: String, @Body body: RoomUpgradeBody): RoomUpgradeResponse + + /** + * The API returns the summary of the specified room, if the room could be found and the client should be able to view + * its contents according to the join_rules, history visibility, space membership and similar rules outlined in MSC3173 + * as well as if the user is already a member of that room. + * https://github.com/deepbluev7/matrix-doc/blob/room-summaries/proposals/3266-room-summary.md + */ + @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "im.nheko.summary/rooms/{roomidOrAlias}/summary") + suspend fun getRoomSummary(@Path("roomidOrAlias") roomidOrAlias: String, + @Query("via") viaServers: List?): RoomStrippedState } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt index 794970705c..27e295fc1b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt @@ -253,4 +253,7 @@ internal abstract class RoomModule { @Binds abstract fun bindSign3pidInvitationTask(task: DefaultSign3pidInvitationTask): Sign3pidInvitationTask + + @Binds + abstract fun bindSGetRoomSummaryTask(task: DefaultGetRoomSummaryTask): GetRoomSummaryTask } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt index 219e9c903f..63fc26e9d6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt @@ -33,6 +33,7 @@ import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsFi import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams import org.matrix.android.sdk.api.session.room.peeking.PeekResult import org.matrix.android.sdk.api.util.MatrixItem +import org.matrix.android.sdk.internal.session.room.GetRoomSummaryTask import org.matrix.android.sdk.internal.session.room.alias.GetRoomIdByAliasTask import org.matrix.android.sdk.internal.session.room.directory.GetPublicRoomTask import org.matrix.android.sdk.internal.session.room.directory.GetRoomDirectoryVisibilityTask @@ -49,6 +50,7 @@ internal class DefaultPeekRoomTask @Inject constructor( private val getRoomIdByAliasTask: GetRoomIdByAliasTask, private val getRoomDirectoryVisibilityTask: GetRoomDirectoryVisibilityTask, private val getPublicRoomTask: GetPublicRoomTask, + private val getRoomSummaryTask: GetRoomSummaryTask, private val resolveRoomStateTask: ResolveRoomStateTask ) : PeekRoomTask { @@ -70,6 +72,25 @@ internal class DefaultPeekRoomTask @Inject constructor( serverList = emptyList() } + // If the room summary API is available on the Home Server we should try it first + val strippedState = tryOrNull("Failed to get room stripped state roomId:$roomId") { + getRoomSummaryTask.execute(GetRoomSummaryTask.Params(roomId, serverList)) + } + if (strippedState != null) { + return PeekResult.Success( + roomId = strippedState.roomId, + alias = strippedState.getPrimaryAlias() ?: params.roomIdOrAlias.takeIf { isAlias }, + avatarUrl = strippedState.avatarUrl, + name = strippedState.name, + topic = strippedState.topic, + numJoinedMembers = strippedState.numJoinedMembers, + viaServers = serverList, + roomType = strippedState.roomType, + someMembers = null, + isPublic = strippedState.worldReadable + ) + } + // Is it a public room? val visibilityRes = tryOrNull("## PEEK: failed to get visibility") { getRoomDirectoryVisibilityTask.execute(GetRoomDirectoryVisibilityTask.Params(roomId))