UNPKG

discord-tickets

Version:

Discord.js extention library for manage easily tickets

321 lines (320 loc) 13.1 kB
"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 */