From c4a2be5ff5b93d012aa021c10f03a997903e4b32 Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 13:11:38 +0000
Subject: [PATCH 01/17] resolveUserId support new usernames

Signed-off-by: GitHub <noreply@github.com>
---
 backend/src/utils.ts | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/backend/src/utils.ts b/backend/src/utils.ts
index 1bb4d6ce..f29d990c 100644
--- a/backend/src/utils.ts
+++ b/backend/src/utils.ts
@@ -1222,11 +1222,25 @@ export function resolveUserId(bot: Client, value: string) {
   }
 
   // A non-mention, full username?
-  const usernameMatch = value.match(/^@?([^#]+)#(\d{4})$/);
+  const oldUsernameMatch = value.match(/^@?([^#]+)#(\d{4})$/);
+  if (oldUsernameMatch) {
+    const profiler = getProfiler();
+    const start = performance.now();
+    const user = bot.users.cache.find(
+      (u) => u.username === oldUsernameMatch[1] && u.discriminator === oldUsernameMatch[2],
+    );
+    profiler?.addDataPoint("utils:resolveUserId:usernameMatch", performance.now() - start);
+    if (user) {
+      return user.id;
+    }
+  }
+
+  // new usernames system
+  const usernameMatch = value.match(/^@?([^#]+)$/);
   if (usernameMatch) {
     const profiler = getProfiler();
     const start = performance.now();
-    const user = bot.users.cache.find((u) => u.username === usernameMatch[1] && u.discriminator === usernameMatch[2]);
+    const user = bot.users.cache.find((u) => u.username === usernameMatch[1]);
     profiler?.addDataPoint("utils:resolveUserId:usernameMatch", performance.now() - start);
     if (user) {
       return user.id;

From 43076b3db68bafed52e0963914ebf8a027dcdcba Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 13:16:44 +0000
Subject: [PATCH 02/17] update djs

Signed-off-by: GitHub <noreply@github.com>
---
 backend/package-lock.json                     | 289 +++++++-----------
 backend/package.json                          |   2 +-
 .../plugins/Automod/actions/startThread.ts    |  13 +-
 3 files changed, 122 insertions(+), 182 deletions(-)

diff --git a/backend/package-lock.json b/backend/package-lock.json
index b1d6d189..4c6eaa14 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -14,7 +14,7 @@
         "cors": "^2.8.5",
         "cross-env": "^7.0.3",
         "deep-diff": "^1.0.2",
-        "discord.js": "^14.11.0",
+        "discord.js": "^14.14.1",
         "dotenv": "^4.0.0",
         "emoji-regex": "^8.0.0",
         "erlpack": "github:discord/erlpack",
@@ -265,84 +265,109 @@
       }
     },
     "node_modules/@discordjs/builders": {
-      "version": "1.6.3",
-      "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.3.tgz",
-      "integrity": "sha512-CTCh8NqED3iecTNuiz49mwSsrc2iQb4d0MjMdmS/8pb69Y4IlzJ/DIy/p5GFlgOrFbNO2WzMHkWKQSiJ3VNXaw==",
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.7.0.tgz",
+      "integrity": "sha512-GDtbKMkg433cOZur8Dv6c25EHxduNIBsxeHrsRoIM8+AwmEZ8r0tEpckx/sHwTLwQPOF3e2JWloZh9ofCaMfAw==",
       "dependencies": {
-        "@discordjs/formatters": "^0.3.1",
-        "@discordjs/util": "^0.3.1",
-        "@sapphire/shapeshift": "^3.8.2",
-        "discord-api-types": "^0.37.41",
+        "@discordjs/formatters": "^0.3.3",
+        "@discordjs/util": "^1.0.2",
+        "@sapphire/shapeshift": "^3.9.3",
+        "discord-api-types": "0.37.61",
         "fast-deep-equal": "^3.1.3",
         "ts-mixer": "^6.0.3",
-        "tslib": "^2.5.0"
+        "tslib": "^2.6.2"
       },
       "engines": {
-        "node": ">=16.9.0"
+        "node": ">=16.11.0"
       }
     },
     "node_modules/@discordjs/collection": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.1.tgz",
-      "integrity": "sha512-aWEc9DCf3TMDe9iaJoOnO2+JVAjeRNuRxPZQA6GVvBf+Z3gqUuWYBy2NWh4+5CLYq5uoc3MOvUQ5H5m8CJBqOA==",
+      "version": "1.5.3",
+      "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz",
+      "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==",
       "engines": {
-        "node": ">=16.9.0"
+        "node": ">=16.11.0"
       }
     },
     "node_modules/@discordjs/formatters": {
-      "version": "0.3.1",
-      "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.1.tgz",
-      "integrity": "sha512-M7X4IGiSeh4znwcRGcs+49B5tBkNDn4k5bmhxJDAUhRxRHTiFAOTVUNQ6yAKySu5jZTnCbSvTYHW3w0rAzV1MA==",
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.3.tgz",
+      "integrity": "sha512-wTcI1Q5cps1eSGhl6+6AzzZkBBlVrBdc9IUhJbijRgVjCNIIIZPgqnUj3ntFODsHrdbGU8BEG9XmDQmgEEYn3w==",
       "dependencies": {
-        "discord-api-types": "^0.37.41"
+        "discord-api-types": "0.37.61"
       },
       "engines": {
-        "node": ">=16.9.0"
+        "node": ">=16.11.0"
       }
     },
     "node_modules/@discordjs/rest": {
-      "version": "1.7.1",
-      "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.7.1.tgz",
-      "integrity": "sha512-Ofa9UqT0U45G/eX86cURQnX7gzOJLG2oC28VhIk/G6IliYgQF7jFByBJEykPSHE4MxPhqCleYvmsrtfKh1nYmQ==",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.2.0.tgz",
+      "integrity": "sha512-nXm9wT8oqrYFRMEqTXQx9DUTeEtXUDMmnUKIhZn6O2EeDY9VCdwj23XCPq7fkqMPKdF7ldAfeVKyxxFdbZl59A==",
       "dependencies": {
-        "@discordjs/collection": "^1.5.1",
-        "@discordjs/util": "^0.3.0",
+        "@discordjs/collection": "^2.0.0",
+        "@discordjs/util": "^1.0.2",
         "@sapphire/async-queue": "^1.5.0",
-        "@sapphire/snowflake": "^3.4.2",
-        "discord-api-types": "^0.37.41",
-        "file-type": "^18.3.0",
-        "tslib": "^2.5.0",
-        "undici": "^5.22.0"
+        "@sapphire/snowflake": "^3.5.1",
+        "@vladfrangu/async_event_emitter": "^2.2.2",
+        "discord-api-types": "0.37.61",
+        "magic-bytes.js": "^1.5.0",
+        "tslib": "^2.6.2",
+        "undici": "5.27.2"
       },
       "engines": {
-        "node": ">=16.9.0"
+        "node": ">=16.11.0"
+      }
+    },
+    "node_modules/@discordjs/rest/node_modules/@discordjs/collection": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz",
+      "integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==",
+      "engines": {
+        "node": ">=18"
       }
     },
     "node_modules/@discordjs/util": {
-      "version": "0.3.1",
-      "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.3.1.tgz",
-      "integrity": "sha512-HxXKYKg7vohx2/OupUN/4Sd02Ev3PBJ5q0gtjdcvXb0ErCva8jNHWfe/v5sU3UKjIB/uxOhc+TDOnhqffj9pRA==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.2.tgz",
+      "integrity": "sha512-IRNbimrmfb75GMNEjyznqM1tkI7HrZOf14njX7tCAAUetyZM1Pr8hX/EK2lxBCOgWDRmigbp24fD1hdMfQK5lw==",
       "engines": {
-        "node": ">=16.9.0"
+        "node": ">=16.11.0"
       }
     },
     "node_modules/@discordjs/ws": {
-      "version": "0.8.3",
-      "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-0.8.3.tgz",
-      "integrity": "sha512-hcYtppanjHecbdNyCKQNH2I4RP9UrphDgmRgLYrATEQF1oo4sYSve7ZmGsBEXSzH72MO2tBPdWSThunbxUVk0g==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.2.tgz",
+      "integrity": "sha512-+XI82Rm2hKnFwAySXEep4A7Kfoowt6weO6381jgW+wVdTpMS/56qCvoXyFRY0slcv7c/U8My2PwIB2/wEaAh7Q==",
       "dependencies": {
-        "@discordjs/collection": "^1.5.1",
-        "@discordjs/rest": "^1.7.1",
-        "@discordjs/util": "^0.3.1",
+        "@discordjs/collection": "^2.0.0",
+        "@discordjs/rest": "^2.1.0",
+        "@discordjs/util": "^1.0.2",
         "@sapphire/async-queue": "^1.5.0",
-        "@types/ws": "^8.5.4",
-        "@vladfrangu/async_event_emitter": "^2.2.1",
-        "discord-api-types": "^0.37.41",
-        "tslib": "^2.5.0",
-        "ws": "^8.13.0"
+        "@types/ws": "^8.5.9",
+        "@vladfrangu/async_event_emitter": "^2.2.2",
+        "discord-api-types": "0.37.61",
+        "tslib": "^2.6.2",
+        "ws": "^8.14.2"
       },
       "engines": {
-        "node": ">=16.9.0"
+        "node": ">=16.11.0"
+      }
+    },
+    "node_modules/@discordjs/ws/node_modules/@discordjs/collection": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz",
+      "integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@fastify/busboy": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz",
+      "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==",
+      "engines": {
+        "node": ">=14"
       }
     },
     "node_modules/@jest/types": {
@@ -416,9 +441,9 @@
       }
     },
     "node_modules/@sapphire/shapeshift": {
-      "version": "3.9.2",
-      "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz",
-      "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==",
+      "version": "3.9.3",
+      "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.3.tgz",
+      "integrity": "sha512-WzKJSwDYloSkHoBbE8rkRW8UNKJiSRJ/P8NqJ5iVq7U2Yr/kriIBx2hW+wj2Z5e5EnXL1hgYomgaFsdK6b+zqQ==",
       "dependencies": {
         "fast-deep-equal": "^3.1.3",
         "lodash": "^4.17.21"
@@ -499,11 +524,6 @@
         "yarn": ">= 1.3.2"
       }
     },
-    "node_modules/@tokenizer/token": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
-      "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="
-    },
     "node_modules/@types/body-parser": {
       "version": "1.19.2",
       "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
@@ -769,9 +789,9 @@
       "integrity": "sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg=="
     },
     "node_modules/@types/ws": {
-      "version": "8.5.5",
-      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz",
-      "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==",
+      "version": "8.5.9",
+      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.9.tgz",
+      "integrity": "sha512-jbdrY0a8lxfdTp/+r7Z4CkycbOFN8WX+IOchLJr3juT/xzbJ8URyTVSJ/hvNdadTgM1mnedb47n+Y31GsFnQlg==",
       "dependencies": {
         "@types/node": "*"
       }
@@ -3257,32 +3277,32 @@
       }
     },
     "node_modules/discord-api-types": {
-      "version": "0.37.47",
-      "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.47.tgz",
-      "integrity": "sha512-rNif8IAv6duS2z47BMXq/V9kkrLfkAoiwpFY3sLxxbyKprk065zqf3HLTg4bEoxRSmi+Lhc7yqGDrG8C3j8GFA=="
+      "version": "0.37.61",
+      "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.61.tgz",
+      "integrity": "sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw=="
     },
     "node_modules/discord.js": {
-      "version": "14.11.0",
-      "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.11.0.tgz",
-      "integrity": "sha512-CkueWYFQ28U38YPR8HgsBR/QT35oPpMbEsTNM30Fs8loBIhnA4s70AwQEoy6JvLcpWWJO7GY0y2BUzZmuBMepQ==",
+      "version": "14.14.1",
+      "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.14.1.tgz",
+      "integrity": "sha512-/hUVzkIerxKHyRKopJy5xejp4MYKDPTszAnpYxzVVv4qJYf+Tkt+jnT2N29PIPschicaEEpXwF2ARrTYHYwQ5w==",
       "dependencies": {
-        "@discordjs/builders": "^1.6.3",
-        "@discordjs/collection": "^1.5.1",
-        "@discordjs/formatters": "^0.3.1",
-        "@discordjs/rest": "^1.7.1",
-        "@discordjs/util": "^0.3.1",
-        "@discordjs/ws": "^0.8.3",
-        "@sapphire/snowflake": "^3.4.2",
-        "@types/ws": "^8.5.4",
-        "discord-api-types": "^0.37.41",
-        "fast-deep-equal": "^3.1.3",
-        "lodash.snakecase": "^4.1.1",
-        "tslib": "^2.5.0",
-        "undici": "^5.22.0",
-        "ws": "^8.13.0"
+        "@discordjs/builders": "^1.7.0",
+        "@discordjs/collection": "1.5.3",
+        "@discordjs/formatters": "^0.3.3",
+        "@discordjs/rest": "^2.1.0",
+        "@discordjs/util": "^1.0.2",
+        "@discordjs/ws": "^1.0.2",
+        "@sapphire/snowflake": "3.5.1",
+        "@types/ws": "8.5.9",
+        "discord-api-types": "0.37.61",
+        "fast-deep-equal": "3.1.3",
+        "lodash.snakecase": "4.1.1",
+        "tslib": "2.6.2",
+        "undici": "5.27.2",
+        "ws": "8.14.2"
       },
       "engines": {
-        "node": ">=16.9.0"
+        "node": ">=16.11.0"
       }
     },
     "node_modules/distributions": {
@@ -3925,22 +3945,6 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/file-type": {
-      "version": "18.5.0",
-      "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.5.0.tgz",
-      "integrity": "sha512-yvpl5U868+V6PqXHMmsESpg6unQ5GfnPssl4dxdJudBrr9qy7Fddt7EVX1VLlddFfe8Gj9N7goCZH22FXuSQXQ==",
-      "dependencies": {
-        "readable-web-to-node-stream": "^3.0.2",
-        "strtok3": "^7.0.0",
-        "token-types": "^5.0.1"
-      },
-      "engines": {
-        "node": ">=14.16"
-      },
-      "funding": {
-        "url": "https://github.com/sindresorhus/file-type?sponsor=1"
-      }
-    },
     "node_modules/file-uri-to-path": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
@@ -5769,6 +5773,11 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/magic-bytes.js": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.5.0.tgz",
+      "integrity": "sha512-wJkXvutRbNWcc37tt5j1HyOK1nosspdh3dj6LUYYAvF6JYNqs53IfRvK9oEpcwiDA1NdoIi64yAMfdivPeVAyw=="
+    },
     "node_modules/magic-string": {
       "version": "0.25.1",
       "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.1.tgz",
@@ -7118,18 +7127,6 @@
         "node": ">=0.12"
       }
     },
-    "node_modules/peek-readable": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz",
-      "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==",
-      "engines": {
-        "node": ">=14.16"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/Borewit"
-      }
-    },
     "node_modules/performance-now": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@@ -7706,34 +7703,6 @@
         "safe-buffer": "~5.1.0"
       }
     },
-    "node_modules/readable-web-to-node-stream": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz",
-      "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==",
-      "dependencies": {
-        "readable-stream": "^3.6.0"
-      },
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/Borewit"
-      }
-    },
-    "node_modules/readable-web-to-node-stream/node_modules/readable-stream": {
-      "version": "3.6.2",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
-      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
-      "dependencies": {
-        "inherits": "^2.0.3",
-        "string_decoder": "^1.1.1",
-        "util-deprecate": "^1.0.1"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
     "node_modules/readdirp": {
       "version": "3.6.0",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -8873,22 +8842,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/strtok3": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz",
-      "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==",
-      "dependencies": {
-        "@tokenizer/token": "^0.3.0",
-        "peek-readable": "^5.0.0"
-      },
-      "engines": {
-        "node": ">=14.16"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/Borewit"
-      }
-    },
     "node_modules/subarg": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
@@ -9151,22 +9104,6 @@
         "node": ">=0.6"
       }
     },
-    "node_modules/token-types": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz",
-      "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==",
-      "dependencies": {
-        "@tokenizer/token": "^0.3.0",
-        "ieee754": "^1.2.1"
-      },
-      "engines": {
-        "node": ">=14.16"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/Borewit"
-      }
-    },
     "node_modules/tough-cookie": {
       "version": "4.1.3",
       "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
@@ -9276,9 +9213,9 @@
       }
     },
     "node_modules/tslib": {
-      "version": "2.6.0",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz",
-      "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA=="
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+      "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
     },
     "node_modules/ttest": {
       "version": "3.0.0",
@@ -9716,11 +9653,11 @@
       "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA=="
     },
     "node_modules/undici": {
-      "version": "5.22.1",
-      "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz",
-      "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==",
+      "version": "5.27.2",
+      "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz",
+      "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==",
       "dependencies": {
-        "busboy": "^1.6.0"
+        "@fastify/busboy": "^2.0.0"
       },
       "engines": {
         "node": ">=14.0"
@@ -10091,9 +10028,9 @@
       }
     },
     "node_modules/ws": {
-      "version": "8.13.0",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
-      "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
+      "version": "8.14.2",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz",
+      "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==",
       "engines": {
         "node": ">=10.0.0"
       },
diff --git a/backend/package.json b/backend/package.json
index 2ff53482..44101e51 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -35,7 +35,7 @@
     "cors": "^2.8.5",
     "cross-env": "^7.0.3",
     "deep-diff": "^1.0.2",
-    "discord.js": "^14.11.0",
+    "discord.js": "^14.14.1",
     "dotenv": "^4.0.0",
     "emoji-regex": "^8.0.0",
     "erlpack": "github:discord/erlpack",
diff --git a/backend/src/plugins/Automod/actions/startThread.ts b/backend/src/plugins/Automod/actions/startThread.ts
index 25b840e1..66d5ec3a 100644
--- a/backend/src/plugins/Automod/actions/startThread.ts
+++ b/backend/src/plugins/Automod/actions/startThread.ts
@@ -57,7 +57,13 @@ export const StartThreadAction = automodAction({
 
     for (const threadContext of threads) {
       const channel = pluginData.guild.channels.cache.get(threadContext.message!.channel_id);
-      if (!channel || !("threads" in channel) || channel.type === ChannelType.GuildForum) continue;
+      if (
+        !channel ||
+        !("threads" in channel) ||
+        channel.type === ChannelType.GuildForum ||
+        channel.type === ChannelType.GuildMedia
+      )
+        continue;
 
       const renderThreadName = async (str: string) =>
         renderTemplate(
@@ -90,10 +96,7 @@ export const StartThreadAction = automodAction({
           .create({
             ...threadOptions,
             type: actionConfig.private ? ChannelType.PrivateThread : ChannelType.PublicThread,
-            startMessage:
-              !actionConfig.private && guild.features.includes(GuildFeature.PrivateThreads)
-                ? threadContext.message!.id
-                : undefined,
+            startMessage: !actionConfig.private ? threadContext.message!.id : undefined,
           })
           .catch(() => undefined);
       }

From f1791fac4452d63205fda3f0130cec1d46b96bdd Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 13:25:58 +0000
Subject: [PATCH 03/17] redo username check, yeet discrims entirely

Signed-off-by: GitHub <noreply@github.com>
---
 backend/src/utils.ts | 20 +++-----------------
 1 file changed, 3 insertions(+), 17 deletions(-)

diff --git a/backend/src/utils.ts b/backend/src/utils.ts
index f29d990c..af3b5ad8 100644
--- a/backend/src/utils.ts
+++ b/backend/src/utils.ts
@@ -1221,26 +1221,12 @@ export function resolveUserId(bot: Client, value: string) {
     return mentionMatch[1];
   }
 
-  // A non-mention, full username?
-  const oldUsernameMatch = value.match(/^@?([^#]+)#(\d{4})$/);
-  if (oldUsernameMatch) {
-    const profiler = getProfiler();
-    const start = performance.now();
-    const user = bot.users.cache.find(
-      (u) => u.username === oldUsernameMatch[1] && u.discriminator === oldUsernameMatch[2],
-    );
-    profiler?.addDataPoint("utils:resolveUserId:usernameMatch", performance.now() - start);
-    if (user) {
-      return user.id;
-    }
-  }
-
-  // new usernames system
-  const usernameMatch = value.match(/^@?([^#]+)$/);
+  // a username
+  const usernameMatch = value.match(/^@?(\S{3,})$/);
   if (usernameMatch) {
     const profiler = getProfiler();
     const start = performance.now();
-    const user = bot.users.cache.find((u) => u.username === usernameMatch[1]);
+    const user = bot.users.cache.find((u) => u.tag === usernameMatch[1]);
     profiler?.addDataPoint("utils:resolveUserId:usernameMatch", performance.now() - start);
     if (user) {
       return user.id;

From 4c788bc321795d6d4cfb160945017d9a3475ceed Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 13:38:42 +0000
Subject: [PATCH 04/17] some transforms

Signed-off-by: GitHub <noreply@github.com>
---
 .../Automod/functions/matchMultipleTextTypesOnMessage.ts   | 2 +-
 .../plugins/ChannelArchiver/commands/ArchiveChannelCmd.ts  | 7 +++----
 .../src/plugins/Utility/functions/getInviteInfoEmbed.ts    | 2 +-
 .../src/plugins/Utility/functions/getMessageInfoEmbed.ts   | 2 +-
 backend/src/plugins/Utility/functions/getUserInfoEmbed.ts  | 7 +++----
 backend/src/utils.ts                                       | 7 +++++--
 backend/src/utils/templateSafeObjects.ts                   | 2 ++
 7 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/backend/src/plugins/Automod/functions/matchMultipleTextTypesOnMessage.ts b/backend/src/plugins/Automod/functions/matchMultipleTextTypesOnMessage.ts
index 9e51c490..f0eee5ec 100644
--- a/backend/src/plugins/Automod/functions/matchMultipleTextTypesOnMessage.ts
+++ b/backend/src/plugins/Automod/functions/matchMultipleTextTypesOnMessage.ts
@@ -42,7 +42,7 @@ export async function* matchMultipleTextTypesOnMessage(
   }
 
   if (trigger.match_visible_names) {
-    yield ["visiblename", member.nickname || msg.data.author.username];
+    yield ["visiblename", member.nickname || member.user.globalName || msg.data.author.username];
   }
 
   if (trigger.match_usernames) {
diff --git a/backend/src/plugins/ChannelArchiver/commands/ArchiveChannelCmd.ts b/backend/src/plugins/ChannelArchiver/commands/ArchiveChannelCmd.ts
index 13a72a87..f7350b5f 100644
--- a/backend/src/plugins/ChannelArchiver/commands/ArchiveChannelCmd.ts
+++ b/backend/src/plugins/ChannelArchiver/commands/ArchiveChannelCmd.ts
@@ -68,10 +68,9 @@ export const ArchiveChannelCmd = channelArchiverCmd({
 
       for (const message of messages.values()) {
         const ts = moment.utc(message.createdTimestamp).format("YYYY-MM-DD HH:mm:ss");
-        let content = `[${ts}] [${message.author.id}] [${renderUsername(
-          message.author.username,
-          message.author.discriminator,
-        )}]: ${message.content || "<no text content>"}`;
+        let content = `[${ts}] [${message.author.id}] [${renderUsername(message.author)}]: ${
+          message.content || "<no text content>"
+        }`;
 
         if (message.attachments.size) {
           if (args["attachment-channel"]) {
diff --git a/backend/src/plugins/Utility/functions/getInviteInfoEmbed.ts b/backend/src/plugins/Utility/functions/getInviteInfoEmbed.ts
index 12c97a8a..b844b937 100644
--- a/backend/src/plugins/Utility/functions/getInviteInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getInviteInfoEmbed.ts
@@ -85,7 +85,7 @@ export async function getInviteInfoEmbed(
       embed.fields.push({
         name: preEmbedPadding + "Invite creator",
         value: trimLines(`
-          Name: **${renderUsername(invite.inviter.username, invite.inviter.discriminator)}**
+          Name: **${renderUsername(invite.inviter)}**
           ID: \`${invite.inviter.id}\`
           Mention: <@!${invite.inviter.id}>
         `),
diff --git a/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts b/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts
index 1568a3e3..3a49a80d 100644
--- a/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts
@@ -71,7 +71,7 @@ export async function getMessageInfoEmbed(
   embed.fields.push({
     name: preEmbedPadding + "Author information",
     value: trimLines(`
-      Name: **${renderUsername(message.author.username, message.author.discriminator)}**
+      Name: **${renderUsername(message.author)}**
       ID: \`${message.author.id}\`
       Created: **<t:${Math.round(message.author.createdTimestamp / 1000)}:R>**
       ${authorJoinedAtTS ? `Joined: **<t:${Math.round(authorJoinedAtTS / 1000)}:R>**` : ""}
diff --git a/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts b/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts
index ef8d2320..2de8b4db 100644
--- a/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts
@@ -43,7 +43,7 @@ export async function getUserInfoEmbed(
   const timeAndDate = pluginData.getPlugin(TimeAndDatePlugin);
 
   embed.author = {
-    name: `${user.bot ? "Bot" : "User"}:  ${renderUsername(user.username, user.discriminator)}`,
+    name: `${user.bot ? "Bot" : "User"}:  ${renderUsername(user)}`,
   };
 
   const avatarURL = user.displayAvatarURL();
@@ -72,9 +72,8 @@ export async function getUserInfoEmbed(
   }
 
   const userInfoLines = [`ID: \`${user.id}\``, `Username: **${user.username}**`];
-  if (user.discriminator !== "0") {
-    userInfoLines.push(`Discriminator: **${user.discriminator}**`);
-  }
+  if (user.discriminator !== "0") userInfoLines.push(`Discriminator: **${user.discriminator}**`);
+  if (user.globalName) userInfoLines.push(`Display Name: **${user.globalName}**`);
   userInfoLines.push(`Created: **<t:${Math.round(user.createdTimestamp / 1000)}:R>**`);
   userInfoLines.push(`Mention: <@!${user.id}>`);
 
diff --git a/backend/src/utils.ts b/backend/src/utils.ts
index af3b5ad8..ee6b556c 100644
--- a/backend/src/utils.ts
+++ b/backend/src/utils.ts
@@ -1603,8 +1603,11 @@ export function isTruthy<T>(value: T): value is Exclude<T, false | null | undefi
 
 export const DBDateFormat = "YYYY-MM-DD HH:mm:ss";
 
-export function renderUsername(username: string, discriminator: string): string {
-  if (discriminator === "0") {
+export function renderUsername(username: User): string;
+export function renderUsername(username: string, discriminator?: string): string;
+export function renderUsername(username: string | User, discriminator?: string): string {
+  if (username instanceof User) return username.tag;
+  if (discriminator === "0" || discriminator === "0000") {
     return username;
   }
   return `${username}#${discriminator}`;
diff --git a/backend/src/utils/templateSafeObjects.ts b/backend/src/utils/templateSafeObjects.ts
index 67517f19..fbd27754 100644
--- a/backend/src/utils/templateSafeObjects.ts
+++ b/backend/src/utils/templateSafeObjects.ts
@@ -49,6 +49,7 @@ export class TemplateSafeUser extends TemplateSafeValueContainer {
   id: Snowflake | string;
   username: string;
   discriminator: string;
+  globalName?: string;
   mention: string;
   tag: string;
   avatarURL?: string;
@@ -257,6 +258,7 @@ export function userToTemplateSafeUser(user: User | UnknownUser): TemplateSafeUs
     id: user.id,
     username: user.username,
     discriminator: user.discriminator,
+    globalName: user.globalName,
     mention: `<@${user.id}>`,
     tag: user.tag,
     avatarURL: user.displayAvatarURL?.(),

From 1579c3ec25398a5341af0b66a4f68626ddd92f70 Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 13:40:05 +0000
Subject: [PATCH 05/17] disable status-search arg

Signed-off-by: GitHub <noreply@github.com>
---
 backend/src/plugins/Utility/commands/SearchCmd.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/backend/src/plugins/Utility/commands/SearchCmd.ts b/backend/src/plugins/Utility/commands/SearchCmd.ts
index 777bb890..fb4d2ad1 100644
--- a/backend/src/plugins/Utility/commands/SearchCmd.ts
+++ b/backend/src/plugins/Utility/commands/SearchCmd.ts
@@ -15,7 +15,7 @@ export const searchCmdSignature = {
   export: ct.switchOption({ def: false, shortcut: "e" }),
   ids: ct.switchOption(),
   regex: ct.switchOption({ def: false, shortcut: "re" }),
-  "status-search": ct.switchOption({ def: false, shortcut: "ss" }),
+  // "status-search": ct.switchOption({ def: false, shortcut: "ss" }),
 };
 
 export const SearchCmd = utilityCmd({

From c5704131cefd1b17da76ef179c2da81855c3fb25 Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 13:44:42 +0000
Subject: [PATCH 06/17] support media channels

Signed-off-by: GitHub <noreply@github.com>
---
 backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts | 1 +
 backend/src/plugins/Utility/functions/getServerInfoEmbed.ts  | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts b/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts
index ee006f5f..d41e3e44 100644
--- a/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts
@@ -56,6 +56,7 @@ export async function getChannelInfoEmbed(
       [ChannelType.AnnouncementThread]: "News Thread channel",
       [ChannelType.GuildDirectory]: "Hub channel",
       [ChannelType.GuildForum]: "Forum channel",
+      [ChannelType.GuildMedia]: "Media channel",
     }[channel.type] ?? "Channel";
 
   embed.author = {
diff --git a/backend/src/plugins/Utility/functions/getServerInfoEmbed.ts b/backend/src/plugins/Utility/functions/getServerInfoEmbed.ts
index d0202db7..afcefb80 100644
--- a/backend/src/plugins/Utility/functions/getServerInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getServerInfoEmbed.ts
@@ -149,12 +149,16 @@ export async function getServerInfoEmbed(
     const textChannels = thisServer.channels.cache.filter((channel) => channel.type === ChannelType.GuildText);
     const voiceChannels = thisServer.channels.cache.filter((channel) => channel.type === ChannelType.GuildVoice);
     const forumChannels = thisServer.channels.cache.filter((channel) => channel.type === ChannelType.GuildForum);
+    const mediaChannels = thisServer.channels.cache.filter((channel) => channel.type === ChannelType.GuildMedia);
     const threadChannelsText = thisServer.channels.cache.filter(
       (channel) => channel.isThread() && channel.parent?.type !== ChannelType.GuildForum,
     );
     const threadChannelsForums = thisServer.channels.cache.filter(
       (channel) => channel.isThread() && channel.parent?.type === ChannelType.GuildForum,
     );
+    const threadChannelsMedia = thisServer.channels.cache.filter(
+      (channel) => channel.isThread() && channel.parent?.type === ChannelType.GuildMedia,
+    );
     const announcementChannels = thisServer.channels.cache.filter(
       (channel) => channel.type === ChannelType.GuildAnnouncement,
     );
@@ -169,6 +173,7 @@ export async function getServerInfoEmbed(
           Categories: **${categories.size}**
           Text: **${textChannels.size}** (**${threadChannelsText.size} threads**)
           Forums: **${forumChannels.size}** (**${threadChannelsForums.size} threads**)
+          Media: **${mediaChannels.size}** (**${threadChannelsMedia.size} threads**)
           Announcement: **${announcementChannels.size}**
           Voice: **${voiceChannels.size}**
           Stage: **${stageChannels.size}**

From 1e66f235b2f447ef07af2d17c1cda1108872a1dc Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 14:06:23 +0000
Subject: [PATCH 07/17] media channel icon

Signed-off-by: GitHub <noreply@github.com>
---
 backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts b/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts
index d41e3e44..f601dd5c 100644
--- a/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts
@@ -19,6 +19,8 @@ const PRIVATE_THREAD_ICON =
 const FORUM_CHANNEL_ICON =
   "https://cdn.discordapp.com/attachments/740650744830623756/1091681253364875294/forum-channel-icon.png";
 
+const MEDIA_CHANNEL_ICON = "https://cdn.discordapp.com/attachments/876134205229252658/1178335624940490792/media.png";
+
 export async function getChannelInfoEmbed(
   pluginData: GuildPluginData<UtilityPluginType>,
   channelId: string,
@@ -42,6 +44,7 @@ export async function getChannelInfoEmbed(
       [ChannelType.PrivateThread]: PRIVATE_THREAD_ICON,
       [ChannelType.AnnouncementThread]: PUBLIC_THREAD_ICON,
       [ChannelType.GuildForum]: FORUM_CHANNEL_ICON,
+      [ChannelType.GuildMedia]: MEDIA_CHANNEL_ICON,
     }[channel.type] ?? TEXT_CHANNEL_ICON;
 
   const channelType =

From ba4a2b45b8c73fc1ac201365e7cf9bbf7b9ea8bf Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 14:09:34 +0000
Subject: [PATCH 08/17] remove useless feature check

Signed-off-by: GitHub <noreply@github.com>
---
 backend/src/plugins/Automod/actions/startThread.ts | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/backend/src/plugins/Automod/actions/startThread.ts b/backend/src/plugins/Automod/actions/startThread.ts
index 66d5ec3a..970e9ec8 100644
--- a/backend/src/plugins/Automod/actions/startThread.ts
+++ b/backend/src/plugins/Automod/actions/startThread.ts
@@ -1,10 +1,4 @@
-import {
-  ChannelType,
-  GuildFeature,
-  GuildTextThreadCreateOptions,
-  ThreadAutoArchiveDuration,
-  ThreadChannel,
-} from "discord.js";
+import { ChannelType, GuildTextThreadCreateOptions, ThreadAutoArchiveDuration, ThreadChannel } from "discord.js";
 import * as t from "io-ts";
 import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
 import { MINUTES, convertDelayStringToMS, noop, tDelayString, tNullable } from "../../../utils";
@@ -77,10 +71,7 @@ export const StartThreadAction = automodAction({
       const threadOptions: GuildTextThreadCreateOptions<unknown> = {
         name: threadName,
         autoArchiveDuration: autoArchive,
-        startMessage:
-          !actionConfig.private && guild.features.includes(GuildFeature.PrivateThreads)
-            ? threadContext.message!.id
-            : undefined,
+        startMessage: !actionConfig.private ? threadContext.message!.id : undefined,
       };
 
       let thread: ThreadChannel | undefined;

From 10bb0b67bc22a3f8dfef1c65809a9035143ba51a Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 14:53:54 +0000
Subject: [PATCH 09/17] some more patches thanks to ruby

Signed-off-by: GitHub <noreply@github.com>
---
 .../plugins/Automod/triggers/threadArchive.ts |  4 ++--
 .../plugins/Automod/triggers/threadCreate.ts  |  3 ++-
 .../plugins/Automod/triggers/threadDelete.ts  |  3 ++-
 .../Automod/triggers/threadUnarchive.ts       |  4 ++--
 .../plugins/BotControl/commands/ServersCmd.ts |  6 +++--
 .../src/plugins/Cases/functions/createCase.ts |  8 +++----
 .../plugins/Cases/functions/createCaseNote.ts |  4 ++--
 .../InternalPoster/functions/sendMessage.ts   |  2 +-
 .../ModActions/commands/CasesModCmd.ts        | 12 +++++-----
 .../ModActions/commands/CasesUserCmd.ts       | 22 ++++++++++++++-----
 .../src/plugins/Post/util/actualPostCmd.ts    |  4 ++--
 .../util/createStarboardEmbedFromMessage.ts   |  6 ++---
 .../src/plugins/Utility/commands/AboutCmd.ts  |  4 ++--
 .../src/plugins/Utility/commands/AvatarCmd.ts |  8 +++----
 .../Utility/functions/getUserInfoEmbed.ts     |  5 +----
 backend/src/plugins/Utility/search.ts         | 10 ++++-----
 backend/src/utils.ts                          |  9 +++++---
 backend/src/utils/templateSafeObjects.ts      |  7 +++---
 18 files changed, 69 insertions(+), 52 deletions(-)

diff --git a/backend/src/plugins/Automod/triggers/threadArchive.ts b/backend/src/plugins/Automod/triggers/threadArchive.ts
index 0e65b10a..8a692f6d 100644
--- a/backend/src/plugins/Automod/triggers/threadArchive.ts
+++ b/backend/src/plugins/Automod/triggers/threadArchive.ts
@@ -1,6 +1,6 @@
 import { User, escapeBold, type Snowflake } from "discord.js";
 import * as t from "io-ts";
-import { tNullable } from "../../../utils";
+import { renderUsername, tNullable } from "../../../utils";
 import { automodTrigger } from "../helpers";
 
 interface ThreadArchiveResult {
@@ -48,7 +48,7 @@ export const ThreadArchiveTrigger = automodTrigger<ThreadArchiveResult>()({
     const parentName = matchResult.extra.matchedThreadParentName;
     const base = `Thread **#${threadName}** (\`${threadId}\`) has been archived in the **#${parentName}** (\`${parentId}\`) channel`;
     if (threadOwner) {
-      return `${base} by **${escapeBold(threadOwner.tag)}** (\`${threadOwner.id}\`)`;
+      return `${base} by **${escapeBold(renderUsername(threadOwner.tag))}** (\`${threadOwner.id}\`)`;
     }
     return base;
   },
diff --git a/backend/src/plugins/Automod/triggers/threadCreate.ts b/backend/src/plugins/Automod/triggers/threadCreate.ts
index 7b8aca71..dc613068 100644
--- a/backend/src/plugins/Automod/triggers/threadCreate.ts
+++ b/backend/src/plugins/Automod/triggers/threadCreate.ts
@@ -1,5 +1,6 @@
 import { User, escapeBold, type Snowflake } from "discord.js";
 import * as t from "io-ts";
+import { renderUsername } from "../../../utils.js";
 import { automodTrigger } from "../helpers";
 
 interface ThreadCreateResult {
@@ -40,7 +41,7 @@ export const ThreadCreateTrigger = automodTrigger<ThreadCreateResult>()({
     const parentName = matchResult.extra.matchedThreadParentName;
     const base = `Thread **#${threadName}** (\`${threadId}\`) has been created in the **#${parentName}** (\`${parentId}\`) channel`;
     if (threadOwner) {
-      return `${base} by **${escapeBold(threadOwner.tag)}** (\`${threadOwner.id}\`)`;
+      return `${base} by **${escapeBold(renderUsername(threadOwner.tag))}** (\`${threadOwner.id}\`)`;
     }
     return base;
   },
diff --git a/backend/src/plugins/Automod/triggers/threadDelete.ts b/backend/src/plugins/Automod/triggers/threadDelete.ts
index 489b5b4c..f27a1d0b 100644
--- a/backend/src/plugins/Automod/triggers/threadDelete.ts
+++ b/backend/src/plugins/Automod/triggers/threadDelete.ts
@@ -1,5 +1,6 @@
 import { User, escapeBold, type Snowflake } from "discord.js";
 import * as t from "io-ts";
+import { renderUsername } from "../../../utils.js";
 import { automodTrigger } from "../helpers";
 
 interface ThreadDeleteResult {
@@ -40,7 +41,7 @@ export const ThreadDeleteTrigger = automodTrigger<ThreadDeleteResult>()({
     const parentName = matchResult.extra.matchedThreadParentName;
     if (threadOwner) {
       return `Thread **#${threadName ?? "Unknown"}** (\`${threadId}\`) created by **${escapeBold(
-        threadOwner.tag,
+        renderUsername(threadOwner.tag),
       )}** (\`${threadOwner.id}\`) in the **#${parentName}** (\`${parentId}\`) channel has been deleted`;
     }
     return `Thread **#${
diff --git a/backend/src/plugins/Automod/triggers/threadUnarchive.ts b/backend/src/plugins/Automod/triggers/threadUnarchive.ts
index f6047f48..94c69ace 100644
--- a/backend/src/plugins/Automod/triggers/threadUnarchive.ts
+++ b/backend/src/plugins/Automod/triggers/threadUnarchive.ts
@@ -1,6 +1,6 @@
 import { User, escapeBold, type Snowflake } from "discord.js";
 import * as t from "io-ts";
-import { tNullable } from "../../../utils";
+import { renderUsername, tNullable } from "../../../utils";
 import { automodTrigger } from "../helpers";
 
 interface ThreadUnarchiveResult {
@@ -48,7 +48,7 @@ export const ThreadUnarchiveTrigger = automodTrigger<ThreadUnarchiveResult>()({
     const parentName = matchResult.extra.matchedThreadParentName;
     const base = `Thread **#${threadName}** (\`${threadId}\`) has been unarchived in the **#${parentName}** (\`${parentId}\`) channel`;
     if (threadOwner) {
-      return `${base} by **${escapeBold(threadOwner.tag)}** (\`${threadOwner.id}\`)`;
+      return `${base} by **${escapeBold(renderUsername(threadOwner.tag))}** (\`${threadOwner.id}\`)`;
     }
     return base;
   },
diff --git a/backend/src/plugins/BotControl/commands/ServersCmd.ts b/backend/src/plugins/BotControl/commands/ServersCmd.ts
index 23146d21..5cb62433 100644
--- a/backend/src/plugins/BotControl/commands/ServersCmd.ts
+++ b/backend/src/plugins/BotControl/commands/ServersCmd.ts
@@ -1,7 +1,7 @@
 import escapeStringRegexp from "escape-string-regexp";
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { isStaffPreFilter } from "../../../pluginUtils";
-import { createChunkedMessage, getUser, sorter } from "../../../utils";
+import { createChunkedMessage, getUser, renderUsername, sorter } from "../../../utils";
 import { botControlCmd } from "../types";
 
 export const ServersCmd = botControlCmd({
@@ -48,7 +48,9 @@ export const ServersCmd = botControlCmd({
         const lines = filteredGuilds.map((g) => {
           const paddedId = g.id.padEnd(longestId, " ");
           const owner = getUser(pluginData.client, g.ownerId);
-          return `\`${paddedId}\` **${g.name}** (${g.memberCount} members) (owner **${owner.tag}** \`${owner.id}\`)`;
+          return `\`${paddedId}\` **${g.name}** (${g.memberCount} members) (owner **${renderUsername(owner.tag)}** \`${
+            owner.id
+          }\`)`;
         });
         createChunkedMessage(msg.channel, lines.join("\n"));
       } else {
diff --git a/backend/src/plugins/Cases/functions/createCase.ts b/backend/src/plugins/Cases/functions/createCase.ts
index c16d937b..70717f51 100644
--- a/backend/src/plugins/Cases/functions/createCase.ts
+++ b/backend/src/plugins/Cases/functions/createCase.ts
@@ -1,23 +1,23 @@
 import type { Snowflake } from "discord.js";
 import { GuildPluginData } from "knub";
 import { logger } from "../../../logger";
-import { renderUserUsername, resolveUser } from "../../../utils";
+import { renderUsername, resolveUser } from "../../../utils";
 import { CaseArgs, CasesPluginType } from "../types";
 import { createCaseNote } from "./createCaseNote";
 import { postCaseToCaseLogChannel } from "./postToCaseLogChannel";
 
 export async function createCase(pluginData: GuildPluginData<CasesPluginType>, args: CaseArgs) {
   const user = await resolveUser(pluginData.client, args.userId);
-  const userName = renderUserUsername(user);
+  const userName = renderUsername(user.username, user.discriminator);
 
   const mod = await resolveUser(pluginData.client, args.modId);
-  const modName = mod.tag;
+  const modName = renderUsername(mod.username, mod.discriminator);
 
   let ppName: string | null = null;
   let ppId: Snowflake | null = null;
   if (args.ppId) {
     const pp = await resolveUser(pluginData.client, args.ppId);
-    ppName = pp.tag;
+    ppName = renderUsername(pp.username, pp.discriminator);
     ppId = pp.id;
   }
 
diff --git a/backend/src/plugins/Cases/functions/createCaseNote.ts b/backend/src/plugins/Cases/functions/createCaseNote.ts
index 92520b7d..71b11302 100644
--- a/backend/src/plugins/Cases/functions/createCaseNote.ts
+++ b/backend/src/plugins/Cases/functions/createCaseNote.ts
@@ -1,6 +1,6 @@
 import { GuildPluginData } from "knub";
 import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
-import { UnknownUser, resolveUser } from "../../../utils";
+import { UnknownUser, renderUsername, resolveUser } from "../../../utils";
 import { CaseNoteArgs, CasesPluginType } from "../types";
 import { postCaseToCaseLogChannel } from "./postToCaseLogChannel";
 import { resolveCaseId } from "./resolveCaseId";
@@ -16,7 +16,7 @@ export async function createCaseNote(pluginData: GuildPluginData<CasesPluginType
     throw new RecoverablePluginError(ERRORS.INVALID_USER);
   }
 
-  const modName = mod.tag;
+  const modName = renderUsername(mod);
 
   let body = args.body;
 
diff --git a/backend/src/plugins/InternalPoster/functions/sendMessage.ts b/backend/src/plugins/InternalPoster/functions/sendMessage.ts
index ec811240..3d4d6424 100644
--- a/backend/src/plugins/InternalPoster/functions/sendMessage.ts
+++ b/backend/src/plugins/InternalPoster/functions/sendMessage.ts
@@ -48,7 +48,7 @@ export async function sendMessage(
         ...content,
         ...(pluginData.client.user && {
           username: pluginData.client.user.username,
-          avatarURL: pluginData.client.user.avatarURL() || pluginData.client.user.defaultAvatarURL,
+          avatarURL: pluginData.client.user.displayAvatarURL(),
         }),
       })
       .then((apiMessage) => ({
diff --git a/backend/src/plugins/ModActions/commands/CasesModCmd.ts b/backend/src/plugins/ModActions/commands/CasesModCmd.ts
index 5b0e3273..a911091d 100644
--- a/backend/src/plugins/ModActions/commands/CasesModCmd.ts
+++ b/backend/src/plugins/ModActions/commands/CasesModCmd.ts
@@ -1,7 +1,7 @@
-import { APIEmbed, User } from "discord.js";
+import { APIEmbed, GuildMember, User } from "discord.js";
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { sendErrorMessage } from "../../../pluginUtils";
-import { emptyEmbedValue, resolveUser, trimLines } from "../../../utils";
+import { emptyEmbedValue, renderUsername, resolveMember, resolveUser, trimLines } from "../../../utils";
 import { asyncMap } from "../../../utils/async";
 import { createPaginatedMessage } from "../../../utils/createPaginatedMessage";
 import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields";
@@ -28,8 +28,10 @@ export const CasesModCmd = modActionsCmd({
 
   async run({ pluginData, message: msg, args }) {
     const modId = args.mod || msg.author.id;
-    const mod = await resolveUser(pluginData.client, modId);
-    const modName = mod instanceof User ? mod.tag : modId;
+    const mod =
+      (await resolveMember(pluginData.client, pluginData.guild, modId)) ||
+      (await resolveUser(pluginData.client, modId));
+    const modName = mod instanceof User ? renderUsername(mod) : modId;
 
     const casesPlugin = pluginData.getPlugin(CasesPlugin);
     const totalCases = await casesPlugin.getTotalCasesByMod(modId);
@@ -57,7 +59,7 @@ export const CasesModCmd = modActionsCmd({
         const embed = {
           author: {
             name: title,
-            icon_url: mod instanceof User ? mod.displayAvatarURL() : undefined,
+            icon_url: mod instanceof User || mod instanceof GuildMember ? mod.displayAvatarURL() : undefined,
           },
           fields: [
             ...getChunkedEmbedFields(emptyEmbedValue, lines.join("\n")),
diff --git a/backend/src/plugins/ModActions/commands/CasesUserCmd.ts b/backend/src/plugins/ModActions/commands/CasesUserCmd.ts
index 069ad31f..05ab65eb 100644
--- a/backend/src/plugins/ModActions/commands/CasesUserCmd.ts
+++ b/backend/src/plugins/ModActions/commands/CasesUserCmd.ts
@@ -1,9 +1,17 @@
-import { APIEmbed, User } from "discord.js";
+import { APIEmbed } from "discord.js";
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { CaseTypes } from "../../../data/CaseTypes";
 import { sendErrorMessage } from "../../../pluginUtils";
 import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
-import { UnknownUser, chunkArray, emptyEmbedValue, renderUserUsername, resolveUser, trimLines } from "../../../utils";
+import {
+  UnknownUser,
+  chunkArray,
+  emptyEmbedValue,
+  renderUsername,
+  resolveMember,
+  resolveUser,
+  trimLines,
+} from "../../../utils";
 import { asyncMap } from "../../../utils/async";
 import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields";
 import { getGuildPrefix } from "../../../utils/getGuildPrefix";
@@ -35,8 +43,10 @@ export const CasesUserCmd = modActionsCmd({
   ],
 
   async run({ pluginData, message: msg, args }) {
-    const user = await resolveUser(pluginData.client, args.user);
-    if (!user.id) {
+    const user =
+      (await resolveMember(pluginData.client, pluginData.guild, args.user)) ||
+      (await resolveUser(pluginData.client, args.user));
+    if (!user.id || user instanceof UnknownUser) {
       sendErrorMessage(pluginData, msg.channel, `User not found`);
       return;
     }
@@ -62,7 +72,7 @@ export const CasesUserCmd = modActionsCmd({
     const hiddenCases = cases.filter((c) => c.is_hidden);
 
     const userName =
-      user instanceof UnknownUser && cases.length ? cases[cases.length - 1].user_name : renderUserUsername(user);
+      user instanceof UnknownUser && cases.length ? cases[cases.length - 1].user_name : renderUsername(user);
 
     if (cases.length === 0) {
       msg.channel.send(`No cases found for **${userName}**`);
@@ -123,7 +133,7 @@ export const CasesUserCmd = modActionsCmd({
                 lineChunks.length === 1
                   ? `Cases for ${userName} (${lines.length} total)`
                   : `Cases ${chunkStart}–${chunkEnd} of ${lines.length} for ${userName}`,
-              icon_url: user instanceof User ? user.displayAvatarURL() : undefined,
+              icon_url: user.displayAvatarURL(),
             },
             fields: [
               ...getChunkedEmbedFields(emptyEmbedValue, linesInChunk.join("\n")),
diff --git a/backend/src/plugins/Post/util/actualPostCmd.ts b/backend/src/plugins/Post/util/actualPostCmd.ts
index c73a672b..29c3d5ec 100644
--- a/backend/src/plugins/Post/util/actualPostCmd.ts
+++ b/backend/src/plugins/Post/util/actualPostCmd.ts
@@ -4,7 +4,7 @@ import { GuildPluginData } from "knub";
 import moment from "moment-timezone";
 import { registerUpcomingScheduledPost } from "../../../data/loops/upcomingScheduledPostsLoop";
 import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { DBDateFormat, MINUTES, StrictMessageContent, errorMessage } from "../../../utils";
+import { DBDateFormat, MINUTES, StrictMessageContent, errorMessage, renderUsername } from "../../../utils";
 import { LogsPlugin } from "../../Logs/LogsPlugin";
 import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
 import { PostPluginType } from "../types";
@@ -122,7 +122,7 @@ export async function actualPostCmd(
 
     const post = await pluginData.state.scheduledPosts.create({
       author_id: msg.author.id,
-      author_name: msg.author.tag,
+      author_name: renderUsername(msg.author),
       channel_id: targetChannel.id,
       content,
       attachments: [...msg.attachments.values()],
diff --git a/backend/src/plugins/Starboard/util/createStarboardEmbedFromMessage.ts b/backend/src/plugins/Starboard/util/createStarboardEmbedFromMessage.ts
index 5f028c0a..5126f20f 100644
--- a/backend/src/plugins/Starboard/util/createStarboardEmbedFromMessage.ts
+++ b/backend/src/plugins/Starboard/util/createStarboardEmbedFromMessage.ts
@@ -1,6 +1,6 @@
 import { GuildChannel, Message } from "discord.js";
 import path from "path";
-import { EMPTY_CHAR, EmbedWith } from "../../../utils";
+import { EMPTY_CHAR, EmbedWith, renderUsername } from "../../../utils";
 
 const imageAttachmentExtensions = ["jpeg", "jpg", "png", "gif", "webp"];
 const audioAttachmentExtensions = ["wav", "mp3", "m4a"];
@@ -18,7 +18,7 @@ export function createStarboardEmbedFromMessage(
       text: `#${(msg.channel as GuildChannel).name}`,
     },
     author: {
-      name: msg.author.tag,
+      name: renderUsername(msg.author),
     },
     fields: [],
     timestamp: msg.createdAt.toISOString(),
@@ -28,7 +28,7 @@ export function createStarboardEmbedFromMessage(
     embed.color = color;
   }
 
-  embed.author.icon_url = msg.author.displayAvatarURL();
+  embed.author.icon_url = (msg.member || msg.author).displayAvatarURL();
 
   // The second condition here checks for messages with only an image link that is then embedded.
   // The message content in that case is hidden by the Discord client, so we hide it here too.
diff --git a/backend/src/plugins/Utility/commands/AboutCmd.ts b/backend/src/plugins/Utility/commands/AboutCmd.ts
index 53408d71..d4188ad7 100644
--- a/backend/src/plugins/Utility/commands/AboutCmd.ts
+++ b/backend/src/plugins/Utility/commands/AboutCmd.ts
@@ -100,8 +100,8 @@ export const AboutCmd = utilityCmd({
     }
 
     // Use the bot avatar as the embed image
-    if (pluginData.client.user!.avatarURL()) {
-      aboutEmbed.thumbnail = { url: pluginData.client.user!.avatarURL()! };
+    if (pluginData.client.user!.displayAvatarURL()) {
+      aboutEmbed.thumbnail = { url: pluginData.client.user!.displayAvatarURL()! };
     }
 
     msg.channel.send({ embeds: [aboutEmbed] });
diff --git a/backend/src/plugins/Utility/commands/AvatarCmd.ts b/backend/src/plugins/Utility/commands/AvatarCmd.ts
index ef44a2cb..b1215df6 100644
--- a/backend/src/plugins/Utility/commands/AvatarCmd.ts
+++ b/backend/src/plugins/Utility/commands/AvatarCmd.ts
@@ -1,7 +1,7 @@
 import { APIEmbed, ImageFormat } from "discord.js";
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { sendErrorMessage } from "../../../pluginUtils";
-import { UnknownUser, renderUserUsername } from "../../../utils";
+import { UnknownUser, renderUsername } from "../../../utils";
 import { utilityCmd } from "../types";
 
 export const AvatarCmd = utilityCmd({
@@ -10,17 +10,17 @@ export const AvatarCmd = utilityCmd({
   permission: "can_avatar",
 
   signature: {
-    user: ct.resolvedUserLoose({ required: false }),
+    user: ct.resolvedMember({ required: false }) || ct.resolvedUserLoose({ required: false }),
   },
 
   async run({ message: msg, args, pluginData }) {
-    const user = args.user || msg.author;
+    const user = args.user || msg.member || msg.author;
     if (!(user instanceof UnknownUser)) {
       const embed: APIEmbed = {
         image: {
           url: user.displayAvatarURL({ extension: ImageFormat.PNG, size: 2048 }),
         },
-        title: `Avatar of ${renderUserUsername(user)}:`,
+        title: `Avatar of ${renderUsername(user)}:`,
       };
       msg.channel.send({ embeds: [embed] });
     } else {
diff --git a/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts b/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts
index 2de8b4db..58d34d56 100644
--- a/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts
@@ -13,7 +13,6 @@ import {
   trimLines,
   UnknownUser,
 } from "../../../utils";
-import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
 import { UtilityPluginType } from "../types";
 
 const MAX_ROLES_TO_DISPLAY = 15;
@@ -40,13 +39,11 @@ export async function getUserInfoEmbed(
     fields: [],
   };
 
-  const timeAndDate = pluginData.getPlugin(TimeAndDatePlugin);
-
   embed.author = {
     name: `${user.bot ? "Bot" : "User"}:  ${renderUsername(user)}`,
   };
 
-  const avatarURL = user.displayAvatarURL();
+  const avatarURL = (member || user).displayAvatarURL();
   embed.author.icon_url = avatarURL;
 
   if (compact) {
diff --git a/backend/src/plugins/Utility/search.ts b/backend/src/plugins/Utility/search.ts
index 19710b58..632a85a7 100644
--- a/backend/src/plugins/Utility/search.ts
+++ b/backend/src/plugins/Utility/search.ts
@@ -14,7 +14,7 @@ import { ArgsFromSignatureOrArray, GuildPluginData } from "knub";
 import moment from "moment-timezone";
 import { RegExpRunner, allowTimeout } from "../../RegExpRunner";
 import { getBaseUrl, sendErrorMessage } from "../../pluginUtils";
-import { MINUTES, multiSorter, renderUserUsername, sorter, trimLines } from "../../utils";
+import { MINUTES, multiSorter, renderUsername, sorter, trimLines } from "../../utils";
 import { asyncFilter } from "../../utils/async";
 import { hasDiscordPermissions } from "../../utils/hasDiscordPermissions";
 import { InvalidRegexError, inputPatternToRegExp } from "../../validatorUtils";
@@ -381,7 +381,7 @@ async function performMemberSearch(
         return true;
       }
 
-      const fullUsername = renderUserUsername(member.user);
+      const fullUsername = renderUsername(member.user);
       if (await execRegExp(queryRegex, fullUsername).catch(allowTimeout)) return true;
 
       return false;
@@ -448,7 +448,7 @@ async function performBanSearch(
 
     const execRegExp = getOptimizedRegExpRunner(pluginData, isSafeRegex);
     matchingBans = await asyncFilter(matchingBans, async (user) => {
-      const fullUsername = renderUserUsername(user);
+      const fullUsername = renderUsername(user);
       if (await execRegExp(queryRegex, fullUsername).catch(allowTimeout)) return true;
       return false;
     });
@@ -492,10 +492,10 @@ function formatSearchResultList(members: Array<GuildMember | User>): string {
     const paddedId = member.id.padEnd(longestId, " ");
     let line;
     if (member instanceof GuildMember) {
-      line = `${paddedId} ${renderUserUsername(member.user)}`;
+      line = `${paddedId} ${renderUsername(member.user)}`;
       if (member.nickname) line += ` (${member.nickname})`;
     } else {
-      line = `${paddedId} ${member.tag}`;
+      line = `${paddedId} ${renderUsername(member)}`;
     }
     return line;
   });
diff --git a/backend/src/utils.ts b/backend/src/utils.ts
index ee6b556c..5c795072 100644
--- a/backend/src/utils.ts
+++ b/backend/src/utils.ts
@@ -1603,9 +1603,12 @@ export function isTruthy<T>(value: T): value is Exclude<T, false | null | undefi
 
 export const DBDateFormat = "YYYY-MM-DD HH:mm:ss";
 
-export function renderUsername(username: User): string;
-export function renderUsername(username: string, discriminator?: string): string;
-export function renderUsername(username: string | User, discriminator?: string): string {
+// TODO: Fix overloads
+//export function renderUsername(username: GuildMember): string;
+//export function renderUsername(username: User): string;
+//export function renderUsername(username: string, discriminator?: string): string;
+export function renderUsername(username: string | User | GuildMember, discriminator?: string): string {
+  if (username instanceof GuildMember) return username.user.tag;
   if (username instanceof User) return username.tag;
   if (discriminator === "0" || discriminator === "0000") {
     return username;
diff --git a/backend/src/utils/templateSafeObjects.ts b/backend/src/utils/templateSafeObjects.ts
index fbd27754..33e36971 100644
--- a/backend/src/utils/templateSafeObjects.ts
+++ b/backend/src/utils/templateSafeObjects.ts
@@ -52,7 +52,7 @@ export class TemplateSafeUser extends TemplateSafeValueContainer {
   globalName?: string;
   mention: string;
   tag: string;
-  avatarURL?: string;
+  avatarURL: string;
   bot?: boolean;
   createdAt?: number;
   renderedUsername: string;
@@ -92,7 +92,7 @@ export class TemplateSafeMember extends TemplateSafeUser {
   nick: string;
   roles: TemplateSafeRole[];
   joinedAt?: number;
-  // guildAvatarURL: string, Once DJS supports per-server avatars
+  guildAvatarURL: string;
   guildName: string;
 
   constructor(data: InputProps<TemplateSafeMember>) {
@@ -261,7 +261,7 @@ export function userToTemplateSafeUser(user: User | UnknownUser): TemplateSafeUs
     globalName: user.globalName,
     mention: `<@${user.id}>`,
     tag: user.tag,
-    avatarURL: user.displayAvatarURL?.(),
+    avatarURL: user.displayAvatarURL(),
     bot: user.bot,
     createdAt: user.createdTimestamp,
     renderedUsername: renderUserUsername(user),
@@ -287,6 +287,7 @@ export function memberToTemplateSafeMember(member: GuildMember | PartialGuildMem
     nick: member.nickname ?? "*None*",
     roles: [...member.roles.cache.mapValues((r) => roleToTemplateSafeRole(r)).values()],
     joinedAt: member.joinedTimestamp ?? undefined,
+    guildAvatarURL: member.displayAvatarURL(),
     guildName: member.guild.name,
   });
 }

From 4d0161a49f77e28ef89a819d7124a8239fd1a8c9 Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 15:50:01 +0000
Subject: [PATCH 10/17] oh god almeida looked at my code

Signed-off-by: GitHub <noreply@github.com>
---
 backend/src/plugins/Automod/triggers/threadArchive.ts   | 2 +-
 backend/src/plugins/Automod/triggers/threadCreate.ts    | 2 +-
 backend/src/plugins/Automod/triggers/threadDelete.ts    | 2 +-
 backend/src/plugins/Automod/triggers/threadUnarchive.ts | 2 +-
 backend/src/plugins/BotControl/commands/ServersCmd.ts   | 7 ++++---
 5 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/backend/src/plugins/Automod/triggers/threadArchive.ts b/backend/src/plugins/Automod/triggers/threadArchive.ts
index 8a692f6d..274732f5 100644
--- a/backend/src/plugins/Automod/triggers/threadArchive.ts
+++ b/backend/src/plugins/Automod/triggers/threadArchive.ts
@@ -48,7 +48,7 @@ export const ThreadArchiveTrigger = automodTrigger<ThreadArchiveResult>()({
     const parentName = matchResult.extra.matchedThreadParentName;
     const base = `Thread **#${threadName}** (\`${threadId}\`) has been archived in the **#${parentName}** (\`${parentId}\`) channel`;
     if (threadOwner) {
-      return `${base} by **${escapeBold(renderUsername(threadOwner.tag))}** (\`${threadOwner.id}\`)`;
+      return `${base} by **${escapeBold(renderUsername(threadOwner))}** (\`${threadOwner.id}\`)`;
     }
     return base;
   },
diff --git a/backend/src/plugins/Automod/triggers/threadCreate.ts b/backend/src/plugins/Automod/triggers/threadCreate.ts
index dc613068..793708e4 100644
--- a/backend/src/plugins/Automod/triggers/threadCreate.ts
+++ b/backend/src/plugins/Automod/triggers/threadCreate.ts
@@ -41,7 +41,7 @@ export const ThreadCreateTrigger = automodTrigger<ThreadCreateResult>()({
     const parentName = matchResult.extra.matchedThreadParentName;
     const base = `Thread **#${threadName}** (\`${threadId}\`) has been created in the **#${parentName}** (\`${parentId}\`) channel`;
     if (threadOwner) {
-      return `${base} by **${escapeBold(renderUsername(threadOwner.tag))}** (\`${threadOwner.id}\`)`;
+      return `${base} by **${escapeBold(renderUsername(threadOwner))}** (\`${threadOwner.id}\`)`;
     }
     return base;
   },
diff --git a/backend/src/plugins/Automod/triggers/threadDelete.ts b/backend/src/plugins/Automod/triggers/threadDelete.ts
index f27a1d0b..3c108bb0 100644
--- a/backend/src/plugins/Automod/triggers/threadDelete.ts
+++ b/backend/src/plugins/Automod/triggers/threadDelete.ts
@@ -41,7 +41,7 @@ export const ThreadDeleteTrigger = automodTrigger<ThreadDeleteResult>()({
     const parentName = matchResult.extra.matchedThreadParentName;
     if (threadOwner) {
       return `Thread **#${threadName ?? "Unknown"}** (\`${threadId}\`) created by **${escapeBold(
-        renderUsername(threadOwner.tag),
+        renderUsername(threadOwner),
       )}** (\`${threadOwner.id}\`) in the **#${parentName}** (\`${parentId}\`) channel has been deleted`;
     }
     return `Thread **#${
diff --git a/backend/src/plugins/Automod/triggers/threadUnarchive.ts b/backend/src/plugins/Automod/triggers/threadUnarchive.ts
index 94c69ace..0a081c2b 100644
--- a/backend/src/plugins/Automod/triggers/threadUnarchive.ts
+++ b/backend/src/plugins/Automod/triggers/threadUnarchive.ts
@@ -48,7 +48,7 @@ export const ThreadUnarchiveTrigger = automodTrigger<ThreadUnarchiveResult>()({
     const parentName = matchResult.extra.matchedThreadParentName;
     const base = `Thread **#${threadName}** (\`${threadId}\`) has been unarchived in the **#${parentName}** (\`${parentId}\`) channel`;
     if (threadOwner) {
-      return `${base} by **${escapeBold(renderUsername(threadOwner.tag))}** (\`${threadOwner.id}\`)`;
+      return `${base} by **${escapeBold(renderUsername(threadOwner))}** (\`${threadOwner.id}\`)`;
     }
     return base;
   },
diff --git a/backend/src/plugins/BotControl/commands/ServersCmd.ts b/backend/src/plugins/BotControl/commands/ServersCmd.ts
index 5cb62433..3658a36c 100644
--- a/backend/src/plugins/BotControl/commands/ServersCmd.ts
+++ b/backend/src/plugins/BotControl/commands/ServersCmd.ts
@@ -48,9 +48,10 @@ export const ServersCmd = botControlCmd({
         const lines = filteredGuilds.map((g) => {
           const paddedId = g.id.padEnd(longestId, " ");
           const owner = getUser(pluginData.client, g.ownerId);
-          return `\`${paddedId}\` **${g.name}** (${g.memberCount} members) (owner **${renderUsername(owner.tag)}** \`${
-            owner.id
-          }\`)`;
+          return `\`${paddedId}\` **${g.name}** (${g.memberCount} members) (owner **${renderUsername(
+            owner.username,
+            owner.discriminator,
+          )}** \`${owner.id}\`)`;
         });
         createChunkedMessage(msg.channel, lines.join("\n"));
       } else {

From bfc90093dc83d0c891d7ea542852835f1337e2d0 Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 15:57:23 +0000
Subject: [PATCH 11/17] yeet renderUserUsername

Signed-off-by: GitHub <noreply@github.com>
---
 backend/src/plugins/Automod/triggers/roleAdded.ts    |  4 ++--
 backend/src/plugins/Automod/triggers/roleRemoved.ts  |  4 ++--
 .../BotControl/commands/AddDashboardUserCmd.ts       |  4 ++--
 .../BotControl/commands/ListDashboardPermsCmd.ts     |  6 +++---
 .../BotControl/commands/ListDashboardUsersCmd.ts     |  4 ++--
 .../BotControl/commands/RemoveDashboardUserCmd.ts    |  4 ++--
 .../src/plugins/ModActions/commands/AddCaseCmd.ts    |  4 ++--
 backend/src/plugins/ModActions/commands/BanCmd.ts    |  4 ++--
 backend/src/plugins/ModActions/commands/NoteCmd.ts   |  4 ++--
 backend/src/plugins/ModActions/commands/WarnCmd.ts   |  4 ++--
 .../ModActions/events/PostAlertOnMemberJoinEvt.ts    |  4 ++--
 .../ModActions/functions/actualKickMemberCmd.ts      |  4 ++--
 .../ModActions/functions/actualMuteUserCmd.ts        | 10 +++++-----
 .../ModActions/functions/actualUnmuteUserCmd.ts      |  6 +++---
 backend/src/plugins/Mutes/commands/MutesCmd.ts       |  6 +++---
 backend/src/plugins/NameHistory/commands/NamesCmd.ts |  4 ++--
 .../ReactionRoles/util/addMemberPendingRoleChange.ts |  6 ++----
 .../plugins/Slowmode/commands/SlowmodeClearCmd.ts    |  8 ++++----
 backend/src/plugins/UsernameSaver/updateUsername.ts  |  4 ++--
 backend/src/plugins/Utility/commands/LevelCmd.ts     |  4 ++--
 .../src/plugins/Utility/commands/VcdisconnectCmd.ts  |  4 ++--
 backend/src/plugins/Utility/commands/VcmoveCmd.ts    | 12 ++++--------
 backend/src/utils.ts                                 |  8 ++------
 backend/src/utils/templateSafeObjects.ts             |  6 +++---
 24 files changed, 59 insertions(+), 69 deletions(-)

diff --git a/backend/src/plugins/Automod/triggers/roleAdded.ts b/backend/src/plugins/Automod/triggers/roleAdded.ts
index dc62f163..754be1b3 100644
--- a/backend/src/plugins/Automod/triggers/roleAdded.ts
+++ b/backend/src/plugins/Automod/triggers/roleAdded.ts
@@ -1,6 +1,6 @@
 import { Snowflake } from "discord.js";
 import * as t from "io-ts";
-import { renderUserUsername } from "../../../utils";
+import { renderUsername } from "../../../utils";
 import { consumeIgnoredRoleChange } from "../functions/ignoredRoleChanges";
 import { automodTrigger } from "../helpers";
 
@@ -38,7 +38,7 @@ export const RoleAddedTrigger = automodTrigger<RoleAddedMatchResult>()({
     const role = pluginData.guild.roles.cache.get(matchResult.extra.matchedRoleId as Snowflake);
     const roleName = role?.name || "Unknown";
     const member = contexts[0].member!;
-    const memberName = `**${renderUserUsername(member.user)}** (\`${member.id}\`)`;
+    const memberName = `**${renderUsername(member.user)}** (\`${member.id}\`)`;
     return `Role ${roleName} (\`${matchResult.extra.matchedRoleId}\`) was added to ${memberName}`;
   },
 });
diff --git a/backend/src/plugins/Automod/triggers/roleRemoved.ts b/backend/src/plugins/Automod/triggers/roleRemoved.ts
index 65624827..fc5d5ae3 100644
--- a/backend/src/plugins/Automod/triggers/roleRemoved.ts
+++ b/backend/src/plugins/Automod/triggers/roleRemoved.ts
@@ -1,6 +1,6 @@
 import { Snowflake } from "discord.js";
 import * as t from "io-ts";
-import { renderUserUsername } from "../../../utils";
+import { renderUsername } from "../../../utils";
 import { consumeIgnoredRoleChange } from "../functions/ignoredRoleChanges";
 import { automodTrigger } from "../helpers";
 
@@ -38,7 +38,7 @@ export const RoleRemovedTrigger = automodTrigger<RoleAddedMatchResult>()({
     const role = pluginData.guild.roles.cache.get(matchResult.extra.matchedRoleId as Snowflake);
     const roleName = role?.name || "Unknown";
     const member = contexts[0].member!;
-    const memberName = `**${renderUserUsername(member.user)}** (\`${member.id}\`)`;
+    const memberName = `**${renderUsername(member.user)}** (\`${member.id}\`)`;
     return `Role ${roleName} (\`${matchResult.extra.matchedRoleId}\`) was removed from ${memberName}`;
   },
 });
diff --git a/backend/src/plugins/BotControl/commands/AddDashboardUserCmd.ts b/backend/src/plugins/BotControl/commands/AddDashboardUserCmd.ts
index c1259594..0cb87f95 100644
--- a/backend/src/plugins/BotControl/commands/AddDashboardUserCmd.ts
+++ b/backend/src/plugins/BotControl/commands/AddDashboardUserCmd.ts
@@ -1,7 +1,7 @@
 import { ApiPermissions } from "@shared/apiPermissions";
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { isStaffPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { renderUserUsername } from "../../../utils";
+import { renderUsername } from "../../../utils";
 import { botControlCmd } from "../types";
 
 export const AddDashboardUserCmd = botControlCmd({
@@ -35,7 +35,7 @@ export const AddDashboardUserCmd = botControlCmd({
       await pluginData.state.apiPermissionAssignments.addUser(args.guildId, user.id, [ApiPermissions.EditConfig]);
     }
 
-    const userNameList = args.users.map((user) => `<@!${user.id}> (**${renderUserUsername(user)}**, \`${user.id}\`)`);
+    const userNameList = args.users.map((user) => `<@!${user.id}> (**${renderUsername(user)}**, \`${user.id}\`)`);
     sendSuccessMessage(
       pluginData,
       msg.channel,
diff --git a/backend/src/plugins/BotControl/commands/ListDashboardPermsCmd.ts b/backend/src/plugins/BotControl/commands/ListDashboardPermsCmd.ts
index 18c7d0d7..7c6d2aa5 100644
--- a/backend/src/plugins/BotControl/commands/ListDashboardPermsCmd.ts
+++ b/backend/src/plugins/BotControl/commands/ListDashboardPermsCmd.ts
@@ -2,7 +2,7 @@ import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { AllowedGuild } from "../../../data/entities/AllowedGuild";
 import { ApiPermissionAssignment } from "../../../data/entities/ApiPermissionAssignment";
 import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { renderUserUsername, resolveUser } from "../../../utils";
+import { renderUsername, resolveUser } from "../../../utils";
 import { botControlCmd } from "../types";
 
 export const ListDashboardPermsCmd = botControlCmd({
@@ -42,7 +42,7 @@ export const ListDashboardPermsCmd = botControlCmd({
 
     // If we have user, always display which guilds they have permissions in (or only specified guild permissions)
     if (args.user) {
-      const userInfo = `**${renderUserUsername(args.user)}** (\`${args.user.id}\`)`;
+      const userInfo = `**${renderUsername(args.user)}** (\`${args.user.id}\`)`;
 
       for (const assignment of existingUserAssignment!) {
         if (guild != null && assignment.guild_id !== args.guildId) continue;
@@ -74,7 +74,7 @@ export const ListDashboardPermsCmd = botControlCmd({
       finalMessage += `The server ${guildInfo} has the following assigned permissions:\n`; // Double \n for consistency with AddDashboardUserCmd
       for (const assignment of existingGuildAssignment) {
         const user = await resolveUser(pluginData.client, assignment.target_id);
-        finalMessage += `\n**${renderUserUsername(user)}**, \`${assignment.target_id}\`: ${assignment.permissions.join(
+        finalMessage += `\n**${renderUsername(user)}**, \`${assignment.target_id}\`: ${assignment.permissions.join(
           ", ",
         )}`;
       }
diff --git a/backend/src/plugins/BotControl/commands/ListDashboardUsersCmd.ts b/backend/src/plugins/BotControl/commands/ListDashboardUsersCmd.ts
index 36f1432f..1d3c1ffe 100644
--- a/backend/src/plugins/BotControl/commands/ListDashboardUsersCmd.ts
+++ b/backend/src/plugins/BotControl/commands/ListDashboardUsersCmd.ts
@@ -1,6 +1,6 @@
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { renderUserUsername, resolveUser } from "../../../utils";
+import { renderUsername, resolveUser } from "../../../utils";
 import { botControlCmd } from "../types";
 
 export const ListDashboardUsersCmd = botControlCmd({
@@ -27,7 +27,7 @@ export const ListDashboardUsersCmd = botControlCmd({
     );
     const userNameList = users.map(
       ({ user, permission }) =>
-        `<@!${user.id}> (**${renderUserUsername(user)}**, \`${user.id}\`): ${permission.permissions.join(", ")}`,
+        `<@!${user.id}> (**${renderUsername(user)}**, \`${user.id}\`): ${permission.permissions.join(", ")}`,
     );
 
     sendSuccessMessage(
diff --git a/backend/src/plugins/BotControl/commands/RemoveDashboardUserCmd.ts b/backend/src/plugins/BotControl/commands/RemoveDashboardUserCmd.ts
index 3a90683c..c3d1ec99 100644
--- a/backend/src/plugins/BotControl/commands/RemoveDashboardUserCmd.ts
+++ b/backend/src/plugins/BotControl/commands/RemoveDashboardUserCmd.ts
@@ -1,6 +1,6 @@
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { isStaffPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { renderUserUsername } from "../../../utils";
+import { renderUsername } from "../../../utils";
 import { botControlCmd } from "../types";
 
 export const RemoveDashboardUserCmd = botControlCmd({
@@ -34,7 +34,7 @@ export const RemoveDashboardUserCmd = botControlCmd({
       await pluginData.state.apiPermissionAssignments.removeUser(args.guildId, user.id);
     }
 
-    const userNameList = args.users.map((user) => `<@!${user.id}> (**${renderUserUsername(user)}**, \`${user.id}\`)`);
+    const userNameList = args.users.map((user) => `<@!${user.id}> (**${renderUsername(user)}**, \`${user.id}\`)`);
     sendSuccessMessage(
       pluginData,
       msg.channel,
diff --git a/backend/src/plugins/ModActions/commands/AddCaseCmd.ts b/backend/src/plugins/ModActions/commands/AddCaseCmd.ts
index 43575463..3f8b9dfc 100644
--- a/backend/src/plugins/ModActions/commands/AddCaseCmd.ts
+++ b/backend/src/plugins/ModActions/commands/AddCaseCmd.ts
@@ -3,7 +3,7 @@ import { CaseTypes } from "../../../data/CaseTypes";
 import { Case } from "../../../data/entities/Case";
 import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
 import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { renderUserUsername, resolveMember, resolveUser } from "../../../utils";
+import { renderUsername, resolveMember, resolveUser } from "../../../utils";
 import { LogsPlugin } from "../../Logs/LogsPlugin";
 import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
 import { modActionsCmd } from "../types";
@@ -75,7 +75,7 @@ export const AddCaseCmd = modActionsCmd({
       sendSuccessMessage(
         pluginData,
         msg.channel,
-        `Case #${theCase.case_number} created for **${renderUserUsername(user)}**`,
+        `Case #${theCase.case_number} created for **${renderUsername(user)}**`,
       );
     } else {
       sendSuccessMessage(pluginData, msg.channel, `Case #${theCase.case_number} created`);
diff --git a/backend/src/plugins/ModActions/commands/BanCmd.ts b/backend/src/plugins/ModActions/commands/BanCmd.ts
index 9d32cd10..3e66e8a2 100644
--- a/backend/src/plugins/ModActions/commands/BanCmd.ts
+++ b/backend/src/plugins/ModActions/commands/BanCmd.ts
@@ -5,7 +5,7 @@ import { CaseTypes } from "../../../data/CaseTypes";
 import { clearExpiringTempban, registerExpiringTempban } from "../../../data/loops/expiringTempbansLoop";
 import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
 import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
-import { renderUserUsername, resolveMember, resolveUser } from "../../../utils";
+import { renderUsername, resolveMember, resolveUser } from "../../../utils";
 import { banLock } from "../../../utils/lockNameHelpers";
 import { waitForButtonConfirm } from "../../../utils/waitForInteraction";
 import { LogsPlugin } from "../../Logs/LogsPlugin";
@@ -207,7 +207,7 @@ export const BanCmd = modActionsCmd({
     // Confirm the action to the moderator
     let response = "";
     if (!forceban) {
-      response = `Banned **${renderUserUsername(user)}** ${forTime}(Case #${banResult.case.case_number})`;
+      response = `Banned **${renderUsername(user)}** ${forTime}(Case #${banResult.case.case_number})`;
       if (banResult.notifyResult.text) response += ` (${banResult.notifyResult.text})`;
     } else {
       response = `Member forcebanned ${forTime}(Case #${banResult.case.case_number})`;
diff --git a/backend/src/plugins/ModActions/commands/NoteCmd.ts b/backend/src/plugins/ModActions/commands/NoteCmd.ts
index b13ed498..edb2202d 100644
--- a/backend/src/plugins/ModActions/commands/NoteCmd.ts
+++ b/backend/src/plugins/ModActions/commands/NoteCmd.ts
@@ -1,7 +1,7 @@
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { CaseTypes } from "../../../data/CaseTypes";
 import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { renderUserUsername, resolveUser } from "../../../utils";
+import { renderUsername, resolveUser } from "../../../utils";
 import { CasesPlugin } from "../../Cases/CasesPlugin";
 import { LogsPlugin } from "../../Logs/LogsPlugin";
 import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
@@ -29,7 +29,7 @@ export const NoteCmd = modActionsCmd({
       return;
     }
 
-    const userName = renderUserUsername(user);
+    const userName = renderUsername(user);
     const reason = formatReasonWithAttachments(args.note, [...msg.attachments.values()]);
 
     const casesPlugin = pluginData.getPlugin(CasesPlugin);
diff --git a/backend/src/plugins/ModActions/commands/WarnCmd.ts b/backend/src/plugins/ModActions/commands/WarnCmd.ts
index c8192015..f917c55e 100644
--- a/backend/src/plugins/ModActions/commands/WarnCmd.ts
+++ b/backend/src/plugins/ModActions/commands/WarnCmd.ts
@@ -1,7 +1,7 @@
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { CaseTypes } from "../../../data/CaseTypes";
 import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { errorMessage, renderUserUsername, resolveMember, resolveUser } from "../../../utils";
+import { errorMessage, renderUsername, resolveMember, resolveUser } from "../../../utils";
 import { waitForButtonConfirm } from "../../../utils/waitForInteraction";
 import { CasesPlugin } from "../../Cases/CasesPlugin";
 import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
@@ -106,7 +106,7 @@ export const WarnCmd = modActionsCmd({
     sendSuccessMessage(
       pluginData,
       msg.channel,
-      `Warned **${renderUserUsername(memberToWarn.user)}** (Case #${warnResult.case.case_number})${messageResultText}`,
+      `Warned **${renderUsername(memberToWarn.user)}** (Case #${warnResult.case.case_number})${messageResultText}`,
     );
   },
 });
diff --git a/backend/src/plugins/ModActions/events/PostAlertOnMemberJoinEvt.ts b/backend/src/plugins/ModActions/events/PostAlertOnMemberJoinEvt.ts
index 677fb603..7874c241 100644
--- a/backend/src/plugins/ModActions/events/PostAlertOnMemberJoinEvt.ts
+++ b/backend/src/plugins/ModActions/events/PostAlertOnMemberJoinEvt.ts
@@ -1,5 +1,5 @@
 import { PermissionsBitField, Snowflake, TextChannel } from "discord.js";
-import { renderUserUsername, resolveMember } from "../../../utils";
+import { renderUsername, resolveMember } from "../../../utils";
 import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
 import { LogsPlugin } from "../../Logs/LogsPlugin";
 import { modActionsEvt } from "../types";
@@ -46,7 +46,7 @@ export const PostAlertOnMemberJoinEvt = modActionsEvt({
       }
 
       await alertChannel.send(
-        `<@!${member.id}> (${renderUserUsername(member.user)} \`${member.id}\`) joined with ${
+        `<@!${member.id}> (${renderUsername(member.user)} \`${member.id}\`) joined with ${
           actions.length
         } prior record(s)`,
       );
diff --git a/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts b/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts
index 73a1e2d9..fac3f906 100644
--- a/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts
+++ b/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts
@@ -3,7 +3,7 @@ import { GuildPluginData } from "knub";
 import { hasPermission } from "knub/helpers";
 import { LogType } from "../../../data/LogType";
 import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { DAYS, SECONDS, errorMessage, renderUserUsername, resolveMember, resolveUser } from "../../../utils";
+import { DAYS, SECONDS, errorMessage, renderUsername, resolveMember, resolveUser } from "../../../utils";
 import { IgnoredEventType, ModActionsPluginType } from "../types";
 import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
 import { ignoreEvent } from "./ignoreEvent";
@@ -103,7 +103,7 @@ export async function actualKickMemberCmd(
   }
 
   // Confirm the action to the moderator
-  let response = `Kicked **${renderUserUsername(memberToKick.user)}** (Case #${kickResult.case.case_number})`;
+  let response = `Kicked **${renderUsername(memberToKick.user)}** (Case #${kickResult.case.case_number})`;
 
   if (kickResult.notifyResult.text) response += ` (${kickResult.notifyResult.text})`;
   sendSuccessMessage(pluginData, msg.channel, response);
diff --git a/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts b/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts
index 5c628c4e..2f108410 100644
--- a/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts
+++ b/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts
@@ -4,7 +4,7 @@ import { GuildPluginData } from "knub";
 import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
 import { logger } from "../../../logger";
 import { hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { UnknownUser, asSingleLine, isDiscordAPIError, renderUserUsername } from "../../../utils";
+import { UnknownUser, asSingleLine, isDiscordAPIError, renderUsername } from "../../../utils";
 import { MutesPlugin } from "../../Mutes/MutesPlugin";
 import { MuteResult } from "../../Mutes/types";
 import { ModActionsPluginType } from "../types";
@@ -86,24 +86,24 @@ export async function actualMuteUserCmd(
   if (args.time) {
     if (muteResult.updatedExistingMute) {
       response = asSingleLine(`
-        Updated **${renderUserUsername(user)}**'s
+        Updated **${renderUsername(user)}**'s
         mute to ${timeUntilUnmute} (Case #${muteResult.case.case_number})
       `);
     } else {
       response = asSingleLine(`
-        Muted **${renderUserUsername(user)}**
+        Muted **${renderUsername(user)}**
         for ${timeUntilUnmute} (Case #${muteResult.case.case_number})
       `);
     }
   } else {
     if (muteResult.updatedExistingMute) {
       response = asSingleLine(`
-        Updated **${renderUserUsername(user)}**'s
+        Updated **${renderUsername(user)}**'s
         mute to indefinite (Case #${muteResult.case.case_number})
       `);
     } else {
       response = asSingleLine(`
-        Muted **${renderUserUsername(user)}**
+        Muted **${renderUsername(user)}**
         indefinitely (Case #${muteResult.case.case_number})
       `);
     }
diff --git a/backend/src/plugins/ModActions/functions/actualUnmuteUserCmd.ts b/backend/src/plugins/ModActions/functions/actualUnmuteUserCmd.ts
index d70a219c..5b28aee7 100644
--- a/backend/src/plugins/ModActions/functions/actualUnmuteUserCmd.ts
+++ b/backend/src/plugins/ModActions/functions/actualUnmuteUserCmd.ts
@@ -3,7 +3,7 @@ import humanizeDuration from "humanize-duration";
 import { GuildPluginData } from "knub";
 import { hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
 import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin";
-import { UnknownUser, asSingleLine, renderUserUsername } from "../../../utils";
+import { UnknownUser, asSingleLine, renderUsername } from "../../../utils";
 import { ModActionsPluginType } from "../types";
 import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
 
@@ -48,7 +48,7 @@ export async function actualUnmuteCmd(
       pluginData,
       msg.channel,
       asSingleLine(`
-        Unmuting **${renderUserUsername(user)}**
+        Unmuting **${renderUsername(user)}**
         in ${timeUntilUnmute} (Case #${result.case.case_number})
       `),
     );
@@ -57,7 +57,7 @@ export async function actualUnmuteCmd(
       pluginData,
       msg.channel,
       asSingleLine(`
-        Unmuted **${renderUserUsername(user)}**
+        Unmuted **${renderUsername(user)}**
         (Case #${result.case.case_number})
       `),
     );
diff --git a/backend/src/plugins/Mutes/commands/MutesCmd.ts b/backend/src/plugins/Mutes/commands/MutesCmd.ts
index 179d1a65..22cd74c5 100644
--- a/backend/src/plugins/Mutes/commands/MutesCmd.ts
+++ b/backend/src/plugins/Mutes/commands/MutesCmd.ts
@@ -10,7 +10,7 @@ import moment from "moment-timezone";
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { humanizeDurationShort } from "../../../humanizeDurationShort";
 import { getBaseUrl } from "../../../pluginUtils";
-import { DBDateFormat, MINUTES, renderUserUsername, resolveMember } from "../../../utils";
+import { DBDateFormat, MINUTES, renderUsername, resolveMember } from "../../../utils";
 import { IMuteWithDetails, mutesCmd } from "../types";
 
 export const MutesCmd = mutesCmd({
@@ -74,7 +74,7 @@ export const MutesCmd = mutesCmd({
       totalMutes = manuallyMutedMembers.length;
 
       lines = manuallyMutedMembers.map((member) => {
-        return `<@!${member.id}> (**${renderUserUsername(member.user)}**, \`${member.id}\`)   🔧 Manual mute`;
+        return `<@!${member.id}> (**${renderUsername(member.user)}**, \`${member.id}\`)   🔧 Manual mute`;
       });
     } else {
       // Show filtered active mutes (but not manual mutes)
@@ -123,7 +123,7 @@ export const MutesCmd = mutesCmd({
 
       lines = filteredMutes.map((mute) => {
         const user = pluginData.client.users.resolve(mute.user_id as Snowflake);
-        const username = user ? renderUserUsername(user) : "Unknown#0000";
+        const username = user ? renderUsername(user) : "Unknown#0000";
         const theCase = muteCasesById.get(mute.case_id);
         const caseName = theCase ? `Case #${theCase.case_number}` : "No case";
 
diff --git a/backend/src/plugins/NameHistory/commands/NamesCmd.ts b/backend/src/plugins/NameHistory/commands/NamesCmd.ts
index 373f1671..da8ba48a 100644
--- a/backend/src/plugins/NameHistory/commands/NamesCmd.ts
+++ b/backend/src/plugins/NameHistory/commands/NamesCmd.ts
@@ -5,7 +5,7 @@ import { MAX_NICKNAME_ENTRIES_PER_USER } from "../../../data/GuildNicknameHistor
 import { MAX_USERNAME_ENTRIES_PER_USER } from "../../../data/UsernameHistory";
 import { NICKNAME_RETENTION_PERIOD } from "../../../data/cleanup/nicknames";
 import { sendErrorMessage } from "../../../pluginUtils";
-import { DAYS, renderUserUsername } from "../../../utils";
+import { DAYS, renderUsername } from "../../../utils";
 import { nameHistoryCmd } from "../types";
 
 export const NamesCmd = nameHistoryCmd({
@@ -31,7 +31,7 @@ export const NamesCmd = nameHistoryCmd({
     const usernameRows = usernames.map((r) => `\`[${r.timestamp}]\` **${disableCodeBlocks(r.username)}**`);
 
     const user = await pluginData.client.users.fetch(args.userId as Snowflake).catch(() => null);
-    const currentUsername = user ? renderUserUsername(user) : args.userId;
+    const currentUsername = user ? renderUsername(user) : args.userId;
 
     const nicknameDays = Math.round(NICKNAME_RETENTION_PERIOD / DAYS);
     const usernameDays = Math.round(NICKNAME_RETENTION_PERIOD / DAYS);
diff --git a/backend/src/plugins/ReactionRoles/util/addMemberPendingRoleChange.ts b/backend/src/plugins/ReactionRoles/util/addMemberPendingRoleChange.ts
index a2a82fe9..dda8a6bc 100644
--- a/backend/src/plugins/ReactionRoles/util/addMemberPendingRoleChange.ts
+++ b/backend/src/plugins/ReactionRoles/util/addMemberPendingRoleChange.ts
@@ -1,7 +1,7 @@
 import { Snowflake } from "discord.js";
 import { GuildPluginData } from "knub";
 import { logger } from "../../../logger";
-import { renderUserUsername, resolveMember } from "../../../utils";
+import { renderUsername, resolveMember } from "../../../utils";
 import { memberRolesLock } from "../../../utils/lockNameHelpers";
 import { PendingMemberRoleChanges, ReactionRolesPluginType, RoleChangeMode } from "../types";
 
@@ -33,9 +33,7 @@ export async function addMemberPendingRoleChange(
           try {
             await member.roles.set(Array.from(newRoleIds.values()), "Reaction roles");
           } catch (e) {
-            logger.warn(
-              `Failed to apply role changes to ${renderUserUsername(member.user)} (${member.id}): ${e.message}`,
-            );
+            logger.warn(`Failed to apply role changes to ${renderUsername(member.user)} (${member.id}): ${e.message}`);
           }
         }
         lock.unlock();
diff --git a/backend/src/plugins/Slowmode/commands/SlowmodeClearCmd.ts b/backend/src/plugins/Slowmode/commands/SlowmodeClearCmd.ts
index 246a048e..fd133c3a 100644
--- a/backend/src/plugins/Slowmode/commands/SlowmodeClearCmd.ts
+++ b/backend/src/plugins/Slowmode/commands/SlowmodeClearCmd.ts
@@ -1,7 +1,7 @@
 import { ChannelType, escapeInlineCode } from "discord.js";
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { asSingleLine, renderUserUsername } from "../../../utils";
+import { asSingleLine, renderUsername } from "../../../utils";
 import { getMissingChannelPermissions } from "../../../utils/getMissingChannelPermissions";
 import { missingPermissionError } from "../../../utils/missingPermissionError";
 import { BOT_SLOWMODE_CLEAR_PERMISSIONS } from "../requiredPermissions";
@@ -45,7 +45,7 @@ export const SlowmodeClearCmd = slowmodeCmd({
           pluginData,
           msg.channel,
           asSingleLine(`
-            Failed to clear slowmode from **${renderUserUsername(args.user)}** in <#${args.channel.id}>:
+            Failed to clear slowmode from **${renderUsername(args.user)}** in <#${args.channel.id}>:
             Threads cannot have Bot Slowmode
           `),
         );
@@ -56,7 +56,7 @@ export const SlowmodeClearCmd = slowmodeCmd({
         pluginData,
         msg.channel,
         asSingleLine(`
-          Failed to clear slowmode from **${renderUserUsername(args.user)}** in <#${args.channel.id}>:
+          Failed to clear slowmode from **${renderUsername(args.user)}** in <#${args.channel.id}>:
           \`${escapeInlineCode(e.message)}\`
         `),
       );
@@ -66,7 +66,7 @@ export const SlowmodeClearCmd = slowmodeCmd({
     sendSuccessMessage(
       pluginData,
       msg.channel,
-      `Slowmode cleared from **${renderUserUsername(args.user)}** in <#${args.channel.id}>`,
+      `Slowmode cleared from **${renderUsername(args.user)}** in <#${args.channel.id}>`,
     );
   },
 });
diff --git a/backend/src/plugins/UsernameSaver/updateUsername.ts b/backend/src/plugins/UsernameSaver/updateUsername.ts
index 163a4aae..ed0fb73f 100644
--- a/backend/src/plugins/UsernameSaver/updateUsername.ts
+++ b/backend/src/plugins/UsernameSaver/updateUsername.ts
@@ -1,11 +1,11 @@
 import { User } from "discord.js";
 import { GuildPluginData } from "knub";
-import { renderUserUsername } from "../../utils";
+import { renderUsername } from "../../utils";
 import { UsernameSaverPluginType } from "./types";
 
 export async function updateUsername(pluginData: GuildPluginData<UsernameSaverPluginType>, user: User) {
   if (!user) return;
-  const newUsername = renderUserUsername(user);
+  const newUsername = renderUsername(user);
   const latestEntry = await pluginData.state.usernameHistory.getLastEntry(user.id);
   if (!latestEntry || newUsername !== latestEntry.username) {
     await pluginData.state.usernameHistory.addEntry(user.id, newUsername);
diff --git a/backend/src/plugins/Utility/commands/LevelCmd.ts b/backend/src/plugins/Utility/commands/LevelCmd.ts
index 306a1d20..df4d9325 100644
--- a/backend/src/plugins/Utility/commands/LevelCmd.ts
+++ b/backend/src/plugins/Utility/commands/LevelCmd.ts
@@ -1,6 +1,6 @@
 import { helpers } from "knub";
 import { commandTypeHelpers as ct } from "../../../commandTypes";
-import { renderUserUsername } from "../../../utils";
+import { renderUsername } from "../../../utils";
 import { utilityCmd } from "../types";
 
 const { getMemberLevel } = helpers;
@@ -18,6 +18,6 @@ export const LevelCmd = utilityCmd({
   run({ message, args, pluginData }) {
     const member = args.member || message.member;
     const level = getMemberLevel(pluginData, member);
-    message.channel.send(`The permission level of ${renderUserUsername(member.user)} is **${level}**`);
+    message.channel.send(`The permission level of ${renderUsername(member.user)} is **${level}**`);
   },
 });
diff --git a/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts b/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts
index 0f82458a..240c763f 100644
--- a/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts
+++ b/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts
@@ -1,7 +1,7 @@
 import { VoiceChannel } from "discord.js";
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { renderUserUsername } from "../../../utils";
+import { renderUsername } from "../../../utils";
 import { LogsPlugin } from "../../Logs/LogsPlugin";
 import { utilityCmd } from "../types";
 
@@ -43,7 +43,7 @@ export const VcdisconnectCmd = utilityCmd({
     sendSuccessMessage(
       pluginData,
       msg.channel,
-      `**${renderUserUsername(args.member.user)}** disconnected from **${channel.name}**`,
+      `**${renderUsername(args.member.user)}** disconnected from **${channel.name}**`,
     );
   },
 });
diff --git a/backend/src/plugins/Utility/commands/VcmoveCmd.ts b/backend/src/plugins/Utility/commands/VcmoveCmd.ts
index db00161e..6ffe8588 100644
--- a/backend/src/plugins/Utility/commands/VcmoveCmd.ts
+++ b/backend/src/plugins/Utility/commands/VcmoveCmd.ts
@@ -1,7 +1,7 @@
 import { ChannelType, Snowflake, VoiceChannel } from "discord.js";
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { channelMentionRegex, isSnowflake, renderUserUsername, simpleClosestStringMatch } from "../../../utils";
+import { channelMentionRegex, isSnowflake, renderUsername, simpleClosestStringMatch } from "../../../utils";
 import { LogsPlugin } from "../../Logs/LogsPlugin";
 import { utilityCmd } from "../types";
 
@@ -80,11 +80,7 @@ export const VcmoveCmd = utilityCmd({
       newChannel: channel,
     });
 
-    sendSuccessMessage(
-      pluginData,
-      msg.channel,
-      `**${renderUserUsername(args.member.user)}** moved to **${channel.name}**`,
-    );
+    sendSuccessMessage(pluginData, msg.channel, `**${renderUsername(args.member.user)}** moved to **${channel.name}**`);
   },
 });
 
@@ -157,7 +153,7 @@ export const VcmoveAllCmd = utilityCmd({
         sendErrorMessage(
           pluginData,
           msg.channel,
-          `Failed to move ${renderUserUsername(currMember.user)} (${currMember.id}): You cannot act on this member`,
+          `Failed to move ${renderUsername(currMember.user)} (${currMember.id}): You cannot act on this member`,
         );
         errAmt++;
         continue;
@@ -175,7 +171,7 @@ export const VcmoveAllCmd = utilityCmd({
         sendErrorMessage(
           pluginData,
           msg.channel,
-          `Failed to move ${renderUserUsername(currMember.user)} (${currMember.id})`,
+          `Failed to move ${renderUsername(currMember.user)} (${currMember.id})`,
         );
         errAmt++;
         continue;
diff --git a/backend/src/utils.ts b/backend/src/utils.ts
index 5c795072..990c1f7e 100644
--- a/backend/src/utils.ts
+++ b/backend/src/utils.ts
@@ -1607,15 +1607,11 @@ export const DBDateFormat = "YYYY-MM-DD HH:mm:ss";
 //export function renderUsername(username: GuildMember): string;
 //export function renderUsername(username: User): string;
 //export function renderUsername(username: string, discriminator?: string): string;
-export function renderUsername(username: string | User | GuildMember, discriminator?: string): string {
+export function renderUsername(username: string | User | GuildMember | UnknownUser, discriminator?: string): string {
   if (username instanceof GuildMember) return username.user.tag;
-  if (username instanceof User) return username.tag;
+  if (username instanceof User || username instanceof UnknownUser) return username.tag;
   if (discriminator === "0" || discriminator === "0000") {
     return username;
   }
   return `${username}#${discriminator}`;
 }
-
-export function renderUserUsername(user: User | UnknownUser): string {
-  return renderUsername(user.username, user.discriminator);
-}
diff --git a/backend/src/utils/templateSafeObjects.ts b/backend/src/utils/templateSafeObjects.ts
index 33e36971..d6a0dfd6 100644
--- a/backend/src/utils/templateSafeObjects.ts
+++ b/backend/src/utils/templateSafeObjects.ts
@@ -13,7 +13,7 @@ import {
   User,
 } from "discord.js";
 import { GuildPluginData } from "knub";
-import { UnknownUser, renderUserUsername } from "src/utils";
+import { UnknownUser, renderUsername } from "src/utils";
 import { Case } from "../data/entities/Case";
 import {
   ISavedMessageAttachmentData,
@@ -250,7 +250,7 @@ export function userToTemplateSafeUser(user: User | UnknownUser): TemplateSafeUs
       discriminator: "0000",
       mention: `<@${user.id}>`,
       tag: "Unknown#0000",
-      renderedUsername: renderUserUsername(user),
+      renderedUsername: renderUsername(user),
     });
   }
 
@@ -264,7 +264,7 @@ export function userToTemplateSafeUser(user: User | UnknownUser): TemplateSafeUs
     avatarURL: user.displayAvatarURL(),
     bot: user.bot,
     createdAt: user.createdTimestamp,
-    renderedUsername: renderUserUsername(user),
+    renderedUsername: renderUsername(user),
   });
 }
 

From 2e0598194f36ed9d2d12ca063cb37837b1f61556 Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 16:02:15 +0000
Subject: [PATCH 12/17] fix renderUsername overloads

Signed-off-by: GitHub <noreply@github.com>
---
 backend/src/utils.ts | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/backend/src/utils.ts b/backend/src/utils.ts
index 990c1f7e..72f203f2 100644
--- a/backend/src/utils.ts
+++ b/backend/src/utils.ts
@@ -1603,14 +1603,12 @@ export function isTruthy<T>(value: T): value is Exclude<T, false | null | undefi
 
 export const DBDateFormat = "YYYY-MM-DD HH:mm:ss";
 
-// TODO: Fix overloads
-//export function renderUsername(username: GuildMember): string;
-//export function renderUsername(username: User): string;
-//export function renderUsername(username: string, discriminator?: string): string;
+export function renderUsername(memberOrUser: GuildMember | UnknownUser | User): string;
+export function renderUsername(username: string, discriminator: string): string;
 export function renderUsername(username: string | User | GuildMember | UnknownUser, discriminator?: string): string {
   if (username instanceof GuildMember) return username.user.tag;
   if (username instanceof User || username instanceof UnknownUser) return username.tag;
-  if (discriminator === "0" || discriminator === "0000") {
+  if (discriminator === "0") {
     return username;
   }
   return `${username}#${discriminator}`;

From aa1f11e8015b192af39d77bb73f7a5e914d1696f Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 16:10:10 +0000
Subject: [PATCH 13/17] lint

Signed-off-by: GitHub <noreply@github.com>
---
 backend/src/index.ts                                         | 2 +-
 backend/src/plugins/Automod/actions/startThread.ts           | 1 -
 backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts | 2 +-
 backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts | 5 +----
 backend/src/plugins/Utility/functions/getRoleInfoEmbed.ts    | 2 +-
 backend/src/plugins/Utility/functions/getServerInfoEmbed.ts  | 2 +-
 .../src/plugins/Utility/functions/getSnowflakeInfoEmbed.ts   | 2 +-
 backend/src/plugins/Utility/functions/getUserInfoEmbed.ts    | 2 +-
 8 files changed, 7 insertions(+), 11 deletions(-)

diff --git a/backend/src/index.ts b/backend/src/index.ts
index 2fe16c11..6dad14b1 100644
--- a/backend/src/index.ts
+++ b/backend/src/index.ts
@@ -203,7 +203,7 @@ if (env.DEBUG) {
 }
 
 logger.info("Connecting to database");
-connect().then(async (connection) => {
+connect().then(async () => {
   const client = new Client({
     partials: [Partials.User, Partials.Channel, Partials.GuildMember, Partials.Message, Partials.Reaction],
 
diff --git a/backend/src/plugins/Automod/actions/startThread.ts b/backend/src/plugins/Automod/actions/startThread.ts
index 970e9ec8..b5864389 100644
--- a/backend/src/plugins/Automod/actions/startThread.ts
+++ b/backend/src/plugins/Automod/actions/startThread.ts
@@ -41,7 +41,6 @@ export const StartThreadAction = automodAction({
       return true;
     });
 
-    const guild = pluginData.guild;
     const archiveSet = actionConfig.auto_archive
       ? Math.ceil(Math.max(convertDelayStringToMS(actionConfig.auto_archive) ?? 0, 0) / MINUTES)
       : ThreadAutoArchiveDuration.OneDay;
diff --git a/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts b/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts
index f601dd5c..c05bd2c1 100644
--- a/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getChannelInfoEmbed.ts
@@ -24,7 +24,7 @@ const MEDIA_CHANNEL_ICON = "https://cdn.discordapp.com/attachments/8761342052292
 export async function getChannelInfoEmbed(
   pluginData: GuildPluginData<UtilityPluginType>,
   channelId: string,
-  requestMemberId?: string,
+  //  requestMemberId?: string,
 ): Promise<APIEmbed | null> {
   const channel = pluginData.guild.channels.cache.get(channelId as Snowflake);
   if (!channel) {
diff --git a/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts b/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts
index 3a49a80d..e272b904 100644
--- a/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts
@@ -9,7 +9,6 @@ import {
   trimEmptyLines,
   trimLines,
 } from "../../../utils";
-import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
 import { UtilityPluginType } from "../types";
 
 const MESSAGE_ICON = "https://cdn.discordapp.com/attachments/740650744830623756/740685652152025088/message.png";
@@ -18,7 +17,7 @@ export async function getMessageInfoEmbed(
   pluginData: GuildPluginData<UtilityPluginType>,
   channelId: string,
   messageId: string,
-  requestMemberId?: string,
+  //  requestMemberId?: string,
 ): Promise<APIEmbed | null> {
   const message = await (pluginData.guild.channels.resolve(channelId as Snowflake) as TextChannel).messages
     .fetch(messageId as Snowflake)
@@ -27,8 +26,6 @@ export async function getMessageInfoEmbed(
     return null;
   }
 
-  const timeAndDate = pluginData.getPlugin(TimeAndDatePlugin);
-
   const embed: EmbedWith<"fields" | "author"> = {
     fields: [],
     author: {
diff --git a/backend/src/plugins/Utility/functions/getRoleInfoEmbed.ts b/backend/src/plugins/Utility/functions/getRoleInfoEmbed.ts
index fa3188ec..c4d685d2 100644
--- a/backend/src/plugins/Utility/functions/getRoleInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getRoleInfoEmbed.ts
@@ -9,7 +9,7 @@ const MENTION_ICON = "https://cdn.discordapp.com/attachments/705009450855039042/
 export async function getRoleInfoEmbed(
   pluginData: GuildPluginData<UtilityPluginType>,
   role: Role,
-  requestMemberId?: string,
+  // requestMemberId?: string,
 ): Promise<APIEmbed> {
   const embed: EmbedWith<"fields" | "author" | "color"> = {
     fields: [],
diff --git a/backend/src/plugins/Utility/functions/getServerInfoEmbed.ts b/backend/src/plugins/Utility/functions/getServerInfoEmbed.ts
index afcefb80..8a2ebfc7 100644
--- a/backend/src/plugins/Utility/functions/getServerInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getServerInfoEmbed.ts
@@ -25,7 +25,7 @@ const prettifyFeature = (feature: string): string =>
 export async function getServerInfoEmbed(
   pluginData: GuildPluginData<UtilityPluginType>,
   serverId: string,
-  requestMemberId?: string,
+  //  requestMemberId?: string,
 ): Promise<APIEmbed | null> {
   const thisServer = serverId === pluginData.guild.id ? pluginData.guild : null;
   const [restGuild, guildPreview] = await Promise.all([
diff --git a/backend/src/plugins/Utility/functions/getSnowflakeInfoEmbed.ts b/backend/src/plugins/Utility/functions/getSnowflakeInfoEmbed.ts
index ef676fd1..ba7c3374 100644
--- a/backend/src/plugins/Utility/functions/getSnowflakeInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getSnowflakeInfoEmbed.ts
@@ -10,7 +10,7 @@ export async function getSnowflakeInfoEmbed(
   pluginData: GuildPluginData<UtilityPluginType>,
   snowflake: string,
   showUnknownWarning = false,
-  requestMemberId?: string,
+  //  requestMemberId?: string,
 ): Promise<APIEmbed> {
   const embed: EmbedWith<"fields" | "author"> = {
     fields: [],
diff --git a/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts b/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts
index 58d34d56..d8ccc833 100644
--- a/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts
@@ -26,7 +26,7 @@ export async function getUserInfoEmbed(
   pluginData: GuildPluginData<UtilityPluginType>,
   userId: string,
   compact = false,
-  requestMemberId?: string,
+  //  requestMemberId?: string,
 ): Promise<APIEmbed | null> {
   const user = await resolveUser(pluginData.client, userId);
   if (!user || user instanceof UnknownUser) {

From 89d6e8aeecabea2ecc6c788f7ded6c447a870028 Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 16:11:12 +0000
Subject: [PATCH 14/17] missed one

Signed-off-by: GitHub <noreply@github.com>
---
 backend/src/plugins/ModActions/commands/DeleteCaseCmd.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/backend/src/plugins/ModActions/commands/DeleteCaseCmd.ts b/backend/src/plugins/ModActions/commands/DeleteCaseCmd.ts
index 823bc726..c107791d 100644
--- a/backend/src/plugins/ModActions/commands/DeleteCaseCmd.ts
+++ b/backend/src/plugins/ModActions/commands/DeleteCaseCmd.ts
@@ -2,7 +2,7 @@ import { helpers } from "knub";
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { Case } from "../../../data/entities/Case";
 import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
-import { SECONDS, trimLines } from "../../../utils";
+import { SECONDS, renderUsername, trimLines } from "../../../utils";
 import { CasesPlugin } from "../../Cases/CasesPlugin";
 import { LogsPlugin } from "../../Logs/LogsPlugin";
 import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
@@ -60,7 +60,7 @@ export const DeleteCaseCmd = modActionsCmd({
         }
       }
 
-      const deletedByName = message.author.tag;
+      const deletedByName = renderUsername(message.author);
 
       const timeAndDate = pluginData.getPlugin(TimeAndDatePlugin);
       const deletedAt = timeAndDate.inGuildTz().format(timeAndDate.getDateFormat("pretty_datetime"));

From e0637a206f0e9c7bae14ec61c3508b92a83136c1 Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 16:12:57 +0000
Subject: [PATCH 15/17] better startThread if checks (almeida is happy)

Signed-off-by: GitHub <noreply@github.com>
---
 backend/src/plugins/Automod/actions/startThread.ts | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/backend/src/plugins/Automod/actions/startThread.ts b/backend/src/plugins/Automod/actions/startThread.ts
index b5864389..4930ebe5 100644
--- a/backend/src/plugins/Automod/actions/startThread.ts
+++ b/backend/src/plugins/Automod/actions/startThread.ts
@@ -50,13 +50,7 @@ export const StartThreadAction = automodAction({
 
     for (const threadContext of threads) {
       const channel = pluginData.guild.channels.cache.get(threadContext.message!.channel_id);
-      if (
-        !channel ||
-        !("threads" in channel) ||
-        channel.type === ChannelType.GuildForum ||
-        channel.type === ChannelType.GuildMedia
-      )
-        continue;
+      if (!channel || !("threads" in channel) || channel.isThreadOnly()) continue;
 
       const renderThreadName = async (str: string) =>
         renderTemplate(

From 2b5a5e636a230212383ff84af58bb20b97e9777f Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 17:02:54 +0000
Subject: [PATCH 16/17] almeida review.mp4

Signed-off-by: GitHub <noreply@github.com>
---
 .../functions/matchMultipleTextTypesOnMessage.ts       |  2 +-
 backend/src/plugins/Automod/triggers/roleAdded.ts      |  2 +-
 backend/src/plugins/Automod/triggers/roleRemoved.ts    |  2 +-
 backend/src/plugins/BotControl/commands/ServersCmd.ts  |  7 +++----
 backend/src/plugins/Cases/functions/createCase.ts      |  8 ++++----
 backend/src/plugins/ModActions/commands/CasesModCmd.ts |  8 ++++----
 .../src/plugins/ModActions/commands/CasesUserCmd.ts    |  2 +-
 backend/src/plugins/ModActions/commands/WarnCmd.ts     |  2 +-
 .../ModActions/events/PostAlertOnMemberJoinEvt.ts      |  4 +---
 .../ModActions/functions/actualKickMemberCmd.ts        |  2 +-
 backend/src/plugins/Mutes/commands/MutesCmd.ts         |  2 +-
 .../Starboard/util/createStarboardEmbedFromMessage.ts  |  2 +-
 backend/src/plugins/Utility/commands/AvatarCmd.ts      |  2 +-
 backend/src/plugins/Utility/commands/LevelCmd.ts       |  2 +-
 .../src/plugins/Utility/commands/VcdisconnectCmd.ts    |  2 +-
 backend/src/plugins/Utility/commands/VcmoveCmd.ts      | 10 +++-------
 .../src/plugins/Utility/functions/getUserInfoEmbed.ts  |  2 +-
 backend/src/plugins/Utility/search.ts                  |  4 ++--
 18 files changed, 29 insertions(+), 36 deletions(-)

diff --git a/backend/src/plugins/Automod/functions/matchMultipleTextTypesOnMessage.ts b/backend/src/plugins/Automod/functions/matchMultipleTextTypesOnMessage.ts
index f0eee5ec..a82c526e 100644
--- a/backend/src/plugins/Automod/functions/matchMultipleTextTypesOnMessage.ts
+++ b/backend/src/plugins/Automod/functions/matchMultipleTextTypesOnMessage.ts
@@ -42,7 +42,7 @@ export async function* matchMultipleTextTypesOnMessage(
   }
 
   if (trigger.match_visible_names) {
-    yield ["visiblename", member.nickname || member.user.globalName || msg.data.author.username];
+    yield ["visiblename", member.displayName || msg.data.author.username];
   }
 
   if (trigger.match_usernames) {
diff --git a/backend/src/plugins/Automod/triggers/roleAdded.ts b/backend/src/plugins/Automod/triggers/roleAdded.ts
index 754be1b3..5d18de99 100644
--- a/backend/src/plugins/Automod/triggers/roleAdded.ts
+++ b/backend/src/plugins/Automod/triggers/roleAdded.ts
@@ -38,7 +38,7 @@ export const RoleAddedTrigger = automodTrigger<RoleAddedMatchResult>()({
     const role = pluginData.guild.roles.cache.get(matchResult.extra.matchedRoleId as Snowflake);
     const roleName = role?.name || "Unknown";
     const member = contexts[0].member!;
-    const memberName = `**${renderUsername(member.user)}** (\`${member.id}\`)`;
+    const memberName = `**${renderUsername(member)}** (\`${member.id}\`)`;
     return `Role ${roleName} (\`${matchResult.extra.matchedRoleId}\`) was added to ${memberName}`;
   },
 });
diff --git a/backend/src/plugins/Automod/triggers/roleRemoved.ts b/backend/src/plugins/Automod/triggers/roleRemoved.ts
index fc5d5ae3..9452bdda 100644
--- a/backend/src/plugins/Automod/triggers/roleRemoved.ts
+++ b/backend/src/plugins/Automod/triggers/roleRemoved.ts
@@ -38,7 +38,7 @@ export const RoleRemovedTrigger = automodTrigger<RoleAddedMatchResult>()({
     const role = pluginData.guild.roles.cache.get(matchResult.extra.matchedRoleId as Snowflake);
     const roleName = role?.name || "Unknown";
     const member = contexts[0].member!;
-    const memberName = `**${renderUsername(member.user)}** (\`${member.id}\`)`;
+    const memberName = `**${renderUsername(member)}** (\`${member.id}\`)`;
     return `Role ${roleName} (\`${matchResult.extra.matchedRoleId}\`) was removed from ${memberName}`;
   },
 });
diff --git a/backend/src/plugins/BotControl/commands/ServersCmd.ts b/backend/src/plugins/BotControl/commands/ServersCmd.ts
index 3658a36c..5b2cf9c7 100644
--- a/backend/src/plugins/BotControl/commands/ServersCmd.ts
+++ b/backend/src/plugins/BotControl/commands/ServersCmd.ts
@@ -48,10 +48,9 @@ export const ServersCmd = botControlCmd({
         const lines = filteredGuilds.map((g) => {
           const paddedId = g.id.padEnd(longestId, " ");
           const owner = getUser(pluginData.client, g.ownerId);
-          return `\`${paddedId}\` **${g.name}** (${g.memberCount} members) (owner **${renderUsername(
-            owner.username,
-            owner.discriminator,
-          )}** \`${owner.id}\`)`;
+          return `\`${paddedId}\` **${g.name}** (${g.memberCount} members) (owner **${renderUsername(owner)}** \`${
+            owner.id
+          }\`)`;
         });
         createChunkedMessage(msg.channel, lines.join("\n"));
       } else {
diff --git a/backend/src/plugins/Cases/functions/createCase.ts b/backend/src/plugins/Cases/functions/createCase.ts
index 70717f51..c68b899f 100644
--- a/backend/src/plugins/Cases/functions/createCase.ts
+++ b/backend/src/plugins/Cases/functions/createCase.ts
@@ -8,16 +8,16 @@ import { postCaseToCaseLogChannel } from "./postToCaseLogChannel";
 
 export async function createCase(pluginData: GuildPluginData<CasesPluginType>, args: CaseArgs) {
   const user = await resolveUser(pluginData.client, args.userId);
-  const userName = renderUsername(user.username, user.discriminator);
+  const name = renderUsername(user);
 
   const mod = await resolveUser(pluginData.client, args.modId);
-  const modName = renderUsername(mod.username, mod.discriminator);
+  const modName = renderUsername(mod);
 
   let ppName: string | null = null;
   let ppId: Snowflake | null = null;
   if (args.ppId) {
     const pp = await resolveUser(pluginData.client, args.ppId);
-    ppName = renderUsername(pp.username, pp.discriminator);
+    ppName = renderUsername(pp);
     ppId = pp.id;
   }
 
@@ -32,7 +32,7 @@ export async function createCase(pluginData: GuildPluginData<CasesPluginType>, a
   const createdCase = await pluginData.state.cases.create({
     type: args.type,
     user_id: user.id,
-    user_name: userName,
+    user_name: name,
     mod_id: mod.id,
     mod_name: modName,
     audit_log_id: args.auditLogId,
diff --git a/backend/src/plugins/ModActions/commands/CasesModCmd.ts b/backend/src/plugins/ModActions/commands/CasesModCmd.ts
index a911091d..12b6c05c 100644
--- a/backend/src/plugins/ModActions/commands/CasesModCmd.ts
+++ b/backend/src/plugins/ModActions/commands/CasesModCmd.ts
@@ -1,7 +1,7 @@
-import { APIEmbed, GuildMember, User } from "discord.js";
+import { APIEmbed } from "discord.js";
 import { commandTypeHelpers as ct } from "../../../commandTypes";
 import { sendErrorMessage } from "../../../pluginUtils";
-import { emptyEmbedValue, renderUsername, resolveMember, resolveUser, trimLines } from "../../../utils";
+import { UnknownUser, emptyEmbedValue, renderUsername, resolveMember, resolveUser, trimLines } from "../../../utils";
 import { asyncMap } from "../../../utils/async";
 import { createPaginatedMessage } from "../../../utils/createPaginatedMessage";
 import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields";
@@ -31,7 +31,7 @@ export const CasesModCmd = modActionsCmd({
     const mod =
       (await resolveMember(pluginData.client, pluginData.guild, modId)) ||
       (await resolveUser(pluginData.client, modId));
-    const modName = mod instanceof User ? renderUsername(mod) : modId;
+    const modName = mod instanceof UnknownUser ? modId : renderUsername(mod);
 
     const casesPlugin = pluginData.getPlugin(CasesPlugin);
     const totalCases = await casesPlugin.getTotalCasesByMod(modId);
@@ -59,7 +59,7 @@ export const CasesModCmd = modActionsCmd({
         const embed = {
           author: {
             name: title,
-            icon_url: mod instanceof User || mod instanceof GuildMember ? mod.displayAvatarURL() : undefined,
+            icon_url: mod instanceof UnknownUser ? undefined : mod.displayAvatarURL(),
           },
           fields: [
             ...getChunkedEmbedFields(emptyEmbedValue, lines.join("\n")),
diff --git a/backend/src/plugins/ModActions/commands/CasesUserCmd.ts b/backend/src/plugins/ModActions/commands/CasesUserCmd.ts
index 05ab65eb..7b3714b6 100644
--- a/backend/src/plugins/ModActions/commands/CasesUserCmd.ts
+++ b/backend/src/plugins/ModActions/commands/CasesUserCmd.ts
@@ -46,7 +46,7 @@ export const CasesUserCmd = modActionsCmd({
     const user =
       (await resolveMember(pluginData.client, pluginData.guild, args.user)) ||
       (await resolveUser(pluginData.client, args.user));
-    if (!user.id || user instanceof UnknownUser) {
+    if (user instanceof UnknownUser) {
       sendErrorMessage(pluginData, msg.channel, `User not found`);
       return;
     }
diff --git a/backend/src/plugins/ModActions/commands/WarnCmd.ts b/backend/src/plugins/ModActions/commands/WarnCmd.ts
index f917c55e..218eeaf3 100644
--- a/backend/src/plugins/ModActions/commands/WarnCmd.ts
+++ b/backend/src/plugins/ModActions/commands/WarnCmd.ts
@@ -106,7 +106,7 @@ export const WarnCmd = modActionsCmd({
     sendSuccessMessage(
       pluginData,
       msg.channel,
-      `Warned **${renderUsername(memberToWarn.user)}** (Case #${warnResult.case.case_number})${messageResultText}`,
+      `Warned **${renderUsername(memberToWarn)}** (Case #${warnResult.case.case_number})${messageResultText}`,
     );
   },
 });
diff --git a/backend/src/plugins/ModActions/events/PostAlertOnMemberJoinEvt.ts b/backend/src/plugins/ModActions/events/PostAlertOnMemberJoinEvt.ts
index 7874c241..82e39547 100644
--- a/backend/src/plugins/ModActions/events/PostAlertOnMemberJoinEvt.ts
+++ b/backend/src/plugins/ModActions/events/PostAlertOnMemberJoinEvt.ts
@@ -46,9 +46,7 @@ export const PostAlertOnMemberJoinEvt = modActionsEvt({
       }
 
       await alertChannel.send(
-        `<@!${member.id}> (${renderUsername(member.user)} \`${member.id}\`) joined with ${
-          actions.length
-        } prior record(s)`,
+        `<@!${member.id}> (${renderUsername(member)} \`${member.id}\`) joined with ${actions.length} prior record(s)`,
       );
     }
   },
diff --git a/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts b/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts
index fac3f906..a755ee08 100644
--- a/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts
+++ b/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts
@@ -103,7 +103,7 @@ export async function actualKickMemberCmd(
   }
 
   // Confirm the action to the moderator
-  let response = `Kicked **${renderUsername(memberToKick.user)}** (Case #${kickResult.case.case_number})`;
+  let response = `Kicked **${renderUsername(memberToKick)}** (Case #${kickResult.case.case_number})`;
 
   if (kickResult.notifyResult.text) response += ` (${kickResult.notifyResult.text})`;
   sendSuccessMessage(pluginData, msg.channel, response);
diff --git a/backend/src/plugins/Mutes/commands/MutesCmd.ts b/backend/src/plugins/Mutes/commands/MutesCmd.ts
index 22cd74c5..5000218c 100644
--- a/backend/src/plugins/Mutes/commands/MutesCmd.ts
+++ b/backend/src/plugins/Mutes/commands/MutesCmd.ts
@@ -74,7 +74,7 @@ export const MutesCmd = mutesCmd({
       totalMutes = manuallyMutedMembers.length;
 
       lines = manuallyMutedMembers.map((member) => {
-        return `<@!${member.id}> (**${renderUsername(member.user)}**, \`${member.id}\`)   🔧 Manual mute`;
+        return `<@!${member.id}> (**${renderUsername(member)}**, \`${member.id}\`)   🔧 Manual mute`;
       });
     } else {
       // Show filtered active mutes (but not manual mutes)
diff --git a/backend/src/plugins/Starboard/util/createStarboardEmbedFromMessage.ts b/backend/src/plugins/Starboard/util/createStarboardEmbedFromMessage.ts
index 5126f20f..93ba4dfd 100644
--- a/backend/src/plugins/Starboard/util/createStarboardEmbedFromMessage.ts
+++ b/backend/src/plugins/Starboard/util/createStarboardEmbedFromMessage.ts
@@ -28,7 +28,7 @@ export function createStarboardEmbedFromMessage(
     embed.color = color;
   }
 
-  embed.author.icon_url = (msg.member || msg.author).displayAvatarURL();
+  embed.author.icon_url = (msg.member ?? msg.author).displayAvatarURL();
 
   // The second condition here checks for messages with only an image link that is then embedded.
   // The message content in that case is hidden by the Discord client, so we hide it here too.
diff --git a/backend/src/plugins/Utility/commands/AvatarCmd.ts b/backend/src/plugins/Utility/commands/AvatarCmd.ts
index b1215df6..e4ba07d5 100644
--- a/backend/src/plugins/Utility/commands/AvatarCmd.ts
+++ b/backend/src/plugins/Utility/commands/AvatarCmd.ts
@@ -14,7 +14,7 @@ export const AvatarCmd = utilityCmd({
   },
 
   async run({ message: msg, args, pluginData }) {
-    const user = args.user || msg.member || msg.author;
+    const user = args.user ?? msg.member ?? msg.author;
     if (!(user instanceof UnknownUser)) {
       const embed: APIEmbed = {
         image: {
diff --git a/backend/src/plugins/Utility/commands/LevelCmd.ts b/backend/src/plugins/Utility/commands/LevelCmd.ts
index df4d9325..5830f66a 100644
--- a/backend/src/plugins/Utility/commands/LevelCmd.ts
+++ b/backend/src/plugins/Utility/commands/LevelCmd.ts
@@ -18,6 +18,6 @@ export const LevelCmd = utilityCmd({
   run({ message, args, pluginData }) {
     const member = args.member || message.member;
     const level = getMemberLevel(pluginData, member);
-    message.channel.send(`The permission level of ${renderUsername(member.user)} is **${level}**`);
+    message.channel.send(`The permission level of ${renderUsername(member)} is **${level}**`);
   },
 });
diff --git a/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts b/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts
index 240c763f..b6863599 100644
--- a/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts
+++ b/backend/src/plugins/Utility/commands/VcdisconnectCmd.ts
@@ -43,7 +43,7 @@ export const VcdisconnectCmd = utilityCmd({
     sendSuccessMessage(
       pluginData,
       msg.channel,
-      `**${renderUsername(args.member.user)}** disconnected from **${channel.name}**`,
+      `**${renderUsername(args.member)}** disconnected from **${channel.name}**`,
     );
   },
 });
diff --git a/backend/src/plugins/Utility/commands/VcmoveCmd.ts b/backend/src/plugins/Utility/commands/VcmoveCmd.ts
index 6ffe8588..259c60b5 100644
--- a/backend/src/plugins/Utility/commands/VcmoveCmd.ts
+++ b/backend/src/plugins/Utility/commands/VcmoveCmd.ts
@@ -80,7 +80,7 @@ export const VcmoveCmd = utilityCmd({
       newChannel: channel,
     });
 
-    sendSuccessMessage(pluginData, msg.channel, `**${renderUsername(args.member.user)}** moved to **${channel.name}**`);
+    sendSuccessMessage(pluginData, msg.channel, `**${renderUsername(args.member)}** moved to **${channel.name}**`);
   },
 });
 
@@ -153,7 +153,7 @@ export const VcmoveAllCmd = utilityCmd({
         sendErrorMessage(
           pluginData,
           msg.channel,
-          `Failed to move ${renderUsername(currMember.user)} (${currMember.id}): You cannot act on this member`,
+          `Failed to move ${renderUsername(currMember)} (${currMember.id}): You cannot act on this member`,
         );
         errAmt++;
         continue;
@@ -168,11 +168,7 @@ export const VcmoveAllCmd = utilityCmd({
           sendErrorMessage(pluginData, msg.channel, "Unknown error when trying to move members");
           return;
         }
-        sendErrorMessage(
-          pluginData,
-          msg.channel,
-          `Failed to move ${renderUsername(currMember.user)} (${currMember.id})`,
-        );
+        sendErrorMessage(pluginData, msg.channel, `Failed to move ${renderUsername(currMember)} (${currMember.id})`);
         errAmt++;
         continue;
       }
diff --git a/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts b/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts
index d8ccc833..88e4aba0 100644
--- a/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts
+++ b/backend/src/plugins/Utility/functions/getUserInfoEmbed.ts
@@ -43,7 +43,7 @@ export async function getUserInfoEmbed(
     name: `${user.bot ? "Bot" : "User"}:  ${renderUsername(user)}`,
   };
 
-  const avatarURL = (member || user).displayAvatarURL();
+  const avatarURL = (member ?? user).displayAvatarURL();
   embed.author.icon_url = avatarURL;
 
   if (compact) {
diff --git a/backend/src/plugins/Utility/search.ts b/backend/src/plugins/Utility/search.ts
index 632a85a7..76c5af9c 100644
--- a/backend/src/plugins/Utility/search.ts
+++ b/backend/src/plugins/Utility/search.ts
@@ -381,7 +381,7 @@ async function performMemberSearch(
         return true;
       }
 
-      const fullUsername = renderUsername(member.user);
+      const fullUsername = renderUsername(member);
       if (await execRegExp(queryRegex, fullUsername).catch(allowTimeout)) return true;
 
       return false;
@@ -492,7 +492,7 @@ function formatSearchResultList(members: Array<GuildMember | User>): string {
     const paddedId = member.id.padEnd(longestId, " ");
     let line;
     if (member instanceof GuildMember) {
-      line = `${paddedId} ${renderUsername(member.user)}`;
+      line = `${paddedId} ${renderUsername(member)}`;
       if (member.nickname) line += ` (${member.nickname})`;
     } else {
       line = `${paddedId} ${renderUsername(member)}`;

From 2ac7ae85ce5db8c1551aa5cb9d18e2797a55ef4b Mon Sep 17 00:00:00 2001
From: Tiago R <metal@i0.tf>
Date: Sun, 26 Nov 2023 17:05:04 +0000
Subject: [PATCH 17/17] missed one

Signed-off-by: GitHub <noreply@github.com>
---
 .../plugins/ReactionRoles/util/addMemberPendingRoleChange.ts    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/backend/src/plugins/ReactionRoles/util/addMemberPendingRoleChange.ts b/backend/src/plugins/ReactionRoles/util/addMemberPendingRoleChange.ts
index dda8a6bc..8f25a0ae 100644
--- a/backend/src/plugins/ReactionRoles/util/addMemberPendingRoleChange.ts
+++ b/backend/src/plugins/ReactionRoles/util/addMemberPendingRoleChange.ts
@@ -33,7 +33,7 @@ export async function addMemberPendingRoleChange(
           try {
             await member.roles.set(Array.from(newRoleIds.values()), "Reaction roles");
           } catch (e) {
-            logger.warn(`Failed to apply role changes to ${renderUsername(member.user)} (${member.id}): ${e.message}`);
+            logger.warn(`Failed to apply role changes to ${renderUsername(member)} (${member.id}): ${e.message}`);
           }
         }
         lock.unlock();