@elara-services/tickets 3.0.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +6 -0
- package/index.js +4 -3
- package/lib/base.js +1 -1
- package/lib/util.js +3 -3
- package/lib/v13.js +17 -17
- package/lib/v14.js +263 -0
- package/package.json +1 -4
package/index.d.ts
CHANGED
|
@@ -55,6 +55,12 @@ declare module "@elara-services/tickets" {
|
|
|
55
55
|
ticketCategory?: string;
|
|
56
56
|
/** @deprecated Use 'ticket.open', 'ticketOpen' will be removed in the next major version */
|
|
57
57
|
ticketOpen?: Pick<MessageOptions, "content" | "embeds">
|
|
58
|
+
|
|
59
|
+
reports?: {
|
|
60
|
+
enabled: boolean;
|
|
61
|
+
shouldBeTicket?: boolean;
|
|
62
|
+
|
|
63
|
+
}
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
class Tickets {
|
package/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
const v13 = require("./lib/v13");
|
|
2
1
|
const pack = require("./package.json");
|
|
2
|
+
|
|
3
3
|
module.exports = (() => {
|
|
4
4
|
let version = null;
|
|
5
5
|
try { version = require("discord.js").version; } catch {}
|
|
6
6
|
if (!version) throw new Error(`[${pack.name}, v${pack.version}]: I was unable to find the discord.js version you're using.`);
|
|
7
7
|
let [ major ] = version.split(".");
|
|
8
|
-
if (major === "
|
|
8
|
+
if (major === "14") return require("./lib/v14");
|
|
9
|
+
if (major === "13") return require("./lib/v13");
|
|
9
10
|
if ([ "12", "11" ].includes(major)) throw new Error(`[${pack.name}, v${pack.version}]: The discord.js version you're using is outdated and unsupported, please update to v13+`)
|
|
10
|
-
throw new Error(`[${pack.name}, v${pack.version}]: The discord.js version you're using isn't supported by this package. (currently supported: v13)`);
|
|
11
|
+
throw new Error(`[${pack.name}, v${pack.version}]: The discord.js version you're using isn't supported by this package. (currently supported: v13, v14)`);
|
|
11
12
|
})();
|
package/lib/base.js
CHANGED
|
@@ -57,7 +57,7 @@ module.exports = class Tickets {
|
|
|
57
57
|
files: [{ name: "transcript.txt", attachment: Buffer.from(displayMessages(channel, messages.reverse(), channel.name.split("-")[1], this.options.prefix)) }]
|
|
58
58
|
})
|
|
59
59
|
.then(m => {
|
|
60
|
-
let components = [{ type: 2, style: 5, label: "Transcript", emoji: { id: "792290922749624320" }, url: `https://
|
|
60
|
+
let components = [{ type: 2, style: 5, label: "Transcript", emoji: { id: "792290922749624320" }, url: `https://view.elara.workers.dev/tickets?url=${Array.isArray(m.attachments) ? m.attachments?.[0]?.url : m.attachments?.first?.()?.url ?? "URL_NOT_FOUND"}` }];
|
|
61
61
|
embeds[0].description += `\n${de.transcript} Transcript: [View here](${components[0].url})`
|
|
62
62
|
webhook(this.webhookOptions)
|
|
63
63
|
.embeds(embeds)
|
package/lib/util.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { AES } = require("@elara-services/packages"),
|
|
2
|
-
{ Collection } = require("discord.js"),
|
|
2
|
+
{ Collection, version } = require("discord.js"),
|
|
3
3
|
Webhook = require("discord-hook");
|
|
4
4
|
|
|
5
5
|
exports.code = (message, type = "d", token) => {
|
|
@@ -49,7 +49,7 @@ exports.displayMessages = (channel, messages = [], ticketID, type) => {
|
|
|
49
49
|
return [`<discord-messages>`, `<discord-message author="${type} Ticket: ${ticketID}" bot="true" verified avatar="https://cdn.discordapp.com/emojis/847397714677334066.png?v=1" role-color="#1da1f2">Total Messages: ${users.map(c => c.count).reduce((a, b) => a + b, 0).toLocaleString()}<br>${users.map(c => `<discord-mention type="role" color="${channel.guild?.members?.resolve?.(c.user.id)?.displayColor ? channel.guild?.members?.resolve?.(c.user.id)?.displayHexColor : `#ffffff`}">${c.user.tag}</discord-mention> (${c.user.id})`).join("<br>")}</discord-message></discord-messages><discord-messages>`,
|
|
50
50
|
...messages.map(message => {
|
|
51
51
|
let str = [
|
|
52
|
-
`<discord-message${message.author.bot ? ` bot="true" ${message.author.flags?.has?.("VERIFIED_BOT") ? `verified="true"` : ""}` : ""} new_timestamp="${message.createdAt.toISOString()}" author="${message.author.username}" avatar=${message.author.displayAvatarURL({ dynamic: true, format: "png" })} role-color="${channel.guild?.members?.resolve?.(message.author.id)?.displayColor ? channel.guild?.members?.resolve?.(message.author.id)?.displayHexColor : `#ffffff`}">`
|
|
52
|
+
`<discord-message${message.author.bot ? ` bot="true" ${message.author.flags?.has?.(version?.includes?.("14") ? 1 << 16 : "VERIFIED_BOT") ? `verified="true"` : ""}` : ""} new_timestamp="${message.createdAt.toISOString()}" author="${message.author.username}" avatar=${message.author.displayAvatarURL({ dynamic: true, format: "png" })} role-color="${channel.guild?.members?.resolve?.(message.author.id)?.displayColor ? channel.guild?.members?.resolve?.(message.author.id)?.displayHexColor : `#ffffff`}">`
|
|
53
53
|
];
|
|
54
54
|
if (message.content) {
|
|
55
55
|
let content = message.content;
|
|
@@ -109,7 +109,7 @@ exports.displayMessages = (channel, messages = [], ticketID, type) => {
|
|
|
109
109
|
*/
|
|
110
110
|
exports.hasTicket = ({ userId, guild, token, prefix } = {}) => {
|
|
111
111
|
if (!userId || !guild || !token || !prefix || !guild?.channels?.cache?.size) return false;
|
|
112
|
-
let channels = guild.channels.cache.filter(c => c.
|
|
112
|
+
let channels = guild.channels.cache.filter(c => [ 0, "GUILD_TEXT" ].includes(c.type) && c.topic && exports.code(c.topic.split("ID: ")[1], "d", token) === userId && c.name?.match?.(new RegExp(prefix, "gi")));
|
|
113
113
|
if (!channels.size) return false;
|
|
114
114
|
return true;
|
|
115
115
|
};
|
package/lib/v13.js
CHANGED
|
@@ -15,7 +15,7 @@ module.exports = class Tickets extends base {
|
|
|
15
15
|
if (int?.isButton?.() || int?.isModalSubmit()) {
|
|
16
16
|
let { guild, channel, member, customId } = int,
|
|
17
17
|
category = guild?.channels?.resolve?.(this.options.ticket?.category || this.options.ticketCategory || channel?.parentId);
|
|
18
|
-
if (!guild
|
|
18
|
+
if (!guild?.available || !channel || !member || !category) return;
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* @param {import("discord.js").InteractionDeferReplyOptions|import("discord.js").InteractionReplyOptions} options
|
|
@@ -31,7 +31,7 @@ module.exports = class Tickets extends base {
|
|
|
31
31
|
case this.prefix: {
|
|
32
32
|
if (this.options?.ticket?.limitOnePerUser && hasTicket({ userId: member.id, guild, token: this.options.encryptToken, prefix: this.options.prefix })) return send({ embeds: [ embed(`❌ You can only create one (${this.options.prefix}) ticket at a time.`, { guild }) ], ephemeral: true })
|
|
33
33
|
if (this.options.support?.ignore?.length) {
|
|
34
|
-
if (this.options.support.ignore.some(c => member.roles.cache.has(c))) return send({
|
|
34
|
+
if (this.options.support.ignore.some(c => member.roles.cache.has(c))) return send({ embeds: [embed(`❌ You can no longer create tickets, if you believe this is a mistake contact one of the staff members.`)], ephemeral: true });
|
|
35
35
|
}
|
|
36
36
|
if (this.options.modal?.enabled) return int.showModal(this.modal({ title: this.options.modal.title, components: this.options.modal.questions?.length >= 1 ? this.options.modal.questions.slice(0, 5).map(c => ({ type: 1, components: [{ min_length: c.min_length || 10, max_length: c.max_length || 4000, type: 4, style: c.style || 2, label: c.label, value: c.value, placeholder: c.placeholder, required: c.required, custom_id: c.label || `random_${Math.floor(Math.random() * 10000)}` }] })) : [] })).catch(e => this._debug(e));
|
|
37
37
|
return this.handleCreate({ guild, member, category, send })
|
|
@@ -90,21 +90,21 @@ module.exports = class Tickets extends base {
|
|
|
90
90
|
let reason = "No Reason Provided";
|
|
91
91
|
if (int.isModalSubmit()) reason = int.fields.getTextInputValue("reason")
|
|
92
92
|
let user = await this.options.client.users.fetch(customId.split("close:confirm:")[1].replace(/:modal_complete/gi, "")).catch(e => this._debug(e));
|
|
93
|
-
if (!user) return send({
|
|
93
|
+
if (!user) return send({ embeds: [ embed(`❌ I was unable to fetch the user that opened the ticket.`) ] });
|
|
94
94
|
let messages = await fetchMessages(channel, 5000);
|
|
95
|
-
if (!messages?.length) return send({
|
|
95
|
+
if (!messages?.length) return send({ embeds: [ embed(`❌ I was unable to close the ticket, I couldn't fetch the messages in this channel.`) ] });
|
|
96
96
|
let closed = await channel.delete(`${member.user.tag} (${member.id}) closed the ticket.`).catch(e => this._debug(e));
|
|
97
|
-
if (!closed) return send({
|
|
97
|
+
if (!closed) return send({ embeds: [ embed(`❌ I was unable to delete the channel and close the ticket.`) ] });
|
|
98
98
|
return this.closeTicket({ channel, guild, user, member, messages, reason });
|
|
99
99
|
};
|
|
100
100
|
|
|
101
101
|
if (customId.startsWith("unban:")) {
|
|
102
|
-
if (!int.memberPermissions?.has?.([ "BAN_MEMBERS" ])) return send({
|
|
102
|
+
if (!int.memberPermissions?.has?.([ "BAN_MEMBERS" ])) return send({ embeds: [ embed(`❌ You need (Ban Members) in this server to complete this action!`) ], ephemeral: true });
|
|
103
103
|
let server = getAppealServer(this.options);
|
|
104
|
-
if (!server) return send({
|
|
104
|
+
if (!server) return send({ embeds: [embed(`❌ I was unable to find the appeal server!`)], ephemeral: true });
|
|
105
105
|
let mod = server.members.resolve(member.id) || await server.members.fetch(member.id).catch(e => this._debug(e));
|
|
106
|
-
if (!mod) return send({
|
|
107
|
-
if (!mod.permissions?.has?.([ "BAN_MEMBERS" ])) return send({
|
|
106
|
+
if (!mod) return send({ embeds: [embed(`❌ I was unable to find you in ${server.name}!`)], ephemeral: true });
|
|
107
|
+
if (!mod.permissions?.has?.([ "BAN_MEMBERS" ])) return send({ embeds: [embed(`❌ You need (Ban Members) in ${server.name} to complete this action!`)], ephemeral: true });
|
|
108
108
|
return int.showModal(modal({
|
|
109
109
|
id: `unban_modal:${customId.split(":")[1]}`,
|
|
110
110
|
title: `Unban From ${server.name}`,
|
|
@@ -115,20 +115,20 @@ module.exports = class Tickets extends base {
|
|
|
115
115
|
if (customId.startsWith("unban_modal:")) {
|
|
116
116
|
await send({ ephemeral: true }, true);
|
|
117
117
|
const [ , id ] = customId.split(":");
|
|
118
|
-
if (!int.memberPermissions?.has?.([ "BAN_MEMBERS" ])) return send({
|
|
118
|
+
if (!int.memberPermissions?.has?.([ "BAN_MEMBERS" ])) return send({ embeds: [ embed(`❌ You need (Ban Members) in this server to complete this action!`)] });
|
|
119
119
|
let server = getAppealServer(this.options);
|
|
120
|
-
if (!server) return send({
|
|
120
|
+
if (!server) return send({ embeds: [embed(`❌ I was unable to find the appeal server!`)] });
|
|
121
121
|
let mod = server.members.resolve(member.id) || await server.members.fetch(member.id).catch(e => this._debug(e));
|
|
122
|
-
if (!mod) return send({
|
|
123
|
-
if (!mod.permissions?.has?.([ "BAN_MEMBERS" ])) return send({
|
|
122
|
+
if (!mod) return send({ embeds: [embed(`❌ I was unable to find you in ${server.name}!`)] });
|
|
123
|
+
if (!mod.permissions?.has?.([ "BAN_MEMBERS" ])) return send({ embeds: [embed(`❌ You need (Ban Members) in ${server.name} to complete this action!`)] });
|
|
124
124
|
let isBanned = await server.bans.fetch({ user: id, force: true }).catch(e => this._debug(e));
|
|
125
|
-
if (!isBanned) return send({
|
|
125
|
+
if (!isBanned) return send({ embeds: [embed(`❌ User (<@${id}>) isn't banned in the main server!`)] });
|
|
126
126
|
return server.bans.remove(id, int.fields.getTextInputValue("reason") ?? `No Reason Provided | By: ${member.user.tag} (${member.id})`)
|
|
127
127
|
.then(() => {
|
|
128
128
|
int.message.edit({ components: [ { type: 1, components: [ button({ title: "Unbanned!", style: 3, id: "_ _", disabled: true, emoji: { id: `476629550797684736` } }) ] } ] }).catch(e => this._debug(e));
|
|
129
|
-
send({
|
|
129
|
+
send({ embeds: [embed(`✅ Successfully unbanned <@${id}> from ${server.name}!`)] })
|
|
130
130
|
})
|
|
131
|
-
.catch(e => send({
|
|
131
|
+
.catch(e => send({ embeds: [ { title: "ERROR", fields: [ { name: "\u200b", value: `❌ Unable to unban <@${id} from ${server.name}!` } ], description: `\`\`\`js\n${e.message ?? e.stack}\`\`\``, color: 0xFF0000 } ] }))
|
|
132
132
|
}
|
|
133
133
|
};
|
|
134
134
|
};
|
|
@@ -185,7 +185,7 @@ module.exports = class Tickets extends base {
|
|
|
185
185
|
...permissions
|
|
186
186
|
]
|
|
187
187
|
}).catch(e => this._debug(e));
|
|
188
|
-
if (!channel) return send({
|
|
188
|
+
if (!channel) return send({ embeds: [embed(`❌ I was unable to create the ticket channel, if this keeps happening contact one of the staff members via their DMs!`)] });
|
|
189
189
|
let msg = await channel.send({
|
|
190
190
|
content: (this.options.ticket?.open || this.options.ticketOpen)?.content?.replace?.(/%user%/gi, member.user.toString())?.replace?.(/%server%/gi, guild.name) || `${member.user.toString()} 👋 Hello, please explain what you need help with.`,
|
|
191
191
|
embeds: (this.options.ticket?.open || this.options.ticketOpen)?.embeds || [ embed(undefined, { title: `Support will be with you shortly.`, color: 0xF50DE3, guild, footer: { text: `To close the ticket, press the button below` } }) ],
|
package/lib/v14.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
const { EmbedBuilder: MessageEmbed, InteractionType, PermissionFlagsBits, ChannelType } = require("discord.js"),
|
|
2
|
+
base = require("./base"),
|
|
3
|
+
{ de, code, fetchMessages, hasTicket, embed, webhook, getAppealServer } = require("./util"),
|
|
4
|
+
{ generate } = require("shortid"),
|
|
5
|
+
{ Interactions: { button, modal } } = require("@elara-services/packages");
|
|
6
|
+
|
|
7
|
+
module.exports = class Tickets extends base {
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
super(options);
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* @param {import("discord.js").Interaction} int
|
|
13
|
+
*/
|
|
14
|
+
async run(int) {
|
|
15
|
+
if (!int) return;
|
|
16
|
+
if (int.isButton() || int.type === InteractionType.ModalSubmit) {
|
|
17
|
+
let { guild, channel, member, customId } = int,
|
|
18
|
+
category = guild?.channels?.resolve?.(this.options.ticket?.category || this.options.ticketCategory || channel?.parentId);
|
|
19
|
+
if (!guild?.available || !channel || !member || !category) return;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {import("discord.js").InteractionDeferReplyOptions|import("discord.js").InteractionReplyOptions} options
|
|
23
|
+
* @param {boolean} edit
|
|
24
|
+
* @param {boolean} defer
|
|
25
|
+
*/
|
|
26
|
+
const send = async (options = {}, defer = false) => {
|
|
27
|
+
if (defer) return int.deferReply(options).catch(e => this._debug(e));
|
|
28
|
+
if (int.replied || int.deferred) return int.editReply(options).catch(e => this._debug(e));
|
|
29
|
+
return int.reply(options).catch(e => this._debug(e));
|
|
30
|
+
};
|
|
31
|
+
switch (customId) {
|
|
32
|
+
case this.prefix: {
|
|
33
|
+
if (this.options?.ticket?.limitOnePerUser && hasTicket({ userId: member.id, guild, token: this.options.encryptToken, prefix: this.options.prefix })) return send({ embeds: [ embed(`❌ You can only create one (${this.options.prefix}) ticket at a time.`, { guild }) ], ephemeral: true })
|
|
34
|
+
if (this.options.support?.ignore?.length) {
|
|
35
|
+
if (this.options.support.ignore.some(c => member.roles?.cache?.has?.(c))) return send({ embeds: [embed(`❌ You can no longer create tickets, if you believe this is a mistake contact one of the staff members.`)], ephemeral: true });
|
|
36
|
+
}
|
|
37
|
+
if (this.options.modal?.enabled) return int.showModal(this.modal({ title: this.options.modal.title, components: this.options.modal.questions?.length >= 1 ? this.options.modal.questions.slice(0, 5).map(c => ({ type: 1, components: [{ min_length: c.min_length || 10, max_length: c.max_length || 4000, type: 4, style: c.style || 2, label: c.label, value: c.value, placeholder: c.placeholder, required: c.required, custom_id: c.label || `random_${Math.floor(Math.random() * 10000)}` }] })) : [] })).catch(e => this._debug(e));
|
|
38
|
+
return this.handleCreate({ guild, member, category, send })
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
case `${this.prefix}:close`: {
|
|
42
|
+
if (this.options.support?.canOnlyCloseTickets && !member.permissions.has(PermissionFlagsBits.ManageGuild)) {
|
|
43
|
+
if (!this.getSupportIds.users?.includes?.(member.id)) {
|
|
44
|
+
if (!this.getSupportIds.roles?.some?.(c => member.roles?.cache?.has?.(c))) return send({ ephemeral: true, embeds: [{ author: { name: `Only support staff can close tickets`, iconURL: "https://cdn.discordapp.com/emojis/781955502035697745.gif" }, color: 0xFF0000 }] })
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return send({
|
|
48
|
+
ephemeral: true,
|
|
49
|
+
embeds: [ embed(`🤔 Are you sure you want to close the ticket?`, { color: 0xFF000, guild }) ],
|
|
50
|
+
components: [
|
|
51
|
+
{ type: 1, components: [
|
|
52
|
+
button({ title: "Yes, close the ticket!", style: 3, emoji: { id: "807031399563264030" }, id: `${this.prefix}:close:confirm:${code(channel.topic?.split?.("ID: ")?.[1], "d", this.options.encryptToken)}${this.options?.ticket?.closeReason ? `:modal_submit` : ""}` })
|
|
53
|
+
]
|
|
54
|
+
}]
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
case `${this.prefix}:modal_submit`: {
|
|
59
|
+
let [embed, fields, split] = [new MessageEmbed().setColor("Orange").setTimestamp().setTitle(`For Responses`).setFooter({ text: `ID: ${member.id}` }).setAuthor({ name: member.user.username, iconURL: member.user.displayAvatarURL({ dynamic: true }) }), [], false];
|
|
60
|
+
for (const c of int.fields.components) {
|
|
61
|
+
for (const cc of c.components) {
|
|
62
|
+
if (cc.value && cc.customId) {
|
|
63
|
+
fields.push({ name: cc.customId, value: cc.value });
|
|
64
|
+
if (cc.value.length <= 1024) embed.addFields({ name: cc.customId, value: cc.value });
|
|
65
|
+
else split = true
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (embed.length >= 6000 || split) {
|
|
70
|
+
return this.handleCreate({
|
|
71
|
+
guild, member, category, send, embeds: fields.map((v, i) => ({
|
|
72
|
+
title: `Form Response: ${v.name}`, color: embed.color, description: v.value,
|
|
73
|
+
author: i === 0 ? { name: member.user.username, iconURL: member.user.displayAvatarURL({ dynamic: true }) } : undefined,
|
|
74
|
+
timestamp: fields.length - 1 === i ? new Date() : undefined,
|
|
75
|
+
footer: fields.length - 1 === i ? { text: `ID: ${member.id}` } : undefined
|
|
76
|
+
}))
|
|
77
|
+
})
|
|
78
|
+
};
|
|
79
|
+
return this.handleCreate({ guild, member, category, send, embeds: [embed] })
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
if (customId.startsWith(`${this.prefix}:close:confirm`)) {
|
|
83
|
+
if (customId.includes(`:modal_submit`)) {
|
|
84
|
+
return int.showModal(modal({
|
|
85
|
+
id: `${customId.split(":modal_submit")[0]}:modal_complete`,
|
|
86
|
+
title: "Reason",
|
|
87
|
+
components: [ { type: 1, components: [ { type: 4, custom_id: "reason", label: "Reason", style: 2, min_length: 1, max_length: 1024, required: true, placeholder: "What's the reason for closing the ticket?" } ] } ]
|
|
88
|
+
}))
|
|
89
|
+
}
|
|
90
|
+
await send({ ephemeral: true }, true);
|
|
91
|
+
let reason = "No Reason Provided";
|
|
92
|
+
if (int.type === InteractionType.ModalSubmit) reason = int.fields.getTextInputValue("reason")
|
|
93
|
+
let user = await this.options.client.users.fetch(customId.split("close:confirm:")[1].replace(/:modal_complete/gi, "")).catch(e => this._debug(e));
|
|
94
|
+
if (!user) return send({ embeds: [ embed(`❌ I was unable to fetch the user that opened the ticket.`) ] });
|
|
95
|
+
let messages = await fetchMessages(channel, 5000);
|
|
96
|
+
if (!messages?.length) return send({ embeds: [ embed(`❌ I was unable to close the ticket, I couldn't fetch the messages in this channel.`) ] });
|
|
97
|
+
let closed = await channel.delete(`${member.user.tag} (${member.id}) closed the ticket.`).catch(e => this._debug(e));
|
|
98
|
+
if (!closed) return send({ embeds: [ embed(`❌ I was unable to delete the channel and close the ticket.`) ] });
|
|
99
|
+
return this.closeTicket({ channel, guild, user, member, messages, reason });
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
if (customId.startsWith("unban:")) {
|
|
103
|
+
if (!int.memberPermissions?.has?.(PermissionFlagsBits.BanMembers)) return send({ embeds: [ embed(`❌ You need (Ban Members) in this server to complete this action!`) ], ephemeral: true });
|
|
104
|
+
let server = getAppealServer(this.options);
|
|
105
|
+
if (!server) return send({ embeds: [embed(`❌ I was unable to find the appeal server!`)], ephemeral: true });
|
|
106
|
+
let mod = server.members.resolve(member.id) || await server.members.fetch(member.id).catch(e => this._debug(e));
|
|
107
|
+
if (!mod) return send({ embeds: [embed(`❌ I was unable to find you in ${server.name}!`)], ephemeral: true });
|
|
108
|
+
if (!mod.permissions?.has?.(PermissionFlagsBits.BanMembers)) return send({ embeds: [embed(`❌ You need (Ban Members) in ${server.name} to complete this action!`)], ephemeral: true });
|
|
109
|
+
return int.showModal(modal({
|
|
110
|
+
id: `unban_modal:${customId.split(":")[1]}`,
|
|
111
|
+
title: `Unban From ${server.name}`,
|
|
112
|
+
components: [ { type: 1, components: [ { type: 4, label: "Reason", custom_id: "reason", style: 2, min_length: 1, max_length: 512, required: true, value: `No Reason Provided | By: ${member.user.tag} (${member.id})` } ] } ]
|
|
113
|
+
})).catch(e => this._debug(e));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (customId.startsWith("unban_modal:")) {
|
|
117
|
+
await send({ ephemeral: true }, true);
|
|
118
|
+
const [ , id ] = customId.split(":");
|
|
119
|
+
if (!int.memberPermissions?.has?.(PermissionFlagsBits.BanMembers)) return send({ embeds: [ embed(`❌ You need (Ban Members) in this server to complete this action!`)] });
|
|
120
|
+
let server = getAppealServer(this.options);
|
|
121
|
+
if (!server) return send({ embeds: [embed(`❌ I was unable to find the appeal server!`)] });
|
|
122
|
+
let mod = server.members.resolve(member.id) || await server.members.fetch(member.id).catch(e => this._debug(e));
|
|
123
|
+
if (!mod) return send({ embeds: [embed(`❌ I was unable to find you in ${server.name}!`)] });
|
|
124
|
+
if (!mod.permissions?.has?.(PermissionFlagsBits.BanMembers)) return send({ embeds: [embed(`❌ You need (Ban Members) in ${server.name} to complete this action!`)] });
|
|
125
|
+
let isBanned = await server.bans.fetch({ user: id, force: true }).catch(e => this._debug(e));
|
|
126
|
+
if (!isBanned) return send({ embeds: [embed(`❌ User (<@${id}>) isn't banned in the main server!`)] });
|
|
127
|
+
return server.bans.remove(id, int.fields.getTextInputValue("reason") ?? `No Reason Provided | By: ${member.user.tag} (${member.id})`)
|
|
128
|
+
.then(() => {
|
|
129
|
+
int.message.edit({ components: [ { type: 1, components: [ button({ title: "Unbanned!", style: 3, id: "_ _", disabled: true, emoji: { id: `476629550797684736` } }) ] } ] }).catch(e => this._debug(e));
|
|
130
|
+
send({ embeds: [embed(`✅ Successfully unbanned <@${id}> from ${server.name}!`)] })
|
|
131
|
+
})
|
|
132
|
+
.catch(e => send({ embeds: [ { title: "ERROR", fields: [ { name: "\u200b", value: `❌ Unable to unban <@${id} from ${server.name}!` } ], description: `\`\`\`js\n${e.message ?? e.stack}\`\`\``, color: 0xFF0000 } ] }))
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/** @private */
|
|
138
|
+
async handleCreate({ guild, member, category, send, embeds = [] } = {}) {
|
|
139
|
+
await send({ ephemeral: true }, true);
|
|
140
|
+
let [ permissions, allow, { appeals }, sendBanReason ] = [
|
|
141
|
+
[],
|
|
142
|
+
[
|
|
143
|
+
PermissionFlagsBits.AddReactions,
|
|
144
|
+
PermissionFlagsBits.AttachFiles,
|
|
145
|
+
PermissionFlagsBits.CreateInstantInvite,
|
|
146
|
+
PermissionFlagsBits.EmbedLinks,
|
|
147
|
+
PermissionFlagsBits.ReadMessageHistory,
|
|
148
|
+
PermissionFlagsBits.ViewChannel,
|
|
149
|
+
PermissionFlagsBits.UseExternalEmojis,
|
|
150
|
+
PermissionFlagsBits.SendMessages
|
|
151
|
+
],
|
|
152
|
+
this.options ?? {},
|
|
153
|
+
null
|
|
154
|
+
];
|
|
155
|
+
if (this.getSupportIds.roles.length) for (const sup of this.getSupportIds.roles) {
|
|
156
|
+
let role = guild.roles.resolve(sup);
|
|
157
|
+
if (role) permissions.push({ type: "role", id: sup, allow });
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
if (this.getSupportIds.users.length) for (const uId of this.getSupportIds.users) {
|
|
161
|
+
let member = guild.members.resolve(uId) || await guild.members.fetch(uId).catch((e) => {
|
|
162
|
+
if (e?.stack?.includes?.("Unknown Member")) this.options.support.users = this.options.support.users.filter(c => c !== uId);
|
|
163
|
+
return this._debug(e);
|
|
164
|
+
});
|
|
165
|
+
if (member) permissions.push({ type: "member", id: uId, allow });
|
|
166
|
+
}
|
|
167
|
+
if (appeals?.enabled) {
|
|
168
|
+
let server = getAppealServer(this.options);
|
|
169
|
+
if (server) {
|
|
170
|
+
let ban = await server.bans.fetch({ user: member.id, force: true }).catch(e => this._debug(e));
|
|
171
|
+
if (!ban) return send(
|
|
172
|
+
typeof appeals.embeds?.not_banned === "object" ?
|
|
173
|
+
appeals.embeds.not_banned :
|
|
174
|
+
{ embeds: [ embed(`❌ You can't open this ticket due to you not being banned in the main server!`, { guild, color: 0xFF0000 }) ] }
|
|
175
|
+
);
|
|
176
|
+
sendBanReason = {
|
|
177
|
+
embeds: [ embed(ban?.reason ?? "No Reason Provided", { title: "Ban Reason", guild: server }) ],
|
|
178
|
+
components: [
|
|
179
|
+
{
|
|
180
|
+
type: 1, components: [
|
|
181
|
+
button({ id: `unban:${member.id}`, style: 4, title: "Unban", emoji: { name: "🔒" } })
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
let channel = await guild.channels.create({
|
|
189
|
+
name: `${this.options.prefix}-${generate().slice(0, 5).replace(/-|_/g, "")}`,
|
|
190
|
+
type: ChannelType.GuildText,
|
|
191
|
+
parent: category,
|
|
192
|
+
reason: `Ticket created by: @${member.user.tag} (${member.id})`,
|
|
193
|
+
topic: `ID: ${code(member.id, "e", this.options.encryptToken)}`,
|
|
194
|
+
permissionOverwrites: [
|
|
195
|
+
{
|
|
196
|
+
type: "member",
|
|
197
|
+
id: this.options.client.user.id,
|
|
198
|
+
allow: [
|
|
199
|
+
PermissionFlagsBits.AddReactions,
|
|
200
|
+
PermissionFlagsBits.AttachFiles,
|
|
201
|
+
PermissionFlagsBits.SendMessages,
|
|
202
|
+
PermissionFlagsBits.ReadMessageHistory,
|
|
203
|
+
PermissionFlagsBits.EmbedLinks,
|
|
204
|
+
PermissionFlagsBits.UseExternalEmojis,
|
|
205
|
+
PermissionFlagsBits.ViewChannel,
|
|
206
|
+
PermissionFlagsBits.MentionEveryone
|
|
207
|
+
]
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
type: "member",
|
|
211
|
+
id: member.id,
|
|
212
|
+
allow: [
|
|
213
|
+
PermissionFlagsBits.AddReactions,
|
|
214
|
+
PermissionFlagsBits.AttachFiles,
|
|
215
|
+
PermissionFlagsBits.SendMessages,
|
|
216
|
+
PermissionFlagsBits.ReadMessageHistory,
|
|
217
|
+
PermissionFlagsBits.EmbedLinks,
|
|
218
|
+
PermissionFlagsBits.UseExternalEmojis,
|
|
219
|
+
PermissionFlagsBits.ViewChannel
|
|
220
|
+
],
|
|
221
|
+
deny: [ PermissionFlagsBits.MentionEveryone ]
|
|
222
|
+
},
|
|
223
|
+
{ type: "role", id: guild.id, deny: [ PermissionFlagsBits.ViewChannel ] },
|
|
224
|
+
...permissions
|
|
225
|
+
]
|
|
226
|
+
}).catch(e => this._debug(e));
|
|
227
|
+
if (!channel) return send({ embeds: [embed(`❌ I was unable to create the ticket channel, if this keeps happening contact one of the staff members via their DMs!`)] });
|
|
228
|
+
let msg = await channel.send({
|
|
229
|
+
content: (this.options.ticket?.open || this.options.ticketOpen)?.content?.replace?.(/%user%/gi, member.user.toString())?.replace?.(/%server%/gi, guild.name) || `${member.user.toString()} 👋 Hello, please explain what you need help with.`,
|
|
230
|
+
embeds: (this.options.ticket?.open || this.options.ticketOpen)?.embeds || [ embed(undefined, { title: `Support will be with you shortly.`, color: 0xF50DE3, guild, footer: { text: `To close the ticket, press the button below` } }) ],
|
|
231
|
+
components: [ { type: 1, components: [ button({ id: `${this.prefix}:close`, title: `Close Ticket`, style: 4, emoji: { name: "🔒" } }) ] }]
|
|
232
|
+
}).catch(e => this._debug(e));
|
|
233
|
+
if (!msg) return null;
|
|
234
|
+
if (sendBanReason) await channel.send(sendBanReason).catch(e => this._debug(e));
|
|
235
|
+
if (embeds?.length <= 10) for await (const embed of embeds) await channel.send({ embeds: [embed] }).catch(e => this._debug(e));
|
|
236
|
+
if (this.webhookOptions.id && this.webhookOptions.token) webhook(this.webhookOptions)
|
|
237
|
+
.embed(embed(`${de.user} User: ${member.user.toString()} \`@${member.user.tag}\` (${member.id})\n${de.channel} Channel: \`#${channel.name}\` (${channel.id})`, {
|
|
238
|
+
title: `TIcket: Opened`,
|
|
239
|
+
color: 0xFF000,
|
|
240
|
+
footer: { text: `Ticket ID: ${channel.name.split("-")[1]}` },
|
|
241
|
+
guild
|
|
242
|
+
})).send().catch(e => this._debug(e));
|
|
243
|
+
return send({
|
|
244
|
+
embeds: [ embed(channel.toString(), { color: 0xFF000, author: { name: `Ticket Created!`, icon_url: `https://cdn.discordapp.com/emojis/476629550797684736.gif` } }) ],
|
|
245
|
+
components: [{ type: 1, components: [button({ title: "Go to ticket", url: msg.url })] }]
|
|
246
|
+
})
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async starterMessage(channelId, options) {
|
|
250
|
+
let channel = this.options.client.channels.resolve(channelId);
|
|
251
|
+
if (!channel) return Promise.reject(`No channel found for: ${channelId}`);
|
|
252
|
+
if (!channel.isText()) return Promise.reject(`The channel ID provided isn't a text-based-channel`);
|
|
253
|
+
if (!channel.permissionsFor?.(this.options.client.user.id)?.has?.([
|
|
254
|
+
PermissionFlagsBits.ViewChannel,
|
|
255
|
+
PermissionFlagsBits.SendMessages,
|
|
256
|
+
PermissionFlagsBits.AttachFiles,
|
|
257
|
+
PermissionFlagsBits.EmbedLinks,
|
|
258
|
+
PermissionFlagsBits.ReadMessageHistory
|
|
259
|
+
])) return Promise.reject(`I'm missing permissions in ${channel.name} (${channelId})`);
|
|
260
|
+
return channel.send({ content: options?.content, files: options?.attachments, embeds: options?.embeds, components: options?.components || [{ type: 1, components: [this.button()] }] })
|
|
261
|
+
.then(() => console.log(`Sent the starter message in ${channel.name} (${channel.id})`))
|
|
262
|
+
};
|
|
263
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elara-services/tickets",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.1",
|
|
4
4
|
"description": "Helper for tickets",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -10,9 +10,6 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"lint": "eslint ."
|
|
12
12
|
},
|
|
13
|
-
"optionalDependencies": {
|
|
14
|
-
"discord.js": "13.9.0"
|
|
15
|
-
},
|
|
16
13
|
"dependencies": {
|
|
17
14
|
"@elara-services/packages": "5.0.0",
|
|
18
15
|
"discord-hook": "2.0.0",
|