diff options
| author | Fuwn <[email protected]> | 2025-10-23 23:36:36 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2025-10-23 23:36:39 -0700 |
| commit | 46c40a53a569f5f27de016bc0215bf30dcdba1a5 (patch) | |
| tree | bec0ed98689296b6358e1f1c38c20ba6df01705b /packages/gateway/src | |
| parent | feat(gateway:listeners): Add auto message deletion (diff) | |
| download | umabotdiscord-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.ts | 9 | ||||
| -rw-r--r-- | packages/gateway/src/database/rolePersistence.ts | 118 | ||||
| -rw-r--r-- | packages/gateway/src/listeners/index.ts | 2 | ||||
| -rw-r--r-- | packages/gateway/src/listeners/memberJoin.ts | 8 | ||||
| -rw-r--r-- | packages/gateway/src/listeners/memberLeave.ts | 18 |
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); + } + }); +}; |