* Move some message utils out to their own file In another attempt at import cycle breaking * Also add the file * Move tests
110 lines
3.9 KiB
TypeScript
110 lines
3.9 KiB
TypeScript
/*
|
|
Copyright 2025 New Vector Ltd.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
Please see LICENSE files in the repository root for full details.
|
|
*/
|
|
|
|
import { type MatrixEvent, type IContent, type IMentions, type IEventRelation } from "matrix-js-sdk/src/matrix";
|
|
|
|
import type EditorModel from "../editor/model";
|
|
import { Type } from "../editor/parts";
|
|
|
|
/**
|
|
* Build the mentions information based on the editor model (and any related events):
|
|
*
|
|
* 1. Search the model parts for room or user pills and fill in the mentions object.
|
|
* 2. If this is a reply to another event, include any user mentions from that
|
|
* (but do not include a room mention).
|
|
*
|
|
* @param sender - The Matrix ID of the user sending the event.
|
|
* @param content - The event content.
|
|
* @param model - The editor model to search for mentions, null if there is no editor.
|
|
* @param replyToEvent - The event being replied to or undefined if it is not a reply.
|
|
* @param editedContent - The content of the parent event being edited.
|
|
*/
|
|
export function attachMentions(
|
|
sender: string,
|
|
content: IContent,
|
|
model: EditorModel | null,
|
|
replyToEvent: MatrixEvent | undefined,
|
|
editedContent: IContent | null = null,
|
|
): void {
|
|
// We always attach the mentions even if the home server doesn't yet support
|
|
// intentional mentions. This is safe because m.mentions is an additive change
|
|
// that should simply be ignored by incapable home servers.
|
|
|
|
// The mentions property *always* gets included to disable legacy push rules.
|
|
const mentions: IMentions = (content["m.mentions"] = {});
|
|
|
|
const userMentions = new Set<string>();
|
|
let roomMention = false;
|
|
|
|
// If there's a reply, initialize the mentioned users as the sender of that event.
|
|
if (replyToEvent) {
|
|
userMentions.add(replyToEvent.sender!.userId);
|
|
}
|
|
|
|
// If user provided content is available, check to see if any users are mentioned.
|
|
if (model) {
|
|
// Add any mentioned users in the current content.
|
|
for (const part of model.parts) {
|
|
if (part.type === Type.UserPill) {
|
|
userMentions.add(part.resourceId);
|
|
} else if (part.type === Type.AtRoomPill) {
|
|
roomMention = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ensure the *current* user isn't listed in the mentioned users.
|
|
userMentions.delete(sender);
|
|
|
|
// Finally, if this event is editing a previous event, only include users who
|
|
// were not previously mentioned and a room mention if the previous event was
|
|
// not a room mention.
|
|
if (editedContent) {
|
|
// First, the new event content gets the *full* set of users.
|
|
const newContent = content["m.new_content"];
|
|
const newMentions: IMentions = (newContent["m.mentions"] = {});
|
|
|
|
// Only include the users/room if there is any content.
|
|
if (userMentions.size) {
|
|
newMentions.user_ids = [...userMentions];
|
|
}
|
|
if (roomMention) {
|
|
newMentions.room = true;
|
|
}
|
|
|
|
// Fetch the mentions from the original event and remove any previously
|
|
// mentioned users.
|
|
const prevMentions = editedContent["m.mentions"];
|
|
if (Array.isArray(prevMentions?.user_ids)) {
|
|
prevMentions!.user_ids.forEach((userId) => userMentions.delete(userId));
|
|
}
|
|
|
|
// If the original event mentioned the room, nothing to do here.
|
|
if (prevMentions?.room) {
|
|
roomMention = false;
|
|
}
|
|
}
|
|
|
|
// Only include the users/room if there is any content.
|
|
if (userMentions.size) {
|
|
mentions.user_ids = [...userMentions];
|
|
}
|
|
if (roomMention) {
|
|
mentions.room = true;
|
|
}
|
|
}
|
|
|
|
// Merges favouring the given relation
|
|
export function attachRelation(content: IContent, relation?: IEventRelation): void {
|
|
if (relation) {
|
|
content["m.relates_to"] = {
|
|
...(content["m.relates_to"] || {}),
|
|
...relation,
|
|
};
|
|
}
|
|
}
|