Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Show a tile for an unloaded predecessor room if it has via_servers #10483

Merged
merged 21 commits into from
Apr 12, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
20dc6df
Improve typing in constructor of RoomPermalinkCreator
andybalaam Mar 30, 2023
c6736e0
Provide via servers if present when navigating to predecessor room fr…
andybalaam Mar 30, 2023
0075c0c
Show an error tile when the predecessor room is not found
andybalaam Mar 30, 2023
edb38a8
Test for MatrixToPermalinkConstructor.forRoom
andybalaam Mar 30, 2023
44762c9
Test for MatrixToPermalinkConstructor.forEvent
andybalaam Mar 30, 2023
9767dea
Display a tile for predecessor event if it contains via servers
andybalaam Mar 30, 2023
21c8341
Fix missing case where event id is provided as well as via servers
andybalaam Apr 3, 2023
849b45b
Refactor RoomPredecessor tests
andybalaam Apr 3, 2023
8aa996c
Return lost filterConsole to its home
andybalaam Apr 3, 2023
b8cec98
Comments for IState in AdvancedRoomSettingsTab
andybalaam Apr 3, 2023
7db8b26
Explain why we might render a tile even without prevRoom
andybalaam Apr 4, 2023
eba4adb
Guess the old room's via servers if they are not provided
andybalaam Apr 4, 2023
5a110fd
Fix TypeScript errors
andybalaam Apr 4, 2023
1ab7740
Adjust regular expression (hopefully) to avoid potential catastrophic…
andybalaam Apr 5, 2023
7bf4c59
Merge branch 'develop' into andybalaam/viaservers-for-dynamic-predece…
andybalaam Apr 5, 2023
eeb92e6
Another attempt at avoiding super-liner regex performance
andybalaam Apr 5, 2023
475f629
Merge branch 'develop' into andybalaam/viaservers-for-dynamic-predece…
t3chguy Apr 5, 2023
2f80b71
Tests for guessServerNameFromRoomId and better implementation
andybalaam Apr 12, 2023
fb89367
Merge branch 'develop' into andybalaam/viaservers-for-dynamic-predece…
andybalaam Apr 12, 2023
7f1ac7a
Further attempt to prevent backtracking
andybalaam Apr 12, 2023
8430ced
Merge branch 'develop' into andybalaam/viaservers-for-dynamic-predece…
andybalaam Apr 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 87 additions & 10 deletions src/components/views/messages/RoomPredecessorTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ limitations under the License.
import React, { useCallback, useContext } from "react";
import { logger } from "matrix-js-sdk/src/logger";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Room } from "matrix-js-sdk/src/matrix";

import dis from "../../../dispatcher/dispatcher";
import { Action } from "../../../dispatcher/actions";
Expand All @@ -29,6 +30,7 @@ import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import RoomContext from "../../../contexts/RoomContext";
import { useRoomState } from "../../../hooks/useRoomState";
import SettingsStore from "../../../settings/SettingsStore";
import MatrixToPermalinkConstructor from "../../../utils/permalinks/MatrixToPermalinkConstructor";

interface IProps {
/** The m.room.create MatrixEvent that this tile represents */
Expand Down Expand Up @@ -86,18 +88,56 @@ export const RoomPredecessorTile: React.FC<IProps> = ({ mxEvent, timestamp }) =>
}

const prevRoom = MatrixClientPeg.get().getRoom(predecessor.roomId);
if (!prevRoom) {

// We need either the previous room, or some servers to find it with.
// Otherwise, we must bail out here
andybalaam marked this conversation as resolved.
Show resolved Hide resolved
if (!prevRoom && !predecessor.viaServers) {
andybalaam marked this conversation as resolved.
Show resolved Hide resolved
logger.warn(`Failed to find predecessor room with id ${predecessor.roomId}`);
return <></>;
}
const permalinkCreator = new RoomPermalinkCreator(prevRoom, predecessor.roomId);
permalinkCreator.load();
let predecessorPermalink: string;
if (predecessor.eventId) {
predecessorPermalink = permalinkCreator.forEvent(predecessor.eventId);
} else {
predecessorPermalink = permalinkCreator.forRoom();

const guessedLink = guessLinkForRoomId(predecessor.roomId);

return (
<EventTileBubble
className="mx_CreateEvent"
title={_t("This room is a continuation of another conversation.")}
timestamp={timestamp}
>
<div className="mx_EventTile_body">
<span className="mx_EventTile_tileError">
andybalaam marked this conversation as resolved.
Show resolved Hide resolved
{!!guessedLink ? (
<>
{_t(
"Can't find the old version of this room (room ID: %(roomId)s), and we have not been " +
"provided with 'via_servers' to look for it. It's possible that guessing the " +
"server from the room ID will work. If you want to try, click this link:",
{
roomId: predecessor.roomId,
},
)}
<a href={guessedLink}>{guessedLink}</a>
</>
) : (
_t(
"Can't find the old version of this room (room ID: %(roomId)s), and we have not been " +
"provided with 'via_servers' to look for it.",
{
roomId: predecessor.roomId,
},
)
)}
</span>
</div>
</EventTileBubble>
);
}
andybalaam marked this conversation as resolved.
Show resolved Hide resolved
// Otherwise, we expect to be able to find this room either because it is
// already loaded, or because we have via_servers that we can use.
// So we go ahead with rendering the tile.

const predecessorPermalink = prevRoom
? createLinkWithRoom(prevRoom, predecessor.roomId, predecessor.eventId)
: createLinkWithoutRoom(predecessor.roomId, predecessor.viaServers, predecessor.eventId);

const link = (
<a href={predecessorPermalink} onClick={onLinkClicked}>
{_t("Click here to see older messages.")}
Expand All @@ -112,4 +152,41 @@ export const RoomPredecessorTile: React.FC<IProps> = ({ mxEvent, timestamp }) =>
timestamp={timestamp}
/>
);

function createLinkWithRoom(room: Room, roomId: string, eventId?: string): string {
const permalinkCreator = new RoomPermalinkCreator(room, roomId);
permalinkCreator.load();
if (eventId) {
return permalinkCreator.forEvent(eventId);
} else {
return permalinkCreator.forRoom();
}
}

function createLinkWithoutRoom(roomId: string, viaServers: string[], eventId?: string): string {
const matrixToPermalinkConstructor = new MatrixToPermalinkConstructor();
if (eventId) {
return matrixToPermalinkConstructor.forEvent(roomId, eventId, viaServers);
} else {
return matrixToPermalinkConstructor.forRoom(roomId, viaServers);
}
}

/**
* Guess the permalink for a room based on its room ID.
*
* The spec says that Room IDs are opaque [1] so this can only ever be a
* guess. There is no guarantee that this room exists on this server.
*
* [1] https://spec.matrix.org/v1.5/appendices/#room-ids-and-event-ids
*/
function guessLinkForRoomId(roomId: string): string | null {
const m = roomId.match(/:([^:]*)$/);
andybalaam marked this conversation as resolved.
Show resolved Hide resolved
if (m) {
const serverName = m[1];
return new MatrixToPermalinkConstructor().forRoom(roomId, [serverName]);
} else {
return null;
}
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,16 @@ interface IRecommendedVersion {
interface IState {
// This is eventually set to the value of room.getRecommendedVersion()
upgradeRecommendation?: IRecommendedVersion;

/** The room ID of this room's predecessor, if it exists. */
oldRoomId?: string;

/** The ID of tombstone event in this room's predecessor, if it exists. */
oldEventId?: string;

/** The via servers to use to find this room's predecessor, if it exists. */
oldViaServers?: string[];
andybalaam marked this conversation as resolved.
Show resolved Hide resolved

upgraded?: boolean;
}

Expand All @@ -65,6 +73,7 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
if (predecessor) {
additionalStateChanges.oldRoomId = predecessor.roomId;
additionalStateChanges.oldEventId = predecessor.eventId;
additionalStateChanges.oldViaServers = predecessor.viaServers;
}

this.setState({
Expand All @@ -88,6 +97,7 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
action: Action.ViewRoom,
room_id: this.state.oldRoomId,
event_id: this.state.oldEventId,
via_servers: this.state.oldViaServers,
metricsTrigger: "WebPredecessorSettings",
metricsViaKeyboard: e.type !== "click",
});
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2457,8 +2457,10 @@
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s changed the avatar for %(roomName)s",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removed the room avatar.",
"%(senderDisplayName)s changed the room avatar to <img/>": "%(senderDisplayName)s changed the room avatar to <img/>",
"Click here to see older messages.": "Click here to see older messages.",
"This room is a continuation of another conversation.": "This room is a continuation of another conversation.",
"Can't find the old version of this room (room ID: %(roomId)s), and we have not been provided with 'via_servers' to look for it. It's possible that guessing the server from the room ID will work. If you want to try, click this link:": "Can't find the old version of this room (room ID: %(roomId)s), and we have not been provided with 'via_servers' to look for it. It's possible that guessing the server from the room ID will work. If you want to try, click this link:",
"Can't find the old version of this room (room ID: %(roomId)s), and we have not been provided with 'via_servers' to look for it.": "Can't find the old version of this room (room ID: %(roomId)s), and we have not been provided with 'via_servers' to look for it.",
"Click here to see older messages.": "Click here to see older messages.",
"Add an Integration": "Add an Integration",
"You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?",
"Edited at %(date)s": "Edited at %(date)s",
Expand Down
26 changes: 14 additions & 12 deletions src/utils/permalinks/Permalinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export class RoomPermalinkCreator {
// Some of the tests done by this class are relatively expensive, so normally
// throttled to not happen on every update. Pass false as the shouldThrottle
// param to disable this behaviour, eg. for tests.
public constructor(private room: Room, roomId: string | null = null, shouldThrottle = true) {
public constructor(private room: Room | null, roomId: string | null = null, shouldThrottle = true) {
richvdh marked this conversation as resolved.
Show resolved Hide resolved
this.roomId = room ? room.roomId : roomId!;

if (!this.roomId) {
Expand All @@ -118,12 +118,12 @@ export class RoomPermalinkCreator {

public start(): void {
this.load();
this.room.currentState.on(RoomStateEvent.Update, this.onRoomStateUpdate);
this.room?.currentState.on(RoomStateEvent.Update, this.onRoomStateUpdate);
this.started = true;
}

public stop(): void {
this.room.currentState.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
this.room?.currentState.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
this.started = false;
}

Expand Down Expand Up @@ -171,15 +171,15 @@ export class RoomPermalinkCreator {
}

private updateHighestPlUser(): void {
const plEvent = this.room.currentState.getStateEvents("m.room.power_levels", "");
const plEvent = this.room?.currentState.getStateEvents("m.room.power_levels", "");
if (plEvent) {
const content = plEvent.getContent();
if (content) {
const users: Record<string, number> = content.users;
if (users) {
const entries = Object.entries(users);
const allowedEntries = entries.filter(([userId]) => {
const member = this.room.getMember(userId);
const member = this.room?.getMember(userId);
if (!member || member.membership !== "join") {
return false;
}
Expand Down Expand Up @@ -213,8 +213,8 @@ export class RoomPermalinkCreator {
private updateAllowedServers(): void {
const bannedHostsRegexps: RegExp[] = [];
let allowedHostsRegexps = [ANY_REGEX]; // default allow everyone
if (this.room.currentState) {
const aclEvent = this.room.currentState.getStateEvents(EventType.RoomServerAcl, "");
if (this.room?.currentState) {
const aclEvent = this.room?.currentState.getStateEvents(EventType.RoomServerAcl, "");
if (aclEvent && aclEvent.getContent()) {
const getRegex = (hostname: string): RegExp =>
new RegExp("^" + utils.globToRegexp(hostname, false) + "$");
Expand All @@ -237,12 +237,14 @@ export class RoomPermalinkCreator {

private updatePopulationMap(): void {
const populationMap: { [server: string]: number } = {};
for (const member of this.room.getJoinedMembers()) {
const serverName = getServerName(member.userId);
if (!populationMap[serverName]) {
populationMap[serverName] = 0;
if (this.room) {
for (const member of this.room.getJoinedMembers()) {
const serverName = getServerName(member.userId);
if (!populationMap[serverName]) {
populationMap[serverName] = 0;
}
populationMap[serverName]++;
}
populationMap[serverName]++;
}
this.populationMap = populationMap;
}
Expand Down
Loading