Ticket creation

This commit is contained in:
Isaac 2021-03-28 23:49:36 +01:00
parent 91c53f38e6
commit 82c3175f37
8 changed files with 135 additions and 55 deletions

View File

@ -44,6 +44,8 @@ module.exports = class SettingsCommand extends Command {
}); });
category.name = c.name; category.name = c.name;
category.roles = c.roles; category.roles = c.roles;
category.max_per_member = c.max_per_member;
category.name_format = c.name_format;
category.save(); category.save();
let cat_channel = await this.client.channels.fetch(c.id); let cat_channel = await this.client.channels.fetch(c.id);
@ -67,6 +69,7 @@ module.exports = class SettingsCommand extends Command {
let cat_channel = await guild.channels.create(c.name, { let cat_channel = await guild.channels.create(c.name, {
type: 'category', type: 'category',
reason: `Tickets category created by ${member.user.tag}`, reason: `Tickets category created by ${member.user.tag}`,
position: 0,
permissionOverwrites: [ permissionOverwrites: [
...[ ...[
{ {
@ -88,9 +91,11 @@ module.exports = class SettingsCommand extends Command {
}); });
await this.client.db.models.Category.create({ await this.client.db.models.Category.create({
id: cat_channel.id, id: cat_channel.id,
max_per_member: c.max_per_member,
name: c.name, name: c.name,
name_format: c.name_format,
guild: guild.id, guild: guild.id,
roles: c.roles roles: c.roles,
}); });
} }
@ -119,7 +124,9 @@ module.exports = class SettingsCommand extends Command {
data.categories = categories.map(c =>{ data.categories = categories.map(c =>{
return { return {
id: c.id, id: c.id,
max_per_member: c.max_per_member,
name: c.name, name: c.name,
name_format: c.name_format,
roles: c.roles roles: c.roles
}; };
}); });

View File

@ -9,6 +9,7 @@ module.exports = class NewCommand extends Command {
internal: true, internal: true,
name: i18n('commands.new.name'), name: i18n('commands.new.name'),
description: i18n('commands.new.description'), description: i18n('commands.new.description'),
// slash: false,
options: [ options: [
{ {
name: i18n('commands.new.options.category.name'), name: i18n('commands.new.options.category.name'),
@ -37,5 +38,8 @@ module.exports = class NewCommand extends Command {
.setTitle(i18n('bot.version', require('../../package.json').version)) .setTitle(i18n('bot.version', require('../../package.json').version))
.setDescription(args.topic) .setDescription(args.topic)
); );
// this.client.tickets.create(guild.id, member.id, args.category, args.topic);
this.client.tickets.create(guild.id, member.id, '825861413687787560');
} }
}; };

View File

@ -101,7 +101,7 @@ module.exports = async (log) => {
name: { name: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false, allowNull: false,
unique: 'name_guild' unique: 'name-guild'
}, },
guild: { guild: {
type: DataTypes.CHAR(18), type: DataTypes.CHAR(18),
@ -110,10 +110,19 @@ module.exports = async (log) => {
model: Guild, model: Guild,
key: 'id' key: 'id'
}, },
unique: 'name_guild' unique: 'name-guild'
}, },
roles: { roles: {
type: DataTypes.JSON type: DataTypes.JSON
},
max_per_member: {
type: DataTypes.INTEGER,
defaultValue: 1
},
name_format: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: config.defaults.name_format
} }
}, { }, {
tableName: DB_TABLE_PREFIX + 'categories' tableName: DB_TABLE_PREFIX + 'categories'
@ -127,8 +136,8 @@ module.exports = async (log) => {
}, },
number: { number: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
autoIncrement: true,
allowNull: false, allowNull: false,
unique: 'number-guild'
}, },
guild: { guild: {
type: DataTypes.CHAR(18), type: DataTypes.CHAR(18),
@ -136,7 +145,8 @@ module.exports = async (log) => {
references: { references: {
model: Guild, model: Guild,
key: 'id' key: 'id'
}, },
unique: 'number-guild'
}, },
category: { category: {
type: DataTypes.CHAR(18), type: DataTypes.CHAR(18),
@ -150,6 +160,10 @@ module.exports = async (log) => {
type: DataTypes.CHAR(18), type: DataTypes.CHAR(18),
allowNull: false, allowNull: false,
}, },
open: {
type: DataTypes.BOOLEAN,
defaultValue: true
}
}, { }, {
tableName: DB_TABLE_PREFIX + 'tickets' tableName: DB_TABLE_PREFIX + 'tickets'
}); });
@ -193,12 +207,12 @@ module.exports = async (log) => {
user: { user: {
type: DataTypes.CHAR(18), type: DataTypes.CHAR(18),
allowNull: false, allowNull: false,
unique: 'id_ticket' unique: 'id-ticket'
}, },
ticket: { ticket: {
type: DataTypes.CHAR(18), type: DataTypes.CHAR(18),
allowNull: false, allowNull: false,
unique: 'id_ticket', unique: 'id-ticket',
references: { references: {
model: Ticket, model: Ticket,
key: 'id' key: 'id'
@ -219,12 +233,12 @@ module.exports = async (log) => {
channel: { channel: {
type: DataTypes.CHAR(18), type: DataTypes.CHAR(18),
allowNull: false, allowNull: false,
unique: 'id_ticket' unique: 'id-ticket'
}, },
ticket: { ticket: {
type: DataTypes.CHAR(18), type: DataTypes.CHAR(18),
allowNull: false, allowNull: false,
unique: 'id_ticket', unique: 'id-ticket',
references: { references: {
model: Ticket, model: Ticket,
key: 'id' key: 'id'
@ -240,12 +254,12 @@ module.exports = async (log) => {
role: { role: {
type: DataTypes.CHAR(18), type: DataTypes.CHAR(18),
allowNull: false, allowNull: false,
unique: 'id_ticket' unique: 'id-ticket'
}, },
ticket: { ticket: {
type: DataTypes.CHAR(18), type: DataTypes.CHAR(18),
allowNull: false, allowNull: false,
unique: 'id_ticket', unique: 'id-ticket',
references: { references: {
model: Ticket, model: Ticket,
key: 'id' key: 'id'

View File

@ -1,5 +1,4 @@
{ {
"admin_only": "❌ You must be an administrator to use this command.",
"bot": { "bot": {
"version": "Discord Tickets v%s by eartharoid" "version": "Discord Tickets v%s by eartharoid"
}, },
@ -28,5 +27,5 @@
}, },
"must_be_slash": "❌ This command must be invoked by a slash command interaction (`/%s`).", "must_be_slash": "❌ This command must be invoked by a slash command interaction (`/%s`).",
"no_perm": "❌ You do not have the permissions required to use this command:\n%s", "no_perm": "❌ You do not have the permissions required to use this command:\n%s",
"support_only": "❌ You must be a member of staff to use this command." "staff_only": "❌ You must be a member of staff to use this command."
} }

View File

@ -8,53 +8,54 @@ module.exports = new Logger({
splitFile: true, splitFile: true,
directory: path('./logs/'), directory: path('./logs/'),
keepFor: config.logs.keep_for, keepFor: config.logs.keep_for,
timestamp: 'YYYY-MM-DD HH:mm:ss',
levels: { levels: {
_logger: { _logger: {
format: '&7[{timestamp}]&r [LOGGER] {text}' format: '&f&!7{timestamp}&r [LOGGER] {text}'
}, },
basic: { basic: {
format: '[{timestamp}] {text}' format: '&f&!7{timestamp} {text}'
}, },
console: { console: {
format: '[{timestamp}] [INFO] {text}' format: '&f&!7{timestamp} [INFO] {text}'
}, },
info: { info: {
format: '&7[{timestamp}]&r &3[INFO] &b{text}' format: '&f&!7{timestamp}&r &3[INFO] &b{text}'
}, },
success: { success: {
format: '&7[{timestamp}]&r &2[SUCCESS] &a{text}' format: '&f&!7{timestamp}&r &2[SUCCESS] &a{text}'
}, },
debug: { debug: {
format: '&7[{timestamp}]&r &1[DEBUG] &9{text}' format: '&f&!7{timestamp}&r &1[DEBUG] &9{text}'
}, },
notice: { notice: {
format: '&7[{timestamp}]&r &0&!6[NOTICE] {text}' format: '&f&!7{timestamp}&r &0&!6[NOTICE] {text}'
}, },
warn: { warn: {
format: '&7[{timestamp}]&r &6[WARN] &e{text}' format: '&f&!7{timestamp}&r &6[WARN] &e{text}'
}, },
error: { error: {
format: '&7[{timestamp}]&r &4[ERROR] &c{text}' format: '&f&!7{timestamp}&r &4[ERROR] &c{text}'
}, },
commands: { commands: {
type: 'info', type: 'info',
format: '&7[{timestamp}]&r &3[INFO] &d(COMMANDS)&r {text}' format: '&f&!7{timestamp}&r &3[INFO] &d(COMMANDS)&r {text}'
}, },
plugins: { plugins: {
type: 'info', type: 'info',
format: '&7[{timestamp}]&r &3[INFO] &d(PLUGINS)&r {text}' format: '&f&!7{timestamp}&r &3[INFO] &d(PLUGINS)&r {text}'
}, },
tickets: { tickets: {
type: 'info', type: 'info',
format: '&7[{timestamp}]&r &3[INFO] &d(TICKETS)&r {text}' format: '&f&!7{timestamp}&r &3[INFO] &d(TICKETS)&r {text}'
}, },
http: { http: {
type: 'info', type: 'info',
format: '&7[{timestamp}]&r &3[INFO] &d(HTTP)&r {text}' format: '&f&!7{timestamp}&r &3[INFO] &d(HTTP)&r {text}'
}, },
ws: { ws: {
type: 'info', type: 'info',
format: '&7[{timestamp}]&r &3[INFO] &d(WS)&r {text}' format: '&f&!7{timestamp}&r &3[INFO] &d(WS)&r {text}'
} }
} }
}); });

View File

@ -183,7 +183,7 @@ module.exports = class CommandManager {
const cmd = this.commands.get(cmd_name); const cmd = this.commands.get(cmd_name);
if (cmd.slash && !slash) { if (cmd.slash && !slash) {
this.client.log.commands(`Blocking command execution for the "${cmd_name}" command as it was invoked by a message, not a slash command interaction_or_message.`); this.client.log.commands(`Blocking command execution for the "${cmd_name}" command as it was invoked by a message, not a slash command interaction.`);
try { try {
data.channel.send(i18n('must_be_slash', cmd_name)); // interaction_or_message.reply data.channel.send(i18n('must_be_slash', cmd_name)); // interaction_or_message.reply
} catch (err) { } catch (err) {

View File

@ -19,56 +19,110 @@ module.exports = class TicketManager extends EventEmitter {
/** /**
* Create a new ticket * Create a new ticket
* @param {string} guild - ID of the guild to create the ticket in * @param {string} guild_id - ID of the guild to create the ticket in
* @param {string} creator - ID of the ticket creator (user) * @param {string} creator_id - ID of the ticket creator (user)
* @param {string} category - ID of the ticket category * @param {string} category_id - ID of the ticket category
* @param {string} [topic] - The ticket topic * @param {string} [topic] - The ticket topic
*/ */
async create(guild, creator, category, topic) { async create(guild_id, creator_id, category_id, topic) {
if (!topic) topic = '';
let cat_row = await this.client.db.models.Category.findOne({
where: {
id: category_id
}
});
if (!cat_row)
throw new Error('Ticket category does not exist');
let number = (await this.client.db.models.Ticket.count({
where: {
guild: guild_id
}
})) + 1;
let guild = await this.client.guilds.cache.get(guild_id);
let member = await guild.members.fetch(creator_id);
let name = cat_row.name_format
.replace(/{+\s?(user)?name\s?}+/gi, member.displayName)
.replace(/{+\s?number\s?}+/gi, number);
let t_channel = await guild.channels.create(name, {
type: 'text',
topic: `${member}${topic.length > 0 ? ` | ${topic}` : ''}`,
parent: category_id,
reason: `${member.tag} requested a new ticket channel`
});
let t_row = await this.client.db.models.Ticket.create({
id: t_channel.id,
number,
guild: guild_id,
category: category_id,
creator: creator_id,
topic
});
this.emit('create', t_row.id, creator_id);
} }
/** /**
* Get a ticket * Get a ticket
* @param {string} ticket - The channel ID, or the ticket number * @param {(string|number)} ticket - The channel ID, or the ticket number
* @param {string} guild_id - The ID of the ticket's guild (used if a ticket number is provided instead of ID)
*/ */
async get(ticket) { async get(ticket, guild_id) {
let row = await this.resolveTicket(ticket, guild_id);
if (!row) throw new Error(`Could not find a ticket with ID ${ticket}`);
} }
/** /**
* Close a ticket * Close a ticket
* @param {string} ticket - The channel ID, or the ticket number * @param {(string|number)} ticket - The channel ID, or the ticket number
* @param {string} [closer] - ID of the member who is closing the ticket * @param {(string|null)} closer_id - ID of the member who is closing the ticket, or null
* @param {string} [guild_id] - The ID of the ticket's guild (used if a ticket number is provided instead of ID)
*/ */
async close(ticket, closer) { async close(ticket, closer_id, guild_id) {
let row = await this.resolveTicket(ticket, guild_id);
if (!row) throw new Error(`Could not find a ticket with ID ${ticket}`);
this.emit('beforeClose', ticket, closer_id);
/**
*
*
* for each message of ticket, create entities
*
*
*/
this.emit('close', ticket, closer_id);
}
/**
*
* @param {(string|number)} ticket - 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)
*/
async resolve(ticket, guild_id) {
if (!this.client.channels.resolve(ticket)) { if (!this.client.channels.resolve(ticket)) {
let row = await this.client.db.Models.Ticket.findOne({ let row = await this.client.db.models.Ticket.findOne({
where: { where: {
number: ticket number: ticket,
guild_id
} }
}); });
if (!row) throw new Error(`Could not find a ticket with number ${ticket}`); ticket = row?.id;
ticket = row.id;
} }
let row = await this.client.db.Models.Ticket.findOne({ let row = await this.client.db.models.Ticket.findOne({
where: { where: {
id: ticket id: ticket
} }
}); });
if (!row) throw new Error(`Could not find a ticket with ID ${ticket}`); return row;
this.emit('beforeClose', ticket, closer);
/**
*
*
* for each message in table, create entities
*
*
*/
} }
}; };

View File

@ -27,6 +27,7 @@ module.exports = {
defaults: { defaults: {
colour: '#009999', // https://discord.js.org/#/docs/main/stable/typedef/ColorResolvable colour: '#009999', // https://discord.js.org/#/docs/main/stable/typedef/ColorResolvable
log_messages: true, // transcripts/archives will be empty if false log_messages: true, // transcripts/archives will be empty if false
name_format: 'ticket-{number}',
prefix: '-', prefix: '-',
ticket_welcome: 'Hello {{name}}, thank you for creating a ticket. A member of staff will soon be available to assist you.\n\n__All messages in this channel are stored for future reference.__', ticket_welcome: 'Hello {{name}}, thank you for creating a ticket. A member of staff will soon be available to assist you.\n\n__All messages in this channel are stored for future reference.__',
}, },