Browse Source

Handle reapplying violations on user join

ghorsington 4 years ago
parent
commit
9ef1334266
1 changed files with 55 additions and 8 deletions
  1. 55 8
      bot/src/plugins/violation.ts

+ 55 - 8
bot/src/plugins/violation.ts

@@ -1,6 +1,6 @@
-import { Plugin, ICommandData, Command } from "src/model/plugin";
+import { Plugin, ICommandData, Command, Event, BotEventData } from "src/model/plugin";
 import { parseArgs, tryDo, parseDuration, UNIT_MEASURES, Option } from "src/util";
-import { GuildMember, Guild, MessageEmbed, Message, TextChannel } from "discord.js";
+import { GuildMember, Guild, MessageEmbed, Message, TextChannel, PartialGuildMember } from "discord.js";
 import { logger } from "src/logging";
 import { client } from "src/client";
 import humanizeDuration from "humanize-duration";
@@ -25,7 +25,7 @@ interface ViolationInfo {
 
 type TimedViolation = Violation & { endsAt: Date };
 
-type StartViolationFunction = (member: GuildMember, settings: GuildViolationSettings) => Promise<void>;
+type StartViolationFunction = (member: GuildMember | PartialGuildMember, settings: GuildViolationSettings) => Promise<void>;
 type StopViolationFunction = (guild: Guild, userId: string, settings: GuildViolationSettings) => Promise<void>;
 interface TimedViolationStopHandler {
     type: ObjectType<TimedViolation>;
@@ -34,6 +34,14 @@ interface TimedViolationStopHandler {
     command: string;
 }
 
+function isTimed(violation: Violation): violation is TimedViolation {
+    return Object.prototype.hasOwnProperty.call(violation, "endsAt") && (violation as unknown as Record<string, unknown>)["endsAt"] !== undefined;
+}
+
+function getViolationType(violation: TimedViolation): ObjectType<TimedViolation> {
+    return (violation as { constructor: ObjectType<TimedViolation> }).constructor;
+}
+
 @Plugin
 export class ViolationPlugin {
     jobs: Record<number, Job> = {};
@@ -41,14 +49,14 @@ export class ViolationPlugin {
         {
             command: "mute",
             type: Mute,
-            start: async (member: GuildMember, settings: GuildViolationSettings): Promise<void> => {
+            start: async (member: GuildMember | PartialGuildMember, settings: GuildViolationSettings): Promise<void> => {
                 const muteRoleResolve = await tryDo(member.guild.roles.fetch(settings.muteRoleId));
                 if (!muteRoleResolve.ok || !muteRoleResolve.result) {
                     logger.error(
                         "mute: Tried to mute user %s#%s (%s) but mute role ID %s is invalid!",
-                        member.user.username,
-                        member.user.discriminator,
-                        member.user.id,
+                        member.user?.username,
+                        member.user?.discriminator,
+                        member.user?.id,
                         settings.muteRoleId);
                     return;
                 }
@@ -93,6 +101,41 @@ export class ViolationPlugin {
         }
     }
 
+    @Event("guildMemberAdd")
+    async onUserJoin(data: BotEventData, member: GuildMember | PartialGuildMember): Promise<void> {
+        const settingsRepo = getRepository(GuildViolationSettings);
+        const settings = await settingsRepo.findOne(member.guild.id);
+
+        if (!settings)
+            return;
+
+        const repo = getRepository(Violation);
+        const activeViolations = await repo.find({
+            where: {
+                guildId: member.guild.id,
+                userId: member.id,
+                valid: true
+            }
+        });
+
+        if (activeViolations.length == 0)
+            return;
+
+        for (const violation of activeViolations) {
+            if (!isTimed(violation)) {
+                await repo.update({ id: violation.id }, { valid: false });
+                continue;
+            }
+
+            const type = getViolationType(violation);
+            const handler = this.getViolationHandler(type);
+            if (violation.endsAt < new Date())
+                await repo.update({ id: violation.id }, { valid: false });
+            else
+                await handler.start(member, settings);
+        }
+    }
+
     @Command({
         type: "prefix",
         pattern: "mute",
@@ -104,6 +147,10 @@ export class ViolationPlugin {
             return;
 
         const handler = this.getViolationHandler(Mute);
+        if (!handler) {
+            logger.error("Couldn't find handler for Mute");
+            return;
+        }
 
         await this.applyTimedViolation(Mute, info, "mute", handler.start, handler.stop);
         await this.sendViolationMessage(message, info, "User has been muted for server violation");
@@ -114,7 +161,7 @@ export class ViolationPlugin {
             if (handler.type == type)
                 return handler;
         }
-        throw new Error("Cannot find stop handler for violation type!");
+        throw new Error("Couldn't find handler for violation type!");
     }
 
     private async applyTimedViolation<T extends TimedViolation>(type: ObjectType<T>, info: ViolationInfo, command = "violation", apply: StartViolationFunction, remove: StopViolationFunction) {