discord-tickets
Version:
Discord.js extention library for manage easily tickets
321 lines (320 loc) • 13.1 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TicketManager = void 0;
const TextTicket_1 = require("./TextTicket");
const BaseManager_1 = require("../Base/BaseManager");
/**
* @external CategoryChannel
* @see {@link https://discord.js.org/#/docs/main/stable/class/CategoryChannel}
*/
/**
* @external Client
* @see {@link https://discord.js.org/#/docs/main/stable/class/Client}
*/
/**
* @external Collection
* @see {@link https://discord.js.org/#/docs/collection/stable/class/Collection}
*/
/**
* @external Guild
* @see {@link https://discord.js.org/#/docs/main/stable/class/Guild}
*/
/**
* @external GuildMember
* @see {@link https://discord.js.org/#/docs/main/stable/class/GuildMember}
*/
/**
* @external Permissions
* @see {@link https://discord.js.org/#/docs/main/stable/class/Permissions}
*/
const discord_js_1 = require("discord.js");
/**
* Text Ticket Manager
* @extends {BaseManager}
*/
class TicketManager extends BaseManager_1.BaseManager {
/**
* @param {Client} client Discord Client
* @param {TicketManagerOptions} [options] TicketManager options
*/
constructor(client, options) {
super(client, options);
/**
* The Discord Client
* @readonly
* @type {Client}
*/
if (!client)
throw new Error('Client is a required option.');
this.client = client;
/**
* The manager options
* @type {TicketManagerOptions}
*/
this.options = options;
/**
* Collection with all tickets (tickets's cache)
* @type {Collection<string, TicketData>}
*/
this.tickets = new discord_js_1.Collection();
this.cachingTickets().then(r => null);
}
/**
* Caching raws tickets into Array
* @return {Promise<void>}
* @private
*/
cachingTickets() {
return __awaiter(this, void 0, void 0, function* () {
this.ticketRaws = yield this.getAllTickets();
if (this.options.ticketCache) {
this.ticketRaws.forEach(ticket => {
this.tickets.set(ticket.channel, new TextTicket_1.TextTicket(this, ticket));
});
}
});
}
/**
* Get options
* @private
* @param {string} id
* @return {TicketManagerOptions}
*/
// @ts-ignore
getOptions(id) {
return __awaiter(this, void 0, void 0, function* () {
return this.options;
});
}
/**
* Create Ticket
* @param {Guild} guild Discord Guild
* @param {GuildMember} member Discord Guild Member
* @return {Promise<TextTicket>}
* @example
* //Create Thread Ticket
* await ticketText.createTicket(message.guild, message.member)
*/
createTicket(guild, member) {
return __awaiter(this, void 0, void 0, function* () {
const options = yield this.getOptions(guild.id);
if (!options)
throw new Error("Cannot find options");
const category = guild.channels.cache.get(options.parentId);
if (!category || category.type !== "GUILD_CATEGORY")
throw new Error("Cannot find tickets category, please check id/if channel type is GUILD_CATEGORY");
const guildsTickets = this.ticketRaws.filter(ticket => ticket.guild === guild.id);
let number;
if (guildsTickets.length > 0) {
number = guildsTickets.sort((ticketA, ticketB) => ticketB.number - ticketA.number)[0].number;
}
else
number = 0;
number = (parseInt(String(number)) + 1).toString();
let newNumber = "0000" + number;
newNumber = newNumber.slice(newNumber.length - 4, newNumber.length + 2);
const channel = yield guild.channels.create(`ticket-${newNumber}`, {
type: "GUILD_TEXT",
parent: category,
permissionOverwrites: [
{
id: member.id,
allow: [discord_js_1.Permissions.FLAGS.VIEW_CHANNEL, discord_js_1.Permissions.FLAGS.SEND_MESSAGES]
},
{
id: guild.roles.everyone,
deny: [discord_js_1.Permissions.FLAGS.VIEW_CHANNEL]
}, {
id: options.staffRole,
allow: [discord_js_1.Permissions.FLAGS.VIEW_CHANNEL, discord_js_1.Permissions.FLAGS.SEND_MESSAGES]
}
]
});
const data = {
guild: guild.id,
channel: channel.id,
member: member.id,
// @ts-ignore
number: number,
status: "open",
participants: [member.id],
type: "channel"
};
this.ticketRaws.push(data);
yield this.saveTicketRaws();
const ticket = new TextTicket_1.TextTicket(this, data);
if (this.options.ticketCache) {
this.tickets.set(data.channel, new TextTicket_1.TextTicket(this, data));
}
if (this.options.channelTopic) {
yield channel.setTopic("ticket#" + newNumber, "Set ticket topic");
}
/**
* Emitted when user create ticket
* @event TicketManager#ticketCreate
* @param {TextTicket} ticket Ticket resolvable
*/
this.emit("ticketCreate", ticket);
return ticket;
});
}
/**
* Delete Ticket
* @param {TextTicket} ticket Ticket class
* @return {Promise<any>}
*/
deleteTicket(ticket) {
return __awaiter(this, void 0, void 0, function* () {
yield ticket.channel.delete();
this.ticketRaws = this.ticketRaws.filter(y => y.channel !== ticket.channelId);
yield this.saveTicketRaws();
if (this.options.ticketCache) {
this.tickets.delete(ticket.channelId);
}
/**
* Emitted when ticket be delete
* @event TicketManager#ticketDeleted
* @param {TextTicket} ticket Ticket resolvable
*/
return this.emit("ticketDeleted", ticket);
});
}
/**
* Close Ticket
* @param {TextTicket} ticket Ticket class
* @return {Promise<any>}
*/
closeTicket(ticket) {
return __awaiter(this, void 0, void 0, function* () {
const options = yield this.getOptions(ticket.guild.id);
if (!options)
throw new Error("Cannot find options");
const category = ticket.guild.channels.cache.get(options.closeParentId);
if (!category || category.type !== "GUILD_CATEGORY")
throw new Error("Cannot find closed's tickets category, please check id/if channel type is GUILD_CATEGORY");
const ticketChannelToClose = ticket.guild.channels.cache.get(ticket.channelId);
if (!ticketChannelToClose)
return;
let newNumber = "0000" + ticket.number;
newNumber = newNumber.slice(newNumber.length - 4, newNumber.length + 2);
yield ticketChannelToClose.edit({
name: `closed-${newNumber}`,
parent: category,
permissionOverwrites: [
{
id: ticket.member.id,
deny: [discord_js_1.Permissions.FLAGS.VIEW_CHANNEL, discord_js_1.Permissions.FLAGS.SEND_MESSAGES]
},
{
id: ticket.guild.roles.everyone,
deny: [discord_js_1.Permissions.FLAGS.VIEW_CHANNEL]
}, {
id: options.staffRole,
allow: [discord_js_1.Permissions.FLAGS.VIEW_CHANNEL, discord_js_1.Permissions.FLAGS.SEND_MESSAGES]
}
]
});
let data = ticket.data;
data.status = "closed";
ticket = new TextTicket_1.TextTicket(this, data);
this.tickets.set(ticket.channelId, ticket);
let index = this.ticketRaws.indexOf(data);
this.ticketRaws[index] = data;
yield this.saveTicketRaws();
/**
* Emitted when ticket be closed
* @event TicketManager#ticketClosed
* @param {TextTicket} ticket Ticket resolvable
*/
return this.emit("ticketClosed", ticket);
});
}
/**
* ReOpen ticket
* @param {TextTicket} ticket Ticket Resolvable
* @return {Promise<any>}
*/
reOpenTicket(ticket) {
return __awaiter(this, void 0, void 0, function* () {
const options = yield this.getOptions(ticket.guild.id);
if (!options)
throw new Error("Cannot find options");
const category = ticket.guild.channels.cache.get(options.parentId);
if (!category || category.type !== "GUILD_CATEGORY")
throw new Error("Cannot find tickets category, please check id/if channel type is GUILD_CATEGORY");
const ticketChannel = ticket.guild.channels.cache.get(ticket.channelId);
if (!ticketChannel)
return;
yield ticketChannel.edit({
name: `ticket-${ticketChannel.name.split("-")[1]}`,
parent: category,
permissionOverwrites: [
{
id: ticket.memberId,
allow: [discord_js_1.Permissions.FLAGS.VIEW_CHANNEL, discord_js_1.Permissions.FLAGS.SEND_MESSAGES]
},
{
id: ticket.guild.roles.everyone,
deny: [discord_js_1.Permissions.FLAGS.VIEW_CHANNEL]
}, {
id: options.staffRole,
allow: [discord_js_1.Permissions.FLAGS.VIEW_CHANNEL, discord_js_1.Permissions.FLAGS.SEND_MESSAGES]
}
]
});
let data = ticket.data;
data.status = "open";
ticket = new TextTicket_1.TextTicket(this, data);
this.tickets.set(ticket.channelId, ticket);
let index = this.ticketRaws.indexOf(data);
this.ticketRaws[index] = data;
yield this.saveTicketRaws();
/**
* Emitted when ticket be reopen
* @event TicketManager#ticketReOpen
* @param {TextTicket} ticket Ticket resolvable
*/
return this.emit("ticketReOpen", ticket);
});
}
/**
* Rename Ticket
* @param {ThreadTicket} ticket ThreadTicket
* @param {string} name new Name
* @return {Promise<any>}
*/
renameTicket(ticket, name) {
return __awaiter(this, void 0, void 0, function* () {
let newNumber = "0000" + ticket.number;
newNumber = newNumber.slice(newNumber.length - 4, newNumber.length + 2);
yield ticket.channel.setName(`${name}-${newNumber}`);
/**
* Emitted when ticket be renamed
* @event TicketManager#ticketRename
* @param {TextTicket} ticket Ticket resolvable
*/
return this.emit("ticketRename", ticket);
});
}
}
exports.TicketManager = TicketManager;
/**
* Text Ticket Manager Config Types
* @typedef {object} TicketManagerOptions
* @property {boolean} enabled Manager status
* @property {string} parentID Category Id where are created tickets
* @property {string} staffRole Discord Role id who can access to tickets
* @property {string} closedParentID Category Id where are closed tickets
* @property {string} [channelTopic] Ticket's channel topic
* @property {boolean} ticketCache Storing tickets in the cache
* @property {StorageType} storage Storage File path
*/