1 |
rakinar2 |
577 |
/** |
2 |
|
|
* This file is part of SudoBot. |
3 |
|
|
* |
4 |
|
|
* Copyright (C) 2021-2022 OSN Inc. |
5 |
|
|
* |
6 |
|
|
* SudoBot is free software; you can redistribute it and/or modify it |
7 |
|
|
* under the terms of the GNU Affero General Public License as published by |
8 |
|
|
* the Free Software Foundation, either version 3 of the License, or |
9 |
|
|
* (at your option) any later version. |
10 |
|
|
* |
11 |
|
|
* SudoBot is distributed in the hope that it will be useful, but |
12 |
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
|
|
* GNU Affero General Public License for more details. |
15 |
|
|
* |
16 |
|
|
* You should have received a copy of the GNU Affero General Public License |
17 |
|
|
* along with SudoBot. If not, see <https://www.gnu.org/licenses/>. |
18 |
|
|
*/ |
19 |
|
|
|
20 |
|
|
import { roleMention } from "@discordjs/builders"; |
21 |
|
|
import { formatDistanceStrict, formatDistanceToNowStrict, formatDuration, intervalToDuration } from "date-fns"; |
22 |
|
|
import { |
23 |
|
|
Message, |
24 |
|
|
MessageEmbedOptions, |
25 |
|
|
MessageEmbed as MessageEmbedDiscord, |
26 |
|
|
TextChannel, |
27 |
|
|
MessageActionRow, |
28 |
|
|
MessageButton, |
29 |
|
|
FileOptions, |
30 |
|
|
GuildBan, |
31 |
|
|
BanOptions, |
32 |
|
|
Guild, |
33 |
|
|
User, |
34 |
|
|
GuildMember, |
35 |
|
|
Util, |
36 |
|
|
GuildChannel, |
37 |
|
|
Role, |
38 |
|
|
Collection, |
39 |
|
|
} from "discord.js"; |
40 |
|
|
import ms from "ms"; |
41 |
|
|
import BaseMessageEmbed from "../client/MessageEmbed"; |
42 |
|
|
import { IGuildInfo } from "../models/GuildInfo"; |
43 |
|
|
import Punishment, { IPunishment } from "../models/Punishment"; |
44 |
|
|
import PunishmentType from "../types/PunishmentType"; |
45 |
|
|
import Service from "../utils/structures/Service"; |
46 |
|
|
import { timeSince } from "../utils/util"; |
47 |
|
|
|
48 |
|
|
class MessageEmbed extends BaseMessageEmbed { |
49 |
|
|
constructor(options?: MessageEmbedDiscord | MessageEmbedOptions) { |
50 |
|
|
super(options); |
51 |
|
|
this.setTimestamp(); |
52 |
|
|
} |
53 |
|
|
} |
54 |
|
|
|
55 |
|
|
export default class Logger extends Service { |
56 |
|
|
loggingChannel(id: string) { |
57 |
|
|
return this.client.guilds.cache.get(id)?.channels.cache.get(this.client.config.props[id].logging_channel) as TextChannel | null; |
58 |
|
|
} |
59 |
|
|
|
60 |
|
|
loggingChannelBoosts(id: string) { |
61 |
|
|
return this.client.guilds.cache |
62 |
|
|
.get(id) |
63 |
|
|
?.channels.cache.get( |
64 |
|
|
this.client.config.props[id].logging_channel_boosts ?? this.client.config.props[id].logging_channel |
65 |
|
|
) as TextChannel | null; |
66 |
|
|
} |
67 |
|
|
|
68 |
|
|
loggingChannelJoinLeave(id: string) { |
69 |
|
|
return this.client.guilds.cache.get(id)?.channels.cache.get(this.client.config.props[id].logging_channel_join_leave) as TextChannel | null; |
70 |
|
|
} |
71 |
|
|
|
72 |
|
|
async onRoleCreate(role: Role) { |
73 |
|
|
this.loggingChannel(role.guild.id)?.send({ |
74 |
|
|
embeds: [ |
75 |
|
|
new MessageEmbed({ |
76 |
|
|
title: "Role created", |
77 |
|
|
fields: [ |
78 |
|
|
{ |
79 |
|
|
name: "Role", |
80 |
|
|
value: `Name: ${role.name}\nID: ${role.id}\nMention: ${role.toString()}` |
81 |
|
|
} |
82 |
|
|
], |
83 |
|
|
footer: { |
84 |
|
|
text: "Created" |
85 |
|
|
}, |
86 |
|
|
color: 0x007bff |
87 |
|
|
}) |
88 |
|
|
.setTimestamp() |
89 |
|
|
], |
90 |
|
|
allowedMentions: { |
91 |
|
|
roles: [] |
92 |
|
|
} |
93 |
|
|
}); |
94 |
|
|
} |
95 |
|
|
|
96 |
|
|
|
97 |
|
|
async onRoleDelete(role: Role) { |
98 |
|
|
this.loggingChannel(role.guild.id)?.send({ |
99 |
|
|
embeds: [ |
100 |
|
|
new MessageEmbed({ |
101 |
|
|
title: "Role deleted", |
102 |
|
|
fields: [ |
103 |
|
|
{ |
104 |
|
|
name: "Role", |
105 |
|
|
value: `Name: ${role.name}\nID: ${role.id}\nMention: ${role.toString()}` |
106 |
|
|
} |
107 |
|
|
], |
108 |
|
|
footer: { |
109 |
|
|
text: "Deleted" |
110 |
|
|
}, |
111 |
|
|
color: 0xf14a60 |
112 |
|
|
}) |
113 |
|
|
.setTimestamp() |
114 |
|
|
], |
115 |
|
|
allowedMentions: { |
116 |
|
|
roles: [] |
117 |
|
|
} |
118 |
|
|
}); |
119 |
|
|
} |
120 |
|
|
|
121 |
|
|
|
122 |
|
|
async onRoleUpdate(oldRole: Role, newRole: Role) { |
123 |
|
|
this.loggingChannel(newRole.guild.id)?.send({ |
124 |
|
|
embeds: [ |
125 |
|
|
new MessageEmbed({ |
126 |
|
|
title: "Role updated", |
127 |
|
|
fields: [ |
128 |
|
|
...(newRole.name !== oldRole.name ? [ |
129 |
|
|
{ |
130 |
|
|
name: "Name", |
131 |
|
|
value: `New Name: ${newRole.name}\nOld Name: ${oldRole.name}` |
132 |
|
|
} |
133 |
|
|
] : [ |
134 |
|
|
{ |
135 |
|
|
name: "Name", |
136 |
|
|
value: `${newRole.name}` |
137 |
|
|
} |
138 |
|
|
]), |
139 |
|
|
...(newRole.color !== oldRole.color ? [ |
140 |
|
|
{ |
141 |
|
|
name: "Color", |
142 |
|
|
value: `New Color: ${newRole.hexColor}\nOld Color: ${oldRole.hexColor}` |
143 |
|
|
} |
144 |
|
|
] : []), |
145 |
|
|
...(!newRole.permissions.equals(oldRole.permissions) ? [ |
146 |
|
|
{ |
147 |
|
|
name: "New Permissions", |
148 |
|
|
value: `\`${newRole.permissions.toArray().join('`, `')}\`` |
149 |
|
|
} |
150 |
|
|
] : []), |
151 |
|
|
...(oldRole.icon !== newRole.icon ? [ |
152 |
|
|
{ |
153 |
|
|
name: "Icon", |
154 |
|
|
value: `New Icon: ${newRole.iconURL()}\nOld Icon: ${oldRole.iconURL()}` |
155 |
|
|
} |
156 |
|
|
] : []), |
157 |
|
|
{ |
158 |
|
|
name: "ID", |
159 |
|
|
value: `${newRole.id}` |
160 |
|
|
} |
161 |
|
|
], |
162 |
|
|
footer: { |
163 |
|
|
text: "Updated" |
164 |
|
|
}, |
165 |
|
|
}) |
166 |
|
|
.setTimestamp() |
167 |
|
|
.setColor("GREEN") |
168 |
|
|
], |
169 |
|
|
allowedMentions: { |
170 |
|
|
roles: [] |
171 |
|
|
} |
172 |
|
|
}); |
173 |
|
|
} |
174 |
|
|
|
175 |
|
|
async onChannelCreate(channel: GuildChannel) { |
176 |
|
|
this.loggingChannel(channel.guild.id)?.send({ |
177 |
|
|
embeds: [ |
178 |
|
|
new MessageEmbed({ |
179 |
|
|
title: `Channel${channel.type === "GUILD_CATEGORY" ? " Category" : ""} Created`, |
180 |
|
|
color: 0x07bff, |
181 |
|
|
fields: [ |
182 |
|
|
{ |
183 |
|
|
name: "Channel", |
184 |
|
|
value: `#${channel.name} (${channel.toString()}, ${channel.id})` |
185 |
|
|
}, |
186 |
|
|
{ |
187 |
|
|
name: "Type", |
188 |
|
|
value: channel.type.replace("GUILD_", '') |
189 |
|
|
} |
190 |
|
|
], |
191 |
|
|
footer: { |
192 |
|
|
text: 'Created' |
193 |
|
|
} |
194 |
|
|
}).setTimestamp() |
195 |
|
|
] |
196 |
|
|
}).catch(console.error); |
197 |
|
|
} |
198 |
|
|
|
199 |
|
|
async onChannelDelete(channel: GuildChannel) { |
200 |
|
|
this.loggingChannel(channel.guild.id)?.send({ |
201 |
|
|
embeds: [ |
202 |
|
|
new MessageEmbed({ |
203 |
|
|
title: `Channel${channel.type === "GUILD_CATEGORY" ? " Category" : ""} Deleted`, |
204 |
|
|
color: 0xf14a60, |
205 |
|
|
fields: [ |
206 |
|
|
{ |
207 |
|
|
name: "Channel", |
208 |
|
|
value: `#${channel.name} (${channel.id})` |
209 |
|
|
}, |
210 |
|
|
{ |
211 |
|
|
name: "Type", |
212 |
|
|
value: channel.type.replace("GUILD_", '') |
213 |
|
|
} |
214 |
|
|
], |
215 |
|
|
footer: { |
216 |
|
|
text: 'Deleted' |
217 |
|
|
} |
218 |
|
|
}).setTimestamp() |
219 |
|
|
] |
220 |
|
|
}).catch(console.error); |
221 |
|
|
} |
222 |
|
|
|
223 |
|
|
async onMemberRoleAdd(member: GuildMember, roles: Role[]) { |
224 |
|
|
this.loggingChannel(member.guild.id)?.send({ |
225 |
|
|
embeds: [ |
226 |
|
|
new MessageEmbed({ |
227 |
|
|
title: `Roles added to member`, |
228 |
|
|
color: 0xf14a60, |
229 |
|
|
fields: [ |
230 |
|
|
{ |
231 |
|
|
name: "Member", |
232 |
|
|
value: `${member.user.toString()} (${member.user.id})` |
233 |
|
|
}, |
234 |
|
|
{ |
235 |
|
|
name: "Roles", |
236 |
|
|
value: `${roles.map(r => r.toString()).join(', ')}` |
237 |
|
|
} |
238 |
|
|
], |
239 |
|
|
footer: { |
240 |
|
|
text: 'Roles Added' |
241 |
|
|
} |
242 |
|
|
}).setTimestamp() |
243 |
|
|
], |
244 |
|
|
allowedMentions: { |
245 |
|
|
roles: [], |
246 |
|
|
users: [] |
247 |
|
|
} |
248 |
|
|
}).catch(console.error); |
249 |
|
|
} |
250 |
|
|
|
251 |
|
|
async onMemberRoleUpdate(newMember: GuildMember, oldMember: GuildMember) { |
252 |
|
|
this.loggingChannel(newMember.guild.id)?.send({ |
253 |
|
|
embeds: [ |
254 |
|
|
new MessageEmbed({ |
255 |
|
|
author: { |
256 |
|
|
name: newMember.user.username, |
257 |
|
|
icon_url: newMember.displayAvatarURL() |
258 |
|
|
}, |
259 |
|
|
title: `Roles modified`, |
260 |
|
|
color: 0xf14a60, |
261 |
|
|
fields: [ |
262 |
|
|
{ |
263 |
|
|
name: "Member", |
264 |
|
|
value: `${newMember.user.toString()} (${newMember.user.id})` |
265 |
|
|
}, |
266 |
|
|
{ |
267 |
|
|
name: "Old Roles", |
268 |
|
|
value: `${oldMember.roles.cache.map(r => r.toString()).join(', ')}` |
269 |
|
|
}, |
270 |
|
|
{ |
271 |
|
|
name: "New Roles", |
272 |
|
|
value: `${newMember.roles.cache.map(r => r.toString()).join(', ')}` |
273 |
|
|
} |
274 |
|
|
], |
275 |
|
|
footer: { |
276 |
|
|
text: 'Roles Updated' |
277 |
|
|
} |
278 |
|
|
}).setTimestamp() |
279 |
|
|
], |
280 |
|
|
allowedMentions: { |
281 |
|
|
roles: [], |
282 |
|
|
users: [] |
283 |
|
|
} |
284 |
|
|
}).catch(console.error); |
285 |
|
|
} |
286 |
|
|
|
287 |
|
|
async onMemberRoleRemove(member: GuildMember, roles: Role[]) { |
288 |
|
|
this.loggingChannel(member.guild.id)?.send({ |
289 |
|
|
embeds: [ |
290 |
|
|
new MessageEmbed({ |
291 |
|
|
title: `Roles removed from member`, |
292 |
|
|
color: 0xf14a60, |
293 |
|
|
fields: [ |
294 |
|
|
{ |
295 |
|
|
name: "Member", |
296 |
|
|
value: `${member.user.toString()} (${member.user.id})` |
297 |
|
|
}, |
298 |
|
|
{ |
299 |
|
|
name: "Roles", |
300 |
|
|
value: `${roles.map(r => r.toString()).join(', ')}` |
301 |
|
|
} |
302 |
|
|
], |
303 |
|
|
footer: { |
304 |
|
|
text: 'Roles Removed' |
305 |
|
|
} |
306 |
|
|
}).setTimestamp() |
307 |
|
|
], |
308 |
|
|
allowedMentions: { |
309 |
|
|
roles: [], |
310 |
|
|
users: [] |
311 |
|
|
} |
312 |
|
|
}).catch(console.error); |
313 |
|
|
} |
314 |
|
|
|
315 |
|
|
|
316 |
|
|
async onBulkDelete(messages: Collection<string, Message>) { |
317 |
|
|
this.loggingChannel(messages.at(0)?.guildId!)?.send({ |
318 |
|
|
embeds: [ |
319 |
|
|
new MessageEmbed({ |
320 |
|
|
title: `Messages deleted in bulk`, |
321 |
|
|
color: 0xf14a60, |
322 |
|
|
fields: [ |
323 |
|
|
{ |
324 |
|
|
name: "Channel", |
325 |
|
|
value: `${messages.at(0)?.channel.toString()} (${messages.at(0)?.channelId})` |
326 |
|
|
}, |
327 |
|
|
{ |
328 |
|
|
name: "Count", |
329 |
|
|
value: `${messages.size}` |
330 |
|
|
} |
331 |
|
|
], |
332 |
|
|
footer: { |
333 |
|
|
text: 'Deleted' |
334 |
|
|
} |
335 |
|
|
}).setTimestamp() |
336 |
|
|
] |
337 |
|
|
}).catch(console.error); |
338 |
|
|
} |
339 |
|
|
|
340 |
|
|
async onAIModMessageDelete(message: Message, config: any, response: any, meta: any) { |
341 |
|
|
const toxicScore = response.data.attributeScores.TOXICITY.summaryScore.value * 100; |
342 |
|
|
const severeToxicScore = response.data.attributeScores.SEVERE_TOXICITY.summaryScore.value * 100; |
343 |
|
|
const threatScore = response.data.attributeScores.THREAT.summaryScore.value * 100; |
344 |
|
|
|
345 |
|
|
let conf = meta.toxic ? `Toxicity score is ${toxicScore}%, which is higher than or equal to the given maximum value in the configuration (${config.toxicity * 100}%)` : ( |
346 |
|
|
meta.severeToxic ? `Severe Toxicity score is ${severeToxicScore}%, which is higher than or equal to the given maximum value in the configuration (${config.severe_toxicity * 100}%)` : ( |
347 |
|
|
meta.threat ? `Threat score is ${threatScore}%, which is higher than or equal to the given maximum value in the configuration (${config.threat * 100}%)` : `Unknown` |
348 |
|
|
) |
349 |
|
|
); |
350 |
|
|
|
351 |
|
|
await this.loggingChannel(message.guildId!)?.send({ |
352 |
|
|
embeds: [ |
353 |
|
|
new MessageEmbed({ |
354 |
|
|
title: "AI Moderator has deleted this message", |
355 |
|
|
author: { |
356 |
|
|
name: message.author.tag, |
357 |
|
|
iconURL: message.author.displayAvatarURL(), |
358 |
|
|
}, |
359 |
|
|
color: 0xf14a60, |
360 |
|
|
description: message.content, |
361 |
|
|
fields: [ |
362 |
|
|
{ |
363 |
|
|
name: "User ID", |
364 |
|
|
value: message.author.id, |
365 |
|
|
}, |
366 |
|
|
{ |
367 |
|
|
name: "Message Analysis Results", |
368 |
|
|
value: `Toxicity: ${toxicScore}%\nSevere Toxicity: ${severeToxicScore}%\nThreat: ${threatScore}%`, |
369 |
|
|
}, |
370 |
|
|
{ |
371 |
|
|
name: "Reason", |
372 |
|
|
value: `Deleted the message because of the following configuration:\n\`\`\`${conf}\`\`\`` |
373 |
|
|
} |
374 |
|
|
], |
375 |
|
|
footer: { |
376 |
|
|
text: 'Deleted' |
377 |
|
|
} |
378 |
|
|
}) |
379 |
|
|
.setTimestamp(), |
380 |
|
|
], |
381 |
|
|
}); |
382 |
|
|
} |
383 |
|
|
|
384 |
|
|
async onServerBoost(member: GuildMember, level: number) { |
385 |
|
|
const distance = formatDistanceToNowStrict(member.premiumSince!); |
386 |
|
|
|
387 |
|
|
await this.loggingChannelBoosts(member.guild.id)?.send({ |
388 |
|
|
embeds: [ |
389 |
|
|
new MessageEmbed({ |
390 |
|
|
title: "Server Boosted", |
391 |
|
|
author: { |
392 |
|
|
name: member.user.tag, |
393 |
|
|
iconURL: member.user.displayAvatarURL(), |
394 |
|
|
}, |
395 |
|
|
description: `${member.user.toString()} has boosted the server!${level > 0 ? ` The server has reached level **${level}**!` : ""}`, |
396 |
|
|
fields: [ |
397 |
|
|
{ |
398 |
|
|
name: "Boosting Since", |
399 |
|
|
value: `${member.premiumSince!.toUTCString()} (${distance.startsWith("0 second") ? "just now" : distance})`, |
400 |
|
|
}, |
401 |
|
|
], |
402 |
|
|
footer: { |
403 |
|
|
text: "Boosted", |
404 |
|
|
}, |
405 |
|
|
}).setTimestamp(), |
406 |
|
|
], |
407 |
|
|
}); |
408 |
|
|
} |
409 |
|
|
|
410 |
|
|
async onServerUnboost(oldMember: GuildMember, newMember: GuildMember) { |
411 |
|
|
await this.loggingChannelBoosts(oldMember.guild.id)?.send({ |
412 |
|
|
embeds: [ |
413 |
|
|
new MessageEmbed({ |
414 |
|
|
title: "Server Unboosted", |
415 |
|
|
author: { |
416 |
|
|
name: newMember.user.tag, |
417 |
|
|
iconURL: newMember.user.displayAvatarURL(), |
418 |
|
|
}, |
419 |
|
|
description: `${newMember.user.toString()} has unboosted the server.`, |
420 |
|
|
fields: [ |
421 |
|
|
{ |
422 |
|
|
name: "Boosting Since", |
423 |
|
|
value: `${oldMember.premiumSince!.toUTCString()} (${formatDistanceToNowStrict(oldMember.premiumSince!)})`, |
424 |
|
|
}, |
425 |
|
|
], |
426 |
|
|
footer: { |
427 |
|
|
text: "Unboosted", |
428 |
|
|
}, |
429 |
|
|
}) |
430 |
|
|
.setColor("PURPLE") |
431 |
|
|
.setTimestamp(), |
432 |
|
|
], |
433 |
|
|
}); |
434 |
|
|
} |
435 |
|
|
|
436 |
|
|
async onNicknameChange(oldMember: GuildMember, newMember: GuildMember) { |
437 |
|
|
await this.loggingChannel(oldMember.guild.id)?.send({ |
438 |
|
|
embeds: [ |
439 |
|
|
new MessageEmbed({ |
440 |
|
|
title: "Nickname Updated", |
441 |
|
|
author: { |
442 |
|
|
name: oldMember.user.tag, |
443 |
|
|
iconURL: oldMember.user.displayAvatarURL(), |
444 |
|
|
}, |
445 |
|
|
color: 0xf14a60, |
446 |
|
|
fields: [ |
447 |
|
|
{ |
448 |
|
|
name: "Old Nickname", |
449 |
|
|
value: oldMember.nickname ? Util.escapeMarkdown(oldMember.nickname) : "*No nickname was set*", |
450 |
|
|
}, |
451 |
|
|
{ |
452 |
|
|
name: "New Nickname", |
453 |
|
|
value: newMember.nickname ? Util.escapeMarkdown(newMember.nickname) : "*Nickname was removed*", |
454 |
|
|
}, |
455 |
|
|
{ |
456 |
|
|
name: "User ID", |
457 |
|
|
value: newMember.user.id, |
458 |
|
|
}, |
459 |
|
|
], |
460 |
|
|
footer: { |
461 |
|
|
text: "Updated", |
462 |
|
|
}, |
463 |
|
|
}).setTimestamp(), |
464 |
|
|
], |
465 |
|
|
}); |
466 |
|
|
} |
467 |
|
|
|
468 |
|
|
async onMessageUpdate(oldMessage: Message, newMessage: Message) { |
469 |
|
|
const row = new MessageActionRow().addComponents(new MessageButton().setLabel("Go to context").setStyle("LINK").setURL(newMessage.url)); |
470 |
|
|
|
471 |
|
|
if (newMessage.type === "REPLY") { |
472 |
|
|
row.addComponents( |
473 |
|
|
new MessageButton() |
474 |
|
|
.setLabel("Go to referenced message") |
475 |
|
|
.setStyle("LINK") |
476 |
|
|
.setURL(`https://discord.com/channels/${newMessage.guildId!}/${newMessage.channelId!}/${newMessage.reference!.messageId}`) |
477 |
|
|
); |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
await this.loggingChannel(newMessage.guild!.id)?.send({ |
481 |
|
|
embeds: [ |
482 |
|
|
new MessageEmbed({ |
483 |
|
|
title: "Message Updated", |
484 |
|
|
author: { |
485 |
|
|
name: oldMessage.author.tag, |
486 |
|
|
iconURL: oldMessage.author.displayAvatarURL(), |
487 |
|
|
}, |
488 |
|
|
description: "**-+-+Before**\n" + oldMessage.content + "\n\n**-+-+After**\n" + newMessage.content, |
489 |
|
|
fields: [ |
490 |
|
|
{ |
491 |
|
|
name: "Message ID", |
492 |
|
|
value: newMessage.id, |
493 |
|
|
}, |
494 |
|
|
{ |
495 |
|
|
name: "User ID", |
496 |
|
|
value: oldMessage.author.id, |
497 |
|
|
}, |
498 |
|
|
{ |
499 |
|
|
name: "Channel", |
500 |
|
|
value: `${oldMessage.channel} (${oldMessage.channelId})`, |
501 |
|
|
}, |
502 |
|
|
], |
503 |
|
|
footer: { |
504 |
|
|
text: `Updated • ${newMessage.id}`, |
505 |
|
|
}, |
506 |
|
|
}), |
507 |
|
|
], |
508 |
|
|
components: [row], |
509 |
|
|
}); |
510 |
|
|
} |
511 |
|
|
|
512 |
|
|
async onMessageDelete(message: Message) { |
513 |
|
|
const embed = new MessageEmbed({ |
514 |
|
|
title: "Message Deleted", |
515 |
|
|
color: 0xf14a60, |
516 |
|
|
author: { |
517 |
|
|
name: message.author.tag, |
518 |
|
|
iconURL: message.author.displayAvatarURL(), |
519 |
|
|
}, |
520 |
|
|
description: message.content, |
521 |
|
|
fields: [ |
522 |
|
|
{ |
523 |
|
|
name: "Message ID", |
524 |
|
|
value: message.id, |
525 |
|
|
}, |
526 |
|
|
{ |
527 |
|
|
name: "User ID", |
528 |
|
|
value: message.author.id, |
529 |
|
|
}, |
530 |
|
|
{ |
531 |
|
|
name: "Channel", |
532 |
|
|
value: `${message.channel} (${message.channelId})`, |
533 |
|
|
}, |
534 |
|
|
], |
535 |
|
|
footer: { |
536 |
|
|
text: `Deleted • ${message.id}`, |
537 |
|
|
}, |
538 |
|
|
}); |
539 |
|
|
|
540 |
|
|
const files: FileOptions[] = []; |
541 |
|
|
|
542 |
|
|
if (message.attachments.size > 0) { |
543 |
|
|
let str = ""; |
544 |
|
|
|
545 |
|
|
message.attachments.forEach((a) => { |
546 |
|
|
str += `${a.name}\n`; |
547 |
|
|
files.push({ |
548 |
|
|
name: a.name!, |
549 |
|
|
attachment: a.proxyURL, |
550 |
|
|
}); |
551 |
|
|
}); |
552 |
|
|
|
553 |
|
|
embed.addFields({ |
554 |
|
|
name: "Attachments (top)", |
555 |
|
|
value: str, |
556 |
|
|
}); |
557 |
|
|
} |
558 |
|
|
|
559 |
|
|
const row = new MessageActionRow().addComponents(new MessageButton().setLabel("Go to context").setStyle("LINK").setURL(message.url)); |
560 |
|
|
|
561 |
|
|
if (message.type === "REPLY") { |
562 |
|
|
row.addComponents( |
563 |
|
|
new MessageButton() |
564 |
|
|
.setLabel("Go to referenced message") |
565 |
|
|
.setStyle("LINK") |
566 |
|
|
.setURL(`https://discord.com/channels/${message.guildId!}/${message.channelId!}/${message.reference!.messageId}`) |
567 |
|
|
); |
568 |
|
|
} |
569 |
|
|
|
570 |
|
|
await this.loggingChannel(message.guild!.id)?.send({ |
571 |
|
|
embeds: [embed], |
572 |
|
|
components: [row], |
573 |
|
|
files, |
574 |
|
|
}); |
575 |
|
|
} |
576 |
|
|
|
577 |
|
|
async onGuildBanAdd(ban: GuildBan, _executor?: User, id?: string | number) { |
578 |
|
|
const auditLog = ( |
579 |
|
|
await ban.guild.fetchAuditLogs({ |
580 |
|
|
limit: 1, |
581 |
|
|
type: "MEMBER_BAN_ADD", |
582 |
|
|
}) |
583 |
|
|
).entries.first(); |
584 |
|
|
|
585 |
|
|
const executor = _executor ?? auditLog?.executor; |
586 |
|
|
|
587 |
|
|
if (executor?.id === this.client.user!.id) { |
588 |
|
|
console.log("Action taken by bot"); |
589 |
|
|
return; |
590 |
|
|
} |
591 |
|
|
|
592 |
|
|
const guildBan = await ban.guild.bans.fetch(ban.user.id); |
593 |
|
|
const reason = ban.reason ?? guildBan.reason ?? "*No reason provided*"; |
594 |
|
|
|
595 |
|
|
await this.loggingChannel(ban.guild.id)?.send({ |
596 |
|
|
embeds: [ |
597 |
|
|
new MessageEmbed() |
598 |
|
|
.setColor("#f14a60") |
599 |
|
|
.setTitle("A user was banned") |
600 |
|
|
.setAuthor({ |
601 |
|
|
name: guildBan.user.tag, |
602 |
|
|
iconURL: guildBan.user.displayAvatarURL(), |
603 |
|
|
}) |
604 |
|
|
.addField("Reason", reason) |
605 |
|
|
.addField("User ID", guildBan.user.id) |
606 |
|
|
.addFields( |
607 |
|
|
{ |
608 |
|
|
name: "Banned by", |
609 |
|
|
value: executor ? `${executor.tag} (${executor.id})` : "Unknown", |
610 |
|
|
}, |
611 |
|
|
{ |
612 |
|
|
name: "Infraction ID", |
613 |
|
|
value: id?.toString() ?? "*Unavailable*", |
614 |
|
|
} |
615 |
|
|
) |
616 |
|
|
.setFooter({ |
617 |
|
|
text: "Banned", |
618 |
|
|
}), |
619 |
|
|
], |
620 |
|
|
}); |
621 |
|
|
} |
622 |
|
|
|
623 |
|
|
async onGuildBanRemove(ban: GuildBan, _executor?: User) { |
624 |
|
|
const auditLog = ( |
625 |
|
|
await ban.guild.fetchAuditLogs({ |
626 |
|
|
limit: 1, |
627 |
|
|
type: "MEMBER_BAN_REMOVE", |
628 |
|
|
}) |
629 |
|
|
).entries.first(); |
630 |
|
|
|
631 |
|
|
const executor = _executor ?? auditLog?.executor; |
632 |
|
|
|
633 |
|
|
await this.loggingChannel(ban.guild.id)?.send({ |
634 |
|
|
embeds: [ |
635 |
|
|
new MessageEmbed() |
636 |
|
|
.setColor("#f14a60") |
637 |
|
|
.setTitle("A user was unbanned") |
638 |
|
|
.setAuthor({ |
639 |
|
|
name: ban.user.tag, |
640 |
|
|
iconURL: ban.user.displayAvatarURL(), |
641 |
|
|
}) |
642 |
|
|
.addField("User ID", ban.user.id) |
643 |
|
|
.addFields({ |
644 |
|
|
name: "Unbanned By", |
645 |
|
|
value: executor ? `${executor.tag} (${executor.id})` : "Unknown", |
646 |
|
|
}) |
647 |
|
|
.setFooter({ |
648 |
|
|
text: "Unbanned", |
649 |
|
|
}) |
650 |
|
|
.setTimestamp(), |
651 |
|
|
], |
652 |
|
|
}); |
653 |
|
|
} |
654 |
|
|
|
655 |
|
|
async onSoftban(banOptions: BanOptions, guild: Guild, user: User, model: IPunishment) { |
656 |
|
|
let r = banOptions.reason ?? "*No reason provided*"; |
657 |
|
|
|
658 |
|
|
await this.loggingChannel(guild.id)?.send({ |
659 |
|
|
embeds: [ |
660 |
|
|
new MessageEmbed() |
661 |
|
|
.setColor("#f14a60") |
662 |
|
|
.setTitle("A user was softbanned") |
663 |
|
|
.setAuthor({ |
664 |
|
|
name: user.tag, |
665 |
|
|
iconURL: user.displayAvatarURL(), |
666 |
|
|
}) |
667 |
|
|
.addField("Reason", r) |
668 |
|
|
.addField("Softbanned by", `${model.mod_tag} (${model.mod_id})`) |
669 |
|
|
.addField("User ID", user.id) |
670 |
|
|
.addFields({ |
671 |
|
|
name: "Case ID", |
672 |
|
|
value: model.numericId + "", |
673 |
|
|
}) |
674 |
|
|
.setFooter({ |
675 |
|
|
text: "Softbanned", |
676 |
|
|
}) |
677 |
|
|
.setTimestamp(), |
678 |
|
|
], |
679 |
|
|
}); |
680 |
|
|
} |
681 |
|
|
|
682 |
|
|
async onTempBan(banOptions: BanOptions, guild: Guild, user: User, model: IPunishment) { |
683 |
|
|
let r = banOptions.reason ?? "*No reason provided*"; |
684 |
|
|
|
685 |
|
|
await this.loggingChannel(guild.id)?.send({ |
686 |
|
|
embeds: [ |
687 |
|
|
new MessageEmbed() |
688 |
|
|
.setColor("#f14a60") |
689 |
|
|
.setTitle("A user was temporarily banned") |
690 |
|
|
.setAuthor({ |
691 |
|
|
name: user.tag, |
692 |
|
|
iconURL: user.displayAvatarURL(), |
693 |
|
|
}) |
694 |
|
|
.addField("Reason", r) |
695 |
|
|
.addField("Banned by", `${model.mod_tag} (${model.mod_id})`) |
696 |
|
|
.addField("User ID", user.id) |
697 |
|
|
.addField("Duration", ms((model.meta as any).time)) |
698 |
|
|
.addFields({ |
699 |
|
|
name: "Case ID", |
700 |
|
|
value: model.numericId + "", |
701 |
|
|
}) |
702 |
|
|
.setFooter({ |
703 |
|
|
text: "Temporarily banned", |
704 |
|
|
}) |
705 |
|
|
.setTimestamp(), |
706 |
|
|
], |
707 |
|
|
}); |
708 |
|
|
} |
709 |
|
|
|
710 |
|
|
async onGuildMemberAdd(member: GuildMember, info?: IGuildInfo) { |
711 |
|
|
let members = 0, |
712 |
|
|
bots = 0; |
713 |
|
|
|
714 |
|
|
for (const m of member.guild!.members.cache.values()) { |
715 |
|
|
if (m.user.bot) bots++; |
716 |
|
|
else members++; |
717 |
|
|
} |
718 |
|
|
|
719 |
|
|
const invite = member.user.bot ? null : await this.client.inviteTracker.getInviteInfo(member); |
720 |
|
|
|
721 |
|
|
await this.loggingChannelJoinLeave(member.guild.id)?.send({ |
722 |
|
|
embeds: [ |
723 |
|
|
new MessageEmbed() |
724 |
|
|
.setColor("#007bff") |
725 |
|
|
.setTitle("New member joined") |
726 |
|
|
.setAuthor({ |
727 |
|
|
name: member.user.tag, |
728 |
|
|
iconURL: member.user.displayAvatarURL(), |
729 |
|
|
}) |
730 |
|
|
.setDescription(`<@${member.user.id}> just joined the server! Their position is ${members + bots}th.`) |
731 |
|
|
.addField("Account Created", `${member.user.createdAt.toLocaleString()} (${timeSince(member.user.createdAt.getTime())})`) |
732 |
|
|
.addField( |
733 |
|
|
"New Account?", |
734 |
|
|
new Date().getTime() - member.user.createdAt.getTime() <= 3 * 24 * 60 * 60 * 1000 ? ":warning: Yes :warning:" : "No" |
735 |
|
|
) |
736 |
|
|
.addField("Bot?", member.user.bot === true ? "Yes" : "No") |
737 |
|
|
.addField("User ID", member.user.id) |
738 |
|
|
.addFields( |
739 |
|
|
{ |
740 |
|
|
name: "Total Members Joined", |
741 |
|
|
value: info?.totalMembersJoined?.toString() ?? "*Information unavailable*", |
742 |
|
|
}, |
743 |
|
|
{ |
744 |
|
|
name: "Positions", |
745 |
|
|
value: `Among All members: ${members + bots}th\n${ |
746 |
|
|
member.user.bot ? `Among bots: ${bots}th` : `Among human members: ${members}th` |
747 |
|
|
}`, |
748 |
|
|
}, |
749 |
|
|
{ |
750 |
|
|
name: "Invite Information", |
751 |
|
|
value: invite |
752 |
|
|
? `Inviter: ${invite.inviter ?? "*Unavailable*"}\nInvite URL: [https://discord.gg/${ |
753 |
|
|
invite.code |
754 |
|
|
}](https://discord.gg/${invite.code})` |
755 |
|
|
: "*Unavailable*", |
756 |
|
|
} |
757 |
|
|
) |
758 |
|
|
.setFooter({ |
759 |
|
|
text: `Joined • ${members + bots} members total`, |
760 |
|
|
}) |
761 |
|
|
.setTimestamp(), |
762 |
|
|
], |
763 |
|
|
}); |
764 |
|
|
} |
765 |
|
|
|
766 |
|
|
async onGuildMemberRemove(member: GuildMember) { |
767 |
|
|
const roles = member.roles.cache.filter((role) => role.id !== member.guild.id).reduce((acc, val) => ` ${acc} ${roleMention(val.id)}`, ""); |
768 |
|
|
|
769 |
|
|
await this.loggingChannelJoinLeave(member.guild.id)?.send({ |
770 |
|
|
embeds: [ |
771 |
|
|
new MessageEmbed() |
772 |
|
|
.setColor("#f14a60") |
773 |
|
|
.setTitle("Member left") |
774 |
|
|
.setAuthor({ |
775 |
|
|
name: member.user.tag, |
776 |
|
|
iconURL: member.user.displayAvatarURL(), |
777 |
|
|
}) |
778 |
|
|
.setDescription(`**Roles**\n${roles}`) |
779 |
|
|
.addField("Joined at", `${member.joinedAt!.toLocaleString()} (${timeSince(member.joinedAt!.getTime())})`) |
780 |
|
|
.addField("User ID", member.user.id) |
781 |
|
|
.addField("Bot?", member.user.bot === true ? "Yes" : "No") |
782 |
|
|
.setFooter({ |
783 |
|
|
text: `Left • ${member.guild.memberCount} members total`, |
784 |
|
|
}) |
785 |
|
|
.setTimestamp(), |
786 |
|
|
], |
787 |
|
|
}); |
788 |
|
|
} |
789 |
|
|
|
790 |
|
|
async onMemberShot(member: GuildMember, moderator: User, reason?: string, id?: string) { |
791 |
|
|
await this.loggingChannel(member.guild.id)?.send({ |
792 |
|
|
embeds: [ |
793 |
|
|
new MessageEmbed() |
794 |
|
|
.setColor("#007bff") |
795 |
|
|
.setTitle("Member got shot") |
796 |
|
|
.setAuthor({ |
797 |
|
|
name: member.user.tag, |
798 |
|
|
iconURL: member.user.displayAvatarURL(), |
799 |
|
|
}) |
800 |
|
|
.addField("Reason", reason ?? "*No reason provided*") |
801 |
|
|
.addField("Doctor 💉", moderator.tag) |
802 |
|
|
.addField("User ID", member.user.id) |
803 |
|
|
.addFields({ |
804 |
|
|
name: "Infraction ID", |
805 |
|
|
value: id ?? "*Unavailable*", |
806 |
|
|
}) |
807 |
|
|
.setFooter({ |
808 |
|
|
text: "Shot delivered", |
809 |
|
|
}) |
810 |
|
|
.setTimestamp(), |
811 |
|
|
], |
812 |
|
|
}); |
813 |
|
|
} |
814 |
|
|
|
815 |
|
|
async onMemberKick(member: GuildMember, reason?: string, executor?: User, id?: string) { |
816 |
|
|
await this.loggingChannel(member.guild.id)?.send({ |
817 |
|
|
embeds: [ |
818 |
|
|
new MessageEmbed({ |
819 |
|
|
author: { |
820 |
|
|
name: member.user.tag, |
821 |
|
|
iconURL: member.user.displayAvatarURL(), |
822 |
|
|
}, |
823 |
|
|
title: "Member Kicked", |
824 |
|
|
description: "This user has left the server, probably due to a kick.", |
825 |
|
|
fields: [ |
826 |
|
|
{ |
827 |
|
|
name: "Kicked by", |
828 |
|
|
value: executor?.tag ?? "Unknown", |
829 |
|
|
}, |
830 |
|
|
{ |
831 |
|
|
name: "Reason", |
832 |
|
|
value: reason ?? "*No reason provided*", |
833 |
|
|
}, |
834 |
|
|
{ |
835 |
|
|
name: "Infraction ID", |
836 |
|
|
value: id ?? "*Unavailable*", |
837 |
|
|
}, |
838 |
|
|
], |
839 |
|
|
footer: { |
840 |
|
|
text: "Kicked", |
841 |
|
|
}, |
842 |
|
|
}).setTimestamp(), |
843 |
|
|
], |
844 |
|
|
}); |
845 |
|
|
} |
846 |
|
|
|
847 |
|
|
async onMemberMute(member: GuildMember, duration?: number, reason?: string, executor?: User, hard = false, id?: string) { |
848 |
|
|
await this.loggingChannel(member.guild.id)?.send({ |
849 |
|
|
embeds: [ |
850 |
|
|
new MessageEmbed() |
851 |
|
|
.setColor("#f14a60") |
852 |
|
|
.setTitle("Member muted") |
853 |
|
|
.setAuthor({ |
854 |
|
|
name: member.user.tag, |
855 |
|
|
iconURL: member.user.displayAvatarURL(), |
856 |
|
|
}) |
857 |
|
|
.addField("Reason", reason ?? "*No reason provided*") |
858 |
|
|
.addField("Muted by", executor?.tag ?? "Unknown") |
859 |
|
|
.addField( |
860 |
|
|
"Duration Until", |
861 |
|
|
duration |
862 |
|
|
? `${new Date(Date.now() + duration).toLocaleString()} (${formatDuration( |
863 |
|
|
intervalToDuration({ start: 0, end: duration }) |
864 |
|
|
)})` |
865 |
|
|
: "*No duration set*" |
866 |
|
|
) |
867 |
|
|
.addField("User ID", member.user.id) |
868 |
|
|
.addField("Hardmute", hard ? "Yes" : "No") |
869 |
|
|
.addFields({ |
870 |
|
|
name: "Infraction ID", |
871 |
|
|
value: id ?? "*Unavailable*", |
872 |
|
|
}) |
873 |
|
|
.setFooter({ |
874 |
|
|
text: "Muted", |
875 |
|
|
}) |
876 |
|
|
.setTimestamp(), |
877 |
|
|
], |
878 |
|
|
}); |
879 |
|
|
} |
880 |
|
|
|
881 |
|
|
async onMemberUnmute(member: GuildMember, executor?: User) { |
882 |
|
|
await this.loggingChannel(member.guild.id)?.send({ |
883 |
|
|
embeds: [ |
884 |
|
|
new MessageEmbed() |
885 |
|
|
.setColor("#007bff") |
886 |
|
|
.setTitle("Member unmuted") |
887 |
|
|
.setAuthor({ |
888 |
|
|
name: member.user.tag, |
889 |
|
|
iconURL: member.user.displayAvatarURL(), |
890 |
|
|
}) |
891 |
|
|
.addField("Unmuted by", executor?.tag ?? "Unknown") |
892 |
|
|
.addField("User ID", member.user.id) |
893 |
|
|
.setFooter({ |
894 |
|
|
text: "Unmuted", |
895 |
|
|
}) |
896 |
|
|
.setTimestamp(), |
897 |
|
|
], |
898 |
|
|
}); |
899 |
|
|
} |
900 |
|
|
|
901 |
|
|
async onMemberWarn(user: User, guildID: string, id: string, reason?: string, moderator?: User) { |
902 |
|
|
await this.loggingChannel(guildID)?.send({ |
903 |
|
|
embeds: [ |
904 |
|
|
new MessageEmbed() |
905 |
|
|
.setColor("GOLD") |
906 |
|
|
.setTitle("Member warned") |
907 |
|
|
.setAuthor({ |
908 |
|
|
name: user.tag, |
909 |
|
|
iconURL: user.displayAvatarURL(), |
910 |
|
|
}) |
911 |
|
|
.addField("Reason", reason ?? "*No reason provided*") |
912 |
|
|
.addField("Warned by", moderator?.tag ?? "*No reason provided*") |
913 |
|
|
.addField("User ID", user.id) |
914 |
|
|
.addField("Infraction ID", id + "") |
915 |
|
|
.setFooter({ |
916 |
|
|
text: "Warned", |
917 |
|
|
}) |
918 |
|
|
.setTimestamp(), |
919 |
|
|
], |
920 |
|
|
}); |
921 |
|
|
} |
922 |
|
|
|
923 |
|
|
async onMemberWarningDelete(member: GuildMember, id: string, reason?: string, moderator?: User) { |
924 |
|
|
await this.loggingChannel(member.guild.id)?.send({ |
925 |
|
|
embeds: [ |
926 |
|
|
new MessageEmbed() |
927 |
|
|
.setColor("GOLD") |
928 |
|
|
.setTitle("Warning deleted") |
929 |
|
|
.setAuthor({ |
930 |
|
|
name: member.user.tag, |
931 |
|
|
iconURL: member.user.displayAvatarURL(), |
932 |
|
|
}) |
933 |
|
|
.addField("Warned by", moderator?.tag ?? "Unknown") |
934 |
|
|
.addField("Infraction ID", id + "") |
935 |
|
|
.addField("User ID", member.user.id) |
936 |
|
|
.setFooter({ |
937 |
|
|
text: "Warning Deleted", |
938 |
|
|
}) |
939 |
|
|
.setTimestamp(), |
940 |
|
|
], |
941 |
|
|
}); |
942 |
|
|
} |
943 |
|
|
|
944 |
|
|
async onMemberUpdate(oldMember: GuildMember, newMember: GuildMember) { |
945 |
|
|
if (oldMember.isCommunicationDisabled() && !newMember.isCommunicationDisabled()) { |
946 |
|
|
setTimeout(async () => { |
947 |
|
|
const auditLog = await newMember.guild.fetchAuditLogs({ |
948 |
|
|
type: "MEMBER_UPDATE", |
949 |
|
|
limit: 1, |
950 |
|
|
}); |
951 |
|
|
|
952 |
|
|
const data = auditLog?.entries.first(); |
953 |
|
|
|
954 |
|
|
console.log(data); |
955 |
|
|
|
956 |
|
|
Punishment.create({ |
957 |
|
|
createdAt: new Date(), |
958 |
|
|
guild_id: newMember.guild.id, |
959 |
|
|
mod_id: data?.executor?.id, |
960 |
|
|
mod_tag: data?.executor?.tag, |
961 |
|
|
user_id: newMember.user.id, |
962 |
|
|
type: PunishmentType.TIMEOUT_REMOVE, |
963 |
|
|
}).catch(console.error); |
964 |
|
|
|
965 |
|
|
await this.loggingChannel(newMember.guild.id)?.send({ |
966 |
|
|
embeds: [ |
967 |
|
|
new MessageEmbed() |
968 |
|
|
.setColor("GOLD") |
969 |
|
|
.setTitle("Member Timeout Removed") |
970 |
|
|
.setAuthor({ |
971 |
|
|
name: newMember.user.tag, |
972 |
|
|
iconURL: newMember.user.displayAvatarURL(), |
973 |
|
|
}) |
974 |
|
|
.addField( |
975 |
|
|
"Removed by", |
976 |
|
|
data?.target?.id === newMember.user.id && data?.executor?.tag |
977 |
|
|
? `${data?.executor?.tag} (${data?.executor?.id})` |
978 |
|
|
: "*Timeout expired automatically*" |
979 |
|
|
) |
980 |
|
|
.addField("User ID", oldMember.user.id) |
981 |
|
|
.setFooter({ |
982 |
|
|
text: "Timeout Removed", |
983 |
|
|
}) |
984 |
|
|
.setTimestamp(), |
985 |
|
|
], |
986 |
|
|
}); |
987 |
|
|
}, 2000); |
988 |
|
|
} else if (!oldMember.isCommunicationDisabled() && newMember.isCommunicationDisabled()) { |
989 |
|
|
setTimeout(async () => { |
990 |
|
|
const auditLog = await newMember.guild.fetchAuditLogs({ |
991 |
|
|
type: "MEMBER_UPDATE", |
992 |
|
|
limit: 1, |
993 |
|
|
}); |
994 |
|
|
|
995 |
|
|
const data = auditLog?.entries.first(); |
996 |
|
|
|
997 |
|
|
console.log(data); |
998 |
|
|
|
999 |
|
|
Punishment.create({ |
1000 |
|
|
createdAt: new Date(), |
1001 |
|
|
guild_id: newMember.guild.id, |
1002 |
|
|
mod_id: data?.executor?.id, |
1003 |
|
|
mod_tag: data?.executor?.tag, |
1004 |
|
|
reason: data?.reason, |
1005 |
|
|
user_id: newMember.user.id, |
1006 |
|
|
type: PunishmentType.TIMEOUT, |
1007 |
|
|
meta: { |
1008 |
|
|
time: ms(newMember.communicationDisabledUntilTimestamp - Date.now()), |
1009 |
|
|
}, |
1010 |
|
|
}).catch(console.error); |
1011 |
|
|
|
1012 |
|
|
await this.loggingChannel(newMember.guild.id)?.send({ |
1013 |
|
|
embeds: [ |
1014 |
|
|
new MessageEmbed() |
1015 |
|
|
.setColor("#f14a60") |
1016 |
|
|
.setTitle("Member Timed Out") |
1017 |
|
|
.setAuthor({ |
1018 |
|
|
name: newMember.user.tag, |
1019 |
|
|
iconURL: newMember.user.displayAvatarURL(), |
1020 |
|
|
}) |
1021 |
|
|
.addFields( |
1022 |
|
|
{ |
1023 |
|
|
name: "Reason", |
1024 |
|
|
value: data?.reason ?? "*No reason provided*", |
1025 |
|
|
}, |
1026 |
|
|
{ |
1027 |
|
|
name: "Duration", |
1028 |
|
|
value: newMember.communicationDisabledUntil |
1029 |
|
|
? `${newMember.communicationDisabledUntil.toUTCString()} (${formatDistanceStrict( |
1030 |
|
|
newMember.communicationDisabledUntil, |
1031 |
|
|
new Date() |
1032 |
|
|
)})` |
1033 |
|
|
: "Unknown", |
1034 |
|
|
} |
1035 |
|
|
) |
1036 |
|
|
.addField( |
1037 |
|
|
"Action taken by", |
1038 |
|
|
data?.target?.id === newMember.user.id && data?.executor?.tag |
1039 |
|
|
? `${data?.executor?.tag} (${data?.executor?.id})` |
1040 |
|
|
: "Unknown" |
1041 |
|
|
) |
1042 |
|
|
.addField("User ID", oldMember.user.id) |
1043 |
|
|
.setFooter({ |
1044 |
|
|
text: "Timed-out", |
1045 |
|
|
}) |
1046 |
|
|
.setTimestamp(), |
1047 |
|
|
], |
1048 |
|
|
}); |
1049 |
|
|
}, 2000); |
1050 |
|
|
} |
1051 |
|
|
} |
1052 |
|
|
} |