Reset for new version

This commit is contained in:
Isaac
2022-03-11 21:09:17 +00:00
parent aa50daa3a7
commit 83e7ff6019
85 changed files with 0 additions and 18792 deletions

View File

@@ -1,118 +0,0 @@
const Command = require('../modules/commands/command');
const {
Interaction, // eslint-disable-line no-unused-vars
MessageEmbed
} = require('discord.js');
module.exports = class AddCommand extends Command {
constructor(client) {
const i18n = client.i18n.getLocale(client.config.locale);
super(client, {
description: i18n('commands.add.description'),
internal: true,
name: i18n('commands.add.name'),
options: [
{
description: i18n('commands.add.options.member.description'),
name: i18n('commands.add.options.member.name'),
required: true,
type: Command.option_types.USER
},
{
description: i18n('commands.add.options.ticket.description'),
name: i18n('commands.add.options.ticket.name'),
required: false,
type: Command.option_types.CHANNEL
}
]
});
}
/**
* @param {Interaction} interaction
* @returns {Promise<void|any>}
*/
async execute(interaction) {
const settings = await this.client.utils.getSettings(interaction.guild.id);
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
const i18n = this.client.i18n.getLocale(settings.locale);
const channel = interaction.options.getChannel(default_i18n('commands.add.options.ticket.name')) ?? interaction.channel;
const t_row = await this.client.tickets.resolve(channel.id, interaction.guild.id);
if (!t_row) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.add.response.not_a_ticket.title'))
.setDescription(i18n('commands.add.response.not_a_ticket.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
const member = interaction.options.getMember(default_i18n('commands.add.options.member.name'));
if (!member) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.add.response.no_member.title'))
.setDescription(i18n('commands.add.response.no_member.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
if (t_row.creator !== interaction.member.id && !await this.client.utils.isStaff(interaction.member)) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.add.response.no_permission.title'))
.setDescription(i18n('commands.add.response.no_permission.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.success_colour)
.setAuthor(member.user.username, member.user.displayAvatarURL())
.setTitle(i18n('commands.add.response.added.title'))
.setDescription(i18n('commands.add.response.added.description', member.toString(), channel.toString()))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
await channel.send({
embeds: [
new MessageEmbed()
.setColor(settings.colour)
.setAuthor(member.user.username, member.user.displayAvatarURL())
.setTitle(i18n('ticket.member_added.title'))
.setDescription(i18n('ticket.member_added.description', member.toString(), interaction.user.toString()))
.setFooter(settings.footer, interaction.guild.iconURL())
]
});
await channel.permissionOverwrites.edit(member, {
ATTACH_FILES: true,
READ_MESSAGE_HISTORY: true,
SEND_MESSAGES: true,
VIEW_CHANNEL: true
}, `${interaction.user.tag} added ${member.user.tag} to the ticket`);
await this.client.tickets.archives.updateMember(channel.id, member);
this.client.log.info(`${interaction.user.tag} added ${member.user.tag} to ${channel.id}`);
}
};

View File

@@ -1,156 +0,0 @@
const Command = require('../modules/commands/command');
const {
Interaction, // eslint-disable-line no-unused-vars
MessageEmbed,
Role
} = require('discord.js');
module.exports = class BlacklistCommand extends Command {
constructor(client) {
const i18n = client.i18n.getLocale(client.config.locale);
super(client, {
description: i18n('commands.blacklist.description'),
internal: true,
name: i18n('commands.blacklist.name'),
options: [
{
description: i18n('commands.blacklist.options.add.description'),
name: i18n('commands.blacklist.options.add.name'),
options: [
{
description: i18n('commands.blacklist.options.add.options.member_or_role.description'),
name: i18n('commands.blacklist.options.add.options.member_or_role.name'),
required: true,
type: Command.option_types.MENTIONABLE
}
],
type: Command.option_types.SUB_COMMAND
},
{
description: i18n('commands.blacklist.options.remove.description'),
name: i18n('commands.blacklist.options.remove.name'),
options: [
{
description: i18n('commands.blacklist.options.remove.options.member_or_role.description'),
name: i18n('commands.blacklist.options.remove.options.member_or_role.name'),
required: true,
type: Command.option_types.MENTIONABLE
}
],
type: Command.option_types.SUB_COMMAND
},
{
description: i18n('commands.blacklist.options.show.description'),
name: i18n('commands.blacklist.options.show.name'),
type: Command.option_types.SUB_COMMAND
}
],
staff_only: true
});
}
/**
* @param {Interaction} interaction
* @returns {Promise<void|any>}
*/
async execute(interaction) {
const settings = await this.client.utils.getSettings(interaction.guild.id);
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
const i18n = this.client.i18n.getLocale(settings.locale);
const blacklist = JSON.parse(JSON.stringify(settings.blacklist)); // not the same as `const blacklist = { ...settings.blacklist };` ..?
switch (interaction.options.getSubcommand()) {
case default_i18n('commands.blacklist.options.add.name'): {
const member_or_role = interaction.options.getMentionable(default_i18n('commands.blacklist.options.add.options.member_or_role.name'));
const type = member_or_role instanceof Role ? 'role' : 'member';
if (type === 'member' && await this.client.utils.isStaff(member_or_role)) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.blacklist.response.illegal_action.title'))
.setDescription(i18n('commands.blacklist.response.illegal_action.description', member_or_role.toString()))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
blacklist[type + 's'].push(member_or_role.id);
await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.success_colour)
.setTitle(i18n(`commands.blacklist.response.${type}_added.title`))
.setDescription(i18n(`commands.blacklist.response.${type}_added.description`, member_or_role.id))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
await settings.update({ blacklist });
break;
}
case default_i18n('commands.blacklist.options.remove.name'): {
const member_or_role = interaction.options.getMentionable(default_i18n('commands.blacklist.options.remove.options.member_or_role.name'));
const type = member_or_role instanceof Role ? 'role' : 'member';
const index = blacklist[type + 's'].findIndex(element => element === member_or_role.id);
if (index === -1) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.blacklist.response.invalid.title'))
.setDescription(i18n('commands.blacklist.response.invalid.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
blacklist[type + 's'].splice(index, 1);
await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.success_colour)
.setTitle(i18n(`commands.blacklist.response.${type}_removed.title`))
.setDescription(i18n(`commands.blacklist.response.${type}_removed.description`, member_or_role.id))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
await settings.update({ blacklist });
break;
}
case default_i18n('commands.blacklist.options.show.name'): {
if (blacklist.members.length === 0 && blacklist.roles.length === 0) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.colour)
.setTitle(i18n('commands.blacklist.response.empty_list.title'))
.setDescription(i18n('commands.blacklist.response.empty_list.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
} else {
const members = blacklist.members.map(id => `**·** <@${id}>`);
const roles = blacklist.roles.map(id => `**·** <@&${id}>`);
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.colour)
.setTitle(i18n('commands.blacklist.response.list.title'))
.addField(i18n('commands.blacklist.response.list.fields.members'), members.join('\n') || 'none')
.addField(i18n('commands.blacklist.response.list.fields.roles'), roles.join('\n') || 'none')
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
}
}
}
};

View File

@@ -1,322 +0,0 @@
const Command = require('../modules/commands/command');
const {
Interaction, // eslint-disable-line no-unused-vars
MessageActionRow,
MessageButton,
MessageEmbed
} = require('discord.js');
const { Op } = require('sequelize');
const ms = require('ms');
module.exports = class CloseCommand extends Command {
constructor(client) {
const i18n = client.i18n.getLocale(client.config.locale);
super(client, {
description: i18n('commands.close.description'),
internal: true,
name: i18n('commands.close.name'),
options: [
{
description: i18n('commands.close.options.reason.description'),
name: i18n('commands.close.options.reason.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.close.options.ticket.description'),
name: i18n('commands.close.options.ticket.name'),
required: false,
type: Command.option_types.INTEGER
},
{
description: i18n('commands.close.options.time.description'),
name: i18n('commands.close.options.time.name'),
required: false,
type: Command.option_types.STRING
}
]
});
}
/**
* @param {Interaction} interaction
* @returns {Promise<void|any>}
*/
async execute(interaction) {
const settings = await this.client.utils.getSettings(interaction.guild.id);
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
const i18n = this.client.i18n.getLocale(settings.locale);
const reason = interaction.options.getString(default_i18n('commands.close.options.reason.name'));
const ticket = interaction.options.getInteger(default_i18n('commands.close.options.ticket.name'));
const time = interaction.options.getString(default_i18n('commands.close.options.time.name'));
if (time) {
if (!await this.client.utils.isStaff(interaction.member)) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.close.response.no_permission.title'))
.setDescription(i18n('commands.close.response.no_permission.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
let period;
try {
period = ms(time);
} catch {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.close.response.invalid_time.title'))
.setDescription(i18n('commands.close.response.invalid_time.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
const tickets = await this.client.db.models.Ticket.findAndCountAll({
where: {
guild: interaction.guild.id,
last_message: { [Op.lte]: new Date(Date.now() - period) },
open: true
}
});
if (tickets.count === 0) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.close.response.no_tickets.title'))
.setDescription(i18n('commands.close.response.no_tickets.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
} else {
await interaction.reply({
components: [
new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId(`confirm_close_multiple:${interaction.id}`)
.setLabel(i18n('commands.close.response.confirm_multiple.buttons.confirm', tickets.count, tickets.count))
.setEmoji('✅')
.setStyle('SUCCESS')
)
.addComponents(
new MessageButton()
.setCustomId(`cancel_close_multiple:${interaction.id}`)
.setLabel(i18n('commands.close.response.confirm_multiple.buttons.cancel'))
.setEmoji('❌')
.setStyle('SECONDARY')
)
],
embeds: [
new MessageEmbed()
.setColor(settings.colour)
.setTitle(i18n('commands.close.response.confirm_multiple.title'))
.setDescription(i18n('commands.close.response.confirm_multiple.description', tickets.count, tickets.count))
.setFooter(this.client.utils.footer(settings.footer, i18n('collector_expires_in', 30)), interaction.guild.iconURL())
],
ephemeral: true
});
const filter = i => i.user.id === interaction.user.id && i.customId.includes(interaction.id);
const collector = interaction.channel.createMessageComponentCollector({
filter,
time: 30000
});
collector.on('collect', async i => {
await i.deferUpdate();
if (i.customId === `confirm_close_multiple:${interaction.id}`) {
for (const ticket of tickets.rows) {
await this.client.tickets.close(ticket.id, interaction.user.id, interaction.guild.id, reason);
}
await i.editReply({
components: [],
embeds: [
new MessageEmbed()
.setColor(settings.success_colour)
.setTitle(i18n('commands.close.response.closed_multiple.title', tickets.count, tickets.count))
.setDescription(i18n('commands.close.response.closed_multiple.description', tickets.count, tickets.count))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
} else {
await i.editReply({
components: [],
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.close.response.canceled.title'))
.setDescription(i18n('commands.close.response.canceled.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
collector.stop();
});
collector.on('end', async collected => {
if (collected.size === 0) {
await interaction.editReply({
components: [],
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
.setTitle(i18n('commands.close.response.confirmation_timeout.title'))
.setDescription(i18n('commands.close.response.confirmation_timeout.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
});
}
} else {
let t_row;
if (ticket) {
t_row = await this.client.tickets.resolve(ticket, interaction.guild.id);
if (!t_row) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.close.response.unresolvable.title'))
.setDescription(i18n('commands.close.response.unresolvable.description', ticket))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
} else {
t_row = await this.client.db.models.Ticket.findOne({ where: { id: interaction.channel.id } });
if (!t_row) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.close.response.not_a_ticket.title'))
.setDescription(i18n('commands.close.response.not_a_ticket.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
}
if (t_row.creator !== interaction.member.id && !await this.client.utils.isStaff(interaction.member)) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.close.response.no_permission.title'))
.setDescription(i18n('commands.close.response.no_permission.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
await interaction.reply({
components: [
new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId(`confirm_close:${interaction.id}`)
.setLabel(i18n('commands.close.response.confirm.buttons.confirm'))
.setEmoji('✅')
.setStyle('SUCCESS')
)
.addComponents(
new MessageButton()
.setCustomId(`cancel_close:${interaction.id}`)
.setLabel(i18n('commands.close.response.confirm.buttons.cancel'))
.setEmoji('❌')
.setStyle('SECONDARY')
)
],
embeds: [
new MessageEmbed()
.setColor(settings.colour)
.setTitle(i18n('commands.close.response.confirm.title'))
.setDescription(settings.log_messages ? i18n('commands.close.response.confirm.description_with_archive') : i18n('commands.close.response.confirm.description'))
.setFooter(this.client.utils.footer(settings.footer, i18n('collector_expires_in', 30)), interaction.guild.iconURL())
],
ephemeral: true
});
const filter = i => i.user.id === interaction.user.id && i.customId.includes(interaction.id);
const collector = interaction.channel.createMessageComponentCollector({
filter,
time: 30000
});
collector.on('collect', async i => {
await i.deferUpdate();
if (i.customId === `confirm_close:${interaction.id}`) {
await this.client.tickets.close(t_row.id, interaction.user.id, interaction.guild.id, reason);
await i.editReply({
components: [],
embeds: [
new MessageEmbed()
.setColor(settings.success_colour)
.setTitle(i18n('commands.close.response.closed.title', t_row.number))
.setDescription(i18n('commands.close.response.closed.description', t_row.number))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
} else {
await i.editReply({
components: [],
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.close.response.canceled.title'))
.setDescription(i18n('commands.close.response.canceled.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
collector.stop();
});
collector.on('end', async collected => {
if (collected.size === 0) {
await interaction.editReply({
components: [],
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
.setTitle(i18n('commands.close.response.confirmation_timeout.title'))
.setDescription(i18n('commands.close.response.confirmation_timeout.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
});
}
}
};

View File

@@ -1,67 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>{{survey}} Survey Responses | Discord Tickets</title>
<meta charset='UTF-8'>
<meta name='viewport' content='width=device-width, initial-scale=1, user-scalable=no'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css'>
<link rel='stylesheet' href='https://jenil.github.io/bulmaswatch/darkly/bulmaswatch.min.css'>
</head>
<body>
<section class='section'>
<container class='container box has-text-centered'>
<div class='content'>
<h1>{{survey}} survey responses</h1>
</div>
<div class='level'>
<div class='level-item has-text-centered'>
<div class='box'>
<p class='title'>{{count.responses}}</p>
<p class='heading'>Responses</p>
</div>
</div>
<div class='level-item has-text-centered'>
<div class='box'>
<p class='title'>{{count.users}}</p>
<p class='heading'>Users</p>
</div>
</div>
</div>
<div class='table-container'>
<table class='table is-bordered is-striped is-hoverable is-fullwidth'>
<thead>
<tr>
{{#columns}}
<th>{{.}}</th>
{{/columns}}
</tr>
</thead>
<tbody>
{{#responses}}
<tr>
{{#.}}
<td>{{.}}</td>
{{/.}}
</tr>
{{/responses}}
</tbody>
<tfoot>
<tr>
{{#columns}}
<th>{{.}}</th>
{{/columns}}
</tr>
</tfoot>
</table>
</div>
</container>
</section>
</body>
</html>

View File

@@ -1,49 +0,0 @@
const Command = require('../modules/commands/command');
const {
Interaction, // eslint-disable-line no-unused-vars
MessageEmbed
} = require('discord.js');
module.exports = class HelpCommand extends Command {
constructor(client) {
const i18n = client.i18n.getLocale(client.config.locale);
super(client, {
description: i18n('commands.help.description'),
internal: true,
name: i18n('commands.help.name')
});
}
/**
* @param {Interaction} interaction
* @returns {Promise<void|any>}
*/
async execute(interaction) {
const settings = await this.client.utils.getSettings(interaction.guild.id);
const i18n = this.client.i18n.getLocale(settings.locale);
const is_staff = await this.client.utils.isStaff(interaction.member);
const commands = this.manager.commands.filter(command => {
if (command.permissions.length >= 1) return interaction.member.permissions.has(command.permissions);
else if (command.staff_only) return is_staff;
else return true;
});
const list = commands.map(command => {
const description = command.description.length > 50
? command.description.substring(0, 50) + '...'
: command.description;
return `**\`/${command.name}\` ·** ${description}`;
});
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.colour)
.setTitle(i18n('commands.help.response.list.title'))
.setDescription(i18n('commands.help.response.list.description'))
.addField(i18n('commands.help.response.list.fields.commands'), list.join('\n'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
};

View File

@@ -1,190 +0,0 @@
const Command = require('../modules/commands/command');
const {
Interaction, // eslint-disable-line no-unused-vars,
MessageActionRow,
MessageEmbed,
MessageSelectMenu
} = require('discord.js');
module.exports = class NewCommand extends Command {
constructor(client) {
const i18n = client.i18n.getLocale(client.config.locale);
super(client, {
description: i18n('commands.new.description'),
internal: true,
name: i18n('commands.new.name'),
options: [
{
description: i18n('commands.new.options.topic.description'),
name: i18n('commands.new.options.topic.name'),
required: false,
type: Command.option_types.STRING
}
]
});
}
/**
* @param {Interaction} interaction
* @returns {Promise<void|any>}
*/
async execute(interaction) {
const settings = await this.client.utils.getSettings(interaction.guild.id);
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
const i18n = this.client.i18n.getLocale(settings.locale);
const topic = interaction.options.getString(default_i18n('commands.new.options.topic.name'));
const create = async (cat_row, i) => {
const tickets = await this.client.db.models.Ticket.findAndCountAll({
where: {
category: cat_row.id,
creator: interaction.user.id,
open: true
}
});
if (tickets.count >= cat_row.max_per_member) {
if (cat_row.max_per_member === 1) {
const response = {
components: [],
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
.setTitle(i18n('commands.new.response.has_a_ticket.title'))
.setDescription(i18n('commands.new.response.has_a_ticket.description', tickets.rows[0].id))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
};
await i ? i.editReply(response) : interaction.reply(response);
} else {
const list = tickets.rows.map(row => {
if (row.topic) {
const description = row.topic.substring(0, 30);
const ellipses = row.topic.length > 30 ? '...' : '';
return `<#${row.id}>: \`${description}${ellipses}\``;
} else {
return `<#${row.id}>`;
}
});
const response = {
components: [],
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
.setTitle(i18n('commands.new.response.max_tickets.title', tickets.count))
.setDescription(i18n('commands.new.response.max_tickets.description', list.join('\n')))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
};
await i ? i.editReply(response) : interaction.reply(response);
}
} else {
try {
const t_row = await this.client.tickets.create(interaction.guild.id, interaction.user.id, cat_row.id, topic);
const response = {
components: [],
embeds: [
new MessageEmbed()
.setColor(settings.success_colour)
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
.setTitle(i18n('commands.new.response.created.title'))
.setDescription(i18n('commands.new.response.created.description', `<#${t_row.id}>`))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
};
await i ? i.editReply(response) : interaction.reply(response);
} catch (error) {
const response = {
components: [],
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
.setTitle(i18n('commands.new.response.error.title'))
.setDescription(error.message)
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
};
await i ? i.editReply(response) : interaction.reply(response);
}
}
};
const categories = await this.client.db.models.Category.findAndCountAll({ where: { guild: interaction.guild.id } });
if (categories.count === 0) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
.setTitle(i18n('commands.new.response.no_categories.title'))
.setDescription(i18n('commands.new.response.no_categories.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
]
});
} else if (categories.count === 1) {
create(categories.rows[0]); // skip the category selection
} else {
await interaction.reply({
components: [
new MessageActionRow()
.addComponents(
new MessageSelectMenu()
.setCustomId(`select_category:${interaction.id}`)
.setPlaceholder('Select a category')
.addOptions(categories.rows.map(row => ({
label: row.name,
value: row.id
})))
)
],
embeds: [
new MessageEmbed()
.setColor(settings.colour)
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
.setTitle(i18n('commands.new.response.select_category.title'))
.setDescription(i18n('commands.new.response.select_category.description'))
.setFooter(this.client.utils.footer(settings.footer, i18n('collector_expires_in', 30)), interaction.guild.iconURL())
],
ephemeral: true
});
const filter = i => i.user.id === interaction.user.id && i.customId.includes(interaction.id);
const collector = interaction.channel.createMessageComponentCollector({
filter,
time: 30000
});
collector.on('collect', async i => {
await i.deferUpdate();
create(categories.rows.find(row => row.id === i.values[0]), i);
collector.stop();
});
collector.on('end', async collected => {
if (collected.size === 0) {
await interaction.editReply({
components: [],
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
.setTitle(i18n('commands.new.response.select_category_timeout.title'))
.setDescription(i18n('commands.new.response.select_category_timeout.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
});
}
}
};

View File

@@ -1,210 +0,0 @@
const Command = require('../modules/commands/command');
const {
Interaction, // eslint-disable-line no-unused-vars
MessageActionRow,
MessageButton,
MessageEmbed,
MessageSelectMenu
} = require('discord.js');
const { some } = require('../utils');
module.exports = class PanelCommand extends Command {
constructor(client) {
const i18n = client.i18n.getLocale(client.config.locale);
super(client, {
description: i18n('commands.panel.description'),
internal: true,
name: i18n('commands.panel.name'),
options: [
{
description: i18n('commands.panel.options.categories.description'),
multiple: true,
name: i18n('commands.panel.options.categories.name'),
required: true,
type: Command.option_types.STRING
},
{
description: i18n('commands.panel.options.description.description'),
name: i18n('commands.panel.options.description.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.panel.options.image.description'),
name: i18n('commands.panel.options.image.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.panel.options.just_type.description') + ' (false)',
name: i18n('commands.panel.options.just_type.name'),
required: false,
type: Command.option_types.BOOLEAN
},
{
description: i18n('commands.panel.options.title.description'),
name: i18n('commands.panel.options.title.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.panel.options.thumbnail.description'),
name: i18n('commands.panel.options.thumbnail.name'),
required: false,
type: Command.option_types.STRING
}
],
staff_only: true
});
}
/**
* @param {Interaction} interaction
* @returns {Promise<void|any>}
*/
async execute(interaction) {
const settings = await this.client.utils.getSettings(interaction.guild.id);
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
const i18n = this.client.i18n.getLocale(settings.locale);
const categories = interaction.options.getString(default_i18n('commands.panel.options.categories.name')).match(/\d{17,19}/g) ?? [];
const description = interaction.options.getString(default_i18n('commands.panel.options.description.name'))?.replace(/\\n/g, '\n');
const image = interaction.options.getString(default_i18n('commands.panel.options.image.name'));
const just_type = interaction.options.getBoolean(default_i18n('commands.panel.options.just_type.name'));
const title = interaction.options.getString(default_i18n('commands.panel.options.title.name'));
const thumbnail = interaction.options.getString(default_i18n('commands.panel.options.thumbnail.name'));
if (just_type && categories.length > 1) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.panel.response.too_many_categories.title'))
.setDescription(i18n('commands.panel.response.too_many_categories.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
const invalid_category = await some(categories, async id => {
const cat_row = await this.client.db.models.Category.findOne({
where: {
guild: interaction.guild.id,
id
}
});
return !cat_row;
});
if (invalid_category) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.panel.response.invalid_category.title'))
.setDescription(i18n('commands.panel.response.invalid_category.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
let panel_channel;
const embed = new MessageEmbed()
.setColor(settings.colour)
.setFooter(settings.footer, interaction.guild.iconURL());
if (description) embed.setDescription(description);
if (image) embed.setImage(image);
if (title) embed.setTitle(title);
if (thumbnail) embed.setThumbnail(thumbnail);
if (just_type) {
panel_channel = await interaction.guild.channels.create('create-a-ticket', {
permissionOverwrites: [
{
allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'READ_MESSAGE_HISTORY'],
deny: ['ATTACH_FILES', 'EMBED_LINKS', 'ADD_REACTIONS'],
id: interaction.guild.roles.everyone
},
{
allow: ['SEND_MESSAGES', 'EMBED_LINKS', 'ADD_REACTIONS'],
id: this.client.user.id
}
],
position: 1,
rateLimitPerUser: 30,
reason: `${interaction.user.tag} created a new message panel`,
type: 'GUILD_TEXT'
});
await panel_channel.send({ embeds: [embed] });
this.client.log.info(`${interaction.user.tag} has created a new message panel`);
} else {
panel_channel = await interaction.guild.channels.create('create-a-ticket', {
permissionOverwrites: [
{
allow: ['VIEW_CHANNEL', 'READ_MESSAGE_HISTORY'],
deny: ['SEND_MESSAGES', 'ADD_REACTIONS'],
id: interaction.guild.roles.everyone
},
{
allow: ['SEND_MESSAGES', 'EMBED_LINKS', 'ADD_REACTIONS'],
id: this.client.user.id
}
],
position: 1,
reason: `${interaction.user.tag} created a new panel`,
type: 'GUILD_TEXT'
});
if (categories.length === 1) {
// single category
await panel_channel.send({
components: [
new MessageActionRow()
.addComponents(
new MessageButton()
.setCustomId(`panel.single:${categories[0]}`)
.setLabel(i18n('panel.create_ticket'))
.setStyle('PRIMARY')
)
],
embeds: [embed]
});
this.client.log.info(`${interaction.user.tag} has created a new button panel`);
} else {
// multi category
const rows = await this.client.db.models.Category.findAll({ where: { guild: interaction.guild.id } });
await panel_channel.send({
components: [
new MessageActionRow()
.addComponents(
new MessageSelectMenu()
.setCustomId(`panel.multiple:${panel_channel.id}`)
.setPlaceholder('Select a category')
.addOptions(rows.map(row => ({
label: row.name,
value: row.id
})))
)
],
embeds: [embed]
});
this.client.log.info(`${interaction.user.tag} has created a new select panel`);
}
}
interaction.reply({
content: `${panel_channel}`,
ephemeral: true
});
await this.client.db.models.Panel.create({
category: categories.length === 1 ? categories[0] : null,
channel: panel_channel.id,
guild: interaction.guild.id
});
}
};

View File

@@ -1,111 +0,0 @@
const Command = require('../modules/commands/command');
const {
Interaction, // eslint-disable-line no-unused-vars
MessageEmbed
} = require('discord.js');
module.exports = class RemoveCommand extends Command {
constructor(client) {
const i18n = client.i18n.getLocale(client.config.locale);
super(client, {
description: i18n('commands.remove.description'),
internal: true,
name: i18n('commands.remove.name'),
options: [
{
description: i18n('commands.remove.options.member.description'),
name: i18n('commands.remove.options.member.name'),
required: true,
type: Command.option_types.USER
},
{
description: i18n('commands.remove.options.ticket.description'),
name: i18n('commands.remove.options.ticket.name'),
required: false,
type: Command.option_types.CHANNEL
}
]
});
}
/**
* @param {Interaction} interaction
* @returns {Promise<void|any>}
*/
async execute(interaction) {
const settings = await this.client.utils.getSettings(interaction.guild.id);
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
const i18n = this.client.i18n.getLocale(settings.locale);
const channel = interaction.options.getChannel(default_i18n('commands.remove.options.channel.name')) ?? interaction.channel;
const t_row = await this.client.tickets.resolve(channel.id, interaction.guild.id);
if (!t_row) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.remove.response.not_a_channel.title'))
.setDescription(i18n('commands.remove.response.not_a_channel.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
const member = interaction.options.getMember(default_i18n('commands.remove.options.member.name'));
if (!member) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.remove.response.no_member.title'))
.setDescription(i18n('commands.remove.response.no_member.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
if (t_row.creator !== interaction.user.id && !await this.client.utils.isStaff(interaction.member)) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.remove.response.no_permission.title'))
.setDescription(i18n('commands.remove.response.no_permission.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.success_colour)
.setAuthor(member.user.username, member.user.displayAvatarURL())
.setTitle(i18n('commands.remove.response.removed.title'))
.setDescription(i18n('commands.remove.response.removed.description', member.toString(), channel.toString()))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
await channel.send({
embeds: [
new MessageEmbed()
.setColor(settings.colour)
.setAuthor(member.user.username, member.user.displayAvatarURL())
.setTitle(i18n('ticket.member_removed.title'))
.setDescription(i18n('ticket.member_removed.description', member.toString(), interaction.user.toString()))
.setFooter(settings.footer, interaction.guild.iconURL())
]
});
await channel.permissionOverwrites.delete(member.user.id, `${interaction.user.tag} removed ${member.user.tag} from the ticket`);
this.client.log.info(`${interaction.user.tag} removed ${member.user.tag} from ${channel.id}`);
}
};

View File

@@ -1,358 +0,0 @@
/* eslint-disable max-lines */
const Command = require('../modules/commands/command');
const {
Interaction, // eslint-disable-line no-unused-vars
MessageEmbed
} = require('discord.js');
module.exports = class SettingsCommand extends Command {
constructor(client) {
const i18n = client.i18n.getLocale(client.config.locale);
super(client, {
description: i18n('commands.settings.description'),
internal: true,
name: i18n('commands.settings.name'),
options: [
{
description: i18n('commands.settings.options.categories.description'),
name: i18n('commands.settings.options.categories.name'),
options: [
{
description: i18n('commands.settings.options.categories.options.create.description'),
name: i18n('commands.settings.options.categories.options.create.name'),
options: [
{
description: i18n('commands.settings.options.categories.options.create.options.name.description'),
name: i18n('commands.settings.options.categories.options.create.options.name.name'),
required: true,
type: Command.option_types.STRING
},
{
description: i18n('commands.settings.options.categories.options.create.options.roles.description'),
name: i18n('commands.settings.options.categories.options.create.options.roles.name'),
required: true,
type: Command.option_types.STRING
}
],
type: Command.option_types.SUB_COMMAND
},
{
description: i18n('commands.settings.options.categories.options.delete.description'),
name: i18n('commands.settings.options.categories.options.delete.name'),
options: [
{
description: i18n('commands.settings.options.categories.options.delete.options.id.description'),
name: i18n('commands.settings.options.categories.options.delete.options.id.name'),
required: true,
type: Command.option_types.STRING
}
],
type: Command.option_types.SUB_COMMAND
},
{
description: i18n('commands.settings.options.categories.options.edit.description'),
name: i18n('commands.settings.options.categories.options.edit.name'),
options: [
{
description: i18n('commands.settings.options.categories.options.edit.options.id.description'),
name: i18n('commands.settings.options.categories.options.edit.options.id.name'),
required: true,
type: Command.option_types.STRING
},
{
description: i18n('commands.settings.options.categories.options.edit.options.claiming.description'),
name: i18n('commands.settings.options.categories.options.edit.options.claiming.name'),
required: false,
type: Command.option_types.BOOLEAN
},
{
description: i18n('commands.settings.options.categories.options.edit.options.image.description'),
name: i18n('commands.settings.options.categories.options.edit.options.image.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.settings.options.categories.options.edit.options.max_per_member.description'),
name: i18n('commands.settings.options.categories.options.edit.options.max_per_member.name'),
required: false,
type: Command.option_types.INTEGER
},
{
description: i18n('commands.settings.options.categories.options.edit.options.name.description'),
name: i18n('commands.settings.options.categories.options.edit.options.name.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.settings.options.categories.options.edit.options.name_format.description'),
name: i18n('commands.settings.options.categories.options.edit.options.name_format.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.settings.options.categories.options.edit.options.opening_message.description'),
name: i18n('commands.settings.options.categories.options.edit.options.opening_message.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.settings.options.categories.options.edit.options.opening_questions.description'),
name: i18n('commands.settings.options.categories.options.edit.options.opening_questions.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.settings.options.categories.options.edit.options.ping.description'),
name: i18n('commands.settings.options.categories.options.edit.options.ping.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.settings.options.categories.options.edit.options.require_topic.description'),
name: i18n('commands.settings.options.categories.options.edit.options.require_topic.name'),
required: false,
type: Command.option_types.BOOLEAN
},
{
description: i18n('commands.settings.options.categories.options.edit.options.roles.description'),
name: i18n('commands.settings.options.categories.options.edit.options.roles.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.settings.options.categories.options.edit.options.survey.description'),
name: i18n('commands.settings.options.categories.options.edit.options.survey.name'),
required: false,
type: Command.option_types.STRING
}
],
type: Command.option_types.SUB_COMMAND
},
{
description: i18n('commands.settings.options.categories.options.list.description'),
name: i18n('commands.settings.options.categories.options.list.name'),
type: Command.option_types.SUB_COMMAND
}
],
type: Command.option_types.SUB_COMMAND_GROUP
},
{
description: i18n('commands.settings.options.set.description'),
name: i18n('commands.settings.options.set.name'),
options: [
{
description: i18n('commands.settings.options.set.options.close_button.description'),
name: i18n('commands.settings.options.set.options.close_button.name'),
required: false,
type: Command.option_types.BOOLEAN
},
{
description: i18n('commands.settings.options.set.options.colour.description'),
name: i18n('commands.settings.options.set.options.colour.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.settings.options.set.options.error_colour.description'),
name: i18n('commands.settings.options.set.options.error_colour.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.settings.options.set.options.footer.description'),
name: i18n('commands.settings.options.set.options.footer.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.settings.options.set.options.locale.description'),
name: i18n('commands.settings.options.set.options.locale.name'),
required: false,
type: Command.option_types.STRING
},
{
description: i18n('commands.settings.options.set.options.log_messages.description'),
name: i18n('commands.settings.options.set.options.log_messages.name'),
required: false,
type: Command.option_types.BOOLEAN
},
{
description: i18n('commands.settings.options.set.options.success_colour.description'),
name: i18n('commands.settings.options.set.options.success_colour.name'),
required: false,
type: Command.option_types.STRING
}
],
type: Command.option_types.SUB_COMMAND
}
],
permissions: ['MANAGE_GUILD']
});
}
/**
* @param {Interaction} interaction
* @returns {Promise<void|any>}
*/
async execute(interaction) {
const settings = await this.client.utils.getSettings(interaction.guild.id);
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
const i18n = this.client.i18n.getLocale(settings.locale);
switch (interaction.options.getSubcommand()) {
case default_i18n('commands.settings.options.categories.options.create.name'): {
const name = interaction.options.getString(default_i18n('commands.settings.options.categories.options.create.options.name.name'));
const roles = interaction.options.getString(default_i18n('commands.settings.options.categories.options.create.options.roles.name'))?.match(/\d{17,19}/g) ?? [];
const allowed_permissions = ['VIEW_CHANNEL', 'READ_MESSAGE_HISTORY', 'SEND_MESSAGES', 'EMBED_LINKS', 'ATTACH_FILES'];
const cat_channel = await interaction.guild.channels.create(name, {
permissionOverwrites: [
...[
{
deny: ['VIEW_CHANNEL'],
id: interaction.guild.roles.everyone
},
{
allow: allowed_permissions,
id: this.client.user.id
}
],
...roles.map(r => ({
allow: allowed_permissions,
id: r
}))
],
position: 1,
reason: `Tickets category created by ${interaction.user.tag}`,
type: 'GUILD_CATEGORY'
});
await this.client.db.models.Category.create({
guild: interaction.guild.id,
id: cat_channel.id,
name,
roles
});
await this.client.commands.updatePermissions(interaction.guild);
interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.success_colour)
.setTitle(i18n('commands.settings.response.category_created', name))
],
ephemeral: true
});
break;
}
case default_i18n('commands.settings.options.categories.options.delete.name'): {
const category = await this.client.db.models.Category.findOne({ where: { id: interaction.options.getString(default_i18n('commands.settings.options.categories.options.delete.options.id.name')) } });
if (category) {
const channel = this.client.channels.cache.get(interaction.options.getString(default_i18n('commands.settings.options.categories.options.delete.options.id.name')));
if (channel) channel.delete();
await category.destroy();
interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.success_colour)
.setTitle(i18n('commands.settings.response.category_deleted', category.name))
],
ephemeral: true
});
} else {
interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.settings.response.category_does_not_exist'))
],
ephemeral: true
});
}
break;
}
case default_i18n('commands.settings.options.categories.options.edit.name'): {
const category = await this.client.db.models.Category.findOne({ where: { id: interaction.options.getString(default_i18n('commands.settings.options.categories.options.delete.options.id.name')) } });
if (!category) {
return interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.settings.response.category_does_not_exist'))
],
ephemeral: true
});
}
const claiming = interaction.options.getBoolean(default_i18n('commands.settings.options.categories.options.edit.options.claiming.name'));
const image = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.image.name'));
const max_per_member = interaction.options.getInteger(default_i18n('commands.settings.options.categories.options.edit.options.max_per_member.name'));
const name = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.name.name'));
const name_format = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.name_format.name'));
const opening_message = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.opening_message.name'));
const opening_questions = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.opening_questions.name'));
const ping = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.ping.name'));
const require_topic = interaction.options.getBoolean(default_i18n('commands.settings.options.categories.options.edit.options.require_topic.name'));
const roles = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.roles.name'));
const survey = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.survey.name'));
if (claiming !== null) category.set('claiming', claiming);
if (max_per_member !== null) category.set('max_per_member', max_per_member);
if (image !== null) category.set('image', image);
if (name !== null) category.set('name', name);
if (name_format !== null) category.set('name_format', name_format);
if (opening_message !== null) category.set('opening_message', opening_message.replace(/\\n/g, '\n'));
if (opening_questions !== null) category.set('opening_questions', JSON.parse(opening_questions));
if (ping !== null) category.set('ping', ping.match(/\d{17,19}/g) ?? []);
if (require_topic !== null) category.set('require_topic', require_topic);
if (roles !== null) category.set('roles', roles.match(/\d{17,19}/g) ?? []);
if (survey !== null) category.set('survey', survey);
await category.save();
interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.success_colour)
.setTitle(i18n('commands.settings.response.category_updated', category.name))
],
ephemeral: true
});
break;
}
case default_i18n('commands.settings.options.categories.options.list.name'): {
const categories = await this.client.db.models.Category.findAll({ where: { guild: interaction.guild.id } });
await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.colour)
.setTitle(i18n('commands.settings.response.category_list'))
.setDescription(categories.map(c => `- ${c.name} (\`${c.id}\`)`).join('\n'))
],
ephemeral: true
});
break;
}
case default_i18n('commands.settings.options.set.name'): {
const close_button = interaction.options.getBoolean(default_i18n('commands.settings.options.set.options.close_button.name'));
const colour = interaction.options.getString(default_i18n('commands.settings.options.set.options.colour.name'));
const error_colour = interaction.options.getString(default_i18n('commands.settings.options.set.options.error_colour.name'));
const footer = interaction.options.getString(default_i18n('commands.settings.options.set.options.footer.name'));
const locale = interaction.options.getString(default_i18n('commands.settings.options.set.options.locale.name'));
const log_messages = interaction.options.getBoolean(default_i18n('commands.settings.options.set.options.log_messages.name'));
const success_colour = interaction.options.getString(default_i18n('commands.settings.options.set.options.success_colour.name'));
if (close_button !== null) settings.set('close_button', close_button);
if (colour !== null) settings.set('colour', colour.toUpperCase());
if (error_colour !== null) settings.set('error_colour', error_colour.toUpperCase());
if (footer !== null) settings.set('footer', footer);
if (locale !== null) settings.set('locale', locale);
if (log_messages !== null) settings.set('log_messages', log_messages);
if (success_colour !== null) settings.set('success_colour', success_colour.toUpperCase());
await settings.save();
interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.success_colour)
.setTitle(i18n('commands.settings.response.settings_updated'))
],
ephemeral: true
});
break;
}
}
}
};

View File

@@ -1,95 +0,0 @@
const Command = require('../modules/commands/command');
const Keyv = require('keyv');
const {
Interaction, // eslint-disable-line no-unused-vars
MessageEmbed
} = require('discord.js');
module.exports = class StatsCommand extends Command {
constructor(client) {
const i18n = client.i18n.getLocale(client.config.locale);
super(client, {
description: i18n('commands.stats.description'),
internal: true,
name: i18n('commands.stats.name'),
staff_only: true
});
this.cache = new Keyv({ namespace: 'cache.commands.stats' });
}
/**
* @param {Interaction} interaction
* @returns {Promise<void|any>}
*/
async execute(interaction) {
const settings = await this.client.utils.getSettings(interaction.guild.id);
const i18n = this.client.i18n.getLocale(settings.locale);
const messages = await this.client.db.models.Message.findAndCountAll();
let stats = await this.cache.get(interaction.guild.id);
if (!stats) {
const tickets = await this.client.db.models.Ticket.findAndCountAll({ where: { guild: interaction.guild.id } });
stats = { // maths
messages: settings.log_messages
? await messages.rows
.reduce(async (acc, row) => (await this.client.db.models.Ticket.findOne({ where: { id: row.ticket } }))
.guild === interaction.guild.id
? await acc + 1
: await acc, 0)
: null,
response_time: Math.floor(tickets.rows.reduce((acc, row) => row.first_response
? acc + ((Math.abs(new Date(row.createdAt) - new Date(row.first_response)) / 1000) / 60)
: acc, 0) / tickets.count),
tickets: tickets.count
};
await this.cache.set(interaction.guild.id, stats, 60 * 60 * 1000); // cache for an hour
}
const guild_embed = new MessageEmbed()
.setColor(settings.colour)
.setTitle(i18n('commands.stats.response.guild.title'))
.setDescription(i18n('commands.stats.response.guild.description'))
.addField(i18n('commands.stats.fields.tickets'), String(stats.tickets), true)
.addField(i18n('commands.stats.fields.response_time.title'), i18n('commands.stats.fields.response_time.minutes', stats.response_time), true)
.setFooter(settings.footer, interaction.guild.iconURL());
if (stats.messages) guild_embed.addField(i18n('commands.stats.fields.messages'), String(stats.messages), true);
const embeds = [guild_embed];
if (this.client.guilds.cache.size > 1) {
let global = await this.cache.get('global');
if (!global) {
const tickets = await this.client.db.models.Ticket.findAndCountAll();
global = { // maths
messages: settings.log_messages
? await messages.count
: null,
response_time: Math.floor(tickets.rows.reduce((acc, row) => row.first_response
? acc + ((Math.abs(new Date(row.createdAt) - new Date(row.first_response)) / 1000) / 60)
: acc, 0) / tickets.count),
tickets: tickets.count
};
await this.cache.set('global', global, 60 * 60 * 1000); // cache for an hour
}
const global_embed = new MessageEmbed()
.setColor(settings.colour)
.setTitle(i18n('commands.stats.response.global.title'))
.setDescription(i18n('commands.stats.response.global.description'))
.addField(i18n('commands.stats.fields.tickets'), String(global.tickets), true)
.addField(i18n('commands.stats.fields.response_time.title'), i18n('commands.stats.fields.response_time.minutes', global.response_time), true)
.setFooter(settings.footer, interaction.guild.iconURL());
if (stats.messages) global_embed.addField(i18n('commands.stats.fields.messages'), String(global.messages), true);
embeds.push(global_embed);
}
await interaction.reply({ embeds });
}
};

View File

@@ -1,113 +0,0 @@
const Command = require('../modules/commands/command');
// eslint-disable-next-line no-unused-vars
const {
Message, // eslint-disable-line no-unused-vars
MessageAttachment,
MessageEmbed
} = require('discord.js');
const fsp = require('fs').promises;
const { path } = require('../utils/fs');
const mustache = require('mustache');
module.exports = class SurveyCommand extends Command {
constructor(client) {
const i18n = client.i18n.getLocale(client.config.locale);
super(client, {
description: i18n('commands.survey.description'),
internal: true,
name: i18n('commands.survey.name'),
options: async guild => {
const surveys = await this.client.db.models.Survey.findAll({ where: { guild: guild.id } });
return [
{
choices: surveys.map(survey => ({
name: survey.name,
value: survey.name
})),
description: i18n('commands.survey.options.survey.description'),
name: i18n('commands.survey.options.survey.name'),
required: true,
type: Command.option_types.STRING
}
];
},
staff_only: true
});
}
/**
* @param {Interaction} interaction
* @returns {Promise<void|any>}
*/
async execute(interaction) {
const settings = await this.client.utils.getSettings(interaction.guild.id);
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
const i18n = this.client.i18n.getLocale(settings.locale);
const name = interaction.options.getString(default_i18n('commands.survey.options.survey.name'));
const survey = await this.client.db.models.Survey.findOne({
where: {
guild: interaction.guild.id,
name
}
});
if (survey) {
const {
rows: responses, count
} = await this.client.db.models.SurveyResponse.findAndCountAll({ where: { survey: survey.id } });
const users = new Set();
for (const i in responses) {
const ticket = await this.client.db.models.Ticket.findOne({ where: { id: responses[i].ticket } });
users.add(ticket.creator);
const answers = responses[i].answers.map(a => this.client.cryptr.decrypt(a));
answers.unshift(ticket.number);
responses[i] = answers;
}
let template = await fsp.readFile(path('./src/commands/extra/survey.template.html'), { encoding: 'utf8' });
template = template.replace(/[\r\n\t]/g, '');
survey.questions.unshift('Ticket #');
const html = mustache.render(template, {
columns: survey.questions,
count: {
responses: count,
users: users.size
},
responses,
survey: survey.name.charAt(0).toUpperCase() + survey.name.slice(1)
});
const attachment = new MessageAttachment(
Buffer.from(html),
`${survey.name}.html`
);
return await interaction.reply({
ephemeral: true,
files: [attachment]
});
} else {
const surveys = await this.client.db.models.Survey.findAll({ where: { guild: interaction.guild.id } });
const list = surveys.map(s => ` **\`${s.name}\`**`);
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.colour)
.setTitle(i18n('commands.survey.response.list.title'))
.setDescription(list.join('\n'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
}
};

View File

@@ -1,71 +0,0 @@
const Command = require('../modules/commands/command');
const {
Interaction, // eslint-disable-line no-unused-vars
MessageEmbed
} = require('discord.js');
module.exports = class TagCommand extends Command {
constructor(client) {
const i18n = client.i18n.getLocale(client.config.locale);
super(client, {
description: i18n('commands.tag.description'),
internal: true,
name: i18n('commands.tag.name'),
options: async guild => {
const settings = await client.utils.getSettings(guild.id);
return Object.keys(settings.tags).map(tag => ({
description: settings.tags[tag].substring(0, 100),
name: tag,
options: [...settings.tags[tag].matchAll(/(?<!\\){{1,2}\s?([A-Za-z0-9._:]+)\s?(?<!\\)}{1,2}/gi)]
.map(match => ({
description: match[1],
name: match[1],
required: true,
type: Command.option_types.STRING
})),
type: Command.option_types.SUB_COMMAND
}));
},
staff_only: true
});
}
/**
* @param {Interaction} interaction
* @returns {Promise<void|any>}
*/
async execute(interaction) {
const settings = await this.client.utils.getSettings(interaction.guild.id);
const i18n = this.client.i18n.getLocale(settings.locale);
try {
const tag_name = interaction.options.getSubcommand();
const tag = settings.tags[tag_name];
const args = interaction.options.data[0]?.options;
const text = tag.replace(/(?<!\\){{1,2}\s?([A-Za-z0-9._:]+)\s?(?<!\\)}{1,2}/gi, ($, $1) => {
const arg = args.find(arg => arg.name === $1);
return arg ? arg.value : $;
});
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.colour)
.setDescription(text)
],
ephemeral: false
});
} catch {
const list = Object.keys(settings.tags).map(t => ` **\`${t}\`**`);
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.colour)
.setTitle(i18n('commands.tag.response.list.title'))
.setDescription(list.join('\n'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
}
};

View File

@@ -1,87 +0,0 @@
const Command = require('../modules/commands/command');
const {
Interaction, // eslint-disable-line no-unused-vars
MessageEmbed
} = require('discord.js');
module.exports = class TopicCommand extends Command {
constructor(client) {
const i18n = client.i18n.getLocale(client.config.locale);
super(client, {
description: i18n('commands.topic.description'),
internal: true,
name: i18n('commands.topic.name'),
options: [
{
description: i18n('commands.topic.options.new_topic.description'),
name: i18n('commands.topic.options.new_topic.name'),
required: true,
type: Command.option_types.STRING
}
]
});
}
/**
* @param {Interaction} interaction
* @returns {Promise<void|any>}
*/
async execute(interaction) {
const settings = await this.client.utils.getSettings(interaction.guild.id);
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
const i18n = this.client.i18n.getLocale(settings.locale);
const topic = interaction.options.getString(default_i18n('commands.topic.options.new_topic.name'));
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: interaction.channel.id } });
if (!t_row) {
return await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.topic.response.not_a_ticket.title'))
.setDescription(i18n('commands.topic.response.not_a_ticket.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: true
});
}
await t_row.update({ topic: this.client.cryptr.encrypt(topic) });
const member = await interaction.guild.members.fetch(t_row.creator);
interaction.channel.setTopic(`${member} | ${topic}`, { reason: 'User updated ticket topic' });
const cat_row = await this.client.db.models.Category.findOne({ where: { id: t_row.category } });
const description = cat_row.opening_message
.replace(/{+\s?(user)?name\s?}+/gi, member.displayName)
.replace(/{+\s?(tag|ping|mention)?\s?}+/gi, member.user.toString());
const opening_message = await interaction.channel.messages.fetch(t_row.opening_message);
await opening_message.edit({
embeds: [
new MessageEmbed()
.setColor(settings.colour)
.setAuthor(member.user.username, member.user.displayAvatarURL())
.setDescription(description)
.addField(i18n('ticket.opening_message.fields.topic'), topic)
.setFooter(settings.footer, interaction.guild.iconURL())
]
});
await interaction.reply({
embeds: [
new MessageEmbed()
.setColor(settings.success_colour)
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
.setTitle(i18n('commands.topic.response.changed.title'))
.setDescription(i18n('commands.topic.response.changed.description'))
.setFooter(settings.footer, interaction.guild.iconURL())
],
ephemeral: false
});
this.client.log.info(`${interaction.user.tag} changed the topic of #${interaction.channel.name}`);
}
};