summaryrefslogtreecommitdiff
path: root/packages/gateway/src
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-10-23 23:36:36 -0700
committerFuwn <[email protected]>2025-10-23 23:36:39 -0700
commit46c40a53a569f5f27de016bc0215bf30dcdba1a5 (patch)
treebec0ed98689296b6358e1f1c38c20ba6df01705b /packages/gateway/src
parentfeat(gateway:listeners): Add auto message deletion (diff)
downloadumabotdiscord-46c40a53a569f5f27de016bc0215bf30dcdba1a5.tar.xz
umabotdiscord-46c40a53a569f5f27de016bc0215bf30dcdba1a5.zip
feat(gateway:listeners): Add role persistence
Diffstat (limited to 'packages/gateway/src')
-rw-r--r--packages/gateway/src/database/prisma.ts9
-rw-r--r--packages/gateway/src/database/rolePersistence.ts118
-rw-r--r--packages/gateway/src/listeners/index.ts2
-rw-r--r--packages/gateway/src/listeners/memberJoin.ts8
-rw-r--r--packages/gateway/src/listeners/memberLeave.ts18
5 files changed, 154 insertions, 1 deletions
diff --git a/packages/gateway/src/database/prisma.ts b/packages/gateway/src/database/prisma.ts
new file mode 100644
index 0000000..d9ffaf3
--- /dev/null
+++ b/packages/gateway/src/database/prisma.ts
@@ -0,0 +1,9 @@
+import { PrismaClient } from "@prisma/client";
+import { withAccelerate } from "@prisma/extension-accelerate";
+import dotenv from "dotenv";
+
+dotenv.config({ path: "../../.dev.vars" });
+
+const prisma = new PrismaClient().$extends(withAccelerate());
+
+export default prisma;
diff --git a/packages/gateway/src/database/rolePersistence.ts b/packages/gateway/src/database/rolePersistence.ts
new file mode 100644
index 0000000..cd62e6e
--- /dev/null
+++ b/packages/gateway/src/database/rolePersistence.ts
@@ -0,0 +1,118 @@
+/* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */
+
+import { GuildMember, Role } from "discord.js";
+import prisma from "../database/prisma";
+import { log, LogLevel, logUnexpectedDiscordAPIError } from "../utilities";
+
+export class RolePersistenceService {
+ static async saveUserRoles(member: GuildMember): Promise<void> {
+ try {
+ const userId = member.user.id;
+ const guildId = member.guild.id;
+ const roles = member.roles.cache.filter(
+ (role) => role.id !== member.guild.id,
+ );
+
+ if (roles.size === 0) return;
+
+ await prisma.userRole.deleteMany({
+ where: {
+ userId,
+ guildId,
+ },
+ });
+
+ const roleData = Array.from(roles.keys()).map((roleId) => ({
+ userId,
+ guildId,
+ roleId,
+ }));
+
+ await prisma.userRole.createMany({
+ data: roleData,
+ });
+ } catch (error) {
+ logUnexpectedDiscordAPIError(error);
+ }
+ }
+
+ static async restoreUserRoles(member: GuildMember): Promise<void> {
+ try {
+ const userId = member.user.id;
+ const guildId = member.guild.id;
+ const savedRoles = await prisma.userRole.findMany({
+ where: {
+ userId,
+ guildId,
+ },
+ });
+
+ if (savedRoles.length === 0) return;
+
+ const validRoles: Role[] = [];
+
+ for (const savedRole of savedRoles) {
+ const role = member.guild.roles.cache.get(savedRole.roleId);
+
+ if (role && role.id !== member.guild.id) validRoles.push(role);
+ }
+
+ if (validRoles.length === 0) {
+ await prisma.userRole.deleteMany({
+ where: {
+ userId,
+ guildId,
+ },
+ });
+
+ return;
+ }
+
+ await member.roles.add(validRoles);
+ await prisma.userRole.deleteMany({
+ where: {
+ userId,
+ guildId,
+ },
+ });
+ } catch (error) {
+ logUnexpectedDiscordAPIError(error);
+ }
+ }
+
+ static async clearUserRoles(userId: string, guildId: string): Promise<void> {
+ try {
+ await prisma.userRole.deleteMany({
+ where: {
+ userId,
+ guildId,
+ },
+ });
+ } catch (error) {
+ logUnexpectedDiscordAPIError(error);
+ }
+ }
+
+ static async getSavedRoles(
+ userId: string,
+ guildId: string,
+ ): Promise<string[]> {
+ try {
+ const savedRoles = await prisma.userRole.findMany({
+ where: {
+ userId,
+ guildId,
+ },
+ select: {
+ roleId: true,
+ },
+ });
+
+ return savedRoles.map((role: { roleId: string }) => role.roleId);
+ } catch (error) {
+ logUnexpectedDiscordAPIError(error);
+
+ return [];
+ }
+ }
+}
diff --git a/packages/gateway/src/listeners/index.ts b/packages/gateway/src/listeners/index.ts
index 7547d4f..21da227 100644
--- a/packages/gateway/src/listeners/index.ts
+++ b/packages/gateway/src/listeners/index.ts
@@ -6,6 +6,7 @@ import { handleMessageDeletion } from "./messageDeletion";
import { handleMessageEdit } from "./messageEdit";
import { handleClientReady } from "./clientReady";
import { handleMemberJoin } from "./memberJoin";
+import { handleMemberLeave } from "./memberLeave";
import { handleTimeoutMirroring } from "./timeoutMirroring";
import { handleAutoDeletion } from "./autoDeletion";
// import { handleMediaModeration } from "./mediaModeration";
@@ -18,6 +19,7 @@ export const handleListeners = (client: Client) => {
handleMessageDeletion(client);
handleMessageEdit(client);
handleMemberJoin(client);
+ handleMemberLeave(client);
handleTimeoutMirroring(client);
handleAutoDeletion(client);
// handleMediaModeration(client);
diff --git a/packages/gateway/src/listeners/memberJoin.ts b/packages/gateway/src/listeners/memberJoin.ts
index cceae35..97df730 100644
--- a/packages/gateway/src/listeners/memberJoin.ts
+++ b/packages/gateway/src/listeners/memberJoin.ts
@@ -7,6 +7,7 @@ import {
import { WELCOME_GREETINGS, WELCOME_ENDINGS } from "./messageCreate/constants";
import { logUnexpectedDiscordAPIError } from "../utilities";
import { logUnexpectedDiscordAPIResult } from "../../../shared/log";
+import { RolePersistenceService } from "../database/rolePersistence";
const CENTRAL_WELCOME_CHANNEL_ID = "1406422619087044670";
const ROLEPLAY_WELCOME_CHANNEL_ID = "1423919140606971927";
@@ -29,7 +30,6 @@ class WelcomeMessageSystem {
private async initializePersistentWebhook() {
if (!this.client) return;
- // Initialize central server webhook
try {
const centralChannel = this.client.channels.cache.get(
CENTRAL_WELCOME_CHANNEL_ID,
@@ -99,6 +99,12 @@ class WelcomeMessageSystem {
public async handleMemberJoin(member: GuildMember): Promise<void> {
if (!this.client) await this.setClient(member.client);
+ try {
+ await RolePersistenceService.restoreUserRoles(member);
+ } catch (error) {
+ logUnexpectedDiscordAPIError(error);
+ }
+
if (
member.guild.id !== CENTRAL_GUILD_ID &&
member.guild.id !== ROLEPLAY_GUILD_ID
diff --git a/packages/gateway/src/listeners/memberLeave.ts b/packages/gateway/src/listeners/memberLeave.ts
new file mode 100644
index 0000000..e348917
--- /dev/null
+++ b/packages/gateway/src/listeners/memberLeave.ts
@@ -0,0 +1,18 @@
+/* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */
+
+import { Client, Events, GuildMember } from "discord.js";
+import { RolePersistenceService } from "../database/rolePersistence";
+import { log, LogLevel, logUnexpectedDiscordAPIError } from "../utilities";
+
+export const handleMemberLeave = (client: Client) => {
+ client.on(Events.GuildMemberRemove, async (member) => {
+ try {
+ if (!member.user) return;
+
+ if ("roles" in member)
+ await RolePersistenceService.saveUserRoles(member as GuildMember);
+ } catch (error) {
+ logUnexpectedDiscordAPIError(error);
+ }
+ });
+};