3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-05-22 09:15:03 +00:00
zeppelin/backend/src/plugins/ReactionRoles/commands/InitReactionRolesCmd.ts
2020-10-01 01:43:38 +03:00

126 lines
4.2 KiB
TypeScript

import { reactionRolesCmd, TReactionRolePair } from "../types";
import { commandTypeHelpers as ct } from "../../../commandTypes";
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { TextChannel } from "eris";
import { RecoverablePluginError, ERRORS } from "../../../RecoverablePluginError";
import { canUseEmoji, isDiscordRESTError, noop } from "../../../utils";
import { applyReactionRoleReactionsToMessage } from "../util/applyReactionRoleReactionsToMessage";
import { canReadChannel } from "../../../utils/canReadChannel";
const CLEAR_ROLES_EMOJI = "❌";
export const InitReactionRolesCmd = reactionRolesCmd({
trigger: "reaction_roles",
permission: "can_manage",
signature: {
message: ct.messageTarget(),
reactionRolePairs: ct.string({ catchAll: true }),
exclusive: ct.bool({ option: true, isSwitch: true, shortcut: "e" }),
},
async run({ message: msg, args, pluginData }) {
if (!canReadChannel(args.message.channel, msg.member)) {
sendErrorMessage(pluginData, msg.channel, "You can't add reaction roles to channels you can't see yourself");
return;
}
let targetMessage;
try {
targetMessage = await args.message.channel.getMessage(args.message.messageId).catch(noop);
} catch (e) {
if (isDiscordRESTError(e)) {
sendErrorMessage(pluginData, msg.channel, `Error ${e.code} while getting message: ${e.message}`);
return;
}
throw e;
}
// Clear old reaction roles for the message from the DB
await pluginData.state.reactionRoles.removeFromMessage(targetMessage.id);
// Turn "emoji = role" pairs into an array of tuples of the form [emoji, roleId]
// Emoji is either a unicode emoji or the snowflake of a custom emoji
const emojiRolePairs: TReactionRolePair[] = args.reactionRolePairs
.trim()
.split("\n")
.map(v => v.split(/[\s=,]+/).map(v => v.trim())) // tslint:disable-line
.map(
(pair): TReactionRolePair => {
const customEmojiMatch = pair[0].match(/^<a?:(.*?):(\d+)>$/);
if (customEmojiMatch) {
return [customEmojiMatch[2], pair[1], customEmojiMatch[1]];
} else {
return pair as TReactionRolePair;
}
},
);
// Verify the specified emojis and roles are valid and usable
for (const pair of emojiRolePairs) {
if (pair[0] === CLEAR_ROLES_EMOJI) {
sendErrorMessage(
pluginData,
msg.channel,
`The emoji for clearing roles (${CLEAR_ROLES_EMOJI}) is reserved and cannot be used`,
);
return;
}
try {
if (!canUseEmoji(pluginData.client, pair[0])) {
sendErrorMessage(
pluginData,
msg.channel,
"I can only use regular emojis and custom emojis from servers I'm on",
);
return;
}
} catch (e) {
if (e instanceof RecoverablePluginError && e.code === ERRORS.INVALID_EMOJI) {
sendErrorMessage(pluginData, msg.channel, `Invalid emoji: ${pair[0]}`);
return;
}
throw e;
}
if (!pluginData.guild.roles.has(pair[1])) {
sendErrorMessage(pluginData, msg.channel, `Unknown role ${pair[1]}`);
return;
}
}
const progressMessage = msg.channel.createMessage("Adding reaction roles...");
// Save the new reaction roles to the database
for (const pair of emojiRolePairs) {
await pluginData.state.reactionRoles.add(
args.message.channel.id,
targetMessage.id,
pair[0],
pair[1],
args.exclusive,
);
}
// Apply the reactions themselves
const reactionRoles = await pluginData.state.reactionRoles.getForMessage(targetMessage.id);
const errors = await applyReactionRoleReactionsToMessage(
pluginData,
targetMessage.channel.id,
targetMessage.id,
reactionRoles,
);
if (errors.length) {
sendErrorMessage(pluginData, msg.channel, `Errors while adding reaction roles:\n${errors.join("\n")}`);
} else {
sendSuccessMessage(pluginData, msg.channel, "Reaction roles added");
}
(await progressMessage).delete().catch(noop);
},
});