From fd7c50f6836abbd82afd8191017d06f57a0158b1 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 3 Feb 2021 14:05:22 +0000 Subject: [PATCH 1/2] Move route splitting inside route parsing --- .../permalinks/ElementPermalinkConstructor.js | 18 +++++++++++------- src/utils/permalinks/Permalinks.js | 4 ++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/utils/permalinks/ElementPermalinkConstructor.js b/src/utils/permalinks/ElementPermalinkConstructor.js index 29f2602304..7d1096e22d 100644 --- a/src/utils/permalinks/ElementPermalinkConstructor.js +++ b/src/utils/permalinks/ElementPermalinkConstructor.js @@ -75,11 +75,19 @@ export default class ElementPermalinkConstructor extends PermalinkConstructor { throw new Error("Does not appear to be a permalink"); } - const parts = fullUrl.substring(`${this._elementUrl}/#/`.length).split("/"); - return ElementPermalinkConstructor.parseLinkParts(parts); + const parts = fullUrl.substring(`${this._elementUrl}/#/`.length); + return ElementPermalinkConstructor.parseAppRoute(parts); } - static parseLinkParts(parts: string[]): PermalinkParts { + /** + * Parses an app route (`(user|room|group)/identifer`) to a Matrix entity + * (room, user, group). + * @param {string} route The app route + * @returns {PermalinkParts} + */ + static parseAppRoute(route: string): PermalinkParts { + const parts = route.split("/"); + if (parts.length < 2) { // we're expecting an entity and an ID of some kind at least throw new Error("URL is missing parts"); } @@ -93,10 +101,6 @@ export default class ElementPermalinkConstructor extends PermalinkConstructor { // Probably a group, no further parsing needed. return PermalinkParts.forGroup(entity); } else if (entityType === 'room') { - if (parts.length === 2) { - return PermalinkParts.forRoom(entity, []); - } - // rejoin the rest because v3 events can have slashes (annoyingly) const eventIdAndQuery = parts.length > 2 ? parts.slice(2).join('/') : ""; const secondaryParts = eventIdAndQuery.split("?"); diff --git a/src/utils/permalinks/Permalinks.js b/src/utils/permalinks/Permalinks.js index 9851bc3cb3..086abc669d 100644 --- a/src/utils/permalinks/Permalinks.js +++ b/src/utils/permalinks/Permalinks.js @@ -414,8 +414,8 @@ export function parsePermalink(fullUrl: string): PermalinkParts { */ export function parseAppLocalLink(localLink: string): PermalinkParts { try { - const segments = localLink.replace("#/", "").split("/"); - return ElementPermalinkConstructor.parseLinkParts(segments); + const segments = localLink.replace("#/", ""); + return ElementPermalinkConstructor.parseAppRoute(segments); } catch (e) { // Ignore failures } From 474c029db5cda5b2af05505ba31d7e7956b00824 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 3 Feb 2021 15:18:19 +0000 Subject: [PATCH 2/2] Fix permalink via parsing for rooms This adjusts the app local link parsing path to better handle `via`s in query params. Previously this path only expected them when an event ID was also present, but it's also valid to have `via`s without event IDs as well. Fixes https://github.com/vector-im/element-web/issues/16345 --- .../permalinks/ElementPermalinkConstructor.js | 18 +++++------ .../views/messages/TextualBody-test.js | 32 +++++++++++++++++++ test/test-utils.js | 1 + 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/utils/permalinks/ElementPermalinkConstructor.js b/src/utils/permalinks/ElementPermalinkConstructor.js index 7d1096e22d..da7f5797ea 100644 --- a/src/utils/permalinks/ElementPermalinkConstructor.js +++ b/src/utils/permalinks/ElementPermalinkConstructor.js @@ -92,6 +92,11 @@ export default class ElementPermalinkConstructor extends PermalinkConstructor { throw new Error("URL is missing parts"); } + // Split optional query out of last part + const [lastPartMaybeWithQuery] = parts.splice(-1, 1); + const [lastPart, query = ""] = lastPartMaybeWithQuery.split("?"); + parts.push(lastPart); + const entityType = parts[0]; const entity = parts[1]; if (entityType === 'user') { @@ -101,16 +106,9 @@ export default class ElementPermalinkConstructor extends PermalinkConstructor { // Probably a group, no further parsing needed. return PermalinkParts.forGroup(entity); } else if (entityType === 'room') { - // rejoin the rest because v3 events can have slashes (annoyingly) - const eventIdAndQuery = parts.length > 2 ? parts.slice(2).join('/') : ""; - const secondaryParts = eventIdAndQuery.split("?"); - - const eventId = secondaryParts[0]; - const query = secondaryParts.length > 1 ? secondaryParts[1] : ""; - - // TODO: Verify Element works with via args - const via = query.split("via=").filter(p => !!p); - + // Rejoin the rest because v3 events can have slashes (annoyingly) + const eventId = parts.length > 2 ? parts.slice(2).join('/') : ""; + const via = query.split(/&?via=/).filter(p => !!p); return PermalinkParts.forEvent(entity, eventId, via); } else { throw new Error("Unknown entity type in permalink"); diff --git a/test/components/views/messages/TextualBody-test.js b/test/components/views/messages/TextualBody-test.js index 461af19658..d5b80b6756 100644 --- a/test/components/views/messages/TextualBody-test.js +++ b/test/components/views/messages/TextualBody-test.js @@ -242,6 +242,38 @@ describe("", () => { 'rel="noreferrer noopener">event link with text', ); }); + + it("pills appear for room links with vias", () => { + const ev = mkEvent({ + type: "m.room.message", + room: "room_id", + user: "sender", + content: { + body: + "A [room link](https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com" + + "?via=example.com&via=bob.com) with vias", + msgtype: "m.text", + format: "org.matrix.custom.html", + formatted_body: + "A room link with vias", + }, + event: true, + }); + + const wrapper = mount(); + expect(wrapper.text()).toBe("A !ZxbRYPQXDXKGmDnJNg:example.com with vias"); + const content = wrapper.find(".mx_EventTile_body"); + expect(content.html()).toBe( + '' + + 'A ' + + '!ZxbRYPQXDXKGmDnJNg:example.com with vias', + ); + }); }); it("renders url previews correctly", () => { diff --git a/test/test-utils.js b/test/test-utils.js index c8e623b1d9..839e1d6cd8 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -243,6 +243,7 @@ export function mkStubRoom(roomId = null) { on: jest.fn(), removeListener: jest.fn(), getDMInviter: jest.fn(), + getAvatarUrl: () => 'mxc://avatar.url/room.png', }; }