From ca74aaf4d1b402b5f55799f01b3cb66833c143ca Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 2 Dec 2020 11:06:35 +0100 Subject: [PATCH] implement room preview --- src/Link.js | 2 +- src/preview/HomeServer.js | 38 ++++++++++++++++++++++++++++++--- src/preview/PreviewViewModel.js | 25 +++++++++++++++++++--- src/utils/xhr.js | 5 ++++- 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/Link.js b/src/Link.js index 596e6eb..63a3d41 100644 --- a/src/Link.js +++ b/src/Link.js @@ -23,7 +23,7 @@ const EVENT_WITH_ROOMALIAS_PATTERN = /^[#]([^:]*):(.+)\/\$([^:]+):(.+)$/; const USERID_PATTERN = /^@([^:]+):(.+)$/; const GROUPID_PATTERN = /^\+([^:]+):(.+)$/; -const IdentifierKind = createEnum( +export const IdentifierKind = createEnum( "RoomId", "RoomAlias", "UserId", diff --git a/src/preview/HomeServer.js b/src/preview/HomeServer.js index ac9a597..872d8af 100644 --- a/src/preview/HomeServer.js +++ b/src/preview/HomeServer.js @@ -43,7 +43,7 @@ export class HomeServer { } async getUserProfile(userId) { - const {body} = await this._request(`${this.baseURL}/_matrix/client/r0/profile/${userId}`, {method: "GET"}).response(); + const {body} = await this._request(`${this.baseURL}/_matrix/client/r0/profile/${encodeURIComponent(userId)}`).response(); return body; } @@ -51,8 +51,28 @@ export class HomeServer { //`/_matrix/client/r0/groups/${groupId}/profile` } - getPublicRooms() { + async findPublicRoomById(roomId) { + const {body, status} = await this._request(`${this.baseURL}/_matrix/client/r0/directory/list/room/${encodeURIComponent(roomId)}`).response(); + if (status !== 200 || body.visibility !== "public") { + return; + } + let nextBatch; + do { + const queryParams = encodeQueryParams({limit: 10000, since: nextBatch}); + const {body, status} = await this._request(`${this.baseURL}/_matrix/client/r0/publicRooms?${queryParams}`).response(); + nextBatch = body.next_batch; + const publicRoom = body.chunk.find(c => c.room_id === roomId); + if (publicRoom) { + return publicRoom; + } + } while (nextBatch); + } + async getRoomIdFromAlias(alias) { + const {status, body} = await this._request(`${this.baseURL}/_matrix/client/r0/directory/room/${encodeURIComponent(alias)}`).response(); + if (status === 200) { + return body.room_id; + } } mxcUrlThumbnail(url, width, height, method) { @@ -73,4 +93,16 @@ function parseMxcUrl(url) { } else { return null; } -} \ No newline at end of file +} + +function encodeQueryParams(queryParams) { + return Object.entries(queryParams || {}) + .filter(([, value]) => value !== undefined) + .map(([name, value]) => { + if (typeof value === "object") { + value = JSON.stringify(value); + } + return `${encodeURIComponent(name)}=${encodeURIComponent(value)}`; + }) + .join("&"); +} diff --git a/src/preview/PreviewViewModel.js b/src/preview/PreviewViewModel.js index eb1103b..cf024df 100644 --- a/src/preview/PreviewViewModel.js +++ b/src/preview/PreviewViewModel.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {LinkKind, getLabelForLinkKind} from "../Link.js"; +import {LinkKind, IdentifierKind, getLabelForLinkKind} from "../Link.js"; import {ViewModel} from "../utils/ViewModel.js"; import {resolveServer} from "./HomeServer.js"; import {ClientListViewModel} from "../client/ClientListViewModel.js"; @@ -32,6 +32,7 @@ export class PreviewViewModel extends ViewModel { this.loading = false; this.name = null; this.avatarUrl = null; + this.identifier = null; this.previewDomain = null; this.clientsViewModel = null; this.acceptInstructions = null; @@ -51,6 +52,10 @@ export class PreviewViewModel extends ViewModel { switch (this._link.kind) { case LinkKind.User: await this._loadUserPreview(homeserver, this._link.identifier); + break; + case LinkKind.Room: + await this._loadRoomPreview(homeserver, this._link); + break; } // assume we're done if nothing threw this.previewDomain = server; @@ -69,10 +74,24 @@ export class PreviewViewModel extends ViewModel { this.avatarUrl = profile.avatar_url ? homeserver.mxcUrlThumbnail(profile.avatar_url, 64, 64, "crop") : null; + this.identifier = userId; } - get identifier() { - return this._link.identifier; + async _loadRoomPreview(homeserver, link) { + let publicRoom; + if (link.identifierKind === IdentifierKind.RoomId) { + publicRoom = await homeserver.findPublicRoomById(link.identifier); + } else if (link.identifierKind === IdentifierKind.RoomAlias) { + const roomId = await homeserver.getRoomIdFromAlias(link.identifier); + if (roomId) { + publicRoom = await homeserver.findPublicRoomById(roomId); + } + } + this.name = publicRoom?.name || publicRoom?.canonical_alias || link.identifier; + this.avatarUrl = publicRoom?.avatar_url ? + homeserver.mxcUrlThumbnail(publicRoom.avatar_url, 64, 64, "crop") : + null; + this.identifier = `${publicRoom?.canonical_alias || link.identifier} | ${publicRoom?.num_joined_members} members`; } get showClientsLabel() { diff --git a/src/utils/xhr.js b/src/utils/xhr.js index 555542d..2c0a865 100644 --- a/src/utils/xhr.js +++ b/src/utils/xhr.js @@ -79,7 +79,10 @@ function xhrAsPromise(xhr, method, url) { }); } -export function xhrRequest(url, options) { +export function xhrRequest(url, options = {}) { + if (!options.method) { + options.method = "GET"; + } let {cache, body, method} = options; if (!cache) { url = addCacheBuster(url);