From 5075a5973dc4cc6dcda3b7fd0fd8441de51f5cff Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Tue, 21 May 2024 20:21:08 -0600 Subject: [PATCH 1/3] Merge subscribe and usersubscribe into just /subscribe --- data/commands.json | 105 ++++----------- index.js | 317 +++++++++++++++++++++++---------------------- 2 files changed, 191 insertions(+), 231 deletions(-) diff --git a/data/commands.json b/data/commands.json index 73692ec..67669d3 100644 --- a/data/commands.json +++ b/data/commands.json @@ -16,78 +16,6 @@ "description": "Custom message to send when alert is sent", "type": 3, "required": false - } - ] - }, - { - "name": "setmessage", - "description": "Set a custom message for a room", - "default_member_permissions": 0, - "options": [ - { - "name": "room", - "description": "The room/WFO you want to set a message for", - "type": 3, - "required": true, - "autocomplete": false - }, - { - "name": "message", - "description": "Custom message to send when alert is sent", - "type": 3, - "required": true - } - ] - }, - { - "name": "unsubscribe", - "description": "Unsubscribe from a weather.im room", - "default_member_permissions": 0, - "options": [ - { - "name": "room", - "description": "The room/WFO you want to unsubscribe from", - "type": 3, - "required": true, - "autocomplete": false - } - ] - }, - - { - "name": "list", - "description": "List all subscribed rooms for this channel", - "default_member_permissions": 0 - }, - { - "name": "about", - "description": "About this bot" - }, - { - "name": "rooms", - "description": "List all available rooms" - }, - { - "name": "setupall", - "description": "[OWNER ONLY] Setup channels in a category for all rooms", - "default_member_permissions": 0, - "type": 1 - }, - { - "name": "support", - "description": "Get support for the bot", - "type": 1 - }, - { - "name": "usersubscribe", - "description": "Subscribe to alerts for a room", - "type": 1, - "options": [ - { - "name": "room", - "description": "The room/WFO you want to subscribe to", - "type": 3, - "required": true }, { "name": "filter", @@ -136,21 +64,42 @@ ] }, { - "name": "userunsubscribe", - "description": "Unsubscribe from alerts for a room", - "type": 1, + "name": "unsubscribe", + "description": "Unsubscribe from a weather.im room", + "default_member_permissions": 0, "options": [ { "name": "room", "description": "The room/WFO you want to unsubscribe from", "type": 3, - "required": true + "required": true, + "autocomplete": false } ] }, + { - "name": "userlist", - "description": "List all subscribed alerts for this user", + "name": "list", + "description": "List all subscribed rooms for this channel", + "default_member_permissions": 0 + }, + { + "name": "about", + "description": "About this bot" + }, + { + "name": "rooms", + "description": "List all available rooms" + }, + { + "name": "setupall", + "description": "[OWNER ONLY] Setup channels in a category for all rooms", + "default_member_permissions": 0, + "type": 1 + }, + { + "name": "support", + "description": "Get support for the bot", "type": 1 }, { diff --git a/index.js b/index.js index 82c1933..f0fcb28 100644 --- a/index.js +++ b/index.js @@ -18,7 +18,8 @@ const sqlite3 = require("sqlite3").verbose(); const discord = new Discord.Client({ intents: [ "Guilds", - "GuildVoiceStates" + "GuildVoiceStates", + "DirectMessages" ] }); const { @@ -36,8 +37,8 @@ const db = new sqlite3.Database("channels.db", (err) => { } console.log(`${colors.cyan("[INFO]")} Connected to the database`); // Create tables if they dont exist - db.run(`CREATE TABLE IF NOT EXISTS channels (channelid TEXT, iemchannel TEXT, custommessage TEXT)`); - db.run(`CREATE TABLE IF NOT EXISTS userAlerts (userid TEXT, iemchannel TEXT, filter TEXT, filterEvt TEXT, minPriority INT)`); + db.run(`CREATE TABLE IF NOT EXISTS channels (channelid TEXT, iemchannel TEXT, custommessage TEXT, minPriority INTEGER, "filter" TEXT, filterevt TEXT);`); + db.run(`CREATE TABLE IF NOT EXISTS userAlerts (userid TEXT, iemchannel TEXT, filter TEXT, filterEvt TEXT, minPriority INT, custommessage TEXT);`); }); @@ -398,60 +399,74 @@ xmpp.on("stanza", (stanza) => { } ] } - - // Run through the database, and find all channels that are linked to the iem channel - db.all(`SELECT channelid, custommessage FROM channels WHERE iemchannel = ?`, [fromChannel], (err, rows) => { + // Discord Channel Handling + db.all(`SELECT * FROM channels WHERE iemchannel = ?`, [fromChannel], (err, rows) => { if (err) { console.error(err.message); } if (!rows) return; // No channels to alert rows.forEach((row) => { - const channel = discord.channels.cache.get(row.channelid); - if (!channel) { - // Delete the channel from the database and return - return db.run(`DELETE FROM channels WHERE channelid = ?`, [row.channelid], (err) => { - if (err) { - console.error(err.message); - } - console.log(`${colors.cyan("[INFO]")} Deleted channel ${row.channelid} from database`); - }); - }; - thisMsg = JSON.parse(JSON.stringify(discordMsg)); - thisMsg.content = row.custommessage; - channel.send(thisMsg).then((msg) => { - if (msg.channel.type === Discord.ChannelType.GuildAnnouncement) msg.crosspost(); - }).catch((err) => { - console.log(`${colors.red("[ERROR]")} Failed to send message to channel ${row.channelid}: ${err.message}`); - }); - }); - }); - - - // User DM alert handling - db.all(`SELECT userid, filter, minPriority, filterEvt FROM userAlerts WHERE iemchannel = ?`, [fromChannel], (err, rows) => { - if (err) { - console.error(err.message); - } - if (!rows) return; // No users to alert - rows.forEach((row) => { - // Parse filterEvt + // Get Filters as arrays if (!row.filterEvt) row.filterEvt = ""; + if (!row.filter) row.filter = ""; let filterEvt = row.filterEvt.split(","); let filters = row.filter.split(","); - let user = discord.users.cache.get(row.userid); - if (!user) return; // Will handle better later - // If priority is less than the min priority, ignore it if (evt.priority < row.minPriority) return; // If the event type is not in th filter, ignore it. Make sure filterEvt isnt null if (!filterEvt[0]) filterEvt = []; if (!filterEvt.includes(evt.code) && !filterEvt.length == 0) return; + + let channel = discord.channels.cache.get(row.channelid); + if (!channel) return console.log(`${colors.red("[ERROR]")} Channel ${row.channelid} not found`); + // fetch the product text fetch(`https://mesonet.agron.iastate.edu/api/1/nwstext/${product_id_raw}`).then((res) => { // If neither the body nor the product text contains the filter, ignore it res.text().then((text) => { if (!filters.some((filter) => body.includes(filter)) && !filters.some((filter) => text.includes(filter))) return; thisMsg = JSON.parse(JSON.stringify(discordMsg)); + thisMsg.content = row.custommessage || null; + channel.send(thisMsg).catch((err) => { + console.error(err); + }).then((msg) => { + if (msg.channel.type === Discord.ChannelType.GuildAnnouncement) msg.crosspost(); + }); + }); + }); + }); + }); + + + // User DM alert handling + db.all(`SELECT * FROM userAlerts WHERE iemchannel = ?`, [fromChannel], (err, rows) => { + if (err) { + console.error(err.message); + } + if (!rows) return; // No users to alert + rows.forEach((row) => { + // Get Filters as arrays + if (!row.filterEvt) row.filterEvt = ""; + if (!row.filter) row.filter = ""; + let filterEvt = row.filterEvt.split(","); + let filters = row.filter.split(","); + + // If priority is less than the min priority, ignore it + if (evt.priority < row.minPriority) return; + // If the event type is not in th filter, ignore it. Make sure filterEvt isnt null + if (!filterEvt[0]) filterEvt = []; + if (!filterEvt.includes(evt.code) && !filterEvt.length == 0) return; + + let user = discord.users.cache.get(row.userid); + if (!user) return console.log(`${colors.red("[ERROR]")} User ${row.userid} not found`); + + // fetch the product text + fetch(`https://mesonet.agron.iastate.edu/api/1/nwstext/${product_id_raw}`).then((res) => { + // If neither the body nor the product text contains the filter, ignore it + res.text().then((text) => { + if (!filters.some((filter) => body.includes(filter)) && !filters.some((filter) => text.includes(filter))) return; + thisMsg = JSON.parse(JSON.stringify(discordMsg)); + thisMsg.content = row.custommessage || null; user.send(thisMsg).catch((err) => { console.error(err); }); @@ -668,11 +683,6 @@ discord.on('ready', async () => { discord.on("interactionCreate", async (interaction) => { switch (interaction.type) { case Discord.InteractionType.ApplicationCommand: - if (!interaction.channel) return interaction.reply({ content: "This command can only be run in a text channel", ephemeral: true }); - if (interaction.channel.type !== Discord.ChannelType.GuildText && interaction.channel.type !== Discord.ChannelType.GuildAnnouncement) { - interaction.reply({ content: "This command can only be run in a text channel", ephemeral: true }); - return; - } switch (interaction.commandName) { case "subscribe": room = getWFOroom(interaction.options.getString("room")); @@ -680,17 +690,23 @@ discord.on("interactionCreate", async (interaction) => { interaction.reply({ content: "Invalid room", ephemeral: true }); return; } + if (interaction.options.getString("filter")) { + filter = interaction.options.getString("filter").toLowerCase(); + } else { + filter = ""; + } + minPriority = interaction.options.getInteger("minpriority"); + filterEvt = interaction.options.getString("filterevt") || null; message = interaction.options.getString("message") || null; - // Check that the channel isn't already subbed to the room - db.get(`SELECT * FROM channels WHERE channelid = ? AND iemchannel = ?`, [interaction.channel.id, room], (err, row) => { - if (err) { - console.error(err.message); - interaction.reply({ content: "Failed to subscribe to room", ephemeral: true }); - } else if (row) { - return interaction.reply({ content: `Already subscribed to \`${getWFOByRoom(room).location}\``, ephemeral: true }); - } else { - - db.run(`INSERT INTO channels (channelid, iemchannel, custommessage) VALUES (?, ?, ?)`, [interaction.channel.id, room, message], (err) => { + if (interaction.inGuild()) { + db.get(`SELECT * FROM channels WHERE channelid = ? AND iemchannel = ?`, [interaction.channel.id, room], (err, row) => { + if (err) { + console.error(err.message); + interaction.reply({ content: "Failed to subscribe to room", ephemeral: true }); + } else if (row) { + return interaction.reply({ content: `Already subscribed to \`${getWFOByRoom(room).location}\`\nIf you want to update a subscribtion, please unsubscribe and resubscribe. This will be made a command eventually.`, ephemeral: true }); + } + db.run(`INSERT INTO channels (channelid, iemchannel, custommessage, filter, filterevt, minPriority) VALUES (?, ?, ?, ? ,? ,?)`, [interaction.channel.id, room, message, filter, filterEvt, minPriority], (err) => { if (err) { console.error(err.message); interaction.reply({ content: "Failed to subscribe to room", ephemeral: true }); @@ -698,8 +714,25 @@ discord.on("interactionCreate", async (interaction) => { interaction.reply({ content: `Subscribed to \`${getWFOByRoom(room).location}\``, ephemeral: true }); } }); - } - }); + }); + } else { // We're in a DM + db.get(`SELECT * FROM userAlerts WHERE userid = ? AND iemchannel = ?`, [interaction.user.id, room], (err, row) => { + if (err) { + console.error(err.message); + interaction.reply({ content: "Failed to subscribe to room", ephemeral: true }); + } else if (row) { + return interaction.reply({ content: `Already subscribed to \`${getWFOByRoom(room).location}\`\nIf you want to update a subscribtion, please unsubscribe and resubscribe. This will be made a command eventually.`, ephemeral: true }); + } + db.run(`INSERT INTO userAlerts (userid, iemchannel, custommessage, filter, filterEvt, minPriority) VALUES (?, ?, ?, ? ,?, ?)`, [interaction.user.id, room, message, filter, filterEvt, minPriority], (err) => { + if (err) { + console.error(err.message); + interaction.reply({ content: "Failed to subscribe to room", ephemeral: true }); + } else { + interaction.reply({ content: `Subscribed to \`${getWFOByRoom(room).location}\``, ephemeral: true }); + } + }); + }); + } break; case "unsubscribe": // Check that the room is valid @@ -708,58 +741,92 @@ discord.on("interactionCreate", async (interaction) => { interaction.reply({ content: "Invalid room", ephemeral: true }); return; } - // Check that the channel is subbed to the room - db.get(`SELECT * FROM channels WHERE channelid = ? AND iemchannel = ?`, [interaction.channel.id, room], (err, row) => { - if (err) { - console.error(err.message); - interaction.reply({ content: "Failed to unsubscribe from room", ephemeral: true }); - } else if (!row) { - return interaction.reply({ content: `Not subscribed to \`${getWFOByRoom(room).location}\``, ephemeral: true }); - } else { - + if (interaction.inGuild()) { + // Check if subbed + db.get(`SELECT * FROM channels WHERE channelid = ? AND iemchannel = ?`, [interaction.channel.id, room], (err, row) => { + if (err) { + console.error(err.message); + interaction.reply({ content: "Failed to unsubscribe from room", ephemeral: true }); + } + if (!row) { + return interaction.reply({ content: `Not subscribed to \`${getWFOByRoom(room).location}\``, ephemeral: true }); + } db.run(`DELETE FROM channels WHERE channelid = ? AND iemchannel = ?`, [interaction.channel.id, room], (err) => { if (err) { console.error(err.message); interaction.reply({ content: "Failed to unsubscribe from room", ephemeral: true }); - } else { - interaction.reply({ content: `Unsubscribed from \`${getWFOByRoom(room).location}\``, ephemeral: true }); } + interaction.reply({ content: `Unsubscribed from \`${getWFOByRoom(room).location}\``, ephemeral: true }); }); - } - }); + }); + } else { + db.get(`SELECT * FROM userAlerts WHERE userid = ? AND iemchannel = ?`, [interaction.user.id, room], (err, row) => { + if (err) { + console.error(err.message); + interaction.reply({ content: "Failed to unsubscribe from room", ephemeral: true }); + } + if (!row) { + return interaction.reply({ content: `Not subscribed to \`${getWFOByRoom(room).location}\``, ephemeral: true }); + } + db.run(`DELETE FROM userAlerts WHERE userid = ? AND iemchannel = ?`, [interaction.user.id, room], (err) => { + if (err) { + console.error(err.message); + interaction.reply({ content: "Failed to unsubscribe from room", ephemeral: true }); + } + interaction.reply({ content: `Unsubscribed from \`${getWFOByRoom(room).location}\``, ephemeral: true }); + }); + }); + } break; case "list": - db.all(`SELECT iemchannel, custommessage FROM channels WHERE channelid = ?`, [interaction.channel.id], (err, rows) => { - if (err) { - console.error(err.message); - interaction.reply({ content: "Failed to list subscribed rooms", ephemeral: true }); - } else { - let message = ""; - rows.forEach((row) => { - message += `\`${row.iemchannel}\`: ${getWFOByRoom(row.iemchannel).location || "Unknown"} Custom Message: \`${row.custommessage || "None"}\`\n`; - }); - if (message === "") { - message = "No subscribed rooms"; + // List all the subscribed rooms + if (interaction.inGuild()) { + db.all(`SELECT * FROM channels WHERE channelid = ?`, [interaction.channel.id], (err, rows) => { + if (err) { + console.error(err.message); + interaction.reply({ content: "Failed to get subscribed rooms", ephemeral: true }); } - interaction.reply({ content: message, ephemeral: true }); - } - }); - break; - case "setmessage": - room = getWFOroom(interaction.options.getString("room")); - if (!iem.find((channel) => channel.jid.split("@")[0] === room)) { - interaction.reply({ content: "Invalid room", ephemeral: true }); - return; + if (!rows) { + return interaction.reply({ content: "No subscribed rooms", ephemeral: true }); + } + let roomList = []; + rows.forEach((row) => { + roomList.push({ + name: `${row.iemchannel}: ${getWFOByRoom(row.iemchannel).location}`, + value: `Message: \`\`${row.custommessage || "None"}\`\`\nFilter: \`\`${row.filter || "None"}\`\`\nEvent Filter: \`\`${row.filterEvt || "None"}\`\`\nMin Priority: \`\`${row.minPriority || "None"}\`\`` + }); + }); + const embed = { + title: "Subscribed Rooms", + fields: roomList, + color: 0x00ff00 + } + interaction.reply({ embeds: [embed], ephemeral: true }); + }); + } else { + db.all(`SELECT * FROM userAlerts WHERE userid = ?`, [interaction.user.id], (err, rows) => { + if (err) { + console.error(err.message); + interaction.reply({ content: "Failed to get subscribed rooms", ephemeral: true }); + } + if (!rows) { + return interaction.reply({ content: "No subscribed rooms", ephemeral: true }); + } + let roomList = []; + rows.forEach((row) => { + roomList.push({ + name: `${row.iemchannel}: ${getWFOByRoom(row.iemchannel).location}`, + value: `Message: \`\`${row.custommessage || "None"}\`\`\nFilter: \`\`${row.filter || "None"}\`\`\nEvent Filter: \`\`${row.filterEvt || "None"}\`\`\nMin Priority: \`\`${row.minPriority || "None"}\`\`` + }); + }); + const embed = { + title: "Subscribed Rooms", + fields: roomList, + color: 0x00ff00 + } + interaction.reply({ embeds: [embed], ephemeral: true }); + }); } - message = interaction.options.getString("message"); - db.run(`UPDATE channels SET custommessage = ? WHERE channelid = ? AND iemchannel = ?`, [message, interaction.channel.id, room], (err) => { - if (err) { - console.error(err.message); - interaction.reply({ content: "Failed to set message", ephemeral: true }); - } else { - interaction.reply({ content: `Message for ${getWFOByRoom(room).location} to \`${message}\``, ephemeral: true }); - } - }); break; case "about": // Send an embed showing info about the bot, including number of guilds, number of subscribed rooms, etc @@ -976,62 +1043,6 @@ discord.on("interactionCreate", async (interaction) => { interaction.reply({ content: "Failed to set volume", ephemeral: true }); } break; - - case "usersubscribe": - room = getWFOroom(interaction.options.getString("room")); - if (!iem.find((channel) => channel.jid.split("@")[0] === room)) { - interaction.reply({ content: "Invalid room", ephemeral: true }); - return; - } - if (interaction.options.getString("filter")) { - filter = interaction.options.getString("filter").toLowerCase(); - } else { - filter = ""; - } - minPriority = interaction.options.getInteger("minpriority"); - filterEvt = interaction.options.getString("filterevt") || null; - db.run(`INSERT INTO userAlerts (userid, iemchannel, filter, minPriority, filterEvt) VALUES (?, ?, ?, ?, ?)`, [interaction.user.id, room, filter, minPriority, filterEvt], (err) => { - if (err) { - console.error(err.message); - interaction.reply({ content: "Failed to subscribe to alerts", ephemeral: true }); - } else { - interaction.reply({ content: `Subscribed to alerts for \`${getWFOByRoom(room).location}\``, ephemeral: true }); - } - }); - break; - case "userunsubscribe": - room = getWFOroom(interaction.options.getString("room")); - if (!iem.find((channel) => channel.jid.split("@")[0] === room)) { - interaction.reply({ content: "Invalid room", ephemeral: true }); - return; - } - db.run(`DELETE FROM userAlerts WHERE userid = ? AND iemchannel = ?`, [interaction.user.id, room], (err) => { - if (err) { - console.error(err.message); - interaction.reply({ content: "Failed to unsubscribe from alerts", ephemeral: true }); - } else { - interaction.reply({ content: `Unsubscribed from alerts for \`${getWFOByRoom(room).location}\``, ephemeral: true }); - } - }); - break; - case "userlist": - db.all(`SELECT iemchannel, filter, minPriority, filterEvt FROM userAlerts WHERE userid = ?`, [interaction.user.id], (err, rows) => { - if (err) { - console.error(err.message); - interaction.reply({ content: "Failed to list subscribed alerts", ephemeral: true }); - } else { - let message = ""; - rows.forEach((row) => { - message += `\`${row.iemchannel}\`: ${getWFOByRoom(row.iemchannel).location || "Unknown"} Filter: \`${row.filter}\` Min Priority: \`${row.minPriority}\` Filter EVT: \`${row.filterEvt}\`\n`; - } - ); - if (message === "") { - message = "No subscribed alerts"; - } - interaction.reply({ content: message, ephemeral: true }); - } - }); - break; case "outlook": day = interaction.options.getInteger("day"); type = interaction.options.getString("type"); -- 2.43.5 From 3e792352d8cf4d4edc120829a3c8395652276794 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Tue, 21 May 2024 20:23:24 -0600 Subject: [PATCH 2/3] Update descriptions in commands.json --- data/commands.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/commands.json b/data/commands.json index 67669d3..fdea4f5 100644 --- a/data/commands.json +++ b/data/commands.json @@ -19,7 +19,7 @@ }, { "name": "filter", - "description": "Filter for the alert", + "description": "Filter for the alert, you can comma separate multiple strings of text. Don't use spaces between the commas", "type": 3, "required": false }, @@ -57,7 +57,7 @@ }, { "name": "filterevt", - "description": "Filter for event type", + "description": "Filter for event type, you can comma separate multiple strings of text. Don't use spaces between the commas", "type": 3, "required": false } -- 2.43.5 From 6887192f8efaa0402906faa309de6ff363e125d5 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Tue, 21 May 2024 20:27:45 -0600 Subject: [PATCH 3/3] Discord has a 100 char limit on command descriptions :skull: --- data/commands.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/commands.json b/data/commands.json index fdea4f5..37e4f63 100644 --- a/data/commands.json +++ b/data/commands.json @@ -19,7 +19,7 @@ }, { "name": "filter", - "description": "Filter for the alert, you can comma separate multiple strings of text. Don't use spaces between the commas", + "description": "Filter for the alert, you can comma separate multiple strings of text", "type": 3, "required": false }, @@ -57,7 +57,7 @@ }, { "name": "filterevt", - "description": "Filter for event type, you can comma separate multiple strings of text. Don't use spaces between the commas", + "description": "Filter for event type, you can comma separate multiple strings of text", "type": 3, "required": false } -- 2.43.5