mirror of
https://github.com/nx-bat/discordbot-ng.git
synced 2026-11-11 07:13:37 -05:00
[Events] Events become classes with typings. (#19)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { APIEmbedField, APIRole, AuditLogEvent, Guild, GuildAuditLogsEntry, RoleFlags, SnowflakeUtil } from 'discord.js';
|
||||
import { APIEmbedField, APIRole, AuditLogEvent, Client, Guild, GuildAuditLogsEntry, RoleFlags, SnowflakeUtil } from 'discord.js';
|
||||
import { Database } from '../../shared/Database';
|
||||
import { Event } from '../../types';
|
||||
import { CreateDefaultEmbed, formatChanges, formatExtras, formatSnowflake, getTargetType } from '../../utils';
|
||||
|
||||
const IGNORED_ACTIONS = [
|
||||
@@ -33,10 +34,10 @@ async function shouldLogRoleChanges(entry: GuildAuditLogsEntry<AuditLogEvent.Mem
|
||||
return false;
|
||||
}
|
||||
|
||||
export default {
|
||||
event: 'guildAuditLogEntryCreate',
|
||||
class GuildAuditLogEntryCreateEvent implements Event<Client, 'guildAuditLogEntryCreate'> {
|
||||
event = 'guildAuditLogEntryCreate' as const;
|
||||
|
||||
handler: async (entry: GuildAuditLogsEntry, guild: Guild) => {
|
||||
async execute(context: Client, entry: GuildAuditLogsEntry, guild: Guild): Promise<void> {
|
||||
if (!await shouldLog(entry, guild)) return;
|
||||
|
||||
const settings = await Database.getOrCreateSettings(guild.id);
|
||||
@@ -95,4 +96,6 @@ export default {
|
||||
}]
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new GuildAuditLogEntryCreateEvent();
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { GuildBan } from 'discord.js';
|
||||
import { Client, GuildBan } from 'discord.js';
|
||||
import { Database } from '../../shared/Database';
|
||||
import { Event } from '../../types';
|
||||
|
||||
export default {
|
||||
event: 'guildBanRemove',
|
||||
class GuildBanRemoveEvent implements Event<Client, 'guildBanRemove'> {
|
||||
event = 'guildBanRemove' as const;
|
||||
|
||||
handler: async (ban: GuildBan) => {
|
||||
async execute(context: Client<boolean>, ban: GuildBan): Promise<void> {
|
||||
await Database.removeBan(ban.user.id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new GuildBanRemoveEvent();
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { Guild } from 'discord.js';
|
||||
import { Client, Guild } from 'discord.js';
|
||||
import { Database } from '../../shared/Database';
|
||||
import { Event } from '../../types';
|
||||
|
||||
export default {
|
||||
event: 'guildCreate',
|
||||
class GuildCreateEvent implements Event<Client, 'guildCreate'> {
|
||||
event = 'guildCreate' as const;
|
||||
|
||||
handler: async (guild: Guild) => {
|
||||
async execute(context: Client<boolean>, guild: Guild): Promise<void> {
|
||||
await Database.getOrCreateSettings(guild.id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new GuildCreateEvent();
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
import { GuildMember, GuildTextBasedChannel } from 'discord.js';
|
||||
import { Client, GuildMember, GuildTextBasedChannel } from 'discord.js';
|
||||
import { Database } from '../../shared/Database';
|
||||
import { Event } from '../../types';
|
||||
import { getE621Alts } from '../../utils';
|
||||
|
||||
export default {
|
||||
event: 'guildMemberAdd',
|
||||
class GuildMemberAddEvent implements Event<Client, 'guildMemberAdd'> {
|
||||
event = 'guildMemberAdd' as const;
|
||||
|
||||
handler: async (member: GuildMember) => {
|
||||
async execute(context: Client<boolean>, member: GuildMember): Promise<void> {
|
||||
const settings = await Database.getOrCreateSettings(member.guild.id);
|
||||
if (!settings.new_member_channel_id) return;
|
||||
|
||||
if (settings.new_member_channel_id) {
|
||||
const channel = await member.guild.channels.fetch(settings.new_member_channel_id) as GuildTextBasedChannel;
|
||||
const channel = await member.guild.channels.fetch(settings.new_member_channel_id) as GuildTextBasedChannel;
|
||||
if (!channel) return;
|
||||
|
||||
if (channel) {
|
||||
const content = `${member.toString()}'s (${member.id}) e621 and discord account(s):\n${await getE621Alts(member.id, member.guild)}`;
|
||||
const content = `${member.toString()}'s (${member.id}) e621 and discord account(s):\n${await getE621Alts(member.id, member.guild)}`;
|
||||
channel.send(content).catch(console.error);
|
||||
|
||||
channel.send(content).catch(console.error);
|
||||
|
||||
if (settings.moderator_channel_id && content.includes('[BANNED]')) {
|
||||
const modChannel = await member.guild.channels.fetch(settings.moderator_channel_id) as GuildTextBasedChannel;
|
||||
|
||||
if (modChannel) modChannel.send(`Member joined with banned alts:\n${content}`).catch(console.error);
|
||||
}
|
||||
}
|
||||
if (settings.moderator_channel_id && content.includes('[BANNED]')) {
|
||||
const modChannel = await member.guild.channels.fetch(settings.moderator_channel_id) as GuildTextBasedChannel;
|
||||
if (modChannel) modChannel.send(`Member joined with banned alts:\n${content}`).catch(console.error);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new GuildMemberAddEvent();
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { Client } from 'discord.js';
|
||||
import { config } from '../../config';
|
||||
import { Database } from '../../shared/Database';
|
||||
import { Event } from '../../types';
|
||||
import { ALLOWED_MIMETYPES, blacklistIfNecessary, calculateMD5FromURL, getE621PostByMd5, getPostUrl, md5Regex, Message, regexTesters, uniqueRegexMatches } from '../../utils';
|
||||
|
||||
export default {
|
||||
event: 'messageCreate',
|
||||
class MessageCreateEvent implements Event<Client, 'messageCreate'> {
|
||||
event = 'messageCreate' as const;
|
||||
|
||||
handler: async (message: Message) => {
|
||||
async execute(context: Client<boolean>, message: Message): Promise<void> {
|
||||
if (message.author.bot) return;
|
||||
if (message.inGuild()) await Database.putMessage(message);
|
||||
|
||||
@@ -66,4 +68,6 @@ export default {
|
||||
await message.reply(responses.join('\n'));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new MessageCreateEvent();
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Message, PartialMessage } from 'discord.js';
|
||||
import { Client, Message, PartialMessage } from 'discord.js';
|
||||
import { Database } from '../../shared/Database';
|
||||
import { Event } from '../../types';
|
||||
import { logDeletion } from '../../utils';
|
||||
|
||||
export default {
|
||||
event: 'messageDelete',
|
||||
class MessageDeleteEvent implements Event<Client, 'messageDelete'> {
|
||||
event = 'messageDelete' as const;
|
||||
|
||||
handler: async (message: Message | PartialMessage) => {
|
||||
async execute(context: Client<boolean>, message: Message | PartialMessage): Promise<void> {
|
||||
const loggedMessage = await Database.getMessageWithRetry(message.id);
|
||||
if (!loggedMessage) return;
|
||||
|
||||
@@ -13,4 +14,6 @@ export default {
|
||||
|
||||
if (message.inGuild()) await logDeletion(loggedMessage, message);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new MessageDeleteEvent();
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import { GuildTextBasedChannel, Message, OmitPartialGroupDMChannel, PartialMessage, ReadonlyCollection } from 'discord.js';
|
||||
import { Client, GuildTextBasedChannel, Message, OmitPartialGroupDMChannel, PartialMessage, ReadonlyCollection } from 'discord.js';
|
||||
import { Database } from '../../shared/Database';
|
||||
import { Event } from '../../types';
|
||||
import { logDeletion } from '../../utils';
|
||||
|
||||
export default {
|
||||
event: 'messageDeleteBulk',
|
||||
class MessageDeleteBulkEvent implements Event<Client, 'messageDeleteBulk'> {
|
||||
event = 'messageDeleteBulk' as const;
|
||||
|
||||
handler: async (messages: ReadonlyCollection<string, Message | OmitPartialGroupDMChannel<PartialMessage>>, channel: GuildTextBasedChannel) => {
|
||||
async execute(context: Client<boolean>, messages: ReadonlyCollection<string, Message | OmitPartialGroupDMChannel<PartialMessage>>, channel: GuildTextBasedChannel): Promise<void> {
|
||||
for (const message of messages.values()) {
|
||||
const loggedMessage = await Database.getMessageWithRetry(message.id);
|
||||
if (!loggedMessage) continue;
|
||||
|
||||
await Database.removeMessge(message.id);
|
||||
|
||||
if (message.inGuild()) await logDeletion(loggedMessage, message);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new MessageDeleteBulkEvent();
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { PartialMessage } from 'discord.js';
|
||||
import { Client, PartialMessage } from 'discord.js';
|
||||
import { config } from '../../config';
|
||||
import { Database } from '../../shared/Database';
|
||||
import { Event } from '../../types';
|
||||
import { isEdited, logEdit, Message, regexTesters, uniqueRegexMatches } from '../../utils';
|
||||
|
||||
export default {
|
||||
event: 'messageUpdate',
|
||||
class MessageUpdateEvent implements Event<Client, 'messageUpdate'> {
|
||||
event = 'messageUpdate' as const;
|
||||
|
||||
handler: async (oldMessage: Message | PartialMessage, newMessage: Message) => {
|
||||
async execute(context: Client<boolean>, oldMessage: Message | PartialMessage, newMessage: Message): Promise<void> {
|
||||
if (newMessage.author.bot) return;
|
||||
|
||||
const loggedMessage = await Database.getMessageWithRetry(newMessage.id);
|
||||
@@ -31,39 +32,35 @@ export default {
|
||||
const hasMatches = test.regex.test(newMessage.content);
|
||||
test.regex.lastIndex = 0;
|
||||
|
||||
if (hasMatches) {
|
||||
const oldMatches: RegExpExecArray[] = [];
|
||||
const newMatches: RegExpExecArray[] = [];
|
||||
let match: RegExpExecArray | null;
|
||||
if (!hasMatches) continue;
|
||||
|
||||
while ((match = test.regex.exec(newMessage.content)) != null) {
|
||||
newMatches.push(match);
|
||||
}
|
||||
test.regex.lastIndex = 0;
|
||||
const oldMatches: RegExpExecArray[] = [];
|
||||
const newMatches: RegExpExecArray[] = [];
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
while ((match = test.regex.exec(loggedMessage.content)) != null) {
|
||||
oldMatches.push(match);
|
||||
}
|
||||
test.regex.lastIndex = 0;
|
||||
while ((match = test.regex.exec(newMessage.content)) != null) newMatches.push(match);
|
||||
test.regex.lastIndex = 0;
|
||||
|
||||
const properMatches: RegExpExecArray[] = [];
|
||||
while ((match = test.regex.exec(loggedMessage.content)) != null) oldMatches.push(match);
|
||||
test.regex.lastIndex = 0;
|
||||
|
||||
for (const newMatch of newMatches) {
|
||||
if (!oldMatches.find(m => m[1] == newMatch[1])) properMatches.push(newMatch);
|
||||
}
|
||||
const properMatches: RegExpExecArray[] = [];
|
||||
|
||||
if (properMatches.length == 0) continue;
|
||||
|
||||
const response = await test.handler(newMessage, properMatches.filter(uniqueRegexMatches));
|
||||
|
||||
if (response === false) return;
|
||||
|
||||
if (response !== true) responses.push(response as string);
|
||||
for (const newMatch of newMatches) {
|
||||
if (!oldMatches.find(m => m[1] == newMatch[1])) properMatches.push(newMatch);
|
||||
}
|
||||
|
||||
if (properMatches.length == 0) continue;
|
||||
const response = await test.handler(newMessage, properMatches.filter(uniqueRegexMatches));
|
||||
|
||||
if (response === false) return;
|
||||
if (response !== true) responses.push(response as string);
|
||||
}
|
||||
|
||||
if (responses.length > 0) {
|
||||
await newMessage.reply(responses.join('\n'));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new MessageUpdateEvent();
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { AnyThreadChannel } from 'discord.js';
|
||||
import { AnyThreadChannel, Client } from 'discord.js';
|
||||
import { Event } from '../../types';
|
||||
|
||||
export default {
|
||||
event: 'threadCreate',
|
||||
class ThreadCreateEvent implements Event<Client, 'threadCreate'> {
|
||||
event = 'threadCreate' as const;
|
||||
|
||||
handler: async (thread: AnyThreadChannel, newlyCreated: boolean) => {
|
||||
async execute(context: Client<boolean>, thread: AnyThreadChannel, _newlyCreated: boolean) {
|
||||
try {
|
||||
await thread.join();
|
||||
} catch (e) {
|
||||
console.error(`Failed to join thread: ${thread.name} (${thread.id})`, e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new ThreadCreateEvent();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Guild, GuildTextBasedChannel, VoiceState } from 'discord.js';
|
||||
import { Client, Guild, GuildTextBasedChannel, VoiceState } from 'discord.js';
|
||||
import { Database } from '../../shared/Database';
|
||||
import { Event } from '../../types';
|
||||
import { CreateDefaultEmbed, SetSeverity } from '../../utils';
|
||||
|
||||
async function getVoiceLogsChannel(guild: Guild): Promise<GuildTextBasedChannel | undefined> {
|
||||
@@ -22,7 +23,6 @@ async function memberJoinedChannel(_: VoiceState, state: VoiceState) {
|
||||
...SetSeverity('success'),
|
||||
|
||||
title: 'Joined Voice Channel',
|
||||
|
||||
fields: [
|
||||
{ name: 'Member', value: `<@${state.member?.id}>`, inline: false },
|
||||
{ name: 'Channel', value: `${state.channel?.name} (${state.channelId})`, inline: true },
|
||||
@@ -61,7 +61,6 @@ async function memberMovedChannel(oldState: VoiceState, newState: VoiceState) {
|
||||
...SetSeverity('warning'),
|
||||
|
||||
title: 'Moved Voice Channel',
|
||||
|
||||
fields: [
|
||||
{ name: 'Member', value: `<@${newState.member?.id}>`, inline: false },
|
||||
{ name: 'Channel', value: `<#${oldState.channelId}> -> <#${newState.channelId}>`, inline: false },
|
||||
@@ -70,10 +69,10 @@ async function memberMovedChannel(oldState: VoiceState, newState: VoiceState) {
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
event: 'voiceStateUpdate',
|
||||
class VoiceStateUpdateEvent implements Event<Client, 'voiceStateUpdate'> {
|
||||
event = 'voiceStateUpdate' as const;
|
||||
|
||||
handler: async (oldState: VoiceState, newState: VoiceState) => {
|
||||
async execute(context: Client<boolean>, oldState: VoiceState, newState: VoiceState): Promise<void> {
|
||||
// Ignore non-movement voiceStateUpdate events.
|
||||
if (oldState.channelId === newState.channelId) return;
|
||||
|
||||
@@ -84,4 +83,6 @@ export default {
|
||||
else if (newState.channelId == null && oldState.channelId != null)
|
||||
await memberLeftChannel(oldState, newState);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new VoiceStateUpdateEvent();
|
||||
|
||||
+2
-3
@@ -1,4 +1,4 @@
|
||||
import { Client as DiscordClient, GatewayIntentBits, MessageFlags, Partials } from 'discord.js';
|
||||
import { Client, Client as DiscordClient, GatewayIntentBits, MessageFlags, Partials } from 'discord.js';
|
||||
import { config } from './config';
|
||||
import events from './events';
|
||||
import { Database } from './shared/Database';
|
||||
@@ -151,7 +151,7 @@ client.on('clientReady', async () => {
|
||||
|
||||
events.forEach(event =>
|
||||
client.on(event.event, (...args) =>
|
||||
Promise.resolve((event.handler as (...args: unknown[]) => Promise<void>)(...args))
|
||||
Promise.resolve((event.execute as (context: Client, ...args: unknown[]) => Promise<void>)(client, ...args))
|
||||
.catch(e => console.error(`Error in ${event.event} handler:`, e))
|
||||
)
|
||||
);
|
||||
@@ -160,7 +160,6 @@ client.on('clientReady', async () => {
|
||||
console.log('Ready');
|
||||
});
|
||||
|
||||
|
||||
client.on('error', console.error);
|
||||
process.on('uncaughtException', console.error);
|
||||
|
||||
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
import { ClientEvents } from 'discord.js';
|
||||
|
||||
export interface Event<Context, E extends keyof ClientEvents> {
|
||||
readonly event: E;
|
||||
execute(context: Context, ...args: ClientEvents[E]): Promise<void>;
|
||||
}
|
||||
Vendored
+1
@@ -1,5 +1,6 @@
|
||||
export * from './command.d';
|
||||
export * from './database-types.d';
|
||||
export * from './event.d';
|
||||
export * from './e621-types.d';
|
||||
export * from './handler.d';
|
||||
export * from './helper-types.d';
|
||||
|
||||
Reference in New Issue
Block a user