Skip to content

Commit 25f9c66

Browse files
authored
Merge branch 'master' into fix-thanks-regex
2 parents 9a2c0d5 + e417a09 commit 25f9c66

File tree

4 files changed

+103
-23
lines changed

4 files changed

+103
-23
lines changed

.env.example

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ AUTOROLE=MSG_ID:ROLE_ID:EMOJI:AUTOREMOVE
77

88
DATABASE_URL="localhost:5432/tsc-bot"
99

10+
# Role given to trusted members, not full moderators, but can use some commands which
11+
# are not given to all server members.
12+
TRUSTED_ROLE_ID=
13+
14+
# Channel ID to direct users toward for an explanation of the help system.
15+
ASK_HELP_CHANNEL=
16+
1017
ASK_CATEGORY=
1118
ONGOING_CATEGORY=
1219
DORMANT_CATEGORY=

src/env.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ export const categories = {
2424

2525
export const askCooldownRoleId = process.env.ASK_COOLDOWN_ROLE!;
2626

27+
export const trustedRoleId = process.env.TRUSTED_ROLE_ID!;
28+
export const askHelpChannelId = process.env.ASK_HELP_CHANNEL!;
29+
2730
export const channelNames = process.env.CHANNEL_NAMES!.split(',');
2831
export const dormantChannelTimeout = parseInt(
2932
process.env.DORMANT_CHANNEL_TIMEOUT!,

src/modules/helpchan.ts

Lines changed: 78 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ import {
2121
channelNames,
2222
dormantChannelTimeout,
2323
dormantChannelLoop,
24+
askHelpChannelId,
2425
} from '../env';
26+
import { isTrustedMember } from '../util/inhibitors';
2527

2628
export class HelpChanModule extends Module {
2729
constructor(client: CookiecordClient) {
@@ -103,13 +105,8 @@ export class HelpChanModule extends Module {
103105

104106
this.busyChannels.add(msg.channel.id);
105107

106-
const helpUser = new HelpUser();
107-
helpUser.userId = msg.author.id;
108-
helpUser.channelId = msg.channel.id;
109-
await helpUser.save();
110-
111108
await msg.pin();
112-
await msg.member.roles.add(askCooldownRoleId);
109+
await this.addCooldown(msg.member, msg.channel);
113110
await this.moveChannel(msg.channel, categories.ongoing);
114111

115112
await this.ensureAskChannels(msg.guild);
@@ -149,7 +146,7 @@ export class HelpChanModule extends Module {
149146
}
150147

151148
const owner = await HelpUser.findOne({
152-
where: { channelId: msg.channel.id },
149+
channelId: msg.channel.id,
153150
});
154151

155152
if (
@@ -213,7 +210,7 @@ export class HelpChanModule extends Module {
213210
await Promise.all(pinned.map(msg => msg.unpin()));
214211

215212
const helpUser = await HelpUser.findOne({
216-
where: { channelId: channel.id },
213+
channelId: channel.id,
217214
});
218215
if (helpUser) {
219216
const member = await channel.guild.members.fetch({
@@ -249,12 +246,19 @@ export class HelpChanModule extends Module {
249246
}
250247
}
251248

252-
@command()
253-
async cooldown(msg: Message, @optional user?: GuildMember) {
254-
console.log('Cooldown', msg.content);
255-
if (!msg.guild) return;
249+
private async addCooldown(member: GuildMember, channel: TextChannel) {
250+
await member.roles.add(askCooldownRoleId);
251+
const helpUser = new HelpUser();
252+
helpUser.userId = member.user.id;
253+
helpUser.channelId = channel.id;
254+
await helpUser.save();
255+
}
256256

257-
const guildTarget = await msg.guild.members.fetch(user ?? msg.author);
257+
@command({ inhibitors: [CommonInhibitors.guildsOnly] })
258+
async cooldown(msg: Message, @optional member?: GuildMember) {
259+
const guildTarget = await msg.guild!.members.fetch(
260+
member ?? msg.author,
261+
);
258262

259263
if (!guildTarget) return;
260264

@@ -266,19 +270,13 @@ export class HelpChanModule extends Module {
266270
}
267271

268272
const helpUser = await HelpUser.findOne({
269-
where: { userId: guildTarget.id },
273+
userId: guildTarget.id,
270274
});
271275

272276
if (helpUser) {
273-
const channel = msg.guild.channels.resolve(helpUser.channelId);
274-
// If we don't have a channel, just remove the cooldown. This should
275-
// only happen if someone deletes a help channel.
276-
if (channel) {
277-
await msg.channel.send(
278-
`${guildTarget.displayName} has an active help channel: ${channel.name}`,
279-
);
280-
return;
281-
}
277+
return msg.channel.send(
278+
`${guildTarget.displayName} has an active help channel: <#${helpUser.channelId}>`,
279+
);
282280
}
283281

284282
await guildTarget.roles.remove(askCooldownRoleId);
@@ -287,6 +285,63 @@ export class HelpChanModule extends Module {
287285
);
288286
}
289287

288+
@command({ inhibitors: [isTrustedMember] })
289+
async claim(msg: Message, member: GuildMember) {
290+
const helpUser = await HelpUser.findOne({
291+
userId: member.id,
292+
});
293+
if (helpUser) {
294+
return msg.channel.send(
295+
`${member.displayName} already has an open help channel: <#${helpUser.channelId}>`,
296+
);
297+
}
298+
299+
const channelMessages = await msg.channel.messages.fetch({ limit: 50 });
300+
const questionMessages = channelMessages.filter(
301+
questionMsg =>
302+
questionMsg.author.id === member.id &&
303+
questionMsg.id !== msg.id,
304+
);
305+
306+
const msgContent = questionMessages
307+
.array()
308+
.slice(0, 10)
309+
.map(msg => msg.content)
310+
.reverse()
311+
.join('\n')
312+
.slice(0, 2000);
313+
314+
const claimedChannel = msg.guild!.channels.cache.find(
315+
channel =>
316+
channel.type === 'text' &&
317+
channel.parentID == categories.ask &&
318+
channel.name.startsWith(this.CHANNEL_PREFIX) &&
319+
!this.busyChannels.has(channel.id),
320+
) as TextChannel | undefined;
321+
322+
if (!claimedChannel) {
323+
return msg.channel.send(
324+
':warning: failed to claim a help channel, no available channel.',
325+
);
326+
}
327+
328+
this.busyChannels.add(claimedChannel.id);
329+
const toPin = await claimedChannel.send(
330+
new MessageEmbed()
331+
.setAuthor(member.displayName, member.user.displayAvatarURL())
332+
.setDescription(msgContent),
333+
);
334+
await toPin.pin();
335+
await this.addCooldown(member, claimedChannel);
336+
await this.moveChannel(claimedChannel, categories.ongoing);
337+
await claimedChannel.send(
338+
`${member.user} this channel has been claimed for your question. Please review <#${askHelpChannelId}> for how to get help.`,
339+
);
340+
await this.ensureAskChannels(msg.guild!);
341+
342+
this.busyChannels.delete(claimedChannel.id);
343+
}
344+
290345
// Commands to fix race conditions
291346
@command({
292347
inhibitors: [CommonInhibitors.hasGuildPermission('MANAGE_MESSAGES')],

src/util/inhibitors.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Inhibitor } from 'cookiecord';
2+
import { trustedRoleId } from '../env';
3+
4+
export const isTrustedMember: Inhibitor = async (msg, client) => {
5+
if (!msg.guild || !msg.member || msg.channel.type !== 'text') {
6+
return ":warning: you can't use that command here.";
7+
}
8+
9+
if (
10+
!msg.member.roles.cache.has(trustedRoleId) &&
11+
!msg.member.hasPermission('MANAGE_MESSAGES')
12+
) {
13+
return ":warning: you don't have permission to use that command.";
14+
}
15+
};

0 commit comments

Comments
 (0)