aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Lee <andrew@alee14.me>2025-01-11 11:55:18 -0500
committerAndrew Lee <andrew@alee14.me>2025-01-11 11:55:18 -0500
commitf5de90ba89146008af78c16e798e216efccf0c50 (patch)
tree75f2bb7cee8bacce3f92c2b1bc468c7831b3429e
parent83dcca0a0279ce6415a3e9d153c13d91284369b0 (diff)
downloadAleeBot-f5de90ba89146008af78c16e798e216efccf0c50.tar.gz
AleeBot-f5de90ba89146008af78c16e798e216efccf0c50.tar.bz2
AleeBot-f5de90ba89146008af78c16e798e216efccf0c50.zip
Ability to add quotes, web interface, pending quotes
-rw-r--r--api/server.js78
-rw-r--r--bot_discord.js30
-rw-r--r--commands/about.js3
-rw-r--r--commands/addquote.js198
-rw-r--r--commands/quote.js4
-rw-r--r--commands/setup.js6
-rw-r--r--deprecated/balance.js50
-rw-r--r--deprecated/buy.js114
-rw-r--r--deprecated/daily.js56
-rw-r--r--deprecated/pay.js60
-rw-r--r--models/quote.js27
-rw-r--r--package.json1
-rw-r--r--storage/activities.js2
-rw-r--r--storage/settings.json2
-rw-r--r--sync-database.js8
-rw-r--r--web/.gitignore24
-rw-r--r--web/.vscode/extensions.json4
-rw-r--r--web/.vscode/launch.json11
-rw-r--r--web/astro.config.mjs9
-rw-r--r--web/bun.lockbbin0 -> 172416 bytes
-rw-r--r--web/package.json19
-rw-r--r--web/public/favicon.svg9
-rw-r--r--web/src/components/Quotes.jsx86
-rw-r--r--web/src/layouts/Layout.astro22
-rw-r--r--web/src/pages/index.astro29
-rw-r--r--web/src/styles/Quote.css33
-rw-r--r--web/tsconfig.json14
-rw-r--r--yarn.lock12
28 files changed, 528 insertions, 383 deletions
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;
diff --git a/bot_discord.js b/bot_discord.js
index df2264f..8bfa7da 100644
--- a/bot_discord.js
+++ b/bot_discord.js
@@ -1,7 +1,7 @@
/** **************************************
*
* AleeBot: Made for discord servers
- * Copyright (C) 2017-2022 Andrew Lee Projects
+ * Copyright (C) 2017-2025 Andrew Lee Projects
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,17 +24,16 @@ const client = new Discord.Client({
parse: ['users', 'roles'],
repliedUser: true
},
- intents: ['GUILDS', 'GUILD_MESSAGES', 'GUILD_MEMBERS', 'GUILD_MESSAGE_REACTIONS']
+ intents: ['GUILDS', 'GUILD_MESSAGES', 'GUILD_MEMBERS', 'GUILD_MESSAGE_REACTIONS', 'DIRECT_MESSAGES', 'DIRECT_MESSAGE_REACTIONS']
});
const moment = require('moment');
-const express = require('express');
const fs = require('fs');
const readline = require('readline');
const colors = require('colors');
//const i18next = require('i18next');
-const web = express();
const settings = require('./storage/settings.json');
const { activity } = require('./storage/activities');
+const createServer = require("./api/server");
const active = new Map();
let autoRole = true;
let readyEmbedMessage = true;
@@ -50,11 +49,11 @@ const log = (message) => {
function botPresence() {
client.user.setPresence({
- activities: [{
- name: activity[Math.floor(Math.random() * activity.length)]
- }],
- status: 'online',
- afk: false,
+ activities: [{
+ name: activity[Math.floor(Math.random() * activity.length)]
+ }],
+ status: 'online',
+ afk: false,
});
log(`[>] Updated bot presence to "${client.user.presence.activities[0].name}"`.green);
}
@@ -65,7 +64,7 @@ const rl = readline.createInterface({
prompt: '> '.gray,
});
-console.log(`AleeBot ${settings.abVersion}: Copyright (C) 2017-2023 Andrew Lee Projects`.gray);
+console.log(`AleeBot ${settings.abVersion}: Copyright (C) 2017-2025 Andrew Lee Projects`.gray);
console.log('This program comes with ABSOLUTELY NO WARRANTY; for details type `show w\'.'.gray);
console.log('This is free software, and you are welcome to redistribute it'.gray);
console.log('under certain conditions; type `show c\' for details.\n'.gray);
@@ -219,13 +218,7 @@ client.on('ready', async () => {
botPresence();
- web.get('/', (req, res) => {
- res.send("Hello World! This is going to become the AleeBot dashboard...");
- });
-
- web.listen(process.env.port, () => {
- console.log(`Listening at https://localhost:${process.env.port}`)
- })
+ createServer();
setInterval(function() {
botPresence();
@@ -286,7 +279,7 @@ client.on('guildMemberRemove', (member) => {
client.on('messageUpdate', async (oldMessage, newMessage) => {
- if (oldMessage.guild.id !== serverWhitelist) return;
+ if (!oldMessage.guild || oldMessage.guild.id !== serverWhitelist) return;
if (oldMessage.content === newMessage.content) {
return;
}
@@ -407,6 +400,7 @@ client.on("messageReactionAdd", async (reaction, user) => {
client.on('messageCreate', async(msg) => {
if (!client.application?.owner) await client.application?.fetch();
if (msg.author.bot) return;
+ if (!msg.guild) return;
const prefixes = JSON.parse(fs.readFileSync('./storage/prefixes.json', 'utf8'));
diff --git a/commands/about.js b/commands/about.js
index 7272b6a..0ae756d 100644
--- a/commands/about.js
+++ b/commands/about.js
@@ -17,7 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* *************************************/
-const {MessageButton} = require("discord.js");
module.exports.run = async (client, message) => {
const { MessageEmbed, MessageButton, MessageActionRow } = require('discord.js');
@@ -30,7 +29,7 @@ module.exports.run = async (client, message) => {
.addField('About AleeBot', 'AleeBot is an all-in-one bot that\'s made from the Discord.JS API!')
.addField('License', 'GNU General Public License v3.0')
.addField('Contributors', Contributors)
- .setFooter('© Copyright 2017-2023 Andrew Lee Projects')
+ .setFooter('© Copyright 2017-2025 Andrew Lee Projects')
.setColor('#1fd619');
let Buttons = new MessageActionRow()
diff --git a/commands/addquote.js b/commands/addquote.js
index 5f2b9bc..52f7b21 100644
--- a/commands/addquote.js
+++ b/commands/addquote.js
@@ -17,105 +17,164 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* *************************************/
-const quoteDB = require('../models/quote');
+const { pendingQuote } = require('../models/quote');
const { MessageEmbed } = require("discord.js");
-module.exports.run = async (client, message, args) => {
- if (!['242775871059001344'].includes(message.author.id)) return message.reply('**This command is disabled due to a new system being implemented.**');
- try {
- let newAuthor;
- let newAuthorImage;
- let newQuote;
- let newYear;
-
- let quoteOriginator;
+module.exports.run = async (client, message) => {
+ try {
+ let newAuthor, newAuthorImage, newQuote, newYear;
let isSetupRunning = false;
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.',
- 'Enter the quote',
- 'Specify the year from which the quote originates.'
- ]
-
- 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 += "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"
+ '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.',
+ 'Enter the quote:',
+ 'Specify the year from which the quote originates:'
+ ];
+
+ async function createQuote() {
+ await pendingQuote.create({
+ author: newAuthor,
+ authorImage: newAuthorImage,
+ quote: newQuote,
+ year: newYear,
+ });
+ }
- let counter = 0
+ 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 += "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 the quote.');
+ return await message.reply('You are already setting up a quote.');
}
- const filter = m => m.author.id === message.author.id
+
+ const filter = (m) => m.author.id === message.author.id;
isSetupRunning = true;
- await message.reply(':arrow_left: Check your DMs to continue.')
- await message.author.send(setupMessage);
- await message.author.send(setupProcess[counter++]);
+ await message.reply(':arrow_left: Check DMs to continue.');
+
+ const dmChannel = await message.author.createDM();
+ await dmChannel.send(setupMessage);
+ await dmChannel.send(setupProcess[0]);
- const collector = message.channel.createMessageCollector({
+ let counter = 1;
+ const collector = dmChannel.createMessageCollector({
filter,
max: setupProcess.length,
- time: 1000 * 60
+ time: 1000 * 120
});
- collector.on('collect', message => {
- console.log(`Collected ${message.content} from ${message.author.tag}`)
- if (setupProcess.length > setupProcess.length + 1) {
- message.author.send(setupProcess[counter++]);
+ collector.on('collect', async () => {
+ if (counter < setupProcess.length) {
+ await dmChannel.send(setupProcess[counter++]);
}
});
- collector.on('end', collected => {
- if (collected.size === 0 && collected.size < 2) {
- message.author.send('Quote setup was not completed, rerun the command.')
+ collector.on('end', async (collected) => {
+ if (collected.size < setupProcess.length) {
+ dmChannel.send('Quote setup was not completed. Please rerun the command.');
} else {
- let quoteContent = [];
-
- collected.forEach((message) => {
- quoteContent.push(message.content)
- })
-
- newAuthor = quoteContent[0]
- newAuthorImage = quoteContent[1]
- newQuote = quoteContent[2]
- newYear = quoteContent[3]
+ const quoteContent = collected.map((m) => m.content);
+ newAuthor = quoteContent[0];
+ newAuthorImage = quoteContent[1];
+ 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')
+ .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);
+ .addField('Year', newYear)
+ .setColor('#1fd619');
+
+ let messageReact = await dmChannel.send({embeds: [setupEmbed]});
+ await messageReact.react('🧑');
+ await messageReact.react('📷');
+ await messageReact.react('🖋️');
+ await messageReact.react('📅');
+ await messageReact.react('✅');
+ await messageReact.react('❌');
+
+ const reactionFilter = (reaction, user) => {
+ return ['🧑', '📷', '🖋️', '📅', '✅', '❌'].includes(reaction.emoji.name) && user.id === message.author.id;
+ };
+
+ const reactionCollector = messageReact.createReactionCollector({
+ filter: reactionFilter,
+ time: 1000 * 120
+ });
+
+ reactionCollector.on('collect', async (reaction) => {
+ switch (reaction.emoji.name) {
+ case '🧑':
+ await dmChannel.send('You selected the author. Please provide the name of the author.');
+ const authorResponse = await dmChannel.awaitMessages({ filter, max: 1, time: 60000 });
+ if (authorResponse.size) newAuthor = authorResponse.first().content;
+ await dmChannel.send('Updated author name.');
+ break;
+ case '📷':
+ await dmChannel.send('You selected the author image. Please provide the image URL.');
+ const imageResponse = await dmChannel.awaitMessages({ filter, max: 1, time: 60000 });
+ if (imageResponse.size) newAuthorImage = imageResponse.first().content;
+ await dmChannel.send('Updated author URL.');
+ break;
+ case '🖋️':
+ await dmChannel.send('You selected the quote. Please provide the quote.');
+ const quoteResponse = await dmChannel.awaitMessages({ filter, max: 1, time: 60000 });
+ if (quoteResponse.size) newQuote = quoteResponse.first().content;
+ await dmChannel.send('Updated quote.');
+ break;
+ case '📅':
+ await dmChannel.send('You selected the year. Please provide the year.');
+ const yearResponse = await dmChannel.awaitMessages({ filter, max: 1, time: 60000 });
+ if (yearResponse.size) newYear = yearResponse.first().content;
+ await dmChannel.send('Updated year.');
+ break;
+ case '✅':
+ reactionCollector.stop('completed');
+ break;
+ case '❌':
+ reactionCollector.stop('cancelled');
+ 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]});
+ });
+
+ 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();
+ }
+ });
- message.author.send({embeds:[setupEmbed]})
- quoteOriginator = message.author.tag
- console.log(`This quote has been originated from ${quoteOriginator}`)
- isSetupRunning = false;
}
-
});
-
- /*await quoteDB.create({
- author: newAuthor,
- authorImage: newAuthorImage,
- quote: newQuote,
- year: newYear,
- });*/
-
- //let messageReact = await message.author.send({embeds: [setupEmbed]});
- /*await messageReact.react('🧑');
- await messageReact.react('📷');
- await messageReact.react('🖋️');
- await messageReact.react('📅');*/
-
} catch (error) {
- console.log(error)
+ console.error(error);
}
};
@@ -123,6 +182,7 @@ exports.conf = {
aliases: [],
guildOnly: true,
};
+
exports.help = {
name: 'addquote',
description: 'Adds a quote to the database.',
diff --git a/commands/quote.js b/commands/quote.js
index 37f5714..02699cd 100644
--- a/commands/quote.js
+++ b/commands/quote.js
@@ -18,7 +18,7 @@
*
* *************************************/
module.exports.run = async (client, message, args) => {
- const quoteDB = require('../models/quote');
+ const { quote: quoteDB } = require('../models/quote');
const { MessageEmbed } = require('discord.js');
let quoteID = args[0];
@@ -38,7 +38,7 @@ module.exports.run = async (client, message, args) => {
.setColor('#1fd619')
.setFooter('- ' + quote.year);
- await message.reply({ content: 'Alright, here\'s your quote.', embeds: [quoteEmbed] })
+ 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 5c2f232..380e85e 100644
--- a/commands/setup.js
+++ b/commands/setup.js
@@ -20,14 +20,12 @@
module.exports.run = async (client, message) => {
if (!['242775871059001344', message.guild.ownerId].includes(message.author.id)) return message.reply(':warning: You must be a server owner or be the creator of the bot to access this command.');
- message.reply('Look at your DMs.');
- //message.reply("This feature is coming soon. Stay tuned!");
+ message.reply(':arrow_left: Check DMs to continue.');
const Discord = require('discord.js');
const setupEmbed = new Discord.MessageEmbed()
.setTitle('AleeBot Setup', client.user.avatarURL())
.setDescription('Select the options')
- .addField('Chat Logs', 'channelid', true)
- .addField('Joining & Leaving Logs', 'placeholder', true)
+ .addField('Logging', 'channelid', true)
.addField('Broadcast', 'placeholder', true)
.addField('Broadcast', 'placeholder', true);
diff --git a/deprecated/balance.js b/deprecated/balance.js
deleted file mode 100644
index bf7618c..0000000
--- a/deprecated/balance.js
+++ /dev/null
@@ -1,50 +0,0 @@
-/** **************************************
- *
- * Balance: Command for AleeBot
- * Copyright (C) 2017-2021 Alee Productions
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * *************************************/
-module.exports.run = async (client, message) => {
- const db = require('quick.db');
- const {MessageEmbed} = require('discord.js');
-
- const user = message.mentions.users.first() || message.author;
-
- let balance = await db.fetch(`userBalance_${user.id}`);
-
- if (balance === null) {
- db.set(`userBalance_${message.author.id}`, 0);
- balance = 0;
- }
- const embed = new MessageEmbed()
- .setDescription('**AleeCorp Bank**')
- .addField('Account Holder: ', user.username, true)
- .addField('Account Balance: ', balance, true)
- .setColor('#1fd619');
-
- message.channel.send({embed});
-};
-
-exports.conf = {
- aliases: ['bal', 'money'],
- guildOnly: false,
-};
-exports.help = {
- name: 'balance',
- description: 'Checks the balance of AleeBot',
- usage: 'balance [@someone (optional)]',
- category: '- Economy Commands',
-};
diff --git a/deprecated/buy.js b/deprecated/buy.js
deleted file mode 100644
index 98d4fcf..0000000
--- a/deprecated/buy.js
+++ /dev/null
@@ -1,114 +0,0 @@
-/** **************************************
- *
- * Buy: Command for AleeBot
- * Copyright (C) 2017-2021 Alee Productions
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * *************************************/
-module.exports.run = async (client, message, args) => {
-const Discord = require('discord.js');
-const fs = require('fs')
-const db = require('quick.db');
-const items = JSON.parse(fs.readFileSync('./storage/items.json', 'utf8'));
-
- let categories = [];
-
- if (!args.join(" ")) {
-
-
- for (var i in items) {
-
-
- if (!categories.includes(items[i].type)) {
- categories.push(items[i].type)
- }
-
- }
-
-
- const embed = new Discord.MessageEmbed()
- .setDescription(`Available Items`)
- .setColor('#1fd619')
-
- for (var i = 0; i < categories.length; i++) {
-
- var tempDesc = '';
-
- for (var c in items) {
- if (categories[i] === items[c].type) {
-
- tempDesc += `${items[c].name} - ${items[c].price}$ - ${items[c].desc}\n`;
-
- }
-
- }
-
- embed.addField(categories[i], tempDesc);
-
- }
-
-
- return message.channel.send({
- embed
- });
-
-
- }
-
- let itemName = '';
- let itemPrice = 0;
- let itemDesc = '';
-
- for (var i in items) {
- if (args.join(" ").trim().toUpperCase() === items[i].name.toUpperCase()) {
- itemName = items[i].name;
- itemPrice = items[i].price;
- itemDesc = items[i].desc;
- }
- }
-
-
- if (itemName === '') {
- return message.channel.send(`Item ${args.join(" ").trim()} not found.`)
- }
-
- let selfBalance = await db.fetch(`userBalance_${message.author.id}`);
-
- if (selfBalance === null) {
- db.set(`userBalance_${message.author.id}`, 0);
- selfBalance = 0
- }
-
- if (itemPrice > selfBalance) return message.reply('You don\'t have enough money for this item.')
-
- db.subtract(`userBalance_${message.author.id}`, itemPrice);
-
- if (itemName === 'Programmer Role') {
- message.guild.members.get(message.author.id).addRole(message.guild.roles.find("name", "Programmers"));
- }
-
- message.channel.send('You bought ' + itemName + '!');
-};
-
-exports.conf = {
- aliases: [],
- guildOnly: false,
-};
-exports.help = {
- name: 'buy',
- description: 'Buy things.',
- usage: 'buy [item]',
- category: '- Economy Commands',
-};
diff --git a/deprecated/daily.js b/deprecated/daily.js
deleted file mode 100644
index 4a38f26..0000000
--- a/deprecated/daily.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/** **************************************
- *
- * Daily: Command for AleeBot
- * Copyright (C) 2017-2021 Alee Productions
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * *************************************/
-const db = require('quick.db');
-ms = require('parse-ms');
-
-module.exports.run = async (client, message) => {
- const cooldown = 8.64e+7;
- const amount = 100;
-
- const lastDaily = await db.fetch(`lastDaily_${message.author.id}`);
-
- if (lastDaily !== null && cooldown - (Date.now() - lastDaily) > 0) {
- const timeObj = ms(cooldown - (Date.now() - lastDaily));
-
- message.reply(`You already collected your money, please wait **${timeObj.hours}h ${timeObj.minutes}m**!`);
- } else {
- message.channel.send(`You have successfully collected $${amount} dollars!`);
-
- const balance = await db.fetch(`userBalance_${message.author.id}`);
-
- if (balance == null) {
- db.set(`userBalance_${message.author.id}`, 0);
- }
-
- db.set(`lastDaily_${message.author.id}`, Date.now());
- db.add(`userBalance_${message.author.id}`, 100);
- }
-};
-
-exports.conf = {
- aliases: [],
- guildOnly: false,
-};
-exports.help = {
- name: 'daily',
- description: 'This gives you money everyday.',
- usage: 'daily',
- category: '- Economy Commands',
-};
diff --git a/deprecated/pay.js b/deprecated/pay.js
deleted file mode 100644
index 42e0f28..0000000
--- a/deprecated/pay.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/** **************************************
- *
- * Pay: Command for AleeBot
- * Copyright (C) 2017-2021 Alee Productions
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * *************************************/
-
-module.exports.run = async (client, message, args) => {
- const db = require('quick.db');
- if (!message.mentions.members.first()) return message.reply('Please mention a user...');
-
- const targetMember = message.mentions.members.first();
- const amount = parseInt(args.join(' ').replace(targetMember, ''));
-
- if (isNaN(amount)) return message.reply('Please define an amount.');
-
- let targetBalance = await db.fetch(`userBalance_${targetMember.id}`);
- let selfBalance = await db.fetch(`userBalance_${message.author.id}`);
-
- if (targetBalance === null) {
- db.set(`userBalance_${targetMember.id}`, 0);
- targetBalance = 0;
- }
-
- if (selfBalance === null) {
- db.set(`userBalance_${message.author.id}`, 0);
- selfBalance = 0;
- }
-
- if (amount > selfBalance) return message.reply('Sorry you don\'t have enough money.');
-
- db.add(`userBalance_${targetMember.id}`, amount);
- db.subtract(`userBalance_${message.author.id}`, amount);
-
- message.reply(`Successfully transfered $${amount} to ${targetMember.user}`);
-};
-
-exports.conf = {
- aliases: ['transfer'],
- guildOnly: false,
-};
-exports.help = {
- name: 'pay',
- description: 'You can pay others!',
- usage: 'pay [@user] [interger]',
- category: '- Economy Commands',
-};
diff --git a/models/quote.js b/models/quote.js
index f31b472..eab4f57 100644
--- a/models/quote.js
+++ b/models/quote.js
@@ -26,4 +26,29 @@ const quote = sequelize.define('quotes', {
})
-module.exports = quote
+const pendingQuote = sequelize.define('pending-quotes', {
+ id: {
+ type: Sequelize.INTEGER,
+ autoIncrement: true,
+ primaryKey: true
+ },
+ author: {
+ type: Sequelize.STRING,
+ allowNull: false
+ },
+ authorImage: {
+ type: Sequelize.STRING,
+ allowNull: false
+ },
+ quote: {
+ type: Sequelize.TEXT,
+ allowNull: false
+ },
+ year: {
+ type: Sequelize.STRING,
+ allowNull: false
+ }
+
+})
+
+module.exports = { quote, pendingQuote };
diff --git a/package.json b/package.json
index 6e07caa..9584d19 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
"dependencies": {
"blessed": "^0.1.81",
"colors": "^1.3.0",
+ "cors": "^2.8.5",
"discord.js": "^13.0.1",
"dotenv": "^16.3.1",
"eslint": "^7.1.0",
diff --git a/storage/activities.js b/storage/activities.js
index 2b2a286..5d0161e 100644
--- a/storage/activities.js
+++ b/storage/activities.js
@@ -92,10 +92,8 @@ const activities = [
'GNU\'s NOT UNIX!',
'Linux, but actually GNU/Linux',
'Praise RMS! (dont)',
- 'Praying to St IGNUcius',
'Debloating my ThinkPad',
'Turbotastic!',
- 'Goddamn Idiotic Truckload of Windows',
`Now running on Discord.JS ${version}!`
];
diff --git a/storage/settings.json b/storage/settings.json
index b53fd84..83932cc 100644
--- a/storage/settings.json
+++ b/storage/settings.json
@@ -1,4 +1,4 @@
{
"abVersion": "2.13.0 Beta",
- "prefix": "ab:"
+ "prefix": "abb:"
}
diff --git a/sync-database.js b/sync-database.js
index 2462f29..f7b9211 100644
--- a/sync-database.js
+++ b/sync-database.js
@@ -1,9 +1,13 @@
-const quoteDB = require("./models/quote");
+const { quote, pendingQuote } = require("./models/quote");
const guildDB = require ('./models/guild-settings');
-quoteDB.sync({alter: true}).then(() => {
+quote.sync({alter: true}).then(() => {
console.log('Quote database synced!')
});
+pendingQuote.sync({alter: true}).then(() => {
+ console.log('Pending Quote database synced!')
+});
+
guildDB.sync({alter: true}).then(() => {
console.log('Guild database synced!')
});
diff --git a/web/.gitignore b/web/.gitignore
new file mode 100644
index 0000000..016b59e
--- /dev/null
+++ b/web/.gitignore
@@ -0,0 +1,24 @@
+# build output
+dist/
+
+# generated types
+.astro/
+
+# dependencies
+node_modules/
+
+# logs
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# environment variables
+.env
+.env.production
+
+# macOS-specific files
+.DS_Store
+
+# jetbrains setting folder
+.idea/
diff --git a/web/.vscode/extensions.json b/web/.vscode/extensions.json
new file mode 100644
index 0000000..22a1505
--- /dev/null
+++ b/web/.vscode/extensions.json
@@ -0,0 +1,4 @@
+{
+ "recommendations": ["astro-build.astro-vscode"],
+ "unwantedRecommendations": []
+}
diff --git a/web/.vscode/launch.json b/web/.vscode/launch.json
new file mode 100644
index 0000000..d642209
--- /dev/null
+++ b/web/.vscode/launch.json
@@ -0,0 +1,11 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "command": "./node_modules/.bin/astro dev",
+ "name": "Development server",
+ "request": "launch",
+ "type": "node-terminal"
+ }
+ ]
+}
diff --git a/web/astro.config.mjs b/web/astro.config.mjs
new file mode 100644
index 0000000..53e49de
--- /dev/null
+++ b/web/astro.config.mjs
@@ -0,0 +1,9 @@
+// @ts-check
+import { defineConfig } from 'astro/config';
+
+import react from '@astrojs/react';
+
+// https://astro.build/config
+export default defineConfig({
+ integrations: [react()]
+}); \ No newline at end of file
diff --git a/web/bun.lockb b/web/bun.lockb
new file mode 100644
index 0000000..b648049
--- /dev/null
+++ b/web/bun.lockb
Binary files differ
diff --git a/web/package.json b/web/package.json
new file mode 100644
index 0000000..811ab8b
--- /dev/null
+++ b/web/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "aleebot-web",
+ "type": "module",
+ "version": "0.0.1",
+ "scripts": {
+ "dev": "astro dev",
+ "build": "astro build",
+ "preview": "astro preview",
+ "astro": "astro"
+ },
+ "dependencies": {
+ "@astrojs/react": "^4.1.3",
+ "@types/react": "^19.0.4",
+ "@types/react-dom": "^19.0.2",
+ "astro": "^5.1.5",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
+ }
+}
diff --git a/web/public/favicon.svg b/web/public/favicon.svg
new file mode 100644
index 0000000..f157bd1
--- /dev/null
+++ b/web/public/favicon.svg
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
+ <path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
+ <style>
+ path { fill: #000; }
+ @media (prefers-color-scheme: dark) {
+ path { fill: #FFF; }
+ }
+ </style>
+</svg>
diff --git a/web/src/components/Quotes.jsx b/web/src/components/Quotes.jsx
new file mode 100644
index 0000000..1d563e7
--- /dev/null
+++ b/web/src/components/Quotes.jsx
@@ -0,0 +1,86 @@
+import { useState, useEffect } from 'react';
+import '../styles/Quote.css'
+
+export function PendingQuotes() {
+ const [quotes, setQuotes] = useState([]);
+
+ const fetchQuotes = async () => {
+ try {
+ const response = await fetch('http://localhost:3000/api/pending-quotes');
+ const data = await response.json();
+ setQuotes(data);
+ } catch (error) {
+ console.error('Failed to fetch quotes:', error);
+ }
+ };
+
+ useEffect(() => {
+ fetchQuotes();
+ }, []);
+
+ const approveQuote = async (id) => {
+ try {
+ const response = await fetch('http://localhost:3000/api/approve-quote', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ id }),
+ });
+
+ if (response.ok) {
+ fetchQuotes(); // Refresh the listing after approving the quote
+ } else {
+ console.error('Failed to approve quote');
+ }
+ } catch (error) {
+ console.error('Error approving quote:', error);
+ }
+ };
+
+ const rejectQuote = async (id) => {
+ try {
+ const response = await fetch('http://localhost:3000/api/reject-quote', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ id }),
+ });
+
+ if (response.ok) {
+ fetchQuotes(); // Refresh the listing after approving the quote
+ } else {
+ console.error('Failed to reject quote');
+ }
+ } catch (error) {
+ console.error('Error rejecting quote:', error);
+ }
+ };
+
+ return (
+ <div>
+ <h1>Pending Quotes</h1>
+ {quotes.length > 0 ? (
+ <ul className="quoteList">
+ {quotes.map((quote) => (
+ <li key={quote.id} className="quoteList">
+ <div className="quote">
+ <div className="author">
+ <img src={quote.authorImage} alt="No Profile" width="50" height="50"/>
+ <h1 className="quoteAuthor">{quote.author}</h1>
+ </div>
+ <p className="quoteText">{quote.quote}</p>
+ <small>- {quote.year}</small>
+ </div>
+ <button onClick={() => approveQuote(quote.id)}>Approve</button>
+ <button onClick={() => rejectQuote(quote.id)}>Reject</button>
+ </li>
+ ))}
+ </ul>
+ ) : (
+ <p>No pending quotes available.</p>
+ )}
+ </div>
+ );
+}
diff --git a/web/src/layouts/Layout.astro b/web/src/layouts/Layout.astro
new file mode 100644
index 0000000..e455c61
--- /dev/null
+++ b/web/src/layouts/Layout.astro
@@ -0,0 +1,22 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width" />
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
+ <meta name="generator" content={Astro.generator} />
+ <title>Astro Basics</title>
+ </head>
+ <body>
+ <slot />
+ </body>
+</html>
+
+<style>
+ html,
+ body {
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ }
+</style>
diff --git a/web/src/pages/index.astro b/web/src/pages/index.astro
new file mode 100644
index 0000000..b5c607d
--- /dev/null
+++ b/web/src/pages/index.astro
@@ -0,0 +1,29 @@
+---
+import Layout from '../layouts/Layout.astro';
+import { PendingQuotes } from '../components/Quotes';
+
+const version = await fetch('http://localhost:3000/api/version').then(res => res.json());
+---
+
+<Layout>
+ <div class="container">
+ <h1>AleeBot {version}</h1>
+ <PendingQuotes client:load />
+ </div>
+</Layout>
+
+<style>
+ @import url('https://fonts.googleapis.com/css2?family=Exo+2:ital,wght@0,100..900;1,100..900&display=swap');
+ html,
+ body {
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ font-family: "Exo 2", sans-serif;
+ }
+
+ .container {
+ margin: 2em;
+ }
+
+</style>
diff --git a/web/src/styles/Quote.css b/web/src/styles/Quote.css
new file mode 100644
index 0000000..8adfb29
--- /dev/null
+++ b/web/src/styles/Quote.css
@@ -0,0 +1,33 @@
+.quote {
+ display: flex;
+ flex-direction: column;
+ background: #555555;
+ color: #FFFFFF;
+ padding: 1em;
+}
+
+ul.quoteList {
+ margin: 0;
+ padding: 0;
+}
+
+li.quoteList {
+ list-style-type: none;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+.author {
+ display: flex;
+ flex-direction: row;
+}
+
+h1.quoteAuthor {
+ font-size: 1.5em;
+ padding: 0;
+ margin: 0 0 0 .5em;
+}
+
+.quoteText {
+ margin: .5em 0;
+}
diff --git a/web/tsconfig.json b/web/tsconfig.json
new file mode 100644
index 0000000..69c1600
--- /dev/null
+++ b/web/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "extends": "astro/tsconfigs/strict",
+ "include": [
+ ".astro/types.d.ts",
+ "**/*"
+ ],
+ "exclude": [
+ "dist"
+ ],
+ "compilerOptions": {
+ "jsx": "react-jsx",
+ "jsxImportSource": "react"
+ }
+} \ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 5942f18..d266f22 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -513,6 +513,14 @@ cookie@0.5.0:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
+cors@^2.8.5:
+ version "2.8.5"
+ resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
+ integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
+ dependencies:
+ object-assign "^4"
+ vary "^1"
+
cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@@ -1507,7 +1515,7 @@ npmlog@^6.0.0:
gauge "^4.0.3"
set-blocking "^2.0.0"
-object-assign@^4.1.1:
+object-assign@^4, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
@@ -2100,7 +2108,7 @@ validator@^13.7.0:
resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855"
integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==
-vary@~1.1.2:
+vary@^1, vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==