From 63efaf84eee23cc1b8c5cda4729a0e707544a49d Mon Sep 17 00:00:00 2001
From: Dark <7890309+DarkView@users.noreply.github.com>
Date: Wed, 8 Jul 2020 02:53:44 +0200
Subject: [PATCH 1/4] Migrate LocateUser to new Plugin structure

---
 .../plugins/LocateUser/LocateUserPlugin.ts    | 60 ++++++++++++++++++
 .../plugins/LocateUser/commands/FollowCmd.ts  | 63 +++++++++++++++++++
 .../LocateUser/commands/ListFollowCmd.ts      | 57 +++++++++++++++++
 .../plugins/LocateUser/commands/WhereCmd.ts   | 20 ++++++
 .../LocateUser/events/ChannelJoinEvt.ts       | 22 +++++++
 .../LocateUser/events/ChannelLeaveEvt.ts      | 19 ++++++
 .../LocateUser/events/GuildBanAddEvt.ts       | 12 ++++
 backend/src/plugins/LocateUser/types.ts       | 15 +++++
 .../LocateUser/utils/createOrReuseInvite.ts   | 11 ++++
 .../LocateUser/utils/fillAlertsList.ts        |  9 +++
 .../plugins/LocateUser/utils/moveMember.ts    | 25 ++++++++
 .../plugins/LocateUser/utils/outdatedLoop.ts  | 17 +++++
 .../utils/removeUserIdFromActiveAlerts.ts     |  6 ++
 .../plugins/LocateUser/utils/sendAlerts.ts    | 20 ++++++
 .../src/plugins/LocateUser/utils/sendWhere.ts | 22 +++++++
 backend/src/plugins/availablePlugins.ts       |  2 +
 16 files changed, 380 insertions(+)
 create mode 100644 backend/src/plugins/LocateUser/LocateUserPlugin.ts
 create mode 100644 backend/src/plugins/LocateUser/commands/FollowCmd.ts
 create mode 100644 backend/src/plugins/LocateUser/commands/ListFollowCmd.ts
 create mode 100644 backend/src/plugins/LocateUser/commands/WhereCmd.ts
 create mode 100644 backend/src/plugins/LocateUser/events/ChannelJoinEvt.ts
 create mode 100644 backend/src/plugins/LocateUser/events/ChannelLeaveEvt.ts
 create mode 100644 backend/src/plugins/LocateUser/events/GuildBanAddEvt.ts
 create mode 100644 backend/src/plugins/LocateUser/types.ts
 create mode 100644 backend/src/plugins/LocateUser/utils/createOrReuseInvite.ts
 create mode 100644 backend/src/plugins/LocateUser/utils/fillAlertsList.ts
 create mode 100644 backend/src/plugins/LocateUser/utils/moveMember.ts
 create mode 100644 backend/src/plugins/LocateUser/utils/outdatedLoop.ts
 create mode 100644 backend/src/plugins/LocateUser/utils/removeUserIdFromActiveAlerts.ts
 create mode 100644 backend/src/plugins/LocateUser/utils/sendAlerts.ts
 create mode 100644 backend/src/plugins/LocateUser/utils/sendWhere.ts

diff --git a/backend/src/plugins/LocateUser/LocateUserPlugin.ts b/backend/src/plugins/LocateUser/LocateUserPlugin.ts
new file mode 100644
index 00000000..c71bb3d5
--- /dev/null
+++ b/backend/src/plugins/LocateUser/LocateUserPlugin.ts
@@ -0,0 +1,60 @@
+import { PluginOptions } from "knub";
+import { LocateUserPluginType, ConfigSchema } from "./types";
+import { zeppelinPlugin } from "../ZeppelinPluginBlueprint";
+import { GuildVCAlerts } from "src/data/GuildVCAlerts";
+import { outdatedAlertsLoop } from "./utils/outdatedLoop";
+import { fillActiveAlertsList } from "./utils/fillAlertsList";
+import { WhereCmd } from "./commands/WhereCmd";
+import { FollowCmd } from "./commands/FollowCmd";
+import { ListFollowCmd, DeleteFollowCmd } from "./commands/ListFollowCmd";
+import { ChannelJoinEvt, ChannelSwitchEvt } from "./events/ChannelJoinEvt";
+import { ChannelLeaveEvt } from "./events/ChannelLeaveEvt";
+import { GuildBanAddEvt } from "./events/GuildBanAddEvt";
+
+const defaultOptions: PluginOptions<LocateUserPluginType> = {
+  config: {
+    can_where: false,
+    can_alert: false,
+  },
+  overrides: [
+    {
+      level: ">=50",
+      config: {
+        can_where: true,
+        can_alert: true,
+      },
+    },
+  ],
+};
+
+export const LocateUserPlugin = zeppelinPlugin<LocateUserPluginType>()("locate_user", {
+  configSchema: ConfigSchema,
+  defaultOptions,
+
+  // prettier-ignore
+  commands: [
+        WhereCmd,
+        FollowCmd,
+        ListFollowCmd,
+        DeleteFollowCmd,
+    ],
+
+  events: [ChannelJoinEvt, ChannelSwitchEvt, ChannelLeaveEvt, GuildBanAddEvt],
+
+  onLoad(pluginData) {
+    const { state, guild } = pluginData;
+
+    state.alerts = GuildVCAlerts.getGuildInstance(guild.id);
+    state.outdatedAlertsTimeout = null;
+    state.usersWithAlerts = [];
+    state.unloaded = false;
+
+    outdatedAlertsLoop(pluginData);
+    fillActiveAlertsList(pluginData);
+  },
+
+  onUnload(pluginData) {
+    clearTimeout(pluginData.state.outdatedAlertsTimeout);
+    pluginData.state.unloaded = true;
+  },
+});
diff --git a/backend/src/plugins/LocateUser/commands/FollowCmd.ts b/backend/src/plugins/LocateUser/commands/FollowCmd.ts
new file mode 100644
index 00000000..d0e41a79
--- /dev/null
+++ b/backend/src/plugins/LocateUser/commands/FollowCmd.ts
@@ -0,0 +1,63 @@
+import { locateUserCommand } from "../types";
+import { commandTypeHelpers as ct } from "../../../commandTypes";
+import moment from "moment-timezone";
+import humanizeDuration from "humanize-duration";
+import { MINUTES, SECONDS } from "src/utils";
+import { sendSuccessMessage } from "src/pluginUtils";
+
+export const FollowCmd = locateUserCommand({
+  trigger: ["follow", "f"],
+  description: "Sets up an alert that notifies you any time `<member>` switches or joins voice channels",
+  usage: "!f 108552944961454080",
+  permission: "can_alert",
+
+  signature: {
+    member: ct.resolvedMember(),
+    reminder: ct.string({ required: false, rest: true }),
+
+    duration: ct.delay({ option: true, shortcut: "d" }),
+    active: ct.bool({ option: true, shortcut: "a" }),
+  },
+
+  async run({ message: msg, args, pluginData }) {
+    const time = args.duration || 10 * MINUTES;
+    const alertTime = moment().add(time, "millisecond");
+    const body = args.reminder || "None";
+    const active = args.active || false;
+
+    if (time < 30 * SECONDS) {
+      this.sendErrorMessage(msg.channel, "Sorry, but the minimum duration for an alert is 30 seconds!");
+      return;
+    }
+
+    await pluginData.state.alerts.add(
+      msg.author.id,
+      args.member.id,
+      msg.channel.id,
+      alertTime.format("YYYY-MM-DD HH:mm:ss"),
+      body,
+      active,
+    );
+    if (!pluginData.state.usersWithAlerts.includes(args.member.id)) {
+      pluginData.state.usersWithAlerts.push(args.member.id);
+    }
+
+    if (active) {
+      sendSuccessMessage(
+        pluginData,
+        msg.channel,
+        `Every time ${args.member.mention} joins or switches VC in the next ${humanizeDuration(
+          time,
+        )} i will notify and move you.\nPlease make sure to be in a voice channel, otherwise i cannot move you!`,
+      );
+    } else {
+      sendSuccessMessage(
+        pluginData,
+        msg.channel,
+        `Every time ${args.member.mention} joins or switches VC in the next ${humanizeDuration(
+          time,
+        )} i will notify you`,
+      );
+    }
+  },
+});
diff --git a/backend/src/plugins/LocateUser/commands/ListFollowCmd.ts b/backend/src/plugins/LocateUser/commands/ListFollowCmd.ts
new file mode 100644
index 00000000..6f77a0b7
--- /dev/null
+++ b/backend/src/plugins/LocateUser/commands/ListFollowCmd.ts
@@ -0,0 +1,57 @@
+import { locateUserCommand } from "../types";
+import { sendErrorMessage, sendSuccessMessage } from "src/pluginUtils";
+import { commandTypeHelpers as ct } from "../../../commandTypes";
+import { sorter, createChunkedMessage } from "src/utils";
+
+export const ListFollowCmd = locateUserCommand({
+  trigger: ["follows", "fs"],
+  description: "Displays all of your active alerts ordered by expiration time",
+  usage: "!fs",
+  permission: "can_alert",
+
+  async run({ message: msg, pluginData }) {
+    const alerts = await pluginData.state.alerts.getAlertsByRequestorId(msg.member.id);
+    if (alerts.length === 0) {
+      sendErrorMessage(pluginData, msg.channel, "You have no active alerts!");
+      return;
+    }
+
+    alerts.sort(sorter("expires_at"));
+    const longestNum = (alerts.length + 1).toString().length;
+    const lines = Array.from(alerts.entries()).map(([i, alert]) => {
+      const num = i + 1;
+      const paddedNum = num.toString().padStart(longestNum, " ");
+      return `\`${paddedNum}.\` \`${alert.expires_at}\` **Target:** <@!${alert.user_id}> **Reminder:** \`${
+        alert.body
+      }\` **Active:** ${alert.active.valueOf()}`;
+    });
+    await createChunkedMessage(msg.channel, lines.join("\n"));
+  },
+});
+
+export const DeleteFollowCmd = locateUserCommand({
+  trigger: ["follows delete", "fs d"],
+  description:
+    "Deletes the alert at the position <num>.\nThe value needed for <num> can be found using `!follows` (`!fs`)",
+  usage: "!fs d <num>",
+  permission: "can_alert",
+
+  signature: {
+    num: ct.number({ required: true }),
+  },
+
+  async run({ message: msg, args, pluginData }) {
+    const alerts = await pluginData.state.alerts.getAlertsByRequestorId(msg.member.id);
+    alerts.sort(sorter("expires_at"));
+
+    if (args.num > alerts.length || args.num <= 0) {
+      sendErrorMessage(pluginData, msg.channel, "Unknown alert!");
+      return;
+    }
+
+    const toDelete = alerts[args.num - 1];
+    await pluginData.state.alerts.delete(toDelete.id);
+
+    sendSuccessMessage(pluginData, msg.channel, "Alert deleted");
+  },
+});
diff --git a/backend/src/plugins/LocateUser/commands/WhereCmd.ts b/backend/src/plugins/LocateUser/commands/WhereCmd.ts
new file mode 100644
index 00000000..58b18846
--- /dev/null
+++ b/backend/src/plugins/LocateUser/commands/WhereCmd.ts
@@ -0,0 +1,20 @@
+import { locateUserCommand } from "../types";
+import { commandTypeHelpers as ct } from "../../../commandTypes";
+import { resolveMember } from "src/utils";
+import { sendWhere } from "../utils/sendWhere";
+
+export const WhereCmd = locateUserCommand({
+  trigger: ["where", "w"],
+  description: "Posts an instant invite to the voice channel that `<member>` is in",
+  usage: "!w 108552944961454080",
+  permission: "can_where",
+
+  signature: {
+    member: ct.resolvedMember(),
+  },
+
+  async run({ message: msg, args, pluginData }) {
+    const member = await resolveMember(pluginData.client, pluginData.guild, args.member.id);
+    sendWhere.call(this, pluginData.guild, member, msg.channel, `${msg.member.mention} | `);
+  },
+});
diff --git a/backend/src/plugins/LocateUser/events/ChannelJoinEvt.ts b/backend/src/plugins/LocateUser/events/ChannelJoinEvt.ts
new file mode 100644
index 00000000..38c519c7
--- /dev/null
+++ b/backend/src/plugins/LocateUser/events/ChannelJoinEvt.ts
@@ -0,0 +1,22 @@
+import { locateUserEvent } from "../types";
+import { sendAlerts } from "../utils/sendAlerts";
+
+export const ChannelJoinEvt = locateUserEvent({
+  event: "voiceChannelJoin",
+
+  async listener(meta) {
+    if (meta.pluginData.state.usersWithAlerts.includes(meta.args.member.id)) {
+      sendAlerts(meta.pluginData, meta.args.member.id);
+    }
+  },
+});
+
+export const ChannelSwitchEvt = locateUserEvent({
+  event: "voiceChannelSwitch",
+
+  async listener(meta) {
+    if (meta.pluginData.state.usersWithAlerts.includes(meta.args.member.id)) {
+      sendAlerts(meta.pluginData, meta.args.member.id);
+    }
+  },
+});
diff --git a/backend/src/plugins/LocateUser/events/ChannelLeaveEvt.ts b/backend/src/plugins/LocateUser/events/ChannelLeaveEvt.ts
new file mode 100644
index 00000000..c9164171
--- /dev/null
+++ b/backend/src/plugins/LocateUser/events/ChannelLeaveEvt.ts
@@ -0,0 +1,19 @@
+import { locateUserEvent } from "../types";
+import { sendAlerts } from "../utils/sendAlerts";
+import { VoiceChannel, TextableChannel } from "eris";
+
+export const ChannelLeaveEvt = locateUserEvent({
+  event: "voiceChannelLeave",
+
+  async listener(meta) {
+    const triggeredAlerts = await meta.pluginData.state.alerts.getAlertsByUserId(meta.args.member.id);
+    const voiceChannel = meta.args.oldChannel as VoiceChannel;
+
+    triggeredAlerts.forEach(alert => {
+      const txtChannel = meta.pluginData.client.getChannel(alert.channel_id) as TextableChannel;
+      txtChannel.createMessage(
+        `🔴 <@!${alert.requestor_id}> the user <@!${alert.user_id}> disconnected out of \`${voiceChannel.name}\``,
+      );
+    });
+  },
+});
diff --git a/backend/src/plugins/LocateUser/events/GuildBanAddEvt.ts b/backend/src/plugins/LocateUser/events/GuildBanAddEvt.ts
new file mode 100644
index 00000000..599f3aa9
--- /dev/null
+++ b/backend/src/plugins/LocateUser/events/GuildBanAddEvt.ts
@@ -0,0 +1,12 @@
+import { locateUserEvent } from "../types";
+
+export const GuildBanAddEvt = locateUserEvent({
+  event: "guildBanAdd",
+
+  async listener(meta) {
+    const alerts = await meta.pluginData.state.alerts.getAlertsByUserId(meta.args.user.id);
+    alerts.forEach(alert => {
+      meta.pluginData.state.alerts.delete(alert.id);
+    });
+  },
+});
diff --git a/backend/src/plugins/LocateUser/types.ts b/backend/src/plugins/LocateUser/types.ts
new file mode 100644
index 00000000..b928862d
--- /dev/null
+++ b/backend/src/plugins/LocateUser/types.ts
@@ -0,0 +1,15 @@
+import * as t from "io-ts";
+import { BasePluginType, command, eventListener } from "knub";
+
+export const ConfigSchema = t.type({
+  can_where: t.boolean,
+  can_alert: t.boolean,
+});
+export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
+
+export interface LocateUserPluginType extends BasePluginType {
+  config: TConfigSchema;
+}
+
+export const locateUserCommand = command<LocateUserPluginType>();
+export const locateUserEvent = eventListener<LocateUserPluginType>();
diff --git a/backend/src/plugins/LocateUser/utils/createOrReuseInvite.ts b/backend/src/plugins/LocateUser/utils/createOrReuseInvite.ts
new file mode 100644
index 00000000..9f453e21
--- /dev/null
+++ b/backend/src/plugins/LocateUser/utils/createOrReuseInvite.ts
@@ -0,0 +1,11 @@
+import { VoiceChannel } from "eris";
+
+export async function createOrReuseInvite(vc: VoiceChannel) {
+  const existingInvites = await vc.getInvites();
+
+  if (existingInvites.length !== 0) {
+    return existingInvites[0];
+  } else {
+    return vc.createInvite(undefined);
+  }
+}
diff --git a/backend/src/plugins/LocateUser/utils/fillAlertsList.ts b/backend/src/plugins/LocateUser/utils/fillAlertsList.ts
new file mode 100644
index 00000000..675972e6
--- /dev/null
+++ b/backend/src/plugins/LocateUser/utils/fillAlertsList.ts
@@ -0,0 +1,9 @@
+export async function fillActiveAlertsList(pluginData) {
+  const allAlerts = await pluginData.state.alerts.getAllGuildAlerts();
+
+  allAlerts.forEach(alert => {
+    if (!pluginData.state.usersWithAlerts.includes(alert.user_id)) {
+      pluginData.state.usersWithAlerts.push(alert.user_id);
+    }
+  });
+}
diff --git a/backend/src/plugins/LocateUser/utils/moveMember.ts b/backend/src/plugins/LocateUser/utils/moveMember.ts
new file mode 100644
index 00000000..82de1174
--- /dev/null
+++ b/backend/src/plugins/LocateUser/utils/moveMember.ts
@@ -0,0 +1,25 @@
+import { Member, TextableChannel } from "eris";
+import { PluginData } from "knub";
+import { LocateUserPluginType } from "../types";
+import { sendErrorMessage } from "src/pluginUtils";
+
+export async function moveMember(
+  pluginData: PluginData<LocateUserPluginType>,
+  toMoveID: string,
+  target: Member,
+  errorChannel: TextableChannel,
+) {
+  const modMember: Member = await this.bot.getRESTGuildMember(pluginData.guild.id, toMoveID);
+  if (modMember.voiceState.channelID != null) {
+    try {
+      await modMember.edit({
+        channelID: target.voiceState.channelID,
+      });
+    } catch (e) {
+      sendErrorMessage(pluginData, errorChannel, "Failed to move you. Are you in a voice channel?");
+      return;
+    }
+  } else {
+    sendErrorMessage(pluginData, errorChannel, "Failed to move you. Are you in a voice channel?");
+  }
+}
diff --git a/backend/src/plugins/LocateUser/utils/outdatedLoop.ts b/backend/src/plugins/LocateUser/utils/outdatedLoop.ts
new file mode 100644
index 00000000..92d81ef9
--- /dev/null
+++ b/backend/src/plugins/LocateUser/utils/outdatedLoop.ts
@@ -0,0 +1,17 @@
+import { SECONDS } from "src/utils";
+import { removeUserIdFromActiveAlerts } from "./removeUserIdFromActiveAlerts";
+
+const ALERT_LOOP_TIME = 30 * SECONDS;
+
+export async function outdatedAlertsLoop(pluginData) {
+  const outdatedAlerts = await pluginData.state.alerts.getOutdatedAlerts();
+
+  for (const alert of outdatedAlerts) {
+    await pluginData.state.alerts.delete(alert.id);
+    await removeUserIdFromActiveAlerts(pluginData, alert.user_id);
+  }
+
+  if (!pluginData.state.unloaded) {
+    pluginData.state.outdatedAlertsTimeout = setTimeout(() => this.outdatedAlertsLoop(pluginData), ALERT_LOOP_TIME);
+  }
+}
diff --git a/backend/src/plugins/LocateUser/utils/removeUserIdFromActiveAlerts.ts b/backend/src/plugins/LocateUser/utils/removeUserIdFromActiveAlerts.ts
new file mode 100644
index 00000000..9493e416
--- /dev/null
+++ b/backend/src/plugins/LocateUser/utils/removeUserIdFromActiveAlerts.ts
@@ -0,0 +1,6 @@
+export async function removeUserIdFromActiveAlerts(pluginData, userId: string) {
+  const index = pluginData.state.usersWithAlerts.indexOf(userId);
+  if (index > -1) {
+    pluginData.state.usersWithAlerts.splice(index, 1);
+  }
+}
diff --git a/backend/src/plugins/LocateUser/utils/sendAlerts.ts b/backend/src/plugins/LocateUser/utils/sendAlerts.ts
new file mode 100644
index 00000000..14ac1405
--- /dev/null
+++ b/backend/src/plugins/LocateUser/utils/sendAlerts.ts
@@ -0,0 +1,20 @@
+import { PluginData } from "knub";
+import { LocateUserPluginType } from "../types";
+import { resolveMember } from "src/utils";
+import { sendWhere } from "./sendWhere";
+import { TextableChannel } from "eris";
+import { moveMember } from "./moveMember";
+
+export async function sendAlerts(pluginData: PluginData<LocateUserPluginType>, userId: string) {
+  const triggeredAlerts = await pluginData.state.alerts.getAlertsByUserId(userId);
+  const member = await resolveMember(pluginData.client, pluginData.guild, userId);
+
+  triggeredAlerts.forEach(alert => {
+    const prepend = `<@!${alert.requestor_id}>, an alert requested by you has triggered!\nReminder: \`${alert.body}\`\n`;
+    const txtChannel = pluginData.client.getChannel(alert.channel_id) as TextableChannel;
+    sendWhere.call(this, pluginData.guild, member, txtChannel, prepend);
+    if (alert.active) {
+      moveMember(pluginData, alert.requestor_id, member, txtChannel);
+    }
+  });
+}
diff --git a/backend/src/plugins/LocateUser/utils/sendWhere.ts b/backend/src/plugins/LocateUser/utils/sendWhere.ts
new file mode 100644
index 00000000..87d0c690
--- /dev/null
+++ b/backend/src/plugins/LocateUser/utils/sendWhere.ts
@@ -0,0 +1,22 @@
+import { Guild, Member, TextableChannel, VoiceChannel } from "eris";
+import { getInviteLink } from "knub/dist/helpers";
+import { createOrReuseInvite } from "./createOrReuseInvite";
+
+export async function sendWhere(guild: Guild, member: Member, channel: TextableChannel, prepend: string) {
+  const voice = guild.channels.get(member.voiceState.channelID) as VoiceChannel;
+
+  if (voice == null) {
+    channel.createMessage(prepend + "That user is not in a channel");
+  } else {
+    let invite = null;
+    try {
+      invite = await createOrReuseInvite(voice);
+    } catch (e) {
+      this.sendErrorMessage(channel, "Cannot create an invite to that channel!");
+      return;
+    }
+    channel.createMessage(
+      prepend + `${member.mention} is in the following channel: \`${voice.name}\` ${getInviteLink(invite)}`,
+    );
+  }
+}
diff --git a/backend/src/plugins/availablePlugins.ts b/backend/src/plugins/availablePlugins.ts
index f604fbdf..6cb3688f 100644
--- a/backend/src/plugins/availablePlugins.ts
+++ b/backend/src/plugins/availablePlugins.ts
@@ -1,7 +1,9 @@
 import { UtilityPlugin } from "./Utility/UtilityPlugin";
+import { LocateUserPlugin } from "./LocateUser/LocateUserPlugin";
 
 // prettier-ignore
 export const guildPlugins = [
+  LocateUserPlugin,
   UtilityPlugin,
 ];
 

From 0f226bfa93279b77010decbccc0cac6df4ab8a88 Mon Sep 17 00:00:00 2001
From: Dark <7890309+DarkView@users.noreply.github.com>
Date: Wed, 8 Jul 2020 02:54:38 +0200
Subject: [PATCH 2/4] Fix(?) error on docs caused by union type mismatch

---
 backend/src/api/docs.ts | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/backend/src/api/docs.ts b/backend/src/api/docs.ts
index dc8cbef8..771ac8e0 100644
--- a/backend/src/api/docs.ts
+++ b/backend/src/api/docs.ts
@@ -3,6 +3,7 @@ import { guildPlugins } from "../plugins/availablePlugins";
 import { notFound } from "./responses";
 import { indentLines } from "../utils";
 import { getPluginName } from "knub/dist/plugins/pluginUtils";
+import { ZeppelinPluginBlueprint } from "src/plugins/ZeppelinPluginBlueprint";
 
 function formatConfigSchema(schema) {
   if (schema._tag === "InterfaceType" || schema._tag === "PartialType") {
@@ -46,7 +47,9 @@ export function initDocs(app: express.Express) {
   });
 
   app.get("/docs/plugins/:pluginName", (req: express.Request, res: express.Response) => {
-    const plugin = docsPlugins.find(obj => getPluginName(obj) === req.params.pluginName);
+    const plugin = docsPlugins.find(obj => getPluginName(obj) === req.params.pluginName) as ZeppelinPluginBlueprint<
+      any
+    >;
     if (!plugin) {
       return notFound(res);
     }

From 0b8e480626456571013cf649530a5d5225627c9d Mon Sep 17 00:00:00 2001
From: Dark <7890309+DarkView@users.noreply.github.com>
Date: Wed, 8 Jul 2020 02:57:56 +0200
Subject: [PATCH 3/4] Prettier: Ignore union type mismatch fix

Otherwise it puts the any in its new line which is a lot of wasted space and just looks weird
---
 backend/src/api/docs.ts | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/backend/src/api/docs.ts b/backend/src/api/docs.ts
index 771ac8e0..ee4595b6 100644
--- a/backend/src/api/docs.ts
+++ b/backend/src/api/docs.ts
@@ -47,9 +47,8 @@ export function initDocs(app: express.Express) {
   });
 
   app.get("/docs/plugins/:pluginName", (req: express.Request, res: express.Response) => {
-    const plugin = docsPlugins.find(obj => getPluginName(obj) === req.params.pluginName) as ZeppelinPluginBlueprint<
-      any
-    >;
+    // prettier-ignore
+    const plugin = docsPlugins.find(obj => getPluginName(obj) === req.params.pluginName) as ZeppelinPluginBlueprint<any>;
     if (!plugin) {
       return notFound(res);
     }

From ec06577b46e149be897ab26461e8898787e9dba5 Mon Sep 17 00:00:00 2001
From: Dark <7890309+DarkView@users.noreply.github.com>
Date: Wed, 8 Jul 2020 03:01:14 +0200
Subject: [PATCH 4/4] Prettier: Ignore events in LocateUser

---
 .../src/plugins/LocateUser/LocateUserPlugin.ts | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/backend/src/plugins/LocateUser/LocateUserPlugin.ts b/backend/src/plugins/LocateUser/LocateUserPlugin.ts
index c71bb3d5..96f7264c 100644
--- a/backend/src/plugins/LocateUser/LocateUserPlugin.ts
+++ b/backend/src/plugins/LocateUser/LocateUserPlugin.ts
@@ -33,13 +33,19 @@ export const LocateUserPlugin = zeppelinPlugin<LocateUserPluginType>()("locate_u
 
   // prettier-ignore
   commands: [
-        WhereCmd,
-        FollowCmd,
-        ListFollowCmd,
-        DeleteFollowCmd,
-    ],
+    WhereCmd,
+    FollowCmd,
+    ListFollowCmd,
+    DeleteFollowCmd,
+  ],
 
-  events: [ChannelJoinEvt, ChannelSwitchEvt, ChannelLeaveEvt, GuildBanAddEvt],
+  // prettier-ignore
+  events: [
+    ChannelJoinEvt, 
+    ChannelSwitchEvt, 
+    ChannelLeaveEvt, 
+    GuildBanAddEvt
+  ],
 
   onLoad(pluginData) {
     const { state, guild } = pluginData;