@elara-services/tickets 2.2.0 → 2.4.0
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 +2 -0
- package/index.js +115 -48
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ declare module "@elara-services/tickets" {
|
|
|
12
12
|
ticketOpen?: Pick<MessageOptions, "content" | "embeds">
|
|
13
13
|
appeals?: {
|
|
14
14
|
enabled: boolean;
|
|
15
|
+
sendBanResults?: boolean;
|
|
15
16
|
mainserver: {
|
|
16
17
|
id: string;
|
|
17
18
|
checkIfBanned: boolean;
|
|
@@ -43,6 +44,7 @@ declare module "@elara-services/tickets" {
|
|
|
43
44
|
roles?: string[];
|
|
44
45
|
users?: string[];
|
|
45
46
|
canOnlyCloseTickets?: boolean;
|
|
47
|
+
ignore?: string[]
|
|
46
48
|
};
|
|
47
49
|
|
|
48
50
|
/** @deprecated Use 'webhook.id' */
|
package/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
const { Collection, WebhookClient, MessageEmbed } = require("discord.js"),
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
{ generate } = require("shortid"),
|
|
3
|
+
{ Interactions: { button, modal }, AES } = require("@elara-services/packages"),
|
|
4
|
+
Webhook = require("discord-hook"),
|
|
5
|
+
de = {
|
|
6
|
+
user: "<:Members:860931214232125450>",
|
|
7
|
+
channel: "<:Channel:841654412509839390>",
|
|
8
|
+
transcript: "<:Log:792290922749624320>"
|
|
9
|
+
};
|
|
10
10
|
|
|
11
11
|
module.exports = class Tickets {
|
|
12
12
|
constructor(options = {}) {
|
|
@@ -26,7 +26,7 @@ module.exports = class Tickets {
|
|
|
26
26
|
avatar: this.options.webhook?.avatar || this.options.webhookAvatar || "https://cdn.discordapp.com/emojis/818757771310792704.png?v=1"
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
webhook() {
|
|
31
31
|
const { id, token, username, avatar } = this.webhookOptions;
|
|
32
32
|
return new Webhook(`https://discord.com/api/webhooks/${id}/${token}`, { username, avatar_url: avatar });
|
|
@@ -53,21 +53,25 @@ module.exports = class Tickets {
|
|
|
53
53
|
};
|
|
54
54
|
switch (customId) {
|
|
55
55
|
case this.prefix: {
|
|
56
|
+
if (this.options.support?.ignore?.length) {
|
|
57
|
+
if (this.options.support.ignore.some(c => member.roles.cache.has(c))) return send({ content: `❌ You can no longer create tickets, if you believe this is a mistake contact one of the staff members.`, ephemeral: true });
|
|
58
|
+
}
|
|
56
59
|
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));
|
|
57
60
|
return this.handleCreate({ guild, member, category, send })
|
|
58
61
|
};
|
|
59
62
|
|
|
60
63
|
case `${this.prefix}:close`: {
|
|
61
64
|
if (this.options.support?.canOnlyCloseTickets && !member.permissions.has("MANAGE_GUILD")) {
|
|
62
|
-
let [
|
|
63
|
-
if (!support.users?.includes?.(member.id))
|
|
64
|
-
|
|
65
|
+
let [support, staffOnly] = [this.getSupportIds(), () => send({ ephemeral: true, embeds: [{ author: { name: `Only support staff can close tickets`, iconURL: "https://cdn.discordapp.com/emojis/781955502035697745.gif" }, color: 0xFF0000 }] })];
|
|
66
|
+
if (!support.users?.includes?.(member.id)) {
|
|
67
|
+
if (!support.roles?.some?.(c => member.roles.cache.has(c))) return staffOnly()
|
|
68
|
+
}
|
|
65
69
|
}
|
|
66
70
|
return send({ ephemeral: true, content: `🤔 Are you sure you want to close this ticket?`, components: [{ type: 1, components: [{ type: 2, custom_id: `${this.prefix}:close:confirm:${this.code(channel.topic?.split?.("ID: ")?.[1])}`, label: "Yes close the ticket", style: 4, emoji: { id: "807031399563264030" } }] }] })
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
case `${this.prefix}:modal_submit`: {
|
|
70
|
-
let [
|
|
74
|
+
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];
|
|
71
75
|
for (const c of int.fields.components) {
|
|
72
76
|
for (const cc of c.components) {
|
|
73
77
|
if (cc.value && cc.customId) {
|
|
@@ -78,36 +82,82 @@ module.exports = class Tickets {
|
|
|
78
82
|
}
|
|
79
83
|
}
|
|
80
84
|
if (embed.length >= 6000 || split) {
|
|
81
|
-
return this.handleCreate({
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
return this.handleCreate({
|
|
86
|
+
guild, member, category, send, embeds: fields.map((v, i) => ({
|
|
87
|
+
title: `Form Response: ${v.name}`, color: embed.color, description: v.value,
|
|
88
|
+
author: i === 0 ? { name: member.user.username, iconURL: member.user.displayAvatarURL({ dynamic: true }) } : undefined,
|
|
89
|
+
timestamp: fields.length - 1 === i ? new Date() : undefined,
|
|
90
|
+
footer: fields.length - 1 === i ? { text: `ID: ${member.id}` } : undefined
|
|
91
|
+
}))
|
|
92
|
+
})
|
|
87
93
|
};
|
|
88
|
-
return this.handleCreate({ guild, member, category, send, embeds: [
|
|
94
|
+
return this.handleCreate({ guild, member, category, send, embeds: [embed] })
|
|
89
95
|
}
|
|
90
96
|
};
|
|
91
97
|
if (customId.startsWith(`${this.prefix}:close:confirm`)) {
|
|
92
98
|
await send({ ephemeral: true }, true);
|
|
93
|
-
let user = await this.options.client.users.fetch(customId.split("close:confirm:")[1]).catch(
|
|
99
|
+
let user = await this.options.client.users.fetch(customId.split("close:confirm:")[1]).catch(e => this._debug(e));
|
|
94
100
|
if (!user) return send({ content: `❌ I was unable to fetch the user that opened the ticket.` })
|
|
95
101
|
let messages = await this.fetchMessages(channel, 5000);
|
|
96
102
|
if (!messages?.length) return send({ content: `❌ I was unable to close the ticket, I couldn't fetch the messages in this channel.` })
|
|
97
103
|
let closed = await channel.delete(`${member.user.tag} (${member.id}) closed the ticket.`).catch(e => this._debug(e));
|
|
98
104
|
if (!closed) return send({ content: `❌ I was unable to delete the channel & close the ticket.` })
|
|
99
105
|
return this.closeTicket({ channel, guild, user, member, messages });
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
if (customId.startsWith("unban:")) {
|
|
109
|
+
if (!int.memberPermissions?.has?.([ "BAN_MEMBERS" ])) return send({ content: `❌ You need (Ban Members) in this server to complete this action!`, ephemeral: true });
|
|
110
|
+
let server = this.getAppealServer();
|
|
111
|
+
if (!server) return send({ content: `❌ I was unable to find the appeal server!`, ephemeral: true });
|
|
112
|
+
let mod = server.members.resolve(member.id) || await server.members.fetch(member.id).catch(e => this._debug(e));
|
|
113
|
+
if (!mod) return send({ content: `❌ I was unable to find you in ${server.name}!`, ephemeral: true });
|
|
114
|
+
if (!mod.permissions?.has?.([ "BAN_MEMBERS" ])) return send({ content: `❌ You need (Ban Members) in ${server.name} to complete this action!`, ephemeral: true });
|
|
115
|
+
return int.showModal(modal({
|
|
116
|
+
id: `unban_modal:${customId.split(":")[1]}`,
|
|
117
|
+
title: `Unban From ${server.name}`,
|
|
118
|
+
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})` } ] } ]
|
|
119
|
+
})).catch(e => this._debug(e));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (customId.startsWith("unban_modal:")) {
|
|
123
|
+
await send({ ephemeral: true }, true);
|
|
124
|
+
const [ , id ] = customId.split(":");
|
|
125
|
+
if (!int.memberPermissions?.has?.([ "BAN_MEMBERS" ])) return send({ content: `❌ You need (Ban Members) in this server to complete this action!` });
|
|
126
|
+
let server = this.getAppealServer();
|
|
127
|
+
if (!server) return send({ content: `❌ I was unable to find the appeal server!` });
|
|
128
|
+
let mod = server.members.resolve(member.id) || await server.members.fetch(member.id).catch(e => this._debug(e));
|
|
129
|
+
if (!mod) return send({ content: `❌ I was unable to find you in ${server.name}!` });
|
|
130
|
+
if (!mod.permissions?.has?.([ "BAN_MEMBERS" ])) return send({ content: `❌ You need (Ban Members) in ${server.name} to complete this action!` });
|
|
131
|
+
let isBanned = await server.bans.fetch({ user: id, force: true }).catch(e => this._debug(e));
|
|
132
|
+
if (!isBanned) return send({ content: `❌ User (<@${id}>) isn't banned in the main server!` });
|
|
133
|
+
return server.bans.remove(id, int.fields.getTextInputValue("reason") ?? `No Reason Provided | By: ${member.user.tag} (${member.id})`)
|
|
134
|
+
.then(() => {
|
|
135
|
+
int.message.edit({ components: [ { type: 1, components: [ button({ title: "Unbanned!", style: 3, id: "_ _", disabled: true, emoji: { id: `476629550797684736` } }) ] } ] }).catch(e => this._debug(e));
|
|
136
|
+
send({ content: `✅ Successfully unbanned <@${id}> from ${server.name}!` })
|
|
137
|
+
})
|
|
138
|
+
.catch(e => send({ content: `❌ Unable to unban <@${id} from ${server.name}!`, embeds: [ { title: "ERROR", description: `\`\`\`js\n${e.message ?? e.stack}\`\`\``, color: 0xFF0000 } ] }))
|
|
100
139
|
}
|
|
101
140
|
};
|
|
102
141
|
};
|
|
142
|
+
/**
|
|
143
|
+
* @returns {import("discord.js").Guild|null}
|
|
144
|
+
*/
|
|
145
|
+
getAppealServer() {
|
|
146
|
+
const { appeals, client } = this.options;
|
|
147
|
+
if (!appeals?.enabled || !appeals?.mainserver?.checkIfBanned) return null;
|
|
148
|
+
let server = client.guilds.resolve(appeals.mainserver?.id);
|
|
149
|
+
if (!server?.available) return null;
|
|
150
|
+
return server;
|
|
151
|
+
}
|
|
103
152
|
|
|
104
153
|
/** @private */
|
|
105
154
|
async handleCreate({ guild, member, category, send, embeds = [] } = {}) {
|
|
106
155
|
await send({ ephemeral: true }, true);
|
|
107
|
-
let [
|
|
156
|
+
let [supportIds, permissions, allow, { appeals }, sendBanReason] = [
|
|
108
157
|
this.getSupportIds(), [],
|
|
109
158
|
["ADD_REACTIONS", "ATTACH_FILES", "CREATE_INSTANT_INVITE", "EMBED_LINKS", "READ_MESSAGE_HISTORY", "VIEW_CHANNEL", "USE_EXTERNAL_EMOJIS", "SEND_MESSAGES"],
|
|
110
|
-
this.options ?? {}
|
|
159
|
+
this.options ?? {},
|
|
160
|
+
null
|
|
111
161
|
];
|
|
112
162
|
if (supportIds.roles.length) for (const sup of supportIds.roles) {
|
|
113
163
|
let role = guild.roles.resolve(sup);
|
|
@@ -122,25 +172,41 @@ module.exports = class Tickets {
|
|
|
122
172
|
if (member) permissions.push({ type: "member", id: uId, allow });
|
|
123
173
|
}
|
|
124
174
|
if (appeals?.enabled) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
{
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
175
|
+
let server = this.getAppealServer();
|
|
176
|
+
if (server) {
|
|
177
|
+
let ban = await server.bans.fetch({ user: member.id, force: true }).catch(e => this._debug(e));
|
|
178
|
+
if (!ban) return send(
|
|
179
|
+
typeof appeals.embeds?.not_banned === "object" ?
|
|
180
|
+
appeals.embeds.not_banned :
|
|
181
|
+
{
|
|
182
|
+
embeds: [
|
|
183
|
+
{
|
|
184
|
+
author: { name: guild.name, icon_url: guild.iconURL({ dynamic: true }) },
|
|
185
|
+
title: "INFO",
|
|
186
|
+
description: `❌ You can't open this ticket due to you not being banned in the main server!`,
|
|
187
|
+
color: 0xFF0000,
|
|
188
|
+
timestamp: new Date()
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
sendBanReason = {
|
|
194
|
+
embeds: [
|
|
195
|
+
{
|
|
196
|
+
author: { name: server.name, iconURL: server.iconURL({ dynamic: true }) },
|
|
197
|
+
title: "Ban Reason",
|
|
198
|
+
description: ban.reason ?? "No Reason Provided?",
|
|
199
|
+
color: 0xFF0000,
|
|
200
|
+
timestamp: new Date()
|
|
201
|
+
}
|
|
202
|
+
],
|
|
203
|
+
components: [
|
|
204
|
+
{
|
|
205
|
+
type: 1, components: [
|
|
206
|
+
button({ id: `unban:${member.id}`, style: 4, title: "Unban", emoji: { name: "🔒" } })
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
]
|
|
144
210
|
}
|
|
145
211
|
}
|
|
146
212
|
}
|
|
@@ -167,7 +233,8 @@ module.exports = class Tickets {
|
|
|
167
233
|
components: [{ type: 1, components: [{ type: 2, custom_id: `${this.prefix}:close`, label: "Close Ticket", style: 4, emoji: { name: "🔒" } }] }]
|
|
168
234
|
}).catch(e => this._debug(e));
|
|
169
235
|
if (!msg) return null;
|
|
170
|
-
if (
|
|
236
|
+
if (sendBanReason) await channel.send(sendBanReason).catch(e => this._debug(e));
|
|
237
|
+
if (embeds?.length <= 10) for await (const embed of embeds) await channel.send({ embeds: [embed] }).catch(e => this._debug(e));
|
|
171
238
|
if (this.webhookOptions.id && this.webhookOptions.token) this.webhook()
|
|
172
239
|
.embed({
|
|
173
240
|
author: { name: guild.name, icon_url: guild.iconURL({ dynamic: true }) },
|
|
@@ -178,8 +245,8 @@ module.exports = class Tickets {
|
|
|
178
245
|
footer: { text: `Ticket ID: ${channel.name.split("-")[1]}` },
|
|
179
246
|
}).send().catch(e => this._debug(e));
|
|
180
247
|
return send({
|
|
181
|
-
embeds: [
|
|
182
|
-
components: [
|
|
248
|
+
embeds: [{ author: { name: `Ticket Created!`, icon_url: `https://cdn.discordapp.com/emojis/476629550797684736.gif` }, description: channel.toString(), color: 0xFF000 }],
|
|
249
|
+
components: [{ type: 1, components: [button({ title: "Go to ticket", url: msg.url })] }]
|
|
183
250
|
})
|
|
184
251
|
}
|
|
185
252
|
|
|
@@ -193,7 +260,7 @@ module.exports = class Tickets {
|
|
|
193
260
|
* @param {import("@elara-services/packages").Modal['components']} [options.components]
|
|
194
261
|
*/
|
|
195
262
|
modal(options = { title: "", components: [] }) {
|
|
196
|
-
return modal({ id: `${this.prefix}:modal_submit`, title: options?.title || "Create Ticket", components: options?.components?.length >= 1 ? options.components : [
|
|
263
|
+
return modal({ id: `${this.prefix}:modal_submit`, title: options?.title || "Create Ticket", components: options?.components?.length >= 1 ? options.components : [{ type: 1, components: [{ type: 4, min_length: 10, max_length: 4000, custom_id: "message", label: "Content", style: 2, placeholder: "What's the ticket about?", required: true }] }] })
|
|
197
264
|
}
|
|
198
265
|
|
|
199
266
|
async starterMessage(channelId, options) {
|
|
@@ -254,7 +321,7 @@ module.exports = class Tickets {
|
|
|
254
321
|
str.push(content)
|
|
255
322
|
};
|
|
256
323
|
if (message.embeds?.length) {
|
|
257
|
-
let arr = [
|
|
324
|
+
let arr = [`<discord-embeds slot="embeds">`];
|
|
258
325
|
for (const embed of message.embeds) {
|
|
259
326
|
let emb = [
|
|
260
327
|
`<discord-embed slot="embed" ${embed.thumbnail?.url ? `thumbnail="${embed.thumbnail.url}"` : ""} ${embed.image?.url ? `image="${embed.image.url}"` : ""} ${embed.author ? `${embed.author.name ? `author-name="${embed.author.name}"` : ""} ${embed.author.iconURL ? `author-image="${embed.author.iconURL}"` : ""} ${embed.author.url ? `author-url="${embed.author.url}"` : ""}` : ""} ${embed.title ? `embed-title="${embed.title}"` : ""}${embed.color ? `color="${embed.hexColor}"` : ""}>`
|
|
@@ -290,7 +357,7 @@ module.exports = class Tickets {
|
|
|
290
357
|
if (row.length >= 2) str.push(...row, `</discord-attachments>`)
|
|
291
358
|
}
|
|
292
359
|
if (message.attachments.size) str.push(message.attachments.map((c) => `<a href="${c.proxyURL}">${c.name}</a>`).join("<br>"))
|
|
293
|
-
str.push(`${message.content?.length ? `<br><br>` : ""
|
|
360
|
+
str.push(`${message.content?.length ? `<br><br>` : ""}<code style="background-color: #36393e; color: white;">ID: ${message.id}</code>`)
|
|
294
361
|
return [...str, `</discord-message>`].join(" ");
|
|
295
362
|
}),
|
|
296
363
|
"</discord-messages>"].join(" ");
|