From f5de90ba89146008af78c16e798e216efccf0c50 Mon Sep 17 00:00:00 2001 From: Andrew Lee Date: Sat, 11 Jan 2025 11:55:18 -0500 Subject: Ability to add quotes, web interface, pending quotes --- api/server.js | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 api/server.js (limited to 'api') diff --git a/api/server.js b/api/server.js new file mode 100644 index 0000000..a918308 --- /dev/null +++ b/api/server.js @@ -0,0 +1,78 @@ +const express = require('express'); +const cors = require('cors'); +const { pendingQuote, quote: approvedQuote } = require('../models/quote.js'); + +const app = express(); +const PORT = 3000; + +const createServer = () => { + app.use(cors()); // Allow cross-origin requests + app.use(express.json()); + + // Endpoint to get all pending quotes + app.get('/api/pending-quotes', async (req, res) => { + try { + const quotes = await pendingQuote.findAll(); + res.json(quotes); + } catch (error) { + console.error('Error fetching quotes:', error); + res.status(500).send('Internal Server Error'); + } + }); + + app.post('/api/approve-quote', async (req, res) => { + const { id } = req.body; + try { + const quote = await pendingQuote.findByPk(id); + if (quote) { + await approvedQuote.create({ + author: quote.author, + quote: quote.quote, + year: quote.year, + authorImage: quote.authorImage + }); + await pendingQuote.destroy({ where: { id } }); + res.status(200).send('Quote approved'); + } else { + res.status(404).send('Quote not found'); + } + } catch (error) { + console.error('Error approving quote:', error); + res.status(500).send('Internal Server Error'); + } + }); + + app.post('/api/reject-quote', async (req, res) => { + const { id } = req.body; + try { + const quote = await pendingQuote.findByPk(id); + if (quote) { + await pendingQuote.destroy({ where: { id } }); + res.status(200).send('Quote rejected'); + } else { + res.status(404).send('Quote not found'); + } + } catch (error) { + console.error('Error rejecting quote:', error); + res.status(500).send('Internal Server Error'); + } + }); + + app.get('/api/version', (req, res) => { + const { abVersion } = require('../storage/settings.json'); + res.json(abVersion); + + }); + + app.get('/' , (req, res) => { + res.send('API for AleeBot'); + // Most likely going to redirect to the frontend + }); + + // Start the server + app.listen(PORT, () => { + console.log(`Server is running on http://localhost:${PORT}`); + }); +}; + +module.exports = createServer; -- cgit v1.2.3 From 7e65ae0e135098acad76b8081f34478b4efc077f Mon Sep 17 00:00:00 2001 From: Andrew Lee Date: Sat, 11 Jan 2025 18:02:05 -0500 Subject: Cleaned up some code, author image now support attachments --- api/routes/quotes.js | 58 +++++++++++++++++++++++++++++ api/server.js | 56 +--------------------------- commands/addquote.js | 87 ++++++++++++++++++++++++++----------------- commands/quote.js | 4 ++ commands/setup.js | 3 +- models/quote.js | 20 ++++++++++ storage/activities.js | 1 - web/astro.config.mjs | 2 +- web/src/components/Quotes.jsx | 1 + web/src/layouts/Layout.astro | 2 +- web/src/pages/index.astro | 19 +++++++++- 11 files changed, 159 insertions(+), 94 deletions(-) create mode 100644 api/routes/quotes.js (limited to 'api') diff --git a/api/routes/quotes.js b/api/routes/quotes.js new file mode 100644 index 0000000..39aba7b --- /dev/null +++ b/api/routes/quotes.js @@ -0,0 +1,58 @@ +const express = require('express'); +const quoteDB = require('../../models/quote.js'); + +const router = express.Router(); + +const pendingQuote = quoteDB.pendingQuote; +const approvedQuote = quoteDB.quote; + +router.get('/pending-quotes', async (req, res) => { + try { + const quotes = await pendingQuote.findAll(); + res.json(quotes); + } catch (error) { + console.error('Error fetching quotes:', error); + res.status(500).send('Internal Server Error'); + } +}); + +router.post('/approve-quote', async (req, res) => { + const { id } = req.body; + try { + const quote = await pendingQuote.findByPk(id); + if (quote) { + await approvedQuote.create({ + author: quote.author, + authorImage: quote.authorImage, + quote: quote.quote, + year: quote.year, + submitter: quote.submitterID + }); + await pendingQuote.destroy({ where: { id } }); + res.status(200).send('Quote approved'); + } else { + res.status(404).send('Quote not found'); + } + } catch (error) { + console.error('Error approving quote:', error); + res.status(500).send('Internal Server Error'); + } +}); + +router.post('/reject-quote', async (req, res) => { + const { id } = req.body; + try { + const quote = await pendingQuote.findByPk(id); + if (quote) { + await pendingQuote.destroy({ where: { id } }); + res.status(200).send('Quote rejected'); + } else { + res.status(404).send('Quote not found'); + } + } catch (error) { + console.error('Error rejecting quote:', error); + res.status(500).send('Internal Server Error'); + } +}); + +module.exports = router; diff --git a/api/server.js b/api/server.js index a918308..a6cb48c 100644 --- a/api/server.js +++ b/api/server.js @@ -1,6 +1,6 @@ const express = require('express'); const cors = require('cors'); -const { pendingQuote, quote: approvedQuote } = require('../models/quote.js'); +const quotesRouter = require('./routes/quotes'); const app = express(); const PORT = 3000; @@ -9,54 +9,7 @@ const createServer = () => { app.use(cors()); // Allow cross-origin requests app.use(express.json()); - // Endpoint to get all pending quotes - app.get('/api/pending-quotes', async (req, res) => { - try { - const quotes = await pendingQuote.findAll(); - res.json(quotes); - } catch (error) { - console.error('Error fetching quotes:', error); - res.status(500).send('Internal Server Error'); - } - }); - - app.post('/api/approve-quote', async (req, res) => { - const { id } = req.body; - try { - const quote = await pendingQuote.findByPk(id); - if (quote) { - await approvedQuote.create({ - author: quote.author, - quote: quote.quote, - year: quote.year, - authorImage: quote.authorImage - }); - await pendingQuote.destroy({ where: { id } }); - res.status(200).send('Quote approved'); - } else { - res.status(404).send('Quote not found'); - } - } catch (error) { - console.error('Error approving quote:', error); - res.status(500).send('Internal Server Error'); - } - }); - - app.post('/api/reject-quote', async (req, res) => { - const { id } = req.body; - try { - const quote = await pendingQuote.findByPk(id); - if (quote) { - await pendingQuote.destroy({ where: { id } }); - res.status(200).send('Quote rejected'); - } else { - res.status(404).send('Quote not found'); - } - } catch (error) { - console.error('Error rejecting quote:', error); - res.status(500).send('Internal Server Error'); - } - }); + app.use('/api', quotesRouter); app.get('/api/version', (req, res) => { const { abVersion } = require('../storage/settings.json'); @@ -64,11 +17,6 @@ const createServer = () => { }); - app.get('/' , (req, res) => { - res.send('API for AleeBot'); - // Most likely going to redirect to the frontend - }); - // Start the server app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); diff --git a/commands/addquote.js b/commands/addquote.js index 52f7b21..f13d3c9 100644 --- a/commands/addquote.js +++ b/commands/addquote.js @@ -20,14 +20,21 @@ const { pendingQuote } = require('../models/quote'); const { MessageEmbed } = require("discord.js"); +const setupUsers = new Set(); + module.exports.run = async (client, message) => { try { let newAuthor, newAuthorImage, newQuote, newYear; - let isSetupRunning = false; + + if (setupUsers.has(message.author.id)) { + return await message.reply('You are already setting up a quote.'); + } + + setupUsers.add(message.author.id); const setupProcess = [ 'Provide the name of the author:', - 'Submit the image of the author:\nYou need to use a picture link that ends in .jpg or .png (like those from IMGUR or Google Images), and the picture should be either 128x128 pixels or 512x512 pixels in size.', + 'Submit the image of the author:\nYou can use an attachment or a link that ends in .jpg/.jpeg or .png (like those from IMGUR or Google Images), and the picture should be either 128x128 pixels or 512x512 pixels in size.', 'Enter the quote:', 'Specify the year from which the quote originates:' ]; @@ -38,23 +45,38 @@ module.exports.run = async (client, message) => { authorImage: newAuthorImage, quote: newQuote, year: newYear, + submitterAuthor: message.author.username, + submitterID: message.author.id }); } + async function imageCheck(message) { + const attachment = message.attachments.first(); + if (attachment) { + const fileExtension = attachment.name.split('.').pop().toLowerCase(); + if (['jpg', 'png', 'jpeg'].includes(fileExtension)) { + newAuthorImage = attachment.url.toString(); // Use the attachment's URL directly + } else { + await dmChannel.send('Invalid file type. Please attach a .jpg or .png image.'); + return await imageCheck(message); + } + } else if (msg.content.startsWith('http') && (message.content.endsWith('.jpg') || message.content.endsWith('.jpeg') || message.content.endsWith('.png'))) { + newAuthorImage = msg.content; // Use the provided URL + } else { + await dmChannel.send('Invalid input. Please provide an image URL or attach an image file.'); + return await imageCheck(message); + } + } + let setupMessage = "Welcome to the AleeBot Quote Setup!\n"; setupMessage += "Please follow these rules when submitting quotes:\n"; - setupMessage += "```1. Do not use profanity or offensive language.\n"; + setupMessage += "```1. No offensive content (NSFW, Racism, etc).\n"; setupMessage += "2. Do not send any personal information.\n"; setupMessage += "3. Only send noteworthy quotes.```\n"; setupMessage += "We reserve the right to reject any quotes that do not meet our criteria.\n"; - if (isSetupRunning) { - return await message.reply('You are already setting up a quote.'); - } - const filter = (m) => m.author.id === message.author.id; - isSetupRunning = true; await message.reply(':arrow_left: Check DMs to continue.'); const dmChannel = await message.author.createDM(); @@ -65,10 +87,14 @@ module.exports.run = async (client, message) => { const collector = dmChannel.createMessageCollector({ filter, max: setupProcess.length, - time: 1000 * 120 + time: 1000 * 1200 }); - collector.on('collect', async () => { + collector.on('collect', async (msg) => { + if (counter === 2) { // Collecting author image + await imageCheck(msg); + } + if (counter < setupProcess.length) { await dmChannel.send(setupProcess[counter++]); } @@ -77,20 +103,23 @@ module.exports.run = async (client, message) => { collector.on('end', async (collected) => { if (collected.size < setupProcess.length) { dmChannel.send('Quote setup was not completed. Please rerun the command.'); + setupUsers.delete(message.author.id); } else { const quoteContent = collected.map((m) => m.content); newAuthor = quoteContent[0]; - newAuthorImage = quoteContent[1]; + if (!newAuthorImage) { + newAuthorImage = quoteContent[1] || 'N/A'; + } newQuote = quoteContent[2]; newYear = quoteContent[3]; const setupEmbed = new MessageEmbed() .setAuthor('AleeBot Quote Setup', client.user.avatarURL()) - .setDescription('Are you happy with this quote?\nThis quote will be sent for manual approval automatically in 2 minutes.') - .addField('Author', newAuthor) - .addField('Author Image (URL)', newAuthorImage) - .addField('Quote', newQuote) - .addField('Year', newYear) + .setDescription('Are you happy with this quote?\nThis quote will be sent for manual approval automatically in 20 minutes.') + .addField('Author', newAuthor || 'N/A') + .addField('Author Image (URL)', newAuthorImage || 'N/A') + .addField('Quote', newQuote || 'N/A') + .addField('Year', newYear || 'N/A') .setColor('#1fd619'); let messageReact = await dmChannel.send({embeds: [setupEmbed]}); @@ -107,7 +136,7 @@ module.exports.run = async (client, message) => { const reactionCollector = messageReact.createReactionCollector({ filter: reactionFilter, - time: 1000 * 120 + time: 1000 * 1200 }); reactionCollector.on('collect', async (reaction) => { @@ -119,10 +148,10 @@ module.exports.run = async (client, message) => { await dmChannel.send('Updated author name.'); break; case '📷': - await dmChannel.send('You selected the author image. Please provide the image URL.'); + await dmChannel.send('You selected the author image. Please provide the image URL or attach an image file.'); const imageResponse = await dmChannel.awaitMessages({ filter, max: 1, time: 60000 }); - if (imageResponse.size) newAuthorImage = imageResponse.first().content; - await dmChannel.send('Updated author URL.'); + await imageCheck(imageResponse.first()); + await dmChannel.send('Updated author image.'); break; case '🖋️': await dmChannel.send('You selected the quote. Please provide the quote.'); @@ -144,36 +173,26 @@ module.exports.run = async (client, message) => { break; } - const updatedEmbed = new MessageEmbed() - .setAuthor('AleeBot Quote Setup', client.user.avatarURL()) - .setDescription('Are you happy with this quote?\nThis quote will be sent for manual approval automatically in 2 minutes.') - .addField('Author', newAuthor) - .addField('Author Image (URL)', newAuthorImage) - .addField('Quote', newQuote) - .addField('Year', newYear) - .setColor('#1fd619'); - - await messageReact.edit({embeds: [updatedEmbed]}); + await messageReact.edit({embeds: [setupEmbed]}); }); reactionCollector.on('end', async (collected, reason) => { if (reason === 'cancelled') { - isSetupRunning = false; dmChannel.send('Cancelling quote setup.'); } else if (reason === 'completed') { dmChannel.send('Sending this quote for manual approval.'); - isSetupRunning = false; await createQuote(); } else { dmChannel.send('You have not responded. Sending this quote for manual approval.'); - isSetupRunning = false; await createQuote(); } + setupUsers.delete(message.author.id); }); - } }); } catch (error) { + message.author.send('An error occurred while setting up the quote. Please try again.'); + setupUsers.delete(message.author.id); console.error(error); } }; diff --git a/commands/quote.js b/commands/quote.js index 02699cd..0d67b66 100644 --- a/commands/quote.js +++ b/commands/quote.js @@ -38,6 +38,10 @@ module.exports.run = async (client, message, args) => { .setColor('#1fd619') .setFooter('- ' + quote.year); + if (quote.url) { + quoteEmbed.setURL(quote.url); + } + await message.reply({ embeds: [quoteEmbed] }) } else { message.reply('Cannot find quote, specify the correct quote id.'); diff --git a/commands/setup.js b/commands/setup.js index 380e85e..c797f7d 100644 --- a/commands/setup.js +++ b/commands/setup.js @@ -27,7 +27,8 @@ module.exports.run = async (client, message) => { .setDescription('Select the options') .addField('Logging', 'channelid', true) .addField('Broadcast', 'placeholder', true) - .addField('Broadcast', 'placeholder', true); + .addField('Quote of the Day', 'placeholder', true) + .addField('QOTD Channel', 'channelid', true); message.author.send({embeds: [setupEmbed]}); }; diff --git a/models/quote.js b/models/quote.js index eab4f57..b68dfbc 100644 --- a/models/quote.js +++ b/models/quote.js @@ -22,6 +22,14 @@ const quote = sequelize.define('quotes', { year: { type: Sequelize.STRING, allowNull: false + }, + url: { + type: Sequelize.STRING, + allowNull: true + }, + submitter: { + type: Sequelize.STRING, + allowNull: false } }) @@ -47,6 +55,18 @@ const pendingQuote = sequelize.define('pending-quotes', { year: { type: Sequelize.STRING, allowNull: false + }, + url: { + type: Sequelize.STRING, + allowNull: true + }, + submitterAuthor: { + type: Sequelize.STRING, + allowNull: false + }, + submitterID: { + type: Sequelize.STRING, + allowNull: false } }) diff --git a/storage/activities.js b/storage/activities.js index 5d0161e..be28e58 100644 --- a/storage/activities.js +++ b/storage/activities.js @@ -91,7 +91,6 @@ const activities = [ 'What is Web3?', 'GNU\'s NOT UNIX!', 'Linux, but actually GNU/Linux', - 'Praise RMS! (dont)', 'Debloating my ThinkPad', 'Turbotastic!', `Now running on Discord.JS ${version}!` diff --git a/web/astro.config.mjs b/web/astro.config.mjs index 53e49de..515ddf0 100644 --- a/web/astro.config.mjs +++ b/web/astro.config.mjs @@ -6,4 +6,4 @@ import react from '@astrojs/react'; // https://astro.build/config export default defineConfig({ integrations: [react()] -}); \ No newline at end of file +}); diff --git a/web/src/components/Quotes.jsx b/web/src/components/Quotes.jsx index 1d563e7..831408d 100644 --- a/web/src/components/Quotes.jsx +++ b/web/src/components/Quotes.jsx @@ -72,6 +72,7 @@ export function PendingQuotes() {

{quote.quote}

- {quote.year} + Submitted by {quote.submitterAuthor} ({quote.submitterID}) diff --git a/web/src/layouts/Layout.astro b/web/src/layouts/Layout.astro index e455c61..2f6032d 100644 --- a/web/src/layouts/Layout.astro +++ b/web/src/layouts/Layout.astro @@ -5,7 +5,7 @@ - Astro Basics + AleeBot Web Interface diff --git a/web/src/pages/index.astro b/web/src/pages/index.astro index b5c607d..8136402 100644 --- a/web/src/pages/index.astro +++ b/web/src/pages/index.astro @@ -2,12 +2,11 @@ import Layout from '../layouts/Layout.astro'; import { PendingQuotes } from '../components/Quotes'; -const version = await fetch('http://localhost:3000/api/version').then(res => res.json()); ---
-

AleeBot {version}

+

AleeBot

@@ -27,3 +26,19 @@ const version = await fetch('http://localhost:3000/api/version').then(res => res } + + -- cgit v1.2.3 From de5ee661cad7b1fef0f319cbaccd888cb75a1dd4 Mon Sep 17 00:00:00 2001 From: Andrew Lee Date: Sun, 12 Jan 2025 00:45:51 -0500 Subject: Fixed environment variable, prefix using ab --- Dockerfile | 3 ++- api/server.js | 6 +++--- storage/settings.json | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'api') diff --git a/Dockerfile b/Dockerfile index 3f4f771..44c3d57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,4 +12,5 @@ RUN yarn install COPY . . -ENTRYPOINT ["node", "bot_discord.js", "--beta"] +ENTRYPOINT ["node", "bot_discord.js"] + diff --git a/api/server.js b/api/server.js index a6cb48c..2a2afad 100644 --- a/api/server.js +++ b/api/server.js @@ -1,9 +1,9 @@ const express = require('express'); const cors = require('cors'); const quotesRouter = require('./routes/quotes'); +require('dotenv').config() const app = express(); -const PORT = 3000; const createServer = () => { app.use(cors()); // Allow cross-origin requests @@ -18,8 +18,8 @@ const createServer = () => { }); // Start the server - app.listen(PORT, () => { - console.log(`Server is running on http://localhost:${PORT}`); + app.listen(process.env.port, () => { + console.log(`Server is running on http://localhost:${process.env.port}`); }); }; diff --git a/storage/settings.json b/storage/settings.json index 83932cc..b53fd84 100644 --- a/storage/settings.json +++ b/storage/settings.json @@ -1,4 +1,4 @@ { "abVersion": "2.13.0 Beta", - "prefix": "abb:" + "prefix": "ab:" } -- cgit v1.2.3 From 5777f96394444dab18a81d6f085ac81df3e62008 Mon Sep 17 00:00:00 2001 From: Andrew Lee Date: Tue, 25 Feb 2025 23:13:39 -0500 Subject: 2.13 Release (finally); Added more API entries; Proper logging --- api/server.js | 51 +++++++++++++++++++- bot_discord.js | 108 ++++++++++++++++++++++++------------------ commands/addquote.js | 4 +- commands/quote.js | 3 +- commands/setlogchannel.js | 25 ++++++---- models/guild-settings.js | 25 ++++++---- package.json | 2 +- storage/settings.json | 2 +- sync-database.js | 4 +- web/astro.config.mjs | 10 +++- web/src/components/Quotes.jsx | 7 +-- web/src/pages/index.astro | 3 +- 12 files changed, 165 insertions(+), 79 deletions(-) (limited to 'api') diff --git a/api/server.js b/api/server.js index 2a2afad..acfe528 100644 --- a/api/server.js +++ b/api/server.js @@ -5,7 +5,7 @@ require('dotenv').config() const app = express(); -const createServer = () => { +const apiServer = (client) => { app.use(cors()); // Allow cross-origin requests app.use(express.json()); @@ -17,10 +17,57 @@ const createServer = () => { }); + app.get('/api/uptime', (req, res) => { + res.json(client.uptime); + }); + + app.get('/api/servers', (req, res) => { + const guildsInfo = []; + + if (client.guilds.cache.size === 0) { + res.json({ + message: 'No servers found' + }) + } else { + client.guilds.cache.forEach((guild) => { + const guildInfo = { + name: guild.name, + members: guild.memberCount, + id: guild.id + }; + guildsInfo.push(guildInfo); + }); + } + + res.json(guildsInfo); + + }); + + app.post('/api/leave', (req, res) => { + const { id } = req.body; + let guild = client.guilds.cache.get(id); + + try { + guild.leave().then(guild => { + res.json({ + guild: guild.name, + left: true + }) + }); + + } catch (error) { + console.error('Error leaving server:', error); + res.status(500).res.json({ + guild: guild.name, + left: false + }) + } + }); + // Start the server app.listen(process.env.port, () => { console.log(`Server is running on http://localhost:${process.env.port}`); }); }; -module.exports = createServer; +module.exports = apiServer; diff --git a/bot_discord.js b/bot_discord.js index 5a38940..1a87074 100644 --- a/bot_discord.js +++ b/bot_discord.js @@ -33,12 +33,15 @@ const colors = require('colors'); //const i18next = require('i18next'); const settings = require('./storage/settings.json'); const { activity } = require('./storage/activities'); -const createServer = require("./api/server"); +const apiServer = require("./api/server"); const active = new Map(); let autoRole = true; let readyEmbedMessage = true; + +const { guildSettings } = require('./models/guild-settings'); + const ownerID = '242775871059001344'; -let logChannel = '318874545593384970'; +//let logChannel = '318874545593384970'; let statusChannelID = '606602551634296968'; let serverWhitelist = "243022206437687296"; let roleWhitelist = "657426918416580614"; @@ -218,7 +221,7 @@ client.on('ready', async () => { botPresence(); - createServer(); + apiServer(client); setInterval(function() { botPresence(); @@ -238,8 +241,10 @@ client.on('ready', async () => { rl.prompt(); }); -client.on('guildMemberAdd', (member) => { - if (member.guild.id !== serverWhitelist) return; +client.on('guildMemberAdd', async (member) => { + const guildSetting = await guildSettings.findOne({ where: { guildID: member.guild.id } }); + if (!guildSetting || !guildSetting.logChannelID) return; + const logEmbed = new Discord.MessageEmbed() .setAuthor('AleeBot Logging', client.user.avatarURL()) .setDescription(`A user has joined this server!`) @@ -249,7 +254,7 @@ client.on('guildMemberAdd', (member) => { .setColor('#4bff31') .setTimestamp(); - let guildMember = client.channels.cache.get(logChannel); + let guildMember = client.channels.cache.get(guildSetting.logChannelID); if (!guildMember) return; guildMember.send({ embeds: [logEmbed]}); @@ -261,8 +266,10 @@ client.on('guildMemberAdd', (member) => { } }); -client.on('guildMemberRemove', (member) => { - if (member.guild.id !== serverWhitelist) return; +client.on('guildMemberRemove', async (member) => { + const guildSetting = await guildSettings.findOne({ where: { guildID: member.guild.id } }); + if (!guildSetting || !guildSetting.logChannelID) return; + const logEmbed = new Discord.MessageEmbed() .setAuthor('AleeBot Logging', client.user.avatarURL()) .setDescription(`A user has left this server!`) @@ -271,7 +278,7 @@ client.on('guildMemberRemove', (member) => { .setColor('#ec2727') .setTimestamp(); - let guildMember = client.channels.cache.get(logChannel); + let guildMember = client.channels.cache.get(guildSetting.logChannelID); if (!guildMember) return; guildMember.send({ embeds: [logEmbed]}); @@ -279,7 +286,10 @@ client.on('guildMemberRemove', (member) => { client.on('messageUpdate', async (oldMessage, newMessage) => { - if (!oldMessage.guild || oldMessage.guild.id !== serverWhitelist) return; + const guildSetting = await guildSettings.findOne({ where: { guildID: oldMessage.guild.id } }); + if (!oldMessage.guild || !guildSetting || !guildSetting.logChannelID) return; + + //if (!oldMessage.guild || oldMessage.guild.id !== serverWhitelist) return; if (oldMessage.content === newMessage.content) { return; } @@ -292,14 +302,18 @@ client.on('messageUpdate', async (oldMessage, newMessage) => { .setTimestamp() .setFooter(`Author ID: ${oldMessage.author.id}`); - let editMessage = client.channels.cache.get(logChannel); + let editMessage = client.channels.cache.get(guildSetting.logChannelID); if (!editMessage) return; editMessage.send({ embeds: [logEmbed]}); }); -client.on('messageDelete', (message) => { - if (message.guild.id !== serverWhitelist) return; +client.on('messageDelete', async (message) => { + if (!message.content) return; + + const guildSetting = await guildSettings.findOne({ where: { guildID: message.guild.id } }); + if (!guildSetting || !guildSetting.logChannelID) return; + const logEmbed = new Discord.MessageEmbed() .setAuthor('AleeBot Logging', client.user.avatarURL()) .setDescription(`A message from ${message.author.username} was deleted in <#${message.channel.id}>`) @@ -308,43 +322,47 @@ client.on('messageDelete', (message) => { .setTimestamp() .setFooter(`Author ID: ${message.author.id}`); - let deleteMessage = client.channels.cache.get(logChannel); + let deleteMessage = client.channels.cache.get(guildSetting.logChannelID); if (!deleteMessage) return; deleteMessage.send({ embeds: [logEmbed]}); }); -client.on('guildBanAdd', (guild, user) => { - if (guild.id !== serverWhitelist) return; - const logEmbed = new Discord.MessageEmbed() - .setAuthor('AleeBot Logging', client.user.avatarURL()) - .setDescription(`This user got banned from ${guild.name}`) - .addField('User:', `${user.tag}`) - .addField('User ID:', `${user.id}`) - .setColor('#ff021b') - .setTimestamp(); - - let banMessage = client.channels.cache.get(logChannel); - if (!banMessage) return; - - banMessage.send({ embeds: [logEmbed]}); -}); - -client.on('guildBanRemove', (guild, user) => { - if (guild.id !== serverWhitelist) return; - const logEmbed = new Discord.MessageEmbed() - .setAuthor('AleeBot Logging', client.user.avatarURL()) - .setDescription(`This user got unbanned from ${guild.name}`) - .addField('User:', `${user.tag}`) - .addField('User ID:', `${user.id}`) - .setColor('#ff021b') - .setTimestamp(); - - let banMessage = client.channels.cache.get(logChannel); - if (!banMessage) return; - - banMessage.send({ embeds: [logEmbed]}); -}); +// client.on('guildBanAdd', async (guild, user) => { +// const guildSetting = await guildSettings.findOne({ where: { guildID: guild.id } }); +// if (!guildSetting || !guildSetting.logChannelID) return; +// +// const logEmbed = new Discord.MessageEmbed() +// .setAuthor('AleeBot Logging', client.user.avatarURL()) +// .setDescription(`This user got banned from ${guild.name}`) +// .addField('User:', `${user.tag}`) +// .addField('User ID:', `${user.id}`) +// .setColor('#ff021b') +// .setTimestamp(); +// +// let banMessage = client.channels.cache.get(guildSetting.logChannelID); +// if (!banMessage) return; +// +// banMessage.send({ embeds: [logEmbed]}); +// }); +// +// client.on('guildBanRemove', async (guild, user) => { +// const guildSetting = await guildSettings.findOne({ where: { guildID: guild.id } }); +// if (!guildSetting || !guildSetting.logChannelID) return; +// +// const logEmbed = new Discord.MessageEmbed() +// .setAuthor('AleeBot Logging', client.user.avatarURL()) +// .setDescription(`This user got unbanned from ${guild.name}`) +// .addField('User:', `${user.tag}`) +// .addField('User ID:', `${user.id}`) +// .setColor('#ff021b') +// .setTimestamp(); +// +// let banMessage = client.channels.cache.get(guildSetting.logChannelID); +// if (!banMessage) return; +// +// banMessage.send({ embeds: [logEmbed]}); +// }); client.on('guildCreate', (guild) => { log(`[i] New guild joined: ${guild.name} (${guild.id}). This guild has ${guild.memberCount} members!`.blue); diff --git a/commands/addquote.js b/commands/addquote.js index cedee4d..6eae015 100644 --- a/commands/addquote.js +++ b/commands/addquote.js @@ -85,7 +85,7 @@ module.exports.run = async (client, message) => { return; } } else if (msg.content.startsWith('http') && (msg.content.endsWith('.jpg') || msg.content.endsWith('.jpeg') || msg.content.endsWith('.png'))) { - newAuthorImage = message.content; + newAuthorImage = msg.content; } else { await dmChannel.send('Invalid input. Please provide an image URL or attach an image file.'); collector.stop(); @@ -157,7 +157,7 @@ module.exports.run = async (client, message) => { await dmChannel.send('Invalid file type. Please attach a .jpg or .png image.'); } } else if (imageResponse.first().content.startsWith('http') && (imageResponse.first().content.endsWith('.jpg') || imageResponse.first().content.endsWith('.jpeg') || imageResponse.first().content.endsWith('.png'))) { - newAuthorImage = message.content; + newAuthorImage = imageResponse.first().content; } else { await dmChannel.send('Invalid input. Please provide an image URL or attach an image file.'); } diff --git a/commands/quote.js b/commands/quote.js index 02699cd..f19675f 100644 --- a/commands/quote.js +++ b/commands/quote.js @@ -30,13 +30,12 @@ module.exports.run = async (client, message, args) => { const quote = await quoteDB.findOne({ where: { id: quoteID } }) - if (quote) { const quoteEmbed = new MessageEmbed() .setAuthor({ name: quote.author, iconURL: quote.authorImage }) .setDescription(quote.quote) .setColor('#1fd619') - .setFooter('- ' + quote.year); + .setFooter(`- ${quote.year}\nSubmitted by ${quote.submitter}`); await message.reply({ embeds: [quoteEmbed] }) } else { diff --git a/commands/setlogchannel.js b/commands/setlogchannel.js index c04e926..d989f8b 100644 --- a/commands/setlogchannel.js +++ b/commands/setlogchannel.js @@ -17,21 +17,30 @@ * along with this program. If not, see . * * *************************************/ -const guildDB = require ('../models/guild-settings') -module.exports.run = async (client, message) => { +const { guildSettings } = require ('../models/guild-settings') +module.exports.run = async (client, message, args) => { //This will be replaced in the future possibly if (!message.member.permissions.has('MANAGE_GUILD')) return message.reply('It looks like that you can\'t manage this server.'); - const channel = await message.mentions.channels.first().id; - const [ guild ] = await guildDB.findOrCreate({ where: { id: message.guild.id } } ) + + let channel; + + if (message.mentions.channels.first()) { + channel = message.mentions.channels.first().id; + } else if (args[0] && message.guild.channels.cache.has(args[0])) { + channel = args[0]; + } else { + return await message.reply('Please enter a valid channel ID.') + } + + const [ guild ] = await guildSettings.findOrCreate({ where: { guildID: message.guild.id } } ) if (!channel) { message.reply('No channel has been set, disabling the logging channel feature...'); - await guild.update({ channelId: null } ); + await guild.update({ logChannelID: null } ); } else { - await guild.update({ channelId: message.guild.id } ) ; + await guild.update({ logChannelID: channel } ); + await message.reply(`Logging channel has been set to <#${channel}>`); } - - await message.reply(`Logging channel has been set to <#${channel}>`); }; exports.conf = { diff --git a/models/guild-settings.js b/models/guild-settings.js index 2e4f8ef..8cc7478 100644 --- a/models/guild-settings.js +++ b/models/guild-settings.js @@ -3,22 +3,27 @@ const sequelize = require('../utils/sequelize'); const guildSettings = sequelize.define('guild-settings', { id: { - type: Sequelize.STRING, - primaryKey: true + type: Sequelize.INTEGER, + primaryKey: true, + autoIncrement: true, }, - logChannelID: { + guildID: { type: Sequelize.STRING, - allowNull: true + allowNull: false }, - autoRoleToggle: { - type: Sequelize.BOOLEAN, - allowNull: true - }, - autoRoleID: { + logChannelID: { type: Sequelize.STRING, allowNull: true } + // qotdChannelID: { + // type: Sequelize.STRING, + // allowNull: true + // }, + // qotdToggle: { + // type: Sequelize.BOOLEAN, + // allowNull: true + // } }) -module.exports = guildSettings +module.exports = { guildSettings } diff --git a/package.json b/package.json index b300082..404b4a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aleebot", - "version": "2.13.0b", + "version": "2.13.0", "description": "A chat bot for discord written in discord.js.", "main": "bot_discord.js", "scripts": { diff --git a/storage/settings.json b/storage/settings.json index b53fd84..4a6911c 100644 --- a/storage/settings.json +++ b/storage/settings.json @@ -1,4 +1,4 @@ { - "abVersion": "2.13.0 Beta", + "abVersion": "2.13.0", "prefix": "ab:" } diff --git a/sync-database.js b/sync-database.js index f7b9211..7a9271c 100644 --- a/sync-database.js +++ b/sync-database.js @@ -1,5 +1,5 @@ const { quote, pendingQuote } = require("./models/quote"); -const guildDB = require ('./models/guild-settings'); +const { guildSettings } = require ('./models/guild-settings'); quote.sync({alter: true}).then(() => { console.log('Quote database synced!') }); @@ -8,6 +8,6 @@ pendingQuote.sync({alter: true}).then(() => { console.log('Pending Quote database synced!') }); -guildDB.sync({alter: true}).then(() => { +guildSettings.sync({alter: true}).then(() => { console.log('Guild database synced!') }); diff --git a/web/astro.config.mjs b/web/astro.config.mjs index c0fd9ad..d32e23b 100644 --- a/web/astro.config.mjs +++ b/web/astro.config.mjs @@ -1,5 +1,5 @@ // @ts-check -import { defineConfig } from 'astro/config'; +import { defineConfig, envField } from 'astro/config'; import react from '@astrojs/react'; @@ -11,5 +11,11 @@ export default defineConfig({ adapter: node({ mode: 'standalone' - }) + }), + + env: { + schema: { + API_URL: envField.string({ context: 'client', access: 'public' }), + } + } }); diff --git a/web/src/components/Quotes.jsx b/web/src/components/Quotes.jsx index 831408d..1eb258a 100644 --- a/web/src/components/Quotes.jsx +++ b/web/src/components/Quotes.jsx @@ -1,12 +1,13 @@ import { useState, useEffect } from 'react'; import '../styles/Quote.css' +import { API_URL } from "astro:env/client"; export function PendingQuotes() { const [quotes, setQuotes] = useState([]); const fetchQuotes = async () => { try { - const response = await fetch('http://localhost:3000/api/pending-quotes'); + const response = await fetch(`${API_URL}/api/pending-quotes`); const data = await response.json(); setQuotes(data); } catch (error) { @@ -20,7 +21,7 @@ export function PendingQuotes() { const approveQuote = async (id) => { try { - const response = await fetch('http://localhost:3000/api/approve-quote', { + const response = await fetch(`${API_URL}/api/approve-quote`, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -40,7 +41,7 @@ export function PendingQuotes() { const rejectQuote = async (id) => { try { - const response = await fetch('http://localhost:3000/api/reject-quote', { + const response = await fetch(`${API_URL}/api/reject-quote`, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/web/src/pages/index.astro b/web/src/pages/index.astro index 8136402..f1dc6e7 100644 --- a/web/src/pages/index.astro +++ b/web/src/pages/index.astro @@ -28,9 +28,10 @@ import { PendingQuotes } from '../components/Quotes';