diff options
Diffstat (limited to 'src/tasks/feature')
-rw-r--r-- | src/tasks/feature/handleReminders.ts | 39 | ||||
-rw-r--r-- | src/tasks/feature/memberCount.ts | 28 | ||||
-rw-r--r-- | src/tasks/feature/removeExpiredPunishements.ts | 84 | ||||
-rw-r--r-- | src/tasks/feature/updateStats.ts | 26 |
4 files changed, 177 insertions, 0 deletions
diff --git a/src/tasks/feature/handleReminders.ts b/src/tasks/feature/handleReminders.ts new file mode 100644 index 0000000..7863c9a --- /dev/null +++ b/src/tasks/feature/handleReminders.ts @@ -0,0 +1,39 @@ +import { BushTask, dateDelta, format, Reminder, Time } from '#lib'; +const { Op } = (await import('sequelize')).default; + +export default class HandlerRemindersTask extends BushTask { + public constructor() { + super('handlerReminders', { + delay: 30 * Time.Second, + runOnStart: true + }); + } + + public async exec() { + const expiredEntries = await Reminder.findAll({ + where: { + expires: { + [Op.lt]: new Date(Date.now() + 30 * Time.Second) // Find all rows with an expiry date before 30 seconds from now + }, + notified: false + } + }); + + void this.client.logger.verbose( + `handlerReminders`, + `Queried reminders, found <<${expiredEntries.length}>> expired reminders.` + ); + + for (const entry of expiredEntries) { + setTimeout(() => { + void this.client.users + .send( + entry.user, + `The reminder you set ${dateDelta(entry.created)} ago has expired: ${format.bold(entry.content)}\n${entry.messageUrl}` + ) + .catch(() => false); + void entry.update({ notified: true }); + }, entry.expires.getTime() - new Date().getTime()); + } + } +} diff --git a/src/tasks/feature/memberCount.ts b/src/tasks/feature/memberCount.ts new file mode 100644 index 0000000..ea422fa --- /dev/null +++ b/src/tasks/feature/memberCount.ts @@ -0,0 +1,28 @@ +import { BushTask, MemberCount, Time } from '#lib'; +import assert from 'assert'; + +export default class MemberCountTask extends BushTask { + public constructor() { + super('memberCount', { + delay: Time.Minute, + runOnStart: true + }); + } + + public override async exec() { + if (!this.client.config.isProduction) return; + + const res = await Promise.allSettled( + this.client.guilds.cache + .filter((g) => g.memberCount >= 100) + .map((g) => MemberCount.create({ guildId: g.id, memberCount: g.memberCount })) + ); + + res + .filter((r) => r.status === 'rejected') + .forEach((r) => { + assert(r.status === 'rejected'); + void this.client.console.error('memberCount', r.status); + }); + } +} diff --git a/src/tasks/feature/removeExpiredPunishements.ts b/src/tasks/feature/removeExpiredPunishements.ts new file mode 100644 index 0000000..0b20a27 --- /dev/null +++ b/src/tasks/feature/removeExpiredPunishements.ts @@ -0,0 +1,84 @@ +import { ActivePunishment, ActivePunishmentType, BushTask, Time } from '#lib'; +import assert from 'assert'; +const { Op } = (await import('sequelize')).default; + +export default class RemoveExpiredPunishmentsTask extends BushTask { + public constructor() { + super('removeExpiredPunishments', { + delay: 15 * Time.Second, + runOnStart: true + }); + } + + public async exec() { + const expiredEntries = await ActivePunishment.findAll({ + where: { + expires: { + [Op.lt]: new Date(Date.now() + 15 * Time.Second) // Find all rows with an expiry date before 15 seconds from now + } + } + }); + + void this.client.logger.verbose( + `removeExpiredPunishments`, + `Queried punishments, found <<${expiredEntries.length}>> expired punishments.` + ); + + for (const entry of expiredEntries) { + const guild = this.client.guilds.cache.get(entry.guild); + if (!guild) continue; + + // eslint-disable-next-line @typescript-eslint/no-misused-promises + setTimeout(async () => { + const member = guild.members.cache.get(entry.user); + const user = await this.client.utils.resolveNonCachedUser(entry.user); + assert(guild); + + switch (entry.type) { + case ActivePunishmentType.BAN: { + assert(user); + const result = await guild.bushUnban({ user: user, reason: 'Punishment expired' }); + if (['success', 'user not banned', 'cannot resolve user'].includes(result)) await entry.destroy(); + else throw new Error(result); + void this.client.logger.verbose(`removeExpiredPunishments`, `Unbanned ${entry.user}.`); + break; + } + case ActivePunishmentType.BLOCK: { + if (!member) { + await entry.destroy(); // channel overrides are removed when the member leaves the guild + return; + } + const result = await member.bushUnblock({ reason: 'Punishment expired', channel: entry.extraInfo }); + if (['success', 'user not blocked'].includes(result)) await entry.destroy(); + else throw new Error(result); + void this.client.logger.verbose(`removeExpiredPunishments`, `Unblocked ${entry.user}.`); + break; + } + case ActivePunishmentType.MUTE: { + if (!member) return; + const result = await member.bushUnmute({ reason: 'Punishment expired' }); + if (['success', 'failed to dm'].includes(result)) await entry.destroy(); + else throw new Error(result); + void this.client.logger.verbose(`removeExpiredPunishments`, `Unmuted ${entry.user}.`); + break; + } + case ActivePunishmentType.ROLE: { + if (!member) return; + const role = guild?.roles?.cache?.get(entry.extraInfo); + if (!role) throw new Error(`Cannot unmute ${member.user.tag} because I cannot find the mute role.`); + const result = await member.bushRemoveRole({ + reason: 'Punishment expired', + role: role, + addToModlog: true + }); + + if (['success', 'failed to dm'].includes(result)) await entry.destroy(); + else throw new Error(result); + void this.client.logger.verbose(`removeExpiredPunishments`, `Removed a punishment role from ${entry.user}.`); + break; + } + } + }, entry.expires!.getTime() - new Date().getTime()); + } + } +} diff --git a/src/tasks/feature/updateStats.ts b/src/tasks/feature/updateStats.ts new file mode 100644 index 0000000..0d0e661 --- /dev/null +++ b/src/tasks/feature/updateStats.ts @@ -0,0 +1,26 @@ +import { BushTask, Stat, Time } from '#lib'; +import { Client } from 'discord.js'; + +export default class UpdateStatsTask extends BushTask { + public constructor() { + super('updateStats', { + delay: 10 * Time.Minute, + runOnStart: true + }); + } + + public async exec() { + const row = + (await Stat.findByPk(this.client.config.environment)) ?? + (await Stat.create({ environment: this.client.config.environment })); + row.commandsUsed = this.client.stats.commandsUsed; + row.slashCommandsUsed = this.client.stats.slashCommandsUsed; + await row.save(); + } + + public static async init(client: Client): Promise<{ commandsUsed: bigint; slashCommandsUsed: bigint }> { + const temp = + (await Stat.findByPk(client.config.environment)) ?? (await Stat.create({ environment: client.config.environment })); + return { commandsUsed: temp.commandsUsed, slashCommandsUsed: temp.slashCommandsUsed }; + } +} |