diff --git a/base/BaseCommand.js b/base/BaseCommand.js index 90b2b560..e60989b9 100644 --- a/base/BaseCommand.js +++ b/base/BaseCommand.js @@ -1,4 +1,6 @@ /* eslint-disable no-unused-vars */ +const path = require("path"); + class BaseCommand { constructor(options, client) { /** @@ -17,6 +19,14 @@ class BaseCommand { * @type {Boolean} */ this.ownerOnly = options.ownerOnly || false; + /** + * @type {Object} + */ + this.dirname = options.dirname || false; + /** + * @type {String} + */ + this.category = (this.dirname ? this.dirname.split(path.sep)[parseInt(this.dirname.split(path.sep).length - 1, 10)] : "Other"); } } diff --git a/base/JaBa.js b/base/JaBa.js index 3782a482..00927e07 100644 --- a/base/JaBa.js +++ b/base/JaBa.js @@ -124,8 +124,6 @@ class JaBa extends Client { * @returns */ async loadCommands(dir, guild_id) { - if (!this.translations) this.translations = await require("../helpers/languages")(); - const filePath = path.join(__dirname, dir); const files = await fs.readdir(filePath); const rest = new REST({ version: "9" }).setToken(this.config.token); @@ -215,11 +213,8 @@ class JaBa extends Client { this.logger.log(`Unable to connect to the Mongodb database. Error: ${err}`, "error"); }); - // const languages = require("../helpers/languages"); - // this.translations = await languages(); - - // const autoUpdateDocs = require("../helpers/autoUpdateDocs"); - // autoUpdateDocs.update(this); + const autoUpdateDocs = require("../helpers/autoUpdateDocs"); + autoUpdateDocs.update(this); } get defaultLanguage() { @@ -251,12 +246,12 @@ class JaBa extends Client { } convertTime(time, type, noPrefix, locale) { - if (!type) time = "to"; + if (!type) type = false; if (!locale) locale = this.defaultLanguage; const languageData = this.languages.find((language) => language.name === locale || language.aliases.includes(locale)); const m = moment(time).locale(languageData.moment); - return (type === "to" ? m.toNow(noPrefix) : m.fromNow(noPrefix)); + return (type ? m.toNow(noPrefix) : m.fromNow(noPrefix)); } getNoun(number, one, two, five) { diff --git a/commands/Examples/mention.js b/commands/Examples/mention.js index 0c1923b4..af0fe6bf 100644 --- a/commands/Examples/mention.js +++ b/commands/Examples/mention.js @@ -1,9 +1,9 @@ -const BaseCommand = require("../base/BaseCommand"); +const BaseCommand = require("../../base/BaseCommand"); class Mention extends BaseCommand { /** * - * @param {import("../base/JaBa")} client + * @param {import("../../base/JaBa")} client */ constructor() { super({ @@ -12,19 +12,20 @@ class Mention extends BaseCommand { type: 2 // Type 2 is USER COMMAND. }, aliases: ["m"], // Application command aliases. + dirname: __dirname, guildOnly: true // Determines whether your command is only guild. }); } /** * - * @param {import("../base/JaBa")} client + * @param {import("../../base/JaBa")} client */ async onLoad() { //... } /** * - * @param {import("../base/JaBa")} client + * @param {import("../../base/JaBa")} client * @param {import("discord.js").ContextMenuInteraction} interaction */ async execute(client, interaction) { diff --git a/commands/Examples/ping.js b/commands/Examples/ping.js index 313929cf..945c6fe1 100644 --- a/commands/Examples/ping.js +++ b/commands/Examples/ping.js @@ -1,10 +1,10 @@ const { SlashCommandBuilder } = require("@discordjs/builders"); -const BaseCommand = require("../base/BaseCommand"); +const BaseCommand = require("../../base/BaseCommand"); class Ping extends BaseCommand { /** * - * @param {import("../base/JaBa")} client + * @param {import("../../base/JaBa")} client */ constructor() { super({ @@ -12,19 +12,20 @@ class Ping extends BaseCommand { .setName("ping") .setDescription("Ping command."), // This option is included in type 1. You can configure this option directly with the SlashCommandBuilder feature. aliases: ["p"], // Application command aliases. + dirname: __dirname, guildOnly: true // Determines whether your command is only guild. }); } /** * - * @param {import("../base/JaBa")} client + * @param {import("../../base/JaBa")} client */ async onLoad() { //... } /** * - * @param {import("../base/JaBa")} client + * @param {import("../../base/JaBa")} client * @param {import("discord.js").CommandInteraction} interaction */ async execute(client, interaction) { diff --git a/commands/Examples/repeat.js b/commands/Examples/repeat.js index 4b593b32..b7bae955 100644 --- a/commands/Examples/repeat.js +++ b/commands/Examples/repeat.js @@ -1,9 +1,9 @@ -const BaseCommand = require("../base/BaseCommand"); +const BaseCommand = require("../../base/BaseCommand"); class Repeat extends BaseCommand { /** * - * @param {import("../base/JaBa")} client + * @param {import("../../base/JaBa")} client */ constructor() { super({ @@ -12,19 +12,20 @@ class Repeat extends BaseCommand { type: 3 // Type 3 is MESSAGE COMMAND. }, aliases: ["r"], // Application command aliases. + dirname: __dirname, guildOnly: true // Determines whether your command is only guild. }); } /** * - * @param {import("../base/JaBa")} client + * @param {import("../../base/JaBa")} client */ async onLoad() { //... } /** * - * @param {import("../base/JaBa")} client + * @param {import("../../base/JaBa")} client * @param {import("discord.js").ContextMenuInteraction} interaction */ async execute(client, interaction) { diff --git a/commands/Owner/eval.js b/commands/Owner/eval.js index 1c25fd0a..86ab17d3 100644 --- a/commands/Owner/eval.js +++ b/commands/Owner/eval.js @@ -17,6 +17,7 @@ class Eval extends BaseCommand { .setDescription(client.translate("owner/eval:USAGE")) .setRequired(true)), aliases: ["e"], + dirname: __dirname, guildOnly: true, ownerOnly: true }); diff --git a/config.sample.js b/config.sample.js index c7e70c7f..e263f1da 100644 --- a/config.sample.js +++ b/config.sample.js @@ -4,8 +4,8 @@ module.exports = { /* ID of Bot's user */ user: "XXXXXXXXXXX", /* For the support server */ + production: true, // Set to true for production support: { - enabled: false, // Set to false for production id: "XXXXXXXXXXX", // The ID of the support server logs: "XXXXXXXXXXX", // And the ID of the logs channel of your server (new servers for example) }, diff --git a/dashboard/app.js b/dashboard/app.js index 8814c0ea..2990a0b9 100644 --- a/dashboard/app.js +++ b/dashboard/app.js @@ -2,7 +2,7 @@ const config = require("../config"), utils = require("./utils"), CheckAuth = require("./auth/CheckAuth"); -module.exports.load = async(client) => { +module.exports.init = async(client) => { /* Init express app */ const express = require("express"), session = require("express-session"), diff --git a/emojis.json b/emojis.json index b3962b37..31d92b0f 100644 --- a/emojis.json +++ b/emojis.json @@ -8,7 +8,6 @@ "link": "<:atlanta_link:598176933855100976>", "voice": "<:atlanta_voice:598176518891372560>", "add": "<:atlanta_add:598176235700355083>", - "vote": "<:atlanta_vote:598175768274665492>", "help": "<:atlanta_help:598175335078559771>", "warn": "<:atlanta_warn:598179558927106058>", "error": "<:atlanta_error:736144198318686278>", diff --git a/events/CommandHandler.js b/events/CommandHandler.js index bcc84875..d45253b0 100644 --- a/events/CommandHandler.js +++ b/events/CommandHandler.js @@ -24,8 +24,8 @@ class CommandHandler extends BaseEvent { }); data.userData = userData; - if (command.guildOnly && !interaction.inGuild()) return interaction.reply({ content: client.translate("misc:GUILD_ONLY"), ephemeral: true}); - if (command.ownerOnly && interaction.user.id !== client.config.owner.id) return interaction.reply({ content: client.translate("misc:OWNER_ONLY"), ephemeral: true }); + if (command.guildOnly && !interaction.inGuild()) return interaction.replyT("misc:GUILD_ONLY", { ephemeral: true }); + if (command.ownerOnly && interaction.user.id !== client.config.owner.id) return interaction.replyT("misc:OWNER_ONLY", { ephemeral: true }); if (interaction.inGuild()) { const guildData = await client.findOrCreateGuild({ diff --git a/events/guildCreate.js b/events/Guild/guildCreate.js similarity index 97% rename from events/guildCreate.js rename to events/Guild/guildCreate.js index e6466a1e..5f8b33f9 100644 --- a/events/guildCreate.js +++ b/events/Guild/guildCreate.js @@ -1,5 +1,5 @@ const { MessageEmbed } = require("discord.js"), - BaseEvent = require("../base/BaseEvent"); + BaseEvent = require("../../base/BaseEvent"); class GuildCreate extends BaseEvent { constructor() { diff --git a/events/guildDelete.js b/events/Guild/guildDelete.js similarity index 92% rename from events/guildDelete.js rename to events/Guild/guildDelete.js index 809bb25b..1cca1466 100644 --- a/events/guildDelete.js +++ b/events/Guild/guildDelete.js @@ -1,5 +1,5 @@ const { MessageEmbed } = require("discord.js"), - BaseEvent = require("../base/BaseEvent"); + BaseEvent = require("../../base/BaseEvent"); class GuildDelete extends BaseEvent { constructor() { diff --git a/events/guildMemberAdd.js b/events/Guild/guildMemberAdd.js similarity index 99% rename from events/guildMemberAdd.js rename to events/Guild/guildMemberAdd.js index 4349bebc..a227de96 100644 --- a/events/guildMemberAdd.js +++ b/events/Guild/guildMemberAdd.js @@ -1,5 +1,5 @@ const Canvas = require("canvas"), - BaseEvent = require("../base/BaseEvent"), + BaseEvent = require("../../base/BaseEvent"), { MessageAttachment } = require("discord.js"), { resolve } = require("path"); diff --git a/events/guildMemberRemove.js b/events/Guild/guildMemberRemove.js similarity index 99% rename from events/guildMemberRemove.js rename to events/Guild/guildMemberRemove.js index 60760f10..45eae983 100644 --- a/events/guildMemberRemove.js +++ b/events/Guild/guildMemberRemove.js @@ -1,5 +1,5 @@ const Canvas = require("canvas"), - BaseEvent = require("../base/BaseEvent"), + BaseEvent = require("../../base/BaseEvent"), { MessageAttachment } = require("discord.js"), { resolve } = require("path"); diff --git a/events/guildMemberUpdate.js b/events/Guild/guildMemberUpdate.js similarity index 95% rename from events/guildMemberUpdate.js rename to events/Guild/guildMemberUpdate.js index 54699b86..1ac6bd41 100644 --- a/events/guildMemberUpdate.js +++ b/events/Guild/guildMemberUpdate.js @@ -1,4 +1,4 @@ -const BaseEvent = require("../base/BaseEvent"); +const BaseEvent = require("../../base/BaseEvent"); class GuildMemberUpdate extends BaseEvent { constructor() { diff --git a/events/messageCreate.js b/events/messageCreate.js index 91b70020..e4b709c9 100644 --- a/events/messageCreate.js +++ b/events/messageCreate.js @@ -34,7 +34,7 @@ class MessageCreate extends BaseEvent { message.guild.data = data.guild = guild; } - if (message.content.match(new RegExp(`^<@!?${client.user.id}>( |)$`))) return message.sendT("misc:HELLO_SERVER", { username: message.author.username }); + if (message.content.match(new RegExp(`^<@!?${client.user.id}>( |)$`))) return message.replyT("misc:HELLO_SERVER", { username: message.author.username }); if (message.guild) { const memberData = await client.findOrCreateMember({ @@ -68,7 +68,7 @@ class MessageCreate extends BaseEvent { if (afkReason) { data.userData.afk = null; await data.userData.save(); - message.sendT("general/setafk:DELETED", { + message.replyT("general/setafk:DELETED", { username: message.author.username }); } diff --git a/events/ready.js b/events/ready.js index 4a23594e..f7640c62 100644 --- a/events/ready.js +++ b/events/ready.js @@ -19,7 +19,7 @@ class Ready extends BaseEvent { let tServers = client.guilds.cache.size - 1; // Logs some informations using logger - client.logger.log(`Loaded a total of ${commands.length} command(s).`, "log"); + client.logger.log(`Loaded a total of ${commands.length} command(s).`, "ready"); client.logger.log(`${client.user.tag}, ready to serve ${tUsers} users in ${tServers} servers.`, "ready"); client.logger.log(`Invite Link: ${client.generateInvite({ scopes: ["bot", "applications.commands"] , permissions: [Permissions.FLAGS.ADMINISTRATOR] })}`, "ready"); @@ -44,7 +44,7 @@ class Ready extends BaseEvent { clearTransactions.init(client); // Start the dashboard - if (client.config.dashboard.enabled) client.dashboard.load(client); + if (client.config.dashboard.enabled) client.dashboard.init(client); // Update status const version = require("../package.json").version; diff --git a/helpers/autoUpdateDocs.js b/helpers/autoUpdateDocs.js index 5dd5903d..957d5e28 100644 --- a/helpers/autoUpdateDocs.js +++ b/helpers/autoUpdateDocs.js @@ -1,48 +1,40 @@ -/* THIS UPDATES THE DOCS */ -module.exports = { - /** - * Update the doc - * @param {object} client The Discord Client instance - */ - update(client) { - const table = require("markdown-table"), - fs = require("fs"), - commands = client.commands, - categories = []; - commands.forEach((cmd) => { - if (!categories.includes(cmd.help.category)) categories.push(cmd.help.category); +module.exports.update = function (client) { + const table = require("markdown-table"), + fs = require("fs"), + commands = client.commands, + categories = [], + length = [...new Map(commands.map(v => [v.constructor.name, v])).values()].length; + commands.forEach((cmd) => { + if (!categories.includes(cmd.category)) categories.push(cmd.category); + }); + let text = `# JaBa имеет **${length} ${client.getNoun(length, "команда", "команды", "команд")}** в **${categories.length} ${client.getNoun(categories.length, "категории", "категориях", "категориях")}**! \n\n#### Содержимое таблицы \n**Название**: Название команды \n**Описание**: Описание команды \n**Использование**: Использование команды ( [] - обязательно, () - необязательно ) \n**Разрешено использование**: Где можно использовать команду \n\n`; + // categories.sort(function(a, b) { + // const aCmdsSize = commands.filter((cmd) => cmd.category === a).size; + // const bCmdsSize = commands.filter((cmd) => cmd.category === b).size; + // if (aCmdsSize > bCmdsSize) return -1; + // else return 1; + // }) + categories.sort().forEach((cat) => { + const categoriesArray = [ + ["Название", "Описание", "Использование", "Разрешено использование"] + ]; + const cmds = commands.filter((cmd) => cmd.category === cat), + length = [...new Map(cmds.map(v => [v.constructor.name, v])).values()].length; + text += `### ${cat} (${length} ${client.getNoun(length, "команда", "команды", "команд")})\n\n`; + cmds.sort(function (a, b) { + if (a.command.name < b.command.name) return -1; + else return 1; + }).forEach((cmd) => { + categoriesArray.push([ + `**${cmd.command.name}** ${cmd.aliases.length ? `**(${cmd.aliases.join(", ")})**` : ""}`, + client.translate(`${cmd.category.toLowerCase()}/${cmd.command.name}:DESCRIPTION`), + `${cmd.command.name} ${client.translate(`${cmd.category.toLowerCase()}/${cmd.command.name}:USAGE`)}`, + cmd.guildOnly ? "Только на сервере" : "На сервере и в ЛС бота" + ]); }); - let text = `# JaBa имеет свыше **${Math.floor(commands.size / 10)}0 команд** в **${categories.length} категориях**! \n\n#### Содержимое таблицы \n**Название**: Название команды \n**Описание**: Описание команды \n**Использование**: Использование команды ( [] - обязательно, () - необязательно ) \n**Разрешено использование**: Где можно использовать команду \n**Откат**: Время, через которое команду можно будет использовать повторно\n\n`; - - // categories.sort(function(a, b) { - // const aCmdsSize = commands.filter((cmd) => cmd.help.category === a).size; - // const bCmdsSize = commands.filter((cmd) => cmd.help.category === b).size; - // if (aCmdsSize > bCmdsSize) return -1; - // else return 1; - // }) - categories.sort().forEach((cat) => { - const arrCat = [ - ["Название", "Описание", "Использование", "Разрешено использование", "Откат"] - ]; - const cmds = commands.filter((cmd) => cmd.help.category === cat); - text += `### ${cat} (${cmds.size} ${client.getNoun(cmds.size, "команда", "команды", "команд")})\n\n`; - cmds.sort(function (a, b) { - if (a.help.name < b.help.name) return -1; - else return 1; - }).forEach((cmd) => { - arrCat.push([ - `**${cmd.help.name}** ${cmd.help.aliases.length ? `**(${cmd.help.aliases.join(", ")})**` : ""}`, - client.translate(`${cmd.help.category.toLowerCase()}/${cmd.help.name}:DESCRIPTION`), - client.translate(`${cmd.help.category.toLowerCase()}/${cmd.help.name}:USAGE`), - cmd.conf.guildOnly ? "Только на сервере" : "На сервере и в ЛС бота", - `${Math.ceil(cmd.conf.cooldown / 1000)} ${client.getNoun(Math.ceil(cmd.conf.cooldown / 1000), "секунда", "секунды", "секунд")}` - ]); - }); - text += `${table(arrCat)}\n\n`; - }); - - if (!fs.existsSync("./dashboard/public/docs")) fs.mkdirSync("./dashboard/public/docs"); - fs.writeFileSync("./dashboard/public/docs/commands.md", text); - client.logger.log("Dashboard docs updated!"); - } + text += `${table(categoriesArray)}\n\n`; + }); + if (!fs.existsSync("./dashboard/public/docs")) fs.mkdirSync("./dashboard/public/docs"); + fs.writeFileSync("./dashboard/public/docs/commands.md", text); + client.logger.log("Dashboard docs updated!"); }; \ No newline at end of file diff --git a/helpers/birthdays.js b/helpers/birthdays.js index 5b8f58d6..a8fd0982 100644 --- a/helpers/birthdays.js +++ b/helpers/birthdays.js @@ -1,7 +1,7 @@ const CronJob = require("cron").CronJob, Discord = require("discord.js"); -async function init(client) { +module.exports.init = async function (client) { new CronJob("0 5 * * *", async function () { client.guilds.cache.forEach(async (guild) => { const date = new Date(), @@ -55,8 +55,4 @@ async function init(client) { } }); }, null, true, "Europe/Moscow"); -} - -module.exports = { - init }; \ No newline at end of file diff --git a/helpers/checkReminds.js b/helpers/checkReminds.js index 71edc3f5..57e8351a 100644 --- a/helpers/checkReminds.js +++ b/helpers/checkReminds.js @@ -1,51 +1,44 @@ const Discord = require("discord.js"); -/* THIS CHECK IF THERE IS A REMIND MUST BE SENT */ -module.exports = { - /** - * Starts checking... - * @param {object} client The Discord Client instance - */ - init(client) { - client.usersData - .find({ reminds: { $gt: [] } }) - .then((users) => { - for (const user of users) { - if (!client.users.cache.has(user.id)) client.users.fetch(user.id); - client.databaseCache.usersReminds.set(user.id, user); - } - }); - setInterval(async function () { - const dateNow = Date.now(); - client.databaseCache.usersReminds.forEach(async (user) => { - const dUser = client.users.cache.get(user.id); - if (dUser) { - const reminds = user.reminds; - const mustSent = reminds.filter((r) => r.sendAt < dateNow); - if (mustSent.length > 0) { - mustSent.forEach((r) => { - const embed = new Discord.MessageEmbed() - .setAuthor({ - name: client.translate("general/remindme:TITLE") - }) - .addField(client.translate("common:CREATION"), client.translate("general/remindme:CREATED", { - time: client.convertTime(r.createdAt, "from") - })) - .addField(client.translate("common:MESSAGE"), r.message) - .setColor(client.config.embed.color) - .setFooter({ - text: client.config.embed.footer - }); - dUser.send({ - embeds: [embed] +module.exports.init = function (client) { + client.usersData + .find({ reminds: { $gt: [] } }) + .then((users) => { + for (const user of users) { + if (!client.users.cache.has(user.id)) client.users.fetch(user.id); + client.databaseCache.usersReminds.set(user.id, user); + } + }); + setInterval(async function () { + const dateNow = Date.now(); + client.databaseCache.usersReminds.forEach(async (user) => { + const dUser = client.users.cache.get(user.id); + if (dUser) { + const reminds = user.reminds; + const mustSent = reminds.filter((r) => r.sendAt < dateNow); + if (mustSent.length > 0) { + mustSent.forEach((r) => { + const embed = new Discord.MessageEmbed() + .setAuthor({ + name: client.translate("general/remindme:TITLE") + }) + .addField(client.translate("common:CREATION"), client.translate("general/remindme:CREATED", { + time: client.convertTime(r.createdAt, "from") + })) + .addField(client.translate("common:MESSAGE"), r.message) + .setColor(client.config.embed.color) + .setFooter({ + text: client.config.embed.footer }); + dUser.send({ + embeds: [embed] }); - user.reminds = user.reminds.filter((r) => r.sendAt >= dateNow); - user.save(); - if (user.reminds.length === 0) client.databaseCache.usersReminds.delete(user.id); - } + }); + user.reminds = user.reminds.filter((r) => r.sendAt >= dateNow); + user.save(); + if (user.reminds.length === 0) client.databaseCache.usersReminds.delete(user.id); } - }); - }, 1000); - } + } + }); + }, 1000); }; \ No newline at end of file diff --git a/helpers/checkUnmutes.js b/helpers/checkUnmutes.js index 0bfabe38..afd8fc52 100644 --- a/helpers/checkUnmutes.js +++ b/helpers/checkUnmutes.js @@ -1,67 +1,59 @@ const Discord = require("discord.js"); -module.exports = { - /** - * Check if there is a user to unmute - * @param {object} client The Discord Client instance - */ - async init(client) { - client.membersData - .find({ "mute.muted": true }) - .then((members) => { - members.forEach((member) => { - client.databaseCache.mutedUsers.set(`${member.id}${member.guildID}`, member); - }); - }); - setInterval(async () => { - client.databaseCache.mutedUsers.filter((m) => m.mute.endDate <= Date.now()).forEach(async (memberData) => { - const guild = client.guilds.cache.get(memberData.guildID); - if (!guild) return; - const member = guild.members.cache.get(memberData.id) || await guild.members.fetch(memberData.id).catch(() => { - memberData.mute = { - muted: false, - endDate: null, - case: null - }; - memberData.save(); - client.logger.log("[unmute] " + memberData.id + " cannot be found."); - - return null; - }); - const guildData = await client.findOrCreateGuild({ - id: guild.id - }); - guild.data = guildData; - if (member) { - guild.channels.cache.forEach((channel) => { - const permOverwrites = channel.permissionOverwrites.cache.get(member.id); - if (permOverwrites) permOverwrites.delete(); - }); - } - const user = member ? member.user : await client.users.fetch(memberData.id); - const embed = new Discord.MessageEmbed() - .setDescription(guild.translate("moderation/unmute:SUCCESS_CASE", { - user: user.toString(), - usertag: user.tag, - count: memberData.mute.case - })) - .setColor("#f44271") - .setFooter({ - text: guild.client.config.embed.footer - }); - const channel = guild.channels.cache.get(guildData.plugins.modlogs); - if (channel) channel.send({ - embeds: [embed] - }); +module.exports.init = async function (client) { + client.membersData + .find({ "mute.muted": true }) + .then((members) => { + members.forEach((member) => client.databaseCache.mutedUsers.set(`${member.id}${member.guildID}`, member)); + }); + setInterval(async () => { + client.databaseCache.mutedUsers.filter((m) => m.mute.endDate <= Date.now()).forEach(async (memberData) => { + const guild = client.guilds.cache.get(memberData.guildID); + if (!guild) return; + const member = guild.members.cache.get(memberData.id) || await guild.members.fetch(memberData.id).catch(() => { memberData.mute = { muted: false, endDate: null, case: null }; - client.databaseCache.mutedUsers.delete(`${memberData.id}${memberData.guildID}`); - await memberData.save(); + memberData.save(); + client.logger.log("[unmute] " + memberData.id + " cannot be found."); + return null; }); - }, 1000); - } + + const guildData = await client.findOrCreateGuild({ + id: guild.id + }); + + if (member) { + guild.channels.cache.forEach((channel) => { + const permOverwrites = channel.permissionOverwrites.cache.get(member.id); + if (permOverwrites) permOverwrites.delete(); + }); + } + const user = member ? member.user : await client.users.fetch(memberData.id); + const embed = new Discord.MessageEmbed() + .setDescription(guild.translate("moderation/unmute:SUCCESS_CASE", { + user: user.toString(), + usertag: user.tag, + count: memberData.mute.case + })) + .setColor("#F44271") + .setFooter({ + text: guild.client.config.embed.footer + }); + const channel = guild.channels.cache.get(guildData.plugins.modlogs); + if (channel) channel.send({ embeds: [embed] }); + + memberData.mute = { + muted: false, + endDate: null, + case: null + }; + + client.databaseCache.mutedUsers.delete(`${memberData.id}${memberData.guildID}`); + await memberData.save(); + }); + }, 1000); }; \ No newline at end of file diff --git a/helpers/clearTransactions.js b/helpers/clearTransactions.js index 60dc1634..a12f658e 100644 --- a/helpers/clearTransactions.js +++ b/helpers/clearTransactions.js @@ -1,19 +1,18 @@ -module.exports = { - async init(client) { - setInterval(async () => { - const timestamp = Date.now() + 30 * 24 * 60 * 60 * 1000; // day hour min sec msec / 1 month - const members = client.membersData.find({ transactions: { $gt: [] } }); +module.exports.init = async function (client) { + setInterval(async () => { + // Date.now() + days * hours * mins * secs * msecs / 1 month + const timestamp = Date.now() + 30 * 24 * 60 * 60 * 1000; + const members = client.membersData.find({ transactions: { $gt: [] } }); - for (const member of members) { - const transactions = member.transactions; - for await (const transaction of transactions) { - if (transaction.date < timestamp) { - const index = transactions.indexOf(transaction); - transactions.splice(index, 1); - await member.save(); - } + for (const member of members) { + const transactions = member.transactions; + for await (const transaction of transactions) { + if (transaction.date < timestamp) { + const index = transactions.indexOf(transaction); + transactions.splice(index, 1); + await member.save(); } } - }, 24 * 60 * 60 * 1000); // every 24 hours - }, + } + }, 7 * 24 * 60 * 60 * 1000); // every 7 days }; \ No newline at end of file diff --git a/helpers/discordTogether.js b/helpers/discordTogether.js index 1faa8156..e7a2157b 100644 --- a/helpers/discordTogether.js +++ b/helpers/discordTogether.js @@ -1,6 +1,4 @@ -module.exports = { - init(client) { - const { DiscordTogether } = require("discord-together"); - client.discordTogether = new DiscordTogether(client); - } +module.exports.init = function (client) { + const { DiscordTogether } = require("discord-together"); + client.discordTogether = new DiscordTogether(client); }; \ No newline at end of file diff --git a/helpers/extenders.js b/helpers/extenders.js index 46c372bf..b61a4b2c 100644 --- a/helpers/extenders.js +++ b/helpers/extenders.js @@ -1,11 +1,4 @@ -const { Guild, Message } = require("discord.js"); - -Guild.prototype.translate = function (key, args) { - const language = this.client.translations.get(this.guild ? this.guild.data.language : "ru-RU"); - if (!language) throw "Message: Invalid language set in data."; - - return language(key, args); -}; +const { Message, Interaction } = require("discord.js"); Message.prototype.translate = function (key, args) { const language = this.client.translations.get(this.guild ? this.guild.data.language : "ru-RU"); @@ -14,39 +7,49 @@ Message.prototype.translate = function (key, args) { return language(key, args); }; -// Wrapper for sendT with error emoji -Message.prototype.error = function (key, args, options = {}) { - options.prefixEmoji = "error"; - - return this.sendT(key, args, options); -}; - -// Wrapper for sendT with success emoji -Message.prototype.success = function (key, args, options = {}) { - options.prefixEmoji = "success"; - - return this.sendT(key, args, options); -}; - -// Translate and send the message -Message.prototype.sendT = function (key, args, options = {}) { - let string = this.translate(key, args); +Message.prototype.replyT = function (key, args, options = {}) { + let string = this.translate(key, args, this.guild ? this.guild.data.language : "ru-RU"); if (options.prefixEmoji) string = `${this.client.customEmojis[options.prefixEmoji]} | ${string}`; if (options.edit) return this.edit(string); else return this.reply({ content: string }); }; -// Format a date -Message.prototype.printDate = function (date, format) { - return this.client.printDate(date, format, this.guild.data.language); +Message.prototype.error = function (key, args, options = {}) { + options.prefixEmoji = "error"; + + return this.replyT(key, args, options); }; -// Convert time -Message.prototype.convertTime = function (time, type, noPrefix) { - return this.client.convertTime(time, type, noPrefix, (this.guild && this.guild.data) ? this.guild.data.language : null); +Message.prototype.success = function (key, args, options = {}) { + options.prefixEmoji = "success"; + + return this.replyT(key, args, options); }; -Message.prototype.getNoun = function (number, one, two, five) { - return this.client.getNoun(number, one, two, five); +Interaction.prototype.translate = function (key, args) { + const language = this.client.translations.get(this.guild ? this.guild.data.language : "ru-RU"); + if (!language) throw "Message: Invalid language set in data."; + + return language(key, args); +}; + +Interaction.prototype.replyT = function (key, args, options = {}) { + let string = this.translate(key, args, this.guild ? this.guild.data.language : "ru-RU"); + if (options.prefixEmoji) string = `${this.client.customEmojis[options.prefixEmoji]} | ${string}`; + + if (options.edit) return this.editReply(string); + else return this.reply({ content: string, ephemeral: options.ephemeral || false, fetchReply: options.fetchReply || false }); +}; + +Interaction.prototype.error = function (key, args, options = {}) { + options.prefixEmoji = "error"; + + return this.replyT(key, args, options); +}; + +Interaction.prototype.success = function (key, args, options = {}) { + options.prefixEmoji = "success"; + + return this.replyT(key, args, options); }; \ No newline at end of file diff --git a/helpers/functions.js b/helpers/functions.js index 230809d3..6d8781bf 100644 --- a/helpers/functions.js +++ b/helpers/functions.js @@ -1,31 +1,10 @@ -const { Permissions } = require("discord.js"); -const languages = require("../languages/language-meta.json").map((l) => l.moment).filter((l) => l !== "en"); -languages.forEach((lang) => { +const { Permissions } = require("discord.js"), + langs = require("../languages/language-meta.json").map((l) => l.moment).filter((l) => l !== "en"); +langs.forEach((lang) => { require(`moment/locale/${lang}.js`); }); module.exports = { - getPrefix(message, data) { - if (message.channel.type !== "DM") { - const prefixes = [ - `<@!${message.client.user.id}> `, - `<@${message.client.user.id}> `, - `<@!${message.client.user.id}>`, - `<@${message.client.user.id}>`, - message.client.user.username.toLowerCase(), - data.guild.prefix - ]; - - let prefix = null; - - prefixes.forEach((p) => { - if (message.content.startsWith(p) || message.content.toLowerCase().startsWith(p)) prefix = p; - }); - - return prefix; - } else return true; - }, - async createInvite(client, guildId) { const guild = client.guilds.cache.get(guildId); const member = guild.me; @@ -70,49 +49,5 @@ module.exports = { randomNum(min, max) { return Math.floor(Math.random() * (max - min) + min + 1); - }, - - convertTime(guild, time) { - const absoluteSeconds = Math.floor((time / 1000) % 60); - const absoluteMinutes = Math.floor((time / (1000 * 60)) % 60); - const absoluteHours = Math.floor((time / (1000 * 60 * 60)) % 24); - const absoluteDays = Math.floor(time / (1000 * 60 * 60 * 24)); - - const d = absoluteDays ? - absoluteDays === 1 ? - guild.translate("time:ONE_DAY") : - guild.translate("time:DAYS", { - amount: absoluteDays - }) : - null; - const h = absoluteHours ? - absoluteHours === 1 ? - guild.translate("time:ONE_HOUR") : - guild.translate("time:HOURS", { - amount: absoluteHours - }) : - null; - const m = absoluteMinutes ? - absoluteMinutes === 1 ? - guild.translate("time:ONE_MINUTE") : - guild.translate("time:MINUTES", { - amount: absoluteMinutes - }) : - null; - const s = absoluteSeconds ? - absoluteSeconds === 1 ? - guild.translate("time:ONE_SECOND") : - guild.translate("time:SECONDS", { - amount: absoluteSeconds - }) : - null; - - const absoluteTime = []; - if (d) absoluteTime.push(d); - if (h) absoluteTime.push(h); - if (m) absoluteTime.push(m); - if (s) absoluteTime.push(s); - - return absoluteTime.join(", "); } }; \ No newline at end of file diff --git a/helpers/logger.js b/helpers/logger.js index 79cb58b4..5b37e262 100644 --- a/helpers/logger.js +++ b/helpers/logger.js @@ -11,9 +11,9 @@ function dateTimePad(value, digits) { } function format(tDate) { - return (tDate.getFullYear() + "-" + + return (tDate.getDate() + "-" + dateTimePad((tDate.getMonth() + 1), 2) + "-" + - dateTimePad(tDate.getDate(), 2) + " " + + dateTimePad(tDate.getFullYear(), 2) + " " + dateTimePad(tDate.getHours(), 2) + ":" + dateTimePad(tDate.getMinutes(), 2) + ":" + dateTimePad(tDate.getSeconds(), 2) + "." + diff --git a/helpers/tictactoe.js b/helpers/tictactoe.js index 48fc188a..7b5e37ed 100644 --- a/helpers/tictactoe.js +++ b/helpers/tictactoe.js @@ -1,10 +1,10 @@ // Thanks to simply-djs for this =) -const Discord = require("discord.js"); +const { MessageEmbed, MessageButton, MessageActionRow } = require("discord.js"); /** - * @param message Discord Message - * @param options Array of Options + * @param {require("discord.js").Message} message + * @param {Array} options */ /** slash => Boolean @@ -23,7 +23,6 @@ const Discord = require("discord.js"); idleEmoji => (Emoji ID) String */ - async function tictactoe(message, options = []) { // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve) => { @@ -73,7 +72,7 @@ async function tictactoe(message, options = []) { const foot = options.embedFoot ? { text: options.embedFoot } : { text: "Удачи =)" }; - const acceptEmbed = new Discord.MessageEmbed() + const acceptEmbed = new MessageEmbed() .setTitle(message.translate("economy/tictactoe:REQUEST_WAIT", { user: opponent.tag })) @@ -85,17 +84,17 @@ async function tictactoe(message, options = []) { .setFooter(foot) .setTimestamp(); - const accept = new Discord.MessageButton() + const accept = new MessageButton() .setLabel(message.translate("economy/tictactoe:ACCEPT")) .setStyle("SUCCESS") .setCustomId("acceptttt"); - const decline = new Discord.MessageButton() + const decline = new MessageButton() .setLabel(message.translate("economy/tictactoe:DECLINE")) .setStyle("DANGER") .setCustomId("declinettt"); - const accep = new Discord.MessageActionRow().addComponents([ + const accep = new MessageActionRow().addComponents([ accept, decline ]); @@ -199,7 +198,7 @@ async function tictactoe(message, options = []) { }; const { MessageActionRow, MessageButton } = require("discord.js"); - const epm = new Discord.MessageEmbed() + const epm = new MessageEmbed() .setTitle(message.translate("economy/tictactoe:DESCRIPTION")) .setColor(options.embedColor || "#075FFF") .setFooter(foot) @@ -845,7 +844,7 @@ async function tictactoe(message, options = []) { collector.on("end", (collected, reason) => { if (reason == "time") { - const embed = new Discord.MessageEmbed() + const embed = new MessageEmbed() .setTitle(message.translate("economy/tictactoe:NO_ANSWER_TITLE")) .setAuthor({ name: (message.user ? message.user : message.author).tag, @@ -864,7 +863,7 @@ async function tictactoe(message, options = []) { }); } if (reason == "decline") { - const embed = new Discord.MessageEmbed() + const embed = new MessageEmbed() .setTitle(message.translate("economy/tictactoe:CANCELED")) .setAuthor({ name: (message.user ? message.user : message.author).tag, diff --git a/index.js b/index.js index f5aadc0c..13873d65 100644 --- a/index.js +++ b/index.js @@ -9,8 +9,10 @@ const client = new JaBa({ }); (async () => { + client.translations = await require("./helpers/languages")(); + await client.loadEvents("../events"); - await client.loadCommands("../commands", client.config.support.enabled ? client.config.support.id : ""); + await client.loadCommands("../commands", client.config.support.production ? "" : client.config.support.id); await client.init(); })(); diff --git a/languages/en-US/general/invite.json b/languages/en-US/general/invite.json index 1573418a..e80f8c25 100644 --- a/languages/en-US/general/invite.json +++ b/languages/en-US/general/invite.json @@ -6,6 +6,5 @@ "CLICK": "[**Click**]({{link}})", "TIP": "Send `invite copy` to be able to copy the invite link!", "ADD": "Invite JaBa", - "VOTE": "Vote for JaBa", "SUPPORT": "Support developer" } \ No newline at end of file diff --git a/languages/en-US/general/suggest.json b/languages/en-US/general/suggest.json index 0742f2ab..61d512e2 100644 --- a/languages/en-US/general/suggest.json +++ b/languages/en-US/general/suggest.json @@ -4,6 +4,5 @@ "EXAMPLES": "suggest New channel #offtopic please", "MISSING_CHANNEL": "No suggestion channel defined!", "MISSING_CONTENT": "Please enter a suggestion!", - "TITLE": "Suggestion - {{user}}", - "SUCCESS": "Your suggestion is being voted in {{channel}}!" + "TITLE": "Suggestion - {{user}}" } \ No newline at end of file diff --git a/languages/en-US/general/userinfo.json b/languages/en-US/general/userinfo.json index f25efba5..561cf3cf 100644 --- a/languages/en-US/general/userinfo.json +++ b/languages/en-US/general/userinfo.json @@ -6,6 +6,5 @@ "NO_GAME": "Not playing", "NO_ROLE": "No role", "NO_NICKNAME": "No nickname", - "MORE_ROLES": "and {{count}} others roles", - "BOT_STATS": "**{{votes}}** votes ([top.gg](https://top.gg))\n**{{servers}}** servers\n**{{shards}}** shards\nUsing **{{lib}}**" + "MORE_ROLES": "and {{count}} others roles" } \ No newline at end of file diff --git a/languages/en-US/misc.json b/languages/en-US/misc.json index 77be4bc5..7b83904b 100644 --- a/languages/en-US/misc.json +++ b/languages/en-US/misc.json @@ -14,8 +14,6 @@ "NO_PERMS": "You must have an administration rights to perform this action!", "NO_REASON_PROVIDED": "No reason provided", "NO_USER_FOUND_ID": "No user on Discord has the ID `{{id}}`!", - "VOTE_DM": "⬆️ Hello {{user}}, thanks for voting!\nHere's your reward: 40 credits (on the support server)!", - "VOTE_LOGS": "⬆️ **{{usertag}}** (`{{userid}}`) voted for **JaBa** and won **40** credits, thank you!\n", "HELLO_SERVER": "Hello **{{username}}**, my prefix on this server is ``. Use `help` to get the list of the commands!", "HELLO_DM": "Hello, as you are currently in direct message you don't need to add a prefix before command name.", "GUILD_ONLY": "This command is only available on a server!", diff --git a/languages/en-US/music/stop.json b/languages/en-US/music/stop.json index a8d04d6d..e3bfeb3b 100644 --- a/languages/en-US/music/stop.json +++ b/languages/en-US/music/stop.json @@ -2,6 +2,5 @@ "DESCRIPTION": "Stop the music", "USAGE": "stop", "EXAMPLES": "stop", - "VOTE_CONTENT": "React with 👍 to stop the music! {{requiredCount}} more votes are required.", "SUCCESS": "Music stopped!" } \ No newline at end of file diff --git a/languages/ru-RU/general/invite.json b/languages/ru-RU/general/invite.json index f5371766..135c88c2 100644 --- a/languages/ru-RU/general/invite.json +++ b/languages/ru-RU/general/invite.json @@ -6,6 +6,5 @@ "CLICK": "[**Тык**]({{link}})", "TIP": "Отправьте `invite copy`, чтобы получить ссылку для копирования!", "ADD": "Пригласить JaBa", - "VOTE": "Проголосовать за JaBa", "SUPPORT": "Поддержать разработчика" } \ No newline at end of file diff --git a/languages/ru-RU/general/userinfo.json b/languages/ru-RU/general/userinfo.json index 018f8bcf..078a0986 100644 --- a/languages/ru-RU/general/userinfo.json +++ b/languages/ru-RU/general/userinfo.json @@ -7,6 +7,5 @@ "NO_ROLE": "Нет роли", "ROLE": "Высшая роль", "NO_NICKNAME": "Нет никнейма", - "MORE_ROLES": "и ещё {{count}} роль(и/ей)", - "BOT_STATS": "**{{votes}}** голосов ([top.gg](https://top.gg))\n**{{servers}}** серверов\n**{{shards}}** шардов\nИспользует **{{lib}}**" + "MORE_ROLES": "и ещё {{count}} роль(и/ей)" } \ No newline at end of file diff --git a/languages/ru-RU/misc.json b/languages/ru-RU/misc.json index 4a249aae..60f9138c 100644 --- a/languages/ru-RU/misc.json +++ b/languages/ru-RU/misc.json @@ -15,8 +15,6 @@ "NO_PERMS": "Недостаточно прав для выполнения данного действия!", "NO_REASON_PROVIDED": "Причина не указана", "NO_USER_FOUND_ID": "Пользователя с ID `{{id}}` не существует!", - "VOTE_DM": "⬆️ Привет, {{user}}, спасибо за голос!\nТвоя награда - 50 кредитов (на сервере поддержки)!", - "VOTE_LOGS": "⬆️ **{{usertag}}** (`{{userid}}`) проголосовал за **JaBa** и получил **50** кредитов, спасибо!\n", "HELLO_SERVER": "Привет, **{{username}}**! Все мои команды доступны через **/** Используйте `/help`, чтобы получить список команд!", "GUILD_ONLY": "Данную команду можно использовать только на сервере!", "MISSING_BOT_PERMS": "Мне необходимы следующие права для выполнения данной команды: {{list}}", diff --git a/languages/uk-UA/general/invite.json b/languages/uk-UA/general/invite.json index 135550af..64299f20 100644 --- a/languages/uk-UA/general/invite.json +++ b/languages/uk-UA/general/invite.json @@ -6,6 +6,5 @@ "CLICK": "[**Тик**]({{link}})", "TIP": "Відправте `invite copy`, щоб отримати посилання для копіювання!", "ADD": "Запросити JaBa", - "VOTE": "Проголосувати за JaBa", "SUPPORT": "Підтримати розробника" } \ No newline at end of file diff --git a/languages/uk-UA/general/userinfo.json b/languages/uk-UA/general/userinfo.json index 2206b62f..af802dde 100644 --- a/languages/uk-UA/general/userinfo.json +++ b/languages/uk-UA/general/userinfo.json @@ -7,6 +7,5 @@ "NO_ROLE": "Немає ролі", "ROLE": "Вища роль", "NO_NICKNAME": "Немає нікнейму", - "MORE_ROLES": "і ще {{count}} роль(і/ей)", - "BOT_STATS": "**{{votes}}** голосів ([top.gg](https://top.gg))\n**{{servers}}** серверів\n**{{shards }}** шардів\nВикористовує **{{lib}}**" + "MORE_ROLES": "і ще {{count}} роль(і/ей)" } \ No newline at end of file diff --git a/languages/uk-UA/misc.json b/languages/uk-UA/misc.json index 5b92dd92..e4194d45 100644 --- a/languages/uk-UA/misc.json +++ b/languages/uk-UA/misc.json @@ -15,8 +15,6 @@ "NO_PERMS": "Недостатньо прав для виконання цієї дії!", "NO_REASON_PROVIDED": "Причина не вказана", "NO_USER_FOUND_ID": "Користувача з ID `{{id}}` не існує!", - "VOTE_DM": "⬆️ Привіт, {{user}}, дякую за голос!\nТвоя нагорода - 50 кредитів (на сервері підтримки)!", - "VOTE_LOGS": "⬆️ **{{usertag}}** (`{{userid}}`) проголосував за **JaBa** і отримав **50** кредитів, дякую!\n", "HELLO_SERVER": "Привіт, **{{username}}**, мій префікс на даному сервері - ``. Використовуйте `help`, щоб отримати список команд!", "HELLO_DM": "Привіт, тому що ви пишете в ОП, вам не потрібно використовувати префікс.", "GUILD_ONLY": "Цю команду можна використовувати лише на сервері!", diff --git a/scripts/verify-config.js b/scripts/verify-config.js index 4cc801cf..ea6c39c6 100644 --- a/scripts/verify-config.js +++ b/scripts/verify-config.js @@ -1,11 +1,11 @@ /* eslint-disable no-async-promise-executor */ -const config = require("../config"); -const fetch = require("node-fetch"); - -const chalk = require("chalk"); -const success = (message) => console.log(` ${chalk.green("✓")} ${message}`); -const error = (message, howToFix) => console.log(` ${chalk.red("✗")} ${message}${howToFix ? ` : ${howToFix}` : ""}`); -const ignore = (message) => console.log(` ${chalk.yellow("~")} ${message}`); +const { Intents } = require("discord.js"), + config = require("../config"), + fetch = require("node-fetch"), + chalk = require("chalk"), + success = (message) => console.log(` ${chalk.green("✓")} ${message}`), + error = (message, howToFix) => console.log(` ${chalk.red("✗")} ${message}${howToFix ? ` : ${howToFix}` : ""}`), + ignore = (message) => console.log(` ${chalk.yellow("~")} ${message}`); const checks = [ () => { @@ -23,7 +23,7 @@ const checks = [ console.log("\n\nDiscord Bot"); return new Promise((res) => { const Discord = require("discord.js"); - const client = new Discord.Client(); + const client = new Discord.Client({ intents: Object.keys(Intents.FLAGS) }); let readyResolve; new Promise((resolve) => readyResolve = resolve); client.login(config.token).then(async () => { @@ -55,7 +55,7 @@ const checks = [ success("Connection to Mongo database success"); res(); }).catch(() => { - error("Should be able to connect to Mongo database", "please verify if the MongoDB server is started"); + error("Not able to connect to Mongo database", "please verify if the MongoDB server is started"); res(); }); }); @@ -64,7 +64,7 @@ const checks = [ console.log("\n\nAPI keys"); return new Promise(async (resolve) => { if (!config.apiKeys.amethyste) { - ignore("Amethyste API is not configured, key should not be checked."); + ignore("Amethyste API is not configured, skipping check."); } else { const res = await fetch("https://v1.api.amethyste.moe/generate/blurple", { method: "POST", @@ -74,13 +74,13 @@ const checks = [ }); const result = await res.json(); if (result.status === 401) { - error("Should be a valid Amethyste API key", "get your key here: https://api.amethyste.moe/"); + error("Not valid Amethyste API key", "get your key here: https://api.amethyste.moe/"); } else { success("Valid Amethyste API key"); } } if (!config.apiKeys.blagueXYZ) { - ignore("blague.xyz API is not configured, key should not be checked."); + ignore("blague.xyz API is not configured, skipping check."); } else { const res = await fetch("https://blague.xyz/api/joke/random", { headers: { @@ -89,27 +89,11 @@ const checks = [ }); const result = await res.json(); if (result.status === 401) { - error("Should be a valid blague.xyz key", "get your key here: https://blague.xyz/"); + error("Not valid blague.xyz key", "get your key here: https://blague.xyz/"); } else { success("Valid blague.xyz key"); } } - if (!config.apiKeys.dbl) { - ignore("DBL API is not configured, key should not be checked."); - } else { - const res = await fetch("https://top.gg/api/bots/check?userId=test", { - method: "POST", - headers: { - Authorization: config.apiKeys.dbl - } - }); - const result = await res.json(); - if (result.error && result.error === "Unauthorized") { - error("Should be a valid DBL key", "get your key here: https://top.gg/ OR delete the key from the config if you don't have a key"); - } else { - success("Valid DBL key"); - } - } resolve(); }); }, @@ -117,7 +101,7 @@ const checks = [ console.log("\n\nDashboard"); return new Promise(async (resolve) => { if (!config.dashboard.enabled) { - ignore("Dashboard is not enabled, config shouldn't be checked."); + ignore("Dashboard is not enabled, skipping check."); } else { const checkPortTaken = (port) => { return new Promise((resolve) => { @@ -138,7 +122,7 @@ const checks = [ }; const isPortTaken = await checkPortTaken(config.dashboard.port); if (isPortTaken) { - error("Dashboard port should be available", "you have probably another process using this port"); + error("Dashboard port not available", "you have probably another process using this port"); } else { success("Dashboard port is available"); }