From 94d2fc40e66b9388d82d50044c122fe2356e7801 Mon Sep 17 00:00:00 2001 From: moriese Date: Sun, 5 Jan 2025 03:51:02 +0100 Subject: [PATCH] good progress :3 --- src/actions/dm/dm.components.ts | 5 + src/actions/dm/dm.service.ts | 55 ++++++++ src/actions/drink/drink.service.ts | 2 +- src/actions/greeting/greeting.components.ts | 23 +++- src/actions/greeting/greeting.service.ts | 124 ++++++++++++++----- src/actions/medication/medication.service.ts | 19 ++- src/actions/waterMe/waterMe.service.ts | 2 +- src/commands/index.ts | 12 +- src/config.ts | 10 +- src/controllers/discord.controller.ts | 25 +++- src/db/index.ts | 1 + src/lib/client.ts | 19 ++- 12 files changed, 243 insertions(+), 54 deletions(-) create mode 100644 src/actions/dm/dm.components.ts create mode 100644 src/actions/dm/dm.service.ts diff --git a/src/actions/dm/dm.components.ts b/src/actions/dm/dm.components.ts new file mode 100644 index 0000000..0636f97 --- /dev/null +++ b/src/actions/dm/dm.components.ts @@ -0,0 +1,5 @@ +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/src/actions/dm/dm.service.ts b/src/actions/dm/dm.service.ts new file mode 100644 index 0000000..d18a2ae --- /dev/null +++ b/src/actions/dm/dm.service.ts @@ -0,0 +1,55 @@ +import config from "config"; +import client from "lib/client"; +import { getRandomInt } from "lib/utils"; +import { dmWelcomeContent, dmAcceptedContent } from "./dm.components.ts"; +import { + Client, + EmbedBuilder, + type Message, + type CacheType, + type GuildMember, + type Interaction, + type OmitPartialGroupDMChannel, +} from "discord.js"; + +export class DmService { + async handleInteraction(interaction: Interaction) { + // todo ? + } + + async welcomePrivate(member: GuildMember) { + console.log("welcome private"); + try { + await client.users.send(member, dmWelcomeContent); + } catch (error) { + console.error("error while sending a welcome msg:", error); + } + } + + async welcomePrivateTest() { + console.log("test welcome private"); + try { + await client.users.send(config.discord.myId, dmWelcomeContent); + } catch (error) { + console.error("error while sending a welcome msg:", error); + } + } + + async forward(message: OmitPartialGroupDMChannel>) { + console.log("forward message"); + + const context = `<@${message.author.id}> hat geschrieben: " ${message.content} "`; + + console.log(context); + client.users.send(config.discord.myId, context); + } + + async acceptDm(member: GuildMember) { + console.log("acceept dm"); + try { + await client.users.send(member, dmAcceptedContent); + } catch (error) { + console.error("error while sending a accept msg:", error); + } + } +} diff --git a/src/actions/drink/drink.service.ts b/src/actions/drink/drink.service.ts index 519eb4c..00e1b55 100644 --- a/src/actions/drink/drink.service.ts +++ b/src/actions/drink/drink.service.ts @@ -5,7 +5,7 @@ export class GreetingService { async greet() { const channels = client.channels; - const channel = channels.cache.get(config.discord.channelId); + const channel = channels.cache.get(config.discord.channelIdBot); if (channel?.isTextBased && channel?.isSendable()) { await channel.send({ content: "HALLOOOO" }); diff --git a/src/actions/greeting/greeting.components.ts b/src/actions/greeting/greeting.components.ts index 742e9f5..dd071a8 100644 --- a/src/actions/greeting/greeting.components.ts +++ b/src/actions/greeting/greeting.components.ts @@ -1,5 +1,26 @@ import config from "config"; +import { EmbedBuilder } from "discord.js"; export const greetContent = ["HALLOOOO", "guten morgen! ich hoffe es geht euch gut <3"]; export const sleepContent = ["gute nacht! ich muss jetzt schlafen gehen :c", "zzzzZZ..", "*schnarch*"]; -export const customContent = `hey <@&${config.discord.mentionStudy}>! meine [eigene website](https://avocadi.unom.io) ist endlich on :3\ngebe mir gerne rueckmeldung unter <#${config.discord.channelIdFeedback}>! <3`; +export const customContent = `hey <@&${config.discord.roleStudy}>! meine [eigene website](https://avocadi.unom.io) ist endlich on :3\ngebe mir gerne rueckmeldung unter <#${config.discord.channelIdFeedback}>! <3`; +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>`; + +export function createEmbed() { + // ({ embeds: [exampleEmbed] }) + console.log("createEmbed()"); + + const exampleEmbed = new EmbedBuilder() + .setColor(0x004400) + .setAuthor({ + name: "avocadi - neuigkeiten", + iconURL: + "https://media.discordapp.net/attachments/1321933410188656693/1323447010380222474/mo_Avocadi_Avatar_Closeup_2.png?ex=67748b93&is=67733a13&hm=f48efb3523bca5f50e79144c7b41a127c94670e693e3da3dc2e6ffe62ad8a769&=&format=webp&quality=lossless&width=1524&height=1524", + url: "https://avocadi.unom.io", + }) + .setDescription(customContent) + .setTimestamp(); + //.setFooter({ text: 'Some footer text here', iconURL: 'https://i.imgur.com/AfFp7pu.png' }); + return exampleEmbed; +} \ No newline at end of file diff --git a/src/actions/greeting/greeting.service.ts b/src/actions/greeting/greeting.service.ts index 85b6245..4887c7e 100644 --- a/src/actions/greeting/greeting.service.ts +++ b/src/actions/greeting/greeting.service.ts @@ -5,68 +5,126 @@ import { customContent, greetContent, sleepContent, + createEmbed, } from "./greeting.components.ts"; -import { Client, EmbedBuilder, type GuildMember } from "discord.js"; +import { + type ChatInputCommandInteraction, + Client, + EmbedBuilder, + type CacheType, + type GuildMember, + type Interaction, +} from "discord.js"; +import { DmService } from "actions/dm/dm.service.ts"; export class GreetingService { - async customMessage() { - console.log("custom message"); + dmService: DmService; - const channels = client.channels; + constructor() { + this.dmService = new DmService(); + } - const channel = channels.cache.get(config.discord.channelIdBot); + async handleInteraction( + interaction: Interaction + ) { + console.log("accept"); - if (channel?.isTextBased && channel?.isSendable()) { - await channel.send({ embeds: [this.createEmbed()] }); + if (interaction.isChatInputCommand()) { + await this.acceptUser(interaction); } } - createEmbed() { - // ({ embeds: [exampleEmbed] }) - console.log("createEmbed()"); + async custom() { + console.log("custom message"); - const exampleEmbed = new EmbedBuilder() - .setColor(0x004400) - .setAuthor({ - name: "avocadi - neuigkeiten", - iconURL: - "https://media.discordapp.net/attachments/1321933410188656693/1323447010380222474/mo_Avocadi_Avatar_Closeup_2.png?ex=67748b93&is=67733a13&hm=f48efb3523bca5f50e79144c7b41a127c94670e693e3da3dc2e6ffe62ad8a769&=&format=webp&quality=lossless&width=1524&height=1524", - url: "https://avocadi.unom.io", - }) - .setDescription(customContent) - .setTimestamp(); - //.setFooter({ text: 'Some footer text here', iconURL: 'https://i.imgur.com/AfFp7pu.png' }); - return exampleEmbed; + client.users.send(config.discord.myId, "hat funktioniert :)"); } async welcome(member: GuildMember) { - const welcomeMessages = [ + console.log("welcome msg"); + + const welcomeContents = [ `willkommen auf dem server, ${member}! 💕`, `hey ${member}! schoen, dass du hier bist! 😊`, `hi ${member}, willkommen! viel spass hier! 💖`, `willkommen, ${member}! schoen, dass du da bist! 🥳`, `moin ${member}! viel spass im server! c:`, - `hey ${member}! herzlich willkommen! fühl dich wie zu hause! 🏡`, + `hey ${member}, herzlich willkommen! fuehl dich wie zu hause! <3`, `hi ${member}! cool, dass du da bist! 👏`, `willkommen, ${member}! wir freuen uns, dass du hier bist! 💕`, `hey ${member}! schoen, dass du bei uns bist! :3`, - `willkommen auf dem server, ${member}! viel spass hier! ✨` + `willkommen auf dem server, ${member}! viel spass hier! ✨`, ]; - const randomMessage = `${welcomeMessages[Math.floor(Math.random() * welcomeMessages.length)]} bitte stelle dich kurz in <#${config.discord.channelIdIntro}> vor. sobald wir deine nachricht gelesen haben, vergeben wir dir die rolle *lernende:r*, damit du alle kanaele nutzen kannst viel spass und bis bald! :) `; + const welcomeContent = + welcomeContents[Math.floor(Math.random() * welcomeContents.length)]; try { - console.log("welcome msg"); - const channels = client.channels; - const channel = channels.cache.get( - config.discord.channelIdWelcome, - ); + const channel = channels.cache.get(config.discord.channelIdWelcome); if (channel?.isTextBased() && channel?.isSendable()) { - await channel.send(randomMessage); + await channel.send(welcomeContent); } } catch (error) { - console.error("error while senden a welcome msg:", error); + console.error("error while sending a welcome msg:", error); + } + } + + async acceptUser( + interaction: ChatInputCommandInteraction + ) { + console.log("accept user"); + + // get the string option + const input = interaction.options.getString("input") || ""; + // return the value + //console.log(input); + + // permission check + const userIdCommand = interaction.user.id; + if (userIdCommand !== config.discord.myId) { + await interaction.reply({ + content: "you have no permission for that command", + ephemeral: true, + }); + return; + } + + try { + // get user id from mentioning + const userId = input.replace(/[<@!>]/g, ""); + console.log(userId.toString()); + const guild = interaction.guild; + if (!guild) { + await interaction.reply({ + content: "command can only be used on a server", + ephemeral: true, + }); + return; + } + + const username = (await guild.members.fetch(userId)).user.username; + console.log(username); + // get member from id + const member = await guild.members.fetch(userId); + + const role = config.discord.roleStudy; + + await member.roles.add(role); + + await interaction.reply({ + content: `die rolle *lernende:r* wurde erfolgreich an ${member.user.username} vergeben`, + ephemeral: true, + }); + + this.dmService.acceptDm(member); + } catch (error) { + console.error("Fehler beim Hinzufügen der Rolle:", error); + await interaction.reply({ + content: + "Es gab einen Fehler beim Hinzufügen der Rolle. Stelle sicher, dass du einen gültigen User erwähnt hast.", + ephemeral: true, + }); } } diff --git a/src/actions/medication/medication.service.ts b/src/actions/medication/medication.service.ts index 2a8f8b1..797a704 100644 --- a/src/actions/medication/medication.service.ts +++ b/src/actions/medication/medication.service.ts @@ -29,7 +29,7 @@ export class MedicationService { async askMedication() { const channels = client.channels; - const channel = channels.cache.get(config.discord.channelId); + const channel = channels.cache.get(config.discord.channelIdBot); // funkt noch nicht, beides @@ -50,7 +50,7 @@ export class MedicationService { } getMedication() { - throw new Error("Method not implemented."); + // todo } setMedication() { @@ -104,7 +104,7 @@ export class MedicationService { const tookMedication = interaction.customId === "yesMedication"; - interaction.reply({ + await interaction.reply({ content: tookMedication ? "das hast du toll gemacht <3 mach weiter so :3" : "das passiert mal... aber versuch sie heute noch zu nehmen, oki? :)", @@ -134,8 +134,7 @@ export class MedicationService { }); } - /** - * Methode, um die Benutzerdaten in die Datenbank zu schreiben. + /**, um die Benutzerdaten in die Datenbank zu schreiben. * @param discordId unique user id * @param name name how the user wants to get called by avocadi * @param tookMedication if user took medication @@ -155,9 +154,9 @@ export class MedicationService { took_medication_today: Number(tookMedication), }); */ - console.log(`Benutzer mit ID ${id} wurde in der Datenbank gespeichert.`); + console.log(`user with id ${id} saved`); } catch (error) { - console.error("Fehler beim Speichern in der Datenbank:", error); + console.error("error while saving in db:", error); } } @@ -192,11 +191,11 @@ export class MedicationService { console.log(`ID für Discord-ID ${discordId} gefunden: ${result[0].id}`); return result[0].id; } - console.log(`Keine ID für Discord-ID ${discordId} gefunden.`); + console.log(`no id for discordId ${discordId} found`); return null; } catch (error) { console.error( - `Fehler beim Abrufen der ID für Discord-ID ${discordId}:`, + `error while calling id for discordId ${discordId}:`, error, ); return null; @@ -213,7 +212,7 @@ export class MedicationService { } console.log( - `found no entry for discordID ${discordId}. creating new entry.`, + `found no entry for discordID ${discordId}. creating new entry`, ); const result = await db diff --git a/src/actions/waterMe/waterMe.service.ts b/src/actions/waterMe/waterMe.service.ts index 649112c..f12c5b7 100644 --- a/src/actions/waterMe/waterMe.service.ts +++ b/src/actions/waterMe/waterMe.service.ts @@ -52,7 +52,7 @@ export class WaterMeService { async isThirsty() { const channels = client.channels; - const channel = channels.cache.get(config.discord.channelId); + const channel = channels.cache.get(config.discord.channelIdBot); if ( channel?.isTextBased && diff --git a/src/commands/index.ts b/src/commands/index.ts index 31b4a6c..b4ef036 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,7 +1,7 @@ import { SlashCommandBuilder, userMention } from "discord.js"; import { z } from "zod"; -export const Commands = z.enum(["giessen", "medikamente", "hilfe"]); +export const Commands = z.enum(["giessen", "medikamente", "hilfe", "accept"]); export const CommandsMeta: Record, { description: string }> = { giessen: { @@ -13,6 +13,9 @@ export const CommandsMeta: Record, { description: stri hilfe: { description: "ich schreibe dir auf, was du alles mit mir machen kannst :)" }, + accept: { + description: "admin use only" + } } export type CommandsType = z.output; @@ -28,6 +31,13 @@ export default function getCommands() { new SlashCommandBuilder() .setName(Commands.Enum.hilfe) .setDescription(CommandsMeta.hilfe.description), + new SlashCommandBuilder() + .setName(Commands.Enum.accept) + .setDescription(CommandsMeta.accept.description) + .addStringOption(option => + option.setName('input') + .setDescription('input for bot') + .setRequired(true)), ].map((command) => command.toJSON()); return commands; diff --git a/src/config.ts b/src/config.ts index 32660a3..9cc42a0 100644 --- a/src/config.ts +++ b/src/config.ts @@ -5,14 +5,20 @@ export default { channelIdBot: process.env.DISCORD_CHANNEL_ID_BOT || "", // avocadi + serverID: process.env.DISCORD_SERVER_ID || "", channelIdNews: process.env.DISCORD_CHANNEL_ID_NEWS || "", channelIdFeedback: process.env.DISCORD_CHANNEL_ID_FEEDBACK || "", - channelIdIntro: process.env.DISCORD_CHANNEL_ID_INTRO || "", + channelIdIntroduction: process.env.DISCORD_CHANNEL_ID_INTRODUCTION || "", channelIdWelcome: process.env.DISCORD_CHANNEL_ID_WELCOME || "", - mentionStudy: process.env.PEOPLE || "", + channelIdOffTopic: process.env.DISCORD_CHANNEL_ID_OFF_TOPIC || "", + roleStudy: process.env.PEOPLE || "", // other applicationId: process.env.DISCORD_APPLICATION_ID || "", token: process.env.DISCORD_TOKEN || "", + + botId: process.env.BOT_ID || "", + myId: process.env.MY_ID || "", + enricoId: process.env.ENRICO_ID || "", }, }; diff --git a/src/controllers/discord.controller.ts b/src/controllers/discord.controller.ts index 236ffee..4eaa743 100644 --- a/src/controllers/discord.controller.ts +++ b/src/controllers/discord.controller.ts @@ -1,6 +1,8 @@ import { Commands, type CommandsType } from "commands"; import { + ChannelType, Client, + Events, IntentsBitField, type ButtonInteraction, type CacheType, @@ -18,6 +20,7 @@ import { HelpService } from "actions/help/help.service"; import { custom } from "zod"; import { GreetingService } from "actions/greeting/greeting.service"; import { ActivityService } from "actions/activity/activity.service"; +import { DmService } from "actions/dm/dm.service"; export default class DiscordController extends EventEmitter { private discordService!: DiscordService; @@ -26,6 +29,7 @@ export default class DiscordController extends EventEmitter { medicationService: MedicationService; helpService: HelpService; activityService: ActivityService; + dmService: DmService; constructor() { super(); @@ -35,17 +39,29 @@ export default class DiscordController extends EventEmitter { this.medicationService = new MedicationService(); this.helpService = new HelpService(); this.activityService = new ActivityService(); + this.dmService = new DmService(); // log when running client.once("ready", async () => { - this.setActivity(); - this.greetingService.customMessage(); + await this.setActivity(); + console.log("ready"); }); // listen for interactions client.on("interactionCreate", this.handleInteraction.bind(this)); + + client.on("messageCreate", async (message) => { + console.log(message.id) + if (message.channel.type === ChannelType.DM + && message.author.id !== config.discord.botId + ) { + console.log("got msg"); + this.dmService.forward(message); + } + }); + client.on("guildMemberAdd", async (member) => { - console.log("client on guildMemberAdd"); await this.greetingService.welcome(member); + await this.dmService.welcomePrivate(member); }); } @@ -105,6 +121,9 @@ export default class DiscordController extends EventEmitter { case Commands.Enum.hilfe: await this.helpService.handleInteraction(interaction); return; + case Commands.Enum.accept: + await this.greetingService.handleInteraction(interaction); + return; default: break; } diff --git a/src/db/index.ts b/src/db/index.ts index 934d492..e08e96c 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -1,3 +1,4 @@ import { drizzle } from "drizzle-orm/bun-sqlite"; +// biome-ignore lint/style/noNonNullAssertion: export const db = drizzle(process.env.DB_FILE_NAME!); \ No newline at end of file diff --git a/src/lib/client.ts b/src/lib/client.ts index d23393c..cbaa4ee 100644 --- a/src/lib/client.ts +++ b/src/lib/client.ts @@ -1,7 +1,22 @@ import config from "config"; -import { Client, IntentsBitField } from "discord.js"; +import { Client, GatewayIntentBits, Partials, ChannelType, Events, IntentsBitField } from "discord.js"; -const client = new Client({ intents: [IntentsBitField.Flags.Guilds, IntentsBitField.Flags.GuildMessages, IntentsBitField.Flags.GuildMembers] }); +const client = new Client({ + intents: [IntentsBitField.Flags.Guilds, + IntentsBitField.Flags.GuildMembers, + IntentsBitField.Flags.GuildModeration, + IntentsBitField.Flags.GuildMessages, + IntentsBitField.Flags.GuildMessageReactions, + IntentsBitField.Flags.GuildMessagePolls, + IntentsBitField.Flags.MessageContent, + IntentsBitField.Flags.DirectMessages, + IntentsBitField.Flags.DirectMessageReactions, + IntentsBitField.Flags.DirectMessageTyping, + IntentsBitField.Flags.DirectMessagePolls, + GatewayIntentBits.DirectMessages, + GatewayIntentBits.MessageContent], + partials: [Partials.Channel, Partials.Message] +}); await client.login(config.discord.token);