Compare commits

..

5 commits

300 changed files with 14566 additions and 2588 deletions

4
.gitmodules vendored
View file

@ -1,4 +0,0 @@
[submodule "dashboard/dashboard-core"]
path = dashboard/dashboard-core
url = https://git.jonnybro.ru/jonny_bro/dashboard-core
branch = main

3
.prettierignore Normal file
View file

@ -0,0 +1,3 @@
/dist
/coverage
/node_modules

View file

@ -64,7 +64,6 @@ If you want to contribute, feel free to fork this repo and making a pull request
## TODO
* [ ] Refactor [tictactoe](./helpers/tictactoe.js).
* [ ] Finish and release *dashboard-core* submodule.
## License

View file

@ -1,9 +1,7 @@
const { Client, Collection, SlashCommandBuilder, ContextMenuCommandBuilder, EmbedBuilder, PermissionsBitField, ChannelType } = require("discord.js"),
{ GiveawaysManager } = require("discord-giveaways"),
{ REST } = require("@discordjs/rest"),
{ Player: DiscordPlayer } = require("discord-player"),
{ SpotifyExtractor } = require("@discord-player/extractor"),
{ YoutubeiExtractor } = require("discord-player-youtubei"),
{ Player } = require("discord-player"),
{ Routes } = require("discord-api-types/v10");
const BaseEvent = require("./BaseEvent.js"),
@ -33,32 +31,23 @@ class JaBaClient extends Client {
this.databaseCache.guilds = new Collection();
this.databaseCache.members = new Collection();
this.databaseCache.usersReminds = new Collection();
}
/**
* Initializes the client by logging in with the provided token and connecting to the MongoDB database.
*
* This method is called during the client's startup process to set up the necessary connections and resources.
*
* @returns {Promise<void>} A Promise that resolves when the client is fully initialized.
*/
async init() {
this.player = new DiscordPlayer(this);
await this.player.extractors.register(YoutubeiExtractor, {
authentication: this.config.youtubeCookie,
streamOptions: {
useClient: "YTMUSIC_ANDROID",
this.player = new Player(this, {
ytdlOptions: {
requestOptions: {
headers: {
cookie: this.config.youtubeCookie,
},
},
},
});
await this.player.extractors.register(SpotifyExtractor, {
clientId: this.config.spotify.clientId,
clientSecret: this.config.spotify.clientSecret,
this.player.extractors.loadDefault(null, {
SpotifyExtractor: {
clientId: this.config.spotify.clientId,
clientSecret: this.config.spotify.clientSecret,
},
});
await this.player.extractors.loadDefault(ext => !["YouTubeExtractor", "SpotifyExtractor"].includes(ext));
this.player.events.on("playerStart", async (queue, track) => {
const m = (
await queue.metadata.channel.send({
@ -99,24 +88,37 @@ class JaBaClient extends Client {
reaction: "🎉",
},
});
}
/**
* Initializes the client by logging in with the provided token and connecting to the MongoDB database.
*
* This method is called during the client's startup process to set up the necessary connections and resources.
*
* @returns {Promise<void>} A Promise that resolves when the client is fully initialized.
*/
async init() {
this.login(this.config.token);
mongoose
.connect(this.config.mongoDB)
.then(() => {
this.logger.log("Connected to the MongoDB database.");
this.logger.log("Connected to the Mongodb database.");
})
.catch(e => {
this.logger.error(`Unable to connect to the MongoDB database.\nError: ${e.message}\n${e.stack}`);
.catch(err => {
this.logger.error(`Unable to connect to the Mongodb database.\nError: ${err}`);
});
this.login(this.config.token);
// const autoUpdateDocs = require("../helpers/autoUpdateDocs");
// autoUpdateDocs.update(this);
}
/**
* Loads all the commands from the specified directory and registers them with the Discord API.
*
* This method dynamically loads all command files from the specified directory,
* creates instances of the corresponding command classes, and registers them with the Discord API.
* This method is responsible for dynamically loading all the command files from the specified directory,
* creating instances of the corresponding command classes, and registering the commands with the Discord API.
* It also handles any additional setup or initialization required by the loaded commands.
*
* @param {string} dir - The directory path where the command files are located.
* @returns {Promise<void>} A Promise that resolves when all the commands have been loaded and registered.
@ -124,119 +126,43 @@ class JaBaClient extends Client {
async loadCommands(dir) {
const rest = new REST().setToken(this.config.token),
filePath = path.join(__dirname, dir),
folders = (await fs.readdir(filePath)).map(file => path.join(filePath, file));
folders = (await fs.readdir(filePath)).map(file => path.join(filePath, file)).filter(async path => (await fs.lstat(path)).isDirectory());
const commands = [];
for (const folder of folders) {
for (let index = 0; index < folders.length; index++) {
const folder = folders[index];
if (folder.endsWith("!DISABLED")) continue;
const files = await fs.readdir(folder);
for (const file of files) {
if (!file.endsWith(".js")) continue;
for (let index = 0; index < files.length; index++) {
const file = files[index];
const Command = require(path.join(folder, file));
if (file.endsWith(".js")) {
const Command = require(path.join(folder, file));
if (!(Command.prototype instanceof BaseCommand)) continue;
if (Command.prototype instanceof BaseCommand) {
const command = new Command(this);
this.commands.set(command.command.name, command);
const command = new Command(this);
this.commands.set(command.command.name, command);
if (command.onLoad && typeof command.onLoad === "function") await command.onLoad(this);
if (typeof command.onLoad === "function") await command.onLoad(this);
commands.push(command.command instanceof SlashCommandBuilder || command.command instanceof ContextMenuCommandBuilder ? command.command.toJSON() : command.command);
commands.push(command.command instanceof SlashCommandBuilder || command.command instanceof ContextMenuCommandBuilder ? command.command.toJSON() : command.command);
this.logger.log(`Successfully loaded "${file}" command. (Command: ${command.command.name})`);
this.logger.log(`Successfully loaded "${file}" command file. (Command: ${command.command.name})`);
}
}
}
}
try {
const route = this.config.production ? Routes.applicationCommands(this.config.userId) : Routes.applicationGuildCommands(this.config.userId, this.config.support.id);
await rest.put(route, { body: commands });
if (this.config.production) await rest.put(Routes.applicationCommands(this.config.userId), { body: commands });
else await rest.put(Routes.applicationGuildCommands(this.config.userId, this.config.support.id), { body: commands });
this.logger.log("Successfully registered application commands.");
} catch (err) {
this.logger.error("Error registering application commands:", err);
}
}
/**
* Loads a command from the specified directory and file.
* @param {string} dir - The directory containing the command file.
* @param {string} file - The name of the command file (without the .js extension).
* @returns {Promise<void>} This method does not return a value.
*/
async loadCommand(dir, file) {
try {
const Command = require(path.join(dir, `${file}.js`));
if (!(Command.prototype instanceof BaseCommand)) {
return this.logger.error(`Tried to load a non-command file: "${file}.js"`);
}
const command = new Command(this);
this.commands.set(command.command.name, command);
if (typeof command.onLoad === "function") await command.onLoad(this);
this.logger.log(`Successfully loaded "${file}" command file. (Command: ${command.command.name})`);
} catch (error) {
this.logger.error(`Error loading command "${file}":`, error);
}
}
/**
* Unloads a command from the specified directory and file.
* @param {string} dir - The directory containing the command file.
* @param {string} name - The name of the command file (without the .js extension).
* @returns {void} This method does not return a value.
*/
unloadCommand(dir, name) {
delete require.cache[require.resolve(`${dir}${path.sep}${name}.js`)];
return;
}
/**
* Loads all event files from the specified directory and its subdirectories.
* @param {string} dir - The directory containing the event files.
* @returns {Promise<void>} This method does not return a value.
*/
async loadEvents(dir) {
const filePath = path.join(__dirname, dir);
const files = await fs.readdir(filePath);
for (const file of files) {
const fullPath = path.join(filePath, file);
const stat = await fs.lstat(fullPath);
if (stat.isDirectory()) {
await this.loadEvents(path.join(dir, file));
continue;
}
if (file.endsWith(".js")) {
try {
const Event = require(fullPath);
if (!(Event.prototype instanceof BaseEvent)) {
this.logger.error(`"${file}" is not a valid event file.`);
continue;
}
const event = new Event();
if (!event.name || !event.name.length) {
this.logger.error(`Cannot load "${file}" event: Event name is missing!`);
continue;
}
event.once ? this.once(event.name, event.execute.bind(event, this)) : this.on(event.name, event.execute.bind(event, this));
this.logger.log(`Successfully loaded "${file}" event. (Event: ${event.name})`);
} catch (error) {
this.logger.error(`Error loading event "${file}":`, error);
}
}
console.log(err);
}
}
@ -270,24 +196,37 @@ class JaBaClient extends Client {
* @param {Object[]} [data.fields] - An array of field objects for the embed.
* @param {string} [data.image] - The URL of the image for the embed.
* @param {string} [data.url] - The URL to be used as the embed's hyperlink.
* @param {string} [data.color] - The HEX color of the embed's border.
* @param {string|Object} [data.footer] - The text to be displayed as the embed's footer.
* @param {Date} [data.timestamp] - The timestamp to be displayed in the embed.
* @param {string|Object} [data.author] - The author information for the embed.
* @param {string} [data.color] - The HEX color of the embed's border. If not provided, the default color from the client's configuration will be used.
* @param {string} [data.footer] - The text to be displayed as the embed's footer. If not provided, the default footer from the client's configuration will be used.
* @param {Date} [data.timestamp] - The timestamp to be displayed in the embed's footer. If not provided, the current timestamp will be used.
* @param {string|Object} [data.author] - The author information for the embed. Can be a string (name) or an object with `name` and/or `iconURL` properties.
* @returns {EmbedBuilder} The generated EmbedBuilder instance.
*/
embed(data) {
const embed = new EmbedBuilder()
.setTitle(data.title ?? null)
.setDescription(data.description ?? null)
.setThumbnail(data.thumbnail ?? null)
.addFields(data.fields ?? [])
.setImage(data.image ?? null)
.setURL(data.url ?? null)
.setColor(data.color ?? this.config.embed.color)
.setFooter(typeof data.footer === "object" ? data.footer : data.footer ? { text: data.footer } : this.config.embed.footer)
.setTimestamp(data.timestamp ?? null)
.setAuthor(typeof data.author === "string" ? { name: data.author, iconURL: this.user.avatarURL() } : data.author ?? null);
.setTitle(data.title || null)
.setDescription(data.description || null)
.setThumbnail(data.thumbnail || null)
.addFields(data.fields || [])
.setImage(data.image || null)
.setURL(data.url || null);
if (data.color) embed.setColor(data.color);
else if (data.color === null) embed.setColor(null);
else embed.setColor(this.config.embed.color);
if (data.footer) embed.setFooter(data.footer);
else if (data.footer === null) embed.setFooter(null);
else embed.setFooter(this.config.embed.footer);
if (data.timestamp) embed.setTimestamp(data.timestamp);
else if (data.timestamp === null) embed.setTimestamp(null);
else embed.setTimestamp();
if (!data.author || data.author === null) embed.setAuthor(null);
else if (typeof data.author === "string") embed.setAuthor({ name: data.author, iconURL: this.user.avatarURL() });
else if (typeof data.author === "object" && (data.author.iconURL !== null || data.author.iconURL !== undefined)) embed.setAuthor({ name: data.author.name, iconURL: data.author.iconURL });
else embed.setAuthor(data.author);
return embed;
}
@ -305,22 +244,86 @@ class JaBaClient extends Client {
if (channel) return (await channel.createInvite()).url || "No channels found or missing permissions";
}
/**
* Loads a command from the specified directory and file.
* @param {string} dir - The directory containing the command file.
* @param {string} file - The name of the command file (without the .js extension).
* @returns {Promise<string>} A log message indicating the successful loading of the command.
*/
async loadCommand(dir, file) {
const Command = require(path.join(dir, `${file}.js`));
if (!(Command.prototype instanceof BaseCommand)) return this.logger.error("Tried to load a non-command file!");
const command = new Command(this);
this.commands.set(command.command.name, command);
if (command.onLoad && typeof command.onLoad === "function") await command.onLoad(this);
return this.logger.log(`Successfully loaded "${file}" command file. (Command: ${command.command.name})`);
}
/**
* Unloads a command from the specified directory and file.
* @param {string} dir - The directory containing the command file.
* @param {string} name - The name of the command file (without the .js extension).
* @returns {void} This method does not return a value.
*/
async unloadCommand(dir, name) {
delete require.cache[require.resolve(`${dir}${path.sep}${name}.js`)];
return;
}
/**
* Loads all event files from the specified directory and its subdirectories.
* @param {string} dir - The directory containing the event files.
* @returns {void} This method does not return a value.
*/
async loadEvents(dir) {
const filePath = path.join(__dirname, dir);
const files = await fs.readdir(filePath);
for (let index = 0; index < files.length; index++) {
const file = files[index];
const stat = await fs.lstat(path.join(filePath, file));
if (stat.isDirectory()) this.loadEvents(path.join(dir, file));
if (file.endsWith(".js")) {
const Event = require(path.join(filePath, file));
if (Event.prototype instanceof BaseEvent) {
const event = new Event();
if (!event.name || !event.name.length) return console.error(`Cannot load "${file}" event file: Event name is not set!`);
if (event.once) this.once(event.name, event.execute.bind(event, this));
else this.on(event.name, event.execute.bind(event, this));
this.logger.log(`Successfully loaded "${file}" event file. (Event: ${event.name})`);
}
}
}
}
/**
* Returns a User data from the database.
* @param {string} userID - The ID of the user to find or create.
* @returns {Promise<import("./User")>} The user data object, either retrieved from the database or newly created.
*/
*/
async getUserData(userID) {
let userData = await this.usersData.findOne({ id: userID });
if (!userData) {
if (userData) {
this.databaseCache.users.set(userID, userData);
return userData;
} else {
userData = new this.usersData({ id: userID });
await userData.save();
this.databaseCache.users.set(userID, userData);
return userData;
}
this.databaseCache.users.set(userID, userData);
return userData;
}
/**
@ -332,19 +335,27 @@ class JaBaClient extends Client {
async getMemberData(memberId, guildId) {
let memberData = await this.membersData.findOne({ guildID: guildId, id: memberId });
if (!memberData) {
if (memberData) {
this.databaseCache.members.set(`${memberId}${guildId}`, memberData);
return memberData;
} else {
memberData = new this.membersData({ id: memberId, guildID: guildId });
await memberData.save();
const guildData = await this.getGuildData(guildId);
if (guildData) {
guildData.members.push(memberData._id);
await guildData.save();
}
}
this.databaseCache.members.set(`${memberId}/${guildId}`, memberData);
return memberData;
this.databaseCache.members.set(`${memberId}/${guildId}`, memberData);
return memberData;
}
}
/**
@ -355,14 +366,19 @@ class JaBaClient extends Client {
async getGuildData(guildId) {
let guildData = await this.guildsData.findOne({ id: guildId }).populate("members");
if (!guildData) {
if (guildData) {
this.databaseCache.guilds.set(guildId, guildData);
return guildData;
} else {
guildData = new this.guildsData({ id: guildId });
await guildData.save();
this.databaseCache.guilds.set(guildId, guildData);
return guildData;
}
this.databaseCache.guilds.set(guildId, guildData);
return guildData;
}
}

73
commands/!DISABLED/ban.js Normal file
View file

@ -0,0 +1,73 @@
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Ban extends BaseCommand {
/**
*
* @param {import("../../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("ban")
.setDescription(client.translate("moderation/ban:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("moderation/ban:DESCRIPTION", null, "uk-UA"),
ru: client.translate("moderation/ban:DESCRIPTION", null, "ru-RU"),
})
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.BanMembers)
.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),
)
.addStringOption(option =>
option
.setName("reason")
.setDescription(client.translate("common:REASON"))
.setDescriptionLocalizations({
uk: client.translate("common:REASON", null, "uk-UA"),
ru: client.translate("common:REASON", null, "ru-RU"),
})
.setRequired(true),
),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply();
const member = interaction.options.getMember("user"),
reason = interaction.options.getString("reason"),
memberPosition = member.roles.highest.position,
moderationPosition = interaction.member.roles.highest.position;
if (member.user.bot) return interaction.error("misc:BOT_USER", null, { ephemeral: true, edit: true });
if (member.id === interaction.member.id) return interaction.error("moderation/ban:YOURSELF", null, { ephemeral: true, edit: true });
if (interaction.guild.ownerId !== interaction.member.id && !(moderationPosition > memberPosition) && member.bannable) return interaction.error("moderation/ban:SUPERIOR", null, { ephemeral: true, edit: true });
await member.ban({
reason,
});
interaction.success("moderation/ban:SUCCESS", {
user: member.user.toString(),
reason,
}, { edit: true });
}
}
module.exports = Ban;

View file

@ -0,0 +1,49 @@
const { SlashCommandBuilder } = require("discord.js"),
Mee6Api = require("../../helpers/mee6-api");
const BaseCommand = require("../../base/BaseCommand");
class ImportMee6 extends BaseCommand {
/**
*
* @param {import("../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("importmee6")
.setDescription(client.translate("economy/importmee6:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("economy/importmee6:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/importmee6:DESCRIPTION", null, "ru-RU"),
})
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply();
const level = (await Mee6Api.getUserXp(interaction.guildId, interaction.member)).level;
interaction.data.member.level = level;
interaction.data.member.exp = 0;
await interaction.data.member.save();
interaction.editReply({
content: interaction.translate("owner/debug:SUCCESS_LEVEL", {
user: interaction.member.toString(),
amount: level,
}),
});
}
}
module.exports = ImportMee6;

View file

@ -0,0 +1,73 @@
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Kick extends BaseCommand {
/**
*
* @param {import("../../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("kick")
.setDescription(client.translate("moderation/kick:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("moderation/kick:DESCRIPTION", null, "uk-UA"),
ru: client.translate("moderation/kick:DESCRIPTION", null, "ru-RU"),
})
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.KickMembers)
.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),
)
.addStringOption(option =>
option
.setName("reason")
.setDescription(client.translate("common:REASON"))
.setDescriptionLocalizations({
uk: client.translate("common:REASON", null, "uk-UA"),
ru: client.translate("common:REASON", null, "ru-RU"),
})
.setRequired(true),
),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply();
const member = interaction.options.getMember("user"),
reason = interaction.options.getString("reason"),
memberPosition = member.roles.highest.position,
moderationPosition = interaction.member.roles.highest.position;
if (member.user.bot) return interaction.error("misc:BOT_USER", null, { ephemeral: true, edit: true });
if (member.id === interaction.member.id) return interaction.error("moderation/kick:YOURSELF", null, { ephemeral: true, edit: true });
if (interaction.guild.ownerId !== interaction.member.id && !(moderationPosition > memberPosition) && member.kickable) return interaction.error("moderation/kick:SUPERIOR", null, { ephemeral: true, edit: true });
await member.kick({
reason,
});
interaction.success("moderation/kick:SUCCESS", {
user: member.user.toString(),
reason,
}, { edit: true });
}
}
module.exports = Kick;

View file

@ -0,0 +1,79 @@
const { SlashCommandBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
fetch = require("node-fetch");
class Memes extends BaseCommand {
/**
*
* @param {import("../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("memes")
.setDescription(client.translate("fun/memes:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("fun/memes:DESCRIPTION", null, "uk-UA"),
ru: client.translate("fun/memes:DESCRIPTION", null, "ru-RU"),
})
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
*/
async onLoad(client) {
client.on("interactionCreate", async interaction => {
if (!interaction.isStringSelectMenu()) return;
if (interaction.customId === "memes_select") {
interaction.deferUpdate();
interaction.guild.data = await client.getGuildData(interaction.guildId);
const tag = interaction.values[0];
const res = await fetch(`https://meme-api.com/gimme/${tag}`).then(response => response.json());
const embed = client.embed({
title: res.title,
description: `${interaction.translate("fun/memes:SUBREDDIT")}: **${res.subreddit}**\n${interaction.translate("common:AUTHOR")}: **${res.author}**\n${interaction.translate("fun/memes:UPS")}: **${res.ups}**`,
image: res.url,
});
await interaction.editReply({
embeds: [embed],
});
}
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: true });
const tags = ["funny", "memes", "dankmemes", "me_irl", "wholesomememes"].map(tag =>
JSON.parse(
JSON.stringify({
label: tag,
value: tag,
}),
),
);
const row = new ActionRowBuilder().addComponents(new StringSelectMenuBuilder().setCustomId("memes_select").setPlaceholder(interaction.translate("common:NOTHING_SELECTED")).addOptions(tags));
await interaction.editReply({
components: [row],
});
}
}
module.exports = Memes;

View file

@ -0,0 +1,63 @@
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Staff extends BaseCommand {
/**
*
* @param {import("../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("staff")
.setDescription(client.translate("general/staff:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("general/staff:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/staff:DESCRIPTION", null, "ru-RU"),
})
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.guild.members.fetch();
const administrators = interaction.guild.members.cache.filter(m => m.permissions.has(PermissionsBitField.Flags.Administrator) && !m.user.bot);
const moderators = interaction.guild.members.cache.filter(m => !administrators.has(m.id) && m.permissions.has(PermissionsBitField.Flags.ManageMessages) && !m.user.bot);
const embed = client.embed({
author: {
name: interaction.translate("general/staff:TITLE", {
guild: interaction.guild.name,
}),
iconURL: interaction.guild.iconURL(),
},
fields: [
{
name: interaction.translate("general/staff:ADMINS"),
value:
administrators.size > 0
? administrators.map(a => `${a.presence ? client.customEmojis.status[a.presence.status] : client.customEmojis.status.offline} | <@${a.user.id}>`).join("\n")
: interaction.translate("general/staff:NO_ADMINS"),
},
{
name: interaction.translate("general/staff:MODS"),
value: moderators.size > 0 ? moderators.map(m => `${m.presence ? client.customEmojis.status[m.presence.status] : client.customEmojis.status.offline} | <@${m.user.id}>`).join("\n") : interaction.translate("general/staff:NO_MODS"),
},
],
});
interaction.reply({
embeds: [embed],
});
}
}
module.exports = Staff;

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Addemoji extends BaseCommand {
@ -15,8 +15,7 @@ class Addemoji extends BaseCommand {
uk: client.translate("administration/addemoji:DESCRIPTION", null, "uk-UA"),
ru: client.translate("administration/addemoji:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageGuild)
.addStringOption(option =>
option
@ -59,7 +58,7 @@ class Addemoji extends BaseCommand {
})
.then(emoji =>
interaction.success("administration/stealemoji:SUCCESS", {
emoji: emoji.toString(),
emoji: emoji.name,
}, { ephemeral: true }),
)
.catch(e => {

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, ChannelType, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField, ChannelType } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Automod extends BaseCommand {
@ -15,8 +15,7 @@ class Automod extends BaseCommand {
uk: client.translate("administration/automod:DESCRIPTION", null, "uk-UA"),
ru: client.translate("administration/automod:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageGuild)
.addSubcommand(subcommand =>
subcommand

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Autorole extends BaseCommand {
@ -15,8 +15,7 @@ class Autorole extends BaseCommand {
uk: client.translate("administration/autorole:DESCRIPTION", null, "uk-UA"),
ru: client.translate("administration/autorole:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageGuild)
.addBooleanOption(option =>
option

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, ChannelType, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField, ChannelType } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Config extends BaseCommand {
@ -15,8 +15,7 @@ class Config extends BaseCommand {
uk: client.translate("administration/config:DESCRIPTION", null, "uk-UA"),
ru: client.translate("administration/config:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageGuild)
.addSubcommand(subcommand =>
subcommand

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Goodbye extends BaseCommand {
@ -15,8 +15,7 @@ class Goodbye extends BaseCommand {
uk: client.translate("administration/goodbye:DESCRIPTION", null, "uk-UA"),
ru: client.translate("administration/goodbye:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageGuild)
.addSubcommand(subcommand =>
subcommand
@ -27,43 +26,42 @@ class Goodbye extends BaseCommand {
ru: client.translate("administration/goodbye:TEST", null, "ru-RU"),
}),
)
.addSubcommand(
subcommand =>
subcommand
.setName("config")
.setDescription(client.translate("administration/goodbye:CONFIG"))
.setDescriptionLocalizations({
uk: client.translate("administration/goodbye:CONFIG", null, "uk-UA"),
ru: client.translate("administration/goodbye:CONFIG", null, "ru-RU"),
})
.addBooleanOption(option =>
option
.setName("state")
.setDescription(client.translate("common:STATE"))
.setDescriptionLocalizations({
uk: client.translate("common:STATE", null, "uk-UA"),
ru: client.translate("common:STATE", null, "ru-RU"),
})
.setRequired(true),
)
.addChannelOption(option =>
option
.setName("channel")
.setDescription(client.translate("common:CHANNEL"))
.setDescriptionLocalizations({
uk: client.translate("common:CHANNEL", null, "uk-UA"),
ru: client.translate("common:CHANNEL", null, "ru-RU"),
}),
)
.addStringOption(option =>
option
.setName("message")
.setDescription(client.translate("administration/goodbye:MESSAGE"))
.setDescriptionLocalizations({
uk: client.translate("administration/goodbye:MESSAGE", null, "uk-UA"),
ru: client.translate("administration/goodbye:MESSAGE", null, "ru-RU"),
}),
),
.addSubcommand(subcommand =>
subcommand
.setName("config")
.setDescription(client.translate("administration/goodbye:CONFIG"))
.setDescriptionLocalizations({
uk: client.translate("administration/goodbye:CONFIG", null, "uk-UA"),
ru: client.translate("administration/goodbye:CONFIG", null, "ru-RU"),
})
.addBooleanOption(option =>
option
.setName("state")
.setDescription(client.translate("common:STATE"))
.setDescriptionLocalizations({
uk: client.translate("common:STATE", null, "uk-UA"),
ru: client.translate("common:STATE", null, "ru-RU"),
})
.setRequired(true),
)
.addChannelOption(option =>
option
.setName("channel")
.setDescription(client.translate("common:CHANNEL"))
.setDescriptionLocalizations({
uk: client.translate("common:CHANNEL", null, "uk-UA"),
ru: client.translate("common:CHANNEL", null, "ru-RU"),
}),
)
.addStringOption(option =>
option
.setName("message")
.setDescription(client.translate("administration/goodbye:MESSAGE"))
.setDescriptionLocalizations({
uk: client.translate("administration/goodbye:MESSAGE", null, "uk-UA"),
ru: client.translate("administration/goodbye:MESSAGE", null, "ru-RU"),
}),
),
// .addBooleanOption(option =>
// option
// .setName("image")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, ActionRowBuilder, StringSelectMenuBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField, ActionRowBuilder, StringSelectMenuBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Selectroles extends BaseCommand {
@ -15,8 +15,7 @@ class Selectroles extends BaseCommand {
uk: client.translate("administration/selectroles:DESCRIPTION", null, "uk-UA"),
ru: client.translate("administration/selectroles:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageGuild)
.addSubcommand(subcommand =>
subcommand

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Set extends BaseCommand {
@ -15,8 +15,7 @@ class Set extends BaseCommand {
uk: client.translate("administration/set:DESCRIPTION", null, "uk-UA"),
ru: client.translate("administration/set:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageGuild)
.addStringOption(option =>
option

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Setlang extends BaseCommand {
@ -15,8 +15,7 @@ class Setlang extends BaseCommand {
uk: client.translate("administration/setlang:DESCRIPTION", null, "uk-UA"),
ru: client.translate("administration/setlang:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageGuild)
.addStringOption(option =>
option

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, parseEmoji, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, parseEmoji, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Stealemoji extends BaseCommand {
@ -15,8 +15,7 @@ class Stealemoji extends BaseCommand {
uk: client.translate("administration/stealemoji:DESCRIPTION", null, "uk-UA"),
ru: client.translate("administration/stealemoji:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageGuild)
.addStringOption(option =>
option
@ -48,7 +47,7 @@ class Stealemoji extends BaseCommand {
})
.then(emoji =>
interaction.success("administration/stealemoji:SUCCESS", {
emoji: emoji.toString(),
emoji: emoji.name,
}, { ephemeral: true }),
)
.catch(e => {

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Welcome extends BaseCommand {
@ -15,8 +15,7 @@ class Welcome extends BaseCommand {
uk: client.translate("administration/welcome:DESCRIPTION", null, "uk-UA"),
ru: client.translate("administration/welcome:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageGuild)
.addSubcommand(subcommand =>
subcommand
@ -27,43 +26,42 @@ class Welcome extends BaseCommand {
ru: client.translate("administration/goodbye:TEST", null, "ru-RU"),
}),
)
.addSubcommand(
subcommand =>
subcommand
.setName("config")
.setDescription(client.translate("administration/goodbye:CONFIG"))
.setDescriptionLocalizations({
uk: client.translate("administration/goodbye:CONFIG", null, "uk-UA"),
ru: client.translate("administration/goodbye:CONFIG", null, "ru-RU"),
})
.addBooleanOption(option =>
option
.setName("state")
.setDescription(client.translate("common:STATE"))
.setDescriptionLocalizations({
uk: client.translate("common:STATE", null, "uk-UA"),
ru: client.translate("common:STATE", null, "ru-RU"),
})
.setRequired(true),
)
.addChannelOption(option =>
option
.setName("channel")
.setDescription(client.translate("common:CHANNEL"))
.setDescriptionLocalizations({
uk: client.translate("common:CHANNEL", null, "uk-UA"),
ru: client.translate("common:CHANNEL", null, "ru-RU"),
}),
)
.addStringOption(option =>
option
.setName("message")
.setDescription(client.translate("administration/goodbye:MESSAGE"))
.setDescriptionLocalizations({
uk: client.translate("administration/goodbye:MESSAGE", null, "uk-UA"),
ru: client.translate("administration/goodbye:MESSAGE", null, "ru-RU"),
}),
),
.addSubcommand(subcommand =>
subcommand
.setName("config")
.setDescription(client.translate("administration/goodbye:CONFIG"))
.setDescriptionLocalizations({
uk: client.translate("administration/goodbye:CONFIG", null, "uk-UA"),
ru: client.translate("administration/goodbye:CONFIG", null, "ru-RU"),
})
.addBooleanOption(option =>
option
.setName("state")
.setDescription(client.translate("common:STATE"))
.setDescriptionLocalizations({
uk: client.translate("common:STATE", null, "uk-UA"),
ru: client.translate("common:STATE", null, "ru-RU"),
})
.setRequired(true),
)
.addChannelOption(option =>
option
.setName("channel")
.setDescription(client.translate("common:CHANNEL"))
.setDescriptionLocalizations({
uk: client.translate("common:CHANNEL", null, "uk-UA"),
ru: client.translate("common:CHANNEL", null, "ru-RU"),
}),
)
.addStringOption(option =>
option
.setName("message")
.setDescription(client.translate("administration/goodbye:MESSAGE"))
.setDescriptionLocalizations({
uk: client.translate("administration/goodbye:MESSAGE", null, "uk-UA"),
ru: client.translate("administration/goodbye:MESSAGE", null, "ru-RU"),
}),
),
// .addBooleanOption(option =>
// option
// .setName("image")

View file

@ -1,100 +0,0 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
fetch = require("node-fetch");
class Courses extends BaseCommand {
/**
*
* @param {import("../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("courses")
.setDescription(client.translate("beatrun/courses:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("beatrun/courses:DESCRIPTION", null, "uk-UA"),
ru: client.translate("beatrun/courses:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.Guild, InteractionContextType.BotDM, InteractionContextType.PrivateChannel])
.addStringOption(option =>
option
.setName("code")
.setDescription(client.translate("common:CODE"))
.setDescriptionLocalizations({
uk: client.translate("common:CODE", null, "uk-UA"),
ru: client.translate("common:CODE", null, "ru-RU"),
})
.setRequired(true),
)
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
* @param {Object} data
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
const code = interaction.options.getString("code");
const response = await fetch(`https://courses.jonnybro.ru/api/info/${code}`).then(res => res.json()),
{ data } = response;
if (response.res === 401) return interaction.error("beatrun/courses:NOT_FOUND", null, { ephemeral: true, edit: true });
const embed = client.embed({
title: data.name,
description: `[${interaction.translate("beatrun/courses:DOWNLOAD")}](https://courses.jonnybro.ru/${data.path})`,
thumbnail: data.mapimg,
url: `https://courses.jonnybro.ru/?search=${code}`,
fields: [
{
name: interaction.translate("beatrun/courses:MAP"),
value: `[${data.map}](https://steamcommunity.com/sharedfiles/filedetails/?id=${data.mapid})`,
inline: true,
},
{
name: interaction.translate("beatrun/courses:UPLOADER"),
value: `[${data.uploader.name || data.uploader.userid}](https://steamcommunity.com/profiles/${data.uploader.userid})`,
inline: true,
},
{
name: "\u200B",
value: "\u200B",
inline: true,
},
{
name: interaction.translate("beatrun/courses:DATE"),
value: `<t:${Math.floor(data.time / 1000)}:D>`,
inline: true,
},
{
name: interaction.translate("beatrun/courses:PLAYS"),
value: `${data.plays || 0}`,
inline: true,
},
],
});
interaction.editReply({
embeds: [embed],
});
}
}
module.exports = Courses;

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Achievements extends BaseCommand {
@ -15,8 +15,7 @@ class Achievements extends BaseCommand {
uk: client.translate("economy/achievements:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/achievements:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addUserOption(option =>
option
.setName("user")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Bank extends BaseCommand {
@ -15,8 +15,7 @@ class Bank extends BaseCommand {
uk: client.translate("economy/bank:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/bank:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addStringOption(option =>
option
.setName("option")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Birthdate extends BaseCommand {
@ -15,8 +15,7 @@ class Birthdate extends BaseCommand {
uk: client.translate("economy/birthdate:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/birthdate:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.Guild, InteractionContextType.PrivateChannel])
.setDMPermission(true)
.addIntegerOption(option =>
option
.setName("day")
@ -24,7 +23,8 @@ class Birthdate extends BaseCommand {
.setDescriptionLocalizations({
uk: client.translate("economy/birthdate:DAY", null, "uk-UA"),
ru: client.translate("economy/birthdate:DAY", null, "ru-RU"),
}),
})
.setRequired(true),
)
.addIntegerOption(option =>
option
@ -34,19 +34,20 @@ class Birthdate extends BaseCommand {
uk: client.translate("economy/birthdate:MONTH", null, "uk-UA"),
ru: client.translate("economy/birthdate:MONTH", null, "ru-RU"),
})
.setRequired(true)
.setChoices(
{ name: client.translate("misc:MONTHS:JANUARY"), value: 1 },
{ name: client.translate("misc:MONTHS:FEBRUARY"), value: 2 },
{ name: client.translate("misc:MONTHS:MARCH"), value: 3 },
{ name: client.translate("misc:MONTHS:APRIL"), value: 4 },
{ name: client.translate("misc:MONTHS:MAY"), value: 5 },
{ name: client.translate("misc:MONTHS:JUNE"), value: 6 },
{ name: client.translate("misc:MONTHS:JULY"), value: 7 },
{ name: client.translate("misc:MONTHS:AUGUST"), value: 8 },
{ name: client.translate("misc:MONTHS:SEPTEMBER"), value: 9 },
{ name: client.translate("misc:MONTHS:OCTOBER"), value: 10 },
{ name: client.translate("misc:MONTHS:NOVEMBER"), value: 11 },
{ name: client.translate("misc:MONTHS:DECEMBER"), value: 12 },
{ name: client.translate("economy/birthdate:JANUARY"), value: 1 },
{ name: client.translate("economy/birthdate:FEBRUARY"), value: 2 },
{ name: client.translate("economy/birthdate:MARCH"), value: 3 },
{ name: client.translate("economy/birthdate:APRIL"), value: 4 },
{ name: client.translate("economy/birthdate:MAY"), value: 5 },
{ name: client.translate("economy/birthdate:JUNE"), value: 6 },
{ name: client.translate("economy/birthdate:JULY"), value: 7 },
{ name: client.translate("economy/birthdate:AUGUST"), value: 8 },
{ name: client.translate("economy/birthdate:SEPTEMBER"), value: 9 },
{ name: client.translate("economy/birthdate:OCTOBER"), value: 10 },
{ name: client.translate("economy/birthdate:NOVEMBER"), value: 11 },
{ name: client.translate("economy/birthdate:DECEMBER"), value: 12 },
),
)
.addIntegerOption(option =>
@ -56,25 +57,8 @@ class Birthdate extends BaseCommand {
.setDescriptionLocalizations({
uk: client.translate("economy/birthdate:YEAR", null, "uk-UA"),
ru: client.translate("economy/birthdate:YEAR", null, "ru-RU"),
}),
)
.addBooleanOption(option =>
option
.setName("clear")
.setDescription(client.translate("economy/birthdate:CLEAR"))
.setDescriptionLocalizations({
uk: client.translate("economy/birthdate:CLEAR", null, "uk-UA"),
ru: client.translate("economy/birthdate:CLEAR", null, "ru-RU"),
}),
)
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
})
.setRequired(true),
),
dirname: __dirname,
ownerOnly: false,
@ -87,20 +71,8 @@ class Birthdate extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
const userData = interaction.data.user;
if (interaction.options.getBoolean("clear")) {
userData.birthdate = null;
await userData.save();
return interaction.success("economy/birthdate:SUCCESS", {
date: "none",
}, { edit: true });
}
const day = interaction.options.getInteger("day"),
const userData = interaction.data.user,
day = interaction.options.getInteger("day"),
month = interaction.options.getInteger("month"),
year = interaction.options.getInteger("year"),
date = new Date(year, month - 1, day);
@ -109,9 +81,9 @@ class Birthdate extends BaseCommand {
const d = Math.floor(date.getTime() / 1000);
if (!(day == date.getDate() && month - 1 == date.getMonth() && year == date.getFullYear())) return interaction.error("economy/birthdate:INVALID_DATE", null, { edit: true });
if (date.getTime() > Date.now()) return interaction.error("economy/birthdate:DATE_TOO_HIGH", null, { edit: true });
if (date.getTime() < Date.now() - 2.523e12) return interaction.error("economy/birthdate:DATE_TOO_LOW", null, { edit: true });
if (!(day == date.getDate() && month - 1 == date.getMonth() && year == date.getFullYear())) return interaction.error("economy/birthdate:INVALID_DATE");
if (date.getTime() > Date.now()) return interaction.error("economy/birthdate:DATE_TOO_HIGH");
if (date.getTime() < Date.now() - 2.523e12) return interaction.error("economy/birthdate:DATE_TOO_LOW");
userData.birthdate = d;
@ -119,7 +91,7 @@ class Birthdate extends BaseCommand {
interaction.success("economy/birthdate:SUCCESS", {
date: `<t:${d}:D>`,
}, { edit: true });
});
}
}

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Divorce extends BaseCommand {
@ -15,8 +15,7 @@ class Divorce extends BaseCommand {
uk: client.translate("economy/divorce:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/divorce:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild]),
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Leaderboard extends BaseCommand {
@ -15,8 +15,7 @@ class Leaderboard extends BaseCommand {
uk: client.translate("economy/leaderboard:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/leaderboard:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addStringOption(option =>
option
.setName("type")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
pendings = {};
@ -16,8 +16,7 @@ class Marry extends BaseCommand {
uk: client.translate("economy/marry:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/marry:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addUserOption(option =>
option
.setName("user")
@ -45,7 +44,7 @@ class Marry extends BaseCommand {
const member = interaction.options.getMember("user");
if (member.user.bot) return interaction.error("economy/marry:BOT_USER");
if (member.id === interaction.member.id) return interaction.error("misc:CANT_YOURSELF");
if (member.id === interaction.member.id) return interaction.error("economy/marry:YOURSELF");
const otherUserData = await client.getUserData(member.id);
if (otherUserData.lover) return interaction.error("economy/marry:ALREADY_MARRIED_USER", { user: member.toString() });

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Money extends BaseCommand {
@ -15,8 +15,7 @@ class Money extends BaseCommand {
uk: client.translate("economy/money:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/money:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addUserOption(option =>
option
.setName("user")
@ -40,9 +39,10 @@ class Money extends BaseCommand {
await interaction.deferReply();
const member = interaction.options.getMember("user") || interaction.member;
if (member.user.bot) return interaction.error("economy/money:BOT_USER", null, { edit: true });
if (member.user.bot) return interaction.error("economy/money:BOT_USER");
const memberData = member.id === interaction.user.id ? interaction.data.member : await client.getMemberData(member.id, interaction.guildId);
const guilds = client.guilds.cache.filter(g => g.members.cache.find(m => m.id === member.id));
let globalMoney = 0;

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Pay extends BaseCommand {
@ -15,8 +15,7 @@ class Pay extends BaseCommand {
uk: client.translate("economy/pay:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/pay:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addUserOption(option =>
option
.setName("user")
@ -51,7 +50,7 @@ class Pay extends BaseCommand {
const memberData = interaction.data.member,
otherMember = interaction.options.getMember("user");
if (otherMember.user.bot) return interaction.error("economy/pay:BOT_USER");
if (otherMember.id === interaction.member.id) return interaction.error("misc:CANT_YOURSELF");
if (otherMember.id === interaction.member.id) return interaction.error("economy/pay:YOURSELF");
const amount = interaction.options.getInteger("amount");
if (amount <= 0) return interaction.error("misc:MORE_THAN_ZERO");

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Profile extends BaseCommand {
@ -15,8 +15,7 @@ class Profile extends BaseCommand {
uk: client.translate("economy/profile:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/profile:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addUserOption(option =>
option
.setName("user")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Rep extends BaseCommand {
@ -15,8 +15,7 @@ class Rep extends BaseCommand {
uk: client.translate("economy/rep:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/rep:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addUserOption(option =>
option
.setName("user")
@ -50,7 +49,7 @@ class Rep extends BaseCommand {
const user = interaction.options.getUser("user");
if (user.bot) return interaction.error("economy/rep:BOT_USER");
if (user.id === interaction.user.id) return interaction.error("misc:CANT_YOURSELF");
if (user.id === interaction.user.id) return interaction.error("economy/rep:YOURSELF");
const toWait = Math.floor((Date.now() + 12 * 60 * 60 * 1000) / 1000); // 12 hours
if (!userData.cooldowns) userData.cooldowns = {};

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Rob extends BaseCommand {
@ -15,8 +15,7 @@ class Rob extends BaseCommand {
uk: client.translate("economy/rob:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/rob:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addUserOption(option =>
option
.setName("user")
@ -51,7 +50,7 @@ class Rob extends BaseCommand {
const memberData = interaction.data.member,
otherMember = interaction.options.getMember("user");
if (otherMember.user.bot) return interaction.error("economy/pay:BOT_USER");
if (otherMember.id === interaction.member.id) return interaction.error("misc:CANT_YOURSELF");
if (otherMember.id === interaction.member.id) return interaction.error("economy/rob:YOURSELF");
const amount = interaction.options.getInteger("amount");
if (amount <= 0) return interaction.error("misc:MORE_THAN_ZERO");

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType, escapeEscape, escapeCodeBlock, escapeInlineCode } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Setbio extends BaseCommand {
@ -15,8 +15,7 @@ class Setbio extends BaseCommand {
uk: client.translate("economy/setbio:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/setbio:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.Guild])
.setDMPermission(true)
.addStringOption(option =>
option
.setName("text")
@ -26,15 +25,6 @@ class Setbio extends BaseCommand {
ru: client.translate("economy/profile:BIO", null, "ru-RU"),
})
.setRequired(true),
)
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
dirname: __dirname,
ownerOnly: false,
@ -47,17 +37,15 @@ class Setbio extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
const userData = interaction.data.user,
newBio = interaction.options.getString("text");
if (newBio.length > 150) return interaction.error("misc:MAX_150_CHARS", null, { edit: true });
if (newBio.length > 150) return interaction.error("economy/setbio:MAX_CHARACTERS");
userData.bio = escapeEscape(escapeCodeBlock(escapeInlineCode(newBio))).replace("@", "@\u200b");
userData.bio = newBio;
await userData.save();
interaction.success("economy/setbio:SUCCESS", null, { edit: true });
interaction.success("economy/setbio:SUCCESS");
}
}

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Slots extends BaseCommand {
@ -15,8 +15,7 @@ class Slots extends BaseCommand {
uk: client.translate("economy/slots:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/slots:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addIntegerOption(option =>
option
.setName("amount")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Transactions extends BaseCommand {
@ -15,8 +15,7 @@ class Transactions extends BaseCommand {
uk: client.translate("economy/transactions:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/transactions:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addBooleanOption(option =>
option
.setName("clear")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, parseEmoji, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, parseEmoji } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Work extends BaseCommand {
@ -15,8 +15,7 @@ class Work extends BaseCommand {
uk: client.translate("economy/work:DESCRIPTION", null, "uk-UA"),
ru: client.translate("economy/work:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild]),
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Eightball extends BaseCommand {
@ -15,8 +15,7 @@ class Eightball extends BaseCommand {
uk: client.translate("fun/8ball:DESCRIPTION", null, "uk-UA"),
ru: client.translate("fun/8ball:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.setDMPermission(true)
.addStringOption(option =>
option
.setName("question")
@ -26,15 +25,6 @@ class Eightball extends BaseCommand {
ru: client.translate("fun/8ball:QUESTION", null, "ru-RU"),
})
.setRequired(true),
)
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
dirname: __dirname,
ownerOnly: false,
@ -47,7 +37,7 @@ class Eightball extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
await interaction.deferReply();
const question = interaction.options.getString("question");
const embed = client.embed({

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
fetch = require("node-fetch");
@ -16,17 +16,7 @@ class Cat extends BaseCommand {
uk: client.translate("fun/cat:DESCRIPTION", null, "uk-UA"),
ru: client.translate("fun/cat:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
.setDMPermission(true),
dirname: __dirname,
ownerOnly: false,
});
@ -38,7 +28,7 @@ class Cat extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
await interaction.deferReply();
const res = await fetch("https://api.thecatapi.com/v1/images/search").then(r => r.json());
const cat = res[0].url;

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
fetch = require("node-fetch");
@ -16,17 +16,7 @@ class Dog extends BaseCommand {
uk: client.translate("fun/dog:DESCRIPTION", null, "uk-UA"),
ru: client.translate("fun/dog:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
.setDMPermission(true),
dirname: __dirname,
ownerOnly: false,
});
@ -38,7 +28,7 @@ class Dog extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
await interaction.deferReply();
const res = await fetch("https://dog.ceo/api/breeds/image/random").then(r => r.json());
const dog = res.message;

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
fetch = require("node-fetch");
@ -16,8 +16,7 @@ class LMGTFY extends BaseCommand {
uk: client.translate("fun/lmgtfy:DESCRIPTION", null, "uk-UA"),
ru: client.translate("fun/lmgtfy:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.setDMPermission(true)
.addStringOption(option =>
option
.setName("query")
@ -37,15 +36,6 @@ class LMGTFY extends BaseCommand {
ru: client.translate("fun/lmgtfy:SHORT", null, "ru-RU"),
})
.setRequired(true),
)
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
dirname: __dirname,
ownerOnly: false,
@ -58,24 +48,24 @@ class LMGTFY extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
await interaction.deferReply({ ephemeral: true });
const query = interaction.options.getString("query").replace(/[' '_]/g, "+"),
short = interaction.options.getBoolean("short"),
url = `https://letmegooglethat.com/?q=${encodeURIComponent(query)}`;
if (short) {
const res = await fetch("https://i.jonnybro.ru/api/shorten", {
const res = await fetch("https://plsgo.ru/rest/v3/short-urls", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: client.config.apiKeys.zipline,
"Content-Type": "application/x-www-form-urlencoded",
"X-Api-Key": client.config.apiKeys.shlink,
},
body: JSON.stringify({ url: url }),
body: new URLSearchParams({ longUrl: url }),
}).then(res => res.json());
interaction.editReply({
content: `<${res.url}>`,
content: `<${res.shortUrl}>`,
});
} else {
interaction.editReply({

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
md5 = require("md5");
@ -16,8 +16,7 @@ class Lovecalc extends BaseCommand {
uk: client.translate("fun/lovecalc:DESCRIPTION", null, "uk-UA"),
ru: client.translate("fun/lovecalc:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addUserOption(option =>
option
.setName("first_member")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, MessageCollector, ButtonBuilder, ActionRowBuilder, ButtonStyle, ThreadAutoArchiveDuration, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, MessageCollector, ButtonBuilder, ActionRowBuilder, ButtonStyle, ThreadAutoArchiveDuration } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
currentGames = {};
@ -16,8 +16,7 @@ class Number extends BaseCommand {
uk: client.translate("fun/number:DESCRIPTION", null, "uk-UA"),
ru: client.translate("fun/number:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild]),
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
tictactoe = require("../../helpers/tictactoe");
@ -16,8 +16,7 @@ class TicTacToe extends BaseCommand {
uk: client.translate("fun/tictactoe:DESCRIPTION", null, "uk-UA"),
ru: client.translate("fun/tictactoe:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.Guild, InteractionContextType.PrivateChannel])
.setDMPermission(false)
.addUserOption(option =>
option
.setName("user")
@ -39,23 +38,26 @@ class TicTacToe extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
const winner = await tictactoe(interaction, {
tictactoe(interaction, {
resultBtn: true,
embedColor: client.config.embed.color,
embedFoot: client.config.embed.footer,
}).then(async winner => {
const memberData = await client.getMemberData(winner.id, interaction.guildId);
memberData.money += 100;
const info = {
user: interaction.translate("economy/transactions:TTT"),
amount: 100,
date: Date.now(),
type: "got",
};
memberData.transactions.push(info);
await memberData.save();
});
const memberData = await client.getMemberData(winner.id, interaction.guildId);
memberData.money += 100;
const info = {
user: interaction.translate("economy/transactions:TTT"),
amount: 100,
date: Date.now(),
type: "got",
};
memberData.transactions.push(info);
await memberData.save();
}
}

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType, escapeEscape, escapeCodeBlock, escapeInlineCode } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Afk extends BaseCommand {
@ -15,8 +15,7 @@ class Afk extends BaseCommand {
uk: client.translate("general/afk:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/afk:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.setDMPermission(true)
.addStringOption(option =>
option
.setName("message")
@ -26,15 +25,6 @@ class Afk extends BaseCommand {
ru: client.translate("common:MESSAGE", null, "ru-RU"),
})
.setRequired(true),
)
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
dirname: __dirname,
ownerOnly: false,
@ -47,19 +37,17 @@ class Afk extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
await interaction.deferReply({ ephemeral: true });
const userData = interaction.data.user,
message = interaction.options.getString("message");
reason = interaction.options.getString("message");
if (message.length > 150) return interaction.error("misc:MAX_150_CHARS", null, { edit: true });
userData.afk = escapeEscape(escapeCodeBlock(escapeInlineCode(message))).replace("@", "@\u200b");
userData.afk = reason;
await userData.save();
interaction.success("general/afk:SUCCESS", {
message,
reason,
}, { edit: true });
}
}

View file

@ -1,4 +1,4 @@
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { ContextMenuCommandBuilder, ApplicationCommandType } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class AvatarContext extends BaseCommand {
@ -11,8 +11,7 @@ class AvatarContext extends BaseCommand {
command: new ContextMenuCommandBuilder()
.setName("Get Avatar")
.setType(ApplicationCommandType.User)
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild]),
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Avatar extends BaseCommand {
@ -15,8 +15,7 @@ class Avatar extends BaseCommand {
uk: client.translate("general/avatar:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/avatar:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.setDMPermission(true)
.addUserOption(option =>
option
.setName("user")
@ -34,15 +33,6 @@ class Avatar extends BaseCommand {
uk: client.translate("general/avatar:SERVER", null, "uk-UA"),
ru: client.translate("general/avatar:SERVER", null, "ru-RU"),
}),
)
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
dirname: __dirname,
ownerOnly: false,
@ -55,13 +45,11 @@ class Avatar extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
const user = interaction.options.getUser("user") || interaction.user;
const avatarURL = interaction.options.getBoolean("server") ? user.displayAvatarURL({ size: 2048 }) : user.avatarURL({ size: 2048 });
const member = interaction.options.getMember("user") || interaction.member;
const avatarURL = interaction.options.getBoolean("server") ? member.displayAvatarURL({ size: 2048 }) : member.user.displayAvatarURL({ size: 2048 });
const embed = client.embed({ image: avatarURL });
interaction.editReply({
interaction.reply({
embeds: [embed],
});
}

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Boosters extends BaseCommand {
@ -15,8 +15,7 @@ class Boosters extends BaseCommand {
uk: client.translate("general/boosters:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/boosters:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild]),
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, parseEmoji, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, parseEmoji } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Emoji extends BaseCommand {
@ -15,8 +15,7 @@ class Emoji extends BaseCommand {
uk: client.translate("general/emoji:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/emoji:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.setDMPermission(true)
.addStringOption(option =>
option
.setName("emoji")
@ -26,15 +25,6 @@ class Emoji extends BaseCommand {
ru: client.translate("common:EMOJI", null, "ru-RU"),
})
.setRequired(true),
)
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
dirname: __dirname,
ownerOnly: false,
@ -47,10 +37,9 @@ class Emoji extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
const rawEmoji = interaction.options.getString("emoji");
const parsedEmoji = parseEmoji(rawEmoji);
const embed = client.embed({
author: {
name: interaction.translate("general/emoji:TITLE", {
@ -77,7 +66,7 @@ class Emoji extends BaseCommand {
],
});
interaction.editReply({
interaction.reply({
embeds: [embed],
});
}

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, ActionRowBuilder, StringSelectMenuBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, ActionRowBuilder, StringSelectMenuBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Help extends BaseCommand {
@ -15,8 +15,7 @@ class Help extends BaseCommand {
uk: client.translate("general/help:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/help:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.setDMPermission(true)
.addStringOption(option =>
option
.setName("command")
@ -26,15 +25,6 @@ class Help extends BaseCommand {
ru: client.translate("common:COMMAND", null, "ru-RU"),
})
.setAutocomplete(true),
)
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
dirname: __dirname,
ownerOnly: false,
@ -90,7 +80,7 @@ class Help extends BaseCommand {
* @param {Object} data
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
await interaction.deferReply();
const commands = [...new Map(client.commands.map(v => [v.constructor.name, v])).values()];
const categories = [... new Set(commands.map(c => c.category))];

View file

@ -1,236 +0,0 @@
const { SlashCommandBuilder, ChannelType, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Info extends BaseCommand {
/**
*
* @param {import("../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("info")
.setDescription(client.translate("general/info:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("general/info:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/info:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.addSubcommand(subcommand =>
subcommand
.setName("user")
.setDescription(client.translate("general/info:USER"))
.setDescriptionLocalizations({
uk: client.translate("general/info:USER", null, "uk-UA"),
ru: client.translate("general/info:USER", null, "ru-RU"),
})
.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"),
}),
),
)
.addSubcommand(subcommand =>
subcommand
.setName("server")
.setDescription(client.translate("general/info:SERVER"))
.setDescriptionLocalizations({
uk: client.translate("general/info:SERVER", null, "uk-UA"),
ru: client.translate("general/info:SERVER", null, "ru-RU"),
}),
),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply();
const command = interaction.options.getSubcommand();
if (command === "user") {
const member = interaction.options.getMember("user") || interaction.member;
const embed = getUserInfo(client, interaction, member);
return interaction.editReply({
embeds: [embed],
});
} else {
const embed = await getServerInfo(client, interaction);
return interaction.editReply({
embeds: [embed],
});
}
}
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
* @returns {Promise<import("discord.js").Embed>} Embed containing information about the guild
*/
async function getServerInfo(client, interaction) {
const { guild } = interaction;
await guild.members.fetch();
const owner = await guild.fetchOwner();
const embed = client.embed({
author: guild.name,
thumbnail: guild.iconURL(),
fields: [
{
name: client.customEmojis.title + interaction.translate("common:NAME"),
value: guild.name,
inline: true,
},
{
name: client.customEmojis.calendar + interaction.translate("common:CREATION"),
value: `<t:${Math.floor(guild.createdTimestamp / 1000)}:D>`,
inline: true,
},
{
name: client.customEmojis.users + interaction.translate("common:MEMBERS"),
value:
`${guild.members.cache.filter(m => !m.user.bot).size} ${client.functions.getNoun(
guild.members.cache.filter(m => !m.user.bot).size,
interaction.translate("misc:NOUNS:MEMBERS:1"),
interaction.translate("misc:NOUNS:MEMBERS:2"),
interaction.translate("misc:NOUNS:MEMBERS:5"),
)}` +
"\n" +
`${guild.members.cache.filter(m => m.user.bot).size} ${client.functions.getNoun(
guild.members.cache.filter(m => m.user.bot).size,
interaction.translate("misc:NOUNS:BOTS:1"),
interaction.translate("misc:NOUNS:BOTS:2"),
interaction.translate("misc:NOUNS:BOTS:5"),
)}`,
inline: true,
},
{
name: client.customEmojis.afk + interaction.translate("general/info:AFK_CHANNEL"),
value: guild.afkChannel?.toString() || interaction.translate("common:MISSING"),
inline: true,
},
{
name: client.customEmojis.id + interaction.translate("common:SERVER_ID"),
value: guild.id,
inline: true,
},
{
name: client.customEmojis.crown + interaction.translate("common:OWNER"),
value: owner.toString(),
inline: true,
},
{
name: client.customEmojis.boost + interaction.translate("general/info:BOOSTS"),
value: guild.premiumSubscriptionCount?.toString() || "0",
inline: true,
},
{
name: client.customEmojis.channels + interaction.translate("common:CHANNELS"),
value:
`${guild.channels.cache.filter(c => c.type === ChannelType.GuildText).size} ${client.functions.getNoun(
guild.channels.cache.filter(c => c.type === ChannelType.GuildText).size,
interaction.translate("misc:NOUNS:TEXT:1"),
interaction.translate("misc:NOUNS:TEXT:2"),
interaction.translate("misc:NOUNS:TEXT:5"),
)}` +
"\n" +
`${guild.channels.cache.filter(c => c.type === ChannelType.GuildVoice).size} ${client.functions.getNoun(
guild.channels.cache.filter(c => c.type === ChannelType.GuildVoice).size,
interaction.translate("misc:NOUNS:VOICE:1"),
interaction.translate("misc:NOUNS:VOICE:2"),
interaction.translate("misc:NOUNS:VOICE:5"),
)}` +
"\n" +
`${guild.channels.cache.filter(c => c.type === ChannelType.GuildCategory).size} ${client.functions.getNoun(
guild.channels.cache.filter(c => c.type === ChannelType.GuildCategory).size,
interaction.translate("misc:NOUNS:CATEGORY:1"),
interaction.translate("misc:NOUNS:CATEGORY:2"),
interaction.translate("misc:NOUNS:CATEGORY:5"),
)}`,
inline: true,
},
],
});
return embed;
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
* @param {import("discord.js").Member} member
* @returns {import("discord.js").Embed} Embed containing information about the user
*/
function getUserInfo(client, interaction, member) {
const embed = client.embed({
author: {
name: `${member.user.getUsername()} (${member.id})`,
iconURL: member.displayAvatarURL(),
},
thumbnail: member.displayAvatarURL(),
fields: [
{
name: ":man: " + interaction.translate("common:USERNAME"),
value: member.user.getUsername(),
inline: true,
},
{
name: client.customEmojis.pencil + " " + interaction.translate("common:NICKNAME"),
value: member.nickname || interaction.translate("general/info:NO_NICKNAME"),
inline: true,
},
{
name: client.customEmojis.bot + " " + interaction.translate("common:ROBOT"),
value: member.user.bot ? interaction.translate("common:YES") : interaction.translate("common:NO"),
inline: true,
},
{
name: client.customEmojis.calendar + " " + interaction.translate("common:CREATION"),
value: `<t:${Math.floor(member.user.createdTimestamp / 1000)}:D>`,
inline: true,
},
{
name: client.customEmojis.calendar2 + " " + interaction.translate("common:JOINED"),
value: `<t:${Math.floor(member.joinedTimestamp / 1000)}:D>`,
inline: true,
},
{
name: client.customEmojis.color + " " + interaction.translate("common:COLOR"),
value: member.displayHexColor,
inline: true,
},
{
name: client.customEmojis.roles + " " + interaction.translate("common:ROLES"),
value:
member.roles.size > 10
? member.roles.cache.map(r => r).filter(r => r.id !== interaction.guild.roles.everyone.id).slice(0, 10).join(", ") + " " +
interaction.translate("general/info:MORE_ROLES", {
count: member.roles.cache.size - 10,
})
: member.roles.cache.size < 1 ? interaction.translate("general/info:NO_ROLE") : member.roles.cache.map(r => r).filter(r => r.id !== interaction.guild.roles.everyone.id).slice(0, 10).join(", "),
inline: true,
},
],
});
return embed;
}
module.exports = Info;

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
gamedig = require("gamedig");
@ -16,8 +16,7 @@ class Minecraft extends BaseCommand {
uk: client.translate("general/minecraft:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/minecraft:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.setDMPermission(true)
.addStringOption(option =>
option
.setName("ip")
@ -27,15 +26,6 @@ class Minecraft extends BaseCommand {
ru: client.translate("common:IP", null, "ru-RU"),
})
.setRequired(true),
)
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
dirname: __dirname,
ownerOnly: false,
@ -48,7 +38,7 @@ class Minecraft extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
await interaction.deferReply();
const ip = interaction.options.getString("ip");
const options = {
@ -65,7 +55,7 @@ class Minecraft extends BaseCommand {
let res = await gamedig.query(options).catch(() => {});
if (!res) {
options.type = "mbe";
options.type = "minecraftpe";
res = await gamedig.query(options).catch(() => {});
}

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Ping extends BaseCommand {
@ -15,17 +15,7 @@ class Ping extends BaseCommand {
uk: client.translate("general/ping:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/ping:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
.setDMPermission(true),
dirname: __dirname,
ownerOnly: false,
});
@ -37,8 +27,6 @@ class Ping extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
const embed = client.embed({
author: {
name: interaction.translate("general/ping:PONG"),
@ -48,7 +36,7 @@ class Ping extends BaseCommand {
}),
});
interaction.editReply({
interaction.reply({
embeds: [embed],
});
}

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
ms = require("ms");
@ -16,8 +16,7 @@ class Remindme extends BaseCommand {
uk: client.translate("general/remindme:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/remindme:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.setDMPermission(true)
.addStringOption(option =>
option
.setName("time")
@ -51,12 +50,6 @@ class Remindme extends BaseCommand {
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: true });
const conditions = ["s", "m", "h", "d", "w", "y"],
time = interaction.options.getString("time"),
message = interaction.options.getString("message");
if (!conditions.some(s => time.includes(s))) return interaction.error("general/remindme:TIME", null, { edit: true });
const userData = interaction.data.user;
if (!userData.reminds) userData.reminds = [];
@ -64,9 +57,9 @@ class Remindme extends BaseCommand {
const dateNow = Date.now();
const reminder = {
message: message,
message: interaction.options.getString("message"),
createdAt: Math.floor(dateNow / 1000),
sendAt: Math.floor((dateNow + ms(time)) / 1000),
sendAt: Math.floor((dateNow + ms(interaction.options.getString("time"))) / 1000),
};
userData.reminds.push(reminder);

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Reminds extends BaseCommand {
@ -15,8 +15,7 @@ class Reminds extends BaseCommand {
uk: client.translate("general/reminds:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/reminds:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild]),
.setDMPermission(true),
dirname: __dirname,
ownerOnly: false,
});
@ -29,129 +28,88 @@ class Reminds extends BaseCommand {
async onLoad(client) {
client.on("interactionCreate", async interaction => {
if (!interaction.isButton()) return;
if (!interaction.customId.startsWith("reminds_")) return;
interaction.data = [];
interaction.data.guild = await client.getGuildData(interaction.guildId);
interaction.data.user = await client.getUserData(interaction.user.id);
if (interaction.customId.startsWith("reminds_")) {
interaction.data = [];
interaction.data.guild = await client.getGuildData(interaction.guildId);
interaction.data.user = await client.getUserData(interaction.user.id);
const reminds = interaction.data.user.reminds,
embeds = generateRemindsEmbeds(interaction, reminds);
const reminds = interaction.data.user.reminds,
embeds = generateRemindsEmbeds(interaction, reminds);
const row = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId("reminds_prev_page").setStyle(ButtonStyle.Primary).setEmoji("⬅️"),
new ButtonBuilder().setCustomId("reminds_next_page").setStyle(ButtonStyle.Primary).setEmoji("➡️"),
new ButtonBuilder().setCustomId("reminds_jump_page").setStyle(ButtonStyle.Secondary).setEmoji("↗️"),
new ButtonBuilder().setCustomId("reminds_stop").setStyle(ButtonStyle.Danger).setEmoji("❌"),
);
const row = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId("reminds_prev_page").setStyle(ButtonStyle.Primary).setEmoji("⬅️"),
new ButtonBuilder().setCustomId("reminds_next_page").setStyle(ButtonStyle.Primary).setEmoji("➡️"),
new ButtonBuilder().setCustomId("reminds_jump_page").setStyle(ButtonStyle.Secondary).setEmoji("↗️"),
new ButtonBuilder().setCustomId("reminds_stop").setStyle(ButtonStyle.Danger).setEmoji("❌"),
);
let currentPage = Number(interaction.message.content.match(/\d+/g)[0]) - 1 ?? 0;
let currentPage = Number(interaction.message.content.match(/\d+/g)[0]) - 1 ?? 0;
if (interaction.customId === "reminds_prev_page") {
await interaction.deferUpdate();
if (currentPage !== 0) {
--currentPage;
const row2 = new ActionRowBuilder().addComponents(embeds[currentPage].data._buttons);
interaction.editReply({
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${embeds.length}**`,
embeds: [embeds[currentPage]],
components: [row, row2],
});
}
} else if (interaction.customId === "reminds_next_page") {
await interaction.deferUpdate();
if (currentPage < embeds.length - 1) {
currentPage++;
const row2 = new ActionRowBuilder().addComponents(embeds[currentPage].data._buttons);
interaction.editReply({
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${embeds.length}**`,
embeds: [embeds[currentPage]],
components: [row, row2],
});
}
} else if (interaction.customId === "reminds_jump_page") {
await interaction.deferUpdate();
const msg = await interaction.followUp({
content: interaction.translate("misc:JUMP_TO_PAGE", {
length: embeds.length,
}),
fetchReply: true,
ephemeral: true,
});
const filter = res => {
return res.author.id === interaction.user.id && !isNaN(res.content);
};
interaction.channel.awaitMessages({ filter, max: 1, time: 10 * 1000 }).then(collected => {
if (embeds[collected.first().content - 1]) {
currentPage = collected.first().content - 1;
const row2 = new ActionRowBuilder().addComponents(embeds[currentPage].data._buttons);
if (interaction.customId === "reminds_prev_page") {
await interaction.deferUpdate();
if (currentPage !== 0) {
--currentPage;
interaction.editReply({
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${embeds.length}**`,
embeds: [embeds[currentPage]],
components: [row, row2],
components: [row],
});
if (collected.first().deletable) collected.first().delete();
if (msg.deletable) msg.delete();
} else {
if (collected.first().deletable) collected.first().delete();
if (msg.deletable) msg.delete();
return;
}
});
} else if (interaction.customId === "reminds_stop") {
await interaction.deferUpdate();
} else if (interaction.customId === "reminds_next_page") {
await interaction.deferUpdate();
row.components.forEach(component => {
component.setDisabled(true);
});
if (currentPage < embeds.length - 1) {
currentPage++;
interaction.editReply({
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${embeds.length}**`,
embeds: [embeds[currentPage]],
components: [row],
});
}
} else if (interaction.customId === "reminds_jump_page") {
await interaction.deferUpdate();
return interaction.editReply({
components: [row],
});
} else if (interaction.customId.startsWith("reminds_delete_")) {
await interaction.deferUpdate();
const msg = await interaction.followUp({
content: interaction.translate("misc:JUMP_TO_PAGE", {
length: embeds.length,
}),
fetchReply: true,
});
const id = parseInt(interaction.customId.split("_")[2]);
const remindToDelete = reminds[id - 1];
const filter = res => {
return res.author.id === interaction.user.id && !isNaN(res.content);
};
interaction.data.user.reminds = reminds.filter(r => r.sendAt !== remindToDelete.sendAt);
interaction.channel.awaitMessages({ filter, max: 1, time: 10 * 1000 }).then(collected => {
if (embeds[collected.first().content - 1]) {
currentPage = collected.first().content - 1;
interaction.editReply({
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${embeds.length}**`,
embeds: [embeds[currentPage]],
components: [row],
});
await interaction.data.user.save();
if (collected.first().deletable) collected.first().delete();
if (msg.deletable) msg.delete();
} else {
if (collected.first().deletable) collected.first().delete();
if (msg.deletable) msg.delete();
return;
}
});
} else if (interaction.customId === "reminds_stop") {
await interaction.deferUpdate();
const embeds = generateRemindsEmbeds(interaction, interaction.data.user.reminds);
row.components.forEach(component => {
component.setDisabled(true);
});
if (embeds.length === 0) return interaction.editReply({
content: interaction.translate("general/reminds:NO_REMINDS"),
embeds: [],
components: [],
});
embeds.length <= 5 ? currentPage = 0 : currentPage;
const row2 = new ActionRowBuilder().addComponents(embeds[currentPage].data._buttons);
await interaction.editReply({
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${embeds.length}**`,
embeds: [embeds[currentPage]],
components: [row, row2],
});
return interaction.followUp({
content: `${client.customEmojis.success} | ${interaction.translate("general/reminds:DELETED", { pos: id })}`,
ephemeral: true,
});
return interaction.editReply({
components: [row],
});
}
}
});
}
@ -176,12 +134,10 @@ class Reminds extends BaseCommand {
new ButtonBuilder().setCustomId("reminds_stop").setStyle(ButtonStyle.Danger).setEmoji("❌"),
);
const buttonsRow = new ActionRowBuilder().addComponents(embeds[0].data._buttons);
await interaction.editReply({
content: `${interaction.translate("common:PAGE")}: **1**/**${embeds.length}**`,
embeds: [embeds[0]],
components: [row, buttonsRow],
components: [row],
ephemeral: true,
});
}
@ -212,21 +168,9 @@ function generateRemindsEmbeds(interaction, reminds) {
description: info,
});
embed.data._buttons = [];
for (const key in current) {
embed.data._buttons.push(
new ButtonBuilder()
.setCustomId(`reminds_delete_${parseInt(key) + i + 1}`)
.setLabel(interaction.translate("general/reminds:DELETE", { pos: parseInt(key) + i + 1 }))
.setStyle(ButtonStyle.Danger),
);
}
embeds.push(embed);
}
return embeds;
}

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, parseEmoji, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, parseEmoji } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Report extends BaseCommand {
@ -15,8 +15,7 @@ class Report extends BaseCommand {
uk: client.translate("general/report:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/report:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addUserOption(option =>
option
.setName("user")
@ -87,14 +86,14 @@ class Report extends BaseCommand {
],
});
const cool = parseEmoji(client.customEmojis.cool).id;
const notcool = parseEmoji(client.customEmojis.notcool).id;
const success = parseEmoji(client.customEmojis.cool).id;
const error = parseEmoji(client.customEmojis.notcool).id;
repChannel.send({
embeds: [embed],
}).then(async m => {
await m.react(cool);
await m.react(notcool);
await m.react(success);
await m.react(error);
});
interaction.success("general/report:SUCCESS", {

View file

@ -0,0 +1,121 @@
const { SlashCommandBuilder, ChannelType } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Serverinfo extends BaseCommand {
/**
*
* @param {import("../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("serverinfo")
.setDescription(client.translate("general/serverinfo:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("general/serverinfo:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/serverinfo:DESCRIPTION", null, "ru-RU"),
})
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
const { guild } = interaction;
await guild.members.fetch();
const owner = await guild.fetchOwner();
const embed = client.embed({
author: guild.name,
thumbnail: guild.iconURL(),
fields: [
{
name: client.customEmojis.title + interaction.translate("common:NAME"),
value: guild.name,
inline: true,
},
{
name: client.customEmojis.calendar + interaction.translate("common:CREATION"),
value: `<t:${guild.createdTimestamp}:D>`,
inline: true,
},
{
name: client.customEmojis.users + interaction.translate("common:MEMBERS"),
value:
`${guild.members.cache.filter(m => !m.user.bot).size} ${client.functions.getNoun(
guild.members.cache.filter(m => !m.user.bot).size,
interaction.translate("misc:NOUNS:MEMBERS:1"),
interaction.translate("misc:NOUNS:MEMBERS:2"),
interaction.translate("misc:NOUNS:MEMBERS:5"),
)}` +
"\n" +
`${guild.members.cache.filter(m => m.user.bot).size} ${client.functions.getNoun(
guild.members.cache.filter(m => m.user.bot).size,
interaction.translate("misc:NOUNS:BOTS:1"),
interaction.translate("misc:NOUNS:BOTS:2"),
interaction.translate("misc:NOUNS:BOTS:5"),
)}`,
inline: true,
},
{
name: client.customEmojis.afk + interaction.translate("general/serverinfo:AFK_CHANNEL"),
value: guild.afkChannel?.toString() || interaction.translate("common:MISSING"),
inline: true,
},
{
name: client.customEmojis.id + interaction.translate("common:SERVER_ID"),
value: guild.id,
inline: true,
},
{
name: client.customEmojis.crown + interaction.translate("common:OWNER"),
value: owner.toString(),
inline: true,
},
{
name: client.customEmojis.boost + interaction.translate("general/serverinfo:BOOSTS"),
value: guild.premiumSubscriptionCount?.toString() || "0",
inline: true,
},
{
name: client.customEmojis.channels + interaction.translate("common:CHANNELS"),
value:
`${guild.channels.cache.filter(c => c.type === ChannelType.GuildText).size} ${client.functions.getNoun(
guild.channels.cache.filter(c => c.type === ChannelType.GuildText).size,
interaction.translate("misc:NOUNS:TEXT:1"),
interaction.translate("misc:NOUNS:TEXT:2"),
interaction.translate("misc:NOUNS:TEXT:5"),
)}` +
"\n" +
`${guild.channels.cache.filter(c => c.type === ChannelType.GuildVoice).size} ${client.functions.getNoun(
guild.channels.cache.filter(c => c.type === ChannelType.GuildVoice).size,
interaction.translate("misc:NOUNS:VOICE:1"),
interaction.translate("misc:NOUNS:VOICE:2"),
interaction.translate("misc:NOUNS:VOICE:5"),
)}` +
"\n" +
`${guild.channels.cache.filter(c => c.type === ChannelType.GuildCategory).size} ${client.functions.getNoun(
guild.channels.cache.filter(c => c.type === ChannelType.GuildCategory).size,
interaction.translate("misc:NOUNS:CATEGORY:1"),
interaction.translate("misc:NOUNS:CATEGORY:2"),
interaction.translate("misc:NOUNS:CATEGORY:5"),
)}`,
inline: true,
},
],
});
interaction.reply({
embeds: [embed],
});
}
}
module.exports = Serverinfo;

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
fetch = require("node-fetch");
@ -16,8 +16,7 @@ class Shorturl extends BaseCommand {
uk: client.translate("general/shorturl:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/shorturl:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.setDMPermission(true)
.addStringOption(option =>
option
.setName("url")
@ -27,15 +26,6 @@ class Shorturl extends BaseCommand {
ru: client.translate("common:URL", null, "ru-RU"),
})
.setRequired(true),
)
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
dirname: __dirname,
ownerOnly: false,
@ -48,22 +38,20 @@ class Shorturl extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
await interaction.deferReply({ ephemeral: true });
const url = interaction.options.getString("url");
const res = await fetch("https://i.jonnybro.ru/api/shorten", {
const res = await fetch("https://plsgo.ru/rest/v3/short-urls", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: client.config.apiKeys.zipline,
"Content-Type": "application/x-www-form-urlencoded",
"X-Api-Key": client.config.apiKeys.shlink,
},
body: JSON.stringify({ url: url }),
body: new URLSearchParams({ longUrl: url }),
}).then(res => res.json());
console.log(res);
interaction.editReply({
content: `<${res.url}>`,
content: `<${res.shortUrl}>`,
});
}
}

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, version: discordJsVersion, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField, version: djsVersion } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Stats extends BaseCommand {
@ -15,17 +15,7 @@ class Stats extends BaseCommand {
uk: client.translate("general/stats:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/stats:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
.setDMPermission(true),
dirname: __dirname,
ownerOnly: false,
});
@ -37,13 +27,13 @@ class Stats extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
const servers = client.guilds.cache.size;
const hiddenGuildMembersCount = client.guilds.cache.get("568120814776614924").memberCount;
const servers = client.guilds.cache.size - 1;
let users = 0;
client.guilds.cache.forEach(g => {
users += g.memberCount;
});
users = users - hiddenGuildMembersCount;
const embed = client.embed({
author: interaction.translate("common:STATS"),
@ -59,7 +49,7 @@ class Stats extends BaseCommand {
},
{
name: client.customEmojis.version + " " + interaction.translate("general/stats:VERSIONS_TITLE"),
value: `\`Discord.js: v${discordJsVersion}\`\n\`Nodejs: v${process.versions.node}\``,
value: `\`Discord.js: v${djsVersion}\`\n\`Nodejs: v${process.versions.node}\``,
inline: true,
},
{
@ -94,13 +84,14 @@ class Stats extends BaseCommand {
dashboardLink: client.config.dashboard.domain,
supportLink: "https://discord.gg/Ptkj2n9nzZ",
inviteLink: client.generateInvite({ scopes: ["bot", "applications.commands"], permissions: [PermissionsBitField.Flags.Administrator] }),
donateLink: "https://www.donationalerts.com/r/jonny_bro",
owner: client.config.owner.id,
}),
},
],
});
interaction.editReply({
interaction.reply({
embeds: [embed],
});
}

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, parseEmoji, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, parseEmoji } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Suggest extends BaseCommand {
@ -15,8 +15,7 @@ class Suggest extends BaseCommand {
uk: client.translate("general/suggest:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/suggest:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addStringOption(option =>
option
.setName("message")

View file

@ -0,0 +1,99 @@
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Userinfo extends BaseCommand {
/**
*
* @param {import("../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("userinfo")
.setDescription(client.translate("general/userinfo:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("general/userinfo:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/userinfo:DESCRIPTION", null, "ru-RU"),
})
.setDMPermission(false)
.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"),
}),
),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
* @param {Object} data
*/
async execute(client, interaction) {
const member = interaction.options.getMember("user") || interaction.member;
const embed = client.embed({
author: {
name: `${member.user.getUsername()} (${member.id})`,
iconURL: member.displayAvatarURL(),
},
thumbnail: member.displayAvatarURL(),
fields: [
{
name: ":man: " + interaction.translate("common:USERNAME"),
value: member.user.getUsername(),
inline: true,
},
{
name: client.customEmojis.pencil + " " + interaction.translate("common:NICKNAME"),
value: member.nickname || interaction.translate("general/userinfo:NO_NICKNAME"),
inline: true,
},
{
name: client.customEmojis.bot + " " + interaction.translate("common:ROBOT"),
value: member.user.bot ? interaction.translate("common:YES") : interaction.translate("common:NO"),
inline: true,
},
{
name: client.customEmojis.calendar + " " + interaction.translate("common:CREATION"),
value: `<t:${member.user.createdTimestamp}:D>`,
inline: true,
},
{
name: client.customEmojis.calendar2 + " " + interaction.translate("common:JOINED"),
value: `<t:${member.joinedTimestamp}:D>`,
inline: true,
},
{
name: client.customEmojis.color + " " + interaction.translate("common:COLOR"),
value: member.displayHexColor,
inline: true,
},
{
name: client.customEmojis.roles + " " + interaction.translate("common:ROLES"),
value:
member.roles.size > 10
? member.roles.cache.map(r => r).filter(r => r.id !== interaction.guild.roles.everyone.id).slice(0, 10).join(", ") + " " +
interaction.translate("general/userinfo:MORE_ROLES", {
count: member.roles.cache.size - 10,
})
: member.roles.cache.size < 1 ? interaction.translate("general/userinfo:NO_ROLE") : member.roles.cache.map(r => r).filter(r => r.id !== interaction.guild.roles.everyone.id).slice(0, 10).join(", "),
inline: true,
},
],
});
interaction.reply({
embeds: [embed],
});
}
}
module.exports = Userinfo;

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
fetch = require("node-fetch");
@ -16,8 +16,7 @@ class Whois extends BaseCommand {
uk: client.translate("general/whois:DESCRIPTION", null, "uk-UA"),
ru: client.translate("general/whois:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.setDMPermission(true)
.addStringOption(option =>
option
.setName("ip")
@ -27,15 +26,6 @@ class Whois extends BaseCommand {
ru: client.translate("common:IP", null, "ru-RU"),
})
.setRequired(true),
)
.addBooleanOption(option =>
option
.setName("ephemeral")
.setDescription(client.translate("misc:EPHEMERAL_RESPONSE"))
.setDescriptionLocalizations({
uk: client.translate("misc:EPHEMERAL_RESPONSE", null, "uk-UA"),
ru: client.translate("misc:EPHEMERAL_RESPONSE", null, "ru-RU"),
}),
),
dirname: __dirname,
ownerOnly: false,
@ -48,12 +38,12 @@ class Whois extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: interaction.options.getBoolean("ephemeral") || false });
await interaction.deferReply();
const ip = interaction.options.getString("ip"),
whois = await fetch(`http://ip-api.com/json/${ip}?fields=status,message,continent,continentCode,country,countryCode,region,regionName,city,zip,timezone,currency,isp,org,as,mobile,proxy,hosting,query`).then(response => response.json());
if (whois.status === "fail") return interaction.error("general/whois:ERROR", { ip }, { edit: true });
if (whois.status === "fail") return interaction.editReply({ content: interaction.translate("general/whois:ERROR", { ip }) });
const embed = client.embed({
title: interaction.translate("general/whois:INFO_ABOUT", {

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
fetch = require("node-fetch"),
moment = require("moment");
@ -17,8 +17,7 @@ class Checkjar extends BaseCommand {
uk: client.translate("iat/checkjar:DESCRIPTION", null, "uk-UA"),
ru: client.translate("iat/checkjar:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild]),
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Clear extends BaseCommand {
@ -15,8 +15,7 @@ class Clear extends BaseCommand {
uk: client.translate("moderation/clear:DESCRIPTION", null, "uk-UA"),
ru: client.translate("moderation/clear:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages)
.addStringOption(option =>
option
@ -118,7 +117,7 @@ class Clear extends BaseCommand {
}
});
} else {
if (isNaN(option) || parseInt(option) < 1) return interaction.error("misc:OPTION_NAN_ALL", null, { edit: true });
if (isNaN(option) || parseInt(option) < 1) return interaction.error("misc:OPTION_NAN_ALL", null, { ephemeral: true });
let messages = await interaction.channel.messages.fetch({ limit: option });

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Clearwarns extends BaseCommand {
@ -15,8 +15,7 @@ class Clearwarns extends BaseCommand {
uk: client.translate("moderation/clearwarns:DESCRIPTION", null, "uk-UA"),
ru: client.translate("moderation/clearwarns:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages)
.addUserOption(option =>
option
@ -40,7 +39,6 @@ class Clearwarns extends BaseCommand {
*/
async execute(client, interaction) {
const member = interaction.options.getMember("user");
if (member.user.id === interaction.user.id) return interaction.error("misc:CANT_YOURSELF");
const memberData = await client.getMemberData(member.id, interaction.guildId);

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
ms = require("ms");
@ -16,8 +16,7 @@ class Giveaway extends BaseCommand {
uk: client.translate("moderation/giveaway:DESCRIPTION", null, "uk-UA"),
ru: client.translate("moderation/giveaway:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages)
.addSubcommand(subcommand =>
subcommand

119
commands/Moderation/poll.js Normal file
View file

@ -0,0 +1,119 @@
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Poll extends BaseCommand {
/**
*
* @param {import("../../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("poll")
.setDescription(client.translate("moderation/poll:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("moderation/poll:DESCRIPTION", null, "uk-UA"),
ru: client.translate("moderation/poll:DESCRIPTION", null, "ru-RU"),
})
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages)
.addStringOption(option =>
option
.setName("question")
.setDescription(client.translate("moderation/poll:QUESTION"))
.setDescriptionLocalizations({
uk: client.translate("moderation/poll:QUESTION", null, "uk-UA"),
ru: client.translate("moderation/poll:QUESTION", null, "ru-RU"),
})
.setRequired(true),
),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
const question = interaction.options.getString("question");
const row = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId("poll_everyone").setLabel("@everyone").setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId("poll_here").setLabel("@here").setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId("poll_nothing").setLabel(interaction.translate("moderation/poll:NOTHING")).setStyle(ButtonStyle.Primary),
new ButtonBuilder().setCustomId("poll_cancel").setLabel(interaction.translate("common:CANCEL")).setStyle(ButtonStyle.Danger),
);
await interaction.reply({
content: interaction.translate("moderation/poll:SELECT_MENTION"),
ephemeral: true,
components: [row],
});
let mention = null;
const filter = i => i.user.id === interaction.user.id;
const collector = interaction.channel.createMessageComponentCollector({ filter, idle: 15 * 1000 });
collector.on("collect", async i => {
if (i.isButton()) {
if (i.customId === "poll_everyone") {
mention = "||@everyone||";
i.update({
content: interaction.translate("moderation/poll:POLL_SENDED"),
components: [],
});
} else if (i.customId === "poll_here") {
mention = "||@here||";
i.update({
content: interaction.translate("moderation/poll:POLL_SENDED"),
components: [],
});
} else if (i.customId === "poll_nothing") {
mention = null;
i.update({
content: interaction.translate("moderation/poll:POLL_SENDED"),
components: [],
});
} else if (i.customId === "poll_cancel") {
return i.update({
content: interaction.translate("misc:SELECT_CANCELED"),
components: [],
});
}
const cool = client.emojis.cache.find(e => e.name === client.customEmojis.cool.split(":")[1]);
const notcool = client.emojis.cache.find(e => e.name === client.customEmojis.notcool.split(":")[1]);
const embed = client.embed({
author: interaction.translate("moderation/poll:TITLE"),
fields: [
{
name: "\u200B",
value: question,
},
{
name: "\u200B",
value: interaction.translate("moderation/poll:REACT", {
success: cool.toString(),
error: notcool.toString(),
}),
},
],
});
return interaction.channel.send({
content: mention,
embeds: [embed],
}).then(async m => {
await m.react(cool);
await m.react(notcool);
});
}
});
}
}
module.exports = Poll;

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Unban extends BaseCommand {
@ -15,8 +15,7 @@ class Unban extends BaseCommand {
uk: client.translate("moderation/unban:DESCRIPTION", null, "uk-UA"),
ru: client.translate("moderation/unban:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages)
.addStringOption(option =>
option

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Ban extends BaseCommand {
@ -15,8 +15,7 @@ class Ban extends BaseCommand {
uk: client.translate("moderation/untimeout:DESCRIPTION", null, "uk-UA"),
ru: client.translate("moderation/untimeout:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ModerateMembers)
.addUserOption(option =>
option
@ -45,7 +44,7 @@ class Ban extends BaseCommand {
timedout = member.isCommunicationDisabled();
if (member.user.bot) return interaction.error("misc:BOT_USER", null, { ephemeral: true, edit: true });
if (member.id === interaction.member.id) return interaction.error("misc:CANT_YOURSELF", null, { ephemeral: true, edit: true });
if (member.id === interaction.member.id) return interaction.error("moderation/untimeout:YOURSELF", null, { ephemeral: true, edit: true });
if (!timedout) return interaction.error("moderation/untimeout:NOT_TIMEDOUT", null, { ephemeral: true, edit: true });
await member.timeout(null);

View file

@ -1,4 +1,4 @@
const { ContextMenuCommandBuilder, ModalBuilder, ActionRowBuilder, TextInputBuilder, ApplicationCommandType, PermissionsBitField, TextInputStyle, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { ContextMenuCommandBuilder, ModalBuilder, ActionRowBuilder, TextInputBuilder, ApplicationCommandType, PermissionsBitField, TextInputStyle } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class WarnContext extends BaseCommand {
@ -11,8 +11,7 @@ class WarnContext extends BaseCommand {
command: new ContextMenuCommandBuilder()
.setName("Give Warn")
.setType(ApplicationCommandType.User)
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages),
dirname: __dirname,
ownerOnly: false,
@ -30,7 +29,7 @@ class WarnContext extends BaseCommand {
moderationPosition = interaction.member.roles.highest.position;
if (member.user.bot) return interaction.error("misc:BOT_USER", null, { ephemeral: true });
if (member.id === interaction.member.id) return interaction.error("misc:CANT_YOURSELF", null, { ephemeral: true });
if (member.id === interaction.member.id) return interaction.error("moderation/warn:YOURSELF", null, { ephemeral: true });
if (interaction.guild.ownerId !== interaction.member.id && !(moderationPosition > memberPosition)) return interaction.error("moderation/warn:SUPERIOR", null, { ephemeral: true });
const memberData = await client.getMemberData(member.id, interaction.guildId);
@ -67,6 +66,11 @@ class WarnContext extends BaseCommand {
if (submitted) {
const reason = submitted.fields.getTextInputValue("warn_reason");
// const sanctions = memberData.sanctions.filter(s => s.type === "warn").length;
// const banCount = data.guildData.plugins.warnsSanctions.ban;
// const kickCount = data.guildData.plugins.warnsSanctions.kick;
const caseInfo = {
moderator: interaction.member.id,
date: Date.now(),
@ -93,6 +97,67 @@ class WarnContext extends BaseCommand {
],
});
/*
if (banCount) {
if (sanctions >= banCount) {
member.send({
content: interaction.translate("moderation/ban:BANNED_DM", {
user: member.user,
moderator: interaction.user.getUsername(),
server: interaction.guild.name,
reason,
}),
});
caseInfo.type = "ban";
embed
.setAuthor({
name: interaction.translate("moderation/warn:BAN"),
})
.setColor(client.config.embed.color);
interaction.guild.members.ban(member).catch(() => {});
interaction.followUp({
content: interaction.translate("moderation/setwarns:AUTO_BAN", {
user: member.user.getUsername(),
count: `${banCount} ${client.functions.getNoun(banCount, interaction.translate("misc:NOUNS:WARNS:1"), interaction.translate("misc:NOUNS:WARNS:2"), interaction.translate("misc:NOUNS:WARNS:5"))}`,
}),
});
}
}
if (kickCount) {
if (sanctions >= kickCount) {
member.send({
content: interaction.translate("moderation/kick:KICKED_DM", {
user: member.user,
moderator: interaction.user.getUsername(),
server: interaction.guild.name,
reason,
}),
});
caseInfo.type = "kick";
embed
.setAuthor({
name: interaction.translate("moderation/warn:KICK"),
})
.setColor(client.config.embed.color);
member.kick().catch(() => {});
interaction.followUp({
content: interaction.translate("moderation/setwarns:AUTO_KICK", {
user: member.user.getUsername(),
count: `${kickCount} ${client.functions.getNoun(kickCount, interaction.translate("misc:NOUNS:WARNS:1"), interaction.translate("misc:NOUNS:WARNS:2"), interaction.translate("misc:NOUNS:WARNS:5"))}`,
}),
});
}
} */
try {
await member.send({
content: interaction.translate("moderation/warn:WARNED_DM", {

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Warns extends BaseCommand {
@ -15,8 +15,7 @@ class Warns extends BaseCommand {
uk: client.translate("moderation/warns:DESCRIPTION", null, "uk-UA"),
ru: client.translate("moderation/warns:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages)
.addUserOption(option =>
option

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Back extends BaseCommand {
@ -15,8 +15,7 @@ class Back extends BaseCommand {
uk: client.translate("music/back:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/back:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild]),
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js"),
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js"),
{ QueryType } = require("discord-player");
const BaseCommand = require("../../base/BaseCommand"),
fs = require("fs");
@ -17,8 +17,7 @@ class Clips extends BaseCommand {
uk: client.translate("music/clips:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/clips:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addStringOption(option =>
option
.setName("query")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js"),
const { SlashCommandBuilder } = require("discord.js"),
{ QueueRepeatMode } = require("discord-player");
const BaseCommand = require("../../base/BaseCommand");
@ -16,8 +16,7 @@ class Loop extends BaseCommand {
uk: client.translate("music/loop:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/loop:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addStringOption(option =>
option
.setName("option")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js"),
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder, StringSelectMenuOptionBuilder } = require("discord.js"),
{ QueueRepeatMode } = require("discord-player");
const BaseCommand = require("../../base/BaseCommand");
@ -16,8 +16,7 @@ class Nowplaying extends BaseCommand {
uk: client.translate("music/nowplaying:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/nowplaying:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild]),
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});

View file

@ -1,4 +1,4 @@
const { ContextMenuCommandBuilder, ApplicationCommandType, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { ContextMenuCommandBuilder, ApplicationCommandType, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class PlayContext extends BaseCommand {
@ -11,8 +11,7 @@ class PlayContext extends BaseCommand {
command: new ContextMenuCommandBuilder()
.setName("Add to Queue")
.setType(ApplicationCommandType.Message)
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild]),
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});
@ -41,6 +40,8 @@ class PlayContext extends BaseCommand {
});
if (!searchResult.hasTracks()) {
console.log(searchResult);
return interaction.error("music/play:NO_RESULT", { query }, { edit: true });
} else {
await client.player.play(voice, searchResult, {

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js"),
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js"),
{ QueryType } = require("discord-player");
const BaseCommand = require("../../base/BaseCommand");
@ -16,8 +16,7 @@ class Play extends BaseCommand {
uk: client.translate("music/play:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/play:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addStringOption(option =>
option
.setName("query")
@ -50,11 +49,14 @@ class Play extends BaseCommand {
if (!perms.has(PermissionsBitField.Flags.Connect) || !perms.has(PermissionsBitField.Flags.Speak)) return interaction.error("music/play:VOICE_CHANNEL_CONNECT", null, { edit: true });
const searchResult = await client.player.search(query, {
requestedBy: interaction.member,
requestedBy: interaction.user,
});
if (!searchResult.hasTracks()) return interaction.error("music/play:NO_RESULT", { query }, { edit: true, ephemeral: true });
else {
if (!searchResult.hasTracks()) {
console.log(searchResult);
return interaction.error("music/play:NO_RESULT", { query }, { edit: true });
} else {
await client.player.play(voice, searchResult, {
nodeOptions: {
metadata: interaction,
@ -83,8 +85,7 @@ class Play extends BaseCommand {
*/
async autocompleteRun(client, interaction) {
const query = interaction.options.getString("query");
if (query === "" || query === null) return interaction.respond([ { name: "No Query Provided", value: "" } ]);
if (query.startsWith("http")) return interaction.respond([ { name: "Current Link", value: query } ]);
if (query === "" || query === null) return;
const youtubeResults = await client.player.search(query, { searchEngine: QueryType.YOUTUBE });
const spotifyResults = await client.player.search(query, { searchEngine: QueryType.SPOTIFY_SEARCH });

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, ActionRowBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, ButtonBuilder, ButtonStyle, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, ActionRowBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Queue extends BaseCommand {
@ -15,8 +15,7 @@ class Queue extends BaseCommand {
uk: client.translate("music/queue:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/queue:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild]),
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Seek extends BaseCommand {
@ -15,8 +15,6 @@ class Seek extends BaseCommand {
uk: client.translate("music/seek:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/seek:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.addIntegerOption(option =>
option
.setName("time")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Shuffle extends BaseCommand {
@ -15,8 +15,7 @@ class Shuffle extends BaseCommand {
uk: client.translate("music/shuffle:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/shuffle:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild]),
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Skip extends BaseCommand {
@ -15,8 +15,7 @@ class Skip extends BaseCommand {
uk: client.translate("music/skip:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/skip:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addIntegerOption(option =>
option
.setName("position")
@ -24,7 +23,8 @@ class Skip extends BaseCommand {
.setDescriptionLocalizations({
uk: client.translate("music/skip:POSITION", null, "uk-UA"),
ru: client.translate("music/skip:POSITION", null, "ru-RU"),
}),
})
.setRequired(false),
),
dirname: __dirname,
ownerOnly: false,

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Stop extends BaseCommand {
@ -15,8 +15,7 @@ class Stop extends BaseCommand {
uk: client.translate("music/stop:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/stop:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild]),
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Volume extends BaseCommand {
@ -15,8 +15,7 @@ class Volume extends BaseCommand {
uk: client.translate("music/volume:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/volume:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addIntegerOption(option =>
option
.setName("int")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, ActionRowBuilder, StringSelectMenuBuilder, AttachmentBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, ActionRowBuilder, StringSelectMenuBuilder, AttachmentBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
fetch = require("node-fetch");
@ -16,8 +16,7 @@ class NSFW extends BaseCommand {
uk: client.translate("nsfw/nsfw:DESCRIPTION", null, "uk-UA"),
ru: client.translate("nsfw/nsfw:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild]),
.setDMPermission(true),
dirname: __dirname,
ownerOnly: false,
});
@ -39,7 +38,7 @@ class NSFW extends BaseCommand {
const tag = interaction?.values[0],
splitted = tag.split("_"),
res = await fetch(`https://nsfw-api.jonnybro.ru/media/${splitted[0].charAt(0).toLowerCase()}/${splitted[1].toLowerCase()}`).then(async r => await r.buffer()),
res = await fetch(`https://nsfw-api.jababot.ru/media/${splitted[0].charAt(0).toLowerCase()}/${splitted[1].toLowerCase()}`).then(async r => await r.buffer()),
image = new AttachmentBuilder(res, { name: "image.jpeg" });
const embed = client.embed({

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Debug extends BaseCommand {
@ -15,8 +15,7 @@ class Debug extends BaseCommand {
uk: client.translate("owner/debug:DESCRIPTION", null, "uk-UA"),
ru: client.translate("owner/debug:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addSubcommand(subcommand =>
subcommand
.setName("set")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Eval extends BaseCommand {
@ -15,8 +15,7 @@ class Eval extends BaseCommand {
uk: client.translate("owner/eval:DESCRIPTION", null, "uk-UA"),
ru: client.translate("owner/eval:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.setDMPermission(true)
.addStringOption(option =>
option
.setName("code")

View file

@ -1,6 +1,7 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
i18next = require("i18next");
// autoUpdateDocs = require("../../helpers/autoUpdateDocs");
class Reload extends BaseCommand {
/**
@ -16,8 +17,7 @@ class Reload extends BaseCommand {
uk: client.translate("owner/reload:DESCRIPTION", null, "uk-UA"),
ru: client.translate("owner/reload:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild])
.setDMPermission(true)
.addStringOption(option =>
option
.setName("command")
@ -40,21 +40,19 @@ class Reload extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply({ ephemeral: true });
const command = interaction.options.getString("command"),
cmd = client.commands.get(command);
if (!cmd) return interaction.error("owner/reload:NOT_FOUND", { command }, { ephemeral: true });
client.unloadCommand(`../commands/${cmd.category}`, cmd.command.name);
await client.unloadCommand(`../commands/${cmd.category}`, cmd.command.name);
await client.loadCommand(`../commands/${cmd.category}`, cmd.command.name);
i18next.reloadResources(["ru-RU", "uk-UA", "en-US"]);
// autoUpdateDocs.update(client);
interaction.success("owner/reload:SUCCESS", {
command: cmd.command.name,
}, { edit: true });
}, { ephemeral: true });
}
/**

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Say extends BaseCommand {
@ -15,8 +15,7 @@ class Say extends BaseCommand {
uk: client.translate("owner/say:DESCRIPTION", null, "uk-UA"),
ru: client.translate("owner/say:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.addStringOption(option =>
option
.setName("message")

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Servers extends BaseCommand {
@ -15,8 +15,7 @@ class Servers extends BaseCommand {
uk: client.translate("owner/servers:DESCRIPTION", null, "uk-UA"),
ru: client.translate("owner/servers:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])
.setContexts([InteractionContextType.BotDM, InteractionContextType.PrivateChannel, InteractionContextType.Guild]),
.setDMPermission(true),
dirname: __dirname,
ownerOnly: true,
});
@ -31,7 +30,7 @@ class Servers extends BaseCommand {
await interaction.deferReply({ ephemeral: true });
let currentPage = 0;
const embeds = generateGuildsEmbeds(interaction, client.guilds.cache);
const embeds = generateServersEmbeds(interaction, client.guilds.cache);
const row = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId("servers_prev_page").setStyle(ButtonStyle.Primary).setEmoji("⬅️"),
@ -94,15 +93,15 @@ class Servers extends BaseCommand {
/**
*
* @param {import("discord.js").ChatInputCommandInteraction} interaction
* @param {Array[import("discord.js").Guild]} guilds
* @param {Array} servers
* @returns
*/
function generateGuildsEmbeds(interaction, guilds) {
function generateServersEmbeds(interaction, servers) {
const embeds = [];
let k = 10;
for (let i = 0; i < guilds.size; i += 10) {
const current = guilds
for (let i = 0; i < servers.size; i += 10) {
const current = servers
.sort((a, b) => b.memberCount - a.memberCount)
.map(g => g)
.slice(i, k);
@ -111,9 +110,9 @@ function generateGuildsEmbeds(interaction, guilds) {
const info = current
.map(
guild =>
`${++j}. ${guild.name} (${guild.id}) | ${guild.memberCount} ${interaction.client.functions.getNoun(
guild.memberCount,
server =>
`${++j}. ${server.name} | ${server.memberCount} ${interaction.client.functions.getNoun(
server.memberCount,
interaction.translate("misc:NOUNS:MEMBERS:1"),
interaction.translate("misc:NOUNS:MEMBERS:2"),
interaction.translate("misc:NOUNS:MEMBERS:5"),

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class AddUser extends BaseCommand {
@ -15,8 +15,7 @@ class AddUser extends BaseCommand {
uk: client.translate("tickets/adduser:DESCRIPTION", null, "uk-UA"),
ru: client.translate("tickets/adduser:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages)
.addUserOption(option =>
option

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, ButtonBuilder, ButtonStyle, ActionRowBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField, ButtonBuilder, ButtonStyle, ActionRowBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class CloseTicket extends BaseCommand {
@ -15,8 +15,7 @@ class CloseTicket extends BaseCommand {
uk: client.translate("tickets/closeticket:DESCRIPTION", null, "uk-UA"),
ru: client.translate("tickets/closeticket:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages),
dirname: __dirname,
ownerOnly: false,

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, ButtonBuilder, ButtonStyle, ActionRowBuilder, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField, ButtonBuilder, ButtonStyle, ActionRowBuilder, ChannelType } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class CreateTicketEmbed extends BaseCommand {
@ -15,14 +15,193 @@ class CreateTicketEmbed extends BaseCommand {
uk: client.translate("tickets/createticketembed:DESCRIPTION", null, "uk-UA"),
ru: client.translate("tickets/createticketembed:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageGuild),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
*/
async onLoad(client) {
client.on("interactionCreate", async interaction => {
if (!interaction.isButton()) return;
interaction.data = [];
interaction.data.guild = await client.getGuildData(interaction.guildId);
const button = interaction.component;
if (button.customId === "support_ticket") {
const guildData = interaction.data.guild,
ticketsCategory = guildData.plugins.tickets.ticketsCategory,
ticketLogs = guildData.plugins.tickets.ticketLogs;
if (interaction.guild.channels.cache.get(ticketsCategory).children.cache.size >= 50) {
const sorted = interaction.guild.channels.cache.get(ticketsCategory).children.cache.sort((ch1, ch2) => ch1.createdTimestamp - ch2.createdTimestamp);
await sorted.first().delete();
}
if (guildData.plugins.tickets.count === undefined) guildData.plugins.tickets.count = 0;
guildData.plugins.tickets.count++;
const channel = await interaction.guild.channels.create({
name: `${interaction.user.username}-support-${guildData.plugins.tickets.count}`,
topic: interaction.user.id,
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 = client.embed({
title: interaction.translate("tickets/createticketembed:TICKET_CREATED_TITLE"),
description: `${interaction.user.toString()} (${channel.toString()})`,
});
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 = client.embed({
author: {
name: interaction.user.getUsername(),
iconURL: interaction.user.displayAvatarURL(),
},
title: "Support Ticket",
description: interaction.translate("tickets/createticketembed:TICKET_CREATED_DESC"),
});
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 guildData.save();
await channel.send({ embeds: [embed], components: [row] });
} else if (button.customId === "close_ticket") {
const embed = client.embed({
title: interaction.translate("tickets/closeticket:CLOSING_TITLE"),
description: interaction.translate("tickets/closeticket:CLOSING_DESC"),
fields: [
{
name: interaction.translate("common:TICKET"),
value: interaction.channel.name,
},
{
name: interaction.translate("tickets/closeticket:CLOSING_BY"),
value: interaction.user.getUsername(),
},
],
});
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),
messages = Array.from(reversedMessages.values()).reverse(),
transcriptionLogs = interaction.data.guild.plugins.tickets.transcriptionLogs,
ticketLogs = interaction.data.guild.plugins.tickets.ticketLogs;
if (messages.length > 1) {
let transcript = "---- TICKET CREATED ----\n";
messages.forEach(message => {
transcript += `[${client.functions.printDate(client, message.createdTimestamp, null, interaction.getLocale())}] ${message.author.getUsername()}: ${message.content}\n`;
});
transcript += "---- TICKET CLOSED ----\n";
if (transcriptionLogs !== null) 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` }] });
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) {
interaction.followUp({ content: interaction.translate("misc:CANT_DM"), ephemeral: true });
}
}
const logChannel = interaction.guild.channels.cache.get(ticketLogs);
const logEmbed = client.embed({
title: interaction.translate("tickets/createticketembed:TICKET_CLOSED_TITLE"),
description: `${interaction.user.toString()} (${interaction.channel.toString()})`,
});
logChannel.send({ embeds: [logEmbed] });
interaction.channel.send("Closed!");
const member = interaction.guild.members.cache.find(u => u.user.id === interaction.channel.topic);
await interaction.channel.permissionOverwrites.edit(member, { ViewChannel: false, SendMessages: null });
await interaction.channel.setName(`${interaction.channel.name}-closed`);
}
});
} else 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();
if (messages.length > 1) {
let transcript = "---- TICKET CREATED ----\n";
messages.forEach(message => {
transcript += `[${client.functions.printDate(client, message.createdTimestamp, null, interaction.getLocale())}] ${message.author.getUsername()}: ${message.content}\n`;
});
transcript += "---- TICKET CLOSED ----\n";
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) {
interaction.followUp({ content: interaction.translate("misc:CANT_DM"), ephemeral: true });
}
} else return;
}
});
}
/**
*
* @param {import("../../base/Client")} client

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, PermissionsBitField, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const { SlashCommandBuilder, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class RemoveUser extends BaseCommand {
@ -15,8 +15,7 @@ class RemoveUser extends BaseCommand {
uk: client.translate("tickets/removeuser:DESCRIPTION", null, "uk-UA"),
ru: client.translate("tickets/removeuser:DESCRIPTION", null, "ru-RU"),
})
.setIntegrationTypes([ApplicationIntegrationType.GuildInstall])
.setContexts([InteractionContextType.Guild])
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages)
.addUserOption(option =>
option

View file

@ -0,0 +1,91 @@
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"),
fetch = require("node-fetch");
class Courses extends BaseCommand {
/**
*
* @param {import("../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("courses")
.setDescription(client.translate("beatrun.ru/courses:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("beatrun.ru/courses:DESCRIPTION", null, "uk-UA"),
ru: client.translate("beatrun.ru/courses:DESCRIPTION", null, "ru-RU"),
})
.setDMPermission(false)
.addStringOption(option =>
option
.setName("code")
.setDescription(client.translate("common:CODE"))
.setDescriptionLocalizations({
uk: client.translate("common:CODE", null, "uk-UA"),
ru: client.translate("common:CODE", null, "ru-RU"),
})
.setRequired(true),
),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
* @param {Object} data
*/
async execute(client, interaction) {
await interaction.deferReply();
const code = interaction.options.getString("code");
const response = await fetch(`https://courses.jonnybro.ru/api/info/${code}`).then(res => res.json());
const course = response.data;
if (response.res === 401) return interaction.error("beatrun.ru/courses:NOT_FOUND", null, { ephemeral: true, edit: true });
const embed = client.embed({
title: code,
description: `[${interaction.translate("beatrun.ru/courses:DOWNLOAD")}](https://courses.jonnybro.ru/${course.path})`,
thumbnail: course.mapimg,
url: `https://courses.beatrun.ru/?search=${code}`,
fields: [
{
name: interaction.translate("beatrun.ru/courses:MAP"),
value: `[${course.map}](https://steamcommunity.com/sharedfiles/filedetails/?id=${course.mapid})`,
inline: true,
},
{
name: interaction.translate("beatrun.ru/courses:UPLOADER"),
value: `[${course.uploader.name || course.uploader.userid}](https://steamcommunity.com/profiles/${course.uploader.userid})`,
inline: true,
},
{
name: "\u200B",
value: "\u200B",
inline: true,
},
{
name: interaction.translate("beatrun.ru/courses:DATE"),
value: `<t:${Math.floor(course.time / 1000)}:D>`,
inline: true,
},
{
name: interaction.translate("beatrun.ru/courses:PLAYS"),
value: `${course.plays || 0}`,
inline: true,
},
],
});
interaction.editReply({
embeds: [embed],
});
}
}
module.exports = Courses;

View file

@ -13,8 +13,6 @@ module.exports = {
clientId: "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
clientSecret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
},
/* YouTube Cookie */
youtubeCookie: "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
/* Support server */
support: {
id: "123456789098765432", // The ID of the support server
@ -43,6 +41,6 @@ module.exports = {
},
/* Add your own API keys here */
apiKeys: {
shlink: "12345678-1234-1234-1234-123456789098" /* Shlink.io REST API key */,
shlink: "12345678-1234-1234-1234-123456789098", /* Shlink.io REST API key */
},
};

8
dashboard/.env.example Normal file
View file

@ -0,0 +1,8 @@
BOT_CLIENT_ID="<YOUR_BOT_CLIENT_ID>"
BOT_CLIENT_SECRET="<YOUR_BOT_CLIENT_SECRET>"
# The absolute url of the dashboard (Production)
APP_URL="http://localhost:3000"
# The absolute url of the api endpoint of your bot (Production)
NEXT_PUBLIC_API_ENDPOINT="http://localhost:8080"

3
dashboard/.eslintrc.json Normal file
View file

@ -0,0 +1,3 @@
{
"extends": ["next/core-web-vitals", "prettier"]
}

37
dashboard/.gitignore vendored Normal file
View file

@ -0,0 +1,37 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

213
dashboard/README.md Normal file
View file

@ -0,0 +1,213 @@
# Discord Bot Dashboard Template
> Forked from [here](https://github.com/FileEditor97/discord-bot-dashboard)
Using Typescript, Next.js 13, React 18 and Chakra ui 2.0
- Support Light/Dark theme
- Multi languages support (i18n)
- Typescript support
- Nice UI & UX + Fast performance
- Flexiable and Customizable
- Detailed Documentation
**Video:** <https://youtu.be/IdMPjT5PzVk>\
**Live Demo:** <https://demo-bot.vercel.app>
- Only 'Welcome message' Feature is Supported
## Review (not the latest version)
| Light | Dark |
| :--------------------------------------: | :------------------------------------: |
| ![light-mode](./document/home-light.png) | ![dark-mode](./document/home-dark.png) |
## Getting Started
As a template, you need to customize a few things in order to get it work
### Before that
- Install Node.js, and a Package Manager (ex: npm or pnpm)
### Required Skills
- Basic knowledge about React.js
- Able to read javascript/typescript
### Set up
1. **Clone the repo**
\
`git clone https://github.com/fuma_nama/discord-bot-dashboard-next.git`
2. **Install dependencies**
\
We always prefer [`PNpm`](https://pnpm.io)
| NPM | PNPM |
| :-----------: | :------------: |
| `npm install` | `pnpm install` |
3. **Customize files**
\
The file structure of this project
| Path | Description |
| ------------------------------------- | ------------- |
| [src/pages/\*](./src/pages) | All the pages |
| [src/components/\*](./src/components) | Components |
| [src/api/\*](./src/api) | API utils |
| [src/config/\*](./src/api) | Common configurations |
4. **Define Features**
\
The dashboard has built-in support for configuring features
\
Users are able to enable/disable features and config the feature after enabling it
**Customize all typings in [src/config/types/custom-types.ts](./src/config/types/custom-types.ts)**
\
`CustomFeatures` is used for defining features and options, see the example for more details
**Open [src/config/features](./src/config/features.tsx)**
\
You can see how a feature is configured
```tsx
'feature-id': {
name: 'Feature name',
description: 'Description about this feature',
icon: <Icon as={BsMusicNoteBeamed} />, //give it a cool icon
useRender: (data) => {
//render the form
},
}
```
The `useRender` property is used to render Feature Configuration Panel \
Take a look at [here](./src/config/example/WelcomeMessageFeature.tsx) for examples
5. **Configure General Information**
\
Modify [src/config/common.tsx](./src/config/common.tsx)
- Bot name & icon
- Invite url _(example: <https://discord.com/oauth2/authorize?client_id=1234&scope=bot>)_
- Guild settings
6. **Configure Environment variables**
\
Those variables in [.env.example](./.env.example) are required
\
You can define environment variables by creating a `.env` file
7. **Setup Backend Server**
\
In order to let the dashboard connected with your discord bot, you will need a backend server
\
You can implement it in any programming languages
Read [here](#backend-development) for a guide to develop your own server
8. **Done!**
\
Start the app by `pnpm run dev` _(depends on your package manager)_
\
Then you should see the app started in port `3000`
[Localization](./document/localization.md) | [Forms](./document/form.md)
## Authorization
We are using the [API Routes](https://nextjs.org/docs/api-routes/introduction) of Next.js to handle Authorization
### Configure the Application
1. Open Discord Developer Portal
2. Create your OAuth2 application in <https://discord.com/developers/applications>
3. In `<Your Application>` -> OAuth2 -> Redirects
Add `<APP_URL>/api/auth/callback` url to the redirects
For Example: `http://localhost:3000/api/auth/callback` \
**This is required for Authorization**
### Authorization Flow
**`Login -> Discord OAuth -> API Routes -> Client`**
- Login (`/api/auth/login`)
\
- Redirects user to discord oauth url
- Open Discord OAuth url
- User authorizes the application
- Redirect back to `/api/auth/callback`
- API Routes
- Store the access token in http-only cookies
- Redirect back to home page
### Token Expiration
The Discord access token can be expired or unauthorized by the user \
We will require the user to login again after getting `401` error from the Discord API
The refresh token won't be used, but you are able to customize the Authorization Flow
## Backend Development
Check [src/api/bot.ts](./src/api/bot.ts), it defined a built-in API for fetching data
You can use `express.js` (Node.js), `Rocket` (Rust) or any libraries/languages to develop your own server
\
Usually the server runs along with your discord bot (in the same program)
\
Moreover, you can use redis instead of connecting to the bot server directly
### Official Example
[Node.js (Typescript)](https://github.com/fuma-nama/discord-dashboard-backend-next)
### Authorization Header
The client will pass their access token via the `Authorization` header
`Bearer MY_TOKEN_1212112`
### Required Routes
You may extend it for more functions
GET `/guilds/{guild}`
- Get guild info (`custom-types.ts > CustomGuildInfo`)
- **Respond 404 or `null` if bot hasn't joined the guild**
GET `/guilds/{guild}/features/{feature}`
- Get Feature options (`custom-types.ts > CustomFeatures[K]`)
- **Respond 404 if not enabled**
PATCH `/guilds/{guild}/features/{feature}`
- Update feature options
- With custom body (defined in `config/features`)
- Respond updated feature options
POST `/guilds/{guild}/features/{feature}`
- Enable a feature
DELETE `/guilds/{guild}/features/{feature}`
- Disable a feature
GET `/guilds/{guild}/roles`
- Get Roles of the guild
- Responds a list of [Role Object](https://discord.com/developers/docs/topics/permissions#role-object) _(Same as discord documentation)_
GET `/guilds/{guild}/channels`
- Get Channels of the guild
- Responds a list of [Guild Channel](https://discord.com/developers/docs/resources/channel#channel-object) _(Same as discord documentation)_
## Any issues?
Feel free to ask a question by opening a issue
**Love this project?** Give this repo a star!

@ -1 +0,0 @@
Subproject commit 42cb44000f844f17b0d9e12e15a45ab60f3dcdb7

View file

@ -0,0 +1,31 @@
# The `useForm` hook
We are using [`react-hook-form`](https://react-hook-form.com/) for forms, including feature configuration or settings page
## Built-in Components
There're some common components such as `<FilePicker />` in the [src/components/forms/\*](./src/components/forms) folder
## Controller
We add `useController` into custom components so as to provides better code quality
Therefore, You don't have to wrap the inputs into the `<Controller />` component
For example, the Color picker & Switch field can be used in this way
```tsx
<ColorPickerForm
control={{
label: 'Color',
description: 'The color of message',
}}
controller={{ control, name: 'color' }} //from the useForm hook
/>
```
[Learn More](https://react-hook-form.com/api/usecontroller/)
## Example
Take a look at [here](./src/config/example/WelcomeMessageFeature.tsx) for examples

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Some files were not shown because too many files have changed in this diff Show more