diff --git a/base/Guild.js b/base/Guild.js index 3368e067..9b10368b 100644 --- a/base/Guild.js +++ b/base/Guild.js @@ -43,8 +43,10 @@ module.exports = mongoose.model("Guild", new Schema({ messageUpdate: null, }, tickets: { + count: 0, ticketLogs: null, transcriptionLogs: null, + ticketsCategory: null, }, suggestions: null, reports: null, diff --git a/commands/!DISABLED/memes.js b/commands/!DISABLED/memes.js index 4fdec159..36eab8d2 100644 --- a/commands/!DISABLED/memes.js +++ b/commands/!DISABLED/memes.js @@ -72,9 +72,7 @@ class Memes extends BaseCommand { const embed = new EmbedBuilder() .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }) + .setFooter(client.config.embed.footer) .setTitle(res.title) .setDescription(`${interaction.translate("fun/memes:SUBREDDIT")}: **${res.subreddit}**\n${interaction.translate("common:AUTHOR")}: **${res.author}**\n${interaction.translate("fun/memes:UPS")}: **${res.ups}**`) .setImage(res.url) diff --git a/commands/!DISABLED/rename.js b/commands/!DISABLED/rename.js new file mode 100644 index 00000000..1ca1a9ca --- /dev/null +++ b/commands/!DISABLED/rename.js @@ -0,0 +1,23 @@ +const { SlashCommandBuilder, PermissionFlagsBits } = require("discord.js"); + +module.exports = { + data: new SlashCommandBuilder() + .setName("rename") + .setDescription("Renames the ticket channel. Usage: /rename ") + .addStringOption(option => option.setName("newname").setDescription("The new name for the ticket channel").setRequired(true)) + .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages), + async execute(interaction) { + try { + const newName = interaction.options.getString("newname"); + if (!interaction.channel.name.includes("support")) { + interaction.reply("This command can only be used in a ticket channel."); + return; + } + await interaction.channel.setName(newName + "-" + interaction.channel.name.split("-")[1]); + interaction.reply(`Renamed the ticket channel to ${newName}`); + } catch (error) { + console.error(error); + interaction.reply("An error occurred while trying to rename the ticket channel."); + } + }, +}; diff --git a/commands/!DISABLED/staff.js b/commands/!DISABLED/staff.js index 2ac8a490..fbe39db5 100644 --- a/commands/!DISABLED/staff.js +++ b/commands/!DISABLED/staff.js @@ -58,9 +58,7 @@ class Staff extends BaseCommand { }, ]) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }); + .setFooter(client.config.embed.footer); interaction.reply({ embeds: [embed], diff --git a/commands/Administration/config.js b/commands/Administration/config.js index 8b360fe3..d958a531 100644 --- a/commands/Administration/config.js +++ b/commands/Administration/config.js @@ -1,4 +1,4 @@ -const { SlashCommandBuilder, EmbedBuilder, PermissionsBitField } = require("discord.js"); +const { SlashCommandBuilder, EmbedBuilder, PermissionsBitField, ChannelType } = require("discord.js"); const BaseCommand = require("../../base/BaseCommand"); class Config extends BaseCommand { @@ -47,6 +47,9 @@ class Config extends BaseCommand { { name: client.translate("administration/config:MODLOGS"), value: "modlogs" }, { name: client.translate("administration/config:REPORTS"), value: "reports" }, { name: client.translate("administration/config:SUGGESTIONS"), value: "suggestions" }, + { name: client.translate("administration/config:TICKETSCATEGORY"), value: "tickets.ticketsCategory" }, + { name: client.translate("administration/config:TICKETLOGS"), value: "tickets.ticketLogs" }, + { name: client.translate("administration/config:TRANSCRIPTIONLOGS"), value: "tickets.transcriptionLogs" }, { name: client.translate("administration/config:MESSAGEUPDATE"), value: "monitoring.messageUpdate" }, ) .setRequired(true), @@ -101,9 +104,7 @@ class Config extends BaseCommand { iconURL: interaction.guild.iconURL(), }) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }) + .setFooter(client.config.embed.footer) .addFields([ { name: interaction.translate("administration/config:WELCOME_TITLE"), @@ -155,10 +156,13 @@ class Config extends BaseCommand { { name: interaction.translate("administration/config:SPECIAL_CHANNELS"), value: - `${interaction.translate("administration/config:SUGGESTIONS")}: ${guildData.plugins.suggestions ? `<#${guildData.plugins.suggestions}>` : `*${interaction.translate("common:NOT_DEFINED")}*`}\n` + - `${interaction.translate("administration/config:REPORTS")}: ${guildData.plugins.reports ? `<#${guildData.plugins.reports}>` : `*${interaction.translate("common:NOT_DEFINED")}*`}\n` + + `${interaction.translate("administration/config:BIRTHDAYS")}: ${guildData.plugins.birthdays ? `<#${guildData.plugins.birthdays}>` : `*${interaction.translate("common:NOT_DEFINED")}*`}` + `${interaction.translate("administration/config:MODLOGS")}: ${guildData.plugins.modlogs ? `<#${guildData.plugins.modlogs}>` : `*${interaction.translate("common:NOT_DEFINED")}*`}\n` + - `${interaction.translate("administration/config:BIRTHDAYS")}: ${guildData.plugins.birthdays ? `<#${guildData.plugins.birthdays}>` : `*${interaction.translate("common:NOT_DEFINED")}*`}`, + `${interaction.translate("administration/config:REPORTS")}: ${guildData.plugins.reports ? `<#${guildData.plugins.reports}>` : `*${interaction.translate("common:NOT_DEFINED")}*`}\n` + + `${interaction.translate("administration/config:SUGGESTIONS")}: ${guildData.plugins.suggestions ? `<#${guildData.plugins.suggestions}>` : `*${interaction.translate("common:NOT_DEFINED")}*`}\n` + + `${interaction.translate("administration/config:TICKETSCATEGORY")}: ${guildData.plugins.tickets.ticketsCategory ? `<#${guildData.plugins.tickets.ticketsCategory}>` : `*${interaction.translate("common:NOT_DEFINED")}*`}\n` + + `${interaction.translate("administration/config:TICKETLOGS")}: ${guildData.plugins.tickets.ticketLogs ? `<#${guildData.plugins.tickets.ticketLogs}>` : `*${interaction.translate("common:NOT_DEFINED")}*`}\n` + + `${interaction.translate("administration/config:TRANSCRIPTIONLOGS")}: ${guildData.plugins.tickets.transcriptionLogs ? `<#${guildData.plugins.tickets.transcriptionLogs}>` : `*${interaction.translate("common:NOT_DEFINED")}*`}\n`, }, { name: interaction.translate("administration/config:DASHBOARD_TITLE"), @@ -185,14 +189,18 @@ class Config extends BaseCommand { * @param {import("discord.js").ChatInputCommandInteraction} interaction * @param {String} setting * @param {Boolean} state - * @param {import("discord.js").GuildTextBasedChannel} channel + * @param {import("discord.js").GuildTextBasedChannel | import("discord.js").CategoryChannel} channel * @param {import("../../base/Guild")} guildData * @returns */ async function changeSetting(interaction, setting, state, channel, guildData) { + const settingSplitted = setting.split("."); + + if (settingSplitted.length === 2 && guildData.plugins[settingSplitted[0]] === undefined) guildData.plugins[settingSplitted[0]] = {}; + if (!state) { - guildData.plugins[setting] = null; - guildData.markModified(`plugins.${setting}`); + guildData.plugins[settingSplitted[0]][settingSplitted[1]] = null; + guildData.markModified("plugins"); await guildData.save(); return interaction.reply({ @@ -200,18 +208,20 @@ async function changeSetting(interaction, setting, state, channel, guildData) { ephemeral: true, }); } else { + if (settingSplitted[1] === "ticketsCategory" && channel.type !== ChannelType.GuildCategory) return interaction.reply({ content: interaction.translate("administration/config:TICKETS_NOT_CATEGORY"), ephemeral: true }); + if (channel) { - guildData.plugins[setting] = channel.id; - guildData.markModified(`plugins.${setting}`); + guildData.plugins[settingSplitted[0]][settingSplitted[1]] = channel.id; + guildData.markModified("plugins"); await guildData.save(); return interaction.reply({ - content: `${interaction.translate(`administration/config:${setting.toUpperCase()}`)}: **${interaction.translate("common:ENABLED")}** (${channel.toString()})`, + content: `${interaction.translate(`administration/config:${settingSplitted.length === 2 ? settingSplitted[1].toUpperCase() : setting.toUpperCase()}`)}: **${interaction.translate("common:ENABLED")}** (${channel.toString()})`, ephemeral: true, }); } else return interaction.reply({ - content: `${interaction.translate(`administration/config:${setting.toUpperCase()}`)}: ${ + content: `${interaction.translate(`administration/config:${settingSplitted.length === 2 ? settingSplitted[1].toUpperCase() : setting.toUpperCase()}`)}: ${ guildData.plugins[setting] ? `**${interaction.translate("common:ENABLED")}** (<#${guildData.plugins[setting]}>)` : `**${interaction.translate("common:DISABLED")}**` }`, ephemeral: true, diff --git a/commands/Economy/achievements.js b/commands/Economy/achievements.js index 7e08c016..939772e0 100644 --- a/commands/Economy/achievements.js +++ b/commands/Economy/achievements.js @@ -54,9 +54,7 @@ class Achievements extends BaseCommand { name: interaction.translate("economy/achievements:TITLE"), }) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }); + .setFooter(client.config.embed.footer); embed.addFields([ { diff --git a/commands/Economy/money.js b/commands/Economy/money.js index 29117778..9e42f707 100644 --- a/commands/Economy/money.js +++ b/commands/Economy/money.js @@ -86,9 +86,7 @@ class Money extends BaseCommand { }, ]) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }); + .setFooter(client.config.embed.footer); interaction.editReply({ embeds: [embed], }); diff --git a/commands/Economy/profile.js b/commands/Economy/profile.js index 24bd6741..a80be786 100644 --- a/commands/Economy/profile.js +++ b/commands/Economy/profile.js @@ -133,9 +133,7 @@ class Profile extends BaseCommand { }, ]) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }) + .setFooter(client.config.embed.footer) .setTimestamp(); const buffer = await userData.getAchievements(); diff --git a/commands/Economy/transactions.js b/commands/Economy/transactions.js index a2c97b31..7a9e7cfa 100644 --- a/commands/Economy/transactions.js +++ b/commands/Economy/transactions.js @@ -58,9 +58,7 @@ class Transactions extends BaseCommand { iconURL: interaction.member.displayAvatarURL(), }) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }); + .setFooter(client.config.embed.footer); const transactions = data.memberData.transactions, sortedTransactions = [[], []]; diff --git a/commands/Fun/lovecalc.js b/commands/Fun/lovecalc.js index f0122550..17b518f0 100644 --- a/commands/Fun/lovecalc.js +++ b/commands/Fun/lovecalc.js @@ -79,9 +79,7 @@ class Lovecalc extends BaseCommand { }), ) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }); + .setFooter(client.config.embed.footer); interaction.reply({ embeds: [embed], diff --git a/commands/General/boosters.js b/commands/General/boosters.js index 8ba349fd..28363ee5 100644 --- a/commands/General/boosters.js +++ b/commands/General/boosters.js @@ -156,10 +156,8 @@ function generateBoostersEmbeds(client, interaction, boosters, guildData) { const info = current.map(member => `${++j}. ${member.toString()} | ${interaction.translate("general/boosters:BOOSTER_SINCE")}: **${client.functions.printDate(client, member.premiumSince, null, guildData.language)}**`).join("\n"); const embed = new EmbedBuilder() - .setColor(interaction.client.config.embed.color) - .setFooter({ - text: interaction.client.config.embed.footer, - }) + .setColor(client.config.embed.color) + .setFooter(client.config.embed.footer) .setTitle(interaction.translate("general/boosters:BOOSTERS_LIST")) .setDescription(info) .setTimestamp(); diff --git a/commands/General/emoji.js b/commands/General/emoji.js index 303b5de2..9d40b268 100644 --- a/commands/General/emoji.js +++ b/commands/General/emoji.js @@ -55,9 +55,7 @@ class Emoji extends BaseCommand { }), }) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }) + .setFooter(client.config.embed.footer) .addFields([ { name: interaction.translate("common:NAME"), diff --git a/commands/General/help.js b/commands/General/help.js index af2beeb6..562a93c0 100644 --- a/commands/General/help.js +++ b/commands/General/help.js @@ -101,9 +101,7 @@ class Help extends BaseCommand { const embed = new EmbedBuilder() .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }) + .setFooter(client.config.embed.footer) .setAuthor({ name: interaction.translate("general/help:COMMANDS_IN", { category: arg }), }) @@ -189,9 +187,7 @@ function generateCommandHelp(interaction, command) { }, ]) .setColor(interaction.client.config.embed.color) - .setFooter({ - text: interaction.client.config.embed.footer, - }); + .setFooter(interaction.client.config.embed.footer); return embed; } diff --git a/commands/General/minecraft.js b/commands/General/minecraft.js index 0203d203..63ab30ac 100644 --- a/commands/General/minecraft.js +++ b/commands/General/minecraft.js @@ -109,9 +109,7 @@ class Minecraft extends BaseCommand { ]) .setColor(client.config.embed.color) .setThumbnail(`https://eu.mc-api.net/v3/server/favicon/${ip}`) - .setFooter({ - text: client.config.embed.footer, - }); + .setFooter(client.config.embed.footer); interaction.editReply({ embeds: [embed], diff --git a/commands/General/ping.js b/commands/General/ping.js index 3daa391b..0075389a 100644 --- a/commands/General/ping.js +++ b/commands/General/ping.js @@ -37,9 +37,7 @@ class Ping extends BaseCommand { async execute(client, interaction) { const embed = new EmbedBuilder() .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }) + .setFooter(client.config.embed.footer) .setAuthor({ name: interaction.translate("general/ping:PONG"), iconURL: client.user.avatarURL(), diff --git a/commands/General/report.js b/commands/General/report.js index 1ca82e1d..d15176e3 100644 --- a/commands/General/report.js +++ b/commands/General/report.js @@ -95,9 +95,7 @@ class Report extends BaseCommand { }, ]) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }); + .setFooter(client.config.embed.footer); const success = parseEmoji(client.customEmojis.cool).id; const error = parseEmoji(client.customEmojis.notcool).id; diff --git a/commands/General/serverinfo.js b/commands/General/serverinfo.js index 4b58ca39..ba9b1695 100644 --- a/commands/General/serverinfo.js +++ b/commands/General/serverinfo.js @@ -127,9 +127,7 @@ class Serverinfo extends BaseCommand { ]) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }); + .setFooter(client.config.embed.footer); interaction.reply({ embeds: [embed], diff --git a/commands/General/stats.js b/commands/General/stats.js index e3af50bf..1d1ef79c 100644 --- a/commands/General/stats.js +++ b/commands/General/stats.js @@ -45,9 +45,7 @@ class Stats extends BaseCommand { const statsEmbed = new EmbedBuilder() .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }) + .setFooter(client.config.embed.footer) .setAuthor({ name: interaction.translate("common:STATS"), }) diff --git a/commands/General/suggest.js b/commands/General/suggest.js index a3efa801..92daf0c6 100644 --- a/commands/General/suggest.js +++ b/commands/General/suggest.js @@ -74,9 +74,7 @@ class Suggest extends BaseCommand { }, ]) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }); + .setFooter(client.config.embed.footer); const success = parseEmoji(client.customEmojis.cool).id; const error = parseEmoji(client.customEmojis.notcool).id; diff --git a/commands/General/userinfo.js b/commands/General/userinfo.js index 14fdcc59..42609d5a 100644 --- a/commands/General/userinfo.js +++ b/commands/General/userinfo.js @@ -104,9 +104,7 @@ class Userinfo extends BaseCommand { }, ]) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }); + .setFooter(client.config.embed.footer); /* if (member.presence.activities[0]?.name === "Custom Status") { diff --git a/commands/General/whois.js b/commands/General/whois.js index 4502c430..8d0fe551 100644 --- a/commands/General/whois.js +++ b/commands/General/whois.js @@ -59,9 +59,7 @@ class Whois extends BaseCommand { ip, }), ) - .setFooter({ - text: client.config.embed.footer, - }) + .setFooter(client.config.embed.footer) .setColor(client.config.embed.color) .addFields( { name: interaction.translate("common:IP"), value: whois.query, inline: true }, diff --git a/commands/IAT/checkjar.js b/commands/IAT/checkjar.js index b1e915ce..628f0f65 100644 --- a/commands/IAT/checkjar.js +++ b/commands/IAT/checkjar.js @@ -57,9 +57,7 @@ class Checkjar extends BaseCommand { const embed = new EmbedBuilder() .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }) + .setFooter(client.config.embed.footer) .setTimestamp() .setDescription(`Текущий баланс: **${jar.balance / Math.pow(10, 2)}** грн\nТребуется на след. месяц: **379,18** грн (по курсу евро на 02.07.2023).\nЗдесь указаны последние 10 транзакций.`); diff --git a/commands/Moderation/warns.js b/commands/Moderation/warns.js index 647b9882..e1062e84 100644 --- a/commands/Moderation/warns.js +++ b/commands/Moderation/warns.js @@ -62,9 +62,7 @@ class Warns extends BaseCommand { iconURL: member.displayAvatarURL(), }) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }); + .setFooter(client.config.embed.footer); if (memberData.sanctions.length === 0) { embed.setDescription( diff --git a/commands/Music/nowplaying.js b/commands/Music/nowplaying.js index 84fadfb8..819711ab 100644 --- a/commands/Music/nowplaying.js +++ b/commands/Music/nowplaying.js @@ -88,9 +88,7 @@ class Nowplaying extends BaseCommand { }, ]) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }) + .setFooter(client.config.embed.footer) .setTimestamp(); interaction.editReply({ diff --git a/commands/NSFW/nsfw.js b/commands/NSFW/nsfw.js index e931e062..a3c4f3ce 100644 --- a/commands/NSFW/nsfw.js +++ b/commands/NSFW/nsfw.js @@ -70,9 +70,7 @@ class NSFW extends BaseCommand { const embed = new EmbedBuilder() .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }) + .setFooter(client.config.embed.footer) .setTitle(res.title) .setDescription(`${interaction.translate("fun/memes:SUBREDDIT")}: **${res.subreddit}**\n${interaction.translate("common:AUTHOR")}: **${res.author}**\n${interaction.translate("fun/memes:UPS")}: **${res.ups}**`) .setImage(res.url) diff --git a/commands/Owner/servers.js b/commands/Owner/servers.js index 8bff3ff3..2fb9a693 100644 --- a/commands/Owner/servers.js +++ b/commands/Owner/servers.js @@ -130,9 +130,7 @@ function generateServersEmbeds(interaction, servers) { const embed = new EmbedBuilder() .setColor(interaction.client.config.embed.color) - .setFooter({ - text: interaction.client.config.embed.footer, - }) + .setFooter(interaction.client.config.embed.footer) .setTitle(interaction.translate("owner/servers:SERVERS_LIST")) .setDescription(info) .setTimestamp(); diff --git a/commands/Tickets/adduser.js b/commands/Tickets/adduser.js index 665177b0..1ea953eb 100644 --- a/commands/Tickets/adduser.js +++ b/commands/Tickets/adduser.js @@ -1,7 +1,7 @@ const { SlashCommandBuilder, PermissionsBitField } = require("discord.js"); const BaseCommand = require("../../base/BaseCommand"); -class Adduser extends BaseCommand { +class AddUser extends BaseCommand { /** * * @param {import("../../base/JaBa")} client @@ -52,7 +52,7 @@ class Adduser extends BaseCommand { const member = interaction.options.getMember("user"); if (member.user.bot) return interaction.error("misc:BOT_USER", null, { ephemeral: true, edit: true }); - if (!interaction.channel.name.includes("support") && !interaction.channel.name.includes("application")) return interaction.error("tickets/adduser:NOT_TICKET", null, { ephemeral: true, edit: true }); + if (!interaction.channel.name.includes("support")) return interaction.error("tickets/adduser:NOT_TICKET", null, { ephemeral: true, edit: true }); await interaction.channel.permissionOverwrites.edit(member, { ViewChannel: true, SendMessages: true }); @@ -62,4 +62,4 @@ class Adduser extends BaseCommand { } } -module.exports = Adduser; +module.exports = AddUser; diff --git a/commands/Tickets/closeticket.js b/commands/Tickets/closeticket.js index c99a5e52..367e8e65 100644 --- a/commands/Tickets/closeticket.js +++ b/commands/Tickets/closeticket.js @@ -39,7 +39,7 @@ class CloseTicket extends BaseCommand { async execute(client, interaction, data) { await interaction.deferReply(); - if (!interaction.channel.name.includes("support") && !interaction.channel.name.includes("application")) return interaction.error("tickets/adduser:NOT_TICKET", null, { ephemeral: true, edit: true }); + if (!interaction.channel.name.includes("support")) return interaction.error("tickets/adduser:NOT_TICKET", null, { ephemeral: true, edit: true }); const embed = new EmbedBuilder() .setTitle(interaction.translate("tickets/closeticket:CLOSING_TITLE")) @@ -51,14 +51,14 @@ class CloseTicket extends BaseCommand { }, { name: interaction.translate("tickets/closeticket:CLOSING_BY"), - value: interaction.user.getUsetname(), + value: interaction.user.getUsername(), }, ) .setColor(client.config.embed.color) .setFooter(client.config.embed.footer) .setTimestamp(); - const button = new ButtonBuilder().setCustomId("cancel").setLabel(interaction.translate("common:CANCEL")).setStyle(ButtonStyle.Danger); + const button = new ButtonBuilder().setCustomId("cancel_closing").setLabel(interaction.translate("common:CANCEL")).setStyle(ButtonStyle.Danger); const row = new ActionRowBuilder().addComponents(button); await interaction.reply({ @@ -66,7 +66,7 @@ class CloseTicket extends BaseCommand { components: [row], }); - const filter = i => i.customId === "cancel"; + const filter = i => i.customId === "cancel_closing"; const collector = interaction.channel.createMessageComponentCollector({ filter, time: 5000 }); collector.on("collect", async i => { @@ -75,26 +75,44 @@ class CloseTicket extends BaseCommand { }); collector.on("end", async (_, reason) => { - if (reason === "canceled") { - const transcriptionLogs = data.guildData.plugins.tickets.transcriptionLogs; - if (transcriptionLogs) interaction.guild.channels.cache.get(transcriptionLogs).send({ content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: `<#${transcriptionLogs}>` }), files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }] }); - const reversedMessages = await interaction.channel.messages.fetch(); - + if (reason !== "canceled") { + const transcriptionLogs = data.guildData.plugins.tickets.transcriptionLogs, + ticketLogs = data.guildData.plugins.tickets.ticketLogs; + const reversedMessages = (await interaction.channel.messages.fetch()).filter(m => !m.author.bot); const messages = Array.from(reversedMessages.values()).reverse(); - let transcript = ""; + let transcript = "---- TICKET CREATED ----\n"; messages.forEach(message => { - transcript += `${message.author.username}: ${message.content}\n`; + transcript += `[${client.functions.printDate(client, message.createdTimestamp)}] ${message.author.getUsername()}: ${message.content}\n`; }); + transcript += "---- TICKET CLOSED ----"; - try { - await interaction.user.send({ content: `Here is the transcript for your ticket: ${interaction.channel.name}`, files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }] }); - } catch (error) { - console.error(error); - await interaction.reply("An error occurred while trying to send the transcript to the user."); + if (transcriptionLogs) interaction.guild.channels.cache.get(transcriptionLogs).send({ content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: `<#${interaction.channelId}>` }), files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }] }); + + if (ticketLogs) { + const logChannel = interaction.guild.channels.cache.get(ticketLogs); + const logEmbed = new EmbedBuilder() + .setTitle(interaction.translate("tickets/createticketembed:TICKET_CLOSED_TITLE")) + .setDescription(`${interaction.user.toString()} (${interaction.channel.toString()})`) + .setColor(client.config.embed.color) + .setFooter(client.config.embed.footer) + .setTimestamp(); + + logChannel.send({ embeds: [logEmbed] }); } - await interaction.channel.delete(); + interaction.channel.send("Closed!"); + + try { + await interaction.user.send({ + content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: interaction.channel.name }), + files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }], + }); + } catch (e) { + await interaction.reply({ content: interaction.translate("misc:CANT_DM"), ephemeral: true }); + } + + await interaction.channel.permissionOverwrites.edit(interaction.member, { ViewChannel: false, SendMessages: null }); } }); @@ -108,7 +126,7 @@ class CloseTicket extends BaseCommand { }, { name: interaction.translate("tickets/closeticket:CLOSING_BY"), - value: interaction.user.getUsetname(), + value: interaction.user.getUsername(), }, ) .setColor(client.config.embed.color) diff --git a/commands/Tickets/createticketembed.js b/commands/Tickets/createticketembed.js new file mode 100644 index 00000000..bffe47f4 --- /dev/null +++ b/commands/Tickets/createticketembed.js @@ -0,0 +1,225 @@ +const { SlashCommandBuilder, PermissionsBitField, EmbedBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder, ChannelType } = require("discord.js"); +const BaseCommand = require("../../base/BaseCommand"); + +class CreateTicketEmbed extends BaseCommand { + /** + * + * @param {import("../../base/JaBa")} client + */ + constructor(client) { + super({ + command: new SlashCommandBuilder() + .setName("createticketembed") + .setDescription(client.translate("tickets/createticketembed:DESCRIPTION")) + .setDescriptionLocalizations({ + uk: client.translate("tickets/createticketembed:DESCRIPTION", null, "uk-UA"), + ru: client.translate("tickets/createticketembed:DESCRIPTION", null, "ru-RU"), + }) + .setDMPermission(false) + .setDefaultMemberPermissions(PermissionsBitField.Flags.ManageGuild), + aliases: [], + dirname: __dirname, + ownerOnly: false, + }); + } + + /** + * + * @param {import("../../base/JaBa")} client + */ + async onLoad(client) { + client.on("interactionCreate", async interaction => { + if (!interaction.isButton()) return; + + const guildData = await client.findOrCreateGuild({ id: interaction.guildId }); + + const ticketsCategory = guildData.plugins.tickets.ticketsCategory, + ticketLogs = guildData.plugins.tickets.ticketLogs, + transcriptionLogs = guildData.plugins.tickets.transcriptionLogs; + + if (interaction.isButton()) { + const button = interaction.component; + + if (button.customId === "support_ticket") { + if (guildData.plugins.tickets.count === undefined) guildData.plugins.tickets.count = 0; + + guildData.plugins.tickets.count++; + guildData.markModified("plugins.tickets"); + guildData.save(); + + const channel = await interaction.guild.channels.create({ + name: `${interaction.user.username}-support-${guildData.plugins.tickets.count}`, + type: ChannelType.GuildText, + parent: ticketsCategory, + permissionOverwrites: [ + { + id: interaction.user.id, + allow: [PermissionsBitField.Flags.ViewChannel, PermissionsBitField.Flags.SendMessages], + }, + { + id: interaction.guild.roles.everyone, + deny: [PermissionsBitField.Flags.ViewChannel, PermissionsBitField.Flags.SendMessages], + }, + ], + }); + + const logChannel = interaction.guild.channels.cache.get(ticketLogs); + const logEmbed = new EmbedBuilder() + .setTitle(interaction.translate("tickets/createticketembed:TICKET_CREATED_TITLE")) + .setDescription(`${interaction.user.toString()} (${channel.toString()})`) + .setColor(client.config.embed.color) + .setFooter(client.config.embed.footer) + .setTimestamp(); + + await logChannel.send({ embeds: [logEmbed] }); + await interaction.success("tickets/createticketembed:TICKET_CREATED", { + channel: channel.toString(), + }, { ephemeral: true }); + + await channel.send(`<@${interaction.user.id}>`); + + const embed = new EmbedBuilder() + .setTitle("Support Ticket") + .setAuthor({ name: interaction.user.getUsername(), iconURL: interaction.user.displayAvatarURL() }) + .setDescription(interaction.translate("tickets/createticketembed:TICKET_CREATED_DESC")) + .setColor(client.config.embed.color) + .setFooter(client.config.embed.footer) + .setTimestamp(); + + const closeButton = new ButtonBuilder() + .setCustomId("close_ticket") + .setLabel(interaction.translate("tickets/closeticket:CLOSE_TICKET")) + .setStyle(ButtonStyle.Danger); + const transcriptButton = new ButtonBuilder() + .setCustomId("transcript_ticket") + .setLabel(interaction.translate("tickets/closeticket:TRANSCRIPT_TICKET")) + .setStyle(ButtonStyle.Secondary); + const row = new ActionRowBuilder().addComponents(closeButton, transcriptButton); + + await channel.send({ embeds: [embed], components: [row] }); + } + + if (button.customId === "close_ticket") { + const embed = new EmbedBuilder() + .setTitle(interaction.translate("tickets/closeticket:CLOSING_TITLE")) + .setDescription(interaction.translate("tickets/closeticket:CLOSING_DESC")) + .addFields( + { + name: interaction.translate("common:TICKET"), + value: interaction.channel.name, + }, + { + name: interaction.translate("tickets/closeticket:CLOSING_BY"), + value: interaction.user.getUsername(), + }, + ) + .setColor(client.config.embed.color) + .setFooter(client.config.embed.footer) + .setTimestamp(); + + const button = new ButtonBuilder().setCustomId("cancel_closing").setLabel(interaction.translate("common:CANCEL")).setStyle(ButtonStyle.Danger); + const row = new ActionRowBuilder().addComponents(button); + + await interaction.reply({ + embeds: [embed], + components: [row], + }); + + const filter = i => i.customId === "cancel_closing"; + const collector = interaction.channel.createMessageComponentCollector({ filter, time: 5000 }); + + collector.on("collect", async i => { + await i.update({ content: interaction.translate("tickets/closeticket:CLOSING_CANCELED"), components: [] }); + collector.stop("canceled"); + }); + + collector.on("end", async (_, reason) => { + if (reason !== "canceled") { + const reversedMessages = (await interaction.channel.messages.fetch()).filter(m => !m.author.bot); + const messages = Array.from(reversedMessages.values()).reverse(); + + let transcript = "---- TICKET CREATED ----\n"; + messages.forEach(message => { + transcript += `[${client.functions.printDate(client, message.createdTimestamp)}] ${message.author.getUsername()}: ${message.content}\n`; + }); + transcript += "---- TICKET CLOSED ----"; + + interaction.guild.channels.cache.get(transcriptionLogs).send({ content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: `<#${interaction.channelId}>` }), files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }] }); + + const logChannel = interaction.guild.channels.cache.get(ticketLogs); + const logEmbed = new EmbedBuilder() + .setTitle(interaction.translate("tickets/createticketembed:TICKET_CLOSED_TITLE")) + .setDescription(`${interaction.user.toString()} (${interaction.channel.toString()})`) + .setColor(client.config.embed.color) + .setFooter(client.config.embed.footer) + .setTimestamp(); + + logChannel.send({ embeds: [logEmbed] }); + + interaction.channel.send("Closed!"); + + try { + await interaction.user.send({ + content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: interaction.channel.name }), + files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }], + }); + } catch (e) { + await interaction.reply({ content: interaction.translate("misc:CANT_DM"), ephemeral: true }); + } + + await interaction.channel.permissionOverwrites.edit(interaction.member, { ViewChannel: false, SendMessages: null }); + } + }); + } + + if (button.customId === "transcript_ticket") { + await interaction.deferUpdate(); + + const reversedMessages = (await interaction.channel.messages.fetch()).filter(m => !m.author.bot); + const messages = Array.from(reversedMessages.values()).reverse(); + + let transcript = "---- TICKET CREATED ----\n"; + messages.forEach(message => { + transcript += `[${client.functions.printDate(client, message.createdTimestamp)}] ${message.author.getUsername()}: ${message.content}\n`; + }); + transcript += "---- TICKET CLOSED ----"; + + try { + await interaction.user.send({ + content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: `<#${interaction.channelId}>` }), + files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }], + }); + } catch (error) { + await interaction.followUp({ content: interaction.translate("misc:CANT_DM"), ephemeral: true }); + } + } + } + }); + } + /** + * + * @param {import("../../base/JaBa")} client + * @param {import("discord.js").ChatInputCommandInteraction} interaction + * @param {Object} data + */ + async execute(client, interaction, data) { + if (!data.guildData.plugins.tickets.ticketsCategory) return interaction.error("tickets/createticketembed:NO_CATEGORY"); + + await interaction.deferReply({ ephemeral: true }); + + const embed = new EmbedBuilder() + .setTitle(interaction.translate("tickets/createticketembed:TICKET_TITLE")) + .setDescription(interaction.translate("tickets/createticketembed:TICKET_DESC")) + .setColor(client.config.embed.color) + .setFooter(client.config.embed.footer); + + const supportButton = new ButtonBuilder().setCustomId("support_ticket").setLabel(interaction.translate("tickets/createticketembed:TICKET_SUPPORT")).setStyle(ButtonStyle.Primary); + const row = new ActionRowBuilder().addComponents(supportButton); + + await interaction.channel.send({ embeds: [embed], components: [row] }); + + interaction.success("tickets/createticketembed:SUCCESS", null, { edit: true }); + } +} + +module.exports = CreateTicketEmbed; diff --git a/commands/Tickets/empty.js b/commands/Tickets/empty.js deleted file mode 100644 index fb85ae69..00000000 --- a/commands/Tickets/empty.js +++ /dev/null @@ -1,10 +0,0 @@ -const { SlashCommandBuilder } = require('discord.js'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('test') - .setDescription('Replies with test'), - async execute(interaction) { - await interaction.reply('test'); - }, -}; \ No newline at end of file diff --git a/commands/Tickets/openTicketChannel.js b/commands/Tickets/openTicketChannel.js deleted file mode 100644 index 03c8cbcb..00000000 --- a/commands/Tickets/openTicketChannel.js +++ /dev/null @@ -1,32 +0,0 @@ -const { SlashCommandBuilder, EmbedBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder, PermissionFlagsBits } = require('discord.js'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('openticketchannel') - .setDescription('Creates an embed with buttons to open a ticket') - .setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild), - async execute(interaction) { - // create embed for ticket - const embed = new EmbedBuilder() - .setTitle('Tickets') - .setDescription('Open a ticket by choosing a category below'); - - // add button for support and application - const supportButton = new ButtonBuilder() - .setCustomId('support') - .setLabel('Support') - .setStyle(ButtonStyle.Primary); - - const applicationButton = new ButtonBuilder() - .setCustomId('application') - .setLabel('Application') - .setStyle(ButtonStyle.Primary); - - const row = new ActionRowBuilder() - .addComponents(supportButton, applicationButton); - - // send message with buttons - await interaction.channel.send({ embeds: [embed], components: [row] }); - await interaction.reply('Done'); - }, -}; \ No newline at end of file diff --git a/commands/Tickets/removeuser.js b/commands/Tickets/removeuser.js index 0c985607..4bb8ca99 100644 --- a/commands/Tickets/removeuser.js +++ b/commands/Tickets/removeuser.js @@ -1,35 +1,65 @@ -const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js'); +const { SlashCommandBuilder, PermissionsBitField } = require("discord.js"); +const BaseCommand = require("../../base/BaseCommand"); -module.exports = { - data: new SlashCommandBuilder() - .setName('removeuser') - .setDescription('Remove a user from a ticket') - .addMentionableOption(option => - option.setName('user') - .setDescription('The user to remove') - .setRequired(true)) - .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages), - async execute(interaction) { - try { - const user = interaction.options.getMentionable('user'); - const currentChannel = interaction.channel; +class RemoveUser extends BaseCommand { + /** + * + * @param {import("../../base/JaBa")} client + */ + constructor(client) { + super({ + command: new SlashCommandBuilder() + .setName("removeuser") + .setDescription(client.translate("tickets/removeuser:DESCRIPTION")) + .setDescriptionLocalizations({ + uk: client.translate("tickets/removeuser:DESCRIPTION", null, "uk-UA"), + ru: client.translate("tickets/removeuser:DESCRIPTION", null, "ru-RU"), + }) + .setDMPermission(false) + .setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages) + .addUserOption(option => + option + .setName("user") + .setDescription(client.translate("common:USER")) + .setDescriptionLocalizations({ + uk: client.translate("common:USER", null, "uk-UA"), + ru: client.translate("common:USER", null, "ru-RU"), + }) + .setRequired(true), + ), + aliases: [], + dirname: __dirname, + ownerOnly: false, + }); + } - if (currentChannel) { - if (!interaction.channel.name.includes('support') && !interaction.channel.name.includes('application')) { - interaction.reply('This command can only be used in a ticket channel.'); - return; - } - const member = await interaction.guild.members.fetch(user.id); - await interaction.channel.permissionOverwrites.edit(member, { ViewChannel: false }); - interaction.reply(`Removed ${user} to the ticket.`); - } - else { - interaction.reply('This channel is not a ticket.'); - } - } - catch (error) { - console.log(error); - interaction.reply('Error adding user to ticket.'); - } - }, -}; \ No newline at end of file + /** + * + * @param {import("../../base/JaBa")} client + */ + async onLoad() { + //... + } + /** + * + * @param {import("../../base/JaBa")} client + * @param {import("discord.js").ChatInputCommandInteraction} interaction + * @param {Object} data + */ + async execute(client, interaction) { + await interaction.deferReply(); + + const member = interaction.options.getMember("user"); + + if (member.user.bot) return interaction.error("misc:BOT_USER", null, { ephemeral: true, edit: true }); + if (!interaction.channel.name.includes("support")) return interaction.error("tickets/adduser:NOT_TICKET", null, { ephemeral: true, edit: true }); + + await interaction.channel.permissionOverwrites.edit(member, { ViewChannel: false, SendMessages: false }); + + interaction.success("tickets/removeuseruser:SUCCESS", { + user: member.user.toString(), + }, { edit: true }); + } +} + +module.exports = RemoveUser; diff --git a/commands/Tickets/rename.js b/commands/Tickets/rename.js deleted file mode 100644 index 1202acbe..00000000 --- a/commands/Tickets/rename.js +++ /dev/null @@ -1,27 +0,0 @@ -const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('rename') - .setDescription('Renames the ticket channel. Usage: /rename ') - .addStringOption(option => - option.setName('newname') - .setDescription('The new name for the ticket channel') - .setRequired(true)) - .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages), - async execute(interaction) { - try { - const newName = interaction.options.getString('newname'); - if (!interaction.channel.name.includes('support') && !interaction.channel.name.includes('application')) { - interaction.reply('This command can only be used in a ticket channel.'); - return; - } - await interaction.channel.setName(newName + '-' + interaction.channel.name.split('-')[1]); - interaction.reply(`Renamed the ticket channel to ${newName}`); - } - catch (error) { - console.error(error); - interaction.reply('An error occurred while trying to rename the ticket channel.'); - } - }, -}; \ No newline at end of file diff --git a/config.sample.js b/config.sample.js index 23858699..56e9aaed 100644 --- a/config.sample.js +++ b/config.sample.js @@ -24,7 +24,9 @@ module.exports = { /* For the embeds (embeded messages) */ embed: { color: "#0091fc", // The default color for the embeds - footer: "Bot | v" + require("./package.json").version, // And the default footer for the embeds + footer: { + text: "Bot | v" + require("./package.json").version, + }, // And the default footer for the embeds }, /* Bot's owner informations */ owner: { diff --git a/dashboard/docs/updates.md b/dashboard/docs/updates.md index de26caf3..00664b05 100644 --- a/dashboard/docs/updates.md +++ b/dashboard/docs/updates.md @@ -1,3 +1,12 @@ +### JaBa v4.3.3 +* Добавлено + * Система Тикетов!\ + Все необходимые команды есть в категории *Tickets*.\ + Для создавания тикетов нужно обязательно выбрать категорию где они будут сохраняться, сделать это можно через *config set*!\ + После этого используйте команду *createticketembed* в канале, где хотите чтобы появилось сообщение с кнопкой создания тикета.\ + С помощью команд *adduser* и *removeuser* можно добавлять и убирать людей из тикета соответственно.\ + *closeticket* позволяет принудительно закрыть тикет. + ### JaBa v4.3.1 * Добавлено * Мониторинг изменения сообщений!\ diff --git a/events/Guild/guildBanAdd.js b/events/Guild/guildBanAdd.js index 47f3c61f..bb6d5b86 100644 --- a/events/Guild/guildBanAdd.js +++ b/events/Guild/guildBanAdd.js @@ -21,7 +21,7 @@ class guildBanAdd extends BaseEvent { iconURL: ban.guild.iconURL(), }) .setColor(client.config.embed.color) - .setFooter({ text: client.config.embed.footer }) + .setFooter(client.config.embed.footer) .setDescription(`You were banned from **${ban.guild.name}**!\nReason: **${ban.reason || "Not specified"}**`); ban.user.send({ diff --git a/events/Guild/guildCreate.js b/events/Guild/guildCreate.js index 41ac0e09..82e0acbe 100644 --- a/events/Guild/guildCreate.js +++ b/events/Guild/guildCreate.js @@ -30,9 +30,7 @@ class GuildCreate extends BaseEvent { }) .setDescription("Use in your server to get list of all commands!.") .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }) + .setFooter(client.config.embed.footer) .setTimestamp(); const owner = await guild.fetchOwner(); @@ -55,7 +53,7 @@ class GuildCreate extends BaseEvent { iconURL: guild.iconURL(), }) .setColor(client.config.embed.color) - .setFooter({ text: client.config.embed.footer }) + .setFooter(client.config.embed.footer) .setDescription(`Зашёл на сервер **${guild.name}**. На нём **${users}** ${client.functions.getNoun(users, client.translate("misc:NOUNS:USERS:1"), client.translate("misc:NOUNS:USERS:2"), client.translate("misc:NOUNS:USERS:5"))} и **${bots}** ${client.functions.getNoun(bots, client.translate("misc:NOUNS:BOTS:1"), client.translate("misc:NOUNS:BOTS:2"), client.translate("misc:NOUNS:BOTS:5"))}`); client.channels.cache.get(client.config.support.logs).send({ embeds: [embed], diff --git a/events/Guild/guildDelete.js b/events/Guild/guildDelete.js index b557fe7f..4cb81af2 100644 --- a/events/Guild/guildDelete.js +++ b/events/Guild/guildDelete.js @@ -21,7 +21,7 @@ class GuildDelete extends BaseEvent { iconURL: guild.iconURL(), }) .setColor(client.config.embed.color) - .setFooter({ text: client.config.embed.footer }) + .setFooter(client.config.embed.footer) .setDescription(`Вышел с сервера **${guild.name}**.`); client.channels.cache.get(client.config.support.logs).send({ embeds: [embed], diff --git a/events/MessageHandler.js b/events/MessageHandler.js index 6c373369..a0614945 100644 --- a/events/MessageHandler.js +++ b/events/MessageHandler.js @@ -29,7 +29,7 @@ class MessageCreate extends BaseEvent { if (message.guild && !message.member) await message.guild.members.fetch(message.author.id); if (message.guild) { - const guildData = await client.findOrCreateGuild({ id: message.guild.id }); + const guildData = await client.findOrCreateGuild({ id: message.guildId }); const memberData = await client.findOrCreateMember({ id: message.author.id, guildId: message.guild.id }); message.guild.data = data.guildData = guildData; @@ -92,7 +92,7 @@ class MessageCreate extends BaseEvent { }); } - if (data.guildData.plugins.automod.enabled && !data.guildData.plugins.automod.ignored.includes(message.channel.id)) + if (data.guildData.plugins.automod.enabled && !data.guildData.plugins.automod.ignored.includes(message.channelId)) if (/(discord\.(gg|io|me|li)\/.+|discordapp\.com\/invite\/.+)/i.test(message.content)) if (!message.channel.permissionsFor(message.member).has(PermissionsBitField.Flags.ManageMessages)) { await message.error("administration/automod:DELETED", null, { mention: true }); diff --git a/events/Monitoring/messageUpdate.js b/events/Monitoring/messageUpdate.js index b56b7198..adc4e1a1 100644 --- a/events/Monitoring/messageUpdate.js +++ b/events/Monitoring/messageUpdate.js @@ -30,7 +30,7 @@ class messageUpdate extends BaseEvent { iconURL: newMessage.author.displayAvatarURL(), }) .setColor(client.config.embed.color) - .setFooter({ text: client.config.embed.footer }) + .setFooter(client.config.embed.footer) .setTitle(`${newMessage.author.getUsername()} edited a message!`) .setDescription(`Old Message: \`\`\`${oldMessage.content}\`\`\`\nNew Message: \`\`\`${newMessage.content}\`\`\`\nJump to message: ${newMessage.url}`); diff --git a/helpers/birthdays.js b/helpers/birthdays.js index 37fb5fb1..ba2a16cf 100644 --- a/helpers/birthdays.js +++ b/helpers/birthdays.js @@ -34,9 +34,7 @@ module.exports.init = async function (client) { iconURL: client.user.displayAvatarURL(), }) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }) + .setFooter(client.config.embed.footer) .addFields([ { name: client.translate("economy/birthdate:HAPPY_BIRTHDAY"), diff --git a/helpers/checkReminds.js b/helpers/checkReminds.js index 8a538ccb..06f327f2 100644 --- a/helpers/checkReminds.js +++ b/helpers/checkReminds.js @@ -40,9 +40,8 @@ module.exports.init = function (client) { }, ]) .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer, - }); + .setFooter(client.config.embed.footer); + dUser.send({ embeds: [embed], }); diff --git a/interactions.js b/interactions.js deleted file mode 100644 index 7506082f..00000000 --- a/interactions.js +++ /dev/null @@ -1,241 +0,0 @@ -if (interaction.isModalSubmit()) { - const age = interaction.fields.getTextInputValue('age'); - const location = interaction.fields.getTextInputValue('location'); - const experience = interaction.fields.getTextInputValue('experience'); - const why = interaction.fields.getTextInputValue('why'); - - const embed = new EmbedBuilder() - .setTitle('Application') - .setDescription('Thank you for applying to the server!') - .addFields( - { name: 'Age', value: age }, - { name: 'Location', value: location }, - { name: 'Experience', value: experience }, - { name: 'Why', value: why }, - ) - .setColor('#00ff00') - .setTimestamp(); - - // create ticket channel in application category - const channel = await interaction.guild.channels.create({ - name: `${interaction.user.username}-application`, - type: ChannelType.GuildText, - parent: applicationTicketCategory, - permissionOverwrites: [ - { - id: interaction.user.id, - allow: [PermissionsBitField.Flags.ViewChannel], - }, - { - id: interaction.guild.roles.everyone, - deny: [PermissionsBitField.Flags.ViewChannel], - }, - ], - }); - - // for each role in config access_to_ticket array add permission to view channel - for (const role of access_to_ticket) { - await channel.permissionOverwrites.edit(role, { ViewChannel: true }); - } - - const pingMessage = access_to_ticket.map(role => `||<@&${role}>||`).join(' ') + ` ||${interaction.user}||`; - await channel.send(pingMessage); - - - // send message to ticket log channel - const logChannel = interaction.guild.channels.cache.get(ticketLogChannel); - await logChannel.send(`Ticket created by ${interaction.user} in ${channel}`); - - await interaction.reply({ content: `Your application has been submitted. Please wait for a response from a staff member. ${channel}`, ephemeral: true }); - - const closeButton = new ButtonBuilder() - .setCustomId('close') - .setLabel('Close') - .setStyle(ButtonStyle.Danger); - - const row = new ActionRowBuilder() - .addComponents(closeButton); - - await channel.send({ embeds: [embed], components: [row] }); -} -else if (interaction.isButton()) { - // handle openTicketChannel button interactions here - - // application button ---------------------------------------------------------------------------------------- - const button = interaction.component; - if (button.customId === 'application') { - // TODO: Create application embed builder by taking user input - - const modal = new ModalBuilder() - .setCustomId('application') - .setTitle('Application'); - - const ageInput = new TextInputBuilder() - .setCustomId('age') - .setLabel('Enter your age') - .setStyle(TextInputStyle.Short); - - const locationInput = new TextInputBuilder() - .setCustomId('location') - .setLabel('Enter your time zone and country') - .setStyle(TextInputStyle.Short); - - const experienceInput = new TextInputBuilder() - .setCustomId('experience') - .setLabel('Enter your experience with Minecraft') - .setStyle(TextInputStyle.Paragraph); - - const whyInput = new TextInputBuilder() - .setCustomId('why') - .setLabel('Why do you want to join this server?') - .setStyle(TextInputStyle.Paragraph); - - const modalRow1 = new ActionRowBuilder() - .addComponents(ageInput); - - const modalRow2 = new ActionRowBuilder() - .addComponents(locationInput); - - const modalRow3 = new ActionRowBuilder() - .addComponents(experienceInput); - - const modalRow4 = new ActionRowBuilder() - .addComponents(whyInput); - - modal.addComponents(modalRow1, modalRow2, modalRow3, modalRow4); - - await interaction.showModal(modal); - } - // support button ---------------------------------------------------------------------------------------- - if (button.customId === 'support') { - const channel = await interaction.guild.channels.create({ - name: `${interaction.user.username}-support`, - type: ChannelType.GuildText, - parent: supportTicketCategory, - permissionOverwrites: [ - { - id: interaction.user.id, - allow: [PermissionsBitField.Flags.ViewChannel], - }, - { - id: interaction.guild.roles.everyone, - deny: [PermissionsBitField.Flags.ViewChannel], - }, - ], - }); - - const logChannel = interaction.guild.channels.cache.get(ticketLogChannel); - const logEmbed = new EmbedBuilder() - .setTitle('Ticket Created') - .setDescription(`Ticket created by ${interaction.user} in ${channel}`) - .setTimestamp() - .setFooter({ text: 'Bot created by dylancanada' }); - - await logChannel.send({ embeds: [logEmbed] }); - await interaction.reply({ content: `Ticket created at ${channel}`, ephemeral: true }); - - for (const role of access_to_ticket) { - await channel.permissionOverwrites.edit(role, { ViewChannel: true }); - } - - const pingMessage = access_to_ticket.map(role => `||<@&${role}>||`).join(' '); - await channel.send(pingMessage); - - const embed = new EmbedBuilder() - .setTitle('Support Ticket') - .setDescription('Ticket created, click the button below to close the ticket') - .setAuthor({ name: interaction.user.username, iconURL: interaction.user.displayAvatarURL() }) - .addFields({ name: 'Ticket', value: `Please explain your issue ${interaction.user} and someone will be with you shortly`, inline: false }) - .setTimestamp() - .setFooter({ text: 'Bot created by dylancanada' }); - - const closeButton = new ButtonBuilder() - .setCustomId('close') - .setLabel('Close') - .setStyle(ButtonStyle.Danger); - - const row = new ActionRowBuilder() - .addComponents(closeButton); - - await channel.send({ embeds: [embed], components: [row] }); - - } - - if (button.customId === 'close') { - const closeEmbed = new EmbedBuilder() - .setTitle('Closing Ticket') - .setDescription('This ticket will be closed in 5 seconds.') - .addFields( - { name: 'Ticket', value: interaction.channel.name }, - { name: 'Closed By', value: interaction.user.username }, - ) - .setColor('#ff0000'); - - const closeButton = new ButtonBuilder() - .setCustomId('cancel') - .setLabel('Cancel') - .setStyle(ButtonStyle.Danger); - - const row = new ActionRowBuilder() - .addComponents(closeButton); - - await interaction.reply({ embeds: [closeEmbed], components: [row] }); - - const filter = i => i.customId === 'cancel'; - const collector = interaction.channel.createMessageComponentCollector({ filter, time: 5000 }); - - // eslint-disable-next-line no-unused-vars - collector.on('collect', async i => { - await i.update({ content: 'Ticket close cancelled.', components: [] }); - collector.stop(); - }); - - collector.on('end', async collected => { - if (collected.size === 0) { - const transcriptChannel = interaction.guild.channels.cache.get(ticketTranscriptChannel); - const reversedMessages = await interaction.channel.messages.fetch({ limit: 100 }); - - const messages = Array.from(reversedMessages.values()).reverse(); - - let transcript = ''; - messages.forEach(message => { - transcript += `${message.author.getUsername()}: ${message.content}\n`; - }); - - transcriptChannel.send({ content: `Transcript for ${interaction.channel.name}`, files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }] }); - - try { - await interaction.user.send({ content: `Here is the transcript for your ticket: ${interaction.channel.name}`, files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }] }); - } - catch (error) { - console.error(error); - await interaction.reply('An error occurred while trying to send the transcript to the user.'); - } - - await interaction.channel.delete(); - } - }); - } - - if (button.customId === 'transcript') { - const transcriptChannel = interaction.guild.channels.cache.get(ticketTranscriptChannel); - const reversedMessages = await interaction.channel.messages.fetch({ limit: 100 }); - - const messages = Array.from(reversedMessages.values()).reverse(); - - let transcript = ''; - messages.forEach(message => { - transcript += `${message.author.username}: ${message.content}\n`; - }); - - transcriptChannel.send({ content: `Transcript for ${interaction.channel.name}`, files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }] }); - - try { - await interaction.user.send({ content: `Here is the transcript for your ticket: ${interaction.channel.name}`, files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }] }); - } - catch (error) { - console.error(error); - await interaction.reply('An error occurred while trying to send the transcript to the user.'); - } - } -} \ No newline at end of file diff --git a/languages/en-US/administration/config.json b/languages/en-US/administration/config.json index 538de750..a6a12b43 100644 --- a/languages/en-US/administration/config.json +++ b/languages/en-US/administration/config.json @@ -8,6 +8,10 @@ "MODLOGS": "Moderation Logs", "REPORTS": "Reports", "SUGGESTIONS": "Suggestions", + "TICKETSCATEGORY": "Category For Tickets (They have folder icon)", + "TICKETS_NOT_CATEGORY": "Please select a **categry** channel", + "TICKETLOGS": "Tickets Logs", + "TRANSCRIPTIONLOGS": "Transcripts Logs", "MONITORING_CHANNELS": "Monitoring Channels", "MESSAGEUPDATE": "Message Update Logs", diff --git a/languages/en-US/tickets/adduser.json b/languages/en-US/tickets/adduser.json new file mode 100644 index 00000000..0a83d005 --- /dev/null +++ b/languages/en-US/tickets/adduser.json @@ -0,0 +1,7 @@ +{ + "DESCRIPTION": "Adds user to ticket", + "USAGE": "[@user]", + "EXAMPLES": "adduser user:@jonny_bro", + "NOT_TICKET": "This channel is not a ticket", + "SUCCESS": "{{user}} added to the ticket" +} \ No newline at end of file diff --git a/languages/en-US/tickets/closeticket.json b/languages/en-US/tickets/closeticket.json new file mode 100644 index 00000000..bd0c279a --- /dev/null +++ b/languages/en-US/tickets/closeticket.json @@ -0,0 +1,13 @@ +{ + "DESCRIPTION": "Closes ticket", + "USAGE": "", + "EXAMPLES": "closeticket", + "CLOSE_TICKET": "Close Ticket", + "TRANSCRIPT_TICKET": "Get Transcript", + "CLOSING_TITLE": "Ticket Closure", + "CLOSING_DESC": "The ticket will be closed in 5 seconds", + "CLOSING_BY": "Ticket closed by", + "CLOSING_CANCELED": "Ticket closure canceled", + "CLOSED_TITLE": "Ticket Closed", + "TRANSCRIPT": "Transcript from {{channel}}" +} \ No newline at end of file diff --git a/languages/en-US/tickets/createticketembed.json b/languages/en-US/tickets/createticketembed.json new file mode 100644 index 00000000..2e5a26e6 --- /dev/null +++ b/languages/en-US/tickets/createticketembed.json @@ -0,0 +1,15 @@ +{ + "DESCRIPTION": "Create a message with buttons to create tickets", + "USAGE": "", + "EXAMPLES": "createticketembed", + "SUCCESS": "Post created", + + "TICKET_TITLE": "Create a ticket", + "TICKET_DESC": "Create a ticket by clicking a button", + "TICKET_SUPPORT": "Support", + "TICKET_CREATED_TITLE": "Ticket created", + "TICKET_CREATED_DESC": "You can click the button below if you want to close it", + "TICKET_CLOSED_TITLE": "Ticket closed", + "NO_CATEGORY": "Please select a category for tickets before using this command ()", + "TICKET_CREATED": "Your ticket ({{channel}}) has been created, please wait for a response from the administration" +} \ No newline at end of file diff --git a/languages/en-US/tickets/removeuser.json b/languages/en-US/tickets/removeuser.json new file mode 100644 index 00000000..e86c2d8b --- /dev/null +++ b/languages/en-US/tickets/removeuser.json @@ -0,0 +1,6 @@ +{ + "DESCRIPTION": "Removes user from ticket", + "USAGE": "[@user]", + "EXAMPLES": "removeuser user:@jonny_bro", + "SUCCESS": "{{user}} removed from the ticket" +} \ No newline at end of file diff --git a/languages/language-meta.json b/languages/language-meta.json index f0b8edd5..ae102d46 100644 --- a/languages/language-meta.json +++ b/languages/language-meta.json @@ -3,21 +3,21 @@ "name": "en-US", "nativeName": "English", "moment": "en", - "defaultMomentFormat": "MMMM Do YYYY", + "defaultMomentFormat": "HH:mm:ss, MMMM Do YYYY", "default": true }, { "name": "ru-RU", "nativeName": "Русский", "moment": "ru", - "defaultMomentFormat": "Do MMMM YYYY", + "defaultMomentFormat": "HH:mm:ss, Do MMMM YYYY", "default": false }, { "name": "uk-UA", "nativeName": "Українська", "moment": "uk", - "defaultMomentFormat": "Do MMMM YYYY", + "defaultMomentFormat": "HH:mm:ss, Do MMMM YYYY", "default": false } ] \ No newline at end of file diff --git a/languages/ru-RU/administration/config.json b/languages/ru-RU/administration/config.json index 0c17c27f..d4cdd371 100644 --- a/languages/ru-RU/administration/config.json +++ b/languages/ru-RU/administration/config.json @@ -8,6 +8,10 @@ "MODLOGS": "Логи модерации", "REPORTS": "Жалобы", "SUGGESTIONS": "Предложения", + "TICKETSCATEGORY": "Категория для тикетов (Обозначены иконкой папки)", + "TICKETS_NOT_CATEGORY": "Выберите **категорию** для каналов", + "TICKETLOGS": "Логи тикетов", + "TRANSCRIPTIONLOGS": "Логи расшифровок", "MONITORING_CHANNELS": "Каналы мониторинга", "MESSAGEUPDATE": "Логи изменения сообщений", diff --git a/languages/ru-RU/tickets/closeticket.json b/languages/ru-RU/tickets/closeticket.json index d808d4b7..2526e9d1 100644 --- a/languages/ru-RU/tickets/closeticket.json +++ b/languages/ru-RU/tickets/closeticket.json @@ -2,6 +2,8 @@ "DESCRIPTION": "Закрыть тикет", "USAGE": "", "EXAMPLES": "closeticket", + "CLOSE_TICKET": "Закрыть тикет", + "TRANSCRIPT_TICKET": "Получить расшифровку", "CLOSING_TITLE": "Закрытие тикета", "CLOSING_DESC": "Тикет закроется через 5 секунд", "CLOSING_BY": "Тикет закрыл", diff --git a/languages/ru-RU/tickets/createticketembed.json b/languages/ru-RU/tickets/createticketembed.json new file mode 100644 index 00000000..70e77fd6 --- /dev/null +++ b/languages/ru-RU/tickets/createticketembed.json @@ -0,0 +1,15 @@ +{ + "DESCRIPTION": "Создать сообщение с кнопками для создания тикетов", + "USAGE": "", + "EXAMPLES": "createticketembed", + "SUCCESS": "Сообщение создано", + + "TICKET_TITLE": "Создать тикет", + "TICKET_DESC": "Создайте тикет нажав кнопку ниже", + "TICKET_SUPPORT": "Поддержка", + "TICKET_CREATED_TITLE": "Тикет создан", + "TICKET_CREATED_DESC": "Вы можете нажать кнопку ниже если хотите закрыть его", + "TICKET_CLOSED_TITLE": "Тикет закрыт", + "NO_CATEGORY": "Перед использованием этой команды выберите категорию для тикетов ()", + "TICKET_CREATED": "Ваш тикет ({{channel}}) создан, ожидайте ответа администрации" +} \ No newline at end of file diff --git a/languages/ru-RU/tickets/removeuser.json b/languages/ru-RU/tickets/removeuser.json new file mode 100644 index 00000000..949b76b9 --- /dev/null +++ b/languages/ru-RU/tickets/removeuser.json @@ -0,0 +1,6 @@ +{ + "DESCRIPTION": "Убрать пользователя из тикета", + "USAGE": "[@user]", + "EXAMPLES": "removeuser user:@jonny_bro", + "SUCCESS": "{{user}} убран из тикета" +} \ No newline at end of file diff --git a/languages/uk-UA/administration/config.json b/languages/uk-UA/administration/config.json index 10ed1d22..2ea9da03 100644 --- a/languages/uk-UA/administration/config.json +++ b/languages/uk-UA/administration/config.json @@ -8,6 +8,10 @@ "MODLOGS": "Логи модерації", "REPORTS": "Скарги", "SUGGESTIONS": "Пропозиції", + "TICKETSCATEGORY": "Категорія для тікетів (Позначені іконкою папки)", + "TICKETS_NOT_CATEGORY": "Виберіть **категорію** для каналів", + "TICKETLOGS": "Логи тікетів", + "TRANSCRIPTIONLOGS": "Логи розшифровок", "MONITORING_CHANNELS": "Каналы мониторинга", "MESSAGEUPDATE": "Логи изменения сообщений", diff --git a/languages/uk-UA/tickets/adduser.json b/languages/uk-UA/tickets/adduser.json new file mode 100644 index 00000000..d290c587 --- /dev/null +++ b/languages/uk-UA/tickets/adduser.json @@ -0,0 +1,7 @@ +{ + "DESCRIPTION": "Додати користувача до тікета", + "USAGE": "[@user]", + "EXAMPLES": "adduser user:@jonny_bro", + "NOT_TICKET": "Цей канал не є квитком", + "SUCCESS": "{{user}} додано до тікета" +} \ No newline at end of file diff --git a/languages/uk-UA/tickets/closeticket.json b/languages/uk-UA/tickets/closeticket.json new file mode 100644 index 00000000..0b21a56c --- /dev/null +++ b/languages/uk-UA/tickets/closeticket.json @@ -0,0 +1,13 @@ +{ + "DESCRIPTION": "Закрити тікет", + "USAGE": "", + "EXAMPLES": "closeticket", + "CLOSE_TICKET": "Закрити тікет", + "TRANSCRIPT_TICKET": "Отримати розшифровку", + "CLOSING_TITLE": "Закриття квитка", + "CLOSING_DESC": "Тікет буде закрито через 5 секунд", + "CLOSING_BY": "Тікет закрито користувачем", + "CLOSING_CANCELED": "Скасування закриття квитка", + "CLOSED_TITLE": "Тікет закрито", + "TRANSCRIPT": "Копія повідомлень з {{channel}}" +} \ No newline at end of file diff --git a/languages/uk-UA/tickets/createticketembed.json b/languages/uk-UA/tickets/createticketembed.json new file mode 100644 index 00000000..c9d9dd0d --- /dev/null +++ b/languages/uk-UA/tickets/createticketembed.json @@ -0,0 +1,15 @@ +{ + "DESCRIPTION": "Створити повідомлення з кнопками для створення тікетів", + "USAGE": "", + "EXAMPLES": "createticketembed", + "SUCCESS": "Повідомлення створено", + + "TICKET_TITLE": "Створити тікет", + "TICKET_DESC": "Створіть тікет натиснувши кнопку", + "TICKET_SUPPORT": "Підтримка", + "TICKET_CREATED_TITLE": "Тікет створений", + "TICKET_CREATED_DESC": "Ви можете натиснути кнопку нижче, якщо хочете закрити його", + "TICKET_CLOSED_TITLE": "Тікет закрит", + "NO_CATEGORY": "Перед використанням цієї команди оберіть категорію тікетів ()", + "TICKET_CREATED": "Ваш тікет ({{channel}}) створен, чекайте відповіді адміністрації" +} \ No newline at end of file diff --git a/languages/uk-UA/tickets/removeuser.json b/languages/uk-UA/tickets/removeuser.json new file mode 100644 index 00000000..784146c3 --- /dev/null +++ b/languages/uk-UA/tickets/removeuser.json @@ -0,0 +1,6 @@ +{ + "DESCRIPTION": "Видалити користувача з тікета", + "USAGE": "[@user]", + "EXAMPLES": "removeuser user:@jonny_bro", + "SUCCESS": "{{user}} видалено з тікета" +} \ No newline at end of file diff --git a/package.json b/package.json index 87dc15c6..1873b5b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jaba", - "version": "4.3.1", + "version": "4.3.3", "description": "My Discord Bot", "main": "index.js", "scripts": {