Skip to content

Commit 1c7914a

Browse files
committed
feat: add listusers command
Signed-off-by: Seth Falco <[email protected]>
1 parent ac5180e commit 1c7914a

File tree

2 files changed

+79
-8
lines changed

2 files changed

+79
-8
lines changed

changelog.d/854.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add listusers command to Discord bot to list the users on the Matrix side. Thanks to @SethFalco!

src/discordcommandhandler.ts

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,15 @@ export class DiscordCommandHandler {
5050
permission: "MANAGE_WEBHOOKS",
5151
run: async () => {
5252
if (await this.discord.Provisioner.MarkApproved(chan, discordMember, true)) {
53-
return "Thanks for your response! The matrix bridge has been approved.";
53+
return "Thanks for your response! The Matrix bridge has been approved.";
5454
} else {
5555
return "Thanks for your response, however" +
5656
" it has arrived after the deadline - sorry!";
5757
}
5858
},
5959
},
6060
ban: {
61-
description: "Bans a user on the matrix side",
61+
description: "Bans a user on the Matrix side",
6262
params: ["name"],
6363
permission: "BAN_MEMBERS",
6464
run: this.ModerationActionGenerator(chan, "ban"),
@@ -69,36 +69,42 @@ export class DiscordCommandHandler {
6969
permission: "MANAGE_WEBHOOKS",
7070
run: async () => {
7171
if (await this.discord.Provisioner.MarkApproved(chan, discordMember, false)) {
72-
return "Thanks for your response! The matrix bridge has been declined.";
72+
return "Thanks for your response! The Matrix bridge has been declined.";
7373
} else {
7474
return "Thanks for your response, however" +
7575
" it has arrived after the deadline - sorry!";
7676
}
7777
},
7878
},
7979
kick: {
80-
description: "Kicks a user on the matrix side",
80+
description: "Kicks a user on the Matrix side",
8181
params: ["name"],
8282
permission: "KICK_MEMBERS",
8383
run: this.ModerationActionGenerator(chan, "kick"),
8484
},
8585
unban: {
86-
description: "Unbans a user on the matrix side",
86+
description: "Unbans a user on the Matrix side",
8787
params: ["name"],
8888
permission: "BAN_MEMBERS",
8989
run: this.ModerationActionGenerator(chan, "unban"),
9090
},
9191
unbridge: {
92-
description: "Unbridge matrix rooms from this channel",
92+
description: "Unbridge Matrix rooms from this channel",
9393
params: [],
9494
permission: ["MANAGE_WEBHOOKS", "MANAGE_CHANNELS"],
9595
run: async () => this.UnbridgeChannel(chan),
9696
},
97+
listusers: {
98+
description: "List users on the Matrix side of the bridge",
99+
params: [],
100+
permission: [],
101+
run: async () => this.ListMatrixMembers(chan)
102+
}
97103
};
98104

99105
const parameters: ICommandParameters = {
100106
name: {
101-
description: "The display name or mxid of a matrix user",
107+
description: "The display name or mxid of a Matrix user",
102108
get: async (name) => {
103109
const channelMxids = await this.discord.ChannelSyncroniser.GetRoomIdsFromChannel(msg.channel);
104110
const mxUserId = await Util.GetMxidFromName(intent, name, channelMxids);
@@ -156,12 +162,76 @@ export class DiscordCommandHandler {
156162
return "This channel has been unbridged";
157163
} catch (err) {
158164
if (err.message === "Channel is not bridged") {
159-
return "This channel is not bridged to a plumbed matrix room";
165+
return "This channel is not bridged to a plumbed Matrix room";
160166
}
161167
log.error("Error while unbridging room " + channel.id);
162168
log.error(err);
163169
return "There was an error unbridging this room. " +
164170
"Please try again later or contact the bridge operator.";
165171
}
166172
}
173+
174+
private async ListMatrixMembers(channel: Discord.TextChannel): Promise<string> {
175+
const chanMxids = await this.discord.ChannelSyncroniser.GetRoomIdsFromChannel(channel);
176+
const response: string[] = [];
177+
const errorMessages: string[] = [];
178+
179+
await Promise.all(chanMxids.map(async (chanMxid) => {
180+
try {
181+
const { underlyingClient } = this.bridge.botIntent;
182+
const memberProfiles = await underlyingClient.getJoinedRoomMembersWithProfiles(chanMxid);
183+
184+
for (const key in memberProfiles) {
185+
if (this.bridge.isNamespacedUser(key)) {
186+
continue;
187+
}
188+
189+
const memberProfile = memberProfiles[key];
190+
const hasDisplayName = !!memberProfile.display_name;
191+
let line: string;
192+
193+
if (hasDisplayName) {
194+
line = `${memberProfile.display_name} (${key})`;
195+
} else {
196+
line = `${key}`;
197+
}
198+
199+
response.push(`• ${line}`);
200+
}
201+
} catch (e) {
202+
errorMessages.push(`Couldn't get members from ${chanMxid}`);
203+
}
204+
}));
205+
206+
if (errorMessages.length) {
207+
const errorMessage = errorMessages.join('\n');
208+
throw Error(errorMessage);
209+
}
210+
211+
const length = response.length;
212+
let userCount: string;
213+
214+
switch (length) {
215+
case 0:
216+
userCount = "are **no** users";
217+
break;
218+
case 1:
219+
userCount = `is **1** user`;
220+
break;
221+
default:
222+
const formatter = new Intl.NumberFormat('en-US');
223+
userCount = `are **${formatter.format(length)}** users`;
224+
}
225+
226+
const userCountMessage = `There ${userCount} on the Matrix side.`
227+
228+
if (length === 0) {
229+
return userCountMessage;
230+
}
231+
232+
const disclaimer = `Matrix users in ${channel.toString()} may not necessarily be in the other bridged channels in the server.`;
233+
const userList = response.join('\n');
234+
235+
return `${userCountMessage} ${disclaimer}\n\n${userList}`;
236+
}
167237
}

0 commit comments

Comments
 (0)