Disable some slash commands in LocalRoom (#9192)

This commit is contained in:
Michael Weimann 2022-08-16 15:20:26 +02:00 committed by GitHub
parent 9bf77963ee
commit aa9191bc34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 193 additions and 8 deletions

View file

@ -69,6 +69,7 @@ import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
import VoipUserMapper from './VoipUserMapper';
import { htmlSerializeFromMdIfNeeded } from './editor/serialize';
import { leaveRoomBehaviour } from "./utils/leave-behaviour";
import { isLocalRoom } from './utils/localRoom/isLocalRoom';
// XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816
interface HTMLInputEvent extends Event {
@ -206,6 +207,12 @@ function successSync(value: any) {
return success(Promise.resolve(value));
}
const isCurrentLocalRoom = (): boolean => {
const cli = MatrixClientPeg.get();
const room = cli.getRoom(RoomViewStore.instance.getRoomId());
return isLocalRoom(room);
};
/* Disable the "unexpected this" error for these commands - all of the run
* functions are called with `this` bound to the Command instance.
*/
@ -297,6 +304,7 @@ export const Commands = [
command: 'upgraderoom',
args: '<new_version>',
description: _td('Upgrades a room to a new version'),
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
if (args) {
const cli = MatrixClientPeg.get();
@ -380,6 +388,7 @@ export const Commands = [
aliases: ['roomnick'],
args: '<display_name>',
description: _td('Changes your display nickname in the current room only'),
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
if (args) {
const cli = MatrixClientPeg.get();
@ -399,6 +408,7 @@ export const Commands = [
command: 'roomavatar',
args: '[<mxc_url>]',
description: _td('Changes the avatar of the current room'),
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
let promise = Promise.resolve(args);
if (!args) {
@ -417,6 +427,7 @@ export const Commands = [
command: 'myroomavatar',
args: '[<mxc_url>]',
description: _td('Changes your avatar in this current room only'),
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
const cli = MatrixClientPeg.get();
const room = cli.getRoom(roomId);
@ -462,6 +473,7 @@ export const Commands = [
command: 'topic',
args: '[<topic>]',
description: _td('Gets or sets the room topic'),
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
const cli = MatrixClientPeg.get();
if (args) {
@ -498,6 +510,7 @@ export const Commands = [
command: 'roomname',
args: '<name>',
description: _td('Sets the room name'),
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
if (args) {
return success(MatrixClientPeg.get().setRoomName(roomId, args));
@ -512,7 +525,7 @@ export const Commands = [
args: '<user-id> [<reason>]',
description: _td('Invites user with given id to current room'),
analyticsName: "Invite",
isEnabled: () => shouldShowComponent(UIComponent.InviteUsers),
isEnabled: () => !isCurrentLocalRoom() && shouldShowComponent(UIComponent.InviteUsers),
runFn: function(roomId, args) {
if (args) {
const [address, reason] = args.split(/\s+(.+)/);
@ -694,6 +707,7 @@ export const Commands = [
args: '[<room-address>]',
description: _td('Leave room'),
analyticsName: "Part",
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
const cli = MatrixClientPeg.get();
@ -746,6 +760,7 @@ export const Commands = [
aliases: ["kick"],
args: '<user-id> [reason]',
description: _td('Removes user with given id from this room'),
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
if (args) {
const matches = args.match(/^(\S+?)( +(.*))?$/);
@ -762,6 +777,7 @@ export const Commands = [
command: 'ban',
args: '<user-id> [reason]',
description: _td('Bans user with given id'),
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
if (args) {
const matches = args.match(/^(\S+?)( +(.*))?$/);
@ -778,6 +794,7 @@ export const Commands = [
command: 'unban',
args: '<user-id>',
description: _td('Unbans user with given ID'),
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
if (args) {
const matches = args.match(/^(\S+)$/);
@ -857,7 +874,8 @@ export const Commands = [
isEnabled(): boolean {
const cli = MatrixClientPeg.get();
const room = cli.getRoom(RoomViewStore.instance.getRoomId());
return room?.currentState.maySendStateEvent(EventType.RoomPowerLevels, cli.getUserId());
return room?.currentState.maySendStateEvent(EventType.RoomPowerLevels, cli.getUserId())
&& !isLocalRoom(room);
},
runFn: function(roomId, args) {
if (args) {
@ -897,7 +915,8 @@ export const Commands = [
isEnabled(): boolean {
const cli = MatrixClientPeg.get();
const room = cli.getRoom(RoomViewStore.instance.getRoomId());
return room?.currentState.maySendStateEvent(EventType.RoomPowerLevels, cli.getUserId());
return room?.currentState.maySendStateEvent(EventType.RoomPowerLevels, cli.getUserId())
&& !isLocalRoom(room);
},
runFn: function(roomId, args) {
if (args) {
@ -936,7 +955,9 @@ export const Commands = [
command: 'addwidget',
args: '<url | embed code | Jitsi url>',
description: _td('Adds a custom widget by URL to the room'),
isEnabled: () => SettingsStore.getValue(UIFeature.Widgets) && shouldShowComponent(UIComponent.AddIntegrations),
isEnabled: () => SettingsStore.getValue(UIFeature.Widgets)
&& shouldShowComponent(UIComponent.AddIntegrations)
&& !isCurrentLocalRoom(),
runFn: function(roomId, widgetUrl) {
if (!widgetUrl) {
return reject(newTranslatableError("Please supply a widget URL or embed code"));
@ -1059,6 +1080,7 @@ export const Commands = [
new Command({
command: 'discardsession',
description: _td('Forces the current outbound group session in an encrypted room to be discarded'),
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId) {
try {
MatrixClientPeg.get().forceDiscardSession(roomId);
@ -1074,7 +1096,7 @@ export const Commands = [
command: 'remakeolm',
description: _td('Developer command: Discards the current outbound group session and sets up new Olm sessions'),
isEnabled: () => {
return SettingsStore.getValue("developerMode");
return SettingsStore.getValue("developerMode") && !isCurrentLocalRoom();
},
runFn: (roomId) => {
try {
@ -1125,6 +1147,7 @@ export const Commands = [
command: "whois",
description: _td("Displays information about a user"),
args: "<user-id>",
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, userId) {
if (!userId || !userId.startsWith("@") || !userId.includes(":")) {
return reject(this.getUsage());
@ -1160,7 +1183,7 @@ export const Commands = [
description: _td("Switches to this room's virtual room, if it has one"),
category: CommandCategories.advanced,
isEnabled(): boolean {
return CallHandler.instance.getSupportsVirtualRooms();
return CallHandler.instance.getSupportsVirtualRooms() && !isCurrentLocalRoom();
},
runFn: (roomId) => {
return success((async () => {
@ -1244,6 +1267,7 @@ export const Commands = [
command: "holdcall",
description: _td("Places the call in the current room on hold"),
category: CommandCategories.other,
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
const call = CallHandler.instance.getCallForRoom(roomId);
if (!call) {
@ -1258,6 +1282,7 @@ export const Commands = [
command: "unholdcall",
description: _td("Takes the call in the current room off hold"),
category: CommandCategories.other,
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
const call = CallHandler.instance.getCallForRoom(roomId);
if (!call) {
@ -1272,6 +1297,7 @@ export const Commands = [
command: "converttodm",
description: _td("Converts the room to a DM"),
category: CommandCategories.other,
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
const room = MatrixClientPeg.get().getRoom(roomId);
return success(guessAndSetDMRoom(room, true));
@ -1282,6 +1308,7 @@ export const Commands = [
command: "converttoroom",
description: _td("Converts the DM to a room"),
category: CommandCategories.other,
isEnabled: () => !isCurrentLocalRoom(),
runFn: function(roomId, args) {
const room = MatrixClientPeg.get().getRoom(roomId);
return success(guessAndSetDMRoom(room, false));

View file

@ -14,18 +14,53 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { MatrixClient } from 'matrix-js-sdk/src/matrix';
import { MatrixClient, Room } from 'matrix-js-sdk/src/matrix';
import { mocked } from 'jest-mock';
import { getCommand } from '../src/SlashCommands';
import { Command, Commands, getCommand } from '../src/SlashCommands';
import { createTestClient } from './test-utils';
import { MatrixClientPeg } from '../src/MatrixClientPeg';
import { LocalRoom, LOCAL_ROOM_ID_PREFIX } from '../src/models/LocalRoom';
import { RoomViewStore } from '../src/stores/RoomViewStore';
import SettingsStore from '../src/settings/SettingsStore';
import CallHandler from '../src/CallHandler';
describe('SlashCommands', () => {
let client: MatrixClient;
const roomId = "!room:example.com";
let room: Room;
const localRoomId = LOCAL_ROOM_ID_PREFIX + "test";
let localRoom: LocalRoom;
let command: Command;
const findCommand = (cmd: string): Command => {
return Commands.find((command: Command) => command.command === cmd);
};
const setCurrentRoom = (): void => {
mocked(RoomViewStore.instance.getRoomId).mockReturnValue(roomId);
mocked(client.getRoom).mockImplementation((rId: string): Room => {
if (rId === roomId) return room;
});
};
const setCurrentLocalRoon = (): void => {
mocked(RoomViewStore.instance.getRoomId).mockReturnValue(localRoomId);
mocked(client.getRoom).mockImplementation((rId: string): Room => {
if (rId === localRoomId) return localRoom;
});
};
beforeEach(() => {
jest.clearAllMocks();
client = createTestClient();
jest.spyOn(MatrixClientPeg, 'get').mockReturnValue(client);
room = new Room(roomId, client, client.getUserId());
localRoom = new LocalRoom(localRoomId, client, client.getUserId());
jest.spyOn(RoomViewStore.instance, "getRoomId");
});
describe('/topic', () => {
@ -37,4 +72,127 @@ describe('SlashCommands', () => {
expect(client.setRoomTopic).toHaveBeenCalledWith("room-id", "pizza", undefined);
});
});
describe.each([
["upgraderoom"],
["myroomnick"],
["roomavatar"],
["myroomavatar"],
["topic"],
["roomname"],
["invite"],
["part"],
["remove"],
["ban"],
["unban"],
["op"],
["deop"],
["addwidget"],
["discardsession"],
["whois"],
["holdcall"],
["unholdcall"],
["converttodm"],
["converttoroom"],
])("/%s", (commandName: string) => {
beforeEach(() => {
command = findCommand(commandName);
});
describe("isEnabled", () => {
it("should return true for Room", () => {
setCurrentRoom();
expect(command.isEnabled()).toBe(true);
});
it("should return false for LocalRoom", () => {
setCurrentLocalRoon();
expect(command.isEnabled()).toBe(false);
});
});
});
describe("/tovirtual", () => {
beforeEach(() => {
command = findCommand("tovirtual");
});
describe("isEnabled", () => {
describe("when virtual rooms are supported", () => {
beforeEach(() => {
jest.spyOn(CallHandler.instance, "getSupportsVirtualRooms").mockReturnValue(true);
});
it("should return true for Room", () => {
setCurrentRoom();
expect(command.isEnabled()).toBe(true);
});
it("should return false for LocalRoom", () => {
setCurrentLocalRoon();
expect(command.isEnabled()).toBe(false);
});
});
describe("when virtual rooms are not supported", () => {
beforeEach(() => {
jest.spyOn(CallHandler.instance, "getSupportsVirtualRooms").mockReturnValue(false);
});
it("should return false for Room", () => {
setCurrentRoom();
expect(command.isEnabled()).toBe(false);
});
it("should return false for LocalRoom", () => {
setCurrentLocalRoon();
expect(command.isEnabled()).toBe(false);
});
});
});
});
describe("/remakeolm", () => {
beforeEach(() => {
command = findCommand("remakeolm");
});
describe("isEnabled", () => {
describe("when developer mode is enabled", () => {
beforeEach(() => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => {
if (settingName === "developerMode") return true;
});
});
it("should return true for Room", () => {
setCurrentRoom();
expect(command.isEnabled()).toBe(true);
});
it("should return false for LocalRoom", () => {
setCurrentLocalRoon();
expect(command.isEnabled()).toBe(false);
});
});
describe("when developer mode is not enabled", () => {
beforeEach(() => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => {
if (settingName === "developerMode") return false;
});
});
it("should return false for Room", () => {
setCurrentRoom();
expect(command.isEnabled()).toBe(false);
});
it("should return false for LocalRoom", () => {
setCurrentLocalRoon();
expect(command.isEnabled()).toBe(false);
});
});
});
});
});