This commit is contained in:
Isaac
2021-05-22 00:04:18 +01:00
parent 777719d1b3
commit 32f43ac18f
58 changed files with 837 additions and 926 deletions

View File

@@ -1,12 +1,14 @@
// eslint-disable-next-line no-unused-vars
const { MessageEmbed, Message } = require('discord.js');
const {
Message, // eslint-disable-line no-unused-vars
MessageEmbed
} = require('discord.js');
/**
* A command
*/
module.exports = class Command {
/**
*
*
* @typedef CommandArgument
* @property {string} name - The argument's name
* @property {string} description - The argument's description
@@ -37,7 +39,7 @@ module.exports = class Command {
}
/**
* The name of the command
* The name of the command
* @type {string}
*/
this.name = data.name;
@@ -53,7 +55,7 @@ module.exports = class Command {
/**
* The command description
* @type {string}
*/
*/
this.description = data.description;
/**
@@ -61,12 +63,12 @@ module.exports = class Command {
* @type {boolean}
* @default false
*/
this.staff_only = data.staff_only === true ? true : false;
this.staff_only = data.staff_only === true;
/**
* Array of permissions needed for a user to use this command
* @type {string[]}
*/
*/
this.permissions = data.permissions ?? [];
/**
@@ -74,9 +76,9 @@ module.exports = class Command {
* @type {boolean}
* @default false
*/
this.process_args = data.process_args === true ? true : false;
this.process_args = data.process_args === true;
/**
/**
* The command options
* @type {CommandArgument[]}
*/
@@ -86,7 +88,7 @@ module.exports = class Command {
* True if command is internal, false if it is from a plugin
* @type {boolean}
*/
this.internal = data.internal === true ? true : false;
this.internal = data.internal === true;
if (!this.internal) {
/**
@@ -155,7 +157,7 @@ module.exports = class Command {
this.args.forEach(arg => addArgs(embed, arg));
return await channel.send(embed);
}
};

View File

@@ -1,5 +1,10 @@
// eslint-disable-next-line no-unused-vars
const { Collection, Client, Message, MessageEmbed } = require('discord.js');
const {
Client, // eslint-disable-line no-unused-vars
Collection,
Message, // eslint-disable-line no-unused-vars
MessageEmbed
} = require('discord.js');
const fs = require('fs');
const { path } = require('../../utils/fs');
@@ -13,7 +18,7 @@ const parseArgs = require('command-line-args');
module.exports = class CommandManager {
/**
* Create a CommandManager instance
* @param {import('../..').Bot} client
* @param {import('../..').Bot} client
*/
constructor(client) {
/** The Discord Client */
@@ -49,15 +54,13 @@ module.exports = class CommandManager {
if (is_internal) {
const plugin = this.client.plugins.plugins.find(p => p.commands.includes(cmd.name));
if (plugin)
this.client.log.commands(`The "${plugin.name}" plugin has overridden the internal "${cmd.name}" command`);
else
this.client.log.commands(`An unknown plugin has overridden the internal "${cmd.name}" command`);
if (plugin) this.client.log.commands(`The "${plugin.name}" plugin has overridden the internal "${cmd.name}" command`);
else this.client.log.commands(`An unknown plugin has overridden the internal "${cmd.name}" command`);
if(cmd.internal) return;
}
else if (exists)
} else if (exists) {
throw new Error(`A non-internal command with the name "${cmd.name}" already exists`);
}
this.commands.set(cmd.name, cmd);
this.client.log.commands(`Loaded "${cmd.name}" command`);
}
@@ -114,7 +117,7 @@ module.exports = class CommandManager {
'MANAGE_CHANNELS',
'MANAGE_MESSAGES',
'READ_MESSAGE_HISTORY',
'SEND_MESSAGES',
'SEND_MESSAGES'
];
if (!bot_permissions.has(required_bot_permissions)) {
@@ -182,10 +185,10 @@ module.exports = class CommandManager {
return await cmd.sendUsage(message.channel, cmd_name);
}
}
try {
this.client.log.commands(`Executing "${cmd.name}" command (invoked by ${message.author.tag})`);
await cmd.execute(message, args); // execute the command
await cmd.execute(message, args); // execute the command
} catch (e) {
this.client.log.warn(`An error occurred whilst executing the ${cmd.name} command`);
this.client.log.error(e);

View File

@@ -1,9 +1,9 @@
module.exports = class EventListener {
/**
*
* @param {import("../..").Bot} client
* @param {*} data
*
* @param {import("../..").Bot} client
* @param {*} data
*/
constructor(client, data) {
this.client = client;

View File

@@ -7,7 +7,7 @@ const { path } = require('../../utils/fs');
module.exports = class ListenerLoader {
/**
* Create a ListenerLoader instance
* @param {import('../..').Bot} client
* @param {import('../..').Bot} client
*/
constructor(client) {
/** The Discord Client */
@@ -23,10 +23,8 @@ module.exports = class ListenerLoader {
file = require(`../../listeners/${file}`);
const listener = new file(this.client);
const on = listener.once ? 'once' : 'on';
if (listener.raw)
this.client.ws[on](listener.event, (...data) => listener.execute(...data));
else
this.client[on](listener.event, (...data) => listener.execute(...data));
if (listener.raw) this.client.ws[on](listener.event, (...data) => listener.execute(...data));
else this.client[on](listener.event, (...data) => listener.execute(...data));
} catch (e) {
this.client.log.warn('An error occurred whilst loading a listener');
this.client.log.error(e);

View File

@@ -9,12 +9,12 @@ const Plugin = require('./plugin');
module.exports = class PluginManager {
/**
* Create a PluginManager instance
* @param {import('../..').Bot} client
* @param {import('../..').Bot} client
*/
constructor(client) {
/** The Discord Client */
this.client = client;
/**
* A discord.js Collection (Map) of loaded plugins
* @type {Collection<string, import('./plugin')>}
@@ -29,8 +29,7 @@ module.exports = class PluginManager {
}
handleError(id) {
if (!this.official.includes(id))
this.client.log.notice(`"${id}" is NOT an official plugin, please do not ask for help with it in the Discord Tickets support server, seek help from the plugin author instead.`);
if (!this.official.includes(id)) this.client.log.notice(`"${id}" is NOT an official plugin, please do not ask for help with it in the Discord Tickets support server, seek help from the plugin author instead.`);
}
/**
@@ -56,17 +55,17 @@ module.exports = class PluginManager {
}
const about = {
id,
version,
author,
description
description,
id,
version
};
try {
plugin = new (plugin(Plugin))(this.client, about);
this.plugins.set(id, plugin);
this.client.log.plugins(`Loading "${plugin.name}" v${version} by ${author}`);
plugin.preload();
plugin.preload();
} catch (e) {
this.handleError(id);
this.client.log.warn(`An error occurred whilst loading the "${id}" plugin`);

View File

@@ -40,31 +40,31 @@ module.exports = class Plugin {
*/
this.name = options.name ?? id;
/**
/**
* An array of commands from this plugin
* @type {string[]}
*/
this.commands = options.commands;
/**
/**
* The unique ID of the plugin (NPM package name)
* @type {string}
*/
this.id = id;
/**
/**
* The version of the plugin (NPM package version)
* @type {string}
*/
this.version = version;
/**
/**
* The plugin author's name (NPM package author)
* @type {(undefined|string)}
*/
this.author = author;
/**
/**
* The plugin description (NPM package description)
* @type {string}
*/

View File

@@ -5,6 +5,5 @@ module.exports = () => {
const files = fs.readdirSync(path('./src/structures'))
.filter(file => file.endsWith('.js'));
for (const file of files)
require(`../structures/${file}`);
for (const file of files) require(`../structures/${file}`);
};

View File

@@ -20,26 +20,22 @@ module.exports = class TicketArchives {
try {
// await this.client.db.transaction(async t => {
const t_row = await this.client.db.models.Ticket.findOne({
where: {
id: message.channel.id
},
where: { id: message.channel.id }
/* transaction: t */
});
if (t_row) {
await this.client.db.models.Message.create({
id: message.id,
ticket: t_row.id,
author: message.author.id,
createdAt: new Date(message.createdTimestamp),
data: this.encrypt(JSON.stringify({
attachments: [...message.attachments.values()],
content: message.content,
embeds: message.embeds.map(embed => {
return { embed };
}),
attachments: [...message.attachments.values()]
embeds: message.embeds.map(embed => ({ embed }))
})),
createdAt: new Date(message.createdTimestamp)
}, /* { transaction: t } */);
id: message.id,
ticket: t_row.id
} /* { transaction: t } */);
await this.updateEntities(message);
}
@@ -54,19 +50,15 @@ module.exports = class TicketArchives {
try {
// await this.client.db.transaction(async t => {
const m_row = await this.client.db.models.Message.findOne({
where: {
id: message.id
},
where: { id: message.id }
/* transaction: t */
});
if (m_row) {
m_row.data = this.encrypt(JSON.stringify({
attachments: [...message.attachments.values()],
content: message.content,
embeds: message.embeds.map(embed => {
return { embed };
}),
attachments: [...message.attachments.values()]
embeds: message.embeds.map(embed => ({ embed }))
}));
if (message.editedTimestamp) {
@@ -87,9 +79,7 @@ module.exports = class TicketArchives {
try {
// await this.client.db.transaction(async t => {
const msg = await this.client.db.models.Message.findOne({
where: {
id: message.id
},
where: { id: message.id }
/* transaction: t */
});
@@ -130,27 +120,27 @@ module.exports = class TicketArchives {
try {
// await this.client.db.transaction(async t => {
const u_model_data = {
user: member.user.id,
ticket: ticket_id
ticket: ticket_id,
user: member.user.id
};
const [u_row] = await this.client.db.models.UserEntity.findOrCreate({
where: u_model_data,
defaults: {
...u_model_data,
role: member.roles.highest.id
},
where: u_model_data
/* transaction: t */
});
await u_row.update({
avatar: member.user.avatar,
username: this.encrypt(member.user.username),
bot: member.user.bot,
discriminator: member.user.discriminator,
display_name: this.encrypt(member.displayName),
role: member.roles.highest.id,
bot: member.user.bot
}, /* { transaction: t } */);
username: this.encrypt(member.user.username)
} /* { transaction: t } */);
return u_row;
// });
@@ -168,14 +158,12 @@ module.exports = class TicketArchives {
ticket: ticket_id
};
const [c_row] = await this.client.db.models.ChannelEntity.findOrCreate({
where: c_model_data,
defaults: c_model_data,
where: c_model_data
/* transaction: t */
});
await c_row.update({
name: this.encrypt(channel.name)
}, /* { transaction: t } */);
await c_row.update({ name: this.encrypt(channel.name) } /* { transaction: t } */);
return c_row;
// });
@@ -193,15 +181,15 @@ module.exports = class TicketArchives {
ticket: ticket_id
};
const [r_row] = await this.client.db.models.RoleEntity.findOrCreate({
where: r_model_data,
defaults: r_model_data,
where: r_model_data
/* transaction: t */
});
await r_row.update({
name: this.encrypt(role.name),
colour: role.color === 0 ? '7289DA' : int2hex(role.color) // 7289DA = 7506394
}, /* { transaction: t } */);
colour: role.color === 0 ? '7289DA' : int2hex(role.color), // 7289DA = 7506394
name: this.encrypt(role.name)
} /* { transaction: t } */);
return r_row;
// });

View File

@@ -1,3 +1,4 @@
/* eslint-disable max-lines */
const EventEmitter = require('events');
const TicketArchives = require('./archives');
const { MessageEmbed } = require('discord.js');
@@ -25,30 +26,20 @@ module.exports = class TicketManager extends EventEmitter {
* @param {string} guild_id - ID of the guild to create the ticket in
* @param {string} creator_id - ID of the ticket creator (user)
* @param {string} category_id - ID of the ticket category
* @param {string} [topic] - The ticket topic
* @param {string} [topic] - The ticket topic
*/
async create(guild_id, creator_id, category_id, topic) {
if (!topic) topic = '';
const cat_row = await this.client.db.models.Category.findOne({
where: {
id: category_id
}
});
const cat_row = await this.client.db.models.Category.findOne({ where: { id: category_id } });
if (!cat_row) throw new Error('Ticket category does not exist');
if (!cat_row)
throw new Error('Ticket category does not exist');
const cat_channel = await this.client.channels.fetch(category_id);
if (cat_channel.children.size >= 50)
throw new Error('Ticket category has reached child channel limit (50)');
if (cat_channel.children.size >= 50) throw new Error('Ticket category has reached child channel limit (50)');
const number = (await this.client.db.models.Ticket.count({
where: {
guild: guild_id
}
})) + 1;
const number = (await this.client.db.models.Ticket.count({ where: { guild: guild_id } })) + 1;
const guild = this.client.guilds.cache.get(guild_id);
const creator = await guild.members.fetch(creator_id);
@@ -57,25 +48,25 @@ module.exports = class TicketManager extends EventEmitter {
.replace(/{+\s?num(ber)?\s?}+/gi, number);
const t_channel = await guild.channels.create(name, {
type: 'text',
topic: `${creator}${topic.length > 0 ? ` | ${topic}` : ''}`,
parent: category_id,
reason: `${creator.user.tag} requested a new ticket channel`
reason: `${creator.user.tag} requested a new ticket channel`,
topic: `${creator}${topic.length > 0 ? ` | ${topic}` : ''}`,
type: 'text'
});
t_channel.updateOverwrite(creator_id, {
VIEW_CHANNEL: true,
ATTACH_FILES: true,
READ_MESSAGE_HISTORY: true,
SEND_MESSAGES: true,
ATTACH_FILES: true
VIEW_CHANNEL: true
}, `Ticket channel created by ${creator.user.tag}`);
const t_row = await this.client.db.models.Ticket.create({
id: t_channel.id,
number,
guild: guild_id,
category: category_id,
creator: creator_id,
guild: guild_id,
id: t_channel.id,
number,
topic: topic.length === 0 ? null : this.client.cryptr.encrypt(topic)
});
@@ -115,9 +106,7 @@ module.exports = class TicketManager extends EventEmitter {
const sent = await t_channel.send(creator.user.toString(), embed);
await sent.pin({ reason: 'Ticket opening message' });
await t_row.update({
opening_message: sent.id
});
await t_row.update({ opening_message: sent.id });
const pinned = t_channel.messages.cache.last();
@@ -147,17 +136,13 @@ module.exports = class TicketManager extends EventEmitter {
.setFooter(footer(settings.footer, i18n('collector_expires_in', 120)), guild.iconURL())
);
const collector_filter = (message) => message.author.id === t_row.creator;
const collector_filter = message => message.author.id === t_row.creator;
const collector = t_channel.createMessageCollector(collector_filter, {
time: 120000
});
const collector = t_channel.createMessageCollector(collector_filter, { time: 120000 });
collector.on('collect', async (message) => {
collector.on('collect', async message => {
topic = message.content;
await t_row.update({
topic: this.client.cryptr.encrypt(topic)
});
await t_row.update({ topic: this.client.cryptr.encrypt(topic) });
await t_channel.setTopic(`${creator} | ${topic}`, { reason: 'User updated ticket topic' });
await sent.edit(
new MessageEmbed()
@@ -225,9 +210,9 @@ module.exports = class TicketManager extends EventEmitter {
const close = async () => {
const pinned = await channel.messages.fetchPinned();
await t_row.update({
open: false,
closed_by: closer_id || null,
closed_reason: reason ? this.client.cryptr.encrypt(reason) : null,
open: false,
pinned_messages: [...pinned.keys()]
});
@@ -276,11 +261,7 @@ module.exports = class TicketManager extends EventEmitter {
if (channel) {
const creator = await guild.members.fetch(t_row.creator);
const cat_row = await this.client.db.models.Category.findOne({
where: {
id: t_row.category
}
});
const cat_row = await this.client.db.models.Category.findOne({ where: { id: t_row.category } });
if (creator && cat_row.survey) {
const survey = await this.client.db.models.Survey.findOne({
@@ -302,13 +283,9 @@ module.exports = class TicketManager extends EventEmitter {
await r_collector_message.react('✅');
const collector_filter = (reaction, user) => {
return user.id === creator.user.id && reaction.emoji.name === '✅';
};
const collector_filter = (reaction, user) => user.id === creator.user.id && reaction.emoji.name === '✅';
const r_collector = r_collector_message.createReactionCollector(collector_filter, {
time: 60000
});
const r_collector = r_collector_message.createReactionCollector(collector_filter, { time: 60000 });
r_collector.on('collect', async () => {
r_collector.stop();
@@ -325,7 +302,11 @@ module.exports = class TicketManager extends EventEmitter {
);
try {
const collected = await channel.awaitMessages(filter, { max: 1, time: 60000, errors: ['time'] });
const collected = await channel.awaitMessages(filter, {
errors: ['time'],
max: 1,
time: 60000
});
answers.push(collected.first().content);
} catch (collected) {
return await close();
@@ -351,7 +332,7 @@ module.exports = class TicketManager extends EventEmitter {
});
r_collector.on('end', async (collected) => {
r_collector.on('end', async collected => {
if (collected.size === 0) {
await close();
}
@@ -367,7 +348,7 @@ module.exports = class TicketManager extends EventEmitter {
}
/**
*
*
* @param {(string|number)} ticket_id - ID or number of the ticket
* @param {string} [guild_id] - The ID of the ticket's guild (used if a ticket number is provided instead of ID)
*/
@@ -375,16 +356,12 @@ module.exports = class TicketManager extends EventEmitter {
let t_row;
if (this.client.channels.resolve(ticket_id)) {
t_row = await this.client.db.models.Ticket.findOne({
where: {
id: ticket_id
}
});
t_row = await this.client.db.models.Ticket.findOne({ where: { id: ticket_id } });
} else {
t_row = await this.client.db.models.Ticket.findOne({
where: {
number: ticket_id,
guild: guild_id
guild: guild_id,
number: ticket_id
}
});
}