aboutsummaryrefslogtreecommitdiff
path: root/bot/src
diff options
context:
space:
mode:
Diffstat (limited to 'bot/src')
-rw-r--r--bot/src/api/routes/quotes.js138
-rw-r--r--bot/src/api/server.js2
-rw-r--r--bot/src/commands/about.js9
-rw-r--r--bot/src/commands/quote.js25
-rw-r--r--bot/src/commands/serverinfo.js6
-rw-r--r--bot/src/commands/stats.js15
-rw-r--r--bot/src/init.js16
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'));
}