summaryrefslogtreecommitdiff
path: root/server/src/commands/reaction/New.ts
blob: c695dbcf586fab2041b5af6aac0f02731300235f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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<null | Message> => {
				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<string | null> => {
				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<Message | Message[] | void> {
		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('');
	}
}