@elara-services/tickets 3.1.6 → 4.0.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/lib/util.js CHANGED
@@ -1,53 +1,101 @@
1
- const { AES } = require("@elara-services/packages"),
2
- { Collection, version } = require("discord.js"),
3
- { DiscordWebhook: Webhook } = require("@elara-services/webhooks"),
4
- defLang = require("../languages/en-US"),
5
- pack = require("../package.json");
1
+ const {
2
+ AES,
3
+ Interactions: { modal },
4
+ } = require("@elara-services/packages"),
5
+ { Collection, version } = require("discord.js"),
6
+ { DiscordWebhook: Webhook } = require("@elara-services/webhooks"),
7
+ defLang = require("../languages/en-US"),
8
+ pack = require("../package.json");
6
9
 
7
10
  exports.getString = (name, lang = "en-US") => {
8
- if (!lang) lang = "en-US";
9
- let str = '[UNKNOWN STRING]';
10
- if (!pack.languages.includes(lang)) lang = "en-US";
11
+ if (!lang) {
12
+ lang = "en-US";
13
+ }
14
+ let str = "[UNKNOWN STRING]";
15
+ if (!pack.languages.includes(lang)) {
16
+ lang = "en-US";
17
+ }
11
18
  try {
12
19
  let file = require(`../languages/${lang}.js`);
13
- if (file[name]) str = file[name];
20
+ if (file[name]) {
21
+ str = file[name];
22
+ }
14
23
  } catch {
15
- if (defLang[name]) str = defLang[name];
16
- };
24
+ if (defLang[name]) {
25
+ str = defLang[name];
26
+ }
27
+ }
17
28
  return str;
18
- }
29
+ };
19
30
 
20
31
  exports.code = (message, type = "d", token) => {
21
- if (!message || !type) return "";
22
- if (!token) return message;
32
+ if (!message || !type) {
33
+ return "";
34
+ }
35
+ if (!token) {
36
+ return message;
37
+ }
23
38
  try {
24
39
  const aes = new AES(token);
25
- switch (type) {
26
- case "e": return aes.encrypt(message);
27
- case "d": return aes.decrypt(message);
28
- }
40
+ return aes[type === "e" ? "encrypt" : "decrypt"](message);
29
41
  } catch {
30
42
  return message;
31
43
  }
32
- }
44
+ };
33
45
 
34
46
  exports.de = {
35
47
  user: "<:Members:860931214232125450>",
36
48
  channel: "<:Channel:841654412509839390>",
37
- transcript: "<:Log:792290922749624320>"
38
- }
49
+ transcript: "<:Log:792290922749624320>",
50
+ };
51
+
52
+ exports.perms = {
53
+ manage: {
54
+ guild: 32n,
55
+ },
56
+ members: {
57
+ ban: 4n,
58
+ },
59
+ basic: 117760n,
60
+ allows: {
61
+ support: 379969n,
62
+ ticketUser: 379968n,
63
+ client: 511040n,
64
+ },
65
+ denied: {
66
+ all: 1024n, // @everyone role
67
+ ticketUser: 131072n,
68
+ },
69
+ };
39
70
 
40
71
  exports.fetchMessages = async (channel, limit = 50, before, after, around) => {
41
72
  if (limit && limit > 100) {
42
73
  let logs = [];
43
74
  const get = async (_before, _after) => {
44
- const messages = [...(await channel.messages.fetch({ limit: 100, before: _before || undefined, after: _after || undefined }).catch(() => new Collection())).values()];
75
+ const messages = [
76
+ ...(
77
+ await channel.messages
78
+ .fetch({
79
+ limit: 100,
80
+ before: _before || undefined,
81
+ after: _after || undefined,
82
+ })
83
+ .catch(() => new Collection())
84
+ ).values(),
85
+ ];
45
86
  if (limit <= messages.length) {
46
- return (_after ? messages.slice(messages.length - limit, messages.length).map((message) => message).concat(logs) : logs.concat(messages.slice(0, limit).map((message) => message)));
87
+ return _after
88
+ ? messages
89
+ .slice(messages.length - limit, messages.length)
90
+ .map((message) => message)
91
+ .concat(logs)
92
+ : logs.concat(messages.slice(0, limit).map((message) => message));
47
93
  }
48
94
  limit -= messages.length;
49
- logs = (_after ? messages.map((message) => message).concat(logs) : logs.concat(messages.map((message) => message)));
50
- if (messages.length < 100) return logs;
95
+ logs = _after ? messages.map((message) => message).concat(logs) : logs.concat(messages.map((message) => message));
96
+ if (messages.length < 100) {
97
+ return logs;
98
+ }
51
99
  return get((_before || !_after) && messages[messages.length - 1].id, _after && messages[0].id);
52
100
  };
53
101
  return get(before, after);
@@ -55,104 +103,253 @@ exports.fetchMessages = async (channel, limit = 50, before, after, around) => {
55
103
  return [...(await channel.messages.fetch({ limit, before, after, around }).catch(() => new Collection())).values()];
56
104
  };
57
105
 
58
- exports.displayMessages = (channel, messages = [], ticketID, type) => {
106
+ exports.displayMessages = (channel, messages = [], ticketID, type, str) => {
59
107
  let users = [];
60
108
  for (const i of messages.values()) {
61
- let f = users.find(c => c.user.id === i.author.id);
62
- if (f) f.count++; else users.push({ user: i.author, count: 1 });
63
- };
64
- 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>`,
65
- ...messages.map(message => {
109
+ let f = users.find((c) => c.user.id === i.author.id);
110
+ if (f) {
111
+ f.count++;
112
+ } else {
113
+ users.push({ user: i.author, count: 1 });
114
+ }
115
+ }
116
+ return [
117
+ `<discord-messages>`,
118
+ `<discord-message author="${type} ${str("TICKET")}: ${ticketID}" bot="true" verified avatar="https://cdn.discordapp.com/emojis/847397714677334066.png?v=1" role-color="#1da1f2">${str("TOTAL_MESSAGES")}: ${users
119
+ .map((c) => c.count)
120
+ .reduce((a, b) => a + b, 0)
121
+ .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>`,
122
+ ...messages.map((message) => {
66
123
  let str = [
67
- `<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`}">`
124
+ `<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({
125
+ dynamic: true,
126
+ format: "png",
127
+ })} role-color="${channel.guild?.members?.resolve?.(message.author.id)?.displayColor ? channel.guild?.members?.resolve?.(message.author.id)?.displayHexColor : `#ffffff`}">`,
68
128
  ];
69
129
  if (message.content) {
70
130
  let content = message.content;
71
- if (message.mentions.users.size) for (const user of message.mentions.users.values()) content = content.replace(new RegExp(`<@!?${user.id}>`, "g"), `<discord-mention type="role" color="${message.guild?.members?.resolve?.(user?.id)?.displayHexColor ?? "#ffffff"}">${user.tag}</discord-mention>`);
72
- if (message.mentions.channels.size) for (const channel of message.mentions.channels.values()) content = content.replace(new RegExp(channel.toString(), "g"), `<discord-mention type="channel">${channel.name}</discord-mention>`);
73
- if (message.mentions.roles.size) for (const role of message.mentions.roles.values()) content = content.replace(new RegExp(role.toString(), "g"), `<discord-mention type="role" color="${role.hexColor}">${role.name}</discord-mention>`)
74
- str.push(content)
75
- };
131
+ if (message.mentions.users.size) {
132
+ for (const user of message.mentions.users.values()) {
133
+ content = content.replace(new RegExp(`<@!?${user.id}>`, "g"), `<discord-mention type="role" color="${message.guild?.members?.resolve?.(user?.id)?.displayHexColor ?? "#ffffff"}">${user.tag}</discord-mention>`);
134
+ }
135
+ }
136
+ if (message.mentions.channels.size) {
137
+ for (const channel of message.mentions.channels.values()) {
138
+ content = content.replace(new RegExp(channel.toString(), "g"), `<discord-mention type="channel">${channel.name}</discord-mention>`);
139
+ }
140
+ }
141
+ if (message.mentions.roles.size) {
142
+ for (const role of message.mentions.roles.values()) {
143
+ content = content.replace(new RegExp(role.toString(), "g"), `<discord-mention type="role" color="${role.hexColor}">${role.name}</discord-mention>`);
144
+ }
145
+ }
146
+ str.push(content);
147
+ }
76
148
  if (message.embeds?.length) {
77
149
  let arr = [`<discord-embeds slot="embeds">`];
78
150
  for (const embed of message.embeds) {
79
151
  let emb = [
80
- `<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}"` : ""}>`
152
+ `<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}"` : ""}${
153
+ embed.color ? `color="${embed.hexColor}"` : ""
154
+ }>`,
81
155
  ];
82
- if (embed.description) emb.push(`<discord-embed-description slot="description">${embed.description}</discord-embed-description>`);
156
+ if (embed.description) {
157
+ emb.push(`<discord-embed-description slot="description">${embed.description}</discord-embed-description>`);
158
+ }
83
159
  if (embed.fields?.length) {
84
- emb.push(`<discord-embed-fields slot="fields">`)
85
- for (const field of embed.fields) emb.push(`<discord-embed-field field-title="${field.name}" ${field.inline ? `inline` : ""}>${field.value}</discord-embed-field>`)
160
+ emb.push(`<discord-embed-fields slot="fields">`);
161
+ for (const field of embed.fields) {
162
+ emb.push(`<discord-embed-field field-title="${field.name}" ${field.inline ? `inline` : ""}>${field.value}</discord-embed-field>`);
163
+ }
86
164
  }
87
- arr.push(...emb, `</discord-embed>`)
165
+ arr.push(...emb, `</discord-embed>`);
88
166
  }
89
- str.push(...arr, "</discord-embeds>")
167
+ str.push(...arr, "</discord-embeds>");
168
+ }
169
+ if (message.interaction?.user) {
170
+ str.push(
171
+ `<discord-command slot="reply" command="${message.interaction.type === "APPLICATION_COMMAND" ? "/" : ""}${message.interaction.commandName}" profile="${message.interaction.user.id}" role-color="${channel.guild?.members?.resolve?.(message.interaction.user?.id)?.displayHexColor || "#fffff"}" author="${message.interaction.user.tag}" avatar="${message.interaction.user.displayAvatarURL({
172
+ dynamic: true,
173
+ })}"></discord-command>`,
174
+ );
90
175
  }
91
- if (message.interaction?.user) str.push(`<discord-command slot="reply" command="${message.interaction.type === "APPLICATION_COMMAND" ? "/" : ""}${message.interaction.commandName}" profile="${message.interaction.user.id}" role-color="${channel.guild?.members?.resolve?.(message.interaction.user?.id)?.displayHexColor || "#fffff"}" author="${message.interaction.user.tag}" avatar="${message.interaction.user.displayAvatarURL({ dynamic: true })}"></discord-command>`)
92
176
  if (message.components?.length) {
93
- let row = [
94
- `<discord-attachments slot="components">`
95
- ],
177
+ let row = [`<discord-attachments slot="components">`],
96
178
  styles = {
97
- "PRIMARY": "primary",
98
- "SECONDARY": "secondary",
99
- "SUCCESS": "success",
100
- "DANGER": "destructive",
101
- "LINK": "secondary"
102
- }
179
+ PRIMARY: "primary",
180
+ SECONDARY: "secondary",
181
+ SUCCESS: "success",
182
+ DANGER: "destructive",
183
+ LINK: "secondary",
184
+ };
103
185
  for (const components of message.components) {
104
- row.push(`<discord-action-row>`)
186
+ row.push(`<discord-action-row>`);
105
187
  for (const c of components.components) {
106
- if (c.type === "BUTTON") row.push(`<discord-button ${c.disabled ? `disabled=true` : ""} type="${styles[c.style]}" ${c.emoji?.name ? `emoji-name="${c.emoji.name}"` : ""} ${c.emoji?.id ? `emoji="https://cdn.discordapp.com/emojis/${c.emoji.id}.${c.emoji.animated ? "gif" : "png"}"` : ""} ${c.url ? `url="${c.url}"` : ""}>${c.label || ""}</discord-button>`)
188
+ if (c.type === "BUTTON") {
189
+ row.push(`<discord-button ${c.disabled ? `disabled=true` : ""} type="${styles[c.style]}" ${c.emoji?.name ? `emoji-name="${c.emoji.name}"` : ""} ${c.emoji?.id ? `emoji="https://cdn.discordapp.com/emojis/${c.emoji.id}.${c.emoji.animated ? "gif" : "png"}"` : ""} ${c.url ? `url="${c.url}"` : ""}>${c.label || ""}</discord-button>`);
190
+ }
107
191
  }
108
- row.push(`</discord-action-row>`)
192
+ row.push(`</discord-action-row>`);
193
+ }
194
+ if (row.length >= 2) {
195
+ str.push(...row, `</discord-attachments>`);
109
196
  }
110
- if (row.length >= 2) str.push(...row, `</discord-attachments>`)
111
197
  }
112
- if (message.attachments.size) str.push(message.attachments.map((c) => `<a href="${c.proxyURL}">${c.name}</a>`).join("<br>"))
113
- str.push(`${message.content?.length ? `<br><br>` : ""}<code style="background-color: #36393e; color: white;">ID: ${message.id}</code>`)
198
+ if (message.attachments.size) {
199
+ str.push(message.attachments.map((c) => `<a href="${c.proxyURL}">${c.name}</a>`).join("<br>"));
200
+ }
201
+ str.push(`${message.content?.length ? `<br><br>` : ""}<code style="background-color: #36393e; color: white;">ID: ${message.id}</code>`);
114
202
  return [...str, `</discord-message>`].join(" ");
115
203
  }),
116
- "</discord-messages>"].join(" ");
204
+ "</discord-messages>",
205
+ ].join(" ");
206
+ };
207
+
208
+ exports.defs = {
209
+ modals: {
210
+ reason: (customId, str) =>
211
+ modal({
212
+ id: `${customId.split(":modal_submit")[0]}:modal_complete`,
213
+ title: str("REASON"),
214
+ components: [
215
+ {
216
+ type: 1,
217
+ components: [
218
+ {
219
+ type: 4,
220
+ custom_id: "reason",
221
+ label: str("REASON"),
222
+ style: 2,
223
+ min_length: 1,
224
+ max_length: 1024,
225
+ required: true,
226
+ placeholder: str("TICKET_CLOSE_PLACEHOLDER"),
227
+ },
228
+ ],
229
+ },
230
+ ],
231
+ }),
232
+ unbanReason: (customId, server, str, member, prefix) =>
233
+ modal({
234
+ id: `${prefix}:unban_modal:${customId.split(":")[1]}`,
235
+ title: `${str("UNBAN_FROM")} ${server.name}`,
236
+ components: [
237
+ {
238
+ type: 1,
239
+ components: [
240
+ {
241
+ type: 4,
242
+ label: str("REASON"),
243
+ custom_id: "reason",
244
+ style: 2,
245
+ min_length: 1,
246
+ max_length: 512,
247
+ required: true,
248
+ value: `${str("NO_REASON")} | ${str("BY")}: ${member.user.tag} (${member.id})`,
249
+ },
250
+ ],
251
+ },
252
+ ],
253
+ }),
254
+
255
+ custom: (options = { title: "", components: [] }, { prefix, str } = {}) =>
256
+ modal({
257
+ id: `${prefix}:modal_submit`,
258
+ title: options?.title || str("CREATE_TICKET"),
259
+ components:
260
+ options?.components?.length >= 1
261
+ ? options.components
262
+ : [
263
+ {
264
+ type: 1,
265
+ components: [
266
+ {
267
+ type: 4,
268
+ min_length: 10,
269
+ max_length: 4000,
270
+ custom_id: "message",
271
+ label: str("MODAL_CONTENT"),
272
+ style: 2,
273
+ placeholder: str("MODAL_CONTENT_PLACEHOLDER"),
274
+ required: true,
275
+ },
276
+ ],
277
+ },
278
+ ],
279
+ }),
280
+ },
281
+
282
+ getModalComponents: (questions) => {
283
+ return questions.length >= 1
284
+ ? questions.slice(0, 5).map((c) => ({
285
+ type: 1,
286
+ components: [
287
+ {
288
+ min_length: c.min_length || 10,
289
+ max_length: c.max_length || 4000,
290
+ type: 4,
291
+ style: c.style || 2,
292
+ label: c.label,
293
+ value: c.value,
294
+ placeholder: c.placeholder,
295
+ required: c.required,
296
+ custom_id: c.label || `random_${Math.floor(Math.random() * 10000)}`,
297
+ },
298
+ ],
299
+ }))
300
+ : [];
301
+ },
117
302
  };
303
+
118
304
  /**
119
305
  * @param {object} options
120
306
  * @param {string} [options.userId]
121
307
  * @param {string} [options.token]
122
- * @param {import("discord.js").Guild} [options.guild]
308
+ * @param {import("discord.js").Guild} [options.guild]
123
309
  * @returns {boolean}
124
310
  */
125
311
  exports.hasTicket = ({ userId, guild, token, prefix } = {}) => {
126
- if (!userId || !guild || !token || !prefix || !guild?.channels?.cache?.size) return false;
127
- 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")));
128
- if (!channels.size) return false;
129
- return true;
312
+ if (!userId || !guild || !token || !prefix || !guild?.channels?.cache?.size) {
313
+ return false;
314
+ }
315
+ return 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"))).size ? true : false;
130
316
  };
131
317
 
132
- exports.embed = (content, { color, title, guild, footer, author } = {}) => ({
133
- title: title || "INFO", description: content,
134
- color: color || 0xFF0000, timestamp: new Date(),
318
+ exports.embed = (content, { color, title, guild, footer, author, str } = {}) => ({
319
+ title: title || str("INFO"),
320
+ description: content,
321
+ color: color || 0xff0000,
322
+ timestamp: new Date(),
135
323
  footer,
136
- author: author || { name: guild?.name ?? "Tickets", icon_url: guild?.iconURL?.({ dynamic: true }) ?? "https://cdn.discordapp.com/emojis/818757771310792704.png?v=1" }
324
+ author: author || {
325
+ name: guild?.name ?? str("TICKETS"),
326
+ icon_url: guild?.iconURL?.({ dynamic: true }) ?? "https://cdn.discordapp.com/emojis/818757771310792704.png?v=1",
327
+ },
137
328
  });
138
329
 
139
330
  exports.webhook = (options) => {
140
- const { id, token, username, avatar } = options;
141
- return new Webhook(`https://discord.com/api/webhooks/${id}/${token}`, { username, avatar_url: avatar });
331
+ const { id, token, username, avatar, threadId } = options;
332
+ return new Webhook(`https://discord.com/api/webhooks/${id}/${token}`, {
333
+ username,
334
+ avatar_url: avatar,
335
+ threadId,
336
+ });
142
337
  };
143
338
 
144
- exports.getWebhookInfo = (options) => {
339
+ exports.getWebhookInfo = (options, username = "Tickets") => {
145
340
  return {
146
341
  id: options.webhook?.id,
147
342
  token: options.webhook?.token,
148
- username: options.webhook?.username || "Tickets",
149
- avatar: options.webhook?.avatar || "https://cdn.discordapp.com/emojis/818757771310792704.png?v=1"
150
- }
343
+ threadId: options.webhook?.threadId,
344
+ username: options.webhook?.username || username,
345
+ avatar: options.webhook?.avatar || "https://cdn.discordapp.com/emojis/818757771310792704.png?v=1",
346
+ };
151
347
  };
152
348
 
153
349
  exports.getAppealServer = ({ appeals, client } = {}) => {
154
- if (!appeals?.enabled || !appeals?.mainserver?.checkIfBanned) return null;
350
+ if (!appeals?.enabled || !appeals?.mainserver?.checkIfBanned) {
351
+ return null;
352
+ }
155
353
  let server = client.guilds.resolve(appeals.mainserver?.id);
156
- if (!server?.available) return null;
157
- return server;
158
- }
354
+ return server?.available === true ? server : null;
355
+ };