From bb511abc03bb66848947e37a999502b813c77269 Mon Sep 17 00:00:00 2001 From: 8cy <50817549+8cy@users.noreply.github.com> Date: Thu, 23 Jul 2020 23:24:17 -0700 Subject: goodbye old uwufier :cry: --- server/src/commands/reaction/List.ts | 46 +++++++++ server/src/commands/reaction/New.ts | 168 +++++++++++++++++++++++++++++++++ server/src/commands/reaction/Remove.ts | 61 ++++++++++++ 3 files changed, 275 insertions(+) create mode 100644 server/src/commands/reaction/List.ts create mode 100644 server/src/commands/reaction/New.ts create mode 100644 server/src/commands/reaction/Remove.ts (limited to 'server/src/commands/reaction') diff --git a/server/src/commands/reaction/List.ts b/server/src/commands/reaction/List.ts new file mode 100644 index 0000000..36c1156 --- /dev/null +++ b/server/src/commands/reaction/List.ts @@ -0,0 +1,46 @@ +import { Command } from 'discord-akairo'; +import { Message } from 'discord.js'; +import { oneLine } from 'common-tags'; +import { colour } from '../../Config'; + +export default class ListReaction extends Command { + public constructor() { + super('reactionlist', { + aliases: ['reactionlist', 'reactionls'], + category: 'reactions', + description: { + content: 'Lists all current reaction roles.', + usage: '', + examples: [ + '' + ] + }, + ratelimit: 3, + userPermissions: ['MANAGE_ROLES'], + channel: 'guild' + }); + } + + public async exec(msg: Message): Promise { + const reactions = this.client.settings.cache.reactions.filter(r => r.guildID === msg.guild!.id && r.active); + if (!reactions.size) return msg.reply('you have no live reaction roles!'); + + const embed = this.client.util.embed() + .setColor(colour) + .setTitle('Live Reaction Roles') + .setDescription( + reactions + .map(r => { + const emoji = r.emojiType === 'custom' ? this.client.emojis.cache.get(r.emoji) : r.emoji; + return oneLine`[\`${r.id}\`] ${emoji} + ${this.client.channels.cache.get(r.channelID) || '#deleted-channel'} + ${msg.guild!.roles.cache.get(r.roleID) || '@deleted-role'} + `; + }) + .join('\n') + .substring(0, 2048), + ); + + return msg.reply({ embed }); + } +} \ No newline at end of file diff --git a/server/src/commands/reaction/New.ts b/server/src/commands/reaction/New.ts new file mode 100644 index 0000000..c695dbc --- /dev/null +++ b/server/src/commands/reaction/New.ts @@ -0,0 +1,168 @@ +import { Command } from 'discord-akairo'; +import { Message, MessageReaction, Permissions, Role, TextChannel, User } from 'discord.js'; +import { stripIndents } from 'common-tags'; +import * as nodemoji from 'node-emoji'; +import { colour } from '../../Config'; + +export default class NewReaction extends Command { + public constructor() { + super('reactionnew', { + aliases: ['reactionnew', 'reactionadd'], + category: 'reactions', + description: { + content: 'Create a new reaction role.', + usage: '[type] [channel] [message id] [emoji] [role]', + examples: [ + '1 #welcome 603009228180815882 🍕 @Pizza Lover' + ] + }, + ratelimit: 3, + userPermissions: ['MANAGE_ROLES'], + clientPermissions: ['ADD_REACTIONS', 'MANAGE_ROLES', 'MANAGE_MESSAGES'], + channel: 'guild' + }); + } + + public *args(m: Message): object { + const type = yield { + type: 'number', + prompt: { + start: stripIndents` + What type of reaction role do you wish to create? + + \`[1]\` for react to add and remove. *Classic* + ~~\`[2]\` for react to add only. + \`[3]\` for react to delete only.~~ + `, + restart: stripIndents` + Please provide a valid number for which type of reaction role do you wish to create? + + \`[1]\` Both react to add and remove. *Classic* + ~~\`[2]\` Only react to add. + \`[3]\` Only react to remove role.~~ + `, + }, + }; + + const channel = yield { + type: 'textChannel', + prompt: { + start: "What channel of the message you'd like to add this reaction role to?", + retry: 'Please provide a valid channel.', + }, + }; + + const message = yield { + type: async (_: Message, str: string): Promise => { + if (str) { + try { + const m = await channel.messages.fetch(str); + if (m) return m; + } catch {} + } + return null; + }, + prompt: { + start: 'What is the ID of the message you want to add that reaction role to?', + retry: 'Please provide a valid message ID.', + }, + }; + + const emoji = yield { + type: async (_: Message, str: string): Promise => { + if (str) { + const unicode = nodemoji.find(str); + if (unicode) return unicode.emoji; + + const custom = this.client.emojis.cache.find(r => r.toString() === str); + if (custom) return custom.id; + return null; + } + + const message = await m.channel.send( + stripIndents`Please **react** to **this** message with the emoji you wish to use? + If it's a custom emoji, please ensure I'm in the server that it's from!`, + ); + // Please **react** to **this** message or respond with the emoji you wish to use? + // If it's a custom emoji, please ensure I'm in the server that it's from! + + const collector = await message.awaitReactions((_: MessageReaction, u: User): boolean => m.author.id === u.id, { + max: 1, + }); + if (!collector || collector.size !== 1) return null; + + const collected = collector.first()!; + + if (collected.emoji.id) { + const emoji = this.client.emojis.cache.find(e => e.id === collected.emoji.id); + if (emoji) return emoji.id; + return null; + } + + return null; + }, + prompt: { + start: + "Please **respond** to **this** message with the emoji you wish to use? If it's a custom emoji, please ensure I'm in the server that it's from!", + retry: + "Please **respond** to **this** message with a valid emoji. If it's a custom emoji, please ensure I'm in the server that it's from!", + }, + }; + + const role = yield { + type: 'role', + match: 'rest', + prompt: { + start: 'What role would you like to apply when they react?', + retry: 'Please provide a valid role.', + }, + }; + + return { type, channel, message, emoji, role }; + } + + public async exec(msg: Message, { type, channel, message, emoji, role }: { type: number; channel: TextChannel; message: Message; emoji: string; role: Role }): Promise { + if (!channel.permissionsFor(this.client.user!.id)!.has(Permissions.FLAGS.ADD_REACTIONS)) + return msg.reply(`I'm missing the permissions to react in ${channel}!`); + + const reaction = await message.react(emoji).catch((err: Error) => err); + + if (reaction instanceof Error) + return msg.reply(`an error occurred when trying to react to that message: \`${reaction}\`.`); + + const id = this.makeID(); + + await this.client.settings.new('reaction', { + guildID: msg.guild!.id, + messageID: message.id, + userID: msg.author.id, + channelID: channel.id, + id, + emoji, + emojiType: emoji.length >= 3 ? 'custom' : 'unicode', + roleID: role.id, + uses: 0, + type, + }); + + const embed = this.client.util.embed() + .setColor(colour) + .setTitle('New Reaction Role!') + .setDescription("Please make sure my highest role is above the one you're trying to assign!") + .addField('🔢 Reference ID', id) + .addField('🏠 Channel', `${channel} \`[${channel.id}]\``) + .addField('💬 Message', `\`${message.id}\``) + .addField('🍕 Emoji', emoji.length >= 3 ? `${emoji} \`[${emoji}]\`` : emoji) + .addField('💼 Role', `${role} \`[${role.id}]\``); + return msg.channel.send({ embed }); + } + + public makeID(times?: number): string { + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + return 'X' + .repeat(times || 4) + .split('') + .map(() => possible.charAt(Math.floor(Math.random() * possible.length))) + .join(''); + } +} \ No newline at end of file diff --git a/server/src/commands/reaction/Remove.ts b/server/src/commands/reaction/Remove.ts new file mode 100644 index 0000000..0a58cdd --- /dev/null +++ b/server/src/commands/reaction/Remove.ts @@ -0,0 +1,61 @@ +import { Command } from 'discord-akairo'; +import { Message, TextChannel } from 'discord.js'; +import { Reaction } from '../../database/models/ReactionModel'; + +export default class RemoveReaction extends Command { + public constructor() { + super('reactionremove', { + aliases: ['reactionremove', 'reactionrm', 'reactiondelete', 'reactiondel'], + category: 'reactions', + description: { + content: 'Removes a reaction from a message via an discriminator.', + usage: '[discriminator]', + examples: [ + '[fV9k]' + ] + }, + ratelimit: 3, + userPermissions: ['MANAGE_ROLES'], + channel: 'guild', + args: [ + { + id: 'reaction', + type: (msg: Message, str: string): Reaction | null => { + const req = this.client.settings.cache.reactions.find(r => r.id === str && r.guildID === msg.guild!.id); + if (!req) return null; + return req; + }, + match: 'rest', + prompt: { + start: "Please provide the unique identifier for the reaction you'd like to delete.", + retry: + "Please provide a valid identifier for the reaction role you'd like to delete. You can also delete the whole message to delete reaction roles on it.", + }, + }, + ], + }); + } + + public async exec(msg: Message, { reaction }: { reaction: Reaction }): Promise { + this.client.logger.info(reaction); + try { + const chan = this.client.channels.cache.get(reaction.channelID) as TextChannel; + if (!chan) throw new Error("That channel doesn't exist!"); + const message = await chan.messages.fetch(reaction.messageID); + if (!message) throw new Error("That message doesn't exist!"); + await message.reactions.cache.get(reaction.emoji)!.users.remove(this.client.user!.id); + } catch (err) { + this.client.logger.error(`[ERROR in REMOVE CMD]: ${err}.`); + } + + this.client.settings.set( + 'reaction', + { messageID: reaction.messageID }, + { + active: false, + }, + ); + + return msg.reply('successfully deleted that reaction role.'); + } +} \ No newline at end of file -- cgit v1.2.3