advancedhandler
Version:
Advanced DiscordJS Handler
1,147 lines (994 loc) • 45.1 kB
JavaScript
const EventEmitter = require('events');
const getAllFiles = require('./get-all-files');
const DiscordJS = require('discord.js');
const path = require('path');
const fs = require('fs');
const mongoose = require('mongoose');
const mongo = require('./mongo');
const ms = require('ms');
const registerCommand = require('./registerCommand');
const moment = require('moment')
require('moment-duration-format')
const reqRolesSchema = require('./models/required-roles-schema');
const cooldownSchema = require('./models/cooldown-schema');
const langSchema = require('./models/language-schema');
const prefixSchema = require('./models/prefix-schema');
const disableCommandsSchema = require('./models/command-schema');
const channelSchema = require('./models/channel-schema');
const statsSchema = require('./models/stats-schema');
const blacklistSchema = require('./models/blacklist-schema');
/**
* @constructor
* @param {DiscordJS.Client} client - DiscordJS Client
* @param {object} options - CommandHandler options
* @returns
*/
class CommandHandler extends EventEmitter {
constructor(client, options = {}) {
super()
if (!client) throw new TypeError(`AdvancedHandler > No client specified`);
this.path = path;
this.client = client;
this.commandsDir = options.commandsDir;
this.defaultPrefix = options.defaultPrefix;
this.defaultLang = options.defaultLang || options.defaultLanguage || "en"
this.mongoURI = options.mongoURI;
this.ignoreBots = options.ignoreBots || true;
this.showWarns = options.showWarns || true;
this.disableCommands = options.disableDefaultCommands;
this.botOwners = options.botOwners;
this.testServers = options.testServers;
this.messagesPath = options.messagesPath || path.join(__dirname, 'messages.json');
this.dbOptions = options.dbOptions;
this.sendMessageBlackList = options.sendMessageBlackList || false;
this.commands = new DiscordJS.Collection();
this.aliases = new DiscordJS.Collection();
this.categories = new DiscordJS.Collection();
this.categories.set('Uncategorized Commands', { name: "Uncategorized Commands", emoji: "❔", custom: false, hidden: false })
this.helpSettings = {};
this.categories.set("Help", { name: "Help", emoji: "❓", custom: false, hidden: false });
this.categories.set("Configuration", { name: "Configuration", emoji: "🔨", custom: false, hidden: false });
this.categories.set("Statistics", { name: "Statistics", emoji: "📊", custom: false, hidden: false });
this.reqRolesSchema = reqRolesSchema;
this.cooldownSchema = cooldownSchema;
this.langSchema = langSchema;
this.prefixSchema = prefixSchema;
this.disableCommandsSchema = disableCommandsSchema;
this.channelSchema = channelSchema;
this.statsSchema = statsSchema;
this.blacklistSchema = blacklistSchema;
this.errorMessageDelete = options.errorMessageDelete || -1;
this.del = this.errorMessageDelete;
this.disableCommandWhenException = options.disableCommandWhenException || false;
this.syntaxErrorTypes = ["MIN_ARGS", "MAX_ARGS", "REQUIRED_PARAM"];
if (this.showWarns === true) {
if (!this.commandsDir) this.commandsDir = "commands", console.warn("AdvancedHandler > No commands dir specified. Using \"commands\".");
if (!this.mongoURI) console.warn("AdvancedHandler > No mongoDB connection uri. Some features don\'t work!");
}
if (fs.existsSync(this.commandsDir)) {
let files = getAllFiles(path.join(require.main.path, this.commandsDir));
let amount = files.length;
if (!amount <= 0) {
console.log("AdvancedHandler > Loaded " + amount + " command" + (amount === 1 ? "" : "s") + ".");
}
for (let _c = 0, files_1 = files; _c < files_1.length; _c++) {
let _d = files_1[_c], file = _d[0], fileName = _d[1];
registerCommand(`${file}`, fileName, this, this.disableCommands);
}
const defaultFiles = getAllFiles(path.join(__dirname, 'commands'));
for (let i = 0; i < defaultFiles.length; i++) {
registerCommand(defaultFiles[i][0], defaultFiles[i][1], this, this.disableCommands);
}
} else throw new Error('Commands directory "' + this.commandsDir + '" doesn\'t exist!');
}
////////////////////
async run() {
mongo(this.mongoURI, this.dpOptions, this)
this.categories.forEach((category) => {
this.categories.commands = this.commands.filter((c) => c.category == category.name);
return;
})
let client = this.client;
client.on('message', async message => {
let prefix = await this.getPrefix(message.guild)
if (!message.content.startsWith(prefix)) return;
let content = message.content;
const args = content.slice(prefix.length).trim().split(/ +/);
let firstElement = args.shift().toLocaleLowerCase();
let isCmdHas = this.isCommandHas(firstElement)
if (!isCmdHas) return;
const command = this.getCommand(firstElement);
let error = command.error;
if (await this.isUserInBlacklist(message.author.id) && this.isDbConnected()) {
if (error) {
return await error({ error: "USER_IN_BLACKLIST", message, command, info: message.member, instance: this, guild: message.guild })
} else if (this.sendMessageBlackList) return message.reply(await this.getMessage(message.guild, "USER_IN_BLACKLIST")).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete()
}, this.del)
} else { return }
})
else return;
}
if (command.guildOnly && !message.guild) {
if (error) {
return await error({ error: "GUILD_ONLY_COMMAND", message, command, info: null, instance: this, guild: message.guild })
} else return message.reply(await this.getMessage(message.guild, "GUILD_ONLY_COMMAND")).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete()
}, this.del)
} else { return }
})
}
if (message.guild && this.isDbConnected()) {
if (await this.isCommandDisabled(message.guild, command.name)) {
if (error) {
return await error({ error: "COMMAND_DISABLED", message, command, info: command, instance: this, guild: message.guild })
} else return message.reply(await this.getMessage(message.guild, "COMMAND_DISABLED")).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete()
}, this.del)
} else { return }
})
}
if (await this.isChannelDisabled(message.guild, command.name, message.channel)) {
if (error) {
return await error({ error: "CHANNEL_DISABLED", message, command, info: message.channel, instance: this, guild: message.guild })
} else return message.reply(await this.getMessage(message.guild, "CHANNEL_DISABLED")).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete()
}, this.del)
} else { return }
})
}
}
if (message.guild) {
if (command.testOnly && this.testServers) {
let isGuildTest = false;
if (this.testServers === message.guild.id || this.testServers.includes(message.guild.id)) isGuildTest = true;
if (!isGuildTest) {
if (error) {
return await error({ error: "TEST_ONLY", message, command, info: message.guild ? message.guild : "dm", instance: this, guild: message.guild })
} else return message.reply(await this.getMessage(message.guild, "TEST_ONLY")).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete()
}, this.del)
} else { return }
})
}
}
} else if (!message.guild && command.testOnly) {
if (error) {
return await error({ error: "TEST_ONLY", message, command, info: message.guild ? message.guild : "dm", instance: this, guild: message.guild })
} else return message.reply(await this.getMessage(message.guild, "TEST_ONLY")).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete()
}, this.del)
} else { return }
})
}
if (command.ownerOnly) {
let isOwner = false;
if (this.botOwners === message.author.id || this.botOwners.includes(message.author.id)) isOwner = true;
if (!isOwner) {
if (error) {
return await error({ error: "BOT_OWNERS_ONLY", message, command, info: message.member, instance: this, guild: message.guild })
} else return message.reply(await this.getMessage(message.guild, "BOT_OWNERS_ONLY")).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete()
}, this.del)
} else { return }
})
}
}
if (this.isDbConnected() && message.guild) {
const reqRoles = await reqRolesSchema.findOneAndUpdate({ guildId: message.guild.id, command: command.name }, { guildId: message.guild.id, command: command.name }, { upsert: true, new: true, setDefaultsOnInsert: true });
let roleResult = [];
if (reqRoles.requiredRoles) {
if (typeof reqRoles.requiredRoles === 'object') {
for (let i = 0; i < reqRoles.requiredRoles.length; i++) {
const role = reqRoles.requiredRoles[i];
if (!message.member.roles.cache.has(role)) {
roleResult = [role, true]
if (error) {
return await error({ error: "MISSING_ROLES", message, command, info: reqRoles.requiredRoles, instance: this, guild: message.guild })
} else return message.reply(await this.getMessage(message.guild, "MISSING_ROLES", {
ROLE: message.guild.roles.cache.get(roleResult[0]).name
})).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete()
}, this.del)
} else { return }
})
}
}
}
}
}
const permissions = command.requiredPermissions;
let permResult = [];
if (permissions && message.guild) {
for (let i = 0; i < permissions.length; i++) {
const perm = permissions[i];
if (!message.member.hasPermission(perm)) {
permResult = [perm, true]
if (error) {
return await error({ error: "MISSING_PERMISSION", message, command, info: permResult[perm], instance: this, guild: message.guild })
} else return message.reply(await this.getMessage(message.guild, "MISSING_PERMISSION", {
PERM: permResult[0]
})).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete()
}, this.del)
} else { return }
})
}
}
}
const requiredBotPermissions = command.requiredBotPermissions;
let permBotResult = [];
if (requiredBotPermissions && message.guild) {
for (let i = 0; i < requiredBotPermissions.length; i++) {
const perm = requiredBotPermissions[i];
if (!message.guild.me.hasPermission(perm)) {
permBotResult = [perm, true]
if (error) {
return await error({ error: "MISSING_BOT_PERMISSION", message, command, info: perm, instance: this, guild: message.guild })
} else return message.reply(await this.getMessage(message.guild, "MISSING_BOT_PERMISSION", {
PERM: permBotResult[0]
})).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete()
}, this.del)
} else { return }
})
}
}
}
let usage = command.usage;
let { params, minArgs, maxArgs } = usage
if (minArgs !== undefined && args.length < minArgs) {
if (error) {
return await error({ error: "SYNTAX_ERROR", message, command, info: args.join(" "), instance: this, guild: message.guild })
} else return message.reply(await this.createSyntaxError(message, command.name, minArgs - 1, "MIN_ARGS")).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete();
}, this.del)
} else return
})
} else if (maxArgs !== undefined && args.length > maxArgs) {
if (error) {
return await error({ error: "SYNTAX_ERROR", message, command, info: args.join(" "), instance: this, guild: message.guild })
} else return message.reply(await this.createSyntaxError(message, command.name, args.length, "MAX_ARGS")).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete();
}, this.del)
} else return
})
} else {
//
for (let i = 0; i < params.length; i++) {
const text = args[i];
const param = params[i]
if (!text) {
if (param.required == true) {
if (error) {
return await error({ error: "SYNTAX_ERROR", message, command, info: args.join(" "), instance: this, guild: message.guild })
} else return message.reply(await this.createSyntaxError(message, command.name, args.length, "REQUIRED_PARAM")).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete();
}, this.del)
} else return
})
} else {
break
}
}
}
// let minArgs = command.minArgs;
// let maxArgs = command.maxArgs || -1;
// if ((minArgs !== undefined && args.length < minArgs) ||
// (maxArgs !== undefined && maxArgs !== -1 && args.length > maxArgs)) {
// if (args.length < minArgs || args.length > maxArgs) {
// if (error) {
// return await error({ error: "SYNTAX_ERROR", message, command, info: args.join(" "), instance: this, guild: message.guild })
// } else return message.reply(await this.newSyntaxError(message.guild, command.name)).then(msg => {
// if (this.del !== -1) {
// setTimeout(() => {
// return msg.delete()
// }, this.del)
// } else { return }
// })
// }
// }
let commandCooldown = command.cooldown;
let globalCooldown = command.globalCooldown;
let userCooldown = command.userCooldown;
let now = Date.now();
if ((commandCooldown || globalCooldown || userCooldown) && this.isDbConnected()) {
let guildId = message.guild ? message.guild.id : "dm"
let cooldownResult;
if (commandCooldown) cooldownResult = await cooldownSchema.findOneAndUpdate({ _id: `${guildId}-${message.author.id}-${command.name}`, name: command.name }, { _id: `${guildId}-${message.author.id}-${command.name}` }, { upsert: true, new: true, setDefaultsOnInsert: true });
if (globalCooldown) cooldownResult = await cooldownSchema.findOneAndUpdate({ _id: `${guildId}-${command.name}`, name: command.name }, { _id: `${guildId}-${command.name}` }, { upsert: true, new: true, setDefaultsOnInsert: true });
if (userCooldown) cooldownResult = await cooldownSchema.findOneAndUpdate({ _id: `${message.author.id}-${command.name}`, name: command.name }, { _id: `${message.author.id}-${command.name}` }, { upsert: true, new: true, setDefaultsOnInsert: true });
if (cooldownResult) {
if (cooldownResult.cooldown > now) {
if (error) {
return await error({ error: "COOLDOWN", message, command, info: cooldownResult.cooldown, instance: this, guild: message.guild })
} else return message.reply(await this.getMessage(message.guild, "COOLDOWN", {
COOLDOWN: this.getLeftTime(cooldownResult.cooldown, now)
})).then(msg => {
if (this.del !== -1) {
setTimeout(() => {
msg.delete()
}, this.del)
} else { return }
})
} else {
this.setCooldown(message, command, now, {
type: commandCooldown ? "commandCooldown" : globalCooldown ? "globalCooldown" : "userCooldown"
})
}
}
}
const _callback = command.callback || command.run || command.execute
try {
_callback({
message,
channel: message.channel,
guild: message.guild,
args,
text: args.join(" "),
client,
prefix,
instance: this
})
} catch (e) {
if (error) {
return await error({ error: "EXCEPTION", message, command, info: e, instance: this, guild: message.guild })
} else {
console.error(e);
message.reply(await this.getMessage(message.guild, "EXCEPTION")).then(msg => {
if (this.disableCommandWhenException === true) {
this.commands.delete(command.name);
if (command.aliases) {
if (typeof command.aliases === 'object') {
command.aliases.forEach(item => {
this.aliases.delete(item)
})
} else if (typeof command.aliases === 'string') {
this.aliases.delete(command.aliases)
} else { return }
} else { return };
console.warn("An exception occured when using command \"" + command.name + "\"! Command was disabled.")
}
if (this.del !== -1) {
setTimeout(() => {
msg.delete()
}, this.del)
} else { return }
})
}
this.emit('commandException', command, message, e)
}
}
})
}
//Options
/**
*
* @param {boolean} ignoreBots
* @returns {CommandHandler}
*/
setIgnoreBots(ignoreBots) {
if (typeof ignoreBots !== 'boolean') throw new TypeError('Ignore bots must be boolean!');
this.ignoreBots = ignoreBots;
return this;
}
/**
*
* @param {boolean} showWarns
* @returns {CommandHandler}
*/
setShowWarns(showWarns) {
if (typeof showWarns !== 'boolean') throw new TypeError('Show warns must be boolean!');
this.showWarns = showWarns;
return this;
}
/**
*
* @param {Array<string>} servers
* @returns {CommandHandler}
*/
setTestServers(servers) {
if (typeof servers !== 'object') throw new TypeError('Test servers must be array!');
this.testServers = servers;
return this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//message
/**
*
* @param {string} path
* @returns {CommandHandler}
*/
setMessagesPath(path) {
if (!typeof path === 'string') throw new TypeError('Path must be string!');
this.messagesPath = path;
return this;
}
/**
* @param {DiscordJS.Guild} guild
* @param {string} messageID
* @param {object} options
* @returns {Promise<string>}
* @expamle
* await instance.getMessage(message.guild, "MESSAGE ID", {
* PREFIX: prefix
* })
*/
async getMessage(guild, messageID, options = {}) {
let result;
let lang = await this.getLanguage(guild);
if (typeof messageID !== 'string') throw new TypeError('messageID must be a string!');
const path = this.messagesPath;
const messagesPath = JSON.parse(fs.readFileSync(path, 'utf8'));
if (messageID.includes(".")) {
let m = messageID.split(".");
result = messagesPath[m[0]];
for (let i = 1; i < m.length; i++) {
let t = m[i];
result = result[t]
}
} else {
result = messagesPath[messageID];
}
result = result[lang];
for (let i = 0, a = Object.keys(options); i < a.length; i++) {
let key = a[i];
let expression = new RegExp("{" + key + "}", 'g');
result = result.replace(expression, options[key]);
}
if (!result) {
throw new Error("Unkown message ID!");
}
return result;
}
/**
* @param {DiscordJS.Message} message
* @param {string} command Command name
* @param {number} paramIndex
* @param {string} type
* @returns {string}
*
*/
async createSyntaxError(message, command, paramIndex, type) {
if (!message) throw new TypeError("Insufficient data for create syntax error!")
if (!command) throw new TypeError("Insufficient data for create syntax error!")
if (!paramIndex && paramIndex !== 0) throw new TypeError("Insufficient data for create syntax error!")
if (!type) throw new TypeError("Insufficient data for create syntax error!")
type = type.toLocaleUpperCase();
command = this.getCommand(command);
if (!command) return console.error("You can't create syntax error with unkown command!");
if (!this.syntaxErrorTypes.includes(type)) throw new Error("Unkown syntax error type!");
let ARGUMENTS = "";
command.usage.params.forEach((data) => {
if (data.required === true) {
ARGUMENTS += "[" + data.param + "] "
} else {
ARGUMENTS += "<" + data.param + "> "
}
return;
})
let err = await this.getMessage(message.guild, `SYNTAX_ERROR.${type}`, {
PARAM: command.usage.params[paramIndex].required === true ? `[${command.usage.params[paramIndex].param}]` : `<${command.usage.params[paramIndex].param}>`,
PREFIX: await this.getPrefix(message.guild),
COMMAND: command.name,
ARGUMENTS
})
return err;
}
// /**
// * @param {DiscordJS.Guild} guild
// * @param {string} command
// * @returns {Promise<string>}
// */
// async newSyntaxError(guild, command) {
// command = this.getCommand(command)
// if (!command) return console.error("You can't create syntax error with unkown command!")
// let text = await this.getMessage(guild, "SYNTAX_ERROR", {
// PREFIX: await this.getPrefix(guild),
// COMMAND: command.name,
// ARGUMENTS: command.expectedArgs || ""
// })
// return text;
// }
/////////////////////////////////////////////////////////////////////////////////////////////////
//Help
/**
*
* @param {object} settings - Help Settings
* @example
* {
embed: {
color: "RED",
withPages: true
},
authoritativePerms: [
"ADMINISTRATOR",
"KICK_MEMBERS",
"BAN_MEMBERS"
],
categories: [
{
name: "Admin",
emoji: "emoji ID",
custom: true,
hidden: true
},
{
name: "Configuration",
emoji: "🔨",
custom: false,
hidden: false
}
]
}
* @returns {CommandHandler}
*/
setHelpSettings(settings) {
let categories = settings.categories;
if (!categories || !categories.length) throw new Error("At least one category must be specified!");
if (!settings.embed || !settings.embed.color) settings.embed = {
color: null
};
if (!settings.authoritativePerms) settings.authoritativePerms = ["ADMINISTRATOR"];
if (settings.embed.withPages) {
for (let category of categories) {
if (!category.name) throw new Error("The category must have a name");
if (!category.emoji) throw new Error("Emoji is required for each category of withPages true!")
if (!category.custom) category.custom = false;
if (!category.hidden) category.hidden = false;
if (this.isNameUsed(category.name)) throw new Error("Names must be used once!");
if (this.isEmojiUsed(category.emoji)) throw new Error("Emojis must be used once!");
if (typeof category.name !== 'string') throw new TypeError("Category name must be string!");
if (typeof category.emoji !== 'string') throw new TypeError("Category emoji must be string!");
if (typeof category.custom !== 'boolean') throw new TypeError("Category emoji custom must be boolean!");
if (typeof category.hidden !== 'boolean') throw new TypeError("Category hidden must be boolean!");
this.categories.set(category.name, category);
}
} else {
for (let category of categories) {
if (!category.name) throw new Error("The category must have a name");
if (category.emoji && !category.custom) category.custom = false;
if (!category.hidden) category.hidden = false;
if (this.isNameUsed(category.name)) throw new Error("Names must be used once!");
if (typeof category.name !== 'string') throw new TypeError("Category name must be string!");
if ((typeof category.emoji !== 'string' && category.emoji)) throw new TypeError("Category emoji must be string!");
if ((typeof category.custom !== 'boolean' && category.custom)) throw new TypeError("Category emoji custom must be boolean!");
if ((typeof category.hidden !== 'boolean' && category.hidde)) throw new TypeError("Category hidden must be boolean!");
this.categories.set(category.name, category);
}
}
this.helpSettings = settings;
return this;
}
/**
*
* @param {string} emoji
* @returns {boolean}
*/
isEmojiUsed(emoji) {
let result;
const e = this.categories.filter(c => c.emoji === emoji);
if (e.size !== 0) result = true
else result = false
return result;
}
/**
*
* @param {string} name
* @returns {boolean}
*/
isNameUsed(name) {
let result;
const e = this.categories.filter(c => c.name === name);
if (e.size !== 0) result = true
else result = false
return result;
}
/**
*
* @param {string} emoji
* @returns {category}
*/
getCategoryByEmoji(emoji) {
let result;
result = this.categories.filter(c => c.emoji = emoji)
if (result.size === 0) result = this.categories.filter(c => c.emoji === emoji.id);
if (result.size === 0) result = undefined;
return result;
}
/**
*
* @param {string} name
* @returns {category}
*/
getCategoryByName(name) {
let result;
result = this.categories.filter(c => c.name = name);
if (result.size === 0) result = undefined;
return result;
}
/**
*
* @param {message} message
* @returns {Array<object>}
*/
getCategories(message) {
let authoritativePerms = this.helpSettings.authoritativePerms || [];
let perm = false,
categories = this.categories
for (let i = 0; i < authoritativePerms.length; i++) {
let _perm = authoritativePerms[i];
if (message.member.hasPermission(_perm)) perm = true
else continue;
}
if (perm) categories = this.categories;
else categories = this.categories.filter(c => c.hidden === false);
return categories;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
//Lang
/**
*
* @param {DiscordJS.Guild} guild
* @param {string} language
* @returns {Promise<any>}
*/
async setLanguage(guild, language) {
let langs = ['en', 'tr']
if (!langs.includes(language)) return console.error("Unkown language.")
const result = await langSchema.findByIdAndUpdate(guild.id, { lang: language }, { upsert: true });
return result;
}
/**
*
* @param {DiscordJS.Guild} guild
* @returns {Promise<string>}
*/
async getLanguage(guild) {
let lang;
if (this.isDbConnected()) {
let result = await langSchema.findOneAndUpdate({ _id: guild ? guild.id : "dm" }, { _id: guild ? guild.id : "dm" }, { upsert: true, new: true, setDefaultsOnInsert: true })
if (!result.lang) result.lang = this.defaultLang;
lang = result.lang
} else {
lang = this.defaultLang;
}
return lang
}
/**
*
* @param {string} language
* @returns {CommandHandler}
*/
setDefaultLanguage(language) {
if (typeof language !== 'string') throw new TypeError('Language must be string!');
const langs = ["tr", "en"]
if (!langs.includes(language.toLocaleLowerCase())) throw new Error("Unkown language!");
this.defaultLang = language;
return this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Prefix
/**
*
* @param {string} prefix
* @returns {CommandHandler}
*/
setDefaultPrefix(prefix) {
if (typeof prefix !== 'string') throw new TypeError('Prefix must be string!');
this.defaultPrefix = prefix;
return this;
}
/**
*
* @param {DiscordJS.Guild} guild
* @returns {Promise<string>}
*/
async getPrefix(guild) {
let prefix;
if (guild) {
if (this.isDbConnected()) {
const result = await prefixSchema.findOneAndUpdate({ _id: guild.id }, { _id: guild.id }, { upsert: true, new: true, setDefaultsOnInsert: true });
if (!result.prefix) {
result.prefix = this.defaultPrefix;
await prefixSchema.findOneAndUpdate({ _id: guild.id }, { _id: guild.id, prefix: this.defaultPrefix }, { upsert: true, new: true, setDefaultsOnInsert: true });
};
prefix = result.prefix;
} else {
prefix = this.defaultPrefix;
}
} else prefix = this.defaultPrefix;
return prefix;
}
/**
*
* @param {DiscordJS.Guild} guild
* @param {string} prefix
* @returns {Promise<any>}
*/
async setPrefix(guild, prefix) {
const result = await prefixSchema.findByIdAndUpdate(guild.id, { prefix: prefix }, { upsert: true });
return result;
}
/////////////////////////////////////////////////////////////////////////////
//command
/**
*
* @param {string} command
* @returns {boolean}
*/
isCommandHas(command) {
let has
let commands = this.commands;
let aliases = this.aliases;
let _command = command.toLocaleLowerCase();
if (commands.has(_command)) return true;
else if (aliases.has(_command)) return true;
else return false;
}
/**
*
* @param {string} command
* @returns {object}
*/
getCommand(command) {
let cmd;
let commands = this.commands;
let aliases = this.aliases;
let _command = command.toLocaleLowerCase()
cmd = commands.get(_command) || aliases.get(_command);
return cmd
}
/**
*
* @param {string} dir
* @returns {CommandHandler}
*/
setCommandsDir(dir) {
if (typeof dir !== 'string') throw new TypeError('Directory must be string!');
this.commandsDir = dir;
return this
}
/**
*
* @param {DiscordJS.Guild} guild
* @param {string} command
* @returns {Promise<boolean>}
*/
async isCommandDisabled(guild, command) {
command = this.getCommand(command)
let result = await disableCommandsSchema.findOne({ guildId: guild.id, command: command.name });
let returns = false
if (result !== null) returns = true
return returns
}
/**
*
* @param {DiscordJS.Guild} guild
* @param {string} command
* @param {DiscordJS.Channel} channel
* @returns {Promise<boolean>}
*/
async isChannelDisabled(guild, command, channel) {
command = this.getCommand(command)
let output = false
let result = await channelSchema.findOne({ guildId: guild.id, command: command.name });
if (result === null) return output;
if (result !== null && result.channels !== null && result.channels.includes(channel.id)) output = true;
return output
}
//////////////////////////////////////////////////////////////////////
//mongoDB
/**
*
* @param {object} dbOptions
* @returns {CommandHandler}
*/
setDbOptions(dbOptions) {
if (typeof dbOptions !== 'object') throw new TypeError('DB options must be object!');
this.dbOptions = dbOptions;
return this;
}
/**
*
* @returns {boolean}
*/
isDbConnected() {
let connect = false
if (mongoose.connection.readyState === 1 || mongoose.connection.readyState === 2) connect = true
return connect;
}
/**
*
* @returns {uri}
*/
getDbConnectionURI() {
return this.mongoURI;
}
/**
*
* @param {string} uri
* @returns {CommandHandler}
*/
setMongoURI(uri) {
if (typeof uri !== 'string') throw new TypeError('mongoDB uri must be string!');
this.mongoURI = uri;
return this;
}
//////////////////////////////////////////////////////////////////////
//stats
/**
*
* @param {DiscordJS.Guild} guild
* @returns {Promise<boolean>}
*/
async isStatsOn(guild) {
let result = await statsSchema.findOneAndUpdate({ _id: guild.id }, { _id: guild.id }, { upsert: true, new: true, setDefaultsOnInsert: true });
let returns;
if (result.statu === true) returns = true
else if (result.statu === false || result.statu === null || !result.statu) returns = false;
return returns;
};
/**
*
* @param {DiscordJS.Guild} guild
* @param {string} counter
* @returns {Promise<boolean>}
*/
async isCounterOn(guild, counter) {
let result = await statsSchema.findOneAndUpdate({ _id: guild.id }, { _id: guild.id }, { upsert: true, new: true, setDefaultsOnInsert: true });
counter = counter.toLocaleLowerCase();
let ch = guild.channels.cache.get(result[counter].channelId);
let returns = false;
if (ch || ch !== null) returns = true;
return returns;
}
/**
*
* @param {DiscordJS.Guild} guild
* @returns {Promise<boolean>}
*/
async iStatsCategoryHas(guild) {
let result = await statsSchema.findOneAndUpdate({ _id: guild.id }, { _id: guild.id }, { upsert: true, new: true, setDefaultsOnInsert: true });
let ch = guild.channels.cache.get(result.categoryId);
let returns = false;
if (ch || ch !== null) returns = true;
return returns;
}
/**
*
* @param {string} counter
* @returns {Promise<string>}
*/
async getCounterName(counter, guild) {
let lang = await this.getLanguage(guild);
let file = JSON.parse(fs.readFileSync(path.join(__dirname, 'counterNames.json'), 'utf8'));
let counters = ['all-members', 'members', 'bots', 'category'];
if (!counters.includes(counter)) {
throw new TypeError("Unkown counter.")
}
let name = file[counter][lang];
if (counter === 'all-members') {
name = name.replace(/{COUNT}/g, guild.memberCount)
} else if (counter === 'members') {
name = name.replace(/{COUNT}/g, guild.members.cache.filter(m => !m.user.bot).size)
} else if (counter === 'bots') {
name = name.replace(/{COUNT}/g, guild.members.cache.filter(m => m.user.bot).size)
}
return name;
}
//cooldown
/**
*
* @param {Date} finishDate
* @param {Date} now
* @returns {string}
*/
getLeftTime(finishDate, now) {
let leftCooldown = finishDate - now;
let text = '';
text = moment.duration(leftCooldown).format("d[d], h[h], m[m], s[s]");
return text;
}
/**
*
* @param {DiscordJS.Message} message
* @param {object} command
* @param {Date} now
* @param {object} options
*/
async setCooldown(message, command, now, options = { type: "commandCooldown" }) {
if (!options.type) options.type = "commandCooldown";
let { type } = options
if (!["commandCooldown", "globalCooldown", "userCooldown"].includes(type)) throw new TypeError("Unkown cooldown type!")
let { guild } = message
let guildId = guild.id
if (type === "commandCooldown") {
await cooldownSchema.findOneAndUpdate({
_id: `${guildId}-${message.author.id}-${command.name}`,
name: command.name,
}, { cooldown: now + ms(command.cooldown) }, { upsert: true })
}
if (type === "globalCooldown") {
await cooldownSchema.findOneAndUpdate({
_id: `${guildId}-${command.name}`,
name: command.name,
}, { cooldown: now + ms(command.globalCooldown) }, { upsert: true })
}
if (type === "userCooldown") {
await cooldownSchema.findOneAndUpdate({
_id: `${message.author.id}-${command.name}`,
name: command.name,
}, { cooldown: now + ms(command.userCooldown) }, { upsert: true })
}
}
/**
*
* @param {DiscordJS.Message} message
* @param {object} command
* @param {object} options
*/
async deleteCooldown(message, command, options = { type: "commandCooldown" }) {
if (!options.type) options.type = "commandCooldown";
let { type } = options
if (!["commandCooldown", "globalCooldown", "userCooldown"].includes(type)) throw new TypeError("Unkown cooldown type!")
let { guild } = message
let guildId = guild.id
if (type === "commandCooldown") {
await cooldownSchema.findOneAndDelete({
_id: `${guildId}-${message.author.id}-${command.name}`,
name: command.name,
})
}
if (type === "globalCooldown") {
await cooldownSchema.findOneAndDelete({
_id: `${guildId}-${command.name}`,
name: command.name,
})
}
if (type === "userCooldown") {
await cooldownSchema.findOneAndDelete({
_id: `${message.author.id}-${command.name}`,
name: command.name,
})
}
}
//blacklist
/**
*
* @param {string} userId
* @returns {Promise<boolean>}
*/
async isUserInBlacklist(userId) {
let result = await blacklistSchema.findOne({ _id: userId });
if (result === null) return false
else if (result !== null) return true;
}
}
module.exports = CommandHandler