From 0e014dd08dbdf0d9a0204bdeda81341e83bba4a3 Mon Sep 17 00:00:00 2001 From: mo Date: Sun, 1 Mar 2026 16:50:43 +0100 Subject: [PATCH] accept user discord implementation --- .../src/entities/roles/roles.service.ts | 11 ++- .../accept-user/accept-user.service.ts | 10 +++ .../log-channel/log-channel.service.ts | 5 +- .../listeners/reactions/reactions.listener.ts | 72 +++++++++++++++---- .../log-channel/log-channel.service.ts | 5 +- core/src/actions/dm/dm.components.ts | 5 -- core/src/locales/de/accept-user.ts | 3 + core/src/locales/en/accept-user.ts | 4 ++ 8 files changed, 93 insertions(+), 22 deletions(-) create mode 100644 adapters/discord/src/features/accept-user/accept-user.service.ts delete mode 100644 core/src/actions/dm/dm.components.ts create mode 100644 core/src/locales/de/accept-user.ts create mode 100644 core/src/locales/en/accept-user.ts diff --git a/adapters/discord/src/entities/roles/roles.service.ts b/adapters/discord/src/entities/roles/roles.service.ts index f126332..a4e9584 100644 --- a/adapters/discord/src/entities/roles/roles.service.ts +++ b/adapters/discord/src/entities/roles/roles.service.ts @@ -5,12 +5,15 @@ import type { GuildMember } from "discord.js"; export class RolesService implements RolesServiceInterface { private logger = createLogger("RolesService"); - async assignRole(user: GuildMember, role: string) { - const roleToAssign = user.guild.roles.cache.find((r) => r.name === role); + async assignRole(user: GuildMember, roleId: string) { + const roleToAssign = user.guild.roles.cache.find((r) => r.id === roleId); if (!roleToAssign) { - this.logger.error(`Role ${role} not found in guild ${user.guild.name}.`); + this.logger.error( + `Role ${roleId} not found in guild ${user.guild.name}.`, + ); return; } + this.logger.info(`Role ${roleId} found in guild ${user.guild.name}.`); await user.roles.add(roleToAssign); } @@ -23,10 +26,12 @@ export class RolesService implements RolesServiceInterface { await user.roles.remove(roleToRemove); } + /*** get all roles of GuildMember */ async getRoles(user: GuildMember) { return user.roles.cache.map((role) => role.name); } + /*** check if GuildMember has a specific role */ async hasRole(user: GuildMember, role: string) { return user.roles.cache.some((r) => r.name === role); } diff --git a/adapters/discord/src/features/accept-user/accept-user.service.ts b/adapters/discord/src/features/accept-user/accept-user.service.ts new file mode 100644 index 0000000..7242e6b --- /dev/null +++ b/adapters/discord/src/features/accept-user/accept-user.service.ts @@ -0,0 +1,10 @@ +import { AcceptUserService } from "@avocadi/bot-core/features/accept-user/accept-user.service"; +import { i18nService } from "@avocadi/bot-core/lib/i18n"; +import type { User } from "discord.js"; +import { messagesService } from "entities/messages/messages.service"; + +export const acceptUserService = new AcceptUserService( + messagesService, + i18nService, + "de", +); diff --git a/adapters/discord/src/features/log-channel/log-channel.service.ts b/adapters/discord/src/features/log-channel/log-channel.service.ts index b5b4661..3635250 100644 --- a/adapters/discord/src/features/log-channel/log-channel.service.ts +++ b/adapters/discord/src/features/log-channel/log-channel.service.ts @@ -3,7 +3,10 @@ import client from "lib/client"; import { logger } from "lib/common-logger"; export class LogChannelService { - private logChannelId = config.channelMapping.text.log; + private logChannelId = + process.env.NODE_ENV === "production" + ? config.channelMapping.text.log + : config.channelMapping.text.testing; async getLogChannel() { const logChannel = await client.channels.fetch(this.logChannelId); diff --git a/adapters/discord/src/listeners/reactions/reactions.listener.ts b/adapters/discord/src/listeners/reactions/reactions.listener.ts index acb9524..5671771 100644 --- a/adapters/discord/src/listeners/reactions/reactions.listener.ts +++ b/adapters/discord/src/listeners/reactions/reactions.listener.ts @@ -1,20 +1,68 @@ -import { Roles } from "@avocadi/bot-core/entities/roles/roles.schema"; -import { ReactionRolesService } from "features/reaction-roles/reaction-roles.service"; +import { createLogger } from "@avocadi/bot-core/lib/logger"; +import type { User } from "@fluxerjs/core"; +import { config } from "config"; +import { RolesService } from "entities/roles/roles.service"; +import { acceptUserService } from "features/accept-user/accept-user.service"; +import { logChannelService } from "features/log-channel/log-channel.service"; import client from "lib/client"; -const reactionRolesService = new ReactionRolesService(); +const logger = createLogger("ReactionsListener"); -// Currently only used for the "people" role, but can be extended to handle multiple roles based on the reaction emoji +// client.on("messageReactionRemove", async (reaction, user) => { +// reactionRolesService.handleReaction( +// reaction, +// user, +// Roles.enum.people, +// "remove", +// ); +// }); client.on("messageReactionAdd", async (reaction, user) => { - reactionRolesService.handleReaction(reaction, user, Roles.enum.people, "add"); -}); + const guild = reaction.message.guild; + if (!guild) { + logger.error(`Guild not found for message ${reaction.message.id}.`); + return; + } + logger.info(`Guild found for message ${reaction.message.id}.`); -client.on("messageReactionRemove", async (reaction, user) => { - reactionRolesService.handleReaction( - reaction, - user, - Roles.enum.people, - "remove", + const channelIntroduction = await client.channels.fetch( + config.channelMapping.text.introduction, ); + + const message = await reaction.message.fetch(); + + // check if valid channel + if (message.guild?.id && message.channel?.id === channelIntroduction?.id) { + logger.info("valid channel"); + + const member = guild?.members.cache.get(user.id); + + // check if member who reacted has role MOD + if (member?.roles.cache.get(config.roleMapping.mod)) { + const messageAuthor_User = await message.author.fetch(); + + if (messageAuthor_User) { + const roleMemberId = config.roleMapping.people; + + const messageAuthor_GuildMember = await guild?.members.fetch( + messageAuthor_User.id, + ); + if ( + !messageAuthor_GuildMember?.roles.cache.find( + (r) => r.id === roleMemberId, + ) + ) { + logger.info(`accepting ${messageAuthor_User?.username}...`); + + const rolesService = new RolesService(); + rolesService.assignRole(messageAuthor_GuildMember, roleMemberId); + + await acceptUserService.sendDmAcceptUser(messageAuthor_User); + await logChannelService.sendLogMessage( + `introduction of <@${messageAuthor_User.id}> (${messageAuthor_User.username}) got accepted`, + ); + } + } + } + } }); diff --git a/adapters/fluxer/src/features/log-channel/log-channel.service.ts b/adapters/fluxer/src/features/log-channel/log-channel.service.ts index cb5bc31..92764d7 100644 --- a/adapters/fluxer/src/features/log-channel/log-channel.service.ts +++ b/adapters/fluxer/src/features/log-channel/log-channel.service.ts @@ -5,7 +5,10 @@ import client from "lib/client"; export class LogChannelService { private logger = createLogger("LogChannelService"); - private logChannelId = config.channelMapping.text.log; + private logChannelId = + process.env.NODE_ENV === "production" + ? config.channelMapping.text.log + : config.channelMapping.text.testing; async getLogChannel() { this.logger.debug(`fetching log channel with ID: ${this.logChannelId}`); diff --git a/core/src/actions/dm/dm.components.ts b/core/src/actions/dm/dm.components.ts deleted file mode 100644 index 0636f97..0000000 --- a/core/src/actions/dm/dm.components.ts +++ /dev/null @@ -1,5 +0,0 @@ -import config from "config"; -import { EmbedBuilder } from "discord.js"; - -export const dmWelcomeContent = `hey! ich bin avocadi von [avocadi-study]()!\n\num auf den rest des servers zugreifen zu koennen, musst du dich noch vorstellen (unter <#${config.discord.channelIdIntroduction}>)!\n\n---\nname und alter:\npronomen:\nklasse/studiengang/beruf:\nhobby:\nueber mich:\n---\n\nsobald wir deine nachricht ueberprueft haben, bekommst du die rolle **lernende:r** :)`; -export const dmAcceptedContent = `huhu! du wurdest als lernende:r akzeptiert :3\nsag gerne hallo: <#${config.discord.channelIdOffTopic}> <:avocadi_cute:1321893797138923602>`; \ No newline at end of file diff --git a/core/src/locales/de/accept-user.ts b/core/src/locales/de/accept-user.ts new file mode 100644 index 0000000..c5c2654 --- /dev/null +++ b/core/src/locales/de/accept-user.ts @@ -0,0 +1,3 @@ +export default { + dmAcceptUser: `huhu! du wurdest als lernende:r akzeptiert :3\nsag gerne hallo!`, +} as const; diff --git a/core/src/locales/en/accept-user.ts b/core/src/locales/en/accept-user.ts new file mode 100644 index 0000000..dc6e706 --- /dev/null +++ b/core/src/locales/en/accept-user.ts @@ -0,0 +1,4 @@ +export default { + dmAcceptUser: `hey there! you've been accepted :3 + feel free to say hello!`, +} as const;