Recalculate mentions metadata of forwarded messages based on message body (#31193)

* recalculate mentions of forwarded messages

In transformEvent(), parse event body back into an EditorModel, and pass this into attachMentions(), so that it actually recalculates mentions.

* refactor ForwardDialog-test.tsx

Refactor test for stripping mentions on forwards to allow for more tests of mention recalculation

* add test to recalculate mention pills

Fails due to not mocking room membership

* fix lint

* fix test: add ability to provide source room stub
This commit is contained in:
Tol Wassman
2026-01-02 15:45:46 +00:00
committed by GitHub
parent 8e6045a687
commit cbe3eb1709
2 changed files with 74 additions and 36 deletions
+19 -10
View File
@@ -58,6 +58,10 @@ import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
import { OverflowTileView } from "../rooms/OverflowTileView";
import { attachMentions } from "../../../utils/messages";
import { CommandPartCreator } from "../../../editor/parts";
import SettingsStore from "../../../settings/SettingsStore";
import { parseEvent } from "../../../editor/deserialize";
import EditorModel from "../../../editor/model";
const AVATAR_SIZE = 30;
@@ -184,13 +188,13 @@ const Entry: React.FC<IEntryProps<any>> = ({ room, type, content, matrixClient:
* 1. Strip all relations.
* 2. Convert location events into a static pin-drop location share,
* and remove description from self-location shares.
* 3. Pass through attachMentions() to strip mentions (as no EditorModel is present to recalculate from).
* 3. Parse the event back into an EditorModel and recalculate mentions.
*
* @param event - The MatrixEvent to transform.
* @param userId - Current user MXID (passed through to attachMentions()).
* @param cli - The MatrixClient (used for recalculation of mentions).
* @returns The transformed event type and content.
*/
const transformEvent = (event: MatrixEvent, userId: string): { type: string; content: IContent } => {
const transformEvent = (event: MatrixEvent, cli: MatrixClient): { type: string; content: IContent } => {
const {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
"m.relates_to": _, // strip relations - in future we will attach a relation pointing at the original event
@@ -225,12 +229,17 @@ const transformEvent = (event: MatrixEvent, userId: string): { type: string; con
};
}
// Mentions can leak information about the context of the original message,
// so pass through attachMentions() to recalculate mentions.
// Currently, this strips all mentions (forces an empty m.mentions),
// as there is no EditorModel to parse pills from.
// Future improvements could actually recalculate mentions based on the message body.
attachMentions(userId, content, null, undefined);
// Mentions can leak information about the context of the original message, so:
// 1. Parse the event's message body back into an EditorModel, then
// 2. Pass through attachMentions() to recalculate mentions.
const room = cli.getRoom(event.getRoomId())!;
const partCreator = new CommandPartCreator(room, cli);
const parts = parseEvent(event, partCreator, {
shouldEscape: SettingsStore.getValue("MessageComposerInput.useMarkdown"),
});
const model = new EditorModel(parts, partCreator); // Temporary EditorModel to pass through
const userId = cli.getSafeUserId();
attachMentions(userId, content, model, undefined);
return { type, content };
};
@@ -242,7 +251,7 @@ const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCr
cli.getProfileInfo(userId).then((info) => setProfileInfo(info));
}, [cli, userId]);
const { type, content } = transformEvent(event, userId);
const { type, content } = transformEvent(event, cli);
// For the message preview we fake the sender as ourselves
const mockEvent = new MatrixEvent({