Merge branch 'master' of https://github.com/Navy-gif/New-GBot
This commit is contained in:
commit
261c007645
@ -15,7 +15,8 @@ class LocaleLoader {
|
||||
|
||||
template(locale, index) {
|
||||
|
||||
return this.languages[locale] ? this.languages[locale][index] : `Locale ${locale} does not exist.` || `Entry ${locale}:${index} does not exist.`;
|
||||
// console.log(String.raw`${this.languages[locale][index]}`);
|
||||
return (this.languages[locale] ? this.languages[locale][index] : `Locale ${locale} does not exist.`) || `Entry ${locale}:${index} does not exist.`;
|
||||
|
||||
}
|
||||
|
||||
@ -55,6 +56,7 @@ class LocaleLoader {
|
||||
let matched = null;
|
||||
let text = '';
|
||||
for(const line of lines) {
|
||||
if(line.startsWith('//')) continue;
|
||||
const matches = line.match(/\[([_A-Z0-9]{1,})]/, 'gi');
|
||||
if(matches) {
|
||||
if(matched) {
|
||||
@ -73,8 +75,8 @@ class LocaleLoader {
|
||||
}
|
||||
}
|
||||
|
||||
if(matched) {
|
||||
parsed[matched] = text;
|
||||
for(const [ key, value ] of Object.entries(parsed)) {
|
||||
parsed[key] = value.replace(/^(\r)|(\r){1,}$/g, '')
|
||||
}
|
||||
|
||||
return parsed;
|
||||
|
@ -1,21 +1,47 @@
|
||||
[C_PING]
|
||||
Pong! {number}
|
||||
//Ping Command
|
||||
|
||||
[C_MODE_TEST]
|
||||
switch('{mode}') {
|
||||
case 'explicit':
|
||||
'works1';
|
||||
break;
|
||||
case 'fuzzy':
|
||||
'works2';
|
||||
break;
|
||||
}
|
||||
[C_PING_RESPONSE]
|
||||
Pong!
|
||||
|
||||
[C_PING_HELP]
|
||||
what?
|
||||
//Settings Command
|
||||
|
||||
[C_SETTING_RESET]
|
||||
Are you sure you want to reset __all__ of your guild settings to the default values?
|
||||
[C_SETTINGS_ADMINISTRATORERROR]
|
||||
You must have the `ADMINISTRATOR` permission to reset the {type} settings.
|
||||
|
||||
[C_SETTINGS_CLIENTPERMISSIONERROR]
|
||||
The setting **{setting}** requires __the bot__ to have permissions to use.
|
||||
*Missing: {missing}*
|
||||
|
||||
[C_SETTINGS_MEMBERPERMISSIONERROR]
|
||||
The setting **{setting}** requires __you__ to have permissions to use.
|
||||
*Missing: {missing}*
|
||||
|
||||
[C_SETTINGS_RESET]
|
||||
Are you sure you want to reset **all** of your {type} settings to the default values? This cannot be undone. *(__y__es, __n__o)*
|
||||
This prompt will time out in __30 seconds__.
|
||||
|
||||
[C_SETTINGS_RESETERROR]
|
||||
You provided an invalid input, please try again.
|
||||
|
||||
[C_SETTINGS_RESETSUCCESS]
|
||||
All {type} settings were successfully deleted and set to default.
|
||||
|
||||
[C_SETTINGS_USERSETTINGSTITLE]
|
||||
User Settings
|
||||
|
||||
[C_SETTINGS_GUILDSETTINGSTITLE]
|
||||
Guild Settings
|
||||
|
||||
[C_SETTINGS_LISTSETTINGS]
|
||||
Use `{prefix}setting [setting-name]` to view a description on the setting. Each setting is unique, so make sure to read carefully.
|
||||
|
||||
[C_SETTINGS_LISTSETTINGSALT]
|
||||
Alternatively, you can view user settings by using the command `{prefix}settings -u`
|
||||
|
||||
[C_SETTINGS_NONEXISTANT]
|
||||
That setting does not exist!
|
||||
|
||||
//User Command
|
||||
|
||||
[C_USER]
|
||||
**Nickname:** {nickname}
|
||||
@ -35,4 +61,4 @@ Search result for keyword: `{key}`
|
||||
Found {matches} matches, displaying {count}
|
||||
|
||||
[C_USER_HELP]
|
||||
To search server members with similar names use `{prefix}user search < arguments >`
|
||||
To search server members with similar names use `{prefix}user search <arguments..>`
|
12
language/languages/en_us/en_us_general.lang
Normal file
12
language/languages/en_us/en_us_general.lang
Normal file
@ -0,0 +1,12 @@
|
||||
[GENERAL_COMPONENTS]
|
||||
switch({component}) {
|
||||
case "command":
|
||||
"command";
|
||||
break;
|
||||
case "setting":
|
||||
"setting";
|
||||
break;
|
||||
case "inhibitor":
|
||||
"inhibitor":
|
||||
break;
|
||||
}
|
17
language/languages/en_us/en_us_modules.lang
Normal file
17
language/languages/en_us/en_us_modules.lang
Normal file
@ -0,0 +1,17 @@
|
||||
[M_UTILITY_NAME]
|
||||
Utility
|
||||
|
||||
[M_MODERATION_NAME]
|
||||
Moderation
|
||||
|
||||
[M_DEVELOPER_NAME]
|
||||
Developer
|
||||
|
||||
[M_ADMINISTRATOR_NAME]
|
||||
Administrator
|
||||
|
||||
[M_INFORMATION_NAME]
|
||||
Information
|
||||
|
||||
[M_MUSIC_NAME]
|
||||
Music
|
11
language/languages/en_us/settings/en_us_utility.lang
Normal file
11
language/languages/en_us/settings/en_us_utility.lang
Normal file
@ -0,0 +1,11 @@
|
||||
[S_GUILDPREFIX_DESCRIPTION]
|
||||
Customizes your prefix in the guild.
|
||||
|
||||
[S_GUILDPREFIX_SUCCESS]
|
||||
Successfully set the guild prefix to `{prefix}`.
|
||||
|
||||
[S_GUILDPREFIX_LENGTH]
|
||||
The guild prefix cannot exceed {max} characters. `[{length}/{max}]`.
|
||||
|
||||
[S_GUILDPREFIX_RESET]
|
||||
Successfully reset the guild prefix to `{prefix}`.
|
@ -33,26 +33,86 @@ class MongoDBProvider extends Provider {
|
||||
type: '', -- The function to use from this class, ex. findOne
|
||||
collection: '', -- Which collection to query from
|
||||
query: { }, -- Actual search query
|
||||
data: { } -- If the operation is to update or insert something, this is what to insert
|
||||
data: { }, -- If the operation is to update or insert something, this is what to insert
|
||||
upsert: bool, -- If true and no matching documents are found, insert a new one
|
||||
options: { },
|
||||
projection: { } -- The fields that should be returned
|
||||
}
|
||||
*/
|
||||
|
||||
if (!this._initialized) return { error: true, message: 'MongoDB not connected' };
|
||||
if (!this[request.type]) return { error: true, message: `Invalid request type, got '${request.type}'` };
|
||||
if (!request.collection) return { error: true, message: `You must specify a collection to query!` };
|
||||
if (!request.collection && request.type !== 'stats') return { error: true, message: `You must specify a collection to query!` };
|
||||
return this[request.type](request);
|
||||
|
||||
|
||||
}
|
||||
|
||||
remove({ collection, query }) {
|
||||
|
||||
/**
|
||||
* Fetches basic statistics about the database or collection
|
||||
*
|
||||
* @param {String} collection The collection to query, optional
|
||||
* @param {Object} options Optional options for the stats method
|
||||
* @returns
|
||||
* @memberof MongoDBProvider
|
||||
*/
|
||||
stats({ collection, options = { } }) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
this.db.collection(collection).remove(query, (err, result) => {
|
||||
|
||||
if (err) reject(err);
|
||||
resolve(result);
|
||||
|
||||
if (!collection || collection.length) {
|
||||
|
||||
this.db.stats(options, (error, stats) => {
|
||||
|
||||
if (err) return reject(err);
|
||||
else {
|
||||
|
||||
let { db, collections, objects, averageSize: avgObjSize, dataSize } = stats;
|
||||
return resolve({ db, collections, objects, averageSize, dataSize });
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
this.db.collection(collection).stats(options, (err, stats) => {
|
||||
|
||||
if (err) return reject(err);
|
||||
else {
|
||||
|
||||
let { index: ns, size, count, averageSize: avgObjSize } = stats;
|
||||
return resolve({ index, size, count, averageSize });
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the objects in
|
||||
*
|
||||
* @param {String} collection The collection to query
|
||||
* @param {Object} query Only documents matching this will be counted, optional
|
||||
* @param {Object} options Optional options, see mongo docs for these
|
||||
* @returns
|
||||
* @memberof MongoDBProvider
|
||||
*/
|
||||
count({ collection, query, options }) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
this.db.collection(collection).countDocuments(query, options, (error, result) => {
|
||||
|
||||
if (error)
|
||||
return reject(error);
|
||||
else
|
||||
return resolve(result);
|
||||
|
||||
});
|
||||
|
||||
@ -60,6 +120,38 @@ class MongoDBProvider extends Provider {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a document from a collection
|
||||
*
|
||||
* @param {String} collection The collection to remove from
|
||||
* @param {Object} query Any documents matching this will be removed
|
||||
* @returns
|
||||
* @memberof MongoDBProvider
|
||||
*/
|
||||
remove({ collection, query }) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
this.db.collection(collection).deleteOne(query, (err, result) => {
|
||||
|
||||
if (err) return reject(err);
|
||||
return resolve(result);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert one document to the collection
|
||||
*
|
||||
* @param {String} collection The collection to insert into
|
||||
* @param {Object} data The document to insert
|
||||
* @returns
|
||||
* @memberof MongoDBProvider
|
||||
*/
|
||||
insertOne({ collection, data }) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@ -77,17 +169,21 @@ class MongoDBProvider extends Provider {
|
||||
|
||||
/**
|
||||
* Find and return the first match
|
||||
*
|
||||
* @param {String} collection The collection to find from
|
||||
* @param {Object} query Documents matching this will be returned
|
||||
* @param {Object} projection Defines which fields to return, { 'key': 1, 'key2': 0 } -- key will return, key2 won't, optional
|
||||
* @memberof Database
|
||||
*/
|
||||
|
||||
find({ collection, query }) {
|
||||
find({ collection, query, projection }) {
|
||||
|
||||
//if(this.manager.debug) this.manager.logger.debug(`Incoming find query for ${db} with parameters ${JSON.stringify(query)}`);
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if(!this._initialized) reject(new Error('MongoDB not connected'));
|
||||
|
||||
this.db.collection(collection).find(query, async (error, cursor) => {
|
||||
this.db.collection(collection).find(query, { projection }, async (error, cursor) => {
|
||||
|
||||
if(error) return reject(error);
|
||||
return resolve(await cursor.toArray());
|
||||
@ -101,20 +197,21 @@ class MongoDBProvider extends Provider {
|
||||
/**
|
||||
* Find and return the first match
|
||||
*
|
||||
* @param {String} db The collection in which the data is to be updated
|
||||
* @param {String} collection The collection in which the data is to be updated
|
||||
* @param {Object} query The filter that is used to find the data
|
||||
* @param {Object} projection Defines which fields to return, { 'key': 1, 'key2': 0 } -- key will return, key2 won't, optional
|
||||
* @returns {Object} An object containing the queried data
|
||||
* @memberof Database
|
||||
*/
|
||||
|
||||
findOne({ collection, query }) {
|
||||
findOne({ collection, query, projection }) {
|
||||
|
||||
//if(this.manager.debug) this.manager.logger.debug(`Incoming findOne query for ${db} with parameters ${JSON.stringify(query)}`);
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if(!this._initialized) reject(new Error('MongoDB not connected'));
|
||||
|
||||
this.db.collection(collection).findOne(query, async (error, item) => {
|
||||
this.db.collection(collection).findOne(query, { projection }, async (error, item) => {
|
||||
|
||||
if(error) return reject(error);
|
||||
return resolve(item);
|
||||
@ -128,14 +225,14 @@ class MongoDBProvider extends Provider {
|
||||
/**
|
||||
* Update the first filter match.
|
||||
*
|
||||
* @param {String} db The collection in which the data is to be updated
|
||||
* @param {Object} filter The filter that is used to find the data
|
||||
* @param {String} collection The collection in which the data is to be updated
|
||||
* @param {Object} query The filter that is used to find the data
|
||||
* @param {Object} data The updated data
|
||||
* @param {Boolean} [upsert=false] Create a new entry if no match is found
|
||||
* @param {Boolean} [upsert=true] Create a new entry if no match is found
|
||||
* @returns {WriteResult} Object containing the followint counts: Matched, Upserted, Modified
|
||||
* @memberof Database
|
||||
*/
|
||||
updateOne({ collection, query, data, upsert = false }) {
|
||||
updateOne({ collection, query, data, upsert = true }) {
|
||||
|
||||
//if(this.manager.debug) this.manager.logger.debug(`Incoming updateOne query for ${db} with parameters ${JSON.stringify(filter)}`);
|
||||
return new Promise((resolve, reject) => {
|
||||
@ -156,17 +253,47 @@ class MongoDBProvider extends Provider {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a document property
|
||||
*
|
||||
* @param {String} collection The collection to query
|
||||
* @param {Object} query The filter that is used to find the data
|
||||
* @param {Array} data Array of fields to remove
|
||||
* @returns
|
||||
* @memberof MongoDBProvider
|
||||
*/
|
||||
removeProperty({ collection, query, data }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let unset = {};
|
||||
for (let field in data) unset[field] = '';
|
||||
this.db.collection(collection).updateOne(query, { $unset: unset }, async (error, result) => {
|
||||
|
||||
if(error) return reject(error);
|
||||
else {
|
||||
|
||||
let { matchedCount, modifiedCount } = result;
|
||||
return resolve({ matched: matchedCount, modified: modifiedCount });
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Push data to an array
|
||||
*
|
||||
* @param {string} db The collection to query
|
||||
* @param {object} filter The filter to find the document to update
|
||||
* @param {string} collection The collection to query
|
||||
* @param {object} query The filter to find the document to update
|
||||
* @param {object} data The data to be pushed
|
||||
* @param {boolean} [upsert=false] Create a new entry if no match is found
|
||||
* @param {boolean} [upsert=true] Create a new entry if no match is found
|
||||
* @returns
|
||||
* @memberof Database
|
||||
*/
|
||||
push({ collection, query, data, upsert = false }) {
|
||||
push({ collection, query, data, upsert = true }) {
|
||||
|
||||
//if(this.manager.debug) this.manager.logger.debug(`Incoming push query for ${db}, with upsert ${upsert} and with parameters ${JSON.stringify(filter)} and data ${JSON.stringify(data)}`);
|
||||
return new Promise((resolve, reject) => {
|
||||
@ -187,8 +314,8 @@ class MongoDBProvider extends Provider {
|
||||
/**
|
||||
* Find a random element from a database
|
||||
*
|
||||
* @param {string} db The collection to query
|
||||
* @param {object} [filter={}] The filtering object to narrow down the sample pool
|
||||
* @param {string} collection The collection to query
|
||||
* @param {object} [query={}] The filtering object to narrow down the sample pool
|
||||
* @param {number} [amount=1] Amount of items to return
|
||||
* @returns {object}
|
||||
* @memberof Database
|
||||
|
@ -28,6 +28,7 @@ class DiscordClient extends Client {
|
||||
this.localeLoader = new LocaleLoader(this);
|
||||
|
||||
this._options = options;
|
||||
this._defaultConfig = null;
|
||||
this._built = false;
|
||||
|
||||
process.on('message', this._handleMessage.bind(this));
|
||||
@ -51,7 +52,7 @@ class DiscordClient extends Client {
|
||||
await this.registry.loadComponents('components/inhibitors/', Inhibitor);
|
||||
await this.registry.loadComponents('components/commands/', Command);
|
||||
await this.registry.loadComponents('components/observers/', Observer);
|
||||
// await this.registry.loadComponents('components/settings/', Setting);
|
||||
await this.registry.loadComponents('components/settings/', Setting);
|
||||
|
||||
await this.dispatcher.dispatch();
|
||||
|
||||
@ -59,6 +60,22 @@ class DiscordClient extends Client {
|
||||
|
||||
}
|
||||
|
||||
get defaultConfig() {
|
||||
if(this._defaultConfig) return this._defaultConfig;
|
||||
const settings = this.registry.components.filter(c=>c.type === 'setting' && c.resolve === 'GUILD');
|
||||
let def = {};
|
||||
for(const setting of settings.values()) {
|
||||
if(setting.default !== null) {
|
||||
def = {
|
||||
...def,
|
||||
...setting.default
|
||||
}
|
||||
}
|
||||
}
|
||||
this._defaultConfig = def;
|
||||
return def;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = DiscordClient;
|
||||
|
@ -17,6 +17,28 @@ class Resolver {
|
||||
return components || [];
|
||||
|
||||
}
|
||||
|
||||
resolveBoolean(input) {
|
||||
input = input.toLowerCase();
|
||||
const truthy = [ 'on', 'true', 'yes', 'enable', 'y' ];
|
||||
const falsey = [ 'off', 'false', 'no', 'disable', 'n' ];
|
||||
|
||||
if(truthy.includes(input)) {
|
||||
return true;
|
||||
} else if (falsey.includes(input)) {
|
||||
return false;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// resolveTrue(input) {
|
||||
// return [ 'on', 'true' ].includes(input.toLowerCase());
|
||||
// }
|
||||
|
||||
// resolveFalse(input) {
|
||||
// return [].includes(input.toLowerCase());
|
||||
// }
|
||||
|
||||
async resolveMemberAndUser(string, guild) {
|
||||
|
||||
|
@ -9,21 +9,7 @@ class TransactionHandler {
|
||||
|
||||
}
|
||||
|
||||
_receive(message) {
|
||||
|
||||
if(!message.transactionID) return undefined;
|
||||
const transaction = this.transactions.get(message.transactionID);
|
||||
|
||||
if(!transaction) return undefined;
|
||||
|
||||
if(message.error) transaction.reject(message.message);
|
||||
else transaction.resolve(message.result);
|
||||
|
||||
this.transactions.delete(message.transactionID);
|
||||
|
||||
}
|
||||
|
||||
_send(message, options = {}) {
|
||||
send(message, options = {}) {
|
||||
|
||||
/** Message structure
|
||||
* {
|
||||
@ -48,6 +34,20 @@ class TransactionHandler {
|
||||
|
||||
}
|
||||
|
||||
_receive(message) {
|
||||
|
||||
if(!message.transactionID) return undefined;
|
||||
const transaction = this.transactions.get(message.transactionID);
|
||||
|
||||
if(!transaction) return undefined;
|
||||
|
||||
if(message.error) transaction.reject(message.message);
|
||||
else transaction.resolve(message.result);
|
||||
|
||||
this.transactions.delete(message.transactionID);
|
||||
|
||||
}
|
||||
|
||||
get transactionID() {
|
||||
return `${[ this.client.shard.ids ]}-${Date.now().toString(36)}`;
|
||||
}
|
||||
|
@ -17,7 +17,8 @@ class PingCommand extends Command {
|
||||
|
||||
async execute(message) {
|
||||
const ping = this.client.ws.ping.toFixed(0);
|
||||
return message.respond(`${message.format('PING_COMMAND_RESPONSE')} \`${ping}ms\``, { emoji: 'success' });
|
||||
//console.log(message.format('C_PING_RESPONSE'))
|
||||
return message.respond(`${message.format('C_PING_RESPONSE')} \`${ping}ms\``, { emoji: 'success' });
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
const { Command } = require('../../../../interfaces/');
|
||||
const { Command, Argument } = require('../../../../interfaces/');
|
||||
|
||||
const { stripIndents } = require('common-tags');
|
||||
|
||||
class SettingCommand extends Command {
|
||||
|
||||
@ -12,7 +14,23 @@ class SettingCommand extends Command {
|
||||
'settings',
|
||||
'set'
|
||||
],
|
||||
showUsage: true
|
||||
arguments: [
|
||||
new Argument(client, {
|
||||
name: 'user',
|
||||
type: 'BOOLEAN',
|
||||
types: ['VERBAL', 'FLAG'],
|
||||
default: true
|
||||
}),
|
||||
new Argument(client, {
|
||||
name: 'all',
|
||||
type: 'BOOLEAN',
|
||||
types: ['VERBAL', 'FLAG'],
|
||||
default: true
|
||||
})
|
||||
],
|
||||
memberPermissions: ['ADMINISTRATOR'],
|
||||
showUsage: true,
|
||||
|
||||
});
|
||||
|
||||
this.client = client;
|
||||
@ -20,31 +38,113 @@ class SettingCommand extends Command {
|
||||
|
||||
}
|
||||
|
||||
//-settings list
|
||||
//-settings reset
|
||||
//-settings walkthrough
|
||||
//-settings [setting]
|
||||
async execute(message, { params, args }) {
|
||||
|
||||
async execute(message, { params }) {
|
||||
const type = (!message.guild || args.user) ? 'USER' : 'GUILD';
|
||||
|
||||
const target = params[0].toLowerCase(); // params[0] should never be null, see showUsage
|
||||
if(target === 'list') {
|
||||
this._listSettings(message);
|
||||
return;
|
||||
this._listSettings(message, type, Boolean(args.all));
|
||||
return undefined;
|
||||
} else if(target === 'reset') {
|
||||
const prompt = await this.message.prompt(message.format('C_SETTING_RESET'), { emoji: 'warning' });
|
||||
return this._handleReset(prompt, message);
|
||||
if(message.channel.permissionsFor(message.member).missing('ADMINISTRATOR').length > 0) {
|
||||
await message.respond(message.format('C_SETTINGS_ADMINISTRATORERROR', { type: type.toLowerCase() }), { emoji: 'failure' });
|
||||
return undefined;
|
||||
}
|
||||
const prompt = await message.prompt(message.format('C_SETTINGS_RESET', { type: type.toLowerCase() }), { emoji: 'warning' });
|
||||
return await this._handleReset(prompt, message, type);
|
||||
} else if(target === 'walkthrough') {
|
||||
return;
|
||||
//TODO
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const [ setting ] = this.client.resolver.components(params, 'setting', false);
|
||||
const settings = this.client.resolver.components(target, 'setting', false).sort(c=>c.resolve === type);
|
||||
const [ setting ] = settings;
|
||||
if(!setting) {
|
||||
|
||||
await message.respond(message.format('C_SETTINGS_NONEXISTANT'), { emoji: 'failure' });
|
||||
return undefined;
|
||||
}
|
||||
|
||||
//Setting permission handling
|
||||
if(setting.clientPermissions.length > 0) {
|
||||
const missing = message.channel.permissionsFor(message.guild.me).missing(command.clientPermissions);
|
||||
if(missing.length > 0) {
|
||||
await message.respond(message.format('C_SETTINGS_CLIENTPERMISSIONERROR', { setting: setting.moduleResolveable, missing: missing.join(', ')}), { emoji: 'failure' });
|
||||
return undefined;
|
||||
}
|
||||
} else if(setting.memberPermissions.length > 0) {
|
||||
const missing = message.channel.permissionsFor(message.member).missing(command.memberPermissions);
|
||||
if(missing.length > 0) {
|
||||
await message.respond(message.format('C_SETTINGS_MEMBERPERMISSIONERROR', { setting: setting.moduleResolveable, missing: missing.join(', ')}), { emoji: 'failure' });
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const response = await setting.handle(message, params.splice(1));
|
||||
message.respond(response.msg, { emoji: response.error ? 'failure' : 'success' });
|
||||
|
||||
}
|
||||
|
||||
_listSettings(message, type, all) {
|
||||
if(!message.guild && type === 'GUILD') type = 'USER';
|
||||
|
||||
const prefix = message.guild?.prefix || this.client._options.bot.prefix;
|
||||
|
||||
let fields = [];
|
||||
const sorted = this.client.registry.components
|
||||
.filter(c=>c.type === 'module')
|
||||
.sort((a, b) => {
|
||||
const filter = c=>c.type === 'setting';
|
||||
return b.components.filter(filter) - a.components.filter(filter);
|
||||
});
|
||||
|
||||
for(const module of sorted.values()) {
|
||||
let field = {
|
||||
name: module.id,
|
||||
value: '',
|
||||
inline: true
|
||||
};
|
||||
|
||||
for(const setting of module.components.values()) {
|
||||
if(setting.type !== 'setting'
|
||||
|| (setting.resolve !== type && !all)
|
||||
|| (setting.restricted && !all)) continue;
|
||||
field.value += `\`${setting.display}\`\n`;
|
||||
}
|
||||
if(field.value) fields.push(field);
|
||||
}
|
||||
|
||||
const embed = {
|
||||
author: {
|
||||
name: `${type === 'GUILD' ? message.format('C_SETTINGS_GUILDSETTINGSTITLE') : message.format('C_SETTINGS_USERSETTINGSTITLE')}`,
|
||||
icon_url: type === 'GUILD' ? message.guild.iconURL() : message.author.avatarURL()
|
||||
},
|
||||
description: stripIndents`${message.format('C_SETTINGS_LISTSETTINGS', { prefix })}
|
||||
|
||||
${type === 'USER' ? '' : message.format('C_SETTINGS_LISTSETTINGSALT', { prefix })}`,
|
||||
fields
|
||||
};
|
||||
|
||||
return message.embed(embed);
|
||||
|
||||
}
|
||||
|
||||
async _handleReset(prompt, message, type) {
|
||||
|
||||
if(!prompt) return;
|
||||
const response = prompt.content.toLowerCase();
|
||||
const bool = this.client.resolver.resolveBoolean(response);
|
||||
if(bool === null) return message.respond(message.format('C_SETTINGS_RESETERROR'), { emoji: 'failure' });
|
||||
if(!bool) return message.respond(message.format('C_SETTINGS_RESETABORT'), { emoji: 'success' });
|
||||
|
||||
type === 'USER'
|
||||
? await message.author._deleteSettings()
|
||||
: await message.guild._deleteSettings();
|
||||
|
||||
return message.respond(message.format('C_SETTINGS_RESETSUCCESS', { type: type.toLowerCase() }), { emoji: 'success' })
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = SettingCommand;
|
||||
module.exports = SettingCommand;
|
||||
|
@ -21,7 +21,7 @@ class PingCommand extends Command {
|
||||
async execute(message) {
|
||||
|
||||
const time1 = new Date().getTime();
|
||||
let response = await this.client.transactionHandler._send({ provider: 'mongodb', request: { collection: 'infractions', type: 'find', query: { case: 1 } } }).catch(err => { return err; });
|
||||
let response = await this.client.transactionHandler.send({ provider: 'mongodb', request: { collection: 'infractions', type: 'find', query: { case: 1 } } }).catch(err => { return err; });
|
||||
const time2 = new Date().getTime();
|
||||
console.log(time2-time1);
|
||||
|
||||
|
@ -15,7 +15,7 @@ class ClientPermissions extends Inhibitor {
|
||||
}
|
||||
|
||||
execute(message, command) {
|
||||
const missing = message.channel.permissionsFor(message.guild.me).missing(command.memberPermissions);
|
||||
const missing = message.channel.permissionsFor(message.guild.me).missing(command.clientPermissions);
|
||||
if(missing.length > 0) {
|
||||
return super._fail(stripIndents`The command **${command.resolveable}** requires the bot to have permissions to use.
|
||||
*Missing: ${missing.join(', ')}*`);
|
||||
|
@ -53,12 +53,14 @@ class CommandHandler extends Observer {
|
||||
|
||||
async _getCommand(message, [arg1, arg2, ...args]) {
|
||||
|
||||
const prefix = this.client._options.bot.prefix; //Change this for guild prefix settings.
|
||||
if(message.guild) await message.guild.settings();
|
||||
const prefix = message.guild?.prefix || this.client._options.bot.prefix;
|
||||
|
||||
let command = null;
|
||||
let remains = [];
|
||||
|
||||
if(arg1 && arg1.startsWith(prefix)) {
|
||||
const commandName = arg1.slice(1);
|
||||
const commandName = arg1.slice(prefix.length);
|
||||
command = await this._matchCommand(message, commandName);
|
||||
remains = [arg2, ...args];
|
||||
} else if(arg1 && arg2 && arg1.startsWith('<@')){
|
||||
@ -165,7 +167,10 @@ class CommandHandler extends Observer {
|
||||
const [one,two,...chars] = word.split('');
|
||||
if(one === '-' && two !== '-') {
|
||||
const name = [ two, ...chars ].join('');
|
||||
if(!keys.includes(name)) continue;
|
||||
if(!keys.includes(name)) {
|
||||
params.push(word);
|
||||
continue;
|
||||
}
|
||||
currentArgument = shortFlags[name];
|
||||
if(currentArgument.type === 'BOOLEAN') {
|
||||
currentArgument.value = currentArgument.default;
|
||||
@ -177,11 +182,14 @@ class CommandHandler extends Observer {
|
||||
return this._handleError({ type: 'argument', info: { argument: currentArgument, word, missing: true }, message });
|
||||
}
|
||||
continue;
|
||||
} else if((one === '-' && two === '-') || one === '—') { //Handling for "long dash" on mobile phones x_x
|
||||
} else if((one === '-' && two === '-') || (one === '—')) { //Handling for "long dash" on mobile phones x_x
|
||||
const name = one === '—'
|
||||
? [ two, ...chars ].join('').toLowerCase()
|
||||
: chars.join('').toLowerCase(); //can convert to lowercase now that shortFlags are out of the way.
|
||||
if(!keys.includes(name)) continue;
|
||||
if(!keys.includes(name)) {
|
||||
params.push(word);
|
||||
continue;
|
||||
}
|
||||
currentArgument = longFlags[name];
|
||||
if(currentArgument.type === 'BOOLEAN') {
|
||||
currentArgument.value = currentArgument.default;
|
||||
|
54
structure/client/components/settings/utility/GuildPrefix.js
Normal file
54
structure/client/components/settings/utility/GuildPrefix.js
Normal file
@ -0,0 +1,54 @@
|
||||
const { Setting } = require('../../../../interfaces/');
|
||||
|
||||
class GuildPrefixSetting extends Setting {
|
||||
|
||||
constructor(client, opts = {}) {
|
||||
|
||||
super(client, {
|
||||
name: 'guildPrefix',
|
||||
index: 'prefix',
|
||||
module: 'utility',
|
||||
display: 'prefix',
|
||||
aliases: [
|
||||
'prefix'
|
||||
],
|
||||
guarded: true,
|
||||
resolve: 'GUILD',
|
||||
default: {
|
||||
prefix: "-"
|
||||
},
|
||||
custom: true
|
||||
});
|
||||
|
||||
this.client = client;
|
||||
|
||||
}
|
||||
|
||||
async handle(message, params, operator) {
|
||||
|
||||
if (operator === 'RESET') {
|
||||
return await super._handleReset(message, params);
|
||||
}
|
||||
|
||||
// let { params, parsedArguments } = await this._parseArguments(params);
|
||||
|
||||
let [ prefix ] = params;
|
||||
|
||||
const MaxCharacters = 6;
|
||||
if(prefix.length > MaxCharacters) return {
|
||||
msg: message.format('S_GPREFIX_LENGTH', { length: prefix.length, max: MaxCharacters }),
|
||||
error: true
|
||||
};
|
||||
|
||||
await message.guild._updateSettings({ prefix });
|
||||
return {
|
||||
msg: message.format(`S_${this.name.toUpperCase()}_SUCCESS`, { prefix }),
|
||||
error: false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
module.exports = GuildPrefixSetting;
|
@ -15,12 +15,110 @@ const Guild = Structures.extend('Guild', (Guild) => {
|
||||
|
||||
async settings() {
|
||||
|
||||
if (!this._settings) this._settings = this.client.transactionHandler._send({ provider: 'mongodb', request: { collection: 'guild_settings', type: 'findOne', query: { guild: this.id } } });
|
||||
if (this._settings instanceof Promise) this._settings = await this._settings || { };
|
||||
if(!this._settings) this._settings = this.client.transactionHandler.send({ provider: 'mongodb', request: { collection: 'guilds', type: 'findOne', query: { guildId: this.id } } });
|
||||
if(this._settings instanceof Promise) this._settings = await this._settings || null
|
||||
if(!this._settings) {
|
||||
this._settings = this.client.defaultConfig;
|
||||
}
|
||||
|
||||
return this._settings;
|
||||
|
||||
}
|
||||
|
||||
/* Database Shortcuts */
|
||||
|
||||
async _deleteSettings() { //Delete whole entry - remove
|
||||
try {
|
||||
await this.client.transactionHandler.send({
|
||||
provider: 'mongodb',
|
||||
request: {
|
||||
type: 'remove',
|
||||
collection: 'guilds',
|
||||
query: {
|
||||
guildId: this.id
|
||||
}
|
||||
}
|
||||
});
|
||||
this._settings = this.client.defaultConfig;
|
||||
this._storageLog(`Database Delete (guild:${this.id}).`);
|
||||
} catch(error) {
|
||||
this._storageError(error);
|
||||
}
|
||||
}
|
||||
|
||||
async _updateSettings(data) { //Update property (upsert true) - updateOne
|
||||
try {
|
||||
await this.client.transactionHandler.send({
|
||||
provider: 'mongodb',
|
||||
request: {
|
||||
type: 'updateOne',
|
||||
collection: 'guilds',
|
||||
query: {
|
||||
guildId: this.id
|
||||
},
|
||||
data
|
||||
}
|
||||
});
|
||||
this._settings = {
|
||||
...this._settings,
|
||||
...data
|
||||
};
|
||||
this._storageLog(`Database Update (guild:${this.id}).`);
|
||||
} catch(error) {
|
||||
this._storageError(error);
|
||||
}
|
||||
}
|
||||
|
||||
async _removeSettings(value) { //Remove property
|
||||
if(this.client.defaultConfig[value]) {
|
||||
await this._updateSettings(this.client.defaultConfig[value]);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.client.transactionHandler.send({
|
||||
provider: 'mongodb',
|
||||
request: {
|
||||
type: 'removeProperty',
|
||||
collection: 'guilds',
|
||||
query: {
|
||||
guildId: this.id
|
||||
},
|
||||
data: [
|
||||
value
|
||||
]
|
||||
}
|
||||
});
|
||||
delete this._settings[value];
|
||||
this._storageLog(`Database Remove (guild:${this.id}).`);
|
||||
} catch(error) {
|
||||
this._storageError(error);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
async _createSettings(data) {
|
||||
try {
|
||||
this.client.transactionHandler.send({
|
||||
provider: 'mongodb',
|
||||
request: {
|
||||
type: 'insertOne',
|
||||
collection: 'guilds',
|
||||
data: {
|
||||
guildId: this.id,
|
||||
...data
|
||||
}
|
||||
}
|
||||
});
|
||||
this._storageLog(`Database Create (guild:${this.id}).`);
|
||||
} catch(error) {
|
||||
this._storageError(error);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/* Language Formatting */
|
||||
|
||||
format(key, parameters = {}) {
|
||||
|
||||
const language = this._settings.locale || "en_us"; //this._settings.language or something idk
|
||||
@ -33,6 +131,8 @@ const Guild = Structures.extend('Guild', (Guild) => {
|
||||
|
||||
}
|
||||
|
||||
/* Resolver Shortcuts */
|
||||
|
||||
async resolveMembers(members, strict = false) {
|
||||
|
||||
return await this.client.resolver.resolveMembers(members, this, strict);
|
||||
@ -72,6 +172,22 @@ const Guild = Structures.extend('Guild', (Guild) => {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Logging */
|
||||
|
||||
_storageLog(log) {
|
||||
this.client.logger.debug(log)
|
||||
}
|
||||
|
||||
_storageError(error) {
|
||||
this.client.logger.error(`Database Error (guild:${this.id}) : \n${error.stack || error}`)
|
||||
}
|
||||
|
||||
get prefix() {
|
||||
return this._settings.prefix;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ExtendedGuild;
|
||||
|
@ -26,15 +26,17 @@ const Message = Structures.extend('Message', (Message) => {
|
||||
let language = this.author._settings.locale || 'en_us';
|
||||
if(this.guild && this.guild._settings.locale) language = this.guild._settings.locale;
|
||||
|
||||
parameters.prefix = this.guild && this.guild._settings.prefix ? this.guild._settings.prefix : this.client._options.bot.prefix ;
|
||||
parameters.prefix = this.guild ? this.guild.prefix : this.client._options.bot.prefix;
|
||||
let template = this.client.localeLoader.template(language, index); //.languages[language][index];
|
||||
|
||||
if(!template) {
|
||||
return `**Missing language index \`${language} [${index}]\` in languages. Contact a bot developer about this.**`;
|
||||
}
|
||||
|
||||
for (const [param, val] of Object.entries(parameters)) {
|
||||
template = template.replace(new RegExp(`{${escapeRegex(param.toLowerCase())}}`, 'gi'), val);
|
||||
}
|
||||
|
||||
template = template.replace(new RegExp(`\r`, 'gi'), '\n');
|
||||
|
||||
if(code) {
|
||||
try {
|
||||
template = eval(template);
|
||||
@ -86,6 +88,7 @@ const Message = Structures.extend('Message', (Message) => {
|
||||
if(opts.reply) str = `<@!${this.author.id}> ${str}`;
|
||||
}
|
||||
|
||||
//console.log(str)
|
||||
this._pending = await this.channel.send(str);
|
||||
return this._pending;
|
||||
|
||||
@ -100,6 +103,21 @@ const Message = Structures.extend('Message', (Message) => {
|
||||
return super.edit(str);
|
||||
}
|
||||
|
||||
async prompt(str, opts) {
|
||||
if(typeof str === 'string') {
|
||||
if(opts.emoji) str = `${emojis[opts.emoji]} ${str}`;
|
||||
if(opts.reply) str = `<@!${this.author.id}> ${str}`;
|
||||
}
|
||||
const message = await this.channel.send(str);
|
||||
return await this.channel.awaitMessages(m => m.author.id === this.author.id, { max: 1, time: 30000, errors: ['time'] })
|
||||
.then((collected) => {
|
||||
return collected.first();
|
||||
})
|
||||
.catch((error) => {
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
async _showUsage() {
|
||||
//TODO: format this
|
||||
return await this.embed({
|
||||
|
@ -20,7 +20,7 @@ const User = Structures.extend('User', (User) => {
|
||||
|
||||
async settings() {
|
||||
|
||||
if (!this._settings) this._settings = this.client.transactionHandler._send({ provider: 'mongodb', request: { collection: 'user_settings', type: 'findOne', query: { user: this.id } } });
|
||||
if (!this._settings) this._settings = this.client.transactionHandler.send({ provider: 'mongodb', request: { collection: 'users', type: 'findOne', query: { user: this.id } } });
|
||||
if (this._settings instanceof Promise) this._settings = await this._settings || {};
|
||||
return this._settings;
|
||||
|
||||
|
@ -25,13 +25,42 @@ class Setting extends Component {
|
||||
this.aliases = opts.aliases || [];
|
||||
this.resolve = (opts.resolve && Constants.Resolves.includes(opts.resolve)) ? opts.resolve : 'GUILD';
|
||||
this.default = opts.default;
|
||||
this.arguments = opts.arguments || [];
|
||||
this.custom = Boolean(opts.custom);
|
||||
this.display = opts.display || opts.name;
|
||||
|
||||
this.memberPermissions = opts.memberPermissions || [];
|
||||
this.clientPermissions = opts.clientPermissions || [];
|
||||
|
||||
this._commandHandler = null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
async handle() {
|
||||
this.client.logger.error(`No handle function found in ${this.moduleResolveable}.`);
|
||||
}
|
||||
|
||||
async _parseArguments(params) {
|
||||
|
||||
const { parsedArguments, newArgs } = await this.commandHandler._parseArguments(this.arguments, params);
|
||||
return { parsedArguments, params: newArgs };
|
||||
|
||||
}
|
||||
|
||||
async _handleReset(message, params) {
|
||||
const response = await message.prompt(message.format('UHHH'), { error: 'warning' });
|
||||
|
||||
}
|
||||
|
||||
get commandHandler() {
|
||||
if(this._commandHandler) return this._commandHandler;
|
||||
else return this._commandHandler = this.client.registry.components.get('observer:commandHandler');
|
||||
}
|
||||
|
||||
|
||||
get moduleResolveable() {
|
||||
return `${this.module.id}:${this.id}`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ class Infraction {
|
||||
|
||||
async save() {
|
||||
|
||||
await this.client.transactionHandler._send({
|
||||
await this.client.transactionHandler.send({
|
||||
provider: 'mongodb',
|
||||
request: {
|
||||
type: 'insertOne',
|
||||
|
Loading…
Reference in New Issue
Block a user