mirror of
https://github.com/DarthKilroy/Spot.git
synced 2025-12-19 18:26:48 +00:00
Initial commit
This commit is contained in:
commit
8ae81f1cc6
24 changed files with 1425 additions and 0 deletions
56
model/command/avatar.js
Normal file
56
model/command/avatar.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const Discord = require('discord.js');
|
||||
const CommandCategory = require('../command-category');
|
||||
const CommandPermission = require('../command-permission');
|
||||
const Guild = require('../guild');
|
||||
|
||||
class Avatar
|
||||
{
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
if (Avatar.instance !== null) {
|
||||
return Avatar.instance;
|
||||
}
|
||||
|
||||
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();
|
||||
81
model/command/changelog.js
Normal file
81
model/command/changelog.js
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const Config = require('../../config.json');
|
||||
const CommandCategory = require('../command-category');
|
||||
const CommandPermission = require('../command-permission');
|
||||
const { search } = require('../jira');
|
||||
|
||||
const MAX_CHARACTERS = 1950;
|
||||
|
||||
class Changelog
|
||||
{
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
if (Changelog.instance !== null) {
|
||||
return Changelog.instance;
|
||||
}
|
||||
|
||||
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();
|
||||
34
model/command/clean.js
Normal file
34
model/command/clean.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const Config = require('../../config.json');
|
||||
const CommandCategory = require('../command-category');
|
||||
const CommandPermission = require('../command-permission');
|
||||
|
||||
class Clean
|
||||
{
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
if (Clean.instance !== null) {
|
||||
return Clean.instance;
|
||||
}
|
||||
|
||||
this.aliases = ['clear', 'purge'];
|
||||
this.category = CommandCategory.MODERATION;
|
||||
this.isAllowedForContext = CommandPermission.isMemberMod;
|
||||
this.description = 'Kills the bot process';
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
42
model/command/custom-front.js
Normal file
42
model/command/custom-front.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
const { MessageEmbed } = require('discord.js');
|
||||
const CommandCategory = require('../command-category');
|
||||
const CommandPermission = require('../command-permission');
|
||||
|
||||
class CustomFront
|
||||
{
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
if (CustomFront.instance !== null) {
|
||||
return CustomFront.instance;
|
||||
}
|
||||
|
||||
this.aliases = ['custom-fronts', 'customfronts', 'customfront', 'cf'];
|
||||
this.category = CommandCategory.FUN;
|
||||
this.isAllowedForContext = CommandPermission.yes;
|
||||
this.description = 'Explains what "custom front" is.';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Message} message
|
||||
* @param {Array} args
|
||||
*/
|
||||
async process(message, args) {
|
||||
const embed = new MessageEmbed();
|
||||
|
||||
embed.setColor(APP_MAIN_COLOUR);
|
||||
embed.setAuthor('Custom fronts', bot.user.displayAvatarURL({ dynamic: true }));
|
||||
embed.setDescription(
|
||||
'Custom fronts is a kind of status for fronts, like "blurred", "unknown member", "dissociated", etc... \n' +
|
||||
'\n' +
|
||||
'You don\'t want those to show up as real members in your system list but you still want to be able to ' +
|
||||
'set front as one of them — that\'s where custom fronts kick in.\n' +
|
||||
'\n' +
|
||||
'They\'re highly customizable (as per popular request) so you can name them anything you want.'
|
||||
);
|
||||
|
||||
return message.channel.send(embed);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new CustomFront();
|
||||
55
model/command/eval.js
Normal file
55
model/command/eval.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
const Discord = require('discord.js');
|
||||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const Config = require('../../config.json');
|
||||
const CommandCategory = require('../command-category');
|
||||
const CommandPermission = require('../command-permission');
|
||||
|
||||
// Including every model here so that it's ready to be used by the command
|
||||
const Guild = require('../guild');
|
||||
|
||||
const JAVASCRIPT_LOGO_URL = 'https://i.discord.fr/IEV8.png';
|
||||
|
||||
class Eval
|
||||
{
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
if (Eval.instance !== null) {
|
||||
return Eval.instance;
|
||||
}
|
||||
|
||||
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();
|
||||
179
model/command/help.js
Normal file
179
model/command/help.js
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
const Discord = require('discord.js');
|
||||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const Config = require('../../config.json');
|
||||
const EmojiCharacters = require('../../emoji-characters.json');
|
||||
const Guild = require('../guild');
|
||||
const CommandCategory = require('../command-category');
|
||||
const CommandPermission = require('../command-permission');
|
||||
|
||||
const cachelessRequire = (path) => {
|
||||
if (typeof path === 'string') {
|
||||
delete require.cache[require.resolve(path)];
|
||||
}
|
||||
|
||||
return typeof path === 'string' ? require(path) : null;
|
||||
};
|
||||
|
||||
class HelpDialog
|
||||
{
|
||||
/**
|
||||
* @param {Message} message
|
||||
*/
|
||||
constructor(message) {
|
||||
this.categoriesMapping = new Discord.Collection();
|
||||
this.categoriesEmbed = new Discord.MessageEmbed();
|
||||
this.originalMessage = message;
|
||||
this.categoryCommandMapping = new Discord.Collection();
|
||||
this.postedMessage = null;
|
||||
this.usedEmojis = [];
|
||||
this.stopAddingReactions = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Command} Command
|
||||
*/
|
||||
async init(Command) {
|
||||
const callableCommands = new Discord.Collection();
|
||||
const commandList = Command.commandList.keyArray();
|
||||
|
||||
for (let i = 0; i < commandList.length; i++) {
|
||||
const commandName = commandList[i];
|
||||
const command = cachelessRequire(`../${Command.commandList.get(commandName)}`);
|
||||
const isAllowed = await command.isAllowedForContext(this.originalMessage);
|
||||
|
||||
if (isAllowed) {
|
||||
callableCommands.set(commandName, command);
|
||||
}
|
||||
}
|
||||
|
||||
callableCommands.forEach((command, commandName) => {
|
||||
if (!this.categoryCommandMapping.has(command.category)) {
|
||||
this.categoryCommandMapping.set(command.category, new Discord.Collection());
|
||||
}
|
||||
|
||||
this.categoryCommandMapping.get(command.category).set(commandName, command);
|
||||
});
|
||||
|
||||
let i = 1;
|
||||
|
||||
const categories = callableCommands.reduce((accumulator, command) => {
|
||||
if (!this.categoriesMapping.array().includes(command.category)) {
|
||||
let commandCategory = command.category.replace('_', ' ');
|
||||
commandCategory = `${commandCategory.slice(0, 1).toUpperCase()}${commandCategory.slice(1)}`;
|
||||
|
||||
this.categoriesMapping.set(EmojiCharacters[i], command.category);
|
||||
this.usedEmojis.push(EmojiCharacters[i]);
|
||||
accumulator += `${EmojiCharacters[i]} ${commandCategory}\n`;
|
||||
i++;
|
||||
}
|
||||
|
||||
return accumulator;
|
||||
}, '');
|
||||
|
||||
this.categoriesEmbed.setTitle('Help command');
|
||||
this.categoriesEmbed.setDescription(categories);
|
||||
|
||||
return this.listCategories();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Collection<Snowflake, MessageReaction>} [collection]
|
||||
*/
|
||||
async listCategories(collection) {
|
||||
this.stopAddingReactions = true;
|
||||
|
||||
if (collection !== undefined && collection.size < 1) {
|
||||
await this.postedMessage.reactions.removeAll();
|
||||
return;
|
||||
}
|
||||
|
||||
const member = await Guild.getMemberFromMessage(this.originalMessage);
|
||||
const filter = (reaction, user) => {
|
||||
const emoji = reaction.emoji.name;
|
||||
|
||||
return this.usedEmojis.includes(emoji) && user.id === member.user.id;
|
||||
};
|
||||
|
||||
if (this.postedMessage === null) {
|
||||
this.postedMessage = await this.originalMessage.channel.send(this.categoriesEmbed).catch(error => Logger.warning(error.toString()));
|
||||
} else {
|
||||
await this.postedMessage.reactions.removeAll();
|
||||
await this.postedMessage.edit('', this.categoriesEmbed);
|
||||
}
|
||||
|
||||
// 5 minutes
|
||||
this.postedMessage.awaitReactions(filter, { time: 300000, max: 1 }).then(this.listCommands.bind(this)).catch(Logger.exception);
|
||||
this.stopAddingReactions = false;
|
||||
|
||||
for (let i = 0; i < this.usedEmojis.length && !this.stopAddingReactions; i++) {
|
||||
await this.postedMessage.react(this.usedEmojis[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Collection<Snowflake, MessageReaction>} collection
|
||||
*/
|
||||
async listCommands(collection) {
|
||||
this.stopAddingReactions = true;
|
||||
await this.postedMessage.reactions.removeAll();
|
||||
|
||||
if (collection.size < 1) {
|
||||
this.postedMessage.edit('Timed out! You may send the command again.');
|
||||
return;
|
||||
}
|
||||
|
||||
const member = await Guild.getMemberFromMessage(this.originalMessage);
|
||||
const filter = (reaction, user) => {
|
||||
const emoji = reaction.emoji.name;
|
||||
|
||||
return emoji === '↩️' && user.id === member.user.id;
|
||||
};
|
||||
|
||||
const category = this.categoriesMapping.get(collection.first().emoji.name);
|
||||
const commandsEmbed = new Discord.MessageEmbed();
|
||||
const commands = this.categoryCommandMapping.get(category).reduce((accumulator, command, commandName) => {
|
||||
accumulator += `**${Config.prefix}${commandName}** ${command.description}\n\n`;
|
||||
|
||||
return accumulator;
|
||||
}, '');
|
||||
|
||||
commandsEmbed.setTitle('Help command');
|
||||
commandsEmbed.setDescription(commands);
|
||||
|
||||
this.postedMessage.edit('', commandsEmbed);
|
||||
|
||||
// 5 minutes
|
||||
this.postedMessage.awaitReactions(filter, { time: 300000, max: 1 }).then(this.listCategories.bind(this)).catch(Logger.exception);
|
||||
|
||||
await this.postedMessage.react('↩️');
|
||||
}
|
||||
}
|
||||
|
||||
class Help
|
||||
{
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
if (Help.instance !== null) {
|
||||
return Help.instance;
|
||||
}
|
||||
|
||||
this.aliases = [];
|
||||
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) {
|
||||
const dialog = new HelpDialog(message);
|
||||
|
||||
return dialog.init(Command);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Help();
|
||||
30
model/command/kill.js
Normal file
30
model/command/kill.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const Config = require('../../config.json');
|
||||
const CommandCategory = require('../command-category');
|
||||
const CommandPermission = require('../command-permission');
|
||||
|
||||
class Kill
|
||||
{
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
if (Kill.instance !== null) {
|
||||
return Kill.instance;
|
||||
}
|
||||
|
||||
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();
|
||||
29
model/command/reload.js
Normal file
29
model/command/reload.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const CommandCategory = require('../command-category');
|
||||
const CommandPermission = require('../command-permission');
|
||||
|
||||
class Reload
|
||||
{
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
if (Reload.instance !== null) {
|
||||
return Reload.instance;
|
||||
}
|
||||
|
||||
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();
|
||||
34
model/command/set-avatar.js
Normal file
34
model/command/set-avatar.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
const Logger = require('@lilywonhalf/pretty-logger');
|
||||
const CommandCategory = require('../command-category');
|
||||
const CommandPermission = require('../command-permission');
|
||||
|
||||
class SetAvatar
|
||||
{
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
if (SetAvatar.instance !== null) {
|
||||
return SetAvatar.instance;
|
||||
}
|
||||
|
||||
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