2015-09-18 12:54:20 +00:00
|
|
|
|
/*
|
2024-09-09 13:57:16 +00:00
|
|
|
|
Copyright 2024 New Vector Ltd.
|
2020-03-30 12:59:08 +00:00
|
|
|
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
2024-09-09 13:57:16 +00:00
|
|
|
|
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
|
|
|
|
Copyright 2018 New Vector Ltd
|
|
|
|
|
Copyright 2015, 2016 OpenMarket Ltd
|
2015-09-18 12:54:20 +00:00
|
|
|
|
|
2024-09-09 13:57:16 +00:00
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
|
|
|
|
Please see LICENSE files in the repository root for full details.
|
2015-09-18 12:54:20 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
import * as React from "react";
|
2024-03-20 14:27:29 +00:00
|
|
|
|
import { ContentHelpers, Direction, EventType, IContent, MRoomTopicEventContent, User } from "matrix-js-sdk/src/matrix";
|
2021-12-09 09:10:23 +00:00
|
|
|
|
import { logger } from "matrix-js-sdk/src/logger";
|
2024-03-20 17:25:23 +00:00
|
|
|
|
import { KnownMembership, RoomMemberEventContent } from "matrix-js-sdk/src/types";
|
2021-12-09 09:10:23 +00:00
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
import dis from "./dispatcher/dispatcher";
|
2023-03-31 07:30:43 +00:00
|
|
|
|
import { _t, _td, UserFriendlyError } from "./languageHandler";
|
2022-12-12 11:24:14 +00:00
|
|
|
|
import Modal from "./Modal";
|
|
|
|
|
import MultiInviter from "./utils/MultiInviter";
|
2023-02-03 08:59:21 +00:00
|
|
|
|
import { Linkify, topicToHtml } from "./HtmlUtils";
|
2019-03-14 23:24:22 +00:00
|
|
|
|
import QuestionDialog from "./components/views/dialogs/QuestionDialog";
|
2019-03-24 06:07:00 +00:00
|
|
|
|
import WidgetUtils from "./utils/WidgetUtils";
|
2021-06-29 12:11:58 +00:00
|
|
|
|
import { textToHtmlRainbow } from "./utils/colour";
|
2022-12-12 11:24:14 +00:00
|
|
|
|
import { AddressType, getAddressType } from "./UserAddress";
|
|
|
|
|
import { abbreviateUrl } from "./utils/UrlUtils";
|
|
|
|
|
import { getDefaultIdentityServerUrl, setToDefaultIdentityServer } from "./utils/IdentityServerUtils";
|
2020-04-09 21:25:11 +00:00
|
|
|
|
import { WidgetType } from "./widgets/WidgetType";
|
2020-04-09 22:02:49 +00:00
|
|
|
|
import { Jitsi } from "./widgets/Jitsi";
|
2020-09-09 20:53:38 +00:00
|
|
|
|
import BugReportDialog from "./components/views/dialogs/BugReportDialog";
|
2020-05-11 09:54:28 +00:00
|
|
|
|
import { ensureDMExists } from "./createRoom";
|
2020-05-14 03:03:12 +00:00
|
|
|
|
import { ViewUserPayload } from "./dispatcher/payloads/ViewUserPayload";
|
|
|
|
|
import { Action } from "./dispatcher/actions";
|
2020-09-15 14:49:25 +00:00
|
|
|
|
import SdkConfig from "./SdkConfig";
|
2020-08-24 08:43:41 +00:00
|
|
|
|
import SettingsStore from "./settings/SettingsStore";
|
2021-10-08 22:04:26 +00:00
|
|
|
|
import { UIComponent, UIFeature } from "./settings/UIFeature";
|
2021-06-29 12:11:58 +00:00
|
|
|
|
import { CHAT_EFFECTS } from "./effects";
|
2022-08-30 19:13:39 +00:00
|
|
|
|
import LegacyCallHandler from "./LegacyCallHandler";
|
2021-06-29 12:11:58 +00:00
|
|
|
|
import { guessAndSetDMRoom } from "./Rooms";
|
2022-12-12 11:24:14 +00:00
|
|
|
|
import { upgradeRoom } from "./utils/RoomUpgrade";
|
|
|
|
|
import DevtoolsDialog from "./components/views/dialogs/DevtoolsDialog";
|
2021-07-03 09:24:33 +00:00
|
|
|
|
import RoomUpgradeWarningDialog from "./components/views/dialogs/RoomUpgradeWarningDialog";
|
|
|
|
|
import InfoDialog from "./components/views/dialogs/InfoDialog";
|
|
|
|
|
import SlashCommandHelpDialog from "./components/views/dialogs/SlashCommandHelpDialog";
|
2021-10-08 22:04:26 +00:00
|
|
|
|
import { shouldShowComponent } from "./customisations/helpers/UIComponents";
|
2022-12-12 11:24:14 +00:00
|
|
|
|
import { TimelineRenderingType } from "./contexts/RoomContext";
|
2022-02-10 14:29:55 +00:00
|
|
|
|
import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
|
2022-12-12 11:24:14 +00:00
|
|
|
|
import VoipUserMapper from "./VoipUserMapper";
|
|
|
|
|
import { htmlSerializeFromMdIfNeeded } from "./editor/serialize";
|
2022-03-24 21:25:44 +00:00
|
|
|
|
import { leaveRoomBehaviour } from "./utils/leave-behaviour";
|
2023-06-14 12:49:18 +00:00
|
|
|
|
import { MatrixClientPeg } from "./MatrixClientPeg";
|
2023-06-28 12:39:34 +00:00
|
|
|
|
import { getDeviceCryptoInfo } from "./utils/crypto/deviceInfo";
|
2023-07-11 12:53:33 +00:00
|
|
|
|
import { isCurrentLocalRoom, reject, singleMxcUpload, success, successSync } from "./slash-commands/utils";
|
|
|
|
|
import { deop, op } from "./slash-commands/op";
|
|
|
|
|
import { CommandCategories } from "./slash-commands/interface";
|
|
|
|
|
import { Command } from "./slash-commands/command";
|
2023-07-14 11:20:59 +00:00
|
|
|
|
import { goto, join } from "./slash-commands/join";
|
2021-09-21 15:48:09 +00:00
|
|
|
|
|
2023-07-11 12:53:33 +00:00
|
|
|
|
export { CommandCategories, Command };
|
2017-05-23 08:44:11 +00:00
|
|
|
|
|
2020-03-30 12:59:08 +00:00
|
|
|
|
export const Commands = [
|
2021-02-25 21:59:27 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "spoiler",
|
|
|
|
|
args: "<message>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|spoiler"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, message = "") {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
return successSync(ContentHelpers.makeHtmlMessage(message, `<span data-mx-spoiler>${message}</span>`));
|
2021-02-25 21:59:27 +00:00
|
|
|
|
},
|
|
|
|
|
category: CommandCategories.messages,
|
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "shrug",
|
|
|
|
|
args: "<message>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|shrug"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
let message = "¯\\_(ツ)_/¯";
|
2019-02-18 23:27:22 +00:00
|
|
|
|
if (args) {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
message = message + " " + args;
|
2019-02-18 23:27:22 +00:00
|
|
|
|
}
|
2021-06-17 10:37:06 +00:00
|
|
|
|
return successSync(ContentHelpers.makeTextMessage(message));
|
2019-02-20 05:46:17 +00:00
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.messages,
|
2019-02-18 23:27:22 +00:00
|
|
|
|
}),
|
2020-12-10 11:19:13 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "tableflip",
|
|
|
|
|
args: "<message>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|tableflip"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
let message = "(╯°□°)╯︵ ┻━┻";
|
2020-12-10 11:19:13 +00:00
|
|
|
|
if (args) {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
message = message + " " + args;
|
2020-12-10 11:19:13 +00:00
|
|
|
|
}
|
2021-06-17 10:37:06 +00:00
|
|
|
|
return successSync(ContentHelpers.makeTextMessage(message));
|
2020-12-10 11:19:13 +00:00
|
|
|
|
},
|
|
|
|
|
category: CommandCategories.messages,
|
|
|
|
|
}),
|
2020-12-10 11:19:30 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "unflip",
|
|
|
|
|
args: "<message>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|unflip"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
let message = "┬──┬ ノ( ゜-゜ノ)";
|
2020-12-10 11:19:30 +00:00
|
|
|
|
if (args) {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
message = message + " " + args;
|
2020-12-10 11:19:30 +00:00
|
|
|
|
}
|
2021-06-17 10:37:06 +00:00
|
|
|
|
return successSync(ContentHelpers.makeTextMessage(message));
|
2020-12-10 11:19:30 +00:00
|
|
|
|
},
|
|
|
|
|
category: CommandCategories.messages,
|
|
|
|
|
}),
|
2020-08-29 11:29:43 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "lenny",
|
|
|
|
|
args: "<message>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|lenny"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
let message = "( ͡° ͜ʖ ͡°)";
|
2020-08-29 11:29:43 +00:00
|
|
|
|
if (args) {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
message = message + " " + args;
|
2020-08-29 11:29:43 +00:00
|
|
|
|
}
|
2021-06-17 10:37:06 +00:00
|
|
|
|
return successSync(ContentHelpers.makeTextMessage(message));
|
2020-08-29 11:29:43 +00:00
|
|
|
|
},
|
|
|
|
|
category: CommandCategories.messages,
|
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "plain",
|
|
|
|
|
args: "<message>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|plain"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, messages = "") {
|
2021-06-17 10:37:06 +00:00
|
|
|
|
return successSync(ContentHelpers.makeTextMessage(messages));
|
2019-09-02 15:44:31 +00:00
|
|
|
|
},
|
|
|
|
|
category: CommandCategories.messages,
|
|
|
|
|
}),
|
2020-03-31 10:49:53 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "html",
|
|
|
|
|
args: "<message>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|html"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, messages = "") {
|
2021-06-17 10:37:06 +00:00
|
|
|
|
return successSync(ContentHelpers.makeHtmlMessage(messages, messages));
|
2020-03-29 19:45:06 +00:00
|
|
|
|
},
|
|
|
|
|
category: CommandCategories.messages,
|
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "upgraderoom",
|
|
|
|
|
args: "<new_version>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|upgraderoom"),
|
2023-10-13 09:48:32 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli) && SettingsStore.getValue("developerMode"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2019-01-17 22:59:05 +00:00
|
|
|
|
if (args) {
|
2019-08-28 11:00:37 +00:00
|
|
|
|
const room = cli.getRoom(roomId);
|
2023-02-16 17:21:44 +00:00
|
|
|
|
if (!room?.currentState.mayClientSendStateEvent("m.room.tombstone", cli)) {
|
2023-09-05 09:44:41 +00:00
|
|
|
|
return reject(new UserFriendlyError("slash_command|upgraderoom_permission_error"));
|
2019-08-28 11:00:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-14 16:51:51 +00:00
|
|
|
|
const { finished } = Modal.createDialog(
|
2022-12-12 11:24:14 +00:00
|
|
|
|
RoomUpgradeWarningDialog,
|
|
|
|
|
{ roomId: roomId, targetVersion: args },
|
2023-02-16 17:21:44 +00:00
|
|
|
|
/*className=*/ undefined,
|
2022-12-12 11:24:14 +00:00
|
|
|
|
/*isPriority=*/ false,
|
|
|
|
|
/*isStatic=*/ true,
|
|
|
|
|
);
|
2019-11-28 03:29:11 +00:00
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
return success(
|
2023-01-12 13:25:14 +00:00
|
|
|
|
finished.then(async ([resp]): Promise<void> => {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
if (!resp?.continue) return;
|
|
|
|
|
await upgradeRoom(room, args, resp.invite);
|
|
|
|
|
}),
|
|
|
|
|
);
|
2019-01-17 22:59:05 +00:00
|
|
|
|
}
|
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.admin,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2019-01-17 22:59:05 +00:00
|
|
|
|
}),
|
2021-12-15 12:34:47 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "jumptodate",
|
|
|
|
|
args: "<YYYY-MM-DD>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|jumptodate"),
|
2021-12-15 12:34:47 +00:00
|
|
|
|
isEnabled: () => SettingsStore.getValue("feature_jump_to_date"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2021-12-15 12:34:47 +00:00
|
|
|
|
if (args) {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
return success(
|
2023-01-12 13:25:14 +00:00
|
|
|
|
(async (): Promise<void> => {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
const unixTimestamp = Date.parse(args);
|
|
|
|
|
if (!unixTimestamp) {
|
2023-09-05 09:44:41 +00:00
|
|
|
|
throw new UserFriendlyError("slash_command|jumptodate_invalid_input", {
|
|
|
|
|
inputDate: args,
|
|
|
|
|
cause: undefined,
|
|
|
|
|
});
|
2022-12-12 11:24:14 +00:00
|
|
|
|
}
|
2021-12-15 12:34:47 +00:00
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
const { event_id: eventId, origin_server_ts: originServerTs } = await cli.timestampToEvent(
|
|
|
|
|
roomId,
|
|
|
|
|
unixTimestamp,
|
|
|
|
|
Direction.Forward,
|
|
|
|
|
);
|
|
|
|
|
logger.log(
|
|
|
|
|
`/timestamp_to_event: found ${eventId} (${originServerTs}) for timestamp=${unixTimestamp}`,
|
|
|
|
|
);
|
|
|
|
|
dis.dispatch<ViewRoomPayload>({
|
|
|
|
|
action: Action.ViewRoom,
|
|
|
|
|
event_id: eventId,
|
|
|
|
|
highlighted: true,
|
|
|
|
|
room_id: roomId,
|
|
|
|
|
metricsTrigger: "SlashCommand",
|
|
|
|
|
metricsViaKeyboard: true,
|
|
|
|
|
});
|
|
|
|
|
})(),
|
|
|
|
|
);
|
2021-12-15 12:34:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
},
|
|
|
|
|
category: CommandCategories.actions,
|
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "nick",
|
|
|
|
|
args: "<display_name>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|nick"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2018-06-18 18:31:40 +00:00
|
|
|
|
if (args) {
|
2023-05-25 15:29:48 +00:00
|
|
|
|
return success(cli.setDisplayName(args));
|
2018-06-18 18:31:40 +00:00
|
|
|
|
}
|
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.actions,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2016-01-14 14:39:58 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "myroomnick",
|
|
|
|
|
aliases: ["roomnick"],
|
|
|
|
|
args: "<display_name>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|myroomnick"),
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2019-02-24 01:36:47 +00:00
|
|
|
|
if (args) {
|
2024-03-20 14:27:29 +00:00
|
|
|
|
const ev = cli.getRoom(roomId)?.currentState.getStateEvents(EventType.RoomMember, cli.getSafeUserId());
|
|
|
|
|
const content: RoomMemberEventContent = {
|
2024-03-12 14:52:54 +00:00
|
|
|
|
...(ev ? ev.getContent() : { membership: KnownMembership.Join }),
|
2020-03-30 13:13:08 +00:00
|
|
|
|
displayname: args,
|
2019-02-24 01:36:47 +00:00
|
|
|
|
};
|
2024-03-20 14:27:29 +00:00
|
|
|
|
return success(cli.sendStateEvent(roomId, EventType.RoomMember, content, cli.getSafeUserId()));
|
2019-02-24 01:36:47 +00:00
|
|
|
|
}
|
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.actions,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2019-02-24 01:36:47 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "roomavatar",
|
|
|
|
|
args: "[<mxc_url>]",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|roomavatar"),
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2023-02-15 13:36:22 +00:00
|
|
|
|
let promise = Promise.resolve(args ?? null);
|
2019-09-18 15:33:56 +00:00
|
|
|
|
if (!args) {
|
2023-05-25 15:29:48 +00:00
|
|
|
|
promise = singleMxcUpload(cli);
|
2019-09-18 15:33:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
return success(
|
|
|
|
|
promise.then((url) => {
|
|
|
|
|
if (!url) return;
|
2024-03-20 14:27:29 +00:00
|
|
|
|
return cli.sendStateEvent(roomId, EventType.RoomAvatar, { url }, "");
|
2022-12-12 11:24:14 +00:00
|
|
|
|
}),
|
|
|
|
|
);
|
2019-09-18 15:33:56 +00:00
|
|
|
|
},
|
|
|
|
|
category: CommandCategories.actions,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2019-09-18 15:33:56 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "myroomavatar",
|
|
|
|
|
args: "[<mxc_url>]",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|myroomavatar"),
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2019-05-09 21:12:21 +00:00
|
|
|
|
const room = cli.getRoom(roomId);
|
2023-05-25 15:29:48 +00:00
|
|
|
|
const userId = cli.getSafeUserId();
|
2019-05-09 21:12:21 +00:00
|
|
|
|
|
2023-02-15 13:36:22 +00:00
|
|
|
|
let promise = Promise.resolve(args ?? null);
|
2019-05-09 21:12:21 +00:00
|
|
|
|
if (!args) {
|
2023-05-25 15:29:48 +00:00
|
|
|
|
promise = singleMxcUpload(cli);
|
2019-05-09 21:12:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
return success(
|
|
|
|
|
promise.then((url) => {
|
|
|
|
|
if (!url) return;
|
2024-03-20 14:27:29 +00:00
|
|
|
|
const ev = room?.currentState.getStateEvents(EventType.RoomMember, userId);
|
|
|
|
|
const content: RoomMemberEventContent = {
|
2024-03-12 14:52:54 +00:00
|
|
|
|
...(ev ? ev.getContent() : { membership: KnownMembership.Join }),
|
2022-12-12 11:24:14 +00:00
|
|
|
|
avatar_url: url,
|
|
|
|
|
};
|
2024-03-20 14:27:29 +00:00
|
|
|
|
return cli.sendStateEvent(roomId, EventType.RoomMember, content, userId);
|
2022-12-12 11:24:14 +00:00
|
|
|
|
}),
|
|
|
|
|
);
|
2019-05-09 21:12:21 +00:00
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.actions,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2019-05-09 21:12:21 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "myavatar",
|
|
|
|
|
args: "[<mxc_url>]",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|myavatar"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2023-02-15 13:36:22 +00:00
|
|
|
|
let promise = Promise.resolve(args ?? null);
|
2019-06-27 18:38:12 +00:00
|
|
|
|
if (!args) {
|
2023-05-25 15:29:48 +00:00
|
|
|
|
promise = singleMxcUpload(cli);
|
2019-06-27 18:38:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
return success(
|
|
|
|
|
promise.then((url) => {
|
|
|
|
|
if (!url) return;
|
2023-05-25 15:29:48 +00:00
|
|
|
|
return cli.setAvatarUrl(url);
|
2022-12-12 11:24:14 +00:00
|
|
|
|
}),
|
|
|
|
|
);
|
2019-06-27 18:38:12 +00:00
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.actions,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2019-06-27 18:38:12 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "topic",
|
|
|
|
|
args: "[<topic>]",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|topic"),
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2018-06-18 18:31:40 +00:00
|
|
|
|
if (args) {
|
2022-06-07 20:20:32 +00:00
|
|
|
|
const html = htmlSerializeFromMdIfNeeded(args, { forceHTML: false });
|
|
|
|
|
return success(cli.setRoomTopic(roomId, args, html));
|
2018-06-18 18:31:40 +00:00
|
|
|
|
}
|
2019-01-30 10:22:05 +00:00
|
|
|
|
const room = cli.getRoom(roomId);
|
2022-01-11 18:25:28 +00:00
|
|
|
|
if (!room) {
|
|
|
|
|
return reject(
|
2023-09-05 09:44:41 +00:00
|
|
|
|
new UserFriendlyError("slash_command|topic_room_error", {
|
2023-03-31 07:30:43 +00:00
|
|
|
|
roomId,
|
|
|
|
|
cause: undefined,
|
|
|
|
|
}),
|
2022-01-11 18:25:28 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
2019-01-30 10:22:05 +00:00
|
|
|
|
|
2023-02-15 13:36:22 +00:00
|
|
|
|
const content = room.currentState.getStateEvents("m.room.topic", "")?.getContent<MRoomTopicEventContent>();
|
2022-06-07 20:20:32 +00:00
|
|
|
|
const topic = !!content
|
|
|
|
|
? ContentHelpers.parseTopicContent(content)
|
2023-09-05 09:44:41 +00:00
|
|
|
|
: { text: _t("slash_command|topic_none") };
|
2022-06-07 20:20:32 +00:00
|
|
|
|
|
2023-02-03 08:59:21 +00:00
|
|
|
|
const body = topicToHtml(topic.text, topic.html, undefined, true);
|
2019-01-30 10:22:05 +00:00
|
|
|
|
|
2022-06-14 16:51:51 +00:00
|
|
|
|
Modal.createDialog(InfoDialog, {
|
2019-01-30 10:22:05 +00:00
|
|
|
|
title: room.name,
|
2023-02-03 08:59:21 +00:00
|
|
|
|
description: <Linkify>{body}</Linkify>,
|
2020-05-12 09:51:27 +00:00
|
|
|
|
hasCloseButton: true,
|
2022-06-07 20:20:32 +00:00
|
|
|
|
className: "markdown-body",
|
2019-01-30 10:22:05 +00:00
|
|
|
|
});
|
|
|
|
|
return success();
|
2018-06-18 18:31:40 +00:00
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.admin,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2016-01-14 14:39:58 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "roomname",
|
|
|
|
|
args: "<name>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|roomname"),
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2019-01-03 23:42:17 +00:00
|
|
|
|
if (args) {
|
2023-05-25 15:29:48 +00:00
|
|
|
|
return success(cli.setRoomName(roomId, args));
|
2019-01-03 23:42:17 +00:00
|
|
|
|
}
|
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.admin,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2019-01-03 23:42:17 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "invite",
|
|
|
|
|
args: "<user-id> [<reason>]",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|invite"),
|
2022-02-10 13:11:10 +00:00
|
|
|
|
analyticsName: "Invite",
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli) && shouldShowComponent(UIComponent.InviteUsers),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2018-06-18 18:31:40 +00:00
|
|
|
|
if (args) {
|
2021-02-26 22:10:20 +00:00
|
|
|
|
const [address, reason] = args.split(/\s+(.+)/);
|
|
|
|
|
if (address) {
|
2018-11-29 22:05:53 +00:00
|
|
|
|
// We use a MultiInviter to re-use the invite logic, even though
|
|
|
|
|
// we're only inviting one user.
|
2019-08-30 17:29:07 +00:00
|
|
|
|
// If we need an identity server but don't have one, things
|
|
|
|
|
// get a bit more complex here, but we try to show something
|
|
|
|
|
// meaningful.
|
2020-07-12 23:19:15 +00:00
|
|
|
|
let prom = Promise.resolve();
|
2023-05-25 15:29:48 +00:00
|
|
|
|
if (getAddressType(address) === AddressType.Email && !cli.getIdentityServerUrl()) {
|
2019-08-30 17:29:07 +00:00
|
|
|
|
const defaultIdentityServerUrl = getDefaultIdentityServerUrl();
|
|
|
|
|
if (defaultIdentityServerUrl) {
|
2023-02-28 10:31:48 +00:00
|
|
|
|
const { finished } = Modal.createDialog(QuestionDialog, {
|
2023-09-22 15:39:40 +00:00
|
|
|
|
title: _t("slash_command|invite_3pid_use_default_is_title"),
|
2022-12-12 11:24:14 +00:00
|
|
|
|
description: (
|
|
|
|
|
<p>
|
2023-09-22 15:39:40 +00:00
|
|
|
|
{_t("slash_command|invite_3pid_use_default_is_title_description", {
|
|
|
|
|
defaultIdentityServerName: abbreviateUrl(defaultIdentityServerUrl),
|
|
|
|
|
})}
|
2022-12-12 11:24:14 +00:00
|
|
|
|
</p>
|
|
|
|
|
),
|
2023-08-22 19:55:15 +00:00
|
|
|
|
button: _t("action|continue"),
|
2022-06-14 16:51:51 +00:00
|
|
|
|
});
|
2020-04-01 15:53:25 +00:00
|
|
|
|
|
2020-07-12 23:19:15 +00:00
|
|
|
|
prom = finished.then(([useDefault]) => {
|
2020-04-01 15:53:25 +00:00
|
|
|
|
if (useDefault) {
|
2023-05-25 15:29:48 +00:00
|
|
|
|
setToDefaultIdentityServer(cli);
|
2020-04-01 15:53:25 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2023-09-22 15:39:40 +00:00
|
|
|
|
throw new UserFriendlyError("slash_command|invite_3pid_needs_is_error");
|
2020-04-01 15:53:25 +00:00
|
|
|
|
});
|
2019-08-30 17:29:07 +00:00
|
|
|
|
} else {
|
2023-09-22 15:39:40 +00:00
|
|
|
|
return reject(new UserFriendlyError("slash_command|invite_3pid_needs_is_error"));
|
2019-08-30 17:29:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-05-25 15:29:48 +00:00
|
|
|
|
const inviter = new MultiInviter(cli, roomId);
|
2022-12-12 11:24:14 +00:00
|
|
|
|
return success(
|
|
|
|
|
prom
|
|
|
|
|
.then(() => {
|
2024-06-14 13:13:41 +00:00
|
|
|
|
return inviter.invite([address], reason);
|
2022-12-12 11:24:14 +00:00
|
|
|
|
})
|
|
|
|
|
.then(() => {
|
|
|
|
|
if (inviter.getCompletionState(address) !== "invited") {
|
2023-03-31 07:30:43 +00:00
|
|
|
|
const errorStringFromInviterUtility = inviter.getErrorText(address);
|
|
|
|
|
if (errorStringFromInviterUtility) {
|
|
|
|
|
throw new Error(errorStringFromInviterUtility);
|
|
|
|
|
} else {
|
2023-09-22 15:39:40 +00:00
|
|
|
|
throw new UserFriendlyError("slash_command|invite_failed", {
|
|
|
|
|
user: address,
|
|
|
|
|
roomId,
|
|
|
|
|
cause: undefined,
|
|
|
|
|
});
|
2023-03-31 07:30:43 +00:00
|
|
|
|
}
|
2022-12-12 11:24:14 +00:00
|
|
|
|
}
|
|
|
|
|
}),
|
|
|
|
|
);
|
2018-06-18 18:31:40 +00:00
|
|
|
|
}
|
2015-09-18 12:54:20 +00:00
|
|
|
|
}
|
2018-06-18 18:31:40 +00:00
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.actions,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2016-01-14 14:39:58 +00:00
|
|
|
|
}),
|
2023-07-14 11:20:59 +00:00
|
|
|
|
goto,
|
|
|
|
|
join,
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "part",
|
|
|
|
|
args: "[<room-address>]",
|
2023-08-22 19:55:15 +00:00
|
|
|
|
description: _td("action|leave_room"),
|
2022-02-10 13:11:10 +00:00
|
|
|
|
analyticsName: "Part",
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2022-11-07 13:45:34 +00:00
|
|
|
|
let targetRoomId: string | undefined;
|
2018-06-18 18:31:40 +00:00
|
|
|
|
if (args) {
|
|
|
|
|
const matches = args.match(/^(\S+)$/);
|
|
|
|
|
if (matches) {
|
|
|
|
|
let roomAlias = matches[1];
|
2022-12-12 11:24:14 +00:00
|
|
|
|
if (roomAlias[0] !== "#") return reject(this.getUsage());
|
2018-06-18 18:31:40 +00:00
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
if (!roomAlias.includes(":")) {
|
|
|
|
|
roomAlias += ":" + cli.getDomain();
|
2018-06-18 18:31:40 +00:00
|
|
|
|
}
|
2015-09-18 12:54:20 +00:00
|
|
|
|
|
2018-06-18 18:31:40 +00:00
|
|
|
|
// Try to find a room with this alias
|
|
|
|
|
const rooms = cli.getRooms();
|
2022-12-12 11:24:14 +00:00
|
|
|
|
targetRoomId = rooms.find((room) => {
|
2022-11-07 13:45:34 +00:00
|
|
|
|
return room.getCanonicalAlias() === roomAlias || room.getAltAliases().includes(roomAlias);
|
|
|
|
|
})?.roomId;
|
2022-01-11 18:25:28 +00:00
|
|
|
|
if (!targetRoomId) {
|
2023-03-31 07:30:43 +00:00
|
|
|
|
return reject(
|
2023-09-22 15:39:40 +00:00
|
|
|
|
new UserFriendlyError("slash_command|part_unknown_alias", {
|
2023-03-31 07:30:43 +00:00
|
|
|
|
roomAlias,
|
|
|
|
|
cause: undefined,
|
|
|
|
|
}),
|
|
|
|
|
);
|
2022-01-11 18:25:28 +00:00
|
|
|
|
}
|
2017-05-23 08:44:11 +00:00
|
|
|
|
}
|
2015-09-18 12:54:20 +00:00
|
|
|
|
}
|
2018-06-18 18:31:40 +00:00
|
|
|
|
|
|
|
|
|
if (!targetRoomId) targetRoomId = roomId;
|
2023-05-23 15:24:12 +00:00
|
|
|
|
return success(leaveRoomBehaviour(cli, targetRoomId));
|
2018-06-18 18:31:40 +00:00
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.actions,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2016-01-14 14:39:58 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "remove",
|
2022-01-14 13:08:34 +00:00
|
|
|
|
aliases: ["kick"],
|
2022-12-12 11:24:14 +00:00
|
|
|
|
args: "<user-id> [reason]",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|remove"),
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2018-06-18 18:31:40 +00:00
|
|
|
|
if (args) {
|
|
|
|
|
const matches = args.match(/^(\S+?)( +(.*))?$/);
|
|
|
|
|
if (matches) {
|
2023-05-25 15:29:48 +00:00
|
|
|
|
return success(cli.kick(roomId, matches[1], matches[3]));
|
2018-06-18 18:31:40 +00:00
|
|
|
|
}
|
2015-09-18 12:54:20 +00:00
|
|
|
|
}
|
2018-06-18 18:31:40 +00:00
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.admin,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2016-01-14 14:39:58 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "ban",
|
|
|
|
|
args: "<user-id> [reason]",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|ban"),
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2018-06-18 18:31:40 +00:00
|
|
|
|
if (args) {
|
|
|
|
|
const matches = args.match(/^(\S+?)( +(.*))?$/);
|
|
|
|
|
if (matches) {
|
2023-05-25 15:29:48 +00:00
|
|
|
|
return success(cli.ban(roomId, matches[1], matches[3]));
|
2018-06-18 18:31:40 +00:00
|
|
|
|
}
|
2015-09-18 12:54:20 +00:00
|
|
|
|
}
|
2018-06-18 18:31:40 +00:00
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.admin,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2016-01-14 14:39:58 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "unban",
|
|
|
|
|
args: "<user-id>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|unban"),
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2018-06-18 18:31:40 +00:00
|
|
|
|
if (args) {
|
|
|
|
|
const matches = args.match(/^(\S+)$/);
|
|
|
|
|
if (matches) {
|
|
|
|
|
// Reset the user membership to "leave" to unban him
|
2023-05-25 15:29:48 +00:00
|
|
|
|
return success(cli.unban(roomId, matches[1]));
|
2018-06-18 18:31:40 +00:00
|
|
|
|
}
|
2015-09-18 12:54:20 +00:00
|
|
|
|
}
|
2018-06-18 18:31:40 +00:00
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.admin,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2016-01-14 14:39:58 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "ignore",
|
|
|
|
|
args: "<user-id>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|ignore"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2018-06-18 18:31:40 +00:00
|
|
|
|
if (args) {
|
2020-07-03 21:22:33 +00:00
|
|
|
|
const matches = args.match(/^(@[^:]+:\S+)$/);
|
2018-06-18 18:31:40 +00:00
|
|
|
|
if (matches) {
|
|
|
|
|
const userId = matches[1];
|
|
|
|
|
const ignoredUsers = cli.getIgnoredUsers();
|
|
|
|
|
ignoredUsers.push(userId); // de-duped internally in the js-sdk
|
|
|
|
|
return success(
|
|
|
|
|
cli.setIgnoredUsers(ignoredUsers).then(() => {
|
2022-06-14 16:51:51 +00:00
|
|
|
|
Modal.createDialog(InfoDialog, {
|
2023-09-22 15:39:40 +00:00
|
|
|
|
title: _t("slash_command|ignore_dialog_title"),
|
2022-12-12 11:24:14 +00:00
|
|
|
|
description: (
|
|
|
|
|
<div>
|
2023-09-22 15:39:40 +00:00
|
|
|
|
<p>{_t("slash_command|ignore_dialog_description", { userId })}</p>
|
2022-12-12 11:24:14 +00:00
|
|
|
|
</div>
|
|
|
|
|
),
|
2018-06-18 18:31:40 +00:00
|
|
|
|
});
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
}
|
2017-09-14 22:08:51 +00:00
|
|
|
|
}
|
2018-06-18 18:31:40 +00:00
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.actions,
|
2017-09-14 22:08:51 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "unignore",
|
|
|
|
|
args: "<user-id>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|unignore"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2018-06-18 18:31:40 +00:00
|
|
|
|
if (args) {
|
2020-07-03 21:22:33 +00:00
|
|
|
|
const matches = args.match(/(^@[^:]+:\S+$)/);
|
2018-06-18 18:31:40 +00:00
|
|
|
|
if (matches) {
|
|
|
|
|
const userId = matches[1];
|
|
|
|
|
const ignoredUsers = cli.getIgnoredUsers();
|
|
|
|
|
const index = ignoredUsers.indexOf(userId);
|
|
|
|
|
if (index !== -1) ignoredUsers.splice(index, 1);
|
|
|
|
|
return success(
|
|
|
|
|
cli.setIgnoredUsers(ignoredUsers).then(() => {
|
2022-06-14 16:51:51 +00:00
|
|
|
|
Modal.createDialog(InfoDialog, {
|
2023-09-22 15:39:40 +00:00
|
|
|
|
title: _t("slash_command|unignore_dialog_title"),
|
2022-12-12 11:24:14 +00:00
|
|
|
|
description: (
|
|
|
|
|
<div>
|
2023-09-22 15:39:40 +00:00
|
|
|
|
<p>{_t("slash_command|unignore_dialog_description", { userId })}</p>
|
2022-12-12 11:24:14 +00:00
|
|
|
|
</div>
|
|
|
|
|
),
|
2018-06-18 18:31:40 +00:00
|
|
|
|
});
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
}
|
2017-09-14 22:08:51 +00:00
|
|
|
|
}
|
2018-06-18 18:31:40 +00:00
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.actions,
|
2017-09-14 22:08:51 +00:00
|
|
|
|
}),
|
2023-07-11 12:53:33 +00:00
|
|
|
|
op,
|
|
|
|
|
deop,
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "devtools",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|devtools"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadRootId) {
|
|
|
|
|
Modal.createDialog(DevtoolsDialog, { roomId, threadRootId }, "mx_DevtoolsDialog_wrapper");
|
2018-06-18 18:31:40 +00:00
|
|
|
|
return success();
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.advanced,
|
2017-07-31 11:08:28 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "addwidget",
|
|
|
|
|
args: "<url | embed code | Jitsi url>",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|addwidget"),
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) =>
|
2022-12-12 11:24:14 +00:00
|
|
|
|
SettingsStore.getValue(UIFeature.Widgets) &&
|
|
|
|
|
shouldShowComponent(UIComponent.AddIntegrations) &&
|
2023-05-25 15:29:48 +00:00
|
|
|
|
!isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, widgetUrl) {
|
2020-04-09 22:02:49 +00:00
|
|
|
|
if (!widgetUrl) {
|
2023-09-13 08:30:56 +00:00
|
|
|
|
return reject(new UserFriendlyError("slash_command|addwidget_missing_url"));
|
2020-04-09 22:02:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try and parse out a widget URL from iframes
|
|
|
|
|
if (widgetUrl.toLowerCase().startsWith("<iframe ")) {
|
2023-05-12 11:13:08 +00:00
|
|
|
|
const embed = new DOMParser().parseFromString(widgetUrl, "text/html").body;
|
2023-03-07 13:19:18 +00:00
|
|
|
|
if (embed?.childNodes?.length === 1) {
|
2023-05-12 11:13:08 +00:00
|
|
|
|
const iframe = embed.firstElementChild;
|
2023-05-25 15:29:48 +00:00
|
|
|
|
if (iframe?.tagName.toLowerCase() === "iframe") {
|
2021-09-21 15:48:09 +00:00
|
|
|
|
logger.log("Pulling URL out of iframe (embed code)");
|
2023-05-12 11:13:08 +00:00
|
|
|
|
if (!iframe.hasAttribute("src")) {
|
2023-09-13 08:30:56 +00:00
|
|
|
|
return reject(new UserFriendlyError("slash_command|addwidget_iframe_missing_src"));
|
2023-05-12 11:13:08 +00:00
|
|
|
|
}
|
2023-05-25 15:29:48 +00:00
|
|
|
|
widgetUrl = iframe.getAttribute("src")!;
|
2020-04-09 22:02:49 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!widgetUrl.startsWith("https://") && !widgetUrl.startsWith("http://")) {
|
2023-09-13 08:30:56 +00:00
|
|
|
|
return reject(new UserFriendlyError("slash_command|addwidget_invalid_protocol"));
|
2019-03-24 06:07:00 +00:00
|
|
|
|
}
|
2023-05-25 15:29:48 +00:00
|
|
|
|
if (WidgetUtils.canUserModifyWidgets(cli, roomId)) {
|
|
|
|
|
const userId = cli.getUserId();
|
2022-12-12 11:24:14 +00:00
|
|
|
|
const nowMs = new Date().getTime();
|
2019-03-24 06:07:00 +00:00
|
|
|
|
const widgetId = encodeURIComponent(`${roomId}_${userId}_${nowMs}`);
|
2020-04-09 22:02:49 +00:00
|
|
|
|
let type = WidgetType.CUSTOM;
|
2022-01-31 15:37:49 +00:00
|
|
|
|
let name = "Custom";
|
2020-04-09 22:02:49 +00:00
|
|
|
|
let data = {};
|
|
|
|
|
|
|
|
|
|
// Make the widget a Jitsi widget if it looks like a Jitsi widget
|
|
|
|
|
const jitsiData = Jitsi.getInstance().parsePreferredConferenceUrl(widgetUrl);
|
|
|
|
|
if (jitsiData) {
|
2021-09-21 15:48:09 +00:00
|
|
|
|
logger.log("Making /addwidget widget a Jitsi conference");
|
2020-04-09 22:02:49 +00:00
|
|
|
|
type = WidgetType.JITSI;
|
2022-01-31 15:37:49 +00:00
|
|
|
|
name = "Jitsi";
|
2020-04-09 22:02:49 +00:00
|
|
|
|
data = jitsiData;
|
|
|
|
|
widgetUrl = WidgetUtils.getLocalJitsiWrapperUrl();
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-25 15:29:48 +00:00
|
|
|
|
return success(WidgetUtils.setRoomWidget(cli, roomId, widgetId, type, widgetUrl, name, data));
|
2019-03-24 06:07:00 +00:00
|
|
|
|
} else {
|
2023-09-13 08:30:56 +00:00
|
|
|
|
return reject(new UserFriendlyError("slash_command|addwidget_no_permissions"));
|
2019-03-24 06:07:00 +00:00
|
|
|
|
}
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.admin,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2019-03-24 06:07:00 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "verify",
|
|
|
|
|
args: "<user-id> <device-id> <device-signing-key>",
|
2023-09-22 15:39:40 +00:00
|
|
|
|
description: _td("slash_command|verify"),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2018-06-18 18:31:40 +00:00
|
|
|
|
if (args) {
|
|
|
|
|
const matches = args.match(/^(\S+) +(\S+) +(\S+)$/);
|
|
|
|
|
if (matches) {
|
|
|
|
|
const userId = matches[1];
|
|
|
|
|
const deviceId = matches[2];
|
|
|
|
|
const fingerprint = matches[3];
|
2017-05-23 08:24:18 +00:00
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
return success(
|
2023-01-12 13:25:14 +00:00
|
|
|
|
(async (): Promise<void> => {
|
2023-06-28 12:39:34 +00:00
|
|
|
|
const device = await getDeviceCryptoInfo(cli, userId, deviceId);
|
2022-12-12 11:24:14 +00:00
|
|
|
|
if (!device) {
|
2023-09-22 15:39:40 +00:00
|
|
|
|
throw new UserFriendlyError("slash_command|verify_unknown_pair", {
|
|
|
|
|
userId,
|
|
|
|
|
deviceId,
|
|
|
|
|
cause: undefined,
|
|
|
|
|
});
|
2022-12-12 11:24:14 +00:00
|
|
|
|
}
|
2023-04-24 13:19:46 +00:00
|
|
|
|
const deviceTrust = await cli.getCrypto()?.getDeviceVerificationStatus(userId, deviceId);
|
2022-12-12 11:24:14 +00:00
|
|
|
|
|
2023-04-24 13:19:46 +00:00
|
|
|
|
if (deviceTrust?.isVerified()) {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
if (device.getFingerprint() === fingerprint) {
|
2023-09-22 15:39:40 +00:00
|
|
|
|
throw new UserFriendlyError("slash_command|verify_nop");
|
2022-12-12 11:24:14 +00:00
|
|
|
|
} else {
|
2023-09-22 15:39:40 +00:00
|
|
|
|
throw new UserFriendlyError("slash_command|verify_nop_warning_mismatch");
|
2022-12-12 11:24:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-03 12:08:35 +00:00
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
if (device.getFingerprint() !== fingerprint) {
|
|
|
|
|
const fprint = device.getFingerprint();
|
2023-09-22 15:39:40 +00:00
|
|
|
|
throw new UserFriendlyError("slash_command|verify_mismatch", {
|
|
|
|
|
fprint,
|
|
|
|
|
userId,
|
|
|
|
|
deviceId,
|
|
|
|
|
fingerprint,
|
|
|
|
|
cause: undefined,
|
|
|
|
|
});
|
2022-12-12 11:24:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await cli.setDeviceVerified(userId, deviceId, true);
|
|
|
|
|
|
|
|
|
|
// Tell the user we verified everything
|
|
|
|
|
Modal.createDialog(InfoDialog, {
|
2023-09-22 15:39:40 +00:00
|
|
|
|
title: _t("slash_command|verify_success_title"),
|
2022-12-12 11:24:14 +00:00
|
|
|
|
description: (
|
|
|
|
|
<div>
|
2023-09-22 15:39:40 +00:00
|
|
|
|
<p>{_t("slash_command|verify_success_description", { userId, deviceId })}</p>
|
2022-12-12 11:24:14 +00:00
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
});
|
|
|
|
|
})(),
|
|
|
|
|
);
|
2018-06-18 18:31:40 +00:00
|
|
|
|
}
|
2017-05-23 08:24:18 +00:00
|
|
|
|
}
|
2018-06-18 18:31:40 +00:00
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.advanced,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2018-06-18 18:31:40 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
2022-12-12 11:24:14 +00:00
|
|
|
|
command: "discardsession",
|
2023-09-13 08:30:56 +00:00
|
|
|
|
description: _td("slash_command|discardsession"),
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
|
|
|
|
runFn: function (cli, roomId) {
|
2018-08-29 17:09:37 +00:00
|
|
|
|
try {
|
2023-05-25 15:29:48 +00:00
|
|
|
|
cli.forceDiscardSession(roomId);
|
2018-08-29 17:09:37 +00:00
|
|
|
|
} catch (e) {
|
2023-07-05 10:53:22 +00:00
|
|
|
|
return reject(e instanceof Error ? e.message : e);
|
2018-08-29 17:09:37 +00:00
|
|
|
|
}
|
|
|
|
|
return success();
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.advanced,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2018-08-29 17:09:37 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
|
|
|
|
command: "rainbow",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|rainbow"),
|
2022-12-12 11:24:14 +00:00
|
|
|
|
args: "<message>",
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2022-11-21 11:24:59 +00:00
|
|
|
|
if (!args) return reject(this.getUsage());
|
2021-06-17 10:37:06 +00:00
|
|
|
|
return successSync(ContentHelpers.makeHtmlMessage(args, textToHtmlRainbow(args)));
|
2019-05-12 15:36:43 +00:00
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.messages,
|
2019-05-12 15:36:43 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
|
|
|
|
command: "rainbowme",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|rainbowme"),
|
2022-12-12 11:24:14 +00:00
|
|
|
|
args: "<message>",
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2022-11-21 11:24:59 +00:00
|
|
|
|
if (!args) return reject(this.getUsage());
|
2021-06-17 10:37:06 +00:00
|
|
|
|
return successSync(ContentHelpers.makeHtmlEmote(args, textToHtmlRainbow(args)));
|
2019-05-12 15:36:43 +00:00
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.messages,
|
2019-05-12 16:14:30 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
new Command({
|
|
|
|
|
command: "help",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|help"),
|
2022-12-12 11:24:14 +00:00
|
|
|
|
runFn: function () {
|
2022-06-14 16:51:51 +00:00
|
|
|
|
Modal.createDialog(SlashCommandHelpDialog);
|
2019-07-29 16:58:34 +00:00
|
|
|
|
return success();
|
|
|
|
|
},
|
2019-08-06 17:03:38 +00:00
|
|
|
|
category: CommandCategories.advanced,
|
2019-07-29 16:58:34 +00:00
|
|
|
|
}),
|
2020-03-30 13:13:08 +00:00
|
|
|
|
new Command({
|
|
|
|
|
command: "whois",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|whois"),
|
2020-03-30 13:13:08 +00:00
|
|
|
|
args: "<user-id>",
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, userId) {
|
2020-03-30 13:13:08 +00:00
|
|
|
|
if (!userId || !userId.startsWith("@") || !userId.includes(":")) {
|
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-25 15:29:48 +00:00
|
|
|
|
const member = cli.getRoom(roomId)?.getMember(userId);
|
2020-05-14 03:03:12 +00:00
|
|
|
|
dis.dispatch<ViewUserPayload>({
|
|
|
|
|
action: Action.ViewUser,
|
2021-06-18 15:21:46 +00:00
|
|
|
|
// XXX: We should be using a real member object and not assuming what the receiver wants.
|
2022-12-12 11:24:14 +00:00
|
|
|
|
member: member || ({ userId } as User),
|
2020-03-30 13:13:08 +00:00
|
|
|
|
});
|
|
|
|
|
return success();
|
|
|
|
|
},
|
|
|
|
|
category: CommandCategories.advanced,
|
|
|
|
|
}),
|
2020-04-19 11:09:07 +00:00
|
|
|
|
new Command({
|
|
|
|
|
command: "rageshake",
|
|
|
|
|
aliases: ["bugreport"],
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|rageshake"),
|
2020-09-15 14:49:25 +00:00
|
|
|
|
isEnabled: () => !!SdkConfig.get().bug_report_endpoint_url,
|
2020-04-19 11:09:07 +00:00
|
|
|
|
args: "<description>",
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2020-04-19 11:19:31 +00:00
|
|
|
|
return success(
|
2022-06-14 16:51:51 +00:00
|
|
|
|
Modal.createDialog(BugReportDialog, {
|
2020-09-09 20:53:38 +00:00
|
|
|
|
initialText: args,
|
|
|
|
|
}).finished,
|
2020-04-19 11:19:31 +00:00
|
|
|
|
);
|
2020-04-19 11:09:07 +00:00
|
|
|
|
},
|
|
|
|
|
category: CommandCategories.advanced,
|
|
|
|
|
}),
|
2022-02-25 15:58:13 +00:00
|
|
|
|
new Command({
|
|
|
|
|
command: "tovirtual",
|
2023-09-13 08:30:56 +00:00
|
|
|
|
description: _td("slash_command|tovirtual"),
|
2022-02-25 15:58:13 +00:00
|
|
|
|
category: CommandCategories.advanced,
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled(cli): boolean {
|
|
|
|
|
return !!LegacyCallHandler.instance.getSupportsVirtualRooms() && !isCurrentLocalRoom(cli);
|
2022-02-25 15:58:13 +00:00
|
|
|
|
},
|
2023-05-25 15:29:48 +00:00
|
|
|
|
runFn: (cli, roomId) => {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
return success(
|
2023-01-12 13:25:14 +00:00
|
|
|
|
(async (): Promise<void> => {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
const room = await VoipUserMapper.sharedInstance().getVirtualRoomForRoom(roomId);
|
2023-09-13 08:30:56 +00:00
|
|
|
|
if (!room) throw new UserFriendlyError("slash_command|tovirtual_not_found");
|
2022-12-12 11:24:14 +00:00
|
|
|
|
dis.dispatch<ViewRoomPayload>({
|
|
|
|
|
action: Action.ViewRoom,
|
|
|
|
|
room_id: room.roomId,
|
|
|
|
|
metricsTrigger: "SlashCommand",
|
|
|
|
|
metricsViaKeyboard: true,
|
|
|
|
|
});
|
|
|
|
|
})(),
|
|
|
|
|
);
|
2022-02-25 15:58:13 +00:00
|
|
|
|
},
|
|
|
|
|
}),
|
2020-05-11 09:54:28 +00:00
|
|
|
|
new Command({
|
|
|
|
|
command: "query",
|
2023-09-13 08:30:56 +00:00
|
|
|
|
description: _td("slash_command|query"),
|
2020-05-11 09:54:28 +00:00
|
|
|
|
args: "<user-id>",
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, userId) {
|
2020-11-04 15:32:21 +00:00
|
|
|
|
// easter-egg for now: look up phone numbers through the thirdparty API
|
|
|
|
|
// (very dumb phone number detection...)
|
|
|
|
|
const isPhoneNumber = userId && /^\+?[0123456789]+$/.test(userId);
|
2022-12-12 11:24:14 +00:00
|
|
|
|
if (!userId || ((!userId.startsWith("@") || !userId.includes(":")) && !isPhoneNumber)) {
|
2020-05-11 09:54:28 +00:00
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
return success(
|
2023-01-12 13:25:14 +00:00
|
|
|
|
(async (): Promise<void> => {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
if (isPhoneNumber) {
|
|
|
|
|
const results = await LegacyCallHandler.instance.pstnLookup(userId);
|
|
|
|
|
if (!results || results.length === 0 || !results[0].userid) {
|
2023-09-13 08:30:56 +00:00
|
|
|
|
throw new UserFriendlyError("slash_command|query_not_found_phone_number");
|
2022-12-12 11:24:14 +00:00
|
|
|
|
}
|
|
|
|
|
userId = results[0].userid;
|
2020-11-04 15:32:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-25 15:29:48 +00:00
|
|
|
|
const roomId = await ensureDMExists(cli, userId);
|
2023-03-07 13:19:18 +00:00
|
|
|
|
if (!roomId) throw new Error("Failed to ensure DM exists");
|
2020-11-04 15:32:21 +00:00
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
dis.dispatch<ViewRoomPayload>({
|
|
|
|
|
action: Action.ViewRoom,
|
|
|
|
|
room_id: roomId,
|
|
|
|
|
metricsTrigger: "SlashCommand",
|
|
|
|
|
metricsViaKeyboard: true,
|
|
|
|
|
});
|
|
|
|
|
})(),
|
|
|
|
|
);
|
2020-05-11 09:54:28 +00:00
|
|
|
|
},
|
|
|
|
|
category: CommandCategories.actions,
|
|
|
|
|
}),
|
|
|
|
|
new Command({
|
|
|
|
|
command: "msg",
|
2023-09-05 09:44:41 +00:00
|
|
|
|
description: _td("slash_command|msg"),
|
2021-10-25 10:40:33 +00:00
|
|
|
|
args: "<user-id> [<message>]",
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2020-05-11 09:54:28 +00:00
|
|
|
|
if (args) {
|
2020-05-12 09:23:53 +00:00
|
|
|
|
// matches the first whitespace delimited group and then the rest of the string
|
2020-05-11 09:54:28 +00:00
|
|
|
|
const matches = args.match(/^(\S+?)(?: +(.*))?$/s);
|
|
|
|
|
if (matches) {
|
|
|
|
|
const [userId, msg] = matches.slice(1);
|
2021-10-25 10:40:33 +00:00
|
|
|
|
if (userId && userId.startsWith("@") && userId.includes(":")) {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
return success(
|
2023-01-12 13:25:14 +00:00
|
|
|
|
(async (): Promise<void> => {
|
2022-12-12 11:24:14 +00:00
|
|
|
|
const roomId = await ensureDMExists(cli, userId);
|
2023-03-07 13:19:18 +00:00
|
|
|
|
if (!roomId) throw new Error("Failed to ensure DM exists");
|
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
dis.dispatch<ViewRoomPayload>({
|
|
|
|
|
action: Action.ViewRoom,
|
|
|
|
|
room_id: roomId,
|
|
|
|
|
metricsTrigger: "SlashCommand",
|
|
|
|
|
metricsViaKeyboard: true,
|
|
|
|
|
});
|
|
|
|
|
if (msg) {
|
|
|
|
|
cli.sendTextMessage(roomId, msg);
|
|
|
|
|
}
|
|
|
|
|
})(),
|
|
|
|
|
);
|
2020-05-11 09:54:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return reject(this.getUsage());
|
|
|
|
|
},
|
|
|
|
|
category: CommandCategories.actions,
|
|
|
|
|
}),
|
2020-10-29 17:56:24 +00:00
|
|
|
|
new Command({
|
|
|
|
|
command: "holdcall",
|
2023-09-13 08:30:56 +00:00
|
|
|
|
description: _td("slash_command|holdcall"),
|
2020-10-29 17:56:24 +00:00
|
|
|
|
category: CommandCategories.other,
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2022-08-30 19:13:39 +00:00
|
|
|
|
const call = LegacyCallHandler.instance.getCallForRoom(roomId);
|
2020-10-29 17:56:24 +00:00
|
|
|
|
if (!call) {
|
2023-09-13 08:30:56 +00:00
|
|
|
|
return reject(new UserFriendlyError("slash_command|no_active_call"));
|
2020-10-29 17:56:24 +00:00
|
|
|
|
}
|
|
|
|
|
call.setRemoteOnHold(true);
|
|
|
|
|
return success();
|
|
|
|
|
},
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2020-10-29 17:56:24 +00:00
|
|
|
|
}),
|
|
|
|
|
new Command({
|
|
|
|
|
command: "unholdcall",
|
2023-09-13 08:30:56 +00:00
|
|
|
|
description: _td("slash_command|unholdcall"),
|
2020-10-29 17:56:24 +00:00
|
|
|
|
category: CommandCategories.other,
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2022-08-30 19:13:39 +00:00
|
|
|
|
const call = LegacyCallHandler.instance.getCallForRoom(roomId);
|
2020-10-29 17:56:24 +00:00
|
|
|
|
if (!call) {
|
2023-09-13 08:30:56 +00:00
|
|
|
|
return reject(new UserFriendlyError("slash_command|no_active_call"));
|
2020-10-29 17:56:24 +00:00
|
|
|
|
}
|
|
|
|
|
call.setRemoteOnHold(false);
|
|
|
|
|
return success();
|
|
|
|
|
},
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2020-10-29 17:56:24 +00:00
|
|
|
|
}),
|
2021-01-13 14:30:09 +00:00
|
|
|
|
new Command({
|
|
|
|
|
command: "converttodm",
|
2023-09-13 08:30:56 +00:00
|
|
|
|
description: _td("slash_command|converttodm"),
|
2021-01-13 14:30:09 +00:00
|
|
|
|
category: CommandCategories.other,
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2023-05-25 15:29:48 +00:00
|
|
|
|
const room = cli.getRoom(roomId);
|
2023-09-13 08:30:56 +00:00
|
|
|
|
if (!room) return reject(new UserFriendlyError("slash_command|could_not_find_room"));
|
2021-01-13 14:30:09 +00:00
|
|
|
|
return success(guessAndSetDMRoom(room, true));
|
|
|
|
|
},
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2021-01-13 14:30:09 +00:00
|
|
|
|
}),
|
|
|
|
|
new Command({
|
|
|
|
|
command: "converttoroom",
|
2023-09-13 08:30:56 +00:00
|
|
|
|
description: _td("slash_command|converttoroom"),
|
2021-01-13 14:30:09 +00:00
|
|
|
|
category: CommandCategories.other,
|
2023-05-25 15:29:48 +00:00
|
|
|
|
isEnabled: (cli) => !isCurrentLocalRoom(cli),
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2023-05-25 15:29:48 +00:00
|
|
|
|
const room = cli.getRoom(roomId);
|
2023-09-13 08:30:56 +00:00
|
|
|
|
if (!room) return reject(new UserFriendlyError("slash_command|could_not_find_room"));
|
2021-01-13 14:30:09 +00:00
|
|
|
|
return success(guessAndSetDMRoom(room, false));
|
|
|
|
|
},
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2021-01-13 14:30:09 +00:00
|
|
|
|
}),
|
2020-02-29 01:29:52 +00:00
|
|
|
|
|
2020-03-30 12:59:08 +00:00
|
|
|
|
// Command definitions for autocompletion ONLY:
|
|
|
|
|
// /me is special because its not handled by SlashCommands.js and is instead done inside the Composer classes
|
|
|
|
|
new Command({
|
2020-04-10 12:59:01 +00:00
|
|
|
|
command: "me",
|
2022-12-12 11:24:14 +00:00
|
|
|
|
args: "<message>",
|
2023-09-13 08:30:56 +00:00
|
|
|
|
description: _td("slash_command|me"),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
category: CommandCategories.messages,
|
|
|
|
|
hideCompletionAfterSpace: true,
|
2020-02-29 01:29:52 +00:00
|
|
|
|
}),
|
2020-11-26 17:27:35 +00:00
|
|
|
|
|
2020-11-27 13:54:21 +00:00
|
|
|
|
...CHAT_EFFECTS.map((effect) => {
|
2020-10-21 11:37:36 +00:00
|
|
|
|
return new Command({
|
|
|
|
|
command: effect.command,
|
|
|
|
|
description: effect.description(),
|
2022-12-12 11:24:14 +00:00
|
|
|
|
args: "<message>",
|
2023-07-07 14:40:25 +00:00
|
|
|
|
runFn: function (cli, roomId, threadId, args) {
|
2022-07-27 10:03:25 +00:00
|
|
|
|
let content: IContent;
|
|
|
|
|
if (!args) {
|
|
|
|
|
content = ContentHelpers.makeEmoteMessage(effect.fallbackMessage());
|
|
|
|
|
} else {
|
|
|
|
|
content = {
|
|
|
|
|
msgtype: effect.msgType,
|
|
|
|
|
body: args,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
dis.dispatch({ action: `effects.${effect.command}` });
|
|
|
|
|
return successSync(content);
|
2020-10-21 11:37:36 +00:00
|
|
|
|
},
|
|
|
|
|
category: CommandCategories.effects,
|
2021-11-18 12:47:11 +00:00
|
|
|
|
renderingTypes: [TimelineRenderingType.Room],
|
2021-06-29 12:11:58 +00:00
|
|
|
|
});
|
2020-08-18 15:57:51 +00:00
|
|
|
|
}),
|
2020-03-30 12:59:08 +00:00
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// build a map from names and aliases to the Command objects.
|
2021-06-30 12:01:26 +00:00
|
|
|
|
export const CommandMap = new Map<string, Command>();
|
2022-12-12 11:24:14 +00:00
|
|
|
|
Commands.forEach((cmd) => {
|
2020-03-30 12:59:08 +00:00
|
|
|
|
CommandMap.set(cmd.command, cmd);
|
2022-12-12 11:24:14 +00:00
|
|
|
|
cmd.aliases.forEach((alias) => {
|
2020-03-30 12:59:08 +00:00
|
|
|
|
CommandMap.set(alias, cmd);
|
|
|
|
|
});
|
|
|
|
|
});
|
2015-09-18 12:54:20 +00:00
|
|
|
|
|
2022-12-12 11:24:14 +00:00
|
|
|
|
export function parseCommandString(input: string): { cmd?: string; args?: string } {
|
2023-04-17 12:57:19 +00:00
|
|
|
|
// trim any trailing whitespace, as it can confuse the parser for IRC-style commands
|
|
|
|
|
input = input.trimEnd();
|
2022-12-12 11:24:14 +00:00
|
|
|
|
if (input[0] !== "/") return {}; // not a command
|
2018-06-18 18:31:40 +00:00
|
|
|
|
|
2021-02-15 12:16:32 +00:00
|
|
|
|
const bits = input.match(/^(\S+?)(?:[ \n]+((.|\n)*))?$/);
|
2021-06-30 12:01:26 +00:00
|
|
|
|
let cmd: string;
|
2023-02-16 17:21:44 +00:00
|
|
|
|
let args: string | undefined;
|
2018-06-18 18:31:40 +00:00
|
|
|
|
if (bits) {
|
|
|
|
|
cmd = bits[1].substring(1).toLowerCase();
|
2020-01-21 16:50:04 +00:00
|
|
|
|
args = bits[2];
|
2018-06-18 18:31:40 +00:00
|
|
|
|
} else {
|
|
|
|
|
cmd = input;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 12:11:58 +00:00
|
|
|
|
return { cmd, args };
|
2020-04-10 12:59:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-30 12:01:26 +00:00
|
|
|
|
interface ICmd {
|
|
|
|
|
cmd?: Command;
|
|
|
|
|
args?: string;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-10 12:59:01 +00:00
|
|
|
|
/**
|
2022-06-07 20:20:32 +00:00
|
|
|
|
* Process the given text for /commands and returns a parsed command that can be used for running the operation.
|
2020-04-10 12:59:01 +00:00
|
|
|
|
* @param {string} input The raw text input by the user.
|
2022-06-07 20:20:32 +00:00
|
|
|
|
* @return {ICmd} The parsed command object.
|
|
|
|
|
* Returns an empty object if the input didn't match a command.
|
2020-04-10 12:59:01 +00:00
|
|
|
|
*/
|
2021-06-30 12:01:26 +00:00
|
|
|
|
export function getCommand(input: string): ICmd {
|
2021-06-29 12:11:58 +00:00
|
|
|
|
const { cmd, args } = parseCommandString(input);
|
2020-04-10 12:59:01 +00:00
|
|
|
|
|
2023-06-14 12:49:18 +00:00
|
|
|
|
if (cmd && CommandMap.has(cmd) && CommandMap.get(cmd)!.isEnabled(MatrixClientPeg.get())) {
|
2021-02-25 19:39:20 +00:00
|
|
|
|
return {
|
|
|
|
|
cmd: CommandMap.get(cmd),
|
|
|
|
|
args,
|
|
|
|
|
};
|
2018-06-18 18:31:40 +00:00
|
|
|
|
}
|
2021-04-13 09:33:32 +00:00
|
|
|
|
return {};
|
2018-06-18 18:31:40 +00:00
|
|
|
|
}
|