@elara-services/tickets 4.0.6 → 4.0.8

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 CHANGED
@@ -50,8 +50,12 @@ declare module "@elara-services/tickets" {
50
50
  ticket?: {
51
51
  category?: string;
52
52
  closeReason?: boolean;
53
+ supportCommentThread?: boolean;
53
54
  limitOnePerUser?: boolean;
54
55
  open?: Pick<MessageOptions, "content" | "embeds">
56
+ close?: {
57
+ confirm?: Pick<MessageOptions, "content" | "embeds">
58
+ }
55
59
  }
56
60
  }
57
61
 
@@ -40,6 +40,7 @@ module.exports = {
40
40
  CLOSED_TICKET: "closed the ticket.",
41
41
  FORM_RESPONSE: "Form Response",
42
42
  MODAL_CONTENT: "Content",
43
+ SUPPORT_TALK: "Support Talk",
43
44
  ONLY_SUPPORT: "Only support staff can close tickets",
44
45
  GO_TO_TICKET: "Go to ticket",
45
46
  CLOSE_TICKET: "Close Ticket",
package/lib/base.js CHANGED
@@ -2,7 +2,7 @@ const { getWebhookInfo, displayMessages, de, webhook, getString } = require("./u
2
2
  const {
3
3
  Interactions: { button },
4
4
  } = require("@elara-services/packages");
5
- const { is } = require("@elara-services/utils");
5
+ const { is, status, isV13 } = require("@elara-services/utils");
6
6
  const { WebhookClient } = require("discord.js");
7
7
  const required = ["client", "prefix", "encryptToken"];
8
8
 
@@ -34,6 +34,7 @@ module.exports = class Tickets {
34
34
  return {
35
35
  roles: this.options.support?.roles || [],
36
36
  users: this.options.support?.users || [],
37
+ empty: [...(this.options.support?.roles || []), ...(this.options.support?.users || [])].length ? false : true,
37
38
  };
38
39
  }
39
40
 
@@ -51,6 +52,62 @@ module.exports = class Tickets {
51
52
  return this;
52
53
  }
53
54
 
55
+ get manage() {
56
+ return {
57
+ add: async (channelId, userId, permType = "member") => {
58
+ const channel = this.options.client.channels.resolve(channelId);
59
+ if (!channel) {
60
+ return status.error(`Unable to find (${channelId}) channel`);
61
+ }
62
+ let mod = permType === "mod";
63
+ let perms = {};
64
+ if (isV13()) {
65
+ perms = {
66
+ VIEW_CHANNEL: true,
67
+ SEND_MESSAGES: true,
68
+ READ_MESSAGE_HISTORY: true,
69
+ ATTACH_FILES: true,
70
+ EMBED_LINKS: true,
71
+ USE_EXTERNAL_EMOJIS: true,
72
+ };
73
+ if (mod) {
74
+ perms["MANAGE_MESSAGES"] = true;
75
+ perms["MANAGE_THREADS"] = true;
76
+ }
77
+ } else {
78
+ perms = {
79
+ ViewChannel: true,
80
+ SendMessages: true,
81
+ ReadMessageHistory: true,
82
+ AttachFiles: true,
83
+ EmbedLinks: true,
84
+ UseExternalEmojis: true,
85
+ };
86
+ if (mod) {
87
+ perms["ManageMessages"] = true;
88
+ perms["ManageThreads"] = true;
89
+ }
90
+ }
91
+ return channel.permissionOverwrites
92
+ .edit(userId, perms, {
93
+ reason: `Added to the ticket.`,
94
+ })
95
+ .then(() => status.success(`Added to the ticket.`))
96
+ .catch((e) => status.error(e.message || e));
97
+ },
98
+ remove: async (channelId, userId) => {
99
+ const channel = this.options.client.channels.resolve(channelId);
100
+ if (!channel) {
101
+ return status.error(`Unable to find (${channelId}) channel`);
102
+ }
103
+ return channel.permissionOverwrites
104
+ .delete(userId, `Removed from the ticket.`)
105
+ .then(() => status.success(`Removed from the ticket.`))
106
+ .catch((e) => status.error(e.message || e));
107
+ },
108
+ };
109
+ }
110
+
54
111
  /**
55
112
  * @param {keyof typeof import("../languages/en-US")} name
56
113
  */
@@ -83,6 +140,14 @@ module.exports = class Tickets {
83
140
  emoji: options.emoji,
84
141
  });
85
142
  }
143
+ /**
144
+ * @param {object} opts
145
+ * @param {import("discord.js").GuildMember} opts.member
146
+ * @param {import("discord.js").TextChannel} opts.channel
147
+ * @param {import("discord.js").Guild} opts.guild
148
+ * @param {import("discord.js").User} opts.user
149
+ * @param {string} opts.reason
150
+ */
86
151
  async closeTicket({ member, messages, channel, guild, user, reason } = {}) {
87
152
  const { id, token, username, avatar: avatarURL, threadId } = this.webhookOptions;
88
153
  if (!id || !token) {
package/lib/v13.js CHANGED
@@ -45,12 +45,12 @@ module.exports = class Tickets extends base {
45
45
  */
46
46
  const send = async (options = {}, defer = false) => {
47
47
  if (defer) {
48
- return int.deferReply(options).catch(this._debug);
48
+ return int.deferReply(options).catch((e) => this._debug(e));
49
49
  }
50
50
  if (int.replied || int.deferred) {
51
- return int.editReply(options).catch(this._debug);
51
+ return int.editReply(options).catch((e) => this._debug(e));
52
52
  }
53
- return int.reply(options).catch(this._debug);
53
+ return int.reply(options).catch((e) => this._debug(e));
54
54
  };
55
55
  switch (customId) {
56
56
  case this.prefix: {
@@ -87,7 +87,7 @@ module.exports = class Tickets extends base {
87
87
  { prefix: this.prefix, str: (name) => this.str(name, this?.options?.lang) },
88
88
  ),
89
89
  )
90
- .catch(this._debug);
90
+ .catch((e) => this._debug(e));
91
91
  }
92
92
  return this.handleCreate({ guild, member, category, send });
93
93
  }
@@ -111,15 +111,24 @@ module.exports = class Tickets extends base {
111
111
  }
112
112
  }
113
113
  }
114
+ let embs = await Promise.all(
115
+ (
116
+ this.options.ticket?.close?.confirm?.embeds || [
117
+ embed(undefined, {
118
+ description: this.str("TICKET_CLOSE_CONFIRM"),
119
+ title: `INFO`,
120
+ color: 0xff000,
121
+ guild,
122
+ str: (name) => this.str(name, this?.options?.lang),
123
+ }),
124
+ ]
125
+ ).map((c) => parser(c, { guild, member, user: member.user })),
126
+ );
127
+ const content = this.options.ticket?.close?.confirm?.content || ``;
114
128
  return send({
115
129
  ephemeral: true,
116
- embeds: [
117
- embed(this.str("TICKET_CLOSE_CONFIRM"), {
118
- color: 0xff000,
119
- guild,
120
- str: (name) => this.str(name, this?.options?.lang),
121
- }),
122
- ],
130
+ content,
131
+ embeds: [embs],
123
132
  components: [
124
133
  {
125
134
  type: 1,
@@ -216,7 +225,7 @@ module.exports = class Tickets extends base {
216
225
  embeds: [embed(this.str("NO_MESSAGES_FETCHED"), { str: (name) => this.str(name, this?.options?.lang) })],
217
226
  });
218
227
  }
219
- let closed = await channel.delete(`${member.user.tag} (${member.id}) ${this.str("CLOSED_TICKET")}`).catch(this._debug);
228
+ let closed = await channel.delete(`${member.user.tag} (${member.id}) ${this.str("CLOSED_TICKET")}`).catch((e) => this._debug(e));
220
229
  if (!closed) {
221
230
  return send({
222
231
  embeds: [embed(this.str("NO_CHANNEL_DELETE"), { str: (name) => this.str(name, this?.options?.lang) })],
@@ -259,7 +268,7 @@ module.exports = class Tickets extends base {
259
268
  ephemeral: true,
260
269
  });
261
270
  }
262
- return int.showModal(defs.modals.unbanReason(customId, server, (name) => this.str(name, this?.options?.lang), member, this.prefix)).catch(this._debug);
271
+ return int.showModal(defs.modals.unbanReason(customId, server, (name) => this.str(name, this?.options?.lang), member, this.prefix)).catch((e) => this._debug(e));
263
272
  }
264
273
 
265
274
  if (customId.startsWith(`${this.prefix}:unban_modal:`)) {
@@ -287,7 +296,7 @@ module.exports = class Tickets extends base {
287
296
  embeds: [embed(this.str("NO_BAN_PERMS_USER_IN_APPEAL_SERVER")(server), { str: (name) => this.str(name, this?.options?.lang) })],
288
297
  });
289
298
  }
290
- let isBanned = await server.bans.fetch({ user: id, force: true }).catch(this._debug);
299
+ let isBanned = await server.bans.fetch({ user: id, force: true }).catch((e) => this._debug(e));
291
300
  if (!isBanned) {
292
301
  return send({
293
302
  embeds: [embed(this.str("USER_NOT_BANNED")(id), { str: (name) => this.str(name, this?.options?.lang) })],
@@ -313,7 +322,7 @@ module.exports = class Tickets extends base {
313
322
  },
314
323
  ],
315
324
  })
316
- .catch(this._debug);
325
+ .catch((e) => this._debug(e));
317
326
  send({
318
327
  embeds: [embed(this.str("UNBAN_SUCCESS")(id, server.name), { str: (name) => this.str(name, this?.options?.lang) })],
319
328
  });
@@ -371,7 +380,7 @@ module.exports = class Tickets extends base {
371
380
  if (appeals?.enabled) {
372
381
  let server = getAppealServer(this.options);
373
382
  if (server) {
374
- let ban = await server.bans.fetch({ user: member.id, force: true }).catch(this._debug);
383
+ let ban = await server.bans.fetch({ user: member.id, force: true }).catch((e) => this._debug(e));
375
384
  if (!ban) {
376
385
  return send(
377
386
  typeof appeals.embeds?.not_banned === "object"
@@ -433,7 +442,7 @@ module.exports = class Tickets extends base {
433
442
  ...permissions,
434
443
  ],
435
444
  })
436
- .catch(this._debug);
445
+ .catch((e) => this._debug(e));
437
446
  if (!channel) {
438
447
  return send({ embeds: [embed(this.str("NO_CHANNEL_CREATE"), { str: (name) => this.str(name, this?.options?.lang) })] });
439
448
  }
@@ -468,19 +477,37 @@ module.exports = class Tickets extends base {
468
477
  ],
469
478
  },
470
479
  ],
480
+ allowedMentions: {
481
+ users: [member.id, ...this.getSupportIds.users],
482
+ roles: [...this.getSupportIds.roles],
483
+ },
471
484
  })
472
- .catch(this._debug);
485
+ .catch((e) => this._debug(e));
473
486
  if (!msg) {
474
487
  return null;
475
488
  }
476
489
  if (sendBanReason) {
477
- await channel.send(sendBanReason).catch(this._debug);
490
+ await channel.send(sendBanReason).catch((e) => this._debug(e));
478
491
  }
479
492
  if (embeds?.length <= 10) {
480
493
  for await (const embed of embeds) {
481
- await channel.send({ embeds: [embed] }).catch(this._debug);
494
+ await channel.send({ embeds: [embed] }).catch((e) => this._debug(e));
482
495
  }
483
496
  }
497
+ if (this.options.ticket?.supportCommentThread === true) {
498
+ await channel.threads
499
+ .create({
500
+ name: this.str("SUPPORT_TALK"),
501
+ invitable: false,
502
+ type: 12,
503
+ startMessage: !this.getSupportIds.empty
504
+ ? {
505
+ content: `${this.getSupportIds.roles.length ? this.getSupportIds.roles.map((c) => `<@&${c}>`).join(" ") : ""}${this.getSupportIds.users.length ? `${this.getSupportIds.roles.length ? ` | ` : ""}${this.getSupportIds.users.map((c) => `<@${c}>`).join(" ")}` : ""}`,
506
+ }
507
+ : undefined,
508
+ })
509
+ .catch((e) => this._debug(e));
510
+ }
484
511
  if (this.webhookOptions.id && this.webhookOptions.token) {
485
512
  webhook(this.webhookOptions)
486
513
  .embed(
@@ -495,7 +522,7 @@ module.exports = class Tickets extends base {
495
522
  }),
496
523
  )
497
524
  .send()
498
- .catch(this._debug);
525
+ .catch((e) => this._debug(e));
499
526
  }
500
527
  return send({
501
528
  embeds: [
package/lib/v14.js CHANGED
@@ -41,12 +41,12 @@ module.exports = class Tickets extends base {
41
41
  */
42
42
  const send = async (options = {}, defer = false) => {
43
43
  if (defer) {
44
- return int.deferReply(options).catch(this._debug);
44
+ return int.deferReply(options).catch((e) => this._debug(e));
45
45
  }
46
46
  if (int.replied || int.deferred) {
47
- return int.editReply(options).catch(this._debug);
47
+ return int.editReply(options).catch((e) => this._debug(e));
48
48
  }
49
- return int.reply(options).catch(this._debug);
49
+ return int.reply(options).catch((e) => this._debug(e));
50
50
  };
51
51
  switch (customId) {
52
52
  case this.prefix: {
@@ -83,7 +83,7 @@ module.exports = class Tickets extends base {
83
83
  { prefix: this.prefix, str: (name) => this.str(name, this?.options?.lang) },
84
84
  ),
85
85
  )
86
- .catch(this._debug);
86
+ .catch((e) => this._debug(e));
87
87
  }
88
88
  return this.handleCreate({ guild, member, category, send });
89
89
  }
@@ -193,7 +193,7 @@ module.exports = class Tickets extends base {
193
193
  }
194
194
  if (customId.startsWith(`${this.prefix}:close:confirm`)) {
195
195
  if (customId.includes(`:modal_submit`)) {
196
- return int.showModal(defs.modals.reason(customId, (name) => this.str(name, this?.options?.lang))).catch(this._debug);
196
+ return int.showModal(defs.modals.reason(customId, (name) => this.str(name, this?.options?.lang))).catch((e) => this._debug(e));
197
197
  }
198
198
  await send({ ephemeral: true }, true);
199
199
  let reason = this.str("NO_REASON");
@@ -212,7 +212,7 @@ module.exports = class Tickets extends base {
212
212
  embeds: [embed(this.str("NO_MESSAGES_FETCHED"), { str: (name) => this.str(name, this?.options?.lang) })],
213
213
  });
214
214
  }
215
- let closed = await channel.delete(`${member.user.tag} (${member.id}) closed the ticket.`).catch(this._debug);
215
+ let closed = await channel.delete(`${member.user.tag} (${member.id}) closed the ticket.`).catch((e) => this._debug(e));
216
216
  if (!closed) {
217
217
  return send({
218
218
  embeds: [embed(this.str("NO_CHANNEL_DELETE"), { str: (name) => this.str(name, this?.options?.lang) })],
@@ -255,7 +255,7 @@ module.exports = class Tickets extends base {
255
255
  ephemeral: true,
256
256
  });
257
257
  }
258
- return int.showModal(defs.modals.unbanReason(customId, server, (name) => this.str(name, this?.options?.lang), member, this.prefix)).catch(this._debug);
258
+ return int.showModal(defs.modals.unbanReason(customId, server, (name) => this.str(name, this?.options?.lang), member, this.prefix)).catch((e) => this._debug(e));
259
259
  }
260
260
 
261
261
  if (customId.startsWith(`${this.prefix}:unban_modal:`)) {
@@ -283,7 +283,7 @@ module.exports = class Tickets extends base {
283
283
  embeds: [embed(this.str("NO_BAN_PERMS_USER_IN_APPEAL_SERVER")(server), { str: (name) => this.str(name, this?.options?.lang) })],
284
284
  });
285
285
  }
286
- let isBanned = await server.bans.fetch({ user: id, force: true }).catch(this._debug);
286
+ let isBanned = await server.bans.fetch({ user: id, force: true }).catch((e) => this._debug(e));
287
287
  if (!isBanned) {
288
288
  return send({
289
289
  embeds: [embed(this.str("USER_NOT_BANNED")(id), { str: (name) => this.str(name, this?.options?.lang) })],
@@ -309,7 +309,7 @@ module.exports = class Tickets extends base {
309
309
  },
310
310
  ],
311
311
  })
312
- .catch(this._debug);
312
+ .catch((e) => this._debug(e));
313
313
  send({
314
314
  embeds: [embed(this.str("UNBAN_SUCCESS")(id, server.name), { str: (name) => this.str(name, this?.options?.lang) })],
315
315
  });
@@ -335,7 +335,15 @@ module.exports = class Tickets extends base {
335
335
  }
336
336
  }
337
337
 
338
- /** @private */
338
+ /**
339
+ * @param {object} [opts]
340
+ * @param {import("discord.js").Guild} opts.guild
341
+ * @param {import("discord.js").GuildMember} opts.member
342
+ * @param {string} opts.category
343
+ * @param {Function} opts.send
344
+ * @param {import("discord.js").APIEmbed[]} opts.embeds
345
+ * @private
346
+ */
339
347
  async handleCreate({ guild, member, category, send, embeds = [] } = {}) {
340
348
  await send({ ephemeral: true }, true);
341
349
  let [permissions, { appeals }, sendBanReason] = [[], this.options ?? {}, null];
@@ -367,7 +375,7 @@ module.exports = class Tickets extends base {
367
375
  if (appeals?.enabled) {
368
376
  let server = getAppealServer(this.options);
369
377
  if (server) {
370
- let ban = await server.bans.fetch({ user: member.id, force: true }).catch(this._debug);
378
+ let ban = await server.bans.fetch({ user: member.id, force: true }).catch((e) => this._debug(e));
371
379
  if (!ban) {
372
380
  return send(
373
381
  typeof appeals.embeds?.not_banned === "object"
@@ -430,7 +438,7 @@ module.exports = class Tickets extends base {
430
438
  ...permissions,
431
439
  ],
432
440
  })
433
- .catch(this._debug);
441
+ .catch((e) => this._debug(e));
434
442
  if (!channel) {
435
443
  return send({ embeds: [embed(this.str("NO_CHANNEL_CREATE"), { str: (name) => this.str(name, this?.options?.lang) })] });
436
444
  }
@@ -465,19 +473,37 @@ module.exports = class Tickets extends base {
465
473
  ],
466
474
  },
467
475
  ],
476
+ allowedMentions: {
477
+ users: [member.id, ...this.getSupportIds.users],
478
+ roles: [...this.getSupportIds.roles],
479
+ },
468
480
  })
469
- .catch(this._debug);
481
+ .catch((e) => this._debug(e));
470
482
  if (!msg) {
471
483
  return null;
472
484
  }
473
485
  if (sendBanReason) {
474
- await channel.send(sendBanReason).catch(this._debug);
486
+ await channel.send(sendBanReason).catch((e) => this._debug(e));
475
487
  }
476
488
  if (embeds?.length <= 10) {
477
489
  for await (const embed of embeds) {
478
- await channel.send({ embeds: [embed] }).catch(this._debug);
490
+ await channel.send({ embeds: [embed] }).catch((e) => this._debug(e));
479
491
  }
480
492
  }
493
+ if (this.options.ticket?.supportCommentThread === true) {
494
+ await channel.threads
495
+ .create({
496
+ name: this.str("SUPPORT_TALK"),
497
+ invitable: false,
498
+ type: 12,
499
+ startMessage: !this.getSupportIds.empty
500
+ ? {
501
+ content: `${this.getSupportIds.roles.length ? this.getSupportIds.roles.map((c) => `<@&${c}>`).join(" ") : ""}${this.getSupportIds.users.length ? `${this.getSupportIds.roles.length ? ` | ` : ""}${this.getSupportIds.users.map((c) => `<@${c}>`).join(" ")}` : ""}`,
502
+ }
503
+ : undefined,
504
+ })
505
+ .catch((e) => this._debug(e));
506
+ }
481
507
  if (this.webhookOptions.id && this.webhookOptions.token) {
482
508
  webhook(this.webhookOptions)
483
509
  .embed(
@@ -492,7 +518,7 @@ module.exports = class Tickets extends base {
492
518
  }),
493
519
  )
494
520
  .send()
495
- .catch(this._debug);
521
+ .catch((e) => this._debug(e));
496
522
  }
497
523
  return send({
498
524
  embeds: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elara-services/tickets",
3
- "version": "4.0.6",
3
+ "version": "4.0.8",
4
4
  "description": "Helper for tickets",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -17,9 +17,9 @@
17
17
  "pc": "prettier --check **/**/*.js"
18
18
  },
19
19
  "dependencies": {
20
- "@elara-services/packages": "^6.0.7",
21
- "@elara-services/utils": "^1.2.33",
22
- "@elara-services/webhooks": "^2.1.9"
20
+ "@elara-services/packages": "^6.0.8",
21
+ "@elara-services/utils": "^1.3.1",
22
+ "@elara-services/webhooks": "^2.1.10"
23
23
  },
24
24
  "devDependencies": {
25
25
  "eslint": "8.20.0",