diff --git a/package.json b/package.json index 7314ac9..a45b87e 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "mongodb": "^3.5.9", "mysql": "^2.18.1", "node-fetch": "^2.6.0", + "request": "^2.88.2", "similarity": "^1.2.1", "timestring": "^6.0.0", "winston": "^3.2.1", diff --git a/structure/client/DiscordClient.js b/structure/client/DiscordClient.js index 3a50eaf..425ee94 100644 --- a/structure/client/DiscordClient.js +++ b/structure/client/DiscordClient.js @@ -15,7 +15,7 @@ const ModerationManager = require('../moderation/ModerationManager.js'); const { Guild, GuildMember, User, Message, TextChannel, Role } = require('../../structure/extensions/'); //eslint-disable-line no-unused-vars const { Command, Observer, Inhibitor, Setting } = require('../../structure/interfaces/'); -const { DefaultGuild } = require('../../util/defaults/'); +const { DefaultGuild, DefaultUser } = require('../../util/defaults/'); class DiscordClient extends Client { @@ -38,7 +38,7 @@ class DiscordClient extends Client { this._built = false; //TODO: Default config for users and guilds. - this._defaultConfig = null; + this._defaultConfig = {}; this._permissionCheck = null; this._evals = new Map(); @@ -110,10 +110,10 @@ 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 = DefaultGuild; + defaultConfig(type) { + if(this._defaultConfig[type]) return this._defaultConfig[type]; + const settings = this.registry.components.filter((c) => c.type === 'setting' && c.resolve === type); + let def = type === 'GUILD' ? DefaultGuild : DefaultUser; for(const setting of settings.values()) { if(setting.default !== null) { def = { @@ -122,7 +122,7 @@ class DiscordClient extends Client { }; } } - this._defaultConfig = def; + this._defaultConfig[type] = def; return def; } diff --git a/structure/client/components/commands/administration/Settings.js b/structure/client/components/commands/administration/Settings.js index 3d38b6c..ffd1aae 100644 --- a/structure/client/components/commands/administration/Settings.js +++ b/structure/client/components/commands/administration/Settings.js @@ -155,9 +155,9 @@ class SettingsCommand extends Command { for(const setting of module.components.values()) { if(setting.type !== 'setting' - || setting.resolve !== type && !all + || type !== setting.resolve || !setting.archivable && !all) continue; - field.value += `\`${setting.display}\`\n`; + field.value += `\`${message.author._settings.camelCase ? setting.name : setting.name.toLowerCase()}\`\n`; } if(field.value) fields.push(field); } diff --git a/structure/client/components/commands/information/PrivacyPolicy.js b/structure/client/components/commands/information/PrivacyPolicy.js new file mode 100644 index 0000000..73ad52a --- /dev/null +++ b/structure/client/components/commands/information/PrivacyPolicy.js @@ -0,0 +1,40 @@ +const { Command } = require('../../../../interfaces/'); + +class PrivacyPolicyCommand extends Command { + + constructor(client) { + + super(client, { + name: 'privacyPolicy', + module: 'information', + aliases: ['privacy'] + }); + + } + + async execute(message) { + const embed = { + author: { + name: 'Privacy Policy', + icon_url: this.client.user.displayAvatarURL() //eslint-disable-line camelcase + }, + description: message.format('C_PRIVACYPOLICY_PRIVACYDESCRIPTION', { invite: this.client._options.bot.invite }), + fields: [ + { + name: 'Data We Collect', + value: message.format('C_PRIVACYPOLICY_DATA', { invite: this.client._options.bot.invite }), + inline: true + }, + { + name: 'Opt-Out Features', + value: message.format('C_PRIVACYPOLICY_OPTOUT'), + inline: true + } + ] + }; + return message.embed(embed); + } + +} + +module.exports = PrivacyPolicyCommand; \ No newline at end of file diff --git a/structure/client/components/commands/utility/Ping.js b/structure/client/components/commands/utility/Ping.js index a9ee54c..1d9f1ef 100644 --- a/structure/client/components/commands/utility/Ping.js +++ b/structure/client/components/commands/utility/Ping.js @@ -6,7 +6,10 @@ class PingCommand extends Command { super(client, { name: 'ping', - module: 'utility' + module: 'utility', + aliases: [ + 'pong' + ] }); this.client = client; @@ -18,7 +21,7 @@ class PingCommand extends Command { const ping = this.client.ws.ping.toFixed(0); const number = (ping/40).toFixed(0); const repeat = number > 1 ? number : 1; - return message.respond(`P${'o'.repeat(repeat)}ng! \`${ping}ms\``, { emoji: 'success' }); + return message.respond(`P${`${message._caller === 'ping' ? 'o' : 'i'}`.repeat(repeat)}ng! \`${ping}ms\``, { emoji: 'success' }); } } diff --git a/structure/client/components/commands/utility/Test.js b/structure/client/components/commands/utility/Test.js index 5b89d35..e4d1e9d 100644 --- a/structure/client/components/commands/utility/Test.js +++ b/structure/client/components/commands/utility/Test.js @@ -6,18 +6,17 @@ class TestCommand extends Command { super(client, { name: 'test', - module: 'utility' + module: 'developer', + archivable: false, + restricted: true }); this.client = client; } - execute(message) { + async execute(message) { - for(const blah of message) { - console.log(blah); - } } diff --git a/structure/client/components/observers/CommandHandler.js b/structure/client/components/observers/CommandHandler.js index 0dd481c..f05942b 100644 --- a/structure/client/components/observers/CommandHandler.js +++ b/structure/client/components/observers/CommandHandler.js @@ -348,6 +348,7 @@ class CommandHandler extends Observer { const [ arg1, arg2, ...args ] = message.content.split(' '); if(message.guild) await message.guild.settings(); + await message.author.settings(); const { prefix } = message; let command = null, diff --git a/structure/client/components/observers/GuildLogging.js b/structure/client/components/observers/GuildLogging.js index 2184242..cc01543 100644 --- a/structure/client/components/observers/GuildLogging.js +++ b/structure/client/components/observers/GuildLogging.js @@ -350,8 +350,8 @@ class GuildLogger extends Observer { .replace(/\{mention\}/gu, `<@${member.id}>`) .replace(/\{tag\}/gu, Util.escapeMarkdown(user.tag)) .replace(/\{user\}/gu, Util.escapeMarkdown(user.username)) - .replace(/\{guildsize\}/gu, guild.memberCount) - .replace(/\{guildname\}/gu, guild.name) + .replace(/\{serversize\}/gu, guild.memberCount) + .replace(/\{servername\}/gu, guild.name) .replace(/\{accage\}/gu, this.client.resolver.timeAgo(Date.now()/1000 - user.createdTimestamp/1000)) //.replace(/a/, '1') .replace(/\{id\}/gu, user.id) .trim(); diff --git a/structure/client/components/observers/MessageCache.js b/structure/client/components/observers/MessageCache.js index d690d5a..1e28fa2 100644 --- a/structure/client/components/observers/MessageCache.js +++ b/structure/client/components/observers/MessageCache.js @@ -178,7 +178,7 @@ class MessageCache extends Observer { const messageCount = deleteMessages.deletedCount; const attachmentCount = deleteAttachments.deletedCount; - this.client.logger.info(`${chalk.bold('[IMAGE]')} Trashed ${messageCount} messages${messageCount === 1 ? '' : 's'} and ${attachmentCount} attachment${attachmentCount === 1 ? '' : 's'}.`); + this.client.logger.info(`${chalk.bold('[IMAGE]')} Trashed ${messageCount} message${messageCount === 1 ? '' : 's'} and ${attachmentCount} attachment${attachmentCount === 1 ? '' : 's'}.`); } diff --git a/structure/client/components/observers/UtilityHook.js b/structure/client/components/observers/UtilityHook.js index ff77ce7..ce4abe2 100644 --- a/structure/client/components/observers/UtilityHook.js +++ b/structure/client/components/observers/UtilityHook.js @@ -128,8 +128,8 @@ class UtilityHook extends Observer { .replace(/\{mention\}/gu, `<@${member.id}>`) .replace(/\{tag\}/gu, Util.escapeMarkdown(user.tag)) .replace(/\{user\}/gu, Util.escapeMarkdown(user.username)) - .replace(/\{guildsize\}/gu, guild.memberCount) - .replace(/\{guildname\}/gu, guild.name) + .replace(/\{serversize\}/gu, guild.memberCount) + .replace(/\{servername\}/gu, guild.name) .replace(/\{accage\}/gu, this.client.resolver.timeAgo(Date.now()/1000 - user.createdTimestamp/1000)) //.replace(/a/, '1') .replace(/\{id\}/gu, user.id) .trim(); diff --git a/structure/client/components/settings/developer/CamelCase.js b/structure/client/components/settings/developer/CamelCase.js new file mode 100644 index 0000000..87d5d16 --- /dev/null +++ b/structure/client/components/settings/developer/CamelCase.js @@ -0,0 +1,45 @@ +const { Setting } = require('../../../../interfaces/'); + +class CamelCaseSetting extends Setting { + + constructor(client) { + super(client, { + name: 'camelCase', + module: 'developer', + resolve: 'USER', + default: { + camelCase: false + }, + restricted: true, + archivable: false + }); + } + + async handle(message, params) { + + const boolean = this.client.resolver.resolveBoolean(params.join(' ')); + if(boolean === null) { + return { + msg: `Unable to parse boolean value.`, + error: true + }; + } + + await message.author._updateSettings({ [this.index]: boolean }); + return { + msg: `Successfully set camelCase to \`${boolean}\`.`, + error: false + }; + + } + + fields(user) { + return { + name: "》 Status", + value: user.format('SETTING_STATUS', { bool: Boolean(user._settings.camelcase) }, true) + }; + } + +} + +module.exports = CamelCaseSetting; \ No newline at end of file diff --git a/structure/client/components/settings/moderation/MemberLogs.js b/structure/client/components/settings/moderation/MemberLogs.js index 782b382..b41adf6 100644 --- a/structure/client/components/settings/moderation/MemberLogs.js +++ b/structure/client/components/settings/moderation/MemberLogs.js @@ -19,12 +19,12 @@ class MemberLogsSetting extends Setting { 'leaveMsg' ], tags: ['log', 'logs', 'logging'], - usage: ' [value]', + usage: " ", resolve: 'GUILD', examples: [ 'memberlogs #channel', - 'memberlogs join|leave ', - 'memberlogs reset', + 'memberlogs join {mention} joined the server!', + 'memberlogs leave **{tag}** ({id}) left the server.', 'memberlogs off' ], default: { diff --git a/structure/client/components/settings/moderation/Mute.js b/structure/client/components/settings/moderation/Mute.js index b86bb0a..36c5d35 100644 --- a/structure/client/components/settings/moderation/Mute.js +++ b/structure/client/components/settings/moderation/Mute.js @@ -1,6 +1,37 @@ const { Setting } = require('../../../../interfaces/'); -const emojis = require('../../../../../util/emojis.json'); -const maxCharacters = 98; +const { Emojis } = require('../../../../../util/'); + +const { PermissionNames, EmbedLimits } = require('../../../../../util/Constants.js'); + +const Constants = { + Types: { + role: [ + 'muteRole', + 'mutedRole' + ], + create: [ + 'createMute', + 'createMuted', + 'createMuteRole', + 'createMutedRole' + ], + type: [ + 'muteType', + 'mutedType' + ], + permanent: [ + 'permaMute', + 'permanentMute' + ], + duration: [ + 'defaultMuteDuration', + 'muteDuration' + ] + }, + MuteTypes: [0, 1, 2], + MaxCharacters: 98, + MaxIssues: 6 +}; const { stripIndents } = require('common-tags'); @@ -25,52 +56,27 @@ class MuteSetting extends Setting { 'permanentMute', 'defaultMuteDuration' ], - arguments: [ - { - name: 'create', - type: 'BOOLEAN', - types: ['VERBAL'], - default: true - }, - { - name: 'type', - type: 'BOOLEAN', - types: ['VERBAL'], - default: true - }, - { - name: 'permanent', - aliases: ['perm', 'perma'], - type: 'BOOLEAN', - types: ['VERBAL'], - default: true - }, - { - name: 'defaultDuration', - aliases: ['duration'], - type: 'BOOLEAN', - types: ['VERBAL'], - default: true - }, - { - name: 'text', - type: 'BOOLEAN', - types: ['FLAG'], - default: true - }, - { - name: 'voice', - type: 'BOOLEAN', - types: ['FLAG'], - default: true - } - ], - usage: '[type|role|create|permanent|duration] [value]', + // arguments: [ + // { + // name: 'text', + // type: 'BOOLEAN', + // types: ['FLAG'], + // default: true + // }, + // { + // name: 'voice', + // type: 'BOOLEAN', + // types: ['FLAG'], + // default: true + // } + // ], + usage: "<'create'|'type'|'permanent'|'default'|role> ", examples: [ - 'createmute Muted', - 'mutetype 1', - 'permamute true', - 'mute default 1 day' + "mute muted-role", + "mute create Muted", + "mute type 1", + "mute permanent true", + "mute default 1 day" ], resolve: 'GUILD', default: { @@ -85,6 +91,237 @@ class MuteSetting extends Setting { } + async handle(message, args) { + + const { params, parsedArguments } = await this._parseArguments(args, message.guild); + if(params.length === 0) { + return { + msg: message.format('S_MUTE_MISSINGARGUMENTS'), + error: true + }; + } + + let type = 'role'; + let parameters = params.join(' '); + + if(!['mute', 'muted'].includes(message._settingCaller)) { + for(const [ key, values ] of Object.entries(Constants.Types)) { + if(values.map((v) => v.toLowerCase()).includes(message._settingCaller.toLowerCase())) { + type = key; + break; + } + } + } else { + const key = params[0].toLowerCase(); + if(['create', 'createrole'].includes(key)) type = 'create', parameters = params.splice(1).join(' '); //eslint-disable-line no-unused-expressions, no-sequences + if(['type'].includes(key)) type = 'type', parameters = params.splice(1).join(' '); //eslint-disable-line no-unused-expressions, no-sequences + if(['duration', 'defaultduration'].includes(key)) type = 'duration', parameters = params.splice(1).join(' '); //eslint-disable-line no-unused-expressions, no-sequences + if(['perma', 'permamute', 'permanent'].includes(key)) type = 'permanent', parameters = params.splice(1).join(' '); //eslint-disable-line no-unused-expressions, no-sequences + } + + if(type === 'role') { + + const role = await this.client.resolver.resolveRole(parameters, true, message.guild); + if(!role) return { + msg: message.format('S_MUTE_ROLEMISSING'), + error: true + }; + + await message.guild._updateSettings({ + [this.index]: { + ...message.guild._settings[this.index], + role: role.id + } + }); + + message.respond(message.format('S_MUTE_ROLESUCCESS'), { + emoji: 'success' + }); + + } else if(type === 'create') { + + const response = await this._createRole(message, parameters, parsedArguments); + if(response.error) return response; + + const { role, issues, created, updatedPermissions } = response; + + await message.guild._updateSettings({ + [this.index]: { + ...message.guild._settings[this.index], + role: role.id + } + }); + + const sorted = issues ? issues.sort((a, b) => a.position - b.position) : []; + + const embed = { + author: { + name: `${Emojis.warning} Warning` + }, + color: 0xffe15c, + description: message.format('S_MUTE_CREATESUCCESSWARNING'), + fields: [] + }; + + const addField = (array, type) => { + const field = { + name: type === 'text' ? 'Text Channels' : 'Voice Channels', + value: '' + }; + const sorted = array.sort((a, b) => a.position - b.position) || []; + for(const i of sorted) { + const text = `${Emojis.role} **${i.role}** has ${i.permissions.map((p) => `\`${PermissionNames[p]}\``).join(', ')} in ${Emojis[i.type === 'text' ? 'text-channel' : 'voice-channel']} **${i.channel}**\n`; + if(field.value.length+text.length <= EmbedLimits.fieldValue) field.value += text; + } + return field; + }; + + const textIssues = issues.filter((i) => i.type === 'text'); + if(textIssues.length > 0) embed.fields.push(addField(textIssues, 'text')); + + const voiceIssues = issues.filter((i) => i.type === 'voice'); + if(voiceIssues.length > 0) embed.fields.push(addField(voiceIssues, 'voice')); + + message.respond(message.format('S_MUTE_CREATESUCCESS', { + created: created ? message.format('S_MUTE_CREATESUCCESSALT') : ' ', + permissions: message.format(updatedPermissions ? 'S_MUTE_GENERATEDPERMISSIONS' : 'S_MUTE_UNGENERATEDPERMISSIONS'), + role: role.name + }), { + emoji: 'success', + embed: issues.length > 0 ? embed : null + }); + + } else if(type === 'type') { + + const number = parseInt(num); + if(Number.isNaN(number)) return { + msg: message.format('S_MUTE_TYPENAN'), + error: true + }; + + if(!Constants.MuteTypes.includes(number)) return { + msg: message.format('S_MUTE_TYPEINVALID'), + error: true + }; + + await message.guild._updateSettings({ + [this.index]: { + ...message.guild._settings[this.index], + type: number + } + }); + + return { + msg: `${message.format('S_MUTE_TYPESUCCESS', { type: number })} ${message.format('S_MUTE_TYPESWITCH', { type: number }, true)}`, + error: false + }; + + } else if(type === 'duration') { + + } else if(type === 'permanent') { + + } + + return { + error: false, + ignore: true + }; + + } + + async _createRole(message, name = 'Muted', args) { + + const createRole = async (name) => { + let role = null; + if(name.length > Constants.MaxCharacters) name = name.slice(0, Constants.MaxCharacters); + try { + role = await message.guild.roles.create({ + data: { + name + }, + reason: super.reason(message.author) + }); + } catch(error) { + return { + msg: message.format('S_MUTE_ROLECREATEERROR'), + error: true + }; + } + return role; + }; + + const hasPermission = message.guild.me.hasPermission('MANAGE_ROLES'); + if(!hasPermission) return { + msg: message.format('S_MUTE_ROLEMISSINGPERMISSION'), + error: true + }; + + let role = null; + + const existing = await this.client.resolver.resolveRole(name, true, message.guild); + if(existing) { + const prompt = await message.prompt(message.format('S_MUTE_ROLEPROMPT', { + name: existing.name, + id: existing.id + }), { emoji: 'loading' }); + const boolean = this.client.resolver.resolveBoolean(prompt.content.toLowerCase()); + if(boolean === null) return { + msg: message.format('S_MUTE_ROLEPROMPTERROR'), + error: true + }; + if(boolean) { + role = existing; + } + } + + let created = false; + + if(!role) { + role = await createRole(name); + if(role.error) return role; + created = true; + } + + const issues = []; + let updatedPermissions = false; + + for(const channel of message.guild.channels.cache.values()) { + const configuration = channel.type === 'text' + ? { permissions: { SEND_MESSAGES: false, ADD_REACTIONS: false }, bitwise: 0x800 } + : { permissions: { CONNECT: false }, bitwise: 0x100000 }; + try { + if(channel.type === 'text' || channel.type === 'voice') { + await channel.createOverwrite(role, configuration.permissions, super.reason(message.author)); + for(const permission of channel.permissionOverwrites.values()) { + if(permission.type !== 'role') continue; + const permissionRole = await this.client.resolver.resolveRole(permission.id, true, message.guild); + if((permission.allow & configuration.bitwise) === configuration.bitwise) { //eslint-disable-line no-bitwise + const issue = { + role: permissionRole.name, + permissions: Object.keys(configuration.permissions), + channel: channel.name, + type: channel.type, + position: permissionRole.rawPosition + }; + issues.push(issue); + } + } + } + updatedPermissions = true; + } catch(error) {} //eslint-disable-line no-empty + } + + return { + error: false, + updatedPermissions, + created, + issues, + role + }; + + } + + /* async handle(message, args) { let { params, parsedArguments } = await this._parseArguments(args, message.guild); //eslint-disable-line prefer-const @@ -250,6 +487,9 @@ class MuteSetting extends Setting { } + */ + + /* async _createRole(message, args) { let role = null; let name = args.join(' ') || 'Muted'; @@ -269,6 +509,7 @@ class MuteSetting extends Setting { } return role; } + */ fields(guild) { const setting = guild._settings[this.index]; diff --git a/structure/extensions/Guild.js b/structure/extensions/Guild.js index d983a2c..d7d5a0b 100644 --- a/structure/extensions/Guild.js +++ b/structure/extensions/Guild.js @@ -201,7 +201,7 @@ const Guild = Structures.extend('Guild', (Guild) => { /* Lazy Developer Getters */ get defaultConfig() { - return JSON.parse(JSON.stringify(this.client.defaultConfig)); + return JSON.parse(JSON.stringify(this.client.defaultConfig('GUILD'))); } get prefix() { diff --git a/structure/extensions/User.js b/structure/extensions/User.js index 0d9da51..ff856b8 100644 --- a/structure/extensions/User.js +++ b/structure/extensions/User.js @@ -21,6 +21,8 @@ const User = Structures.extend('User', (User) => { async settings() { if (!this._settings) this._settings = this.client.storageManager.mongodb.users.findOne({ userId: this.id }); if (this._settings instanceof Promise) this._settings = await this._settings || {}; + if(!this._settings) this._settings = { userId: this.id, ...this.defaultConfig }; + else this._settings = { ...this.defaultConfig, ...this._settings }; return this._settings; } @@ -56,6 +58,42 @@ const User = Structures.extend('User', (User) => { return points.reduce((p, v) => p+v) + this._points.points; } + /* Settings Wrapper */ + + async _updateSettings(data) { //Update property (upsert true) - updateOne + if(!this._settings) await this.settings(); + try { + await this.client.storageManager.mongodb.users.updateOne( + { guildId: this.id }, + data + ); + this._settings = { + ...this._settings, + ...data + }; + this._storageLog(`Database Update (guild:${this.id}).`); + } catch(error) { + this._storageError(error); + } + return true; + } + + /* Logging */ + + _storageLog(log) { + this.client.logger.debug(log); + } + + _storageError(error) { + this.client.logger.error(`Database Error (user:${this.id}) : \n${error.stack || error}`); + } + + /* Lazy Getters */ + + get defaultConfig() { + return JSON.parse(JSON.stringify(this.client.defaultConfig('USER'))); + } + get developer() { return this.client._options.bot.owners.includes(this.id); } diff --git a/structure/language/languages/en_us/en_us_arguments.lang b/structure/language/languages/en_us/en_us_arguments.lang new file mode 100644 index 0000000..b839ffd --- /dev/null +++ b/structure/language/languages/en_us/en_us_arguments.lang @@ -0,0 +1,230 @@ +//Command Arguments + + +//Administration Module + + +//Settings Command +[A_EXPORT_SETTINGS_DESCRIPTION] +Export a JSON file of all of the settings for the server or user. + +[A_USER_SETTINGS_DESCRIPTION] +View or edit user-only settings. + +//Grant Command +[A_CHANNEL_GRANT_DESCRIPTION] +Specify channels to grant specific permissions to. + +//Revoke Command +[A_CHANNEL_REVOKE_DESCRIPTION] +Specify channels to revoke permissions from. + +//Permissions Command +[A_EXPORT_PERMISSIONS_DESCRIPTION] +Export a JSON file of all of the permissions in the server. + + +//Developer Module + + +//Evaluate Command +[A_LOG_EVALUATE_DESCRIPTION] +Prints the evaluation to the console. + +[A_HIDE_EVALUATE_DESCRIPTION] +Hides the evaluation from public view. + + +//Moderation Module + + +//Note Command +[A_SILENT_NOTE_DESCRIPTION] +Deletes the command message and the execution message. + +//Warn Command +[A_SILENT_WARN_DESCRIPTION] +Deletes the command message and the execution message. + +[A_POINTS_WARN_DESCRIPTION] +Assign moderation points to the user. + +[A_EXPIRATION_WARN_DESCRIPTION] +Assign a duration for the moderation points to expire. + +[A_FORCE_WARN_DESCRIPTION] +Bypasses the moderation point escalation. + +[A_PRUNE_WARN_DESCRIPTION] +Removes messages from the user. + +//Unmute Command +[A_SILENT_UNMUTE_DESCRIPTION] +Deletes the command message and the execution message. + +//Mute Command +[A_SILENT_MUTE_DESCRIPTION] +Deletes the command message and the execution message. + +[A_POINTS_MUTE_DESCRIPTION] +Assign moderation points to the user. + +[A_EXPIRATION_MUTE_DESCRIPTION] +Assign a duration for the moderation points to expire. + +[A_FORCE_MUTE_DESCRIPTION] +Bypasses the moderation point escalation. + +[A_PRUNE_MUTE_DESCRIPTION] +Removes messages from the user. + +//Kick Command +[A_SILENT_KICK_DESCRIPTION] +Deletes the command message and the execution message. + +[A_POINTS_KICK_DESCRIPTION] +Assign moderation points to the user. + +[A_EXPIRATION_KICK_DESCRIPTION] +Assign a duration for the moderation points to expire. + +[A_FORCE_KICK_DESCRIPTION] +Bypasses the moderation point escalation. + +[A_PRUNE_KICK_DESCRIPTION] +Removes messages from the user. + +//Softban Command +[A_SILENT_SOFTBAN_DESCRIPTION] +Deletes the command message and the execution message. + +[A_POINTS_SOFTBAN_DESCRIPTION] +Assign moderation points to the user. + +[A_EXPIRATION_SOFTBAN_DESCRIPTION] +Assign a duration for the moderation points to expire. + +[A_FORCE_SOFTBAN_DESCRIPTION] +Bypasses the moderation point escalation. + +[A_DAYS_SOFTBAN_DESCRIPTION] +Specify an amount of days to remove messages from. + +//Ban Command +[A_SILENT_BAN_DESCRIPTION] +Deletes the command message and the execution message. + +[A_POINTS_BAN_DESCRIPTION] +Assign moderation points to the user. + +[A_EXPIRATION_BAN_DESCRIPTION] +Assign a duration for the moderation points to expire. + +[A_FORCE_BAN_DESCRIPTION] +Bypasses the moderation point escalation. + +[A_DAYS_BAN_DESCRIPTION] +Specify an amount of days to remove messages from. + +//Unban Command +[A_SILENT_UNBAN_DESCRIPTION] +Deletes the command message and the execution message. + +//Prune Command +[A_USERS_PRUNE_DESCRIPTION] +Filter messages sent by specified users. + +[A_BOTS_PRUNE_DESCRIPTION] +Filter messages sent by bots. + +[A_HUMANS_PRUNE_DESCRIPTION] +Filter messages sent by non-bots. + +[A_CONTAINS_PRUNE_DESCRIPTION] +Filter messages containing specified text. + +[A_STARTSWITH_PRUNE_DESCRIPTION] +Filter messages starting with specified text. + +[A_ENDSWITH_PRUNE_DESCRIPTION] +Filter messages ending with specified text. + +[A_TEXT_PRUNE_DESCRIPTION] +Filter messages containing text. + +[A_INVITES_PRUNE_DESCRIPTION] +Filter messages containing discord invites. + +[A_LINKS_PRUNE_DESCRIPTION] +Filter messages containing links. + +[A_EMOJIS_PRUNE_DESCRIPTION] +Filter messages containing emojis. + +[A_REACTIONS_PRUNE_DESCRIPTION] +Filter messages containing reactions. + +[A_IMAGES_PRUNE_DESCRIPTION] +Filter messages containing images. + +[A_ATTACHMENTS_PRUNE_DESCRIPTION] +Filter messages containing any attachment. + +[A_AFTER_PRUNE_DESCRIPTION] +Filter messages after a specified message. + +[A_BEFORE_PRUNE_DESCRIPTION] +Filter messages before a specified message. + +[A_AND_PRUNE_DESCRIPTION] +Use a logical AND for checks. + +[A_NOT_PRUNE_DESCRIPTION] +Use a logical NOT for checks. + +[A_SILENT_PRUNE_DESCRIPTION] +Deletes the command message and the execution message. + +//History Arguments +[A_BEFORE_HISTORY_DESCRIPTION] +Search history before a certain date. + +[A_AFTER_HISTORY_DESCRIPTION] +Search history after a certain date. + +[A_TYPE_HISTORY_DESCRIPTION] +Search history only containing certain infraction types. + +[A_OLDEST_HISTORY_DESCRIPTION] +Sort history by oldest. + +[A_VERBOSE_HISTORY_DESCRIPTION] +Display user IDs. + + +//Settings Arguments + + +//Mute Setting +[A_CREATE_MUTE_SETTINGS] +Create a new muted role instead of using an existing one. + +[A_TYPE_MUTE_SETTINGS] +Select a mute type functionality. + +[A_PERMANENT_MUTE_SETTINGS] +Determine if you would like to allow permanent mutes if no duration is provided. + +[A_DEFAULTDURATION_MUTE_SETTINGS] +Determine the default duration chosen if no duration is provided. + +[A_TEXT_MUTE_SETTINGS] +Only creates permissions for text-channels. + +[A_VOICE_MUTE_SETTINGS] +Only creates permissions for voice-channels. + + +//Utility Module + + diff --git a/structure/language/languages/en_us/en_us_commands.lang b/structure/language/languages/en_us/en_us_commands.lang new file mode 100644 index 0000000..ff0e4ca --- /dev/null +++ b/structure/language/languages/en_us/en_us_commands.lang @@ -0,0 +1,970 @@ + + +// Administration Module + + +//Settings Command +[C_SETTINGS_DESCRIPTION] +Configure your server and user settings. + +[C_SETTINGS_MISSINGPERMISSIONS] +You must have `Administrator` or `Manage Server` permissions to change/view server settings. + +[C_SETTINGS_RESETPROMPT] +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_RESETINVALID] +You provided an invalid input, please try again. + +[C_SETTINGS_RESETABORT] +Successfully aborted the operation. + +[C_SETTINGS_RESETSUCCESS] +All {type} settings were successfully deleted and set to default. + +[C_SETTINGS_EXPORT] +Attached the JSON-formatted {type} settings file in the file below. +You may want to format this file for your viewing pleasure. + +[C_SETTINGS_SETTINGNOTFOUND] +That setting does not exist! + +[C_SETTINGS_FORMATTYPE] +switch("{type}") { + case "GUILD": + "server"; + break; + case "USER": + "user"; + break; +} + +//Grant Command +[C_GRANT_DESCRIPTION] +Grant roles or users permissions to use commands or modules. +To view all grantable permissions, use the command `{prefix}perms list`. + +[C_GRANT_MISSINGRESOLVEABLES] +Unable to find any roles or members, view `{prefix}cmd grant` for more information. + +[C_GRANT_MISSINGPERMISSIONNODES] +Unable to find any grantable permissions, view `{prefix}cmd grant` for more information. + +[C_GRANT_DATABASEERROR] +There was an issue pushing the permissions to the database. Contact a bot developer. + +[C_GRANT_SUCCESS] +Successfully granted targets {targets} the following permissions: {permissions}{channel}. + +[C_GRANT_SUCCESSCHANNELS] +in channel{plural} {channels} + +[C_GRANT_WARNING] +You granted a command from the **Administration** module. This is potentially dangerous, as whoever you granted the administration commands to could have access to vital parts of the server. Only grant administration commands to people you trust. + +//Revoke Command +[C_REVOKE_DESCRIPTION] +Revoke permissions granted to roles or users. +NOTE: If a user left the server, you must use the ID to revoke the permissions. + +[C_REVOKE_MISSINGRESOLVEABLES] +Unable to find any roles or users, view `{prefix}cmd revoke` for more information. + +[C_REVOKE_DATABASEERROR] +There was an issue pushing the permissions to the database. Contact a bot developer. + +[C_REVOKE_SUCCESS] +Successfully revoked targets {targets} the following permissions: {permissions}{channel}. + +[C_REVOKE_SUCCESSCHANNELS] +in channel{plural} {channels} + +//Permissions Command +[C_PERMISSIONS_DESCRIPTION] +View permissions granted to roles or users. + +[C_PERMISSIONS_LIST] +You can **grant**/**revoke** the following permissions: {permissions}. + +[C_PERMISSIONS_SHOWTITLE] +switch({user}) { + case true: + "User Permissions" + break; + case false: + "Role Permissions" + break; +} + +[C_PERMISSIONS_SHOWDESCRIPTION] +An overview of all {resolve}'s permissions in the server. If you would like to see an in-depth view of the role or user's permissions, use `{prefix}perms [user|role]`. + +[C_PERMISSIONS_MAXFIELDS] +:warning: **You have met the max amount of fields and you will need to use `{prefix}perms --json` to view them.** :warning: + +[C_PERMISSIONS_NOTFOUND] +Unable to find any roles or users with those arguments. + +[C_PERMISSIONS_JSON] +Attached the JSON-formatted permission file in the file below. +You may want to format this file for your viewing pleasure. + +[C_PERMISSIONS_GLOBAL] +**Global Permissions:** {permissions} +Global permissions can be used in all channels, but you can add specific channels if needed. + +[C_PERMISSIONS_GLOBALALT] +Channel-specific permissions are listed below. + +[C_PERMISSIONS_NOPERMISSIONS] +**No permissions found!** Try granting some permissions by using: +`{prefix}grant }` + +[C_PERMISSIONS_PERMISSIONSNOTFOUND] +Found {type} **{resolveable}** but {they}had no permissions. + +[C_PERMISSIONS_NOPERMISSIONS] +Your server has no granted permissions to any roles or users. +If you would like to grant permissions, use the command `{prefix}grant` for more information. + +//Disable Command +[C_DISABLE_DESCRIPTION] +Disable commands in your server to prevent usage. + +[C_DISABLE_LIST] +The command{plural} currently disabled in your server are: {commands} + +[C_DISABLE_LISTFAIL] +There are no disabled commands in your server. + +[C_DISABLE_MISSINGCOMMANDS] +You must provide commands to disable. + +[C_DISABLE_SUCCESS] +Successfully **disabled** command{plural} {commands} in your server. + +[C_DISABLE_FAIL] +Failed to disable command{plural} {commands}. You are unable to disable the **command:enable** and **command:disable** commands. + +[C_DISABLE_WARNING] +You disabled a command inside of the **Administration** module. It is dangerous to do so, as it may disable configurability of your server. Note you are unable to disable the `command:enable` and `command:disable` commands. + +[C_DISABLE_SUCCESSGLOBAL] +Successfully **disabled** command{plural} {commands} globally. **`[{amount}/{total}]`** +These changes will be reverted if a shard restarts; edit the file{plural} for sustainability. + +[C_DISABLE_FAILGLOBAL] +Failed to globally disable command{plural} {commands}. **`[0/{total}]`** + +//Enable Command +[C_ENABLE_DESCRIPTION] +Enable commands in your server. + +[C_ENABLE_MISSINGCOMMANDS] +You must provide commands to enable. + +[C_ENABLE_SUCCESS] +Successfully **enabled** command{plural} {commands} in your server. + +[C_ENABLE_FAIL] +Failed to enable command{plural} {commands}, they likely were not disabled. + +[C_ENABLE_SUCCESSGLOBAL] +Successfully **enabled** command{plural} {commands} globally. **`[{amount}/{total}]`** +These changes will be reverted if a shard restarts; edit the file{plural} for sustainability. + +[C_ENABLE_FAILGLOBAL] +Failed to globally enable command{plural} {commands}. **`[0/{total}]`** + + +// Moderation Module + + +//Note Command +[C_NOTE_DESCRIPTION] +Note members with a description, will not be logged. +The only way to view notes is through moderation history. + +[C_NOTE_MISSINGMEMBERS] +You must provide members to assign notes to. + +[C_NOTE_MISSINGMEMBERPERMISSIONS] + +//Warn Command +[C_WARN_DESCRIPTION] +Warn members for a particular reason. + +[C_WARN_MISSINGMEMBERS] +You must provide members to warn. + +[C_WARN_INSUFFICIENTPERMISSIONS] +you don't have permission to run this command. + +//Unmute Command +[C_UNMUTE_DESCRIPTION] +Unmute members from the server. + +[C_UNMUTE_MISSINGMEMBERS] +You must provide members to unmute. + +[C_UNMUTE_INSUFFICIENTPERMISSIONS] +I don't have permission to manage roles + +[C_UNMUTE_CANNOTFINDMUTE] +they were not previously muted + +[C_UNMUTE_ROLEDOESNOTEXIST] +the mute role does not exist anymore + +[C_UNMUTE_1FAIL] +I had an issue removing the role + +[C_UNMUTE_2FAIL] +I had issues assigning roles to them + +[C_UNMUTE_3FAIL] +I had issues granting roles to them + +//Mute Command +[C_MUTE_DESCRIPTION] +Assign members to be muted from the server for a specified amount of time. + +[C_MUTE_MISSINGMEMBERS] +You must provide members to mute. + +[C_MUTE_DURATIONEXCEPTION] +The duration must be more than `1 minute` and less than `1 month`. + +[C_MUTE_INSUFFICIENTPERMISSIONS] +I don't have permission to manage roles + +[C_MUTE_NOMUTEROLE] +You don't have a mute role set in your server, use the command `-set mute` for more information. + +[C_MUTE_INVALIDMUTEROLE] +It seems like the mute role was deleted, use the command `-set mute` for more information. + +[C_MUTE_1FAIL] +I had an issue adding the role + +[C_MUTE_2FAIL] +I had issues assigning roles to them + +[C_MUTE_3FAIL] +I had issues revoking roles from them + +//Kick Command +[C_KICK_DESCRIPTION] +Kick provided members from the server. + +[C_KICK_MISSINGMEMBERS] +You must provide members to kick. + +[C_KICK_INSUFFICIENTPERMISSIONS] +I don't have permission to kick members + +[C_KICK_CANNOTBEKICKED] +they are unable to be kicked + +//Softban Command +[C_SOFTBAN_DESCRIPTION] +Bans and then unbans the member from the server. +Primarily used to prune the member's messages in all channels. + +[C_SOFTBAN_MISSINGMEMBERS] +You must provide members to softban. + +[C_SOFTBAN_INSUFFICIENTPERMISSIONS] +I don't have permission to ban members + +[C_SOFTBAN_CANNOTBESOFTBANNED] +they are unable to be softbanned + +//Ban Command +[C_BAN_DESCRIPTION] +Ban provided members or users from the server. Works with users not in the server. +Optionally assign a time to ban them for. + +[C_BAN_MISSINGMEMBERS] +You must provide members to ban. + +[C_BAN_DURATIONREQUIRED] +You must provide a duration while using the **tempban** alias. + +[C_BAN_DURATIONEXCEPTION] +The duration must be more than `1 minute` and less than `3 months`. + +[C_BAN_INSUFFICIENTPERMISSIONS] +I don't have permission to ban members + +[C_BAN_CANNOTBEBANNED] +they are unable to be banned + +[C_BAN_ALREADYBANNED] +they are already banned + +//Unban Command +[C_UNBAN_DESCRIPTION] +Unban provided users from the server. + +[C_UNBAN_MISSINGMEMBERS] +You must provide users to unban. + +[C_UNBAN_INSUFFICIENTPERMISSIONS] +I don't have permission to unban members + +[C_UNBAN_NOTBANNED] +they are not banned + +//Prune Command +[C_PRUNE_DESCRIPTION] +Mass delete messages from provided channels. The amount provided is the amount of messages it searches, not deletes. Filters messages using a logical OR by default. **You cannot prune messages older than 2 weeks.** + +[C_PRUNE_CHANNELEXCEPTION] +You are only able to prune up to `3` channels at a time. + +[C_PRUNE_INTEGERINVALID] +You must provide an amount to prune. + +[C_PRUNE_INTEGEREXCEPTION] +The amount must be more than `1` and less than `300`. + +[C_PRUNE_INSUFFICIENTPERMISSIONS] +I don't have permission to manage messages + +[C_PRUNE_NOTFETCHED] +I was unable to fetch any messages + +[C_PRUNE_NOTDELETABLE] +I could not delete those messages + +[C_PRUNE_NOFILTERRESULTS] +I could not find any messages with those arguments + +[C_PRUNE_NODELETE] +I had issues deleting those messages + +//Vckick Command +[C_VCKICK_DESCRIPTION] +Kick provided members from their connected voice-channel. + +[C_VCKICK_INSUFFICIENTPERMISSIONS] +I don't have permission to move members + +[C_VCKICK_NOCHANNEL] +they are not in a voice-channel + +//Slowmode Command +[C_SLOWMODE_DESCRIPTION] +Set the slowmode in provided channels. Primarily used for setting the slowmode in smaller increments, while Discord will not let you. + +[C_SLOWMODE_SECONDREQUIRED] +You must provide a duration to set the slowmode to. + +[C_SLOWMODE_SECONDEXCEPTION] +The duration must be `0 seconds` or more, and less than `6 hours`. + +[C_SLOWMODE_INSUFFICIENTPERMISSIONS] +I don't have permission to manage channels + +[C_SLOWMODE_NOCHANGE] +the slowmode was already set to that + +//Nickname Command +[C_NICKNAME_DESCRIPTION] +Change the nickname of provided members or dehoist them. You will have to put the nickname in quotes in order to allow for spaced nicknames. + +[C_NICKNAME_MISSINGMEMBERS] +You must provide members to nickname. + +[C_NICKNAME_MISSINGNAME] +You must provide arguments to change their nickname to. + +[C_NICKNAME_NOCHARACTERS] +they had no hoisted characters in their nickname + +[C_NICKNAME_INSUFFICIENTPERMISSIONS] +I don't have permission to manage nicknames + +[C_NICKNAME_MISSINGPERMSSIONS] +they have a higher role than I do + +//Addrole Command +[C_ADDROLE_DESCRIPTION] +Add roles to provided members. The added roles cannot be a higher position than the executor's highest role. + +[C_ADDROLE_MISSINGMEMBERS] +You must provide members to add roles to. + +[C_ADDROLE_MISSINGROLES] +You must provide roles to add to members. + +[C_ADDROLE_INSUFFICIENTPERMISSIONS] +I don't have permission to manage roles + +[C_ADDROLE_ROLEHIERARCHY] +the provided role(s) have a higher position than yours + +[C_ADDROLE_ROLEHIERARCHYBOT] +the provided role(s) are higher than the bot, I cannot add them + +//Removerole Command +[C_REMOVEROLE_DESCRIPTION] +Remove roles to provided members. The removes roles cannot be a higher position than the executor's highest role. + +[C_REMOVEROLE_MISSINGMEMBERS] +You must provide members to remove roles from. + +[C_REMOVEROLE_MISSINGROLES] +You must provide roles to remove from members. + +[C_REMOVEROLE_INSUFFICIENTPERMISSIONS] +I don't have permission to manage roles + +[C_REMOVEROLE_ROLEHIERARCHY] +the provided role(s) have a higher position than yours + +//History Command +[C_HISTORY_DESCRIPTION] +Display moderation history for the server or for certain users. + +[C_HISTORY_ERROR] +I had issues finding moderation history in your server. + +[C_HISTORY_NORESULTS] +There are no results for that search query. + +[C_HISTORY_SUCCESSTYPE] +switch({old}) { + case true: + 'oldest'; + break; + case false: + 'newest'; + break; +} + +[C_HISTORY_SUCCESS] +Fetched the {type} moderation cases{targets}. + +[C_HISTORY_SUCCESSTARGETS] + for target{plural}: {targets} + +[C_HISTORY_SUCCESSEXPORT] +Attached the JSON-formatted moderation file in the file below. +You may want to format this file for your viewing pleasure. + +[C_HISTORY_FAILEXPORT] +Unable to upload JSON file, the file is too large to upload here. **\`[amount/max]\`** +If you absolutely need this, contact a bot developer in our support server. + +//Case Command +[C_CASE_DESCRIPTION] +View a specific case + +[C_CASE_INVALID] +Case ID `{caseID}` is invalid! Make sure it's an integer above 0. + +[C_CASE_NOTFOUND] +No case matching ID `{caseID}` was found. + +[C_CASE_TITLE] +{emoji_book} Case **#{caseID}** + +[C_CASE_TITLE_VERBOSE] +{emoji_book} Case **#{caseID} (verbose)** + +[C_CASE_CHANGES_TITLE] +{emoji_note} Changes to case **#{case}** + +[C_CASE_CHANGES_NONE] +No changes have been made to the case. + +[C_CASE_CHANGE_BASE] +**Timestamp:** {date} | {timeAgo} ago +**Staff:** {staff} + +[C_CASE_CHANGES_RESOLVE] +**Reason:** {reason} + +[C_CASE_CHANGES_REASON] +**Old reason:** {reason} + +[C_CASE_CHANGES_DURATION] +**Old duration:** {duration} + +[C_CASE_CHANGE_NOREASON] +`No reason given` + +[C_CASE_TEMPLATE] +**[Jump to message (if available)](https://discord.com/channels/{guild}/{channel}/{message})** +**Unique ID:** {uniqueID} +**Type:** {type} +**Timestamp:** {date} | {relativeTime} ago +{target} +**Staff:** {staff} +**Changes:** {nrChanges} + +[C_CASE_TEMPLATE_VERBOSE] +**[Jump to message (if available)](https://discord.com/channels/{guild}/{channel}/{message})** +**Unique ID:** {uniqueID} +**Type:** {type} +**Timestamp:** {date} | {relativeTime} ago +**UNIX timestamp:** {unix} | {relativeTimeSeconds} seconds ago +{target} +**Staff:** {staff} ({staffID}) +**Amount of changes:** {nrChanges} +**Changes:** {changes} + +[C_CASE_MODPOINTS] +**Points:** {points} +**Expires:** {expires} + +[C_CASE_REASON] +**Reason:** +```{reason}``` + +[C_CASE_SLOWMODE] +**Slowmode:** {readable} + +[C_CASE_SLOWMODE_VERBOSE] +**Slowmode:** {readable} ({seconds}) seconds + +[C_CASE_TARGET_USER] +**User:** {target} + +[C_CASE_TARGET_CHANNEL] +**Channel:** #{target} + +[C_CASE_TARGET_USER_VERBOSE] +**User:** {target} ({targetID}) + +[C_CASE_TARGET_CHANNEL_VERBOSE] +**Channel:** #{target} ({targetID}) + +[C_CASE_LENGTH] +**Length:** {time} + +[C_CASE_LENGTH_VERBOSE] +**Length:** {time} ({inSeconds} seconds) + + +// Utility Module + + +//Ping Command + +[C_PING_DESCRIPTION] +Shows the millisecond delay between the bot and the discord server. + +//Settings Command + +[C_SETTINGS_DESCRIPTION] +Configure your guild and user settings. + +[C_SETTINGS_ADMINISTRATORERROR] +You must have the `ADMINISTRATOR` permission to run this. + +[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_RESETABORT] +Successfully aborted the operation. + +[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! + +[C_SETTINGS_JSON] +Attached the JSON-formatted settings file in the file below. +You may want to format this file for your viewing pleasure. + +//Avatar Command +[C_AVATAR_DESCRIPTION] +Fetches avatars for various users in different formats and sizes. + +[C_AVATAR_FORMATERROR] +Unable to find an avatar with those arguments, try a different size or format. + +//Lookup Command +[C_LOOKUP_DESCRIPTION] +Looks up a discord invite code and returns the information of the invite. + +[C_LOOKUP_FAILEDMATCH] +Couldn't find a discord invite code, try again. + +[C_LOOKUP_NONEXISTANT] +Unable to find any data about that invite code. + + +// Information Module + + +//Help Command +[C_HELP_DESCRIPTION] +Shows helpful information for commands, settings, and moderation. + +[C_HELP] +**__HELP MENU__** +For a list of all available commands, use `{prefix}commands [ group ]`. + +**❯ Arguments** +The bot splits arguments by space unless specified otherwise. To pass an argument that contains spaces you have to encapsulate it in quotes, some exceptions exist. +**Ex:** +`{prefix}grant "rolename that contains spaces" < permission >` - quotes are necessary +`{prefix}user some user` - quotes not necessary +**Typically** if the argument is at the end of a command it won't require quotes. + +**❯ Documentation notation** +**Optional** arguments are denoted by being encapsulated in brackets `[ ]` - means that the command will run either with default values or show usage prompt. +**Required** arguments are denoted by less and greater than `< >` - means that the command will not run and return an error. +**Infinite** arguments (ones you can list several) are denoted by `..` after the argument. Ex `< argument.. >` - means you can pass more than one argument. +**Alternatives** are denoted by being separated by a `|`. +**Actual values** that you can use in a command are denoted by being surrounded by single quotes `' '`. + +**❯ Moderation** +For help with moderation, see `{prefix}help modhelp`. +__**Warning:** This is a long embed.__ + +**❯ Command aliases** +Most commands and settings have some kind of aliases associated with them, some of which change the behaviour of the command or setting. +For instance the mute setting has a `createmute` (`{prefix}settings createmute `) alias, which changes the behaviour to be identical to `{prefix}settings mute create `. + +**❯ Detailed usage of commands** +`{prefix}help [ command / setting ]` + +**❯ Links** +[Support & Info server](https://discord.gg/SvJgtEj) +[@BotGalactic Twitter](https://twitter.com/BotGalactic) +[GalacticBot Patreon](https://www.patreon.com/galacticbot) + + +[C_HELP_TEMPLATE] +__**{component} HELP**__ +{desc} + +**Example usage** +{text} + + +[C_HELP_HELP] +Shows information about the bot and component usage. +To show help for commands `{prefix}help [command]` + +[C_HELP_404] +Dude stop, {component} doesn't exist! + +[C_HELP_TAGS] +**TAG SEARCH** +Commands and settings matching tag `{keyword}`. +For further help on how to use them, see `{prefix}help `. + +[MODHELP_TITLE] +**Moderation help menu** + +[MODHELP_DESC] +**Galactic Bot** offers extensive moderation tools for servers, small and large, ranging from simple warnings and notes to mutes and tempbans. One of our more recent additions is automod. While not necessarily being a true automod, it'll keep track of moderation escalation for you with some configuration. Automod utilizes configurable modpoints and thresholds, for more information about automod see `{prefix}settings modpoints` and `{prefix}settings automod`. + +**Galactic's** moderation commands can be viewed by using `{prefix}commands moderation`. The moderation utility follows a specific syntax for moderation, some parts allow for variation, while others require the arguments to be in specific locations in the command. +**The general syntax is:** `{prefix} @user [time] [reason]` + +Arguments that don't follow a strict pattern can be put anywhere **in the reason**. Such arguments are flags (and points, though they don't follow the same syntax as flags, more on that in a bit). For now there aren't many flags used by the moderation utility, though more may come in the future. The flags currently in use are `--force` and `--expires: