aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore208
-rw-r--r--.vscode/typescript.code-snippets73
-rw-r--r--src/commands/dev/superUser.ts4
-rw-r--r--src/commands/info/botInfo.ts6
-rw-r--r--src/commands/info/ping.ts4
-rw-r--r--src/commands/moderation/_block.ts (renamed from src/commands/moderation/block.ts)0
-rw-r--r--src/commands/moderation/_unban.ts (renamed from src/commands/moderation/unban.ts)0
-rw-r--r--src/commands/moderation/_unblock.ts (renamed from src/commands/moderation/unblock.ts)0
-rw-r--r--src/commands/moderation/_unmute.ts (renamed from src/commands/moderation/unmute.ts)0
-rw-r--r--src/commands/moderation/ban.ts6
-rw-r--r--src/commands/moderation/kick.ts93
-rw-r--r--src/commands/moderation/modlog.ts4
-rw-r--r--src/commands/moderation/mute.ts35
-rw-r--r--src/commands/moderation/role.ts177
-rw-r--r--src/commands/moderation/warn.ts110
-rw-r--r--src/commands/moulberry-bush/capePerms.ts4
-rw-r--r--src/commands/moulberry-bush/level.ts7
-rw-r--r--src/commands/moulberry-bush/rule.ts25
-rw-r--r--src/lib/extensions/discord-akairo/BushClientUtil.ts55
-rw-r--r--src/lib/extensions/discord-akairo/BushSlashMessage.ts3
-rw-r--r--src/lib/extensions/discord.js/BushGuildMember.ts74
21 files changed, 417 insertions, 471 deletions
diff --git a/.gitignore b/.gitignore
index 7db86d9..4f33c09 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,140 +1,19 @@
-
-# Created by https://www.toptal.com/developers/gitignore/api/node,yarn,vscode,webstorm
-# Edit at https://www.toptal.com/developers/gitignore?templates=node,yarn,vscode,webstorm
-
-### Node ###
# Logs
-logs
*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-lerna-debug.log*
-
-# Diagnostic reports (https://nodejs.org/api/report.html)
-report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
-
-# Runtime data
-pids
-*.pid
-*.seed
-*.pid.lock
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
-
-# Coverage directory used by tools like istanbul
-coverage
-*.lcov
-
-# nyc test coverage
-.nyc_output
-
-# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# Bower dependency directory (https://bower.io/)
-bower_components
-
-# node-waf configuration
-.lock-wscript
-
-# Compiled binary addons (https://nodejs.org/api/addons.html)
-build/Release
# Dependency directories
node_modules/
-jspm_packages/
-
-# TypeScript v1 declaration files
-typings/
-
-# TypeScript cache
-*.tsbuildinfo
-
-# Optional npm cache directory
-.npm
-
-# Optional eslint cache
-.eslintcache
-
-# Optional stylelint cache
-.stylelintcache
-
-# Microbundle cache
-.rpt2_cache/
-.rts2_cache_cjs/
-.rts2_cache_es/
-.rts2_cache_umd/
-
-# Optional REPL history
-.node_repl_history
-
-# Output of 'npm pack'
-*.tgz
-
-# Yarn Integrity file
-.yarn-integrity
-
-# dotenv environment variables file
-.env
-.env.test
-.env*.local
-
-# parcel-bundler cache (https://parceljs.org/)
-.cache
-.parcel-cache
-
-# Next.js build output
-.next
-
-# Nuxt.js build / generate output
-.nuxt
dist
-# Gatsby files
-.cache/
-# Comment in the public line in if your project uses Gatsby and not Next.js
-# https://nextjs.org/blog/next-9-1#public-directory-support
-# public
-
-# vuepress build output
-.vuepress/dist
-
-# Serverless directories
-.serverless/
-
-# FuseBox cache
-.fusebox/
-
-# DynamoDB Local files
-.dynamodb/
-
-# TernJS port file
-.tern-port
-
-# Stores VSCode versions used for testing VSCode extensions
-.vscode-test
-
### vscode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
+!.vscode/*.code-snippets
*.code-workspace
-### WebStorm ###
-# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
-# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
-
-# User-specific stuff
-.idea/**/workspace.xml
-.idea/**/tasks.xml
-.idea/**/usage.statistics.xml
-.idea/**/dictionaries
-.idea/**/shelf
-
# Generated files
.idea/**/contentModel.xml
@@ -147,90 +26,13 @@ dist
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
-# Gradle
-.idea/**/gradle.xml
-.idea/**/libraries
-
-# Gradle and Maven with auto-import
-# When using Gradle or Maven with auto-import, you should exclude module files,
-# since they will be recreated, and may cause churn. Uncomment if using
-# auto-import.
-# .idea/artifacts
-# .idea/compiler.xml
-# .idea/jarRepositories.xml
-# .idea/modules.xml
-# .idea/*.iml
-# .idea/modules
-# *.iml
-# *.ipr
-
-# CMake
-cmake-build-*/
-
-# Mongo Explorer plugin
-.idea/**/mongoSettings.xml
-
-# File-based project format
-*.iws
-
-# IntelliJ
-out/
-
-# mpeltonen/sbt-idea plugin
-.idea_modules/
-
-# JIRA plugin
-atlassian-ide-plugin.xml
-
-# Cursive Clojure plugin
-.idea/replstate.xml
-
-# Crashlytics plugin (for Android Studio and IntelliJ)
-com_crashlytics_export_strings.xml
-crashlytics.properties
-crashlytics-build.properties
-fabric.properties
-
-# Editor-based Rest Client
-.idea/httpRequests
-
-# Android studio 3.1+ serialized cache file
-.idea/caches/build_file_checksums.ser
-
-### WebStorm Patch ###
-# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
-
-# *.iml
-# modules.xml
-# .idea/misc.xml
-# *.ipr
-
-# Sonarlint plugin
-# https://plugins.jetbrains.com/plugin/7973-sonarlint
-.idea/**/sonarlint/
-
-# SonarQube Plugin
-# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
-.idea/**/sonarIssues.xml
-
-# Markdown Navigator plugin
-# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
-.idea/**/markdown-navigator.xml
-.idea/**/markdown-navigator-enh.xml
-.idea/**/markdown-navigator/
-
# Cache file creation bug
-# See https://youtrack.jetbrains.com/issue/JBR-2257
-.idea/$CACHE_FILE$
.yarn/cache/*
.yarn/sdks/eslint/*
.yarn/sdks/prettier/*
.yarn/install-state.gz
.yarn/build-state.url
.yarn/releases.gz
-# CodeStream plugin
-# https://plugins.jetbrains.com/plugin/12206-codestream
-.idea/codestream.xml
### yarn ###
# https://yarnpkg.com/advanced/qa#which-files-should-be-gitignored
@@ -240,16 +42,8 @@ fabric.properties
!.yarn/plugins
!.yarn/sdks
!.yarn/versions
-
-# if you are NOT using Zero-installs, then:
-# comment the following lines
!.yarn/cache
-# and uncomment the following lines
-# .pnp.*
-
-# End of https://www.toptal.com/developers/gitignore/api/node,yarn,vscode,webstorm
-
# Options and credentials for the bot
src/config/options.ts
diff --git a/.vscode/typescript.code-snippets b/.vscode/typescript.code-snippets
new file mode 100644
index 0000000..0984c3c
--- /dev/null
+++ b/.vscode/typescript.code-snippets
@@ -0,0 +1,73 @@
+/* prettier-ignore */
+{
+ /**
+ * Place your snippets for typescript here. Each snippet is defined under a snippet name and has a prefix, body and
+ * description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
+ * $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the
+ * same ids are connected.
+ */
+
+ "Setup Slash Command": {
+ "prefix": "slash",
+ "body": [
+ "slash: true,",
+ "slashOptions: [",
+ "\t$0",
+ "]"
+ ]
+ },
+
+ "Slash Command User Argument": {
+ "prefix": "user",
+ "body": [
+ "{",
+ "\tname: 'user',",
+ "\tdescription: 'The user you would like to$1',",
+ "\ttype: 'USER',",
+ "\trequired: $2",
+ "},$0"
+ ]
+ },
+
+ "Slash Command String Argument": {
+ "prefix": "string",
+ "body": [
+ "{",
+ "\tname: '$1',",
+ "\tdescription: '$2',",
+ "\ttype: 'STRING',",
+ "\trequired: $3",
+ "},$0"
+ ]
+ },
+
+ "Slash Command Choice Argument": {
+ "prefix": "choice",
+ "body": [
+ "{",
+ "\tname: '$1',",
+ "\tdescription: '$2',",
+ "\ttype: 'STRING',",
+ "\tchoices: [",
+ "\t\t{",
+ "\t\t\tname: '$3',",
+ "\t\t\tvalue: '$4'",
+ "\t\t},",
+ "\t],",
+ "\trequired: $5",
+ "},$0"
+ ]
+ },
+
+ "Slash Boolean Argument": {
+ "prefix": "boolean",
+ "body": [
+ "{",
+ "\tname: '$1',",
+ "\tdescription: '$2',",
+ "\ttype: 'BOOLEAN',",
+ "\trequired: $3",
+ "},$0"
+ ]
+ }
+}
diff --git a/src/commands/dev/superUser.ts b/src/commands/dev/superUser.ts
index 981c0da..4d5ce2d 100644
--- a/src/commands/dev/superUser.ts
+++ b/src/commands/dev/superUser.ts
@@ -1,6 +1,6 @@
import { Constants } from 'discord-akairo';
import { User } from 'discord.js';
-import { BushCommand, BushMessage, Global } from '../../lib';
+import { BushCommand, BushMessage, BushSlashMessage, Global } from '../../lib';
export default class SuperUserCommand extends BushCommand {
public constructor() {
@@ -39,7 +39,7 @@ export default class SuperUserCommand extends BushCommand {
};
return { action, user };
}
- public async exec(message: BushMessage, args: { action: 'add' | 'remove'; user: User }): Promise<unknown> {
+ public async exec(message: BushMessage | BushSlashMessage, args: { action: 'add' | 'remove'; user: User }): Promise<unknown> {
if (!message.author.isOwner())
return await message.util.reply(`${this.client.util.emojis.error} Only my developers can run this command.`);
diff --git a/src/commands/info/botInfo.ts b/src/commands/info/botInfo.ts
index 4a94318..80ca29d 100644
--- a/src/commands/info/botInfo.ts
+++ b/src/commands/info/botInfo.ts
@@ -1,5 +1,5 @@
-import { Message, MessageEmbed } from 'discord.js';
-import { BushCommand } from '../../lib';
+import { MessageEmbed } from 'discord.js';
+import { BushCommand, BushMessage, BushSlashMessage } from '../../lib';
export default class BotInfoCommand extends BushCommand {
public constructor() {
@@ -17,7 +17,7 @@ export default class BotInfoCommand extends BushCommand {
});
}
- public async exec(message: Message): Promise<void> {
+ public async exec(message: BushMessage | BushSlashMessage): Promise<void> {
const owners = (await this.client.util.mapIDs(this.client.ownerID)).map((u) => u.tag).join('\n');
const currentCommit = (await this.client.util.shell('git rev-parse HEAD')).stdout.replace('\n', '');
const repoUrl = (await this.client.util.shell('git remote get-url origin')).stdout.replace('\n', '');
diff --git a/src/commands/info/ping.ts b/src/commands/info/ping.ts
index c1be3fb..804ede2 100644
--- a/src/commands/info/ping.ts
+++ b/src/commands/info/ping.ts
@@ -1,5 +1,5 @@
import { Message, MessageEmbed } from 'discord.js';
-import { BushCommand, BushSlashMessage } from '../../lib';
+import { BushCommand, BushMessage, BushSlashMessage } from '../../lib';
export default class PingCommand extends BushCommand {
public constructor() {
@@ -17,7 +17,7 @@ export default class PingCommand extends BushCommand {
});
}
- public async exec(message: Message): Promise<void> {
+ public async exec(message: BushMessage): Promise<void> {
const sentMessage = (await message.util.send('Pong!')) as Message;
const timestamp: number = message.editedTimestamp ? message.editedTimestamp : message.createdTimestamp;
const botLatency = `\`\`\`\n ${Math.floor(sentMessage.createdTimestamp - timestamp)}ms \`\`\``;
diff --git a/src/commands/moderation/block.ts b/src/commands/moderation/_block.ts
index e69de29..e69de29 100644
--- a/src/commands/moderation/block.ts
+++ b/src/commands/moderation/_block.ts
diff --git a/src/commands/moderation/unban.ts b/src/commands/moderation/_unban.ts
index e69de29..e69de29 100644
--- a/src/commands/moderation/unban.ts
+++ b/src/commands/moderation/_unban.ts
diff --git a/src/commands/moderation/unblock.ts b/src/commands/moderation/_unblock.ts
index e69de29..e69de29 100644
--- a/src/commands/moderation/unblock.ts
+++ b/src/commands/moderation/_unblock.ts
diff --git a/src/commands/moderation/unmute.ts b/src/commands/moderation/_unmute.ts
index e69de29..e69de29 100644
--- a/src/commands/moderation/unmute.ts
+++ b/src/commands/moderation/_unmute.ts
diff --git a/src/commands/moderation/ban.ts b/src/commands/moderation/ban.ts
index 0c68497..244014b 100644
--- a/src/commands/moderation/ban.ts
+++ b/src/commands/moderation/ban.ts
@@ -1,5 +1,5 @@
-import { Message, User } from 'discord.js';
-import { BushCommand } from '../../lib';
+import { User } from 'discord.js';
+import { BushCommand, BushMessage, BushSlashMessage } from '../../lib';
export default class BanCommand extends BushCommand {
public constructor() {
@@ -140,7 +140,7 @@ export default class BanCommand extends BushCommand {
// }
// }
async exec(
- message: Message,
+ message: BushMessage | BushSlashMessage,
{ user, reason, time }: { user: User; reason?: string; time?: number | string }
): Promise<unknown> {
return message.util.reply(`${this.client.util.emojis.error} This command is not finished.`);
diff --git a/src/commands/moderation/kick.ts b/src/commands/moderation/kick.ts
index 8375198..919c14b 100644
--- a/src/commands/moderation/kick.ts
+++ b/src/commands/moderation/kick.ts
@@ -1,15 +1,19 @@
-import { GuildMember, Message } from 'discord.js';
-import { BushCommand } from '../../lib';
+import { BushCommand, BushGuildMember, BushMessage, BushSlashMessage, BushUser } from '../../lib';
export default class KickCommand extends BushCommand {
public constructor() {
super('kick', {
aliases: ['kick'],
category: 'moderation',
+ description: {
+ content: 'Kick a user.',
+ usage: 'kick <member> <reason>',
+ examples: ['kick @user bad']
+ },
args: [
{
id: 'user',
- type: 'member',
+ type: 'user',
prompt: {
start: 'What user would you like to kick?',
retry: '{error} Choose a valid user to kick.'
@@ -20,19 +24,13 @@ export default class KickCommand extends BushCommand {
type: 'string',
match: 'restContent',
prompt: {
- start: 'Why would you like to kick this user?',
- retry: '{error} Choose a valid user to kick.',
+ start: 'Why should this user be kicked?',
+ retry: '{error} Choose a valid kick reason.',
optional: true
}
}
],
- clientPermissions: ['KICK_MEMBERS'],
- userPermissions: ['KICK_MEMBERS'],
- description: {
- content: 'Kick a member from the server.',
- usage: 'kick <member> <reason>',
- examples: ['kick @user bad']
- },
+ slash: true,
slashOptions: [
{
type: 'USER',
@@ -43,67 +41,30 @@ export default class KickCommand extends BushCommand {
{
type: 'STRING',
name: 'reason',
- description: 'Why would you like to kick this user?',
+ description: 'Why should this user be kicked?',
required: false
}
],
- slash: true
+ clientPermissions: ['SEND_MESSAGES', 'KICK_MEMBERS'],
+ userPermissions: ['KICK_MEMBERS']
});
}
- // private async *genResponses(
- // message: Message | CommandInteraction,
- // user: GuildMember,
- // reason?: string
- // ): AsyncIterable<string> {
- // let modlogEnry: ModLog;
- // // Create guild entry so postgres doesn't get mad when I try and add a modlog entry
- // await Guild.findOrCreate({
- // where: {
- // id: message.guild.id
- // },
- // defaults: {
- // id: message.guild.id
- // }
- // });
- // try {
- // modlogEnry = ModLog.build({
- // user: user.id,
- // guild: message.guild.id,
- // moderator: message instanceof Message ? message.author.id : message.user.id,
- // type: ModLogType.KICK,
- // reason
- // });
- // await modlogEnry.save();
- // } catch (e) {
- // this.client.console.error(`KickCommand`, `Error saving to database. ${e?.stack || e}`);
- // yield `${this.client.util.emojis.error} Error saving to database. Please report this to a developer.`;
- // return;
- // }
- // try {
- // await user.send(`You were kicked in ${message.guild.name} with reason \`${reason || 'No reason given'}\``);
- // } catch {
- // yield `${this.client.util.emojis.warn} Unable to dm user`;
- // }
- // try {
- // await user.kick(
- // `Kicked by ${message instanceof Message ? message.author.tag : message.user.tag} with ${
- // reason ? `reason ${reason}` : 'no reason'
- // }`
- // );
- // } catch {
- // yield `${this.client.util.emojis.error} Error kicking :/`;
- // await modlogEnry.destroy();
- // return;
- // }
- // yield `${this.client.util.emojis.success} Kicked <@!${user.id}> with reason \`${reason || 'No reason given'}\``;
- // }
+ async exec(message: BushMessage | BushSlashMessage, { user, reason }: { user: BushUser; reason?: string }): Promise<unknown> {
+ const member = message.guild.members.cache.get(user.id) as BushGuildMember;
+ const canModerateResponse = this.client.util.moderationPermissionCheck(message.member, member, 'kick');
+ // const victimBoldTag = `**${member.user.tag}**`;
+
+ if (typeof canModerateResponse !== 'boolean') {
+ return message.util.reply(canModerateResponse);
+ }
- async exec(message: Message, { user, reason }: { user: GuildMember; reason?: string }): Promise<unknown> {
- return message.util.reply(`${this.client.util.emojis.error} This command is not finished.`);
- // for await (const response of this.genResponses(message, user, reason)) {
- // await message.util.send(response);
- // }
+ const response = await member.bushKick({
+ reason,
+ moderator: message.author
+ });
+
+
}
}
diff --git a/src/commands/moderation/modlog.ts b/src/commands/moderation/modlog.ts
index 5be50a4..36f72fc 100644
--- a/src/commands/moderation/modlog.ts
+++ b/src/commands/moderation/modlog.ts
@@ -1,7 +1,7 @@
import { Argument } from 'discord-akairo';
import { MessageEmbed } from 'discord.js';
import moment from 'moment';
-import { BushCommand, BushMessage, ModLog } from '../../lib';
+import { BushCommand, BushMessage, BushSlashMessage, ModLog } from '../../lib';
export default class ModlogCommand extends BushCommand {
public constructor() {
@@ -48,7 +48,7 @@ export default class ModlogCommand extends BushCommand {
return modLog.join(`\n`);
}
- async exec(message: BushMessage, { search }: { search: string }): Promise<unknown> {
+ async exec(message: BushMessage | BushSlashMessage, { search }: { search: string }): Promise<unknown> {
const foundUser = await this.client.util.resolveUserAsync(search);
if (foundUser) {
const logs = await ModLog.findAll({
diff --git a/src/commands/moderation/mute.ts b/src/commands/moderation/mute.ts
index 33c0e32..bc3abf2 100644
--- a/src/commands/moderation/mute.ts
+++ b/src/commands/moderation/mute.ts
@@ -1,5 +1,5 @@
import { Argument } from 'discord-akairo';
-import { BushCommand, BushGuildMember, BushMessage, BushUser } from '../../lib';
+import { BushCommand, BushGuildMember, BushMessage, BushSlashMessage, BushUser } from '../../lib';
export default class MuteCommand extends BushCommand {
public constructor() {
@@ -8,8 +8,8 @@ export default class MuteCommand extends BushCommand {
category: 'moderation',
description: {
content: 'Mute a user.',
- usage: 'mute <member> <reason> [--time]',
- examples: ['mute @user bad boi --time 1h']
+ usage: 'mute <member> [reason] [duration]',
+ examples: ['mute 322862723090219008 1 day commands in #general']
},
args: [
{
@@ -31,8 +31,7 @@ export default class MuteCommand extends BushCommand {
}
}
],
- clientPermissions: ['MANAGE_ROLES'],
- userPermissions: ['MANAGE_MESSAGES'],
+ slash: true,
slashOptions: [
{
type: 'USER',
@@ -47,37 +46,29 @@ export default class MuteCommand extends BushCommand {
required: false
}
],
- slash: true
+ channel: 'guild',
+ clientPermissions: ['SEND_MESSAGES', 'MANAGE_ROLES'],
+ userPermissions: ['MANAGE_MESSAGES']
});
}
async exec(
- message: BushMessage,
+ message: BushMessage | BushSlashMessage,
{ user, reason }: { user: BushUser; reason?: { duration: number; contentWithoutTime: string } }
): Promise<unknown> {
const error = this.client.util.emojis.error;
const member = message.guild.members.cache.get(user.id) as BushGuildMember;
- const canModerateResponse = this.client.util.moderationPermissionCheck(message.member, member);
+ const canModerateResponse = this.client.util.moderationPermissionCheck(message.member, member, 'mute');
const victimBoldTag = `**${member.user.tag}**`;
- switch (canModerateResponse) {
- case 'moderator':
- return message.util.reply(`${error} You cannot mute ${victimBoldTag} because they are a moderator.`);
- case 'user hierarchy':
- return message.util.reply(
- `${error} You cannot mute ${victimBoldTag} because they have higher or equal role hierarchy as you do.`
- );
- case 'client hierarchy':
- return message.util.reply(
- `${error} You cannot mute ${victimBoldTag} because they have higher or equal role hierarchy as I do.`
- );
- case 'self':
- return message.util.reply(`${error} You cannot mute yourself.`);
+
+ if (typeof canModerateResponse !== 'boolean') {
+ return message.util.reply(canModerateResponse);
}
let time: number;
if (reason) {
time =
typeof reason === 'string'
- ? await Argument.cast('duration', this.client.commandHandler.resolver, message, reason)
+ ? await Argument.cast('duration', this.client.commandHandler.resolver, message as BushMessage, reason)
: reason.duration;
}
const parsedReason = reason.contentWithoutTime;
diff --git a/src/commands/moderation/role.ts b/src/commands/moderation/role.ts
index 83e85e0..6bac9e8 100644
--- a/src/commands/moderation/role.ts
+++ b/src/commands/moderation/role.ts
@@ -1,28 +1,7 @@
/* eslint-disable @typescript-eslint/no-empty-function */
-import { GuildMember, Message, Role } from 'discord.js';
-import { AllowedMentions, BushCommand } from '../../lib';
+import { AllowedMentions, BushCommand, BushGuildMember, BushMessage, BushRole, BushSlashMessage } from '../../lib';
export default class RoleCommand extends BushCommand {
- private roleWhitelist: Record<string, string[]> = {
- 'Partner': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'Suggester': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator', 'Helper', 'Trial Helper', 'Contributor'],
- 'Level Locked': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'No Files': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'No Reactions': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'No Links': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'No Bots': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'No VC': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'No Giveaways': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator', 'Helper'],
- 'No Support': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'Giveaway Donor': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'Giveaway (200m)': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'Giveaway (100m)': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'Giveaway (50m)': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'Giveaway (25m)': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'Giveaway (10m)': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'Giveaway (5m)': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator'],
- 'Giveaway (1m)': ['*', 'Admin Perms', 'Sr. Moderator', 'Moderator']
- };
public constructor() {
super('role', {
aliases: ['role', 'addrole', 'removerole'],
@@ -32,59 +11,103 @@ export default class RoleCommand extends BushCommand {
usage: 'role <add|remove> <user> <role>',
examples: ['role add tyman adminperms']
},
- clientPermissions: ['MANAGE_ROLES', 'EMBED_LINKS', 'SEND_MESSAGES'],
- channel: 'guild',
- typing: true,
- args: [
+ slash: true,
+ slashOptions: [
{
- id: 'user',
- type: 'member',
- prompt: {
- start: `What user do you want to add/remove the role on?`,
- retry: `{error} Choose a valid user to add/remove the role on.`
- }
+ name: 'action',
+ description: 'Would you like to add or remove a role?',
+ type: 'STRING',
+ choices: [
+ {
+ name: 'add',
+ value: 'add'
+ },
+ {
+ name: 'remove',
+ value: 'remove'
+ }
+ ],
+ required: true
},
{
- id: 'role',
- type: 'role',
- match: 'restContent',
- prompt: {
- start: `What role do you want to add/remove?`,
- retry: `{error} Choose a valid role to add/remove.`
- }
- }
- ],
- slashOptions: [
- {
- type: 'USER',
name: 'user',
- description: 'The user to add/remove the role on',
+ description: 'The user you would like to add/remove the role from.',
+ type: 'USER',
required: true
},
{
- type: 'ROLE',
name: 'role',
- description: 'The role to add/remove',
+ description: 'The role you would like to add/remove from the user.',
+ type: 'ROLE',
required: true
}
- ]
+ ],
+ channel: 'guild',
+ typing: true,
+ clientPermissions: ['MANAGE_ROLES', 'EMBED_LINKS', 'SEND_MESSAGES'],
+ userPermissions: ['SEND_MESSAGES']
});
}
- public async exec(message: Message, { user, role }: { user: GuildMember; role: Role }): Promise<unknown> {
+ *args(): unknown {
+ const action: 'add' | 'remove' = yield {
+ id: 'action',
+ type: [['add'], ['remove']],
+ prompt: {
+ start: 'Would you like to `add` or `remove` a role?',
+ retry: '{error} Choose whether you would you like to `add` or `remove` a role.'
+ }
+ };
+ let action2: 'to' | 'from';
+ if (action === 'add') action2 = 'to';
+ else if (action === 'remove') action2 = 'from';
+ else return;
+ const user = yield {
+ id: 'user',
+ type: 'member',
+ prompt: {
+ start: `What user do you want to ${action} the role ${action2}?`,
+ retry: `{error} Choose a valid user to ${action} the role ${action2}.`
+ }
+ //unordered: true
+ };
+ const role = yield {
+ id: 'role',
+ type: 'role',
+ match: 'restContent',
+ prompt: {
+ start: `What role do you want to ${action}?`,
+ retry: `{error} Choose a valid role to ${action}.`
+ }
+ };
+ return { action, user, role };
+ }
+
+ public async exec(
+ message: BushMessage | BushSlashMessage,
+ { action, user, role }: { action: 'add' | 'remove'; user: BushGuildMember; role: BushRole }
+ ): Promise<unknown> {
if (!message.member.permissions.has('MANAGE_ROLES') && !this.client.ownerID.includes(message.author.id)) {
- const mappedRole = this.client.consts.moulberryBushRoleMap.find((m) => m.id === role.id);
- if (!mappedRole || !this.roleWhitelist[mappedRole.name]) {
- return message.util.reply({
+ const mappings = this.client.consts.mappings;
+ let mappedRole: { name: string; id: string };
+ for (let i = 0; i < mappings.roleMap.length; i++) {
+ const a = mappings.roleMap[i];
+ if (a.id == role.id) mappedRole = a;
+ }
+ if (!mappedRole || !mappings.roleWhitelist[mappedRole.name]) {
+ return await message.util.reply({
content: `${this.client.util.emojis.error} <@&${role.id}> is not whitelisted, and you do not have manage roles permission.`,
allowedMentions: AllowedMentions.none()
});
}
- const allowedRoles = this.roleWhitelist[mappedRole.name].map((r) => {
- return this.client.consts.moulberryBushRoleMap.find((m) => m.name === r).id;
+ const allowedRoles = mappings.roleWhitelist[mappedRole.name].map((r) => {
+ for (let i = 0; i < mappings.roleMap.length; i++) {
+ if (mappings.roleMap[i].name == r) return mappings.roleMap[i].id;
+ }
+ return;
});
if (!message.member.roles.cache.some((role) => allowedRoles.includes(role.id))) {
- return message.util.reply({
+ return await message.util.reply({
content: `${this.client.util.emojis.error} <@&${role.id}> is whitelisted, but you do not have any of the roles required to manage it.`,
allowedMentions: AllowedMentions.none()
});
@@ -92,51 +115,51 @@ export default class RoleCommand extends BushCommand {
}
if (!this.client.ownerID.includes(message.author.id)) {
if (role.comparePositionTo(message.member.roles.highest) >= 0) {
- return message.util.reply({
+ return await message.util.reply({
content: `${this.client.util.emojis.error} <@&${role.id}> is higher or equal to your highest role.`,
allowedMentions: AllowedMentions.none()
});
}
if (role.comparePositionTo(message.guild.me.roles.highest) >= 0) {
- return message.util.reply({
+ return await message.util.reply({
content: `${this.client.util.emojis.error} <@&${role.id}> is higher or equal to my highest role.`,
allowedMentions: AllowedMentions.none()
});
}
if (role.managed) {
- await message.util.reply({
+ await await message.util.reply({
content: `${this.client.util.emojis.error} <@&${role.id}> is managed by an integration and cannot be managed.`,
allowedMentions: AllowedMentions.none()
});
}
}
- // No checks if the user has MANAGE_ROLES
- if (user.roles.cache.has(role.id)) {
- try {
- await user.roles.remove(role.id);
- } catch {
- return message.util.reply({
+ // no checks if the user has MANAGE_ROLES
+ if (action == 'remove') {
+ const success = await user.roles.remove(role.id).catch(() => {});
+ if (success) {
+ return await message.util.reply({
+ content: `${this.client.util.emojis.success}Successfully removed <@&${role.id}> from <@${user.id}>!`,
+ allowedMentions: AllowedMentions.none()
+ });
+ } else {
+ return await message.util.reply({
content: `${this.client.util.emojis.error} Could not remove <@&${role.id}> from <@${user.id}>.`,
allowedMentions: AllowedMentions.none()
});
}
- return message.util.reply({
- content: `${this.client.util.emojis.success} Successfully removed <@&${role.id}> from <@${user.id}>!`,
- allowedMentions: AllowedMentions.none()
- });
- } else {
- try {
- await user.roles.add(role.id);
- } catch {
- return message.util.reply({
+ } else if (action == 'add') {
+ const success = await user.roles.add(role.id).catch(() => {});
+ if (success) {
+ return await message.util.reply({
+ content: `${this.client.util.emojis.success} Successfully added <@&${role.id}> to <@${user.id}>!`,
+ allowedMentions: AllowedMentions.none()
+ });
+ } else {
+ return await message.util.reply({
content: `${this.client.util.emojis.error} Could not add <@&${role.id}> to <@${user.id}>.`,
allowedMentions: AllowedMentions.none()
});
}