diff options
Diffstat (limited to 'bot/src')
| -rw-r--r-- | bot/src/api/routes/quotes.js | 138 | ||||
| -rw-r--r-- | bot/src/api/server.js | 2 | ||||
| -rw-r--r-- | bot/src/commands/about.js | 9 | ||||
| -rw-r--r-- | bot/src/commands/quote.js | 25 | ||||
| -rw-r--r-- | bot/src/commands/serverinfo.js | 6 | ||||
| -rw-r--r-- | bot/src/commands/stats.js | 15 | ||||
| -rw-r--r-- | bot/src/init.js | 16 |
7 files changed, 132 insertions, 79 deletions
diff --git a/bot/src/api/routes/quotes.js b/bot/src/api/routes/quotes.js index f362d7e..1b89f67 100644 --- a/bot/src/api/routes/quotes.js +++ b/bot/src/api/routes/quotes.js @@ -2,70 +2,88 @@ import { Router } from 'express'; import { pendingQuote, quote as newQuote } from '../../models/quote.js'; import { verifyToken } from './auth.js'; -export const quoteRouter = Router(); +export function quoteRouter(client) { + const router = Router(); -quoteRouter.get('/quotes/pending', verifyToken, async (req, res) => { - try { - const quotes = await pendingQuote.findAll(); - res.json(quotes); - } catch (error) { - console.error('Error fetching quotes:', error); - res.status(500).send({ message: 'Internal Server Error' }); - } -}); - -quoteRouter.post('/quotes/add', verifyToken, async (req, res) => { - const { author, authorImage, quote, year, submitterID } = req.body; - try { - await newQuote.create({ - author: author, - authorImage: authorImage, - quote: quote, - year: year, - submitter: submitterID - }); - res.status(200).send({ message: 'Added a new quote' }); - } catch (error) { - console.error('Something went wrong:', error); - res.status(500).send({ message: 'Internal Server Error' }); - } -}); + router.get('/quotes/pending', verifyToken, async (req, res) => { + try { + const quotes = await pendingQuote.findAll(); + res.json(quotes); + } catch (error) { + console.error('Error fetching quotes:', error); + res.status(500).send({ message: 'Internal Server Error' }); + } + }); -quoteRouter.post('/quotes/approve', verifyToken, async (req, res) => { - const { id } = req.body; - try { - const quote = await pendingQuote.findByPk(id); - if (quote) { + router.post('/quotes/add', verifyToken, async (req, res) => { + const { author, authorImage, quote, year, submitterID } = req.body; + try { await newQuote.create({ - author: quote.author, - authorImage: quote.authorImage, - quote: quote.quote, - year: quote.year, - submitter: quote.submitterID + author: author, + authorImage: authorImage, + quote: quote, + year: year, + submitter: submitterID }); - await pendingQuote.destroy({ where: { id } }); - res.status(200).send({ message: 'Quote approved' }); - } else { - res.status(404).send({ message: 'Quote not found' }); + res.status(200).send({ message: 'Added a new quote' }); + } catch (error) { + console.error('Something went wrong:', error); + res.status(500).send({ message: 'Internal Server Error' }); + } + }); + + router.post('/quotes/approve', verifyToken, async (req, res) => { + const { id } = req.body; + try { + const quote = await pendingQuote.findByPk(id); + if (quote) { + await newQuote.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({ message: 'Quote approved' }); + } else { + res.status(404).send({ message: 'Quote not found '}); + } + } catch (error) { + console.error('Error approving quote:', error); + res.status(500).send({ message: 'Internal Server Error' }); } - } catch (error) { - console.error('Error approving quote:', error); - res.status(500).send({ message: 'Internal Server Error' }); - } -}); + }); + + router.post('/quotes/reject', verifyToken, async (req, res) => { + const { id } = req.body; + try { + const quote = await pendingQuote.findByPk(id); + if (quote) { + await pendingQuote.destroy({ where: {id} }); -quoteRouter.post('/quotes/reject', verifyToken, 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({ message: 'Quote rejected' }); - } else { - res.status(404).send({ message: 'Quote not found' }); + if (!req.body.silent) { + client.users.fetch(quote.submitterID).then((user) => { + if (req.body.reason) { + user.send(`Hello ${user.displayName},\nYour quote was rejected for the following reason:\n\`\`\`\n${req.body.reason}\n\`\`\``); + } else { + user.send(`Hello ${user.displayName},\nYour quote was rejected.`); + } + }).catch((err) => { + console.error('Error sending rejection message:', err); + }); + } + + res.status(200).send({ message: 'Quote rejected', reason: req.body.reason }); + } else { + res.status(404).send({ message: 'Quote not found' }); + } + } catch (error) { + console.error('Error rejecting quote:', error); + res.status(500).send({ message: 'Internal Server Error' }); } - } catch (error) { - console.error('Error rejecting quote:', error); - res.status(500).send({ message: 'Internal Server Error' }); - } -}); + }); + + return router; +} diff --git a/bot/src/api/server.js b/bot/src/api/server.js index 379f410..53b29d4 100644 --- a/bot/src/api/server.js +++ b/bot/src/api/server.js @@ -14,7 +14,7 @@ export const apiServer = (client) => { app.use(cors()); // Allow cross-origin requests app.use(express.json()); - app.use('/api', quoteRouter); + app.use('/api', quoteRouter(client)); app.use('/api', settingsRouter(client)); app.use('/api', authRouter()); diff --git a/bot/src/commands/about.js b/bot/src/commands/about.js index 22b3441..177ac47 100644 --- a/bot/src/commands/about.js +++ b/bot/src/commands/about.js @@ -23,12 +23,13 @@ export default { { name: 'License', value: 'GNU General Public License v3.0' }, { name: 'Contributors', value: '- <@297201585090723841> (Uptime command from 2.x)\n' + - '- <@236279900728721409> (Eval command from 2.x)' } + '- <@236279900728721409> (Eval command from 2.x)' + } ) .setFooter({ text: '© Copyright 2017-2025 Andrew Lee & contributors' }) .setColor(abEmbedColour); - let Buttons = new ActionRowBuilder() + let aboutButtons = new ActionRowBuilder() .addComponents( new ButtonBuilder() .setStyle(ButtonStyle.Link) @@ -37,13 +38,13 @@ export default { new ButtonBuilder() .setStyle(ButtonStyle.Link) .setLabel('Invite AleeBot') - .setURL('https://discord.com/oauth2/authorize?client_id=282547024547545109'), + .setURL(`https://discord.com/oauth2/authorize?client_id=${interaction.client.user.id}`), new ButtonBuilder() .setStyle(ButtonStyle.Link) .setLabel('Join Andrew Lee Projects') .setURL('https://discord.gg/EFhRDqG') ); - return await interaction.reply({ embeds: [aboutEmbed], components: [Buttons] }); + return await interaction.reply({ embeds: [aboutEmbed], components: [aboutButtons] }); } }; diff --git a/bot/src/commands/quote.js b/bot/src/commands/quote.js index 55b8cbc..9c409f9 100644 --- a/bot/src/commands/quote.js +++ b/bot/src/commands/quote.js @@ -50,6 +50,7 @@ export default { .setCustomId('authorImage') .setLabel('Submit the image of the author') .setMaxLength(100) + .setMinLength(4) .setPlaceholder('Image URL (512x512) or (128x128)') .setStyle(TextInputStyle.Short); @@ -57,6 +58,7 @@ export default { .setCustomId('quote') .setLabel('Enter the quote') .setMaxLength(200) + .setMinLength(5) .setPlaceholder('Quote') .setStyle(TextInputStyle.Paragraph); @@ -85,6 +87,29 @@ export default { const quote = modalInteraction.fields.getTextInputValue('quote'); const year = modalInteraction.fields.getTextInputValue('year'); + try { + new URL(authorImage); + } catch { + return modalInteraction.reply({ + content: 'Error: Author image must be a valid URL.', + flags: MessageFlags.Ephemeral + }); + } + + if (!authorImage.match(/\.(jpeg|jpg|png|webp)$/i)) { + return modalInteraction.reply({ + content: 'Error: Author image URL must end with a valid image extension (jpeg, jpg, png, webp).', + flags: MessageFlags.Ephemeral + }); + } + + if (isNaN(year) || year.trim() === '' || !Number.isInteger(Number(year))) { + return modalInteraction.reply({ + content: 'Error: Year must be a number.', + flags: MessageFlags.Ephemeral + }); + } + await pendingQuote.create({ author: author, authorImage: authorImage, diff --git a/bot/src/commands/serverinfo.js b/bot/src/commands/serverinfo.js index 3f7bd72..7ebf6ea 100644 --- a/bot/src/commands/serverinfo.js +++ b/bot/src/commands/serverinfo.js @@ -22,10 +22,10 @@ export default { .addFields( { name: 'Main Information', value: `**Server Name:** ${interaction.guild.name}\n**Server ID:** ${interaction.guild.id}\n**Server Owner:** ${guildOwner.user.username}`}, { name: 'Join Dates', value: `**Created At:** ${interaction.guild.createdAt.toUTCString()}\n**AleeBot Joined:** ${interaction.guild.joinedAt.toUTCString()}`}, - { name: 'Total Channels (without threads)', value: `${interaction.guild.channels.channelCountWithoutThreads}` }, + { name: 'Total Channels (without threads)', value: interaction.guild.channels.channelCountWithoutThreads.toString() }, // { name: 'Channels', value: listedChannels.join(' ') }, - { name: 'Total Members (with bots)', value: `${interaction.guild.memberCount}` }, - { name: 'Total Members (without bots)', value: `${memberCountNoBots}` } + { name: 'Total Members (with bots)', value: interaction.guild.memberCount.toString() }, + { name: 'Total Members (without bots)', value: memberCountNoBots.toString() } ) .setColor(abEmbedColour); return await interaction.reply({ embeds: [serverEmbed] }); diff --git a/bot/src/commands/stats.js b/bot/src/commands/stats.js index 9504386..6924874 100644 --- a/bot/src/commands/stats.js +++ b/bot/src/commands/stats.js @@ -1,21 +1,26 @@ import { EmbedBuilder, SlashCommandBuilder } from 'discord.js'; import { commandUsages } from '../models/command-usages.js'; import { abEmbedColour } from '../storage/consts.js'; +import { quote } from '../models/quote.js'; export default { data: new SlashCommandBuilder() .setName('stats') - .setDescription('Shows how many times you executed a command.'), + .setDescription('Shows statistics of your interaction with AleeBot.'), async execute(interaction) { - let cmdUsage = await commandUsages.findAll({ where: { userID: interaction.user.id } }); + const cmdUsage = await commandUsages.findAll({ where: { userID: interaction.user.id } }); + const quoteSubmitted = await quote.findAll({ where: { submitter: interaction.user.id } }); + const totalCommands = cmdUsage.length; const guildCommands = cmdUsage.filter(cmd => cmd.guildID === interaction.guild.id).length; + const totalQuotes = quoteSubmitted.length; const statsEmbed = new EmbedBuilder() - .setAuthor({ name: `Stats for ${interaction.user.username}`, iconURL: interaction.client.user.avatarURL() }) + .setAuthor({ name: `AleeBot Stats for ${interaction.user.displayName}`, iconURL: interaction.client.user.avatarURL() }) .addFields( - { name: 'Total Commands Executed', value: totalCommands.toString() }, - { name: 'Total Commands Executed in this Guild', value: guildCommands.toString() } + { name: 'Total Commands Executed (Global)', value: totalCommands.toString() }, + { name: 'Total Commands Executed (Guild)', value: guildCommands.toString() }, + { name: 'Total Quotes Submitted', value: totalQuotes.toString() } ) .setColor(abEmbedColour); diff --git a/bot/src/init.js b/bot/src/init.js index 3557757..45b9a41 100644 --- a/bot/src/init.js +++ b/bot/src/init.js @@ -5,11 +5,15 @@ import { command } from './handlers/command.js'; //import { deployCommands } from './util/deploy.js'; export async function init(client) { - if (process.env.NODE_ENV === 'development') { - await syncDB(); + try { + if (process.env.NODE_ENV === 'development') { + await syncDB(); + } + //deployCommands().then(() => console.log('[>] Deployed commands')); + await apiServer(client); + await event(client).then(() => console.log('[>] Event module loaded')); + await command(client).then(() => console.log('[>] Command module loaded')); + } catch (e) { + console.error(e); } - //deployCommands().then(() => console.log('[>] Deployed commands')); - await apiServer(client); - await event(client).then(() => console.log('[>] Event module loaded')); - await command(client).then(() => console.log('[>] Command module loaded')); } |
