@elara-services/tickets 3.1.6 → 4.0.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/lib/v14.js CHANGED
@@ -1,263 +1,515 @@
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("@elara-services/utils"),
5
- { Interactions: { button, modal } } = require("@elara-services/packages");
1
+ const { EmbedBuilder: MessageEmbed, InteractionType, ChannelType, ComponentType } = require("discord.js"),
2
+ base = require("./base"),
3
+ { de, code, fetchMessages, hasTicket, embed, webhook, getAppealServer, perms, defs } = require("./util"),
4
+ { generate, parser, discord } = require("@elara-services/utils"),
5
+ {
6
+ Interactions: { button },
7
+ } = require("@elara-services/packages");
6
8
 
7
9
  module.exports = class Tickets extends base {
10
+ /**
11
+ * @param {import("@elara-services/tickets").TicketOptions} options
12
+ */
8
13
  constructor(options = {}) {
9
14
  super(options);
10
- };
15
+ }
11
16
  /**
12
- * @param {import("discord.js").Interaction} int
17
+ * @param {import("discord.js").Interaction} int
13
18
  */
14
19
  async run(int) {
15
- if (!int) return;
20
+ if (!int) {
21
+ return;
22
+ }
23
+ if (int.isStringSelectMenu()) {
24
+ if (int.values[0] === this.prefix) {
25
+ int.customId = this.prefix;
26
+ int.componentType = ComponentType.Button;
27
+ }
28
+ }
16
29
  if (int.isButton() || int.type === InteractionType.ModalSubmit) {
17
30
  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;
31
+ category = guild?.channels?.resolve?.(this.options.ticket?.category || channel?.parentId);
32
+ if (!guild?.available || !channel || !member || !category) {
33
+ return;
34
+ }
20
35
 
21
36
  /**
22
- * @param {import("discord.js").InteractionDeferReplyOptions|import("discord.js").InteractionReplyOptions} options
23
- * @param {boolean} edit
24
- * @param {boolean} defer
37
+ * @param {import("discord.js").InteractionDeferReplyOptions|import("discord.js").InteractionReplyOptions} options
38
+ * @param {boolean} edit
39
+ * @param {boolean} defer
25
40
  */
26
41
  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));
42
+ if (defer) {
43
+ return int.deferReply(options).catch(this._debug);
44
+ }
45
+ if (int.replied || int.deferred) {
46
+ return int.editReply(options).catch(this._debug);
47
+ }
48
+ return int.reply(options).catch(this._debug);
30
49
  };
31
50
  switch (customId) {
32
51
  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 })
52
+ if (
53
+ this.options?.ticket?.limitOnePerUser &&
54
+ hasTicket({
55
+ userId: member.id,
56
+ guild,
57
+ token: this.options.encryptToken,
58
+ prefix: this.options.prefix,
59
+ })
60
+ ) {
61
+ return send({
62
+ embeds: [embed(this.str("TICKET_LIMIT_ONE_PER_USER")(this.options.prefix), { guild, str: this.str })],
63
+ ephemeral: true,
64
+ });
65
+ }
34
66
  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 });
67
+ if (this.options.support.ignore.some((c) => member.roles?.cache?.has?.(c))) {
68
+ return send({
69
+ embeds: [embed(this.str("TICKET_BLOCKED"), { str: this.str })],
70
+ ephemeral: true,
71
+ });
72
+ }
36
73
  }
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
- };
74
+ if (this.options.modal?.enabled) {
75
+ return int
76
+ .showModal(
77
+ defs.modals.custom(
78
+ {
79
+ title: this.options.modal?.title,
80
+ components: defs.getModalComponents(this.options.modal.questions || []),
81
+ },
82
+ { prefix: this.prefix, str: this.str },
83
+ ),
84
+ )
85
+ .catch(this._debug);
86
+ }
87
+ return this.handleCreate({ guild, member, category, send });
88
+ }
40
89
 
41
90
  case `${this.prefix}:close`: {
42
- if (this.options.support?.canOnlyCloseTickets && !member.permissions.has(PermissionFlagsBits.ManageGuild)) {
91
+ if (this.options.support?.canOnlyCloseTickets && !member.permissions.has(perms.manage.guild)) {
43
92
  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 }] })
93
+ if (!this.getSupportIds.roles?.some?.((c) => member.roles?.cache?.has?.(c))) {
94
+ return send({
95
+ ephemeral: true,
96
+ embeds: [
97
+ {
98
+ author: {
99
+ name: this.str("ONLY_SUPPORT"),
100
+ iconURL: "https://cdn.discordapp.com/emojis/781955502035697745.gif",
101
+ },
102
+ color: 0xff0000,
103
+ },
104
+ ],
105
+ });
106
+ }
45
107
  }
46
108
  }
47
- return send({
48
- ephemeral: true,
49
- embeds: [ embed(`🤔 Are you sure you want to close the ticket?`, { color: 0xFF000, guild }) ],
109
+ return send({
110
+ ephemeral: true,
111
+ embeds: [
112
+ embed(this.str("TICKET_CLOSE_CONFIRM"), {
113
+ color: 0xff000,
114
+ guild,
115
+ str: this.str,
116
+ }),
117
+ ],
50
118
  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
- })
119
+ {
120
+ type: 1,
121
+ components: [
122
+ button({
123
+ title: this.str("TICKET_CLOSE_CONFIRM_BUTTON"),
124
+ style: 3,
125
+ emoji: { id: "807031399563264030" },
126
+ id: `${this.prefix}:close:confirm:${code(channel.topic?.split?.(`ID: `)?.[1], "d", this.options.encryptToken)}${this.options?.ticket?.closeReason ? `:modal_submit` : ""}`,
127
+ }),
128
+ ],
129
+ },
130
+ ],
131
+ });
56
132
  }
57
133
 
58
134
  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];
135
+ let [embed, fields, split] = [
136
+ new MessageEmbed()
137
+ .setColor("Orange")
138
+ .setTimestamp()
139
+ .setTitle(this.str("FORM_RESPONSES"))
140
+ .setFooter({ text: this.str("ID")(member.id) })
141
+ .setAuthor({
142
+ name: member.user.username,
143
+ iconURL: member.user.displayAvatarURL({ dynamic: true }),
144
+ }),
145
+ [],
146
+ false,
147
+ ];
60
148
  for (const c of int.fields.components) {
61
149
  for (const cc of c.components) {
62
150
  if (cc.value && cc.customId) {
63
151
  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
152
+ if (cc.value.length <= 1024) {
153
+ embed.addFields({ name: cc.customId, value: cc.value });
154
+ } else {
155
+ split = true;
156
+ }
66
157
  }
67
158
  }
68
159
  }
69
160
  if (embed.length >= 6000 || split) {
70
161
  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,
162
+ guild,
163
+ member,
164
+ category,
165
+ send,
166
+ embeds: fields.map((v, i) => ({
167
+ title: `${this.str("FORM_RESPONSE")}: ${v.name}`,
168
+ color: embed.color,
169
+ description: v.value,
170
+ author:
171
+ i === 0
172
+ ? {
173
+ name: member.user.username,
174
+ iconURL: member.user.displayAvatarURL({
175
+ dynamic: true,
176
+ }),
177
+ }
178
+ : undefined,
74
179
  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] })
180
+ footer: fields.length - 1 === i ? { text: this.str("ID")(member.id) } : undefined,
181
+ })),
182
+ });
183
+ }
184
+ return this.handleCreate({
185
+ guild,
186
+ member,
187
+ category,
188
+ send,
189
+ embeds: [embed],
190
+ });
80
191
  }
81
- };
192
+ }
82
193
  if (customId.startsWith(`${this.prefix}:close:confirm`)) {
83
194
  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
- }))
195
+ return int.showModal(defs.modals.reason(customId, this.str)).catch(this._debug);
89
196
  }
90
197
  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.`) ] });
198
+ let reason = this.str("NO_REASON");
199
+ if (int.type === InteractionType.ModalSubmit) {
200
+ reason = int.fields.getTextInputValue("reason");
201
+ }
202
+ const user = await discord.user(this.options.client, customId.split("close:confirm:")[1].replace(/:modal_complete/gi, ""), { fetch: true, mock: false });
203
+ if (!user) {
204
+ return send({
205
+ embeds: [embed(this.str("NO_USER_FOUND"), { str: this.str })],
206
+ });
207
+ }
95
208
  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
- };
209
+ if (!messages?.length) {
210
+ return send({
211
+ embeds: [embed(this.str("NO_MESSAGES_FETCHED"), { str: this.str })],
212
+ });
213
+ }
214
+ let closed = await channel.delete(`${member.user.tag} (${member.id}) closed the ticket.`).catch(this._debug);
215
+ if (!closed) {
216
+ return send({
217
+ embeds: [embed(this.str("NO_CHANNEL_DELETE"), { str: this.str })],
218
+ });
219
+ }
220
+ return this.closeTicket({
221
+ channel,
222
+ guild,
223
+ user,
224
+ member,
225
+ messages,
226
+ reason,
227
+ });
228
+ }
101
229
 
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 });
230
+ if (customId.startsWith(`${this.prefix}:unban:`)) {
231
+ if (!int.memberPermissions?.has?.(perms.members.ban)) {
232
+ return send({
233
+ embeds: [embed(this.str("NO_BAN_PERMS_USER"), { str: this.str })],
234
+ ephemeral: true,
235
+ });
236
+ }
104
237
  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));
238
+ if (!server) {
239
+ return send({
240
+ embeds: [embed(this.str("NO_APPEAL_SERVER_FOUND"), { str: this.str })],
241
+ ephemeral: true,
242
+ });
243
+ }
244
+ const mod = await discord.member(server, member.id, true);
245
+ if (!mod) {
246
+ return send({
247
+ embeds: [embed(this.str("NOT_FOUND_IN_APPEAL_SERVER")(server), { str: this.str })],
248
+ ephemeral: true,
249
+ });
250
+ }
251
+ if (!mod.permissions?.has?.(perms.members.ban)) {
252
+ return send({
253
+ embeds: [embed(this.str("NO_BAN_PERMS_USER_IN_APPEAL_SERVER")(server), { str: this.str })],
254
+ ephemeral: true,
255
+ });
256
+ }
257
+ return int.showModal(defs.modals.unbanReason(customId, server, this.str, member, this.prefix)).catch(this._debug);
114
258
  }
115
259
 
116
- if (customId.startsWith("unban_modal:")) {
260
+ if (customId.startsWith(`${this.prefix}:unban_modal:`)) {
117
261
  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!`)] });
262
+ const [, , id] = customId.split(":");
263
+ if (!int.memberPermissions?.has?.(perms.members.ban)) {
264
+ return send({
265
+ embeds: [embed(this.str("NO_BAN_PERMS_USER"), { str: this.str })],
266
+ });
267
+ }
120
268
  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 } ] }))
269
+ if (!server) {
270
+ return send({
271
+ embeds: [embed(this.str("NO_APPEAL_SERVER_FOUND"), { str: this.str })],
272
+ });
273
+ }
274
+ const mod = await discord.member(server, member.id, true);
275
+ if (!mod) {
276
+ return send({
277
+ embeds: [embed(this.str("NOT_FOUND_IN_APPEAL_SERVER")(server), { str: this.str })],
278
+ });
279
+ }
280
+ if (!mod.permissions?.has?.(perms.members.ban)) {
281
+ return send({
282
+ embeds: [embed(this.str("NO_BAN_PERMS_USER_IN_APPEAL_SERVER")(server), { str: this.str })],
283
+ });
284
+ }
285
+ let isBanned = await server.bans.fetch({ user: id, force: true }).catch(this._debug);
286
+ if (!isBanned) {
287
+ return send({
288
+ embeds: [embed(this.str("USER_NOT_BANNED")(id), { str: this.str })],
289
+ });
290
+ }
291
+ return server.bans
292
+ .remove(id, int.fields.getTextInputValue("reason") ?? `${this.str("NO_REASON")} | ${this.str("BY")}: ${member.user.tag} (${member.id})`)
293
+ .then(() => {
294
+ int.message
295
+ .edit({
296
+ components: [
297
+ {
298
+ type: 1,
299
+ components: [
300
+ button({
301
+ title: this.str("UNBANNED"),
302
+ style: 3,
303
+ id: "_ _",
304
+ disabled: true,
305
+ emoji: { id: `476629550797684736` },
306
+ }),
307
+ ],
308
+ },
309
+ ],
310
+ })
311
+ .catch(this._debug);
312
+ send({
313
+ embeds: [embed(this.str("UNBAN_SUCCESS")(id, server.name), { str: this.str })],
314
+ });
315
+ })
316
+ .catch((e) =>
317
+ send({
318
+ embeds: [
319
+ {
320
+ title: this.str("ERROR"),
321
+ fields: [
322
+ {
323
+ name: "\u200b",
324
+ value: this.str("UNBAN_FAILED")(id, server.name),
325
+ },
326
+ ],
327
+ description: `\`\`\`js\n${e.message ?? e.stack}\`\`\``,
328
+ color: 0xff0000,
329
+ },
330
+ ],
331
+ }),
332
+ );
133
333
  }
134
- };
135
- };
334
+ }
335
+ }
136
336
 
137
337
  /** @private */
138
338
  async handleCreate({ guild, member, category, send, embeds = [] } = {}) {
139
339
  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
- };
340
+ let [permissions, { appeals }, sendBanReason] = [[], this.options ?? {}, null];
341
+ if (this.getSupportIds.roles.length) {
342
+ for (const sup of this.getSupportIds.roles) {
343
+ let role = guild.roles.resolve(sup);
344
+ if (role) {
345
+ permissions.push({
346
+ type: "role",
347
+ id: sup,
348
+ allow: perms.allows.support,
349
+ });
350
+ }
351
+ }
352
+ }
159
353
 
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 });
354
+ if (this.getSupportIds.users.length) {
355
+ for await (const uId of this.getSupportIds.users) {
356
+ const member = await discord.member(guild, uId, true);
357
+ if (member) {
358
+ permissions.push({
359
+ type: "member",
360
+ id: uId,
361
+ allow: perms.allows.support,
362
+ });
363
+ }
364
+ }
166
365
  }
167
366
  if (appeals?.enabled) {
168
367
  let server = getAppealServer(this.options);
169
368
  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
- );
369
+ let ban = await server.bans.fetch({ user: member.id, force: true }).catch(this._debug);
370
+ if (!ban) {
371
+ return send(
372
+ typeof appeals.embeds?.not_banned === "object"
373
+ ? await parser(appeals.embeds.not_banned, { guild: server, member, user: member.user })
374
+ : {
375
+ embeds: [
376
+ embed(this.str("NOT_BANNED_MAIN_SERVER"), {
377
+ guild,
378
+ color: 0xff0000,
379
+ str: this.str,
380
+ }),
381
+ ],
382
+ },
383
+ );
384
+ }
176
385
  sendBanReason = {
177
- embeds: [ embed(ban?.reason ?? "No Reason Provided", { title: "Ban Reason", guild: server }) ],
386
+ embeds: [
387
+ embed(ban?.reason ?? this.str("NO_REASON"), {
388
+ title: this.str("BAN_REASON"),
389
+ guild: server,
390
+ str: this.str,
391
+ }),
392
+ ],
178
393
  components: [
179
394
  {
180
- type: 1, components: [
181
- button({ id: `unban:${member.id}`, style: 4, title: "Unban", emoji: { name: "🔒" } })
182
- ]
183
- }
184
- ]
185
- }
395
+ type: 1,
396
+ components: [
397
+ button({
398
+ id: `${this.prefix}:unban:${member.id}`,
399
+ style: 4,
400
+ title: this.str("UNBAN"),
401
+ emoji: { name: "🔒" },
402
+ }),
403
+ ],
404
+ },
405
+ ],
406
+ };
186
407
  }
187
408
  }
188
- let channel = await guild.channels.create({
189
- name: `${this.options.prefix}-${generate(5)}`,
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));
409
+ let channel = await guild.channels
410
+ .create({
411
+ name: `${this.options.prefix}-${generate(5)}`,
412
+ type: ChannelType.GuildText,
413
+ parent: category,
414
+ reason: `${this.str("OPEN_TICKET_AUDIT_REASON")} @${member.user.tag} (${member.id})`,
415
+ topic: `ID: ${code(member.id, "e", this.options.encryptToken)}`,
416
+ permissionOverwrites: [
417
+ {
418
+ type: "member",
419
+ id: this.options.client.user.id,
420
+ allow: perms.allows.client,
421
+ },
422
+ {
423
+ type: "member",
424
+ id: member.id,
425
+ allow: perms.allows.ticketUser,
426
+ deny: perms.denied.ticketUser,
427
+ },
428
+ { type: "role", id: guild.id, deny: perms.denied.all },
429
+ ...permissions,
430
+ ],
431
+ })
432
+ .catch(this._debug);
433
+ if (!channel) {
434
+ return send({ embeds: [embed(this.str("NO_CHANNEL_CREATE"), { str: this.str })] });
435
+ }
436
+ let embs = await Promise.all(
437
+ (
438
+ this.options.ticket?.open?.embeds || [
439
+ embed(undefined, {
440
+ title: this.str("OPEN_TICKET_MESSAGE"),
441
+ color: 0xf50de3,
442
+ guild,
443
+ footer: { text: this.str("OPEN_TICKET_MESSAGE_FOOTER") },
444
+ str: this.str,
445
+ }),
446
+ ]
447
+ ).map((c) => parser(c, { guild, member, user: member.user })),
448
+ );
449
+ const content = this.options.ticket?.open?.content || `${member.user.toString()} ${this.str("OPEN_TICKET_MESSAGE_CONTENT")}`;
450
+ let msg = await channel
451
+ .send({
452
+ content: await parser(content, { guild, member, user: member.user }),
453
+ embeds: embs,
454
+ components: [
455
+ {
456
+ type: 1,
457
+ components: [
458
+ button({
459
+ id: `${this.prefix}:close`,
460
+ title: this.str("CLOSE_TICKET"),
461
+ style: 4,
462
+ emoji: { name: "🔒" },
463
+ }),
464
+ ],
465
+ },
466
+ ],
467
+ })
468
+ .catch(this._debug);
469
+ if (!msg) {
470
+ return null;
471
+ }
472
+ if (sendBanReason) {
473
+ await channel.send(sendBanReason).catch(this._debug);
474
+ }
475
+ if (embeds?.length <= 10) {
476
+ for await (const embed of embeds) {
477
+ await channel.send({ embeds: [embed] }).catch(this._debug);
478
+ }
479
+ }
480
+ if (this.webhookOptions.id && this.webhookOptions.token) {
481
+ webhook(this.webhookOptions)
482
+ .embed(
483
+ embed(`${de.user} ${this.str("USER")}: ${member.user.toString()} \`@${member.user.tag}\` (${member.id})\n${de.channel} ${this.str("CHANNEL")}: \`#${channel.name}\` (${channel.id})`, {
484
+ title: this.str("OPEN_TICKET_TITLE"),
485
+ color: 0xff000,
486
+ footer: {
487
+ text: `${this.str("TICKET_ID")} ${channel.name.split("-")[1]}`,
488
+ },
489
+ guild,
490
+ str: this.str,
491
+ }),
492
+ )
493
+ .send()
494
+ .catch(this._debug);
495
+ }
243
496
  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
- })
497
+ embeds: [
498
+ embed(channel.toString(), {
499
+ color: 0xff000,
500
+ author: {
501
+ name: this.str("OPEN_TICKET_CREATE"),
502
+ icon_url: `https://cdn.discordapp.com/emojis/476629550797684736.gif`,
503
+ },
504
+ str: this.str,
505
+ }),
506
+ ],
507
+ components: [
508
+ {
509
+ type: 1,
510
+ components: [button({ title: this.str("GO_TO_TICKET"), url: msg.url })],
511
+ },
512
+ ],
513
+ });
247
514
  }
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.isTextBased()) 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
- };
515
+ };