mirror of
https://github.com/DarthKilroy/Spot.git
synced 2026-02-04 02:26:48 +00:00
Remove unused code, clean up folder tree
This commit is contained in:
parent
a4892d854b
commit
1e8c1261f5
14 changed files with 38 additions and 80 deletions
50
command/avatar.js
Normal file
50
command/avatar.js
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const Discord = require('discord.js');
|
||||
const CommandCategory = require('../model/command-category');
|
||||
const CommandPermission = require('../model/command-permission');
|
||||
const Guild = require('../model/guild');
|
||||
|
||||
class Avatar
|
||||
{
|
||||
constructor() {
|
||||
this.aliases = ['av'];
|
||||
this.category = CommandCategory.FUN;
|
||||
this.isAllowedForContext = CommandPermission.yes;
|
||||
this.description = 'Displays the avatar of the specified member.';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Message} message
|
||||
* @param {Array} args
|
||||
*/
|
||||
async process(message, args) {
|
||||
let user = null;
|
||||
|
||||
if (args.length > 0) {
|
||||
const result = Guild.findDesignatedMemberInMessage(message);
|
||||
|
||||
if (result.foundMembers.length > 0) {
|
||||
if (result.foundMembers[0].user !== undefined) {
|
||||
user = result.foundMembers[0].user;
|
||||
} else {
|
||||
user = result.foundMembers[0];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
user = message.author;
|
||||
}
|
||||
|
||||
if (user !== null) {
|
||||
const url = user.displayAvatarURL({ dynamic: true });
|
||||
|
||||
message.channel.send(new Discord.MessageAttachment(
|
||||
url + '?size=2048',
|
||||
user.id + url.substr(url.lastIndexOf('.'))
|
||||
)).catch(error => Logger.warning(error.toString()));
|
||||
} else {
|
||||
message.reply('I... Have no idea who that could be, sorry.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Avatar();
|
||||
75
command/changelog.js
Normal file
75
command/changelog.js
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const Config = require('../config.json');
|
||||
const CommandCategory = require('../model/command-category');
|
||||
const CommandPermission = require('../model/command-permission');
|
||||
const { search } = require('../model/jira');
|
||||
|
||||
const MAX_CHARACTERS = 1950;
|
||||
|
||||
class Changelog
|
||||
{
|
||||
constructor() {
|
||||
this.aliases = ['change-log', 'cl'];
|
||||
this.category = CommandCategory.MODERATION;
|
||||
this.isAllowedForContext = CommandPermission.isMemberMod;
|
||||
this.description = 'Builds the changelog for a given version';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Message} message
|
||||
* @param {Array} args
|
||||
*/
|
||||
async process(message, args) {
|
||||
const errorHandler = async (error) => {
|
||||
if (error) {
|
||||
Logger.exception(error);
|
||||
}
|
||||
|
||||
await message.reactions.removeAll();
|
||||
await message.react('❌');
|
||||
}
|
||||
|
||||
await message.react('⏳').catch(() => {});
|
||||
const issues = args.length > 0 && args[0] ? await search(args[0]).catch(errorHandler) : await search().catch(errorHandler);
|
||||
|
||||
const taskType = Config.jira.issueTypes.task;
|
||||
const bugType = Config.jira.issueTypes.bug;
|
||||
const features = issues.filter(issue => parseInt(issue.fields.issuetype.id) === taskType);
|
||||
const bugs = issues.filter(issue => parseInt(issue.fields.issuetype.id) === bugType);
|
||||
|
||||
if (features.length < 1 && bugs.length < 1) {
|
||||
await message.channel.send('No issues found.');
|
||||
await message.reactions.removeAll().catch(() => {});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const output = `${features.map(
|
||||
issue => `* Feature: ${issue.key} - ${issue.fields.summary}`
|
||||
).join('\n')}\n\n${bugs.map(
|
||||
issue => `* Fixed: ${issue.key} - ${issue.fields.summary}`
|
||||
).join('\n')}`.trim();
|
||||
const messages = [];
|
||||
let currentMessage = '```';
|
||||
|
||||
for (let line of output.split('\n')) {
|
||||
if (currentMessage.length + line.length >= MAX_CHARACTERS) {
|
||||
messages.push(`${currentMessage}\`\`\``);
|
||||
currentMessage = '```';
|
||||
}
|
||||
|
||||
currentMessage = `${currentMessage}\n${line}`;
|
||||
}
|
||||
|
||||
messages.push(`${currentMessage}\`\`\``);
|
||||
|
||||
for (let messageToSend of messages) {
|
||||
await message.channel.send(messageToSend).catch(() => {});
|
||||
}
|
||||
|
||||
await message.reactions.removeAll().catch(() => {});
|
||||
await message.react('✔').catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Changelog();
|
||||
28
command/clean.js
Normal file
28
command/clean.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const Config = require('../config.json');
|
||||
const CommandCategory = require('../model/command-category');
|
||||
const CommandPermission = require('../model/command-permission');
|
||||
|
||||
class Clean
|
||||
{
|
||||
constructor() {
|
||||
this.aliases = ['clear', 'purge'];
|
||||
this.category = CommandCategory.MODERATION;
|
||||
this.isAllowedForContext = CommandPermission.isMemberMod;
|
||||
this.description = 'Deletes messages in a bulk.';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Message} message
|
||||
* @param {Array} args
|
||||
*/
|
||||
async process(message, args) {
|
||||
if (args.length > 0 && parseInt(args[0]) > 0) {
|
||||
await message.channel.bulkDelete(Math.min(parseInt(args[0]) + 1, 100));
|
||||
} else {
|
||||
message.reply(`You have to tell me how many messages I should clean. \`${Config.prefix}clean 10\` for example.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Clean();
|
||||
182
command/embed.js
Normal file
182
command/embed.js
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
const { MessageEmbed, Message } = require('discord.js');
|
||||
const CommandCategory = require('../model/command-category');
|
||||
const CommandPermission = require('../model/command-permission');
|
||||
|
||||
const RGB_REGEX = /(\d{1,3})\D*,\D*(\d{1,3})\D*,\D*(\d{1,3})\D*/u;
|
||||
|
||||
class EmbedDialog
|
||||
{
|
||||
/**
|
||||
* @param {Message} message
|
||||
*/
|
||||
constructor(message) {
|
||||
this.embed = new MessageEmbed();
|
||||
this.message = message;
|
||||
this.channel = message.channel;
|
||||
this.destinationChannel = null;
|
||||
|
||||
this.prompt = (question, hideSkip = false) => {
|
||||
return this.channel.send(`${question}\n*${!hideSkip ? '`skip` to skip, ' : ''}\`cancel\` to cancel*`);
|
||||
};
|
||||
|
||||
this.isMessageSkip = message => message.content.toLowerCase() === 'skip';
|
||||
|
||||
this.messageFilter = testedMessage => {
|
||||
const byAuthor = testedMessage.author.id === message.author.id;
|
||||
const hasContent = testedMessage.cleanContent.trim().length > 0;
|
||||
|
||||
return byAuthor && hasContent;
|
||||
}
|
||||
|
||||
this.channelMessageFilter = testedMessage => {
|
||||
return this.messageFilter(testedMessage)
|
||||
&& (this.isMessageSkip(testedMessage) || testedMessage.mentions.channels.size > 0);
|
||||
}
|
||||
|
||||
this.returnFirstOfCollection = collection => collection && collection.size ? collection.first() : null;
|
||||
this.awaitOptions = { max: 1, time: 5 * MINUTE, errors: ['time'] };
|
||||
|
||||
/**
|
||||
* @param {function} filter
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
this.awaitMessage = (filter = this.messageFilter) => {
|
||||
return this.channel.awaitMessages(
|
||||
filter,
|
||||
this.awaitOptions
|
||||
).then(async collection => {
|
||||
let message = this.returnFirstOfCollection(collection);
|
||||
|
||||
if (message && message.content.toLowerCase() === 'cancel') {
|
||||
message = null;
|
||||
await this.channel.send('Cancelling embed creation.');
|
||||
}
|
||||
|
||||
return message;
|
||||
}).catch(async () => {
|
||||
await this.channel.send('Time out, cancelling embed creation.');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
async execute() {
|
||||
let confirmation = true;
|
||||
|
||||
await this.prompt('#️⃣ In which **channel** would you like this embed to be posted?');
|
||||
const channelMessage = await this.awaitMessage(this.channelMessageFilter);
|
||||
|
||||
if (!channelMessage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.isMessageSkip(channelMessage)) {
|
||||
this.destinationChannel = this.channel;
|
||||
confirmation = false;
|
||||
} else {
|
||||
this.destinationChannel = channelMessage.mentions.channels.first();
|
||||
}
|
||||
|
||||
await this.prompt('📰 What do you want the **title** of this embed to be (you can also ping someone so it appears as they are saying what is going to be the description)?');
|
||||
const titleMessage = await this.awaitMessage(this.messageFilter);
|
||||
|
||||
if (!titleMessage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!this.isMessageSkip(titleMessage)) {
|
||||
if (titleMessage.mentions.members.size > 0) {
|
||||
const member = titleMessage.mentions.members.first();
|
||||
this.embed.setAuthor(member.displayName, member.user.displayAvatarURL({dynamic: true}));
|
||||
} else {
|
||||
this.embed.setTitle(titleMessage.content);
|
||||
}
|
||||
}
|
||||
|
||||
await this.prompt('🎨 What do you want the **colour** of this embed to be?');
|
||||
const colourMessage = await this.awaitMessage(this.messageFilter);
|
||||
|
||||
if (!colourMessage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.isMessageSkip(colourMessage)) {
|
||||
this.embed.setColor(APP_MAIN_COLOUR);
|
||||
} else {
|
||||
if (colourMessage.content.startsWith('#')) {
|
||||
this.embed.setColor(parseInt(colourMessage.content.substr(1), 16));
|
||||
} else if (colourMessage.content.startsWith('0x')) {
|
||||
this.embed.setColor(parseInt(colourMessage.content.substr(2), 16));
|
||||
} else if (RGB_REGEX.test(colourMessage.content)) {
|
||||
const [, red, green, blue] = colourMessage.content.match(RGB_REGEX);
|
||||
this.embed.setColor([parseInt(red), parseInt(green), parseInt(blue)]);
|
||||
} else {
|
||||
this.embed.setColor(colourMessage.content.toUpperCase().replace(/[^A-Z]+/gu, '_'));
|
||||
}
|
||||
}
|
||||
|
||||
await this.prompt('💬 What do you want the **description** (contents) of this embed to be?', true);
|
||||
const descriptionMessage = await this.awaitMessage(this.messageFilter);
|
||||
|
||||
if (!descriptionMessage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.embed.setDescription(descriptionMessage.content);
|
||||
await this.destinationChannel.send(this.embed);
|
||||
|
||||
if (confirmation) {
|
||||
return this.channel.send(`✅ The embed has been posted in ${this.destinationChannel}.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Embed
|
||||
{
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
if (Embed.instance !== null) {
|
||||
return Embed.instance;
|
||||
}
|
||||
|
||||
this.aliases = [];
|
||||
this.category = CommandCategory.MODERATION;
|
||||
this.isAllowedForContext = CommandPermission.isMemberModOrHelper;
|
||||
this.description = 'Allows to post an embed';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Message} message
|
||||
* @param {Array} args
|
||||
*/
|
||||
async process(message, args) {
|
||||
if (args.length > 0) {
|
||||
let destinationChannel = message.channel;
|
||||
let deleteMessage = true;
|
||||
|
||||
if (/<#\d+>/u.test(args[0])) {
|
||||
destinationChannel = message.mentions.channels.first();
|
||||
args.shift();
|
||||
deleteMessage = false;
|
||||
}
|
||||
|
||||
const embed = new MessageEmbed();
|
||||
|
||||
embed.setColor(APP_MAIN_COLOUR);
|
||||
embed.setDescription(args.join(' '));
|
||||
await destinationChannel.send(embed);
|
||||
|
||||
if (deleteMessage) {
|
||||
await message.delete();
|
||||
} else {
|
||||
await message.react('✅');
|
||||
}
|
||||
} else {
|
||||
const dialog = new EmbedDialog(message);
|
||||
|
||||
return dialog.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Embed();
|
||||
49
command/eval.js
Normal file
49
command/eval.js
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
const Discord = require('discord.js');
|
||||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const Config = require('../config.json');
|
||||
const CommandCategory = require('../model/command-category');
|
||||
const CommandPermission = require('../model/command-permission');
|
||||
|
||||
// Including every model here so that it's ready to be used by the command
|
||||
const Guild = require('../model/guild');
|
||||
|
||||
const JAVASCRIPT_LOGO_URL = 'https://i.discord.fr/IEV8.png';
|
||||
|
||||
class Eval
|
||||
{
|
||||
constructor() {
|
||||
this.aliases = [];
|
||||
this.category = CommandCategory.BOT_MANAGEMENT;
|
||||
this.isAllowedForContext = CommandPermission.isMommy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Message} message
|
||||
*/
|
||||
async process(message) {
|
||||
const code = message.content
|
||||
.substr(Config.prefix.length + 'eval'.length)
|
||||
.trim()
|
||||
.replace(/(`{3})js\n(.+)\n\1/iu, '$2')
|
||||
.trim();
|
||||
|
||||
await message.react('✔');
|
||||
Logger.notice('Eval: ' + code);
|
||||
let output = null;
|
||||
|
||||
try {
|
||||
output = eval(`${code}`); // Spoopy! 🎃 🦇 👻 ☠ 🕷
|
||||
} catch (exception) {
|
||||
output = `**${exception.name}: ${exception.message}**\n${exception.stack}`;
|
||||
}
|
||||
|
||||
const embed = new Discord.MessageEmbed()
|
||||
.setAuthor('Eval', JAVASCRIPT_LOGO_URL)
|
||||
.setColor(0x00FF00)
|
||||
.setDescription(output);
|
||||
|
||||
message.channel.send(embed).catch(error => Logger.warning(error.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Eval();
|
||||
139
command/help.js
Normal file
139
command/help.js
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
const CommandPermission = require('../model/command-permission');
|
||||
const CommandCategory = require('../model/command-category');
|
||||
|
||||
const commands = require('../model/command').commandList;
|
||||
const messages = require('../model/messages');
|
||||
|
||||
const cachelessRequire = (path) => {
|
||||
if (!typeof path === 'string') {
|
||||
delete require.cache[require.resolve(path)];
|
||||
}
|
||||
|
||||
return typeof path === 'string' ? require(path) : null;
|
||||
};
|
||||
|
||||
const cleanString = (str) => str === null || str === undefined ? null : str
|
||||
.replace("_", " ")
|
||||
.split(" ")
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
||||
.join(" ");
|
||||
|
||||
const mainPage = (id) => {
|
||||
const buttons = Object.keys(CommandCategory).map(c => ({
|
||||
type: 2,
|
||||
style: 1,
|
||||
label: cleanString(c),
|
||||
custom_id: `help-${id}-${c}`,
|
||||
}))
|
||||
|
||||
return {
|
||||
embeds: [{
|
||||
title: "Help command",
|
||||
color: 0xA95B44,
|
||||
description:
|
||||
'Spot stands for **S**imply **P**lural b**ot**. This bot is mainly used to generate changelogs and help ' +
|
||||
'with the definition of features, so recurring questions can be answered more quickly.\n' +
|
||||
'\n' +
|
||||
'Commands are classified by categories because displaying every command in this small box would be ' +
|
||||
'confusing and would break Discord\'s character limit. Click on a buttom below to show the commands ' +
|
||||
'available in the corresponding category, or type `.help <category name>`.\n'
|
||||
}],
|
||||
components: [{
|
||||
"type": 1,
|
||||
"components": buttons,
|
||||
}]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const categoryPage = (cat, id, direct = false) => {
|
||||
const c = Object.values(CommandCategory).map(x => cleanString(x).toLowerCase());
|
||||
if (!c.includes(cat.toLowerCase()))
|
||||
return;
|
||||
|
||||
let data = {
|
||||
embeds: [{
|
||||
title: `Help command | ${cleanString(cat)}`,
|
||||
color: 0xA95B44,
|
||||
}],
|
||||
components: [{
|
||||
"type": 1,
|
||||
"components": [{
|
||||
type: 2,
|
||||
style: 2,
|
||||
label: "Back",
|
||||
custom_id: `help-${id}-home`,
|
||||
}],
|
||||
}]
|
||||
};
|
||||
|
||||
if (direct) delete data.components;
|
||||
|
||||
if (cat.toLowerCase() == cleanString(CommandCategory.RESOURCE).toLowerCase())
|
||||
data.embeds[0].fields = messages.getList();
|
||||
else
|
||||
data.embeds[0].fields = Array.from(commands.keys()).map(x => {
|
||||
const cmd = cachelessRequire(commands.get(x));
|
||||
if (cleanString(cmd.category)?.toLowerCase() != cat.toLowerCase()) return;
|
||||
return { name: x, value: cmd.description ?? "No description."};
|
||||
}).filter(x => x);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
class Help
|
||||
{
|
||||
constructor() {
|
||||
this.aliases = ['commands'];
|
||||
this.category = CommandCategory.INFO;
|
||||
this.isAllowedForContext = CommandPermission.yes;
|
||||
this.description = 'Provides the list of commands';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Message} message
|
||||
* @param {Array} args
|
||||
* @param {Command} Command
|
||||
*/
|
||||
async process(message, args, command) {
|
||||
if (!args[0])
|
||||
await bot.api.channels(message.channel.id).messages.post({ data: mainPage(message.author.id) });
|
||||
else
|
||||
await bot.api.channels(message.channel.id).messages.post({
|
||||
data:
|
||||
categoryPage(args.join(" "), message.author.id, true)
|
||||
?? {
|
||||
content: "Category not found.",
|
||||
message_reference: { message_id: message.id, guild_id: message.guild?.id },
|
||||
allowed_mentions: { parse: [] },
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Help();
|
||||
|
||||
module.exports.interactionHandler = async (event) => {
|
||||
const user = event.member.user.id;
|
||||
const custom_id = event.data.custom_id;
|
||||
|
||||
let ret;
|
||||
|
||||
if (!custom_id.startsWith(`help-${user}`))
|
||||
ret = {
|
||||
type: 4,
|
||||
data: {
|
||||
flags: 64,
|
||||
content: "This help command was sent by someone else. Please run `.help` again.",
|
||||
},
|
||||
}
|
||||
else if (custom_id.endsWith('home'))
|
||||
ret = { type: 7, data: mainPage(user) };
|
||||
else {
|
||||
let page = categoryPage(cleanString(custom_id.split(`help-${user}-`).join("")), user);
|
||||
if (page) ret = { type: 7, data: page };
|
||||
else ret = { type: 4, data: { flags: 64, content: "Category not found." }}
|
||||
}
|
||||
|
||||
return await bot.api.interactions(event.id, event.token).callback.post({ data: ret })
|
||||
}
|
||||
24
command/kill.js
Normal file
24
command/kill.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const Config = require('../config.json');
|
||||
const CommandCategory = require('../model/command-category');
|
||||
const CommandPermission = require('../model/command-permission');
|
||||
|
||||
class Kill
|
||||
{
|
||||
constructor() {
|
||||
this.aliases = [];
|
||||
this.category = CommandCategory.BOT_MANAGEMENT;
|
||||
this.isAllowedForContext = CommandPermission.isMemberMod;
|
||||
this.description = 'Kills the bot process';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Message} message
|
||||
*/
|
||||
async process(message) {
|
||||
await message.react('✔');
|
||||
Logger.notice('killbotpls');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Kill();
|
||||
23
command/reload.js
Normal file
23
command/reload.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const CommandCategory = require('../model/command-category');
|
||||
const CommandPermission = require('../model/command-permission');
|
||||
|
||||
class Reload
|
||||
{
|
||||
constructor() {
|
||||
this.aliases = ['reboot'];
|
||||
this.category = CommandCategory.BOT_MANAGEMENT;
|
||||
this.isAllowedForContext = CommandPermission.isMemberMod;
|
||||
this.description = 'Reboots the bot';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Message} message
|
||||
*/
|
||||
async process(message) {
|
||||
await message.reply(`OK, I'm rebooting now.`);
|
||||
Logger.notice('Reboot asked');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Reload();
|
||||
28
command/set-avatar.js
Normal file
28
command/set-avatar.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const CommandCategory = require('../model/command-category');
|
||||
const CommandPermission = require('../model/command-permission');
|
||||
|
||||
class SetAvatar
|
||||
{
|
||||
constructor() {
|
||||
this.aliases = ['setavatar'];
|
||||
this.category = CommandCategory.BOT_MANAGEMENT;
|
||||
this.isAllowedForContext = CommandPermission.isMemberMod;
|
||||
this.description = 'Set the bot avatar';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Message} message
|
||||
* @param {Array} args
|
||||
*/
|
||||
async process(message, args) {
|
||||
bot.user.setAvatar(args.join(' ')).then(() => {
|
||||
message.reply('my avatar has been changed!')
|
||||
}).catch((error) => {
|
||||
message.reply('there has been an error changing my avatar. Check the logs for more details.');
|
||||
Logger.exception(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new SetAvatar();
|
||||
Loading…
Add table
Add a link
Reference in a new issue