mirror of
https://github.com/Hessenuk/DiscordTickets.git
synced 2024-12-23 00:03:09 +02:00
Linting
This commit is contained in:
parent
777719d1b3
commit
32f43ac18f
146
.eslintrc.js
146
.eslintrc.js
@ -5,10 +5,73 @@ module.exports = {
|
||||
'node': true
|
||||
},
|
||||
'extends': 'eslint:recommended',
|
||||
'parserOptions': {
|
||||
'ecmaVersion': 12
|
||||
},
|
||||
'parserOptions': { 'ecmaVersion': 12 },
|
||||
'rules': {
|
||||
'array-bracket-newline': [
|
||||
'error',
|
||||
'consistent'
|
||||
],
|
||||
'array-bracket-spacing': [
|
||||
'error',
|
||||
'never'
|
||||
],
|
||||
'array-element-newline': [
|
||||
'error',
|
||||
'consistent'
|
||||
],
|
||||
'arrow-body-style': [
|
||||
'error',
|
||||
'as-needed'
|
||||
],
|
||||
'arrow-parens': [
|
||||
'error',
|
||||
'as-needed'
|
||||
],
|
||||
'block-spacing': [
|
||||
'error',
|
||||
'always'
|
||||
],
|
||||
'brace-style': [
|
||||
'error',
|
||||
'1tbs'
|
||||
],
|
||||
'comma-dangle': [
|
||||
'error',
|
||||
'never'
|
||||
],
|
||||
'comma-spacing': [
|
||||
'error',
|
||||
{
|
||||
'after': true,
|
||||
'before': false
|
||||
}
|
||||
],
|
||||
'comma-style': [
|
||||
'error',
|
||||
'last'
|
||||
],
|
||||
'computed-property-spacing': [
|
||||
'error',
|
||||
'never'
|
||||
],
|
||||
'curly': [
|
||||
'error',
|
||||
'multi-line', // 'multi'
|
||||
'consistent'
|
||||
],
|
||||
'default-case-last': [
|
||||
'error'
|
||||
],
|
||||
'dot-location': [
|
||||
'error',
|
||||
'property'
|
||||
],
|
||||
'dot-notation': [
|
||||
'error'
|
||||
],
|
||||
'eqeqeq': [
|
||||
'error'
|
||||
],
|
||||
'indent': [
|
||||
'error',
|
||||
'tab'
|
||||
@ -17,6 +80,74 @@ module.exports = {
|
||||
'off',
|
||||
'windows'
|
||||
],
|
||||
'max-depth': [
|
||||
'warn',
|
||||
{ 'max': 5 }
|
||||
],
|
||||
'max-len': [
|
||||
'warn',
|
||||
{
|
||||
'code': 150,
|
||||
'ignoreRegExpLiterals': true,
|
||||
'ignoreStrings': true,
|
||||
'ignoreTemplateLiterals': true,
|
||||
'ignoreTrailingComments': true,
|
||||
'ignoreUrls': true
|
||||
}
|
||||
],
|
||||
'max-lines': [
|
||||
'warn'
|
||||
],
|
||||
'max-statements-per-line': [
|
||||
'error'
|
||||
],
|
||||
'multiline-comment-style': [
|
||||
'warn'
|
||||
],
|
||||
'no-console': [
|
||||
'warn'
|
||||
],
|
||||
'no-return-assign': [
|
||||
'error'
|
||||
],
|
||||
'no-template-curly-in-string': [
|
||||
'warn'
|
||||
],
|
||||
'no-trailing-spaces': [
|
||||
'error'
|
||||
],
|
||||
'no-underscore-dangle': [
|
||||
'error'
|
||||
],
|
||||
'no-unneeded-ternary': [
|
||||
'error'
|
||||
],
|
||||
'no-var': [
|
||||
'error'
|
||||
],
|
||||
'no-whitespace-before-property': [
|
||||
'error'
|
||||
],
|
||||
'object-curly-newline': [
|
||||
'error',
|
||||
{
|
||||
'minProperties': 2,
|
||||
'multiline': true
|
||||
}
|
||||
],
|
||||
'object-curly-spacing': [
|
||||
'error',
|
||||
'always'
|
||||
],
|
||||
'object-property-newline': [
|
||||
'error'
|
||||
],
|
||||
'operator-linebreak': [
|
||||
'error'
|
||||
],
|
||||
'prefer-arrow-callback': [
|
||||
'error'
|
||||
],
|
||||
'prefer-const': [
|
||||
'error',
|
||||
{
|
||||
@ -32,5 +163,14 @@ module.exports = {
|
||||
'error',
|
||||
'always'
|
||||
],
|
||||
'sort-keys': [
|
||||
'error',
|
||||
'asc',
|
||||
{ 'natural': true }
|
||||
],
|
||||
'space-in-parens': [
|
||||
'error',
|
||||
'never'
|
||||
]
|
||||
}
|
||||
};
|
27
README.md
27
README.md
@ -1,26 +1,17 @@
|
||||
<img src='https://discordtickets.app/img/logo-small-circle.png' align='left' width='180px' height='180px' style='margin: 30px 40px 0 0'/>
|
||||
<!-- <img align='left' width='0' height='192px' hspace='10'/> -->
|
||||
|
||||
<!-- omit in toc -->
|
||||
# [Discord Tickets](https://discordtickets.app)
|
||||
|
||||
[![GitHub stars](https://img.shields.io/github/stars/discord-tickets/bot?style=flat-square)](https://github.com/discord-tickets/bot/stargazers)
|
||||
[![GitHub forks](https://img.shields.io/github/forks/discord-tickets/bot?style=flat-square)](https://github.com/discord-tickets/bot/stargazers)
|
||||
[![License](https://img.shields.io/github/license/discord-tickets/bot?style=flat-square)](https://github.com/discord-tickets/bot/blob/master/LICENSE)
|
||||
![Codacy grade](https://img.shields.io/codacy/grade/14e6851c85444424b75b8bc3f93e93db?logo=codacy&style=flat-square)
|
||||
[![Discord](https://img.shields.io/discord/451745464480432129?label=discord&color=7289DA&style=flat-square)](https://discord.gg/pXc9vyC)
|
||||
[![Codacy](https://img.shields.io/codacy/grade/b974eb5f984c40868e07d82c968bd02d?logo=codacy&style=flat-square)](https://www.codacy.com/gh/discord-tickets/bot/dashboard?utm_source=github.com&utm_medium=referral&utm_content=discord-tickets/bot&utm_campaign=Badge_Grade)
|
||||
[![Discord](https://img.shields.io/discord/451745464480432129?label=discord&color=7289DA&style=flat-square)](https://go.eartharoid.me/discord)
|
||||
[![Crowdin](https://badges.crowdin.net/discord-tickets/localized.svg)](https://i18n.discordtickets.app/project/discord-tickets)
|
||||
|
||||
<br>
|
||||
|
||||
![Discord Tickets](https://ik.imagekit.io/eartharoid/discord-tickets/wordmark/gradient_HTC7nqZr9.png)
|
||||
|
||||
|
||||
An open-source ticket management bot for Discord - a free alternative to the premium and white-label plans of other popular ticketing bots.
|
||||
|
||||
<br><br>
|
||||
|
||||
⚠️
|
||||
**The code on the master branch is for v3 which is not ready. Please go to the [v2 branch](https://github.com/discord-tickets/bot/tree/v2) for the current version of the code and [documentation](https://github.com/discord-tickets/bot/wiki)**.
|
||||
|
||||
⚠️
|
||||
**The following information is about v3. Please read the README file on the [v2 branch](https://github.com/discord-tickets/bot/tree/v2) for information that is about the current version.**
|
||||
|
||||
## What is this?
|
||||
|
||||
Discord Tickets is a Discord bot for creating and managing "support ticket" channels. It is a free and open-source alternative to the popular paid "premium" and "white-label" ticketing bots, such as [Ticket Tool](https://tickettool.xyz/), [TicketsBot](https://ticketsbot.net/), [Tickety](https://tickety.net/), [Helper.gg](https://helper.gg/), [Helper](https://helper.wtf), and others.
|
||||
@ -65,7 +56,7 @@ If you choose SQLite, which is the default as it is the easiest, you don't need
|
||||
|
||||
### Screenshots
|
||||
|
||||
> screenshot of a ticket channel
|
||||
![The opening message of a ticket channel](https://i.imgur.com/2T5eSH0.png)
|
||||
<!-- -->
|
||||
> screenshot of a panel
|
||||
|
||||
@ -117,6 +108,6 @@ Does your community or company use Discord Tickets? Sponsor the project to get y
|
||||
|
||||
Discord Tickets is licensed under the [GPLv3 license](https://github.com/discord-tickets/bot/blob/master/LICENSE).
|
||||
|
||||
Discord Tickets is not related to Discord Inc.
|
||||
This is not an official Discord product. It is not affiliated with nor endorsed by Discord Inc.
|
||||
|
||||
© 2021 Isaac Saunders
|
||||
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"include": [
|
||||
"src/**/*.js"
|
||||
]
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
/* eslint-disable no-console */
|
||||
const link = require('terminal-link');
|
||||
const leeks = require('leeks.js');
|
||||
|
||||
const { version, homepage } = require('../package.json');
|
||||
const {
|
||||
version, homepage
|
||||
} = require('../package.json');
|
||||
|
||||
module.exports = () => {
|
||||
console.log(leeks.colours.cyan(`
|
||||
|
@ -1,30 +1,32 @@
|
||||
const Command = require('../modules/commands/command');
|
||||
// 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');
|
||||
|
||||
module.exports = class AddCommand extends Command {
|
||||
constructor(client) {
|
||||
const i18n = client.i18n.getLocale(client.config.locale);
|
||||
super(client, {
|
||||
internal: true,
|
||||
name: i18n('commands.add.name'),
|
||||
description: i18n('commands.add.description'),
|
||||
aliases: [],
|
||||
process_args: false,
|
||||
args: [
|
||||
{
|
||||
name: i18n('commands.add.args.member.name'),
|
||||
description: i18n('commands.add.args.member.description'),
|
||||
example: i18n('commands.add.args.member.example'),
|
||||
required: true,
|
||||
name: i18n('commands.add.args.member.name'),
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: i18n('commands.add.args.ticket.name'),
|
||||
description: i18n('commands.add.args.ticket.description'),
|
||||
example: i18n('commands.add.args.ticket.example'),
|
||||
required: false,
|
||||
name: i18n('commands.add.args.ticket.name'),
|
||||
required: false
|
||||
}
|
||||
]
|
||||
],
|
||||
description: i18n('commands.add.description'),
|
||||
internal: true,
|
||||
name: i18n('commands.add.name'),
|
||||
process_args: false
|
||||
});
|
||||
}
|
||||
|
||||
@ -38,7 +40,7 @@ module.exports = class AddCommand extends Command {
|
||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||
|
||||
const ticket = message.mentions.channels.first() ?? message.channel;
|
||||
const t_row = await this.client.tickets.resolve(ticket.id, message.guild.id);
|
||||
const t_row = await this.client.tickets.resolve(ticket.id, message.guild.id);
|
||||
|
||||
if (!t_row) {
|
||||
return await message.channel.send(
|
||||
@ -93,10 +95,10 @@ module.exports = class AddCommand extends Command {
|
||||
);
|
||||
|
||||
await ticket.updateOverwrite(member, {
|
||||
VIEW_CHANNEL: true,
|
||||
ATTACH_FILES: true,
|
||||
READ_MESSAGE_HISTORY: true,
|
||||
SEND_MESSAGES: true,
|
||||
ATTACH_FILES: true
|
||||
VIEW_CHANNEL: true
|
||||
}, `${message.author.tag} added ${member.user.tag} to the ticket`);
|
||||
|
||||
await this.client.tickets.archives.updateMember(ticket.id, member);
|
||||
|
@ -1,27 +1,29 @@
|
||||
const Command = require('../modules/commands/command');
|
||||
// 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');
|
||||
|
||||
module.exports = class BlacklistCommand extends Command {
|
||||
constructor(client) {
|
||||
const i18n = client.i18n.getLocale(client.config.locale);
|
||||
super(client, {
|
||||
internal: true,
|
||||
name: i18n('commands.blacklist.name'),
|
||||
description: i18n('commands.blacklist.description'),
|
||||
aliases: [
|
||||
i18n('commands.blacklist.aliases.unblacklist'),
|
||||
i18n('commands.blacklist.aliases.unblacklist')
|
||||
],
|
||||
process_args: false,
|
||||
args: [
|
||||
{
|
||||
name: i18n('commands.blacklist.args.member_or_role.name'),
|
||||
description: i18n('commands.blacklist.args.member_or_role.description'),
|
||||
example: i18n('commands.blacklist.args.member_or_role.example'),
|
||||
required: false,
|
||||
name: i18n('commands.blacklist.args.member_or_role.name'),
|
||||
required: false
|
||||
}
|
||||
],
|
||||
permissions: ['MANAGE_GUILD']
|
||||
description: i18n('commands.blacklist.description'),
|
||||
internal: true,
|
||||
name: i18n('commands.blacklist.name'),
|
||||
permissions: ['MANAGE_GUILD'],
|
||||
process_args: false
|
||||
});
|
||||
}
|
||||
|
||||
@ -45,16 +47,19 @@ module.exports = class BlacklistCommand extends Command {
|
||||
.setFooter(settings.footer, message.guild.iconURL())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const role = message.mentions.roles.first();
|
||||
let id;
|
||||
const input = args.trim().split(/\s/g)[0];
|
||||
|
||||
if (member) id = member.id;
|
||||
else if (role) id = role.id;
|
||||
else if (/\d{17,19}/.test(input)) id = input;
|
||||
else if (settings.blacklist?.length === 0) {
|
||||
if (member) {
|
||||
id = member.id;
|
||||
} else if (role) {
|
||||
id = role.id;
|
||||
} else if (/\d{17,19}/.test(input)) {
|
||||
id = input;
|
||||
} else if (settings.blacklist?.length === 0) {
|
||||
return await message.channel.send(
|
||||
new MessageEmbed()
|
||||
.setColor(settings.colour)
|
||||
|
@ -1,6 +1,10 @@
|
||||
const Command = require('../modules/commands/command');
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { MessageEmbed, MessageMentions, Message } = require('discord.js');
|
||||
const {
|
||||
Message, // eslint-disable-line no-unused-vars
|
||||
MessageEmbed,
|
||||
MessageMentions
|
||||
} = require('discord.js');
|
||||
const { Op } = require('sequelize');
|
||||
const toTime = require('to-time-monthsfork');
|
||||
const { footer } = require('../utils/discord');
|
||||
@ -9,43 +13,40 @@ module.exports = class CloseCommand extends Command {
|
||||
constructor(client) {
|
||||
const i18n = client.i18n.getLocale(client.config.locale);
|
||||
super(client, {
|
||||
internal: true,
|
||||
name: i18n('commands.close.name'),
|
||||
description: i18n('commands.close.description'),
|
||||
aliases: [
|
||||
i18n('commands.close.aliases.delete'),
|
||||
i18n('commands.close.aliases.lock'),
|
||||
i18n('commands.close.aliases.lock')
|
||||
],
|
||||
process_args: true,
|
||||
args: [
|
||||
{
|
||||
name: i18n('commands.close.args.ticket.name'),
|
||||
alias: i18n('commands.close.args.ticket.alias'),
|
||||
description: i18n('commands.close.args.ticket.description'),
|
||||
example: i18n('commands.close.args.ticket.example'),
|
||||
name: i18n('commands.close.args.ticket.name'),
|
||||
required: false,
|
||||
// for arg parsing
|
||||
alias: i18n('commands.close.args.ticket.alias'),
|
||||
type: String
|
||||
},
|
||||
{
|
||||
name: i18n('commands.close.args.reason.name'),
|
||||
alias: i18n('commands.close.args.reason.alias'),
|
||||
description: i18n('commands.close.args.reason.description'),
|
||||
example: i18n('commands.close.args.reason.example'),
|
||||
name: i18n('commands.close.args.reason.name'),
|
||||
required: false,
|
||||
// for arg parsing
|
||||
alias: i18n('commands.close.args.reason.alias'),
|
||||
type: String
|
||||
},
|
||||
{
|
||||
name: i18n('commands.close.args.time.name'),
|
||||
alias: i18n('commands.close.args.time.alias'),
|
||||
description: i18n('commands.close.args.time.description'),
|
||||
example: i18n('commands.close.args.time.example'),
|
||||
name: i18n('commands.close.args.time.name'),
|
||||
required: false,
|
||||
// for arg parsing
|
||||
alias: i18n('commands.close.args.time.alias'),
|
||||
type: String
|
||||
}
|
||||
]
|
||||
],
|
||||
description: i18n('commands.close.description'),
|
||||
internal: true,
|
||||
name: i18n('commands.close.name'),
|
||||
process_args: true
|
||||
});
|
||||
}
|
||||
|
||||
@ -79,10 +80,8 @@ module.exports = class CloseCommand extends Command {
|
||||
|
||||
const tickets = await this.client.db.models.Ticket.findAndCountAll({
|
||||
where: {
|
||||
last_message: {
|
||||
[Op.lte]: new Date(Date.now() - period)
|
||||
},
|
||||
guild: message.guild.id
|
||||
guild: message.guild.id,
|
||||
last_message: { [Op.lte]: new Date(Date.now() - period) }
|
||||
}
|
||||
});
|
||||
|
||||
@ -105,13 +104,9 @@ module.exports = class CloseCommand extends Command {
|
||||
|
||||
await collector_message.react('✅');
|
||||
|
||||
const collector_filter = (reaction, user) => {
|
||||
return user.id === message.author.id && reaction.emoji.name === '✅';
|
||||
};
|
||||
const collector_filter = (reaction, user) => user.id === message.author.id && reaction.emoji.name === '✅';
|
||||
|
||||
const collector = collector_message.createReactionCollector(collector_filter, {
|
||||
time: 30000
|
||||
});
|
||||
const collector = collector_message.createReactionCollector(collector_filter, { time: 30000 });
|
||||
|
||||
collector.on('collect', async () => {
|
||||
await collector_message.reactions.removeAll();
|
||||
@ -130,7 +125,7 @@ module.exports = class CloseCommand extends Command {
|
||||
|
||||
});
|
||||
|
||||
collector.on('end', async (collected) => {
|
||||
collector.on('end', async collected => {
|
||||
if (collected.size === 0) {
|
||||
await collector_message.reactions.removeAll();
|
||||
await collector_message.edit(
|
||||
@ -169,11 +164,7 @@ module.exports = class CloseCommand extends Command {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
t_row = await this.client.db.models.Ticket.findOne({
|
||||
where: {
|
||||
id: message.channel.id
|
||||
}
|
||||
});
|
||||
t_row = await this.client.db.models.Ticket.findOne({ where: { id: message.channel.id } });
|
||||
|
||||
if (!t_row) {
|
||||
return await message.channel.send(
|
||||
@ -196,13 +187,9 @@ module.exports = class CloseCommand extends Command {
|
||||
|
||||
await collector_message.react('✅');
|
||||
|
||||
const collector_filter = (reaction, user) => {
|
||||
return user.id === message.author.id && reaction.emoji.name === '✅';
|
||||
};
|
||||
const collector_filter = (reaction, user) => user.id === message.author.id && reaction.emoji.name === '✅';
|
||||
|
||||
const collector = collector_message.createReactionCollector(collector_filter, {
|
||||
time: 30000
|
||||
});
|
||||
const collector = collector_message.createReactionCollector(collector_filter, { time: 30000 });
|
||||
|
||||
collector.on('collect', async () => {
|
||||
collector.stop();
|
||||
@ -223,7 +210,7 @@ module.exports = class CloseCommand extends Command {
|
||||
await this.client.tickets.close(t_row.id, message.author.id, message.guild.id, args[arg_reason]);
|
||||
});
|
||||
|
||||
collector.on('end', async (collected) => {
|
||||
collector.on('end', async collected => {
|
||||
if (collected.size === 0) {
|
||||
await collector_message.reactions.removeAll();
|
||||
await collector_message.edit(
|
||||
@ -244,7 +231,7 @@ module.exports = class CloseCommand extends Command {
|
||||
}, 15000);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
};
|
@ -1,33 +1,35 @@
|
||||
const Command = require('../modules/commands/command');
|
||||
// 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');
|
||||
|
||||
module.exports = class HelpCommand extends Command {
|
||||
constructor(client) {
|
||||
const i18n = client.i18n.getLocale(client.config.locale);
|
||||
super(client, {
|
||||
internal: true,
|
||||
name: i18n('commands.help.name'),
|
||||
description: i18n('commands.help.description'),
|
||||
aliases: [
|
||||
i18n('commands.help.aliases.command'),
|
||||
i18n('commands.help.aliases.commands'),
|
||||
i18n('commands.help.aliases.commands')
|
||||
],
|
||||
process_args: false,
|
||||
args: [
|
||||
{
|
||||
name: i18n('commands.help.args.command.name'),
|
||||
description: i18n('commands.help.args.command.description'),
|
||||
example: i18n('commands.help.args.command.example'),
|
||||
required: false,
|
||||
name: i18n('commands.help.args.command.name'),
|
||||
required: false
|
||||
}
|
||||
]
|
||||
],
|
||||
description: i18n('commands.help.description'),
|
||||
internal: true,
|
||||
name: i18n('commands.help.name'),
|
||||
process_args: false
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Message} message
|
||||
* @param {string} args
|
||||
* @param {Message} message
|
||||
* @param {string} args
|
||||
* @returns {Promise<void|any>}
|
||||
*/
|
||||
async execute(message, args) {
|
||||
@ -54,9 +56,7 @@ module.exports = class HelpCommand extends Command {
|
||||
new MessageEmbed()
|
||||
.setColor(settings.colour)
|
||||
.setTitle(i18n('commands.help.response.list.title'))
|
||||
.setDescription(i18n('commands.help.response.list.description', {
|
||||
prefix: settings.command_prefix,
|
||||
}))
|
||||
.setDescription(i18n('commands.help.response.list.description', { prefix: settings.command_prefix }))
|
||||
.addField(i18n('commands.help.response.list.fields.commands'), list.join('\n'))
|
||||
.setFooter(settings.footer, message.guild.iconURL())
|
||||
);
|
||||
|
@ -1,6 +1,8 @@
|
||||
const Command = require('../modules/commands/command');
|
||||
// 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');
|
||||
const { footer } = require('../utils/discord');
|
||||
const { letters } = require('../utils/emoji');
|
||||
const { wait } = require('../utils');
|
||||
@ -9,23 +11,23 @@ module.exports = class NewCommand extends Command {
|
||||
constructor(client) {
|
||||
const i18n = client.i18n.getLocale(client.config.locale);
|
||||
super(client, {
|
||||
internal: true,
|
||||
name: i18n('commands.new.name'),
|
||||
description: i18n('commands.new.description'),
|
||||
aliases: [
|
||||
i18n('commands.new.aliases.create'),
|
||||
i18n('commands.new.aliases.open'),
|
||||
i18n('commands.new.aliases.ticket'),
|
||||
i18n('commands.new.aliases.ticket')
|
||||
],
|
||||
process_args: false,
|
||||
args: [
|
||||
{
|
||||
name: i18n('commands.new.args.topic.name'),
|
||||
description: i18n('commands.new.args.topic.description'),
|
||||
example: i18n('commands.new.args.topic.example'),
|
||||
required: false,
|
||||
name: i18n('commands.new.args.topic.name'),
|
||||
required: false
|
||||
}
|
||||
]
|
||||
],
|
||||
description: i18n('commands.new.description'),
|
||||
internal: true,
|
||||
name: i18n('commands.new.name'),
|
||||
process_args: false
|
||||
});
|
||||
}
|
||||
|
||||
@ -114,11 +116,7 @@ module.exports = class NewCommand extends Command {
|
||||
}, 15000);
|
||||
};
|
||||
|
||||
const categories = await this.client.db.models.Category.findAndCountAll({
|
||||
where: {
|
||||
guild: message.guild.id
|
||||
}
|
||||
});
|
||||
const categories = await this.client.db.models.Category.findAndCountAll({ where: { guild: message.guild.id } });
|
||||
|
||||
if (categories.count === 0) {
|
||||
return await message.channel.send(
|
||||
@ -153,21 +151,21 @@ module.exports = class NewCommand extends Command {
|
||||
return user.id === message.author.id && allowed.includes(reaction.emoji.name);
|
||||
};
|
||||
|
||||
const collector = collector_message.createReactionCollector(collector_filter, {
|
||||
time: 30000
|
||||
});
|
||||
const collector = collector_message.createReactionCollector(collector_filter, { time: 30000 });
|
||||
|
||||
collector.on('collect', async (reaction) => {
|
||||
collector.on('collect', async reaction => {
|
||||
collector.stop();
|
||||
const index = letters_array.findIndex(value => value === reaction.emoji.name); // find where the letter is in the alphabet
|
||||
if (index === -1) return setTimeout(async () => {
|
||||
await collector_message.delete();
|
||||
}, 15000);
|
||||
if (index === -1) {
|
||||
return setTimeout(async () => {
|
||||
await collector_message.delete();
|
||||
}, 15000);
|
||||
}
|
||||
await collector_message.reactions.removeAll();
|
||||
create(categories.rows[index], collector_message); // create the ticket, passing the existing response message to be edited instead of creating a new one
|
||||
});
|
||||
|
||||
collector.on('end', async (collected) => {
|
||||
collector.on('end', async collected => {
|
||||
if (collected.size === 0) {
|
||||
await collector_message.reactions.removeAll();
|
||||
await collector_message.edit(
|
||||
|
@ -1,59 +1,59 @@
|
||||
const Command = require('../modules/commands/command');
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { MessageEmbed, Message } = require('discord.js');
|
||||
const { some, wait } = require('../utils');
|
||||
const {
|
||||
Message, // eslint-disable-line no-unused-vars
|
||||
MessageEmbed
|
||||
} = require('discord.js');
|
||||
const {
|
||||
some, wait
|
||||
} = require('../utils');
|
||||
const { emojify } = require('node-emoji');
|
||||
|
||||
module.exports = class PanelCommand extends Command {
|
||||
constructor(client) {
|
||||
const i18n = client.i18n.getLocale(client.config.locale);
|
||||
super(client, {
|
||||
internal: true,
|
||||
name: i18n('commands.panel.name'),
|
||||
description: i18n('commands.panel.description'),
|
||||
aliases: [],
|
||||
process_args: true,
|
||||
args: [
|
||||
{
|
||||
name: i18n('commands.panel.args.title.name'),
|
||||
alias: i18n('commands.panel.args.title.alias'),
|
||||
description: i18n('commands.panel.args.title.description'),
|
||||
example: i18n('commands.panel.args.title.example'),
|
||||
name: i18n('commands.panel.args.title.name'),
|
||||
required: false,
|
||||
// for arg parsing
|
||||
alias: i18n('commands.panel.args.title.alias'),
|
||||
type: String
|
||||
},
|
||||
{
|
||||
name: i18n('commands.panel.args.description.name'),
|
||||
alias: i18n('commands.panel.args.description.alias'),
|
||||
description: i18n('commands.panel.args.description.description'),
|
||||
example: i18n('commands.panel.args.description.example'),
|
||||
name: i18n('commands.panel.args.description.name'),
|
||||
required: true,
|
||||
// for arg parsing
|
||||
alias: i18n('commands.panel.args.description.alias'),
|
||||
type: String
|
||||
},
|
||||
{
|
||||
name: i18n('commands.panel.args.emoji.name'),
|
||||
alias: i18n('commands.panel.args.emoji.alias'),
|
||||
description: i18n('commands.panel.args.emoji.description'),
|
||||
example: i18n('commands.panel.args.emoji.example'),
|
||||
required: false,
|
||||
// for arg parsing
|
||||
alias: i18n('commands.panel.args.emoji.alias'),
|
||||
type: String,
|
||||
multiple: true,
|
||||
name: i18n('commands.panel.args.emoji.name'),
|
||||
required: false,
|
||||
type: String
|
||||
},
|
||||
{
|
||||
name: i18n('commands.panel.args.categories.name'),
|
||||
alias: i18n('commands.panel.args.categories.alias'),
|
||||
description: i18n('commands.panel.args.categories.description'),
|
||||
example: i18n('commands.panel.args.categories.example'),
|
||||
required: true,
|
||||
// for arg parsing
|
||||
alias: i18n('commands.panel.args.categories.alias'),
|
||||
type: String,
|
||||
multiple: true,
|
||||
name: i18n('commands.panel.args.categories.name'),
|
||||
required: true,
|
||||
type: String
|
||||
}
|
||||
],
|
||||
permissions: ['MANAGE_GUILD']
|
||||
description: i18n('commands.panel.description'),
|
||||
internal: true,
|
||||
name: i18n('commands.panel.name'),
|
||||
permissions: ['MANAGE_GUILD'],
|
||||
process_args: true
|
||||
});
|
||||
}
|
||||
|
||||
@ -72,21 +72,20 @@ module.exports = class PanelCommand extends Command {
|
||||
const settings = await message.guild.getSettings();
|
||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||
|
||||
if (!args[arg_emoji])
|
||||
args[arg_emoji] = [];
|
||||
|
||||
if (!args[arg_emoji]) args[arg_emoji] = [];
|
||||
|
||||
args[arg_emoji] = args[arg_emoji].map(emoji => emojify(emoji.replace(/\\/g, '')));
|
||||
|
||||
const invalid_category = await some(args[arg_categories], async id => {
|
||||
const cat_row = await this.client.db.models.Category.findOne({
|
||||
where: {
|
||||
id: id,
|
||||
guild: message.guild.id
|
||||
guild: message.guild.id,
|
||||
id
|
||||
}
|
||||
});
|
||||
return !cat_row;
|
||||
});
|
||||
|
||||
|
||||
if (invalid_category) {
|
||||
return await message.channel.send(
|
||||
new MessageEmbed()
|
||||
@ -99,36 +98,35 @@ module.exports = class PanelCommand extends Command {
|
||||
|
||||
let panel_channel,
|
||||
panel_message;
|
||||
|
||||
|
||||
let categories_map = args[arg_categories][0];
|
||||
|
||||
|
||||
const embed = new MessageEmbed()
|
||||
.setColor(settings.colour)
|
||||
.setFooter(settings.footer, message.guild.iconURL());
|
||||
|
||||
if (args[arg_title])
|
||||
embed.setTitle(args[arg_title]);
|
||||
|
||||
if (args[arg_title]) embed.setTitle(args[arg_title]);
|
||||
|
||||
if (args[arg_emoji].length === 0) {
|
||||
// reaction-less panel
|
||||
panel_channel = await message.guild.channels.create('create-a-ticket', {
|
||||
type: 'text',
|
||||
rateLimitPerUser: 30,
|
||||
permissionOverwrites: [
|
||||
{
|
||||
id: message.guild.roles.everyone,
|
||||
allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'READ_MESSAGE_HISTORY'],
|
||||
deny: ['ATTACH_FILES', 'EMBED_LINKS', 'ADD_REACTIONS']
|
||||
deny: ['ATTACH_FILES', 'EMBED_LINKS', 'ADD_REACTIONS'],
|
||||
id: message.guild.roles.everyone
|
||||
},
|
||||
{
|
||||
id: this.client.user.id,
|
||||
allow: ['EMBED_LINKS']
|
||||
allow: ['EMBED_LINKS'],
|
||||
id: this.client.user.id
|
||||
}
|
||||
],
|
||||
position: 1,
|
||||
reason: `${message.author.tag} created a new reaction-less panel`
|
||||
rateLimitPerUser: 30,
|
||||
reason: `${message.author.tag} created a new reaction-less panel`,
|
||||
type: 'text'
|
||||
});
|
||||
|
||||
|
||||
embed.setDescription(args[arg_description]);
|
||||
panel_message = await panel_channel.send(embed);
|
||||
|
||||
@ -145,20 +143,20 @@ module.exports = class PanelCommand extends Command {
|
||||
);
|
||||
} else {
|
||||
panel_channel = await message.guild.channels.create('create-a-ticket', {
|
||||
type: 'text',
|
||||
permissionOverwrites: [
|
||||
{
|
||||
id: message.guild.roles.everyone,
|
||||
allow: ['VIEW_CHANNEL', 'READ_MESSAGE_HISTORY'],
|
||||
deny: ['SEND_MESSAGES', 'ADD_REACTIONS']
|
||||
deny: ['SEND_MESSAGES', 'ADD_REACTIONS'],
|
||||
id: message.guild.roles.everyone
|
||||
},
|
||||
{
|
||||
id: this.client.user.id,
|
||||
allow: ['SEND_MESSAGES', 'EMBED_LINKS']
|
||||
allow: ['SEND_MESSAGES', 'EMBED_LINKS'],
|
||||
id: this.client.user.id
|
||||
}
|
||||
],
|
||||
position: 1,
|
||||
reason: `${message.author.tag} created a new panel`
|
||||
reason: `${message.author.tag} created a new panel`,
|
||||
type: 'text'
|
||||
});
|
||||
|
||||
if (args[arg_emoji].length === 1) {
|
||||
@ -172,13 +170,13 @@ module.exports = class PanelCommand extends Command {
|
||||
// multi category
|
||||
let description = '';
|
||||
categories_map = {};
|
||||
|
||||
|
||||
for (const i in args[arg_emoji]) {
|
||||
categories_map[args[arg_emoji][i]] = args[arg_categories][i];
|
||||
const cat_row = await this.client.db.models.Category.findOne({
|
||||
where: {
|
||||
id: args[arg_categories][i],
|
||||
guild: message.guild.id
|
||||
guild: message.guild.id,
|
||||
id: args[arg_categories][i]
|
||||
}
|
||||
});
|
||||
description += `\n> ${args[arg_emoji][i]} | ${cat_row.name}`;
|
||||
@ -191,7 +189,7 @@ module.exports = class PanelCommand extends Command {
|
||||
await panel_message.react(emoji);
|
||||
await wait(1000); // 1 reaction per second rate-limit
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
this.client.log.info(`${message.author.tag} has created a new panel`);
|
||||
@ -204,7 +202,7 @@ module.exports = class PanelCommand extends Command {
|
||||
categories: categories_map,
|
||||
channel: panel_channel.id,
|
||||
guild: message.guild.id,
|
||||
message: panel_message.id,
|
||||
message: panel_message.id
|
||||
});
|
||||
}
|
||||
};
|
@ -1,30 +1,32 @@
|
||||
const Command = require('../modules/commands/command');
|
||||
// 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');
|
||||
|
||||
module.exports = class RemoveCommand extends Command {
|
||||
constructor(client) {
|
||||
const i18n = client.i18n.getLocale(client.config.locale);
|
||||
super(client, {
|
||||
internal: true,
|
||||
name: i18n('commands.remove.name'),
|
||||
description: i18n('commands.remove.description'),
|
||||
aliases: [],
|
||||
process_args: false,
|
||||
args: [
|
||||
{
|
||||
name: i18n('commands.remove.args.member.name'),
|
||||
description: i18n('commands.remove.args.member.description'),
|
||||
example: i18n('commands.remove.args.member.example'),
|
||||
required: true,
|
||||
name: i18n('commands.remove.args.member.name'),
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: i18n('commands.remove.args.ticket.name'),
|
||||
description: i18n('commands.remove.args.ticket.description'),
|
||||
example: i18n('commands.remove.args.ticket.example'),
|
||||
required: false,
|
||||
name: i18n('commands.remove.args.ticket.name'),
|
||||
required: false
|
||||
}
|
||||
]
|
||||
],
|
||||
description: i18n('commands.remove.description'),
|
||||
internal: true,
|
||||
name: i18n('commands.remove.name'),
|
||||
process_args: false
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,22 +1,24 @@
|
||||
const Command = require('../modules/commands/command');
|
||||
const fetch = require('node-fetch');
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { MessageAttachment, Message } = require('discord.js');
|
||||
const {
|
||||
Message, // eslint-disable-line no-unused-vars
|
||||
MessageAttachment
|
||||
} = require('discord.js');
|
||||
const { Validator } = require('jsonschema');
|
||||
|
||||
module.exports = class SettingsCommand extends Command {
|
||||
constructor(client) {
|
||||
const i18n = client.i18n.getLocale(client.config.locale);
|
||||
super(client, {
|
||||
aliases: [
|
||||
i18n('commands.settings.aliases.config')
|
||||
],
|
||||
args: [],
|
||||
description: i18n('commands.settings.description'),
|
||||
internal: true,
|
||||
name: i18n('commands.settings.name'),
|
||||
description: i18n('commands.settings.description'),
|
||||
aliases: [
|
||||
i18n('commands.settings.aliases.config'),
|
||||
],
|
||||
process_args: false,
|
||||
args: [],
|
||||
permissions: ['MANAGE_GUILD']
|
||||
permissions: ['MANAGE_GUILD'],
|
||||
process_args: false
|
||||
});
|
||||
|
||||
this.schema = require('./extra/settings.schema.json');
|
||||
@ -40,7 +42,9 @@ module.exports = class SettingsCommand extends Command {
|
||||
this.client.log.info(`Downloading settings for "${message.guild.name}"`);
|
||||
const data = await (await fetch(attachments[0].url)).json();
|
||||
|
||||
const { valid, errors } = this.v.validate(data, this.schema);
|
||||
const {
|
||||
valid, errors
|
||||
} = this.v.validate(data, this.schema);
|
||||
|
||||
if (!valid) {
|
||||
this.client.log.warn('Settings validation error');
|
||||
@ -60,11 +64,7 @@ module.exports = class SettingsCommand extends Command {
|
||||
for (const c of data.categories) {
|
||||
if (c.id) {
|
||||
// existing category
|
||||
const cat_row = await this.client.db.models.Category.findOne({
|
||||
where: {
|
||||
id: c.id
|
||||
}
|
||||
});
|
||||
const cat_row = await this.client.db.models.Category.findOne({ where: { id: c.id } });
|
||||
cat_row.claiming = c.claiming;
|
||||
cat_row.image = c.image;
|
||||
cat_row.max_per_member = c.max_per_member;
|
||||
@ -81,15 +81,14 @@ module.exports = class SettingsCommand extends Command {
|
||||
const cat_channel = await this.client.channels.fetch(c.id);
|
||||
|
||||
if (cat_channel) {
|
||||
if (cat_channel.name !== c.name)
|
||||
await cat_channel.setName(c.name, `Tickets category updated by ${message.author.tag}`);
|
||||
if (cat_channel.name !== c.name) await cat_channel.setName(c.name, `Tickets category updated by ${message.author.tag}`);
|
||||
|
||||
for (const r of c.roles) {
|
||||
await cat_channel.updateOverwrite(r, {
|
||||
VIEW_CHANNEL: true,
|
||||
ATTACH_FILES: true,
|
||||
READ_MESSAGE_HISTORY: true,
|
||||
SEND_MESSAGES: true,
|
||||
ATTACH_FILES: true
|
||||
VIEW_CHANNEL: true
|
||||
}, `Tickets category updated by ${message.author.tag}`);
|
||||
}
|
||||
}
|
||||
@ -97,33 +96,31 @@ module.exports = class SettingsCommand extends Command {
|
||||
// create a new category
|
||||
const allowed_permissions = ['VIEW_CHANNEL', 'READ_MESSAGE_HISTORY', 'SEND_MESSAGES', 'EMBED_LINKS', 'ATTACH_FILES'];
|
||||
const cat_channel = await message.guild.channels.create(c.name, {
|
||||
type: 'category',
|
||||
reason: `Tickets category created by ${message.author.tag}`,
|
||||
position: 1,
|
||||
permissionOverwrites: [
|
||||
...[
|
||||
{
|
||||
id: message.guild.roles.everyone,
|
||||
deny: ['VIEW_CHANNEL']
|
||||
deny: ['VIEW_CHANNEL'],
|
||||
id: message.guild.roles.everyone
|
||||
},
|
||||
{
|
||||
id: this.client.user.id,
|
||||
allow: allowed_permissions
|
||||
allow: allowed_permissions,
|
||||
id: this.client.user.id
|
||||
}
|
||||
],
|
||||
...c.roles.map(r => {
|
||||
return {
|
||||
id: r,
|
||||
allow: allowed_permissions
|
||||
};
|
||||
})
|
||||
]
|
||||
...c.roles.map(r => ({
|
||||
allow: allowed_permissions,
|
||||
id: r
|
||||
}))
|
||||
],
|
||||
position: 1,
|
||||
reason: `Tickets category created by ${message.author.tag}`,
|
||||
type: 'category'
|
||||
});
|
||||
|
||||
await this.client.db.models.Category.create({
|
||||
id: cat_channel.id,
|
||||
claiming: c.claiming,
|
||||
guild: message.guild.id,
|
||||
id: cat_channel.id,
|
||||
image: c.image,
|
||||
max_per_member: c.max_per_member,
|
||||
name: c.name,
|
||||
@ -141,11 +138,11 @@ module.exports = class SettingsCommand extends Command {
|
||||
for (const survey in data.surveys) {
|
||||
const survey_data = {
|
||||
guild: message.guild.id,
|
||||
name: survey,
|
||||
name: survey
|
||||
};
|
||||
const [s_row] = await this.client.db.models.Survey.findOrCreate({
|
||||
where: survey_data,
|
||||
defaults: survey_data
|
||||
defaults: survey_data,
|
||||
where: survey_data
|
||||
});
|
||||
s_row.questions = data.surveys[survey];
|
||||
await s_row.save();
|
||||
@ -156,35 +153,25 @@ module.exports = class SettingsCommand extends Command {
|
||||
} else {
|
||||
// upload settings as json to be edited
|
||||
|
||||
const categories = await this.client.db.models.Category.findAll({
|
||||
where: {
|
||||
guild: message.guild.id
|
||||
}
|
||||
});
|
||||
|
||||
const surveys = await this.client.db.models.Survey.findAll({
|
||||
where: {
|
||||
guild: message.guild.id
|
||||
}
|
||||
});
|
||||
const categories = await this.client.db.models.Category.findAll({ where: { guild: message.guild.id } });
|
||||
|
||||
const surveys = await this.client.db.models.Survey.findAll({ where: { guild: message.guild.id } });
|
||||
|
||||
const data = {
|
||||
categories: categories.map(c => {
|
||||
return {
|
||||
id: c.id,
|
||||
claiming: c.claiming,
|
||||
image: c.image,
|
||||
max_per_member: c.max_per_member,
|
||||
name: c.name,
|
||||
name_format: c.name_format,
|
||||
opening_message: c.opening_message,
|
||||
opening_questions: c.opening_questions,
|
||||
ping: c.ping,
|
||||
require_topic: c.require_topic,
|
||||
roles: c.roles,
|
||||
survey: c.survey
|
||||
};
|
||||
}),
|
||||
categories: categories.map(c => ({
|
||||
claiming: c.claiming,
|
||||
id: c.id,
|
||||
image: c.image,
|
||||
max_per_member: c.max_per_member,
|
||||
name: c.name,
|
||||
name_format: c.name_format,
|
||||
opening_message: c.opening_message,
|
||||
opening_questions: c.opening_questions,
|
||||
ping: c.ping,
|
||||
require_topic: c.require_topic,
|
||||
roles: c.roles,
|
||||
survey: c.survey
|
||||
})),
|
||||
colour: settings.colour,
|
||||
command_prefix: settings.command_prefix,
|
||||
error_colour: settings.error_colour,
|
||||
@ -197,7 +184,9 @@ module.exports = class SettingsCommand extends Command {
|
||||
};
|
||||
|
||||
for (const survey in surveys) {
|
||||
const { name, questions } = surveys[survey];
|
||||
const {
|
||||
name, questions
|
||||
} = surveys[survey];
|
||||
data.surveys[name] = questions;
|
||||
}
|
||||
|
||||
@ -206,9 +195,7 @@ module.exports = class SettingsCommand extends Command {
|
||||
`Settings for ${message.guild.name}.json`
|
||||
);
|
||||
|
||||
return await message.channel.send({
|
||||
files: [attachment]
|
||||
});
|
||||
return await message.channel.send({ files: [attachment] });
|
||||
}
|
||||
}
|
||||
};
|
@ -1,24 +1,24 @@
|
||||
const Command = require('../modules/commands/command');
|
||||
const Keyv = require('keyv');
|
||||
// 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');
|
||||
|
||||
module.exports = class StatsCommand extends Command {
|
||||
constructor(client) {
|
||||
const i18n = client.i18n.getLocale(client.config.locale);
|
||||
super(client, {
|
||||
aliases: [],
|
||||
args: [],
|
||||
description: i18n('commands.stats.description'),
|
||||
internal: true,
|
||||
name: i18n('commands.stats.name'),
|
||||
description: i18n('commands.stats.description'),
|
||||
aliases: [],
|
||||
process_args: false,
|
||||
args: [],
|
||||
staff_only: true
|
||||
});
|
||||
|
||||
this.cache = new Keyv({
|
||||
namespace: 'cache.commands.stats'
|
||||
});
|
||||
this.cache = new Keyv({ namespace: 'cache.commands.stats' });
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,27 +35,19 @@ module.exports = class StatsCommand extends Command {
|
||||
let stats = await this.cache.get(message.guild.id);
|
||||
|
||||
if (!stats) {
|
||||
const tickets = await this.client.db.models.Ticket.findAndCountAll({
|
||||
where: {
|
||||
guild: message.guild.id
|
||||
}
|
||||
});
|
||||
const tickets = await this.client.db.models.Ticket.findAndCountAll({ where: { guild: message.guild.id } });
|
||||
stats = { // maths
|
||||
tickets: tickets.count,
|
||||
messages: settings.log_messages
|
||||
? await messages.rows
|
||||
.reduce(async (acc, row) => (await this.client.db.models.Ticket.findOne({
|
||||
where: {
|
||||
id: row.ticket
|
||||
}
|
||||
})).guild === message.guild.id
|
||||
.reduce(async (acc, row) => (await this.client.db.models.Ticket.findOne({ where: { id: row.ticket } }))
|
||||
.guild === message.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)
|
||||
: acc, 0) / tickets.count),
|
||||
tickets: tickets.count
|
||||
};
|
||||
await this.cache.set(message.guild.id, stats, 60 * 60 * 1000); // cache for an hour
|
||||
}
|
||||
@ -67,7 +59,7 @@ module.exports = class StatsCommand extends Command {
|
||||
.addField(i18n('commands.stats.fields.tickets'), 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, message.guild.iconURL());
|
||||
|
||||
|
||||
if (stats.messages) guild_embed.addField(i18n('commands.stats.fields.messages'), stats.messages, true);
|
||||
|
||||
await message.channel.send(guild_embed);
|
||||
|
@ -1,6 +1,10 @@
|
||||
const Command = require('../modules/commands/command');
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { MessageAttachment, MessageEmbed, Message } = require('discord.js');
|
||||
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');
|
||||
@ -9,21 +13,21 @@ module.exports = class SurveyCommand extends Command {
|
||||
constructor(client) {
|
||||
const i18n = client.i18n.getLocale(client.config.locale);
|
||||
super(client, {
|
||||
internal: true,
|
||||
name: i18n('commands.survey.name'),
|
||||
description: i18n('commands.survey.description'),
|
||||
aliases: [
|
||||
i18n('commands.survey.aliases.surveys')
|
||||
],
|
||||
process_args: false,
|
||||
args: [
|
||||
{
|
||||
name: i18n('commands.survey.args.survey.name'),
|
||||
description: i18n('commands.survey.args.survey.description'),
|
||||
example: i18n('commands.survey.args.survey.example'),
|
||||
required: false,
|
||||
name: i18n('commands.survey.args.survey.name'),
|
||||
required: false
|
||||
}
|
||||
],
|
||||
description: i18n('commands.survey.description'),
|
||||
internal: true,
|
||||
name: i18n('commands.survey.name'),
|
||||
process_args: false,
|
||||
staff_only: true
|
||||
});
|
||||
}
|
||||
@ -39,49 +43,41 @@ module.exports = class SurveyCommand extends Command {
|
||||
|
||||
const survey = await this.client.db.models.Survey.findOne({
|
||||
where: {
|
||||
name: args,
|
||||
guild: message.guild.id
|
||||
guild: message.guild.id,
|
||||
name: args
|
||||
}
|
||||
});
|
||||
|
||||
if (survey) {
|
||||
const { rows: responses, count } = await this.client.db.models.SurveyResponse.findAndCountAll({
|
||||
where: {
|
||||
survey: survey.id
|
||||
}
|
||||
});
|
||||
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
|
||||
}
|
||||
});
|
||||
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'
|
||||
});
|
||||
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, {
|
||||
survey: survey.name.charAt(0).toUpperCase() + survey.name.slice(1),
|
||||
columns: survey.questions,
|
||||
count: {
|
||||
responses: count,
|
||||
users: users.size
|
||||
},
|
||||
columns: survey.questions,
|
||||
responses
|
||||
responses,
|
||||
survey: survey.name.charAt(0).toUpperCase() + survey.name.slice(1)
|
||||
});
|
||||
|
||||
const attachment = new MessageAttachment(
|
||||
@ -89,15 +85,9 @@ module.exports = class SurveyCommand extends Command {
|
||||
`${survey.name}.html`
|
||||
);
|
||||
|
||||
return await message.channel.send({
|
||||
files: [attachment]
|
||||
});
|
||||
return await message.channel.send({ files: [attachment] });
|
||||
} else {
|
||||
const surveys = await this.client.db.models.Survey.findAll({
|
||||
where: {
|
||||
guild: message.guild.id
|
||||
}
|
||||
});
|
||||
const surveys = await this.client.db.models.Survey.findAll({ where: { guild: message.guild.id } });
|
||||
|
||||
const list = surveys.map(s => `❯ **\`${s.name}\`**`);
|
||||
return await message.channel.send(
|
||||
|
@ -1,6 +1,8 @@
|
||||
const Command = require('../modules/commands/command');
|
||||
// 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');
|
||||
const { parseArgsStringToArgv: argv } = require('string-argv');
|
||||
const parseArgs = require('command-line-args');
|
||||
|
||||
@ -8,41 +10,37 @@ module.exports = class TagCommand extends Command {
|
||||
constructor(client) {
|
||||
const i18n = client.i18n.getLocale(client.config.locale);
|
||||
super(client, {
|
||||
internal: true,
|
||||
name: i18n('commands.tag.name'),
|
||||
description: i18n('commands.tag.description'),
|
||||
aliases: [
|
||||
i18n('commands.tag.aliases.faq'),
|
||||
i18n('commands.tag.aliases.t'),
|
||||
i18n('commands.tag.aliases.tags'),
|
||||
i18n('commands.tag.aliases.tags')
|
||||
],
|
||||
process_args: false,
|
||||
args: [
|
||||
{
|
||||
name: i18n('commands.tag.args.tag.name'),
|
||||
description: i18n('commands.tag.args.command.description'),
|
||||
example: i18n('commands.tag.args.tag.example'),
|
||||
required: false,
|
||||
name: i18n('commands.tag.args.tag.name'),
|
||||
required: false
|
||||
}
|
||||
],
|
||||
description: i18n('commands.tag.description'),
|
||||
internal: true,
|
||||
name: i18n('commands.tag.name'),
|
||||
process_args: false,
|
||||
staff_only: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Message} message
|
||||
* @param {string} args
|
||||
* @param {Message} message
|
||||
* @param {string} args
|
||||
* @returns {Promise<void|any>}
|
||||
*/
|
||||
async execute(message, args) {
|
||||
const settings = await message.guild.getSettings();
|
||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||
|
||||
const t_row = await this.client.db.models.Ticket.findOne({
|
||||
where: {
|
||||
id: message.channel.id
|
||||
}
|
||||
});
|
||||
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: message.channel.id } });
|
||||
|
||||
args = args.split(/\s/g); // convert to an array
|
||||
const tag_name = args.shift(); // shift the first element
|
||||
@ -63,14 +61,12 @@ module.exports = class TagCommand extends Command {
|
||||
);
|
||||
}
|
||||
|
||||
let expected = placeholders
|
||||
const expected = placeholders
|
||||
.filter(p => p.startsWith(':'))
|
||||
.map(p => {
|
||||
return {
|
||||
name: p.substr(1, p.length),
|
||||
type: String,
|
||||
};
|
||||
});
|
||||
.map(p => ({
|
||||
name: p.substr(1, p.length),
|
||||
type: String
|
||||
}));
|
||||
|
||||
if (expected.length >= 1) {
|
||||
try {
|
||||
@ -107,7 +103,7 @@ module.exports = class TagCommand extends Command {
|
||||
}
|
||||
|
||||
// note that this regex is slightly different to the other
|
||||
const text = tag.replace(/(?<!\\){{1,2}\s?:?([A-Za-z0-9._]+)\s?(?<!\\)}{1,2}/gi, ($, $1) => this.client.i18n.resolve(args, $1));
|
||||
const text = tag.replace(/(?<!\\){{1,2}\s?:?([A-Za-z0-9._]+)\s?(?<!\\)}{1,2}/gi, (_$, $1) => this.client.i18n.resolve(args, $1));
|
||||
return await message.channel.send(
|
||||
new MessageEmbed()
|
||||
.setColor(settings.colour)
|
||||
|
@ -1,24 +1,26 @@
|
||||
const Command = require('../modules/commands/command');
|
||||
// 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');
|
||||
|
||||
module.exports = class TopicCommand extends Command {
|
||||
constructor(client) {
|
||||
const i18n = client.i18n.getLocale(client.config.locale);
|
||||
super(client, {
|
||||
internal: true,
|
||||
name: i18n('commands.topic.name'),
|
||||
description: i18n('commands.topic.description'),
|
||||
aliases: [],
|
||||
process_args: false,
|
||||
args: [
|
||||
{
|
||||
name: i18n('commands.topic.args.new_topic.name'),
|
||||
description: i18n('commands.topic.args.new_topic.description'),
|
||||
example: i18n('commands.topic.args.new_topic.example'),
|
||||
required: true,
|
||||
name: i18n('commands.topic.args.new_topic.name'),
|
||||
required: true
|
||||
}
|
||||
]
|
||||
],
|
||||
description: i18n('commands.topic.description'),
|
||||
internal: true,
|
||||
name: i18n('commands.topic.name'),
|
||||
process_args: false
|
||||
});
|
||||
}
|
||||
|
||||
@ -31,11 +33,7 @@ module.exports = class TopicCommand extends Command {
|
||||
const settings = await message.guild.getSettings();
|
||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||
|
||||
const t_row = await this.client.db.models.Ticket.findOne({
|
||||
where: {
|
||||
id: message.channel.id
|
||||
}
|
||||
});
|
||||
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: message.channel.id } });
|
||||
|
||||
if (!t_row) {
|
||||
return await message.channel.send(
|
||||
@ -47,18 +45,12 @@ module.exports = class TopicCommand extends Command {
|
||||
);
|
||||
}
|
||||
|
||||
await t_row.update({
|
||||
topic: this.client.cryptr.encrypt(args)
|
||||
});
|
||||
await t_row.update({ topic: this.client.cryptr.encrypt(args) });
|
||||
|
||||
const member = await message.guild.members.fetch(t_row.creator);
|
||||
/* await */message.channel.setTopic(`${member} | ${args}`, { reason: 'User updated ticket topic' });
|
||||
|
||||
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 } });
|
||||
const description = cat_row.opening_message
|
||||
.replace(/{+\s?(user)?name\s?}+/gi, member.displayName)
|
||||
.replace(/{+\s?(tag|ping|mention)?\s?}+/gi, member.user.toString());
|
||||
|
@ -1,42 +1,42 @@
|
||||
module.exports = {
|
||||
sqlite: {
|
||||
name: 'SQLite',
|
||||
dialect: 'sqlite',
|
||||
packages: ['sqlite3'],
|
||||
},
|
||||
mysql: {
|
||||
name: 'MySQL',
|
||||
dialect: 'mysql',
|
||||
packages: ['mysql2']
|
||||
},
|
||||
maria: {
|
||||
name: 'MariaDB',
|
||||
dialect: 'mariadb',
|
||||
name: 'MariaDB',
|
||||
package: ['mariadb']
|
||||
},
|
||||
mariadb: {
|
||||
name: 'MariaDB',
|
||||
dialect: 'mariadb',
|
||||
name: 'MariaDB',
|
||||
package: ['mariadb']
|
||||
},
|
||||
microsoft: {
|
||||
dialect: 'mssql',
|
||||
name: 'Microsoft SQL',
|
||||
packages: ['tedious']
|
||||
},
|
||||
mysql: {
|
||||
dialect: 'mysql',
|
||||
name: 'MySQL',
|
||||
packages: ['mysql2']
|
||||
},
|
||||
postgre: { // this is wrong
|
||||
name: 'PostgreSQL',
|
||||
dialect: 'postgres',
|
||||
name: 'PostgreSQL',
|
||||
packages: ['pg', 'pg-hstore']
|
||||
},
|
||||
postgres: {
|
||||
name: 'PostgreSQL',
|
||||
dialect: 'postgres',
|
||||
name: 'PostgreSQL',
|
||||
packages: ['pg', 'pg-hstore']
|
||||
},
|
||||
postgresql: {
|
||||
name: 'PostgreSQL',
|
||||
dialect: 'postgres',
|
||||
name: 'PostgreSQL',
|
||||
packages: ['pg', 'pg-hstore']
|
||||
},
|
||||
microsoft: {
|
||||
name: 'Microsoft SQL',
|
||||
dialect: 'mssql',
|
||||
packages: ['tedious']
|
||||
},
|
||||
sqlite: {
|
||||
dialect: 'sqlite',
|
||||
name: 'SQLite',
|
||||
packages: ['sqlite3']
|
||||
}
|
||||
};
|
@ -3,7 +3,7 @@ const fs = require('fs');
|
||||
const { path } = require('../utils/fs');
|
||||
const types = require('./dialects');
|
||||
|
||||
module.exports = async (client) => {
|
||||
module.exports = async client => {
|
||||
|
||||
const {
|
||||
DB_TYPE,
|
||||
@ -36,8 +36,8 @@ module.exports = async (client) => {
|
||||
client.log.info('Using SQLite storage');
|
||||
sequelize = new Sequelize({
|
||||
dialect: types[type].dialect,
|
||||
storage: path('./user/database.sqlite'),
|
||||
logging: text => client.log.debug(text)
|
||||
logging: text => client.log.debug(text),
|
||||
storage: path('./user/database.sqlite')
|
||||
});
|
||||
client.log.warn('SQLite is not sufficient for a production environment if you want to use ticket archives. You should disable "log_messages" in your servers\' settings or use a different database.');
|
||||
} else {
|
||||
@ -45,8 +45,8 @@ module.exports = async (client) => {
|
||||
sequelize = new Sequelize(DB_NAME, DB_USER, DB_PASS, {
|
||||
dialect: types[type].dialect,
|
||||
host: DB_HOST,
|
||||
port: DB_PORT,
|
||||
logging: text => client.log.debug(text)
|
||||
logging: text => client.log.debug(text),
|
||||
port: DB_PORT
|
||||
});
|
||||
}
|
||||
|
||||
@ -66,11 +66,7 @@ module.exports = async (client) => {
|
||||
require(`./models/${model}`)(client, sequelize);
|
||||
}
|
||||
|
||||
sequelize.sync({
|
||||
alter: {
|
||||
drop: false
|
||||
}
|
||||
});
|
||||
sequelize.sync({ alter: { drop: false } });
|
||||
|
||||
return sequelize;
|
||||
};
|
@ -2,67 +2,65 @@ const { DataTypes } = require('sequelize');
|
||||
module.exports = ({ config }, sequelize) => {
|
||||
const { DB_TABLE_PREFIX } = process.env;
|
||||
sequelize.define('Category', {
|
||||
id: {
|
||||
type: DataTypes.CHAR(19),
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
},
|
||||
claiming: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false,
|
||||
type: DataTypes.BOOLEAN
|
||||
},
|
||||
guild: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: DB_TABLE_PREFIX + 'guilds',
|
||||
key: 'id'
|
||||
key: 'id',
|
||||
model: DB_TABLE_PREFIX + 'guilds'
|
||||
},
|
||||
type: DataTypes.CHAR(19),
|
||||
unique: 'name-guild'
|
||||
},
|
||||
id: {
|
||||
allowNull: false,
|
||||
primaryKey: true,
|
||||
type: DataTypes.CHAR(19)
|
||||
},
|
||||
image: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
max_per_member: {
|
||||
type: DataTypes.INTEGER,
|
||||
defaultValue: 1
|
||||
defaultValue: 1,
|
||||
type: DataTypes.INTEGER
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
type: DataTypes.STRING,
|
||||
unique: 'name-guild'
|
||||
},
|
||||
name_format: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: config.defaults.name_format
|
||||
defaultValue: config.defaults.name_format,
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
opening_message: {
|
||||
type: DataTypes.STRING,
|
||||
defaultValue: config.defaults.opening_message,
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
opening_questions: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: true,
|
||||
type: DataTypes.JSON
|
||||
},
|
||||
ping: {
|
||||
type: DataTypes.JSON,
|
||||
defaultValue: [],
|
||||
type: DataTypes.JSON
|
||||
},
|
||||
require_topic: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false,
|
||||
type: DataTypes.BOOLEAN
|
||||
},
|
||||
roles: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: false,
|
||||
type: DataTypes.JSON
|
||||
},
|
||||
survey: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
type: DataTypes.STRING
|
||||
}
|
||||
}, {
|
||||
tableName: DB_TABLE_PREFIX + 'categories'
|
||||
});
|
||||
}, { tableName: DB_TABLE_PREFIX + 'categories' });
|
||||
};
|
@ -1,23 +1,21 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
module.exports = (client, sequelize) => {
|
||||
module.exports = (_client, sequelize) => {
|
||||
const { DB_TABLE_PREFIX } = process.env;
|
||||
sequelize.define('ChannelEntity', {
|
||||
channel: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false,
|
||||
type: DataTypes.CHAR(19),
|
||||
unique: 'channel-ticket'
|
||||
},
|
||||
name: DataTypes.TEXT,
|
||||
ticket: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false,
|
||||
unique: 'channel-ticket',
|
||||
references: {
|
||||
model: DB_TABLE_PREFIX + 'tickets',
|
||||
key: 'id'
|
||||
key: 'id',
|
||||
model: DB_TABLE_PREFIX + 'tickets'
|
||||
},
|
||||
},
|
||||
}, {
|
||||
tableName: DB_TABLE_PREFIX + 'channel_entities'
|
||||
});
|
||||
type: DataTypes.CHAR(19),
|
||||
unique: 'channel-ticket'
|
||||
}
|
||||
}, { tableName: DB_TABLE_PREFIX + 'channel_entities' });
|
||||
};
|
@ -2,48 +2,47 @@ const { DataTypes } = require('sequelize');
|
||||
module.exports = ({ config }, sequelize) => {
|
||||
const { DB_TABLE_PREFIX } = process.env;
|
||||
sequelize.define('Guild', {
|
||||
id: {
|
||||
type: DataTypes.CHAR(19),
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
},
|
||||
|
||||
blacklist: {
|
||||
type: DataTypes.JSON,
|
||||
defaultValue: [],
|
||||
type: DataTypes.JSON
|
||||
},
|
||||
colour: {
|
||||
type: DataTypes.STRING,
|
||||
defaultValue: config.defaults.colour
|
||||
defaultValue: config.defaults.colour,
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
command_prefix: {
|
||||
type: DataTypes.STRING,
|
||||
defaultValue: config.defaults.command_prefix
|
||||
defaultValue: config.defaults.command_prefix,
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
error_colour: {
|
||||
type: DataTypes.STRING,
|
||||
defaultValue: 'RED'
|
||||
defaultValue: 'RED',
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
footer: {
|
||||
type: DataTypes.STRING,
|
||||
defaultValue: 'Discord Tickets by eartharoid'
|
||||
defaultValue: 'Discord Tickets by eartharoid',
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
id: {
|
||||
allowNull: false,
|
||||
primaryKey: true,
|
||||
type: DataTypes.CHAR(19)
|
||||
},
|
||||
locale: {
|
||||
type: DataTypes.STRING,
|
||||
defaultValue: config.locale
|
||||
defaultValue: config.locale,
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
log_messages: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: config.defaults.log_messages
|
||||
defaultValue: config.defaults.log_messages,
|
||||
type: DataTypes.BOOLEAN
|
||||
},
|
||||
success_colour: {
|
||||
type: DataTypes.STRING,
|
||||
defaultValue: 'GREEN'
|
||||
defaultValue: 'GREEN',
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
tags: {
|
||||
type: DataTypes.JSON,
|
||||
defaultValue: {}
|
||||
defaultValue: {},
|
||||
type: DataTypes.JSON
|
||||
}
|
||||
}, {
|
||||
tableName: DB_TABLE_PREFIX + 'guilds'
|
||||
});
|
||||
}, { tableName: DB_TABLE_PREFIX + 'guilds' });
|
||||
};
|
@ -1,37 +1,36 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
module.exports = (client, sequelize) => {
|
||||
module.exports = (_client, sequelize) => {
|
||||
const { DB_TABLE_PREFIX } = process.env;
|
||||
sequelize.define('Message', {
|
||||
id: {
|
||||
type: DataTypes.CHAR(19),
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
},
|
||||
|
||||
author: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false,
|
||||
type: DataTypes.CHAR(19)
|
||||
},
|
||||
data: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false,
|
||||
type: DataTypes.TEXT
|
||||
},
|
||||
deleted: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false,
|
||||
type: DataTypes.BOOLEAN
|
||||
},
|
||||
edited: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false,
|
||||
type: DataTypes.BOOLEAN
|
||||
},
|
||||
id: {
|
||||
allowNull: false,
|
||||
primaryKey: true,
|
||||
type: DataTypes.CHAR(19)
|
||||
},
|
||||
ticket: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: DB_TABLE_PREFIX + 'tickets',
|
||||
key: 'id'
|
||||
key: 'id',
|
||||
model: DB_TABLE_PREFIX + 'tickets'
|
||||
},
|
||||
},
|
||||
}, {
|
||||
tableName: DB_TABLE_PREFIX + 'messages'
|
||||
});
|
||||
type: DataTypes.CHAR(19)
|
||||
}
|
||||
}, { tableName: DB_TABLE_PREFIX + 'messages' });
|
||||
};
|
@ -3,26 +3,24 @@ module.exports = (client, sequelize) => {
|
||||
const { DB_TABLE_PREFIX } = process.env;
|
||||
sequelize.define('Panel', {
|
||||
categories: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
type: DataTypes.JSON
|
||||
},
|
||||
channel: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
type: DataTypes.CHAR(19)
|
||||
},
|
||||
guild: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: DB_TABLE_PREFIX + 'guilds',
|
||||
key: 'id'
|
||||
}
|
||||
key: 'id',
|
||||
model: DB_TABLE_PREFIX + 'guilds'
|
||||
},
|
||||
type: DataTypes.CHAR(19)
|
||||
},
|
||||
message: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false
|
||||
allowNull: false,
|
||||
type: DataTypes.CHAR(19)
|
||||
}
|
||||
}, {
|
||||
tableName: DB_TABLE_PREFIX + 'panels'
|
||||
});
|
||||
}, { tableName: DB_TABLE_PREFIX + 'panels' });
|
||||
};
|
@ -3,25 +3,23 @@ module.exports = (client, sequelize) => {
|
||||
const { DB_TABLE_PREFIX } = process.env;
|
||||
sequelize.define('RoleEntity', {
|
||||
colour: {
|
||||
type: DataTypes.CHAR(6),
|
||||
defaultValue: '7289DA',
|
||||
type: DataTypes.CHAR(6)
|
||||
},
|
||||
name: DataTypes.TEXT,
|
||||
role: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false,
|
||||
type: DataTypes.CHAR(19),
|
||||
unique: 'role-ticket'
|
||||
},
|
||||
ticket: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false,
|
||||
unique: 'role-ticket',
|
||||
references: {
|
||||
model: DB_TABLE_PREFIX + 'tickets',
|
||||
key: 'id'
|
||||
key: 'id',
|
||||
model: DB_TABLE_PREFIX + 'tickets'
|
||||
},
|
||||
},
|
||||
}, {
|
||||
tableName: DB_TABLE_PREFIX + 'role_entities'
|
||||
});
|
||||
type: DataTypes.CHAR(19),
|
||||
unique: 'role-ticket'
|
||||
}
|
||||
}, { tableName: DB_TABLE_PREFIX + 'role_entities' });
|
||||
};
|
@ -3,24 +3,22 @@ module.exports = (client, sequelize) => {
|
||||
const { DB_TABLE_PREFIX } = process.env;
|
||||
sequelize.define('Survey', {
|
||||
guild: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: DB_TABLE_PREFIX + 'guilds',
|
||||
key: 'id'
|
||||
key: 'id',
|
||||
model: DB_TABLE_PREFIX + 'guilds'
|
||||
},
|
||||
type: DataTypes.CHAR(19),
|
||||
unique: 'name-guild'
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
type: DataTypes.STRING,
|
||||
unique: 'name-guild'
|
||||
},
|
||||
questions: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: true,
|
||||
},
|
||||
}, {
|
||||
tableName: DB_TABLE_PREFIX + 'surveys'
|
||||
});
|
||||
type: DataTypes.JSON
|
||||
}
|
||||
}, { tableName: DB_TABLE_PREFIX + 'surveys' });
|
||||
};
|
@ -3,28 +3,26 @@ module.exports = (client, sequelize) => {
|
||||
const { DB_TABLE_PREFIX } = process.env;
|
||||
sequelize.define('SurveyResponse', {
|
||||
answers: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: true,
|
||||
type: DataTypes.JSON
|
||||
},
|
||||
survey: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
unique: 'survey-ticket',
|
||||
references: {
|
||||
model: DB_TABLE_PREFIX + 'surveys',
|
||||
key: 'id'
|
||||
key: 'id',
|
||||
model: DB_TABLE_PREFIX + 'surveys'
|
||||
},
|
||||
type: DataTypes.INTEGER,
|
||||
unique: 'survey-ticket'
|
||||
},
|
||||
ticket: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false,
|
||||
unique: 'survey-ticket',
|
||||
references: {
|
||||
model: DB_TABLE_PREFIX + 'tickets',
|
||||
key: 'id'
|
||||
key: 'id',
|
||||
model: DB_TABLE_PREFIX + 'tickets'
|
||||
},
|
||||
},
|
||||
}, {
|
||||
tableName: DB_TABLE_PREFIX + 'survey_responses'
|
||||
});
|
||||
type: DataTypes.CHAR(19),
|
||||
unique: 'survey-ticket'
|
||||
}
|
||||
}, { tableName: DB_TABLE_PREFIX + 'survey_responses' });
|
||||
};
|
@ -1,75 +1,73 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
module.exports = (client, sequelize) => {
|
||||
module.exports = (_client, sequelize) => {
|
||||
const { DB_TABLE_PREFIX } = process.env;
|
||||
sequelize.define('Ticket', {
|
||||
id: {
|
||||
type: DataTypes.CHAR(19),
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
},
|
||||
category: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: DB_TABLE_PREFIX + 'categories',
|
||||
key: 'id'
|
||||
key: 'id',
|
||||
model: DB_TABLE_PREFIX + 'categories'
|
||||
},
|
||||
type: DataTypes.CHAR(19)
|
||||
},
|
||||
claimed_by: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: true,
|
||||
type: DataTypes.CHAR(19)
|
||||
},
|
||||
closed_by: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: true,
|
||||
type: DataTypes.CHAR(19)
|
||||
},
|
||||
closed_reason: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
creator: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false,
|
||||
type: DataTypes.CHAR(19)
|
||||
},
|
||||
first_response: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
type: DataTypes.DATE
|
||||
},
|
||||
guild: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: DB_TABLE_PREFIX + 'guilds',
|
||||
key: 'id'
|
||||
key: 'id',
|
||||
model: DB_TABLE_PREFIX + 'guilds'
|
||||
},
|
||||
type: DataTypes.CHAR(19),
|
||||
unique: 'number-guild'
|
||||
},
|
||||
id: {
|
||||
allowNull: false,
|
||||
primaryKey: true,
|
||||
type: DataTypes.CHAR(19)
|
||||
},
|
||||
last_message: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
type: DataTypes.DATE
|
||||
},
|
||||
number: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
type: DataTypes.INTEGER,
|
||||
unique: 'number-guild'
|
||||
},
|
||||
open: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: true
|
||||
defaultValue: true,
|
||||
type: DataTypes.BOOLEAN
|
||||
},
|
||||
opening_message: {
|
||||
type: DataTypes.CHAR(19),
|
||||
allowNull: true,
|
||||
type: DataTypes.CHAR(19)
|
||||
},
|
||||
pinned_messages: {
|
||||
type: DataTypes.JSON,
|
||||
defaultValue: []
|
||||
defaultValue: [],
|
||||
type: DataTypes.JSON
|
||||
},
|
||||
topic: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
},
|
||||
}, {
|
||||
tableName: DB_TABLE_PREFIX + 'tickets'
|
||||
});
|
||||
type: DataTypes.TEXT
|
||||
}
|
||||
}, { tableName: DB_TABLE_PREFIX + 'tickets' });
|
||||
};
|
@ -6,30 +6,29 @@ module.exports = (client, sequelize) => {
|
||||
bot: DataTypes.BOOLEAN,
|
||||
discriminator: DataTypes.STRING,
|
||||
display_name: DataTypes.TEXT,
|
||||
ticket: {
|
||||
type: DataTypes.CHAR(19),
|
||||
role: {
|
||||
allowNull: false,
|
||||
unique: 'user-ticket',
|
||||
references: {
|
||||
model: DB_TABLE_PREFIX + 'tickets',
|
||||
key: 'id'
|
||||
key: 'role',
|
||||
model: DB_TABLE_PREFIX + 'role_entities'
|
||||
},
|
||||
type: DataTypes.CHAR(19)
|
||||
},
|
||||
user: {
|
||||
type: DataTypes.CHAR(19),
|
||||
ticket: {
|
||||
allowNull: false,
|
||||
references: {
|
||||
key: 'id',
|
||||
model: DB_TABLE_PREFIX + 'tickets'
|
||||
},
|
||||
type: DataTypes.CHAR(19),
|
||||
unique: 'user-ticket'
|
||||
},
|
||||
username: DataTypes.TEXT,
|
||||
role: {
|
||||
type: DataTypes.CHAR(19),
|
||||
user: {
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: DB_TABLE_PREFIX + 'role_entities',
|
||||
key: 'role'
|
||||
},
|
||||
type: DataTypes.CHAR(19),
|
||||
unique: 'user-ticket'
|
||||
},
|
||||
}, {
|
||||
tableName: DB_TABLE_PREFIX + 'user_entities'
|
||||
});
|
||||
username: DataTypes.TEXT
|
||||
|
||||
}, { tableName: DB_TABLE_PREFIX + 'user_entities' });
|
||||
};
|
42
src/index.js
42
src/index.js
@ -1,20 +1,21 @@
|
||||
/* eslint-disable no-console */
|
||||
/**
|
||||
* Discord Tickets
|
||||
* Copyright (C) 2021 Isaac Saunders
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* @name @eartharoid/discord-tickets
|
||||
* @description An open-source Discord bot for ticket management
|
||||
* @copyright 2021 Isaac Saunders
|
||||
@ -24,8 +25,7 @@
|
||||
process.title = 'Discord Tickets';
|
||||
|
||||
const node_version = Number(process.versions.node.split('.')[0]);
|
||||
if (node_version < 14)
|
||||
return console.log(`\x07Error: Discord Tickets does not work on Node v${node_version}. Please upgrade to v14 or above.`);
|
||||
if (node_version < 14) return console.log(`\x07Error: Discord Tickets does not work on Node v${node_version}. Please upgrade to v14 or above.`);
|
||||
|
||||
const leeks = require('leeks.js');
|
||||
const fs = require('fs');
|
||||
@ -55,9 +55,7 @@ if (!checkFile('./.env', './example.env')) {
|
||||
.randomBytes(24)
|
||||
.toString('hex');
|
||||
|
||||
let data = fs.readFileSync(file, {
|
||||
encoding: 'utf-8'
|
||||
});
|
||||
let data = fs.readFileSync(file, { encoding: 'utf-8' });
|
||||
data = data.replace(key, key + value);
|
||||
|
||||
fs.writeFileSync(file, data);
|
||||
@ -69,9 +67,7 @@ if (!checkFile('./.env', './example.env')) {
|
||||
process.exit();
|
||||
}
|
||||
|
||||
require('dotenv').config({
|
||||
path: path('./.env')
|
||||
});
|
||||
require('dotenv').config({ path: path('./.env') });
|
||||
|
||||
require('./banner')();
|
||||
|
||||
@ -119,11 +115,9 @@ class Bot extends Client {
|
||||
'REACTION'
|
||||
],
|
||||
presence: selectPresence(),
|
||||
ws: {
|
||||
intents: Intents.NON_PRIVILEGED,
|
||||
}
|
||||
ws: { intents: Intents.NON_PRIVILEGED }
|
||||
});
|
||||
|
||||
|
||||
(async () => {
|
||||
/** The global bot configuration */
|
||||
this.config = require('../user/config');
|
||||
@ -144,9 +138,7 @@ class Bot extends Client {
|
||||
fs.readdirSync(path('./src/locales'))
|
||||
.filter(file => file.endsWith('.json'))
|
||||
.forEach(file => {
|
||||
const data = fs.readFileSync(path(`./src/locales/${file}`), {
|
||||
encoding: 'utf8'
|
||||
});
|
||||
const data = fs.readFileSync(path(`./src/locales/${file}`), { encoding: 'utf8' });
|
||||
const name = file.slice(0, file.length - 5);
|
||||
locales[name] = JSON.parse(data);
|
||||
});
|
||||
@ -161,9 +153,9 @@ class Bot extends Client {
|
||||
this.db = await require('./database')(this), // this.db.models.Ticket...
|
||||
|
||||
this.setMaxListeners(this.config.max_listeners); // set the max listeners for each event
|
||||
|
||||
|
||||
require('./updater')(this); // check for updates
|
||||
|
||||
|
||||
const listeners = new ListenerLoader(this);
|
||||
listeners.load(); // load listeners
|
||||
|
||||
@ -191,17 +183,13 @@ class Bot extends Client {
|
||||
*/
|
||||
if (this.config.super_secret_setting) { // you can disable it if you really want
|
||||
const tickets = await this.db.models.Ticket.count();
|
||||
await fetch(`https://stats.discordtickets.app/client?id=${this.user.id}&tickets=${tickets}`, {
|
||||
method: 'post',
|
||||
}).catch(e => {
|
||||
await fetch(`https://stats.discordtickets.app/client?id=${this.user.id}&tickets=${tickets}`, { method: 'post' }).catch(e => {
|
||||
this.log.warn('Failed to post tickets count to stats server (you can disable sending stats by setting "super_secret_setting" to false)');
|
||||
this.log.debug(e);
|
||||
});
|
||||
this.guilds.cache.forEach(async g => {
|
||||
const members = (await g.fetch()).approximateMemberCount;
|
||||
await fetch(`https://stats.discordtickets.app/guild?id=${g.id}&members=${members}`, {
|
||||
method: 'post',
|
||||
}).catch(e => {
|
||||
await fetch(`https://stats.discordtickets.app/guild?id=${g.id}&members=${members}`, { method: 'post' }).catch(e => {
|
||||
// don't spam a warning for each server
|
||||
this.log.debug(e);
|
||||
});
|
||||
|
@ -2,9 +2,7 @@ const EventListener = require('../modules/listeners/listener');
|
||||
|
||||
module.exports = class DebugEventListener extends EventListener {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
event: 'debug'
|
||||
});
|
||||
super(client, { event: 'debug' });
|
||||
}
|
||||
|
||||
async execute(data) {
|
||||
|
@ -2,9 +2,7 @@ const EventListener = require('../modules/listeners/listener');
|
||||
|
||||
module.exports = class ErrorEventListener extends EventListener {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
event: 'error'
|
||||
});
|
||||
super(client, { event: 'error' });
|
||||
}
|
||||
|
||||
async execute(error) {
|
||||
|
@ -2,9 +2,7 @@ const EventListener = require('../modules/listeners/listener');
|
||||
|
||||
module.exports = class GuildCreateEventListener extends EventListener {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
event: 'guildCreate'
|
||||
});
|
||||
super(client, { event: 'guildCreate' });
|
||||
}
|
||||
|
||||
async execute(guild) {
|
||||
|
@ -2,9 +2,7 @@ const EventListener = require('../modules/listeners/listener');
|
||||
|
||||
module.exports = class GuildDeleteEventListener extends EventListener {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
event: 'guildDelete'
|
||||
});
|
||||
super(client, { event: 'guildDelete' });
|
||||
}
|
||||
|
||||
async execute(guild) {
|
||||
|
@ -2,9 +2,7 @@ const EventListener = require('../modules/listeners/listener');
|
||||
|
||||
module.exports = class GuildMemberRemoveEventListener extends EventListener {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
event: 'guildMemberRemove'
|
||||
});
|
||||
super(client, { event: 'guildMemberRemove' });
|
||||
}
|
||||
|
||||
async execute(member) {
|
||||
|
@ -5,9 +5,7 @@ const { footer } = require('../utils/discord');
|
||||
|
||||
module.exports = class MessageEventListener extends EventListener {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
event: 'message'
|
||||
});
|
||||
super(client, { event: 'message' });
|
||||
}
|
||||
|
||||
async execute(message) {
|
||||
@ -16,11 +14,7 @@ module.exports = class MessageEventListener extends EventListener {
|
||||
const settings = await message.guild.getSettings();
|
||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||
|
||||
const t_row = await this.client.db.models.Ticket.findOne({
|
||||
where: {
|
||||
id: message.channel.id
|
||||
}
|
||||
});
|
||||
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: message.channel.id } });
|
||||
|
||||
if (t_row) {
|
||||
if (settings.log_messages && !message.system) this.client.tickets.archives.addMessage(message); // add the message to the archives (if it is in a ticket channel)
|
||||
@ -33,22 +27,14 @@ module.exports = class MessageEventListener extends EventListener {
|
||||
} else {
|
||||
if (message.author.bot) return;
|
||||
|
||||
const p_row = await this.client.db.models.Panel.findOne({
|
||||
where: {
|
||||
channel: message.channel.id
|
||||
}
|
||||
});
|
||||
const p_row = await this.client.db.models.Panel.findOne({ where: { channel: message.channel.id } });
|
||||
|
||||
if (p_row && typeof p_row.categories === 'string') {
|
||||
// handle reaction-less panel
|
||||
|
||||
await message.delete();
|
||||
|
||||
const cat_row = await this.client.db.models.Category.findOne({
|
||||
where: {
|
||||
id: p_row.categories
|
||||
}
|
||||
});
|
||||
const cat_row = await this.client.db.models.Category.findOne({ where: { id: p_row.categories } });
|
||||
|
||||
const tickets = await this.client.db.models.Ticket.findAndCountAll({
|
||||
where: {
|
||||
|
@ -2,9 +2,7 @@ const EventListener = require('../modules/listeners/listener');
|
||||
|
||||
module.exports = class MessageDeleteEventListener extends EventListener {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
event: 'messageDelete'
|
||||
});
|
||||
super(client, { event: 'messageDelete' });
|
||||
}
|
||||
|
||||
async execute(message) {
|
||||
|
@ -5,9 +5,7 @@ const { footer } = require('../utils/discord');
|
||||
|
||||
module.exports = class MessageReactionAddEventListener extends EventListener {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
event: 'messageReactionAdd'
|
||||
});
|
||||
super(client, { event: 'messageReactionAdd' });
|
||||
}
|
||||
|
||||
async execute(r, u) {
|
||||
@ -49,34 +47,20 @@ module.exports = class MessageReactionAddEventListener extends EventListener {
|
||||
});
|
||||
}
|
||||
|
||||
const t_row = await this.client.db.models.Ticket.findOne({
|
||||
where: {
|
||||
id: channel.id
|
||||
}
|
||||
});
|
||||
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: channel.id } });
|
||||
|
||||
if (t_row && t_row.opening_message === r.message.id) {
|
||||
if (r.emoji.name === '🙌' && await member.isStaff()) {
|
||||
// ticket claiming
|
||||
|
||||
await t_row.update({
|
||||
claimed_by: member.user.id
|
||||
});
|
||||
await t_row.update({ claimed_by: member.user.id });
|
||||
|
||||
await channel.updateOverwrite(member.user.id, {
|
||||
VIEW_CHANNEL: true,
|
||||
}, `Ticket claimed by ${member.user.tag}`);
|
||||
await channel.updateOverwrite(member.user.id, { VIEW_CHANNEL: true }, `Ticket claimed by ${member.user.tag}`);
|
||||
|
||||
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 } });
|
||||
|
||||
for (const role of cat_row.roles) {
|
||||
await channel.updateOverwrite(role, {
|
||||
VIEW_CHANNEL: false,
|
||||
}, `Ticket claimed by ${member.user.tag}`);
|
||||
await channel.updateOverwrite(role, { VIEW_CHANNEL: false }, `Ticket claimed by ${member.user.tag}`);
|
||||
}
|
||||
|
||||
this.client.log.info(`${member.user.tag} has claimed "${channel.name}" in "${guild.name}"`);
|
||||
@ -93,11 +77,7 @@ module.exports = class MessageReactionAddEventListener extends EventListener {
|
||||
await r.users.remove(u.id);
|
||||
}
|
||||
} else {
|
||||
const p_row = await this.client.db.models.Panel.findOne({
|
||||
where: {
|
||||
message: r.message.id
|
||||
}
|
||||
});
|
||||
const p_row = await this.client.db.models.Panel.findOne({ where: { message: r.message.id } });
|
||||
|
||||
if (p_row && typeof p_row.categories !== 'string') {
|
||||
// panels
|
||||
@ -106,11 +86,7 @@ module.exports = class MessageReactionAddEventListener extends EventListener {
|
||||
const category_id = p_row.categories[r.emoji.name];
|
||||
if (!category_id) return;
|
||||
|
||||
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 } });
|
||||
|
||||
const tickets = await this.client.db.models.Ticket.findAndCountAll({
|
||||
where: {
|
||||
|
@ -4,9 +4,7 @@ const { MessageEmbed } = require('discord.js');
|
||||
|
||||
module.exports = class MessageReactionRemoveEventListener extends EventListener {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
event: 'messageReactionRemove'
|
||||
});
|
||||
super(client, { event: 'messageReactionRemove' });
|
||||
}
|
||||
|
||||
async execute(r, u) {
|
||||
@ -38,34 +36,22 @@ module.exports = class MessageReactionRemoveEventListener extends EventListener
|
||||
const channel = r.message.channel;
|
||||
const member = await guild.members.fetch(u.id);
|
||||
|
||||
const t_row = await this.client.db.models.Ticket.findOne({
|
||||
where: {
|
||||
id: channel.id
|
||||
}
|
||||
});
|
||||
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: channel.id } });
|
||||
|
||||
if (t_row && t_row.opening_message === r.message.id) {
|
||||
if (r.emoji.name === '🙌' && await member.isStaff()) {
|
||||
// ticket claiming
|
||||
|
||||
await t_row.update({
|
||||
claimed_by: null
|
||||
});
|
||||
await t_row.update({ claimed_by: null });
|
||||
|
||||
await channel.permissionOverwrites
|
||||
.get(member.user.id)
|
||||
?.delete(`Ticket released by ${member.user.tag}`);
|
||||
|
||||
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 } });
|
||||
|
||||
for (const role of cat_row.roles) {
|
||||
await channel.updateOverwrite(role, {
|
||||
VIEW_CHANNEL: true,
|
||||
}, `Ticket released by ${member.user.tag}`);
|
||||
await channel.updateOverwrite(role, { VIEW_CHANNEL: true }, `Ticket released by ${member.user.tag}`);
|
||||
}
|
||||
|
||||
this.client.log.info(`${member.user.tag} has released "${channel.name}" in "${guild.name}"`);
|
||||
|
@ -2,9 +2,7 @@ const EventListener = require('../modules/listeners/listener');
|
||||
|
||||
module.exports = class MessageUpdateEventListener extends EventListener {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
event: 'messageUpdate'
|
||||
});
|
||||
super(client, { event: 'messageUpdate' });
|
||||
}
|
||||
|
||||
async execute(oldm, newm) {
|
||||
|
@ -2,9 +2,7 @@ const EventListener = require('../modules/listeners/listener');
|
||||
|
||||
module.exports = class RateLimitEventListener extends EventListener {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
event: 'rateLimit'
|
||||
});
|
||||
super(client, { event: 'rateLimit' });
|
||||
}
|
||||
|
||||
async execute(limit) {
|
||||
|
@ -2,9 +2,7 @@ const EventListener = require('../modules/listeners/listener');
|
||||
|
||||
module.exports = class WarnEventListener extends EventListener {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
event: 'warn'
|
||||
});
|
||||
super(client, { event: 'warn' });
|
||||
}
|
||||
|
||||
async execute(warning) {
|
||||
|
@ -2,60 +2,38 @@ const { path } = require('./utils/fs');
|
||||
const config = require('../user/config');
|
||||
const Logger = require('leekslazylogger-fastify');
|
||||
module.exports = new Logger({
|
||||
name: 'Discord Tickets by eartharoid',
|
||||
debug: config.debug,
|
||||
logToFile: config.logs.enabled,
|
||||
splitFile: config.logs.split,
|
||||
directory: path('./logs/'),
|
||||
keepFor: config.logs.keep_for,
|
||||
timestamp: 'YYYY-MM-DD HH:mm:ss',
|
||||
levels: {
|
||||
_logger: {
|
||||
format: '&f&!7{timestamp}&r [LOGGER] {text}'
|
||||
},
|
||||
basic: {
|
||||
format: '&f&!7{timestamp} {text}'
|
||||
},
|
||||
console: {
|
||||
format: '&f&!7{timestamp} [INFO] {text}'
|
||||
},
|
||||
info: {
|
||||
format: '&f&!7{timestamp}&r &3[INFO] &b{text}'
|
||||
},
|
||||
success: {
|
||||
format: '&f&!7{timestamp}&r &2[SUCCESS] &a{text}'
|
||||
},
|
||||
debug: {
|
||||
format: '&f&!7{timestamp}&r &1[DEBUG] &9{text}'
|
||||
},
|
||||
notice: {
|
||||
format: '&f&!7{timestamp}&r &0&!6[NOTICE] {text}'
|
||||
},
|
||||
warn: {
|
||||
format: '&f&!7{timestamp}&r &6[WARN] &e{text}'
|
||||
},
|
||||
error: {
|
||||
format: '&f&!7{timestamp}&r &4[ERROR] &c{text}'
|
||||
},
|
||||
_logger: { format: '&f&!7{timestamp}&r [LOGGER] {text}' },
|
||||
basic: { format: '&f&!7{timestamp} {text}' },
|
||||
commands: {
|
||||
type: 'info',
|
||||
format: '&f&!7{timestamp}&r &3[INFO] &d(COMMANDS)&r {text}'
|
||||
},
|
||||
plugins: {
|
||||
type: 'info',
|
||||
format: '&f&!7{timestamp}&r &3[INFO] &d(PLUGINS)&r {text}'
|
||||
},
|
||||
tickets: {
|
||||
type: 'info',
|
||||
format: '&f&!7{timestamp}&r &3[INFO] &d(TICKETS)&r {text}'
|
||||
format: '&f&!7{timestamp}&r &3[INFO] &d(COMMANDS)&r {text}',
|
||||
type: 'info'
|
||||
},
|
||||
console: { format: '&f&!7{timestamp} [INFO] {text}' },
|
||||
debug: { format: '&f&!7{timestamp}&r &1[DEBUG] &9{text}' },
|
||||
error: { format: '&f&!7{timestamp}&r &4[ERROR] &c{text}' },
|
||||
http: {
|
||||
type: 'info',
|
||||
format: '&f&!7{timestamp}&r &3[INFO] &d(HTTP)&r {text}'
|
||||
format: '&f&!7{timestamp}&r &3[INFO] &d(HTTP)&r {text}',
|
||||
type: 'info'
|
||||
},
|
||||
info: { format: '&f&!7{timestamp}&r &3[INFO] &b{text}' },
|
||||
notice: { format: '&f&!7{timestamp}&r &0&!6[NOTICE] {text}' },
|
||||
plugins: {
|
||||
format: '&f&!7{timestamp}&r &3[INFO] &d(PLUGINS)&r {text}',
|
||||
type: 'info'
|
||||
},
|
||||
success: { format: '&f&!7{timestamp}&r &2[SUCCESS] &a{text}' },
|
||||
warn: { format: '&f&!7{timestamp}&r &6[WARN] &e{text}' },
|
||||
ws: {
|
||||
type: 'info',
|
||||
format: '&f&!7{timestamp}&r &3[INFO] &d(WS)&r {text}'
|
||||
format: '&f&!7{timestamp}&r &3[INFO] &d(WS)&r {text}',
|
||||
type: 'info'
|
||||
}
|
||||
}
|
||||
},
|
||||
logToFile: config.logs.enabled,
|
||||
name: 'Discord Tickets by eartharoid',
|
||||
splitFile: config.logs.split,
|
||||
timestamp: 'YYYY-MM-DD HH:mm:ss'
|
||||
});
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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`);
|
||||
|
@ -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}
|
||||
*/
|
||||
|
@ -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}`);
|
||||
};
|
@ -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;
|
||||
// });
|
||||
|
@ -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
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,25 +1,21 @@
|
||||
const { Structures } = require('discord.js');
|
||||
|
||||
Structures.extend('Guild', Guild => {
|
||||
return class extends Guild {
|
||||
constructor(client, data) {
|
||||
super(client, data);
|
||||
}
|
||||
Structures.extend('Guild', Guild => class extends Guild {
|
||||
constructor(client, data) {
|
||||
super(client, data);
|
||||
}
|
||||
|
||||
async deleteSettings() {
|
||||
const row = await this.settings;
|
||||
return await row.destroy();
|
||||
}
|
||||
async deleteSettings() {
|
||||
const row = await this.settings;
|
||||
return await row.destroy();
|
||||
}
|
||||
|
||||
async getSettings() {
|
||||
const data = {
|
||||
id: this.id
|
||||
};
|
||||
const [settings] = await this.client.db.models.Guild.findOrCreate({
|
||||
defaults: data,
|
||||
where: data
|
||||
});
|
||||
return settings;
|
||||
}
|
||||
};
|
||||
async getSettings() {
|
||||
const data = { id: this.id };
|
||||
const [settings] = await this.client.db.models.Guild.findOrCreate({
|
||||
defaults: data,
|
||||
where: data
|
||||
});
|
||||
return settings;
|
||||
}
|
||||
});
|
@ -1,20 +1,14 @@
|
||||
const { Structures } = require('discord.js');
|
||||
|
||||
Structures.extend('GuildMember', GuildMember => {
|
||||
return class extends GuildMember {
|
||||
constructor(client, data, guild) {
|
||||
super(client, data, guild);
|
||||
}
|
||||
Structures.extend('GuildMember', GuildMember => class extends GuildMember {
|
||||
constructor(client, data, guild) {
|
||||
super(client, data, guild);
|
||||
}
|
||||
|
||||
async isStaff() {
|
||||
const guild_categories = await this.client.db.models.Category.findAll({
|
||||
where: {
|
||||
guild: this.guild.id
|
||||
}
|
||||
});
|
||||
|
||||
return guild_categories.some(cat => cat.roles.some(r => this.roles.cache.has(r)));
|
||||
}
|
||||
async isStaff() {
|
||||
const guild_categories = await this.client.db.models.Category.findAll({ where: { guild: this.guild.id } });
|
||||
|
||||
return guild_categories.some(cat => cat.roles.some(r => this.roles.cache.has(r)));
|
||||
}
|
||||
|
||||
};
|
||||
});
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
const fetch = require('node-fetch');
|
||||
const boxen = require('boxen');
|
||||
const link = require('terminal-link');
|
||||
@ -26,11 +27,11 @@ module.exports = async client => {
|
||||
|
||||
console.log(
|
||||
boxen(format(lines.join('\n')), {
|
||||
padding: 1,
|
||||
margin: 1,
|
||||
align: 'center',
|
||||
borderColor: 'yellow',
|
||||
borderStyle: 'round'
|
||||
borderStyle: 'round',
|
||||
margin: 1,
|
||||
padding: 1
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -4,9 +4,9 @@ let current_presence = -1;
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
*
|
||||
* @param {string} text
|
||||
* @param {string} [additional]
|
||||
*
|
||||
* @param {string} text
|
||||
* @param {string} [additional]
|
||||
* @returns {string}
|
||||
*/
|
||||
footer: (text, additional) => {
|
||||
@ -20,16 +20,17 @@ module.exports = {
|
||||
selectPresence: () => {
|
||||
const length = config.presence.presences.length;
|
||||
if (length === 0) return {};
|
||||
|
||||
|
||||
let num;
|
||||
if (length === 1)
|
||||
if (length === 1) {
|
||||
num = 0;
|
||||
else if (config.presence.randomise)
|
||||
} else if (config.presence.randomise) {
|
||||
num = Math.floor(Math.random() * length);
|
||||
else {
|
||||
} else {
|
||||
current_presence = current_presence + 1; // ++ doesn't work on negative numbers
|
||||
if (current_presence === length)
|
||||
if (current_presence === length) {
|
||||
current_presence = 0;
|
||||
}
|
||||
num = current_presence;
|
||||
}
|
||||
|
||||
@ -48,5 +49,5 @@ module.exports = {
|
||||
},
|
||||
status
|
||||
};
|
||||
},
|
||||
}
|
||||
};
|
@ -25,7 +25,7 @@ module.exports = {
|
||||
W: '🇼',
|
||||
X: '🇽',
|
||||
Y: '🇾',
|
||||
Z: '🇿',
|
||||
Z: '🇿'
|
||||
},
|
||||
numbers: {
|
||||
0: '0️⃣',
|
||||
@ -38,6 +38,6 @@ module.exports = {
|
||||
7: '7️⃣',
|
||||
8: '8️⃣',
|
||||
9: '9️⃣',
|
||||
10: '🔟',
|
||||
10: '🔟'
|
||||
}
|
||||
};
|
@ -6,5 +6,5 @@ module.exports = {
|
||||
* @param {string} path - A path relative to the root of the project (like "./user/config.js")
|
||||
* @returns {string} absolute path
|
||||
*/
|
||||
path: path => join(__dirname, '../../', path),
|
||||
path: path => join(__dirname, '../../', path)
|
||||
};
|
@ -1,10 +1,10 @@
|
||||
module.exports = {
|
||||
int2hex: (int) => int.toString(16).toUpperCase(),
|
||||
int2hex: int => int.toString(16).toUpperCase(),
|
||||
some: async (array, func) => {
|
||||
for (const element of array) {
|
||||
if (await func(element)) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
wait: (time) => new Promise(res => setTimeout(res, time)),
|
||||
wait: time => new Promise(res => setTimeout(res, time))
|
||||
};
|
Loading…
Reference in New Issue
Block a user