diff --git a/discordBot/addons/linkCop.mjs b/discordBot/addons/linkCop.mjs index 614c06d..107263b 100644 --- a/discordBot/addons/linkCop.mjs +++ b/discordBot/addons/linkCop.mjs @@ -2,25 +2,30 @@ import { DebugBuilder } from "../../modules/debugger.mjs"; const log = new DebugBuilder("server", "discordBot.addons.linkCop"); import { gptHandler } from "../modules/gptHandler.mjs"; import dotenv from "dotenv"; +import { getGuildConfig, setGuildConfig } from "../../modules/mongo-wrappers/mongoConfigWrappers.mjs"; dotenv.config(); -const approvedLinksChannel = "767303243285790721"; -const restrictedChannelIds = - process.env.LINKCOP_RESTRICTED_CHANNEL_IDS.split(","); - -const linkRegExp = - /(?:http[s]?:\/\/)?(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)/g; +const linkRegExp = /http[s]?:\/\/\S+/g; export const linkCop = async (nodeIo, message) => { - if ( - message.channel.id == approvedLinksChannel || - !restrictedChannelIds.includes(message.channel.id) - ) - return false; + // Set the channel IDs based on the guild the message was sent in + const approvedLinksChannel = await getGuildConfig(message.guild.id, "approvedLinksChannel") || "767303243285790721"; + const restrictedChannelIds = await getGuildConfig(message.guild.id, "restrictedChannelIds"); + + // Check if the message was sent in an restricted channel + if ( + message.channel.id == approvedLinksChannel || !Array.isArray(restrictedChannelIds) || + (Array.isArray(restrictedChannelIds) || !restrictedChannelIds.includes(message.channel.id)) + ) { + return false; + } + + // Check if there are URLs in the sent message + const urls = [...message.content.matchAll(linkRegExp)]; + log.DEBUG("Parsed URLs from message:", urls); - const urls = String(message.content).matchAll(linkRegExp); if (!urls || urls.length === 0) return false; - log.DEBUG("Found URLs: ", urls); + log.INFO("Found URLs: ", urls); let conversation = []; diff --git a/discordBot/discordBot.mjs b/discordBot/discordBot.mjs index 30b1d8d..f4f605f 100644 --- a/discordBot/discordBot.mjs +++ b/discordBot/discordBot.mjs @@ -8,6 +8,7 @@ import { RSSController } from "../rss-manager/rssController.mjs"; import { join, dirname } from "path"; import { readdirSync } from "fs"; import { fileURLToPath } from "url"; +import PresenceManager from "./modules/presenceManager.mjs"; import dotenv from "dotenv"; dotenv.config(); @@ -110,6 +111,10 @@ export const serverClient = new Client({ serverClient.on("ready", async () => { log.INFO(`Logged in as ${serverClient.user.tag}!`); + // Set the presence to default + const pm = new PresenceManager(serverClient); + await pm.resetToDefault(); + // Add and register commands await addEnabledCommands(serverClient); diff --git a/discordBot/events/guildMemberAdd.mjs b/discordBot/events/guildMemberAdd.mjs index 2d355cb..70f39fb 100644 --- a/discordBot/events/guildMemberAdd.mjs +++ b/discordBot/events/guildMemberAdd.mjs @@ -4,12 +4,12 @@ import dotenv from "dotenv"; dotenv.config(); import { Events } from "discord.js"; import { gptHandler } from "../modules/gptHandler.mjs"; - -const welcomeChannel = process.env.WELCOME_CHANNEL_ID; // TODO - Need to add a DB section for server configs so it's not static to one server +import { getGuildConfig, setGuildConfig, getConfig, setConfig } from "../../modules/mongo-wrappers/mongoConfigWrappers.mjs"; export const name = Events.GuildMemberAdd; -export async function execute(nodeIo, member) { +export async function execute(nodeIo, member) { + const welcomeChannel = await getGuildConfig(message.guild.id, "welcomeChannelId"); log.INFO("New user joined the server", member); let conversation = []; conversation.push({ diff --git a/discordBot/events/interactionCreate.mjs b/discordBot/events/interactionCreate.mjs index 77fb324..26bee3e 100644 --- a/discordBot/events/interactionCreate.mjs +++ b/discordBot/events/interactionCreate.mjs @@ -1,6 +1,7 @@ import { DebugBuilder } from "../../modules/debugger.mjs"; const log = new DebugBuilder("server", "discordBot.events.interactionCreate"); import { Events } from "discord.js"; +import PresenceManager from "../modules/presenceManager.mjs"; export const name = Events.InteractionCreate; @@ -8,6 +9,10 @@ export async function execute(nodeIo, interaction) { const command = interaction.client.commands.get(interaction.commandName); log.INFO("Interaction created for command: ", command); + // Set the presence for handling interaction + const interactionPm = new PresenceManager(interaction.client); + await interactionPm.setPresence("online", "PLAYING", "handling interaction"); + // Execute autocomplete if the user is checking autocomplete if (interaction.isAutocomplete()) { log.INFO("Running autocomplete for command: ", command.data.name); @@ -33,4 +38,7 @@ export async function execute(nodeIo, interaction) { // Execute the command command.execute(nodeIo, interaction); + + // Reset the presence + await interactionPm.resetToDefault(); } diff --git a/discordBot/events/messageCreate.mjs b/discordBot/events/messageCreate.mjs index 0440690..2c8b1b8 100644 --- a/discordBot/events/messageCreate.mjs +++ b/discordBot/events/messageCreate.mjs @@ -5,25 +5,40 @@ dotenv.config(); import { Events } from "discord.js"; import { gptInteraction } from "../addons/gptInteraction.mjs"; import { linkCop } from "../addons/linkCop.mjs"; - -const IGNORED_CHANNELS = process.env.IGNORED_CHANNEL_IDS.split(","); +import PresenceManager from "../modules/presenceManager.mjs"; +import { getGuildConfig, setGuildConfig } from "../../modules/mongo-wrappers/mongoConfigWrappers.mjs"; export const name = Events.MessageCreate; export async function execute(nodeIo, message) { + // Get the ignored channels from the server config + const IGNORED_CHANNELS = await getGuildConfig(message.guild.id, "ignoredChannels"); + // Ignore ignored channels - if (IGNORED_CHANNELS.includes(message.channel.id)) return; + if (!Array.isArray(IGNORED_CHANNELS) || Array.isArray(IGNORED_CHANNELS) && IGNORED_CHANNELS.includes(message.channel.id)) { return; } // Ignore messages from a bot - if (message.author.bot) return; + if (message.author.bot) { return; } log.INFO("Message create", message); + // Set presence for reading message + const messagePm = new PresenceManager(message.client); + await messagePm.setPresence("online", "WATCHING", "latest messages"); + // Check if the message mentions the bot if (message.mentions.users.has(nodeIo.serverClient.user.id)) { - return await gptInteraction(nodeIo, message); + const interaction = await gptInteraction(nodeIo, message); + + // Reset the presence + await messagePm.resetToDefault(); + + return interaction; } // Check if the message contains a link in a channel it shouldn't - if (await linkCop(nodeIo, message)) return; + await linkCop(nodeIo, message); + + // Reset the presence + await messagePm.resetToDefault(); } diff --git a/modules/mongo-wrappers/mongoConfigWrappers.mjs b/modules/mongo-wrappers/mongoConfigWrappers.mjs index 65c0ea1..bf20344 100644 --- a/modules/mongo-wrappers/mongoConfigWrappers.mjs +++ b/modules/mongo-wrappers/mongoConfigWrappers.mjs @@ -8,9 +8,9 @@ const collectionName = 'configurations'; // Function to get a configuration by key export const getConfig = async (key) => { try { - const config = await getDocumentByField(collectionName, '_id', key); + const config = await getDocumentByField(collectionName, 'key', key); log.DEBUG(`Configuration for key "${key}" retrieved:`, config); - return config || null; // Return null if no configuration is found + return config ? config[key] : null; // Return null if no configuration is found } catch (error) { log.ERROR('Error retrieving configuration:', error); throw error; @@ -19,8 +19,10 @@ export const getConfig = async (key) => { // Function to set a configuration by key export const setConfig = async (key, value) => { + // Set the config object + value = {key : value}; try { - const result = await upsertDocumentByField(collectionName, '_id', key, value); + const result = await upsertDocumentByField(collectionName, 'key', key, value); log.DEBUG(`Configuration for key "${key}" set:`, value, result); return result > 0 ? key : null; // Return key if updated successfully, otherwise null } catch (error) { @@ -32,7 +34,7 @@ export const setConfig = async (key, value) => { // Function to delete a configuration by key (optional) export const deleteConfig = async (key) => { try { - const result = await deleteDocumentByField(collectionName, '_id', key); + const result = await deleteDocumentByField(collectionName, 'key', key); log.DEBUG(`Configuration for key "${key}" deleted:`, result); return result; // Return the count of deleted documents } catch (error) { @@ -44,9 +46,9 @@ export const deleteConfig = async (key) => { // Function to get a configuration by key for a specific guild export const getGuildConfig = async (guildId, key) => { try { - const config = await getDocumentByFields(collectionName, ['guildId', guildId], ['_id', key]); + const config = await getDocumentByFields(collectionName, ['guildId', guildId], ['key', key]); log.DEBUG(`Guild ${guildId} configuration for key "${key}" retrieved:`, config); - return config || null; // Return null if no configuration is found + return config ? config[key] : null; // Return null if no configuration is found } catch (error) { log.ERROR('Error retrieving guild configuration:', error); throw error; @@ -55,8 +57,10 @@ export const getGuildConfig = async (guildId, key) => { // Function to set a configuration by key for a specific guild export const setGuildConfig = async (guildId, key, value) => { + // Set the config object + value = {key : value}; try { - const result = await upsertDocumentByFields(collectionName, value, ['guildId', guildId], ['_id', key]); + const result = await upsertDocumentByFields(collectionName, value, ['guildId', guildId], ['key', key]); log.DEBUG(`Guild ${guildId} configuration for key "${key}" set:`, value); return result > 0 ? key : null; // Return key if updated successfully, otherwise null } catch (error) { @@ -68,7 +72,7 @@ export const setGuildConfig = async (guildId, key, value) => { // Function to delete a configuration by key for a specific guild (optional) export const deleteGuildConfig = async (guildId, key) => { try { - const result = await deleteDocumentByFields(collectionName, ['guildId', guildId], ['_id', key]); + const result = await deleteDocumentByFields(collectionName, ['guildId', guildId], ['key', key]); log.DEBUG(`Guild ${guildId} configuration for key "${key}" deleted:`, result); return result; // Return the count of deleted documents } catch (error) { diff --git a/rss-manager/feedHandler.mjs b/rss-manager/feedHandler.mjs index af506c9..61e0b34 100644 --- a/rss-manager/feedHandler.mjs +++ b/rss-manager/feedHandler.mjs @@ -10,6 +10,7 @@ import { DebugBuilder } from "../modules/debugger.mjs"; import { removeSource } from "./sourceManager.mjs"; import UserAgent from "user-agents"; import Parser from "rss-parser"; +import PresenceManager from "../discordBot/modules/presenceManager.mjs"; import dotenv from "dotenv"; dotenv.config(); @@ -41,6 +42,10 @@ export const returnHash = (...stringsIncluded) => { export const updateFeeds = async (client) => { if (!client) throw new Error("Client object not passed"); + // Setup presence manager + const feedPm = new PresenceManager(client); + await feedPm.setPresence("online", "WATCHING", "for RSS feed updates"); + try { const records = await getAllFeeds(); @@ -106,6 +111,7 @@ export const updateFeeds = async (client) => { await Promise.all(sourcePromiseArray); log.DEBUG("All sources processed"); + await feedPm.resetToDefault(); } catch (error) { log.ERROR("Error updating feeds:", error); throw error;