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

Commit 65b1bb9

Browse files
authored
Disable some slash commands in LocalRoom (#9193)
1 parent 1371949 commit 65b1bb9

File tree

2 files changed

+193
-8
lines changed

2 files changed

+193
-8
lines changed

src/SlashCommands.tsx

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
6969
import VoipUserMapper from './VoipUserMapper';
7070
import { htmlSerializeFromMdIfNeeded } from './editor/serialize';
7171
import { leaveRoomBehaviour } from "./utils/leave-behaviour";
72+
import { isLocalRoom } from './utils/localRoom/isLocalRoom';
7273

7374
// XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816
7475
interface HTMLInputEvent extends Event {
@@ -206,6 +207,12 @@ function successSync(value: any) {
206207
return success(Promise.resolve(value));
207208
}
208209

210+
const isCurrentLocalRoom = (): boolean => {
211+
const cli = MatrixClientPeg.get();
212+
const room = cli.getRoom(RoomViewStore.instance.getRoomId());
213+
return isLocalRoom(room);
214+
};
215+
209216
/* Disable the "unexpected this" error for these commands - all of the run
210217
* functions are called with `this` bound to the Command instance.
211218
*/
@@ -297,6 +304,7 @@ export const Commands = [
297304
command: 'upgraderoom',
298305
args: '<new_version>',
299306
description: _td('Upgrades a room to a new version'),
307+
isEnabled: () => !isCurrentLocalRoom(),
300308
runFn: function(roomId, args) {
301309
if (args) {
302310
const cli = MatrixClientPeg.get();
@@ -380,6 +388,7 @@ export const Commands = [
380388
aliases: ['roomnick'],
381389
args: '<display_name>',
382390
description: _td('Changes your display nickname in the current room only'),
391+
isEnabled: () => !isCurrentLocalRoom(),
383392
runFn: function(roomId, args) {
384393
if (args) {
385394
const cli = MatrixClientPeg.get();
@@ -399,6 +408,7 @@ export const Commands = [
399408
command: 'roomavatar',
400409
args: '[<mxc_url>]',
401410
description: _td('Changes the avatar of the current room'),
411+
isEnabled: () => !isCurrentLocalRoom(),
402412
runFn: function(roomId, args) {
403413
let promise = Promise.resolve(args);
404414
if (!args) {
@@ -417,6 +427,7 @@ export const Commands = [
417427
command: 'myroomavatar',
418428
args: '[<mxc_url>]',
419429
description: _td('Changes your avatar in this current room only'),
430+
isEnabled: () => !isCurrentLocalRoom(),
420431
runFn: function(roomId, args) {
421432
const cli = MatrixClientPeg.get();
422433
const room = cli.getRoom(roomId);
@@ -462,6 +473,7 @@ export const Commands = [
462473
command: 'topic',
463474
args: '[<topic>]',
464475
description: _td('Gets or sets the room topic'),
476+
isEnabled: () => !isCurrentLocalRoom(),
465477
runFn: function(roomId, args) {
466478
const cli = MatrixClientPeg.get();
467479
if (args) {
@@ -498,6 +510,7 @@ export const Commands = [
498510
command: 'roomname',
499511
args: '<name>',
500512
description: _td('Sets the room name'),
513+
isEnabled: () => !isCurrentLocalRoom(),
501514
runFn: function(roomId, args) {
502515
if (args) {
503516
return success(MatrixClientPeg.get().setRoomName(roomId, args));
@@ -512,7 +525,7 @@ export const Commands = [
512525
args: '<user-id> [<reason>]',
513526
description: _td('Invites user with given id to current room'),
514527
analyticsName: "Invite",
515-
isEnabled: () => shouldShowComponent(UIComponent.InviteUsers),
528+
isEnabled: () => !isCurrentLocalRoom() && shouldShowComponent(UIComponent.InviteUsers),
516529
runFn: function(roomId, args) {
517530
if (args) {
518531
const [address, reason] = args.split(/\s+(.+)/);
@@ -694,6 +707,7 @@ export const Commands = [
694707
args: '[<room-address>]',
695708
description: _td('Leave room'),
696709
analyticsName: "Part",
710+
isEnabled: () => !isCurrentLocalRoom(),
697711
runFn: function(roomId, args) {
698712
const cli = MatrixClientPeg.get();
699713

@@ -746,6 +760,7 @@ export const Commands = [
746760
aliases: ["kick"],
747761
args: '<user-id> [reason]',
748762
description: _td('Removes user with given id from this room'),
763+
isEnabled: () => !isCurrentLocalRoom(),
749764
runFn: function(roomId, args) {
750765
if (args) {
751766
const matches = args.match(/^(\S+?)( +(.*))?$/);
@@ -762,6 +777,7 @@ export const Commands = [
762777
command: 'ban',
763778
args: '<user-id> [reason]',
764779
description: _td('Bans user with given id'),
780+
isEnabled: () => !isCurrentLocalRoom(),
765781
runFn: function(roomId, args) {
766782
if (args) {
767783
const matches = args.match(/^(\S+?)( +(.*))?$/);
@@ -778,6 +794,7 @@ export const Commands = [
778794
command: 'unban',
779795
args: '<user-id>',
780796
description: _td('Unbans user with given ID'),
797+
isEnabled: () => !isCurrentLocalRoom(),
781798
runFn: function(roomId, args) {
782799
if (args) {
783800
const matches = args.match(/^(\S+)$/);
@@ -857,7 +874,8 @@ export const Commands = [
857874
isEnabled(): boolean {
858875
const cli = MatrixClientPeg.get();
859876
const room = cli.getRoom(RoomViewStore.instance.getRoomId());
860-
return room?.currentState.maySendStateEvent(EventType.RoomPowerLevels, cli.getUserId());
877+
return room?.currentState.maySendStateEvent(EventType.RoomPowerLevels, cli.getUserId())
878+
&& !isLocalRoom(room);
861879
},
862880
runFn: function(roomId, args) {
863881
if (args) {
@@ -897,7 +915,8 @@ export const Commands = [
897915
isEnabled(): boolean {
898916
const cli = MatrixClientPeg.get();
899917
const room = cli.getRoom(RoomViewStore.instance.getRoomId());
900-
return room?.currentState.maySendStateEvent(EventType.RoomPowerLevels, cli.getUserId());
918+
return room?.currentState.maySendStateEvent(EventType.RoomPowerLevels, cli.getUserId())
919+
&& !isLocalRoom(room);
901920
},
902921
runFn: function(roomId, args) {
903922
if (args) {
@@ -936,7 +955,9 @@ export const Commands = [
936955
command: 'addwidget',
937956
args: '<url | embed code | Jitsi url>',
938957
description: _td('Adds a custom widget by URL to the room'),
939-
isEnabled: () => SettingsStore.getValue(UIFeature.Widgets) && shouldShowComponent(UIComponent.AddIntegrations),
958+
isEnabled: () => SettingsStore.getValue(UIFeature.Widgets)
959+
&& shouldShowComponent(UIComponent.AddIntegrations)
960+
&& !isCurrentLocalRoom(),
940961
runFn: function(roomId, widgetUrl) {
941962
if (!widgetUrl) {
942963
return reject(newTranslatableError("Please supply a widget URL or embed code"));
@@ -1059,6 +1080,7 @@ export const Commands = [
10591080
new Command({
10601081
command: 'discardsession',
10611082
description: _td('Forces the current outbound group session in an encrypted room to be discarded'),
1083+
isEnabled: () => !isCurrentLocalRoom(),
10621084
runFn: function(roomId) {
10631085
try {
10641086
MatrixClientPeg.get().forceDiscardSession(roomId);
@@ -1074,7 +1096,7 @@ export const Commands = [
10741096
command: 'remakeolm',
10751097
description: _td('Developer command: Discards the current outbound group session and sets up new Olm sessions'),
10761098
isEnabled: () => {
1077-
return SettingsStore.getValue("developerMode");
1099+
return SettingsStore.getValue("developerMode") && !isCurrentLocalRoom();
10781100
},
10791101
runFn: (roomId) => {
10801102
try {
@@ -1125,6 +1147,7 @@ export const Commands = [
11251147
command: "whois",
11261148
description: _td("Displays information about a user"),
11271149
args: "<user-id>",
1150+
isEnabled: () => !isCurrentLocalRoom(),
11281151
runFn: function(roomId, userId) {
11291152
if (!userId || !userId.startsWith("@") || !userId.includes(":")) {
11301153
return reject(this.getUsage());
@@ -1160,7 +1183,7 @@ export const Commands = [
11601183
description: _td("Switches to this room's virtual room, if it has one"),
11611184
category: CommandCategories.advanced,
11621185
isEnabled(): boolean {
1163-
return CallHandler.instance.getSupportsVirtualRooms();
1186+
return CallHandler.instance.getSupportsVirtualRooms() && !isCurrentLocalRoom();
11641187
},
11651188
runFn: (roomId) => {
11661189
return success((async () => {
@@ -1244,6 +1267,7 @@ export const Commands = [
12441267
command: "holdcall",
12451268
description: _td("Places the call in the current room on hold"),
12461269
category: CommandCategories.other,
1270+
isEnabled: () => !isCurrentLocalRoom(),
12471271
runFn: function(roomId, args) {
12481272
const call = CallHandler.instance.getCallForRoom(roomId);
12491273
if (!call) {
@@ -1258,6 +1282,7 @@ export const Commands = [
12581282
command: "unholdcall",
12591283
description: _td("Takes the call in the current room off hold"),
12601284
category: CommandCategories.other,
1285+
isEnabled: () => !isCurrentLocalRoom(),
12611286
runFn: function(roomId, args) {
12621287
const call = CallHandler.instance.getCallForRoom(roomId);
12631288
if (!call) {
@@ -1272,6 +1297,7 @@ export const Commands = [
12721297
command: "converttodm",
12731298
description: _td("Converts the room to a DM"),
12741299
category: CommandCategories.other,
1300+
isEnabled: () => !isCurrentLocalRoom(),
12751301
runFn: function(roomId, args) {
12761302
const room = MatrixClientPeg.get().getRoom(roomId);
12771303
return success(guessAndSetDMRoom(room, true));
@@ -1282,6 +1308,7 @@ export const Commands = [
12821308
command: "converttoroom",
12831309
description: _td("Converts the DM to a room"),
12841310
category: CommandCategories.other,
1311+
isEnabled: () => !isCurrentLocalRoom(),
12851312
runFn: function(roomId, args) {
12861313
const room = MatrixClientPeg.get().getRoom(roomId);
12871314
return success(guessAndSetDMRoom(room, false));

test/SlashCommands-test.tsx

Lines changed: 160 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,53 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import { MatrixClient } from 'matrix-js-sdk/src/matrix';
17+
import { MatrixClient, Room } from 'matrix-js-sdk/src/matrix';
18+
import { mocked } from 'jest-mock';
1819

19-
import { getCommand } from '../src/SlashCommands';
20+
import { Command, Commands, getCommand } from '../src/SlashCommands';
2021
import { createTestClient } from './test-utils';
2122
import { MatrixClientPeg } from '../src/MatrixClientPeg';
23+
import { LocalRoom, LOCAL_ROOM_ID_PREFIX } from '../src/models/LocalRoom';
24+
import { RoomViewStore } from '../src/stores/RoomViewStore';
25+
import SettingsStore from '../src/settings/SettingsStore';
26+
import CallHandler from '../src/CallHandler';
2227

2328
describe('SlashCommands', () => {
2429
let client: MatrixClient;
30+
const roomId = "!room:example.com";
31+
let room: Room;
32+
const localRoomId = LOCAL_ROOM_ID_PREFIX + "test";
33+
let localRoom: LocalRoom;
34+
let command: Command;
35+
36+
const findCommand = (cmd: string): Command => {
37+
return Commands.find((command: Command) => command.command === cmd);
38+
};
39+
40+
const setCurrentRoom = (): void => {
41+
mocked(RoomViewStore.instance.getRoomId).mockReturnValue(roomId);
42+
mocked(client.getRoom).mockImplementation((rId: string): Room => {
43+
if (rId === roomId) return room;
44+
});
45+
};
46+
47+
const setCurrentLocalRoon = (): void => {
48+
mocked(RoomViewStore.instance.getRoomId).mockReturnValue(localRoomId);
49+
mocked(client.getRoom).mockImplementation((rId: string): Room => {
50+
if (rId === localRoomId) return localRoom;
51+
});
52+
};
2553

2654
beforeEach(() => {
55+
jest.clearAllMocks();
56+
2757
client = createTestClient();
2858
jest.spyOn(MatrixClientPeg, 'get').mockReturnValue(client);
59+
60+
room = new Room(roomId, client, client.getUserId());
61+
localRoom = new LocalRoom(localRoomId, client, client.getUserId());
62+
63+
jest.spyOn(RoomViewStore.instance, "getRoomId");
2964
});
3065

3166
describe('/topic', () => {
@@ -37,4 +72,127 @@ describe('SlashCommands', () => {
3772
expect(client.setRoomTopic).toHaveBeenCalledWith("room-id", "pizza", undefined);
3873
});
3974
});
75+
76+
describe.each([
77+
["upgraderoom"],
78+
["myroomnick"],
79+
["roomavatar"],
80+
["myroomavatar"],
81+
["topic"],
82+
["roomname"],
83+
["invite"],
84+
["part"],
85+
["remove"],
86+
["ban"],
87+
["unban"],
88+
["op"],
89+
["deop"],
90+
["addwidget"],
91+
["discardsession"],
92+
["whois"],
93+
["holdcall"],
94+
["unholdcall"],
95+
["converttodm"],
96+
["converttoroom"],
97+
])("/%s", (commandName: string) => {
98+
beforeEach(() => {
99+
command = findCommand(commandName);
100+
});
101+
102+
describe("isEnabled", () => {
103+
it("should return true for Room", () => {
104+
setCurrentRoom();
105+
expect(command.isEnabled()).toBe(true);
106+
});
107+
108+
it("should return false for LocalRoom", () => {
109+
setCurrentLocalRoon();
110+
expect(command.isEnabled()).toBe(false);
111+
});
112+
});
113+
});
114+
115+
describe("/tovirtual", () => {
116+
beforeEach(() => {
117+
command = findCommand("tovirtual");
118+
});
119+
120+
describe("isEnabled", () => {
121+
describe("when virtual rooms are supported", () => {
122+
beforeEach(() => {
123+
jest.spyOn(CallHandler.instance, "getSupportsVirtualRooms").mockReturnValue(true);
124+
});
125+
126+
it("should return true for Room", () => {
127+
setCurrentRoom();
128+
expect(command.isEnabled()).toBe(true);
129+
});
130+
131+
it("should return false for LocalRoom", () => {
132+
setCurrentLocalRoon();
133+
expect(command.isEnabled()).toBe(false);
134+
});
135+
});
136+
137+
describe("when virtual rooms are not supported", () => {
138+
beforeEach(() => {
139+
jest.spyOn(CallHandler.instance, "getSupportsVirtualRooms").mockReturnValue(false);
140+
});
141+
142+
it("should return false for Room", () => {
143+
setCurrentRoom();
144+
expect(command.isEnabled()).toBe(false);
145+
});
146+
147+
it("should return false for LocalRoom", () => {
148+
setCurrentLocalRoon();
149+
expect(command.isEnabled()).toBe(false);
150+
});
151+
});
152+
});
153+
});
154+
155+
describe("/remakeolm", () => {
156+
beforeEach(() => {
157+
command = findCommand("remakeolm");
158+
});
159+
160+
describe("isEnabled", () => {
161+
describe("when developer mode is enabled", () => {
162+
beforeEach(() => {
163+
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => {
164+
if (settingName === "developerMode") return true;
165+
});
166+
});
167+
168+
it("should return true for Room", () => {
169+
setCurrentRoom();
170+
expect(command.isEnabled()).toBe(true);
171+
});
172+
173+
it("should return false for LocalRoom", () => {
174+
setCurrentLocalRoon();
175+
expect(command.isEnabled()).toBe(false);
176+
});
177+
});
178+
179+
describe("when developer mode is not enabled", () => {
180+
beforeEach(() => {
181+
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => {
182+
if (settingName === "developerMode") return false;
183+
});
184+
});
185+
186+
it("should return false for Room", () => {
187+
setCurrentRoom();
188+
expect(command.isEnabled()).toBe(false);
189+
});
190+
191+
it("should return false for LocalRoom", () => {
192+
setCurrentLocalRoon();
193+
expect(command.isEnabled()).toBe(false);
194+
});
195+
});
196+
});
197+
});
40198
});

0 commit comments

Comments
 (0)