WIP: Button Reactions
This still needs some cleanup and some functionality straight up doesn't work or is only a POC
This commit is contained in:
parent
43c23263f0
commit
7c757d4b96
5 changed files with 177 additions and 0 deletions
|
@ -10,11 +10,14 @@ import { RefreshReactionRolesCmd } from "./commands/RefreshReactionRolesCmd";
|
||||||
import { ClearReactionRolesCmd } from "./commands/ClearReactionRolesCmd";
|
import { ClearReactionRolesCmd } from "./commands/ClearReactionRolesCmd";
|
||||||
import { AddReactionRoleEvt } from "./events/AddReactionRoleEvt";
|
import { AddReactionRoleEvt } from "./events/AddReactionRoleEvt";
|
||||||
import { LogsPlugin } from "../Logs/LogsPlugin";
|
import { LogsPlugin } from "../Logs/LogsPlugin";
|
||||||
|
import { PostButtonRolesCmd } from "./commands/PostButtonRolesCmd";
|
||||||
|
import { ButtonInteractionEvt } from "./events/ButtonInteractionEvt";
|
||||||
|
|
||||||
const MIN_AUTO_REFRESH = 1000 * 60 * 15; // 15min minimum, let's not abuse the API
|
const MIN_AUTO_REFRESH = 1000 * 60 * 15; // 15min minimum, let's not abuse the API
|
||||||
|
|
||||||
const defaultOptions: PluginOptions<ReactionRolesPluginType> = {
|
const defaultOptions: PluginOptions<ReactionRolesPluginType> = {
|
||||||
config: {
|
config: {
|
||||||
|
button_groups: {},
|
||||||
auto_refresh_interval: MIN_AUTO_REFRESH,
|
auto_refresh_interval: MIN_AUTO_REFRESH,
|
||||||
remove_user_reactions: true,
|
remove_user_reactions: true,
|
||||||
|
|
||||||
|
@ -47,11 +50,13 @@ export const ReactionRolesPlugin = zeppelinGuildPlugin<ReactionRolesPluginType>(
|
||||||
RefreshReactionRolesCmd,
|
RefreshReactionRolesCmd,
|
||||||
ClearReactionRolesCmd,
|
ClearReactionRolesCmd,
|
||||||
InitReactionRolesCmd,
|
InitReactionRolesCmd,
|
||||||
|
PostButtonRolesCmd,
|
||||||
],
|
],
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
events: [
|
events: [
|
||||||
AddReactionRoleEvt,
|
AddReactionRoleEvt,
|
||||||
|
ButtonInteractionEvt,
|
||||||
],
|
],
|
||||||
|
|
||||||
beforeLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { reactionRolesCmd } from "../types";
|
||||||
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { MessageActionRow, MessageButton, MessageComponentInteraction, TextChannel } from "discord.js";
|
||||||
|
import { sendErrorMessage, sendSuccessMessage } from "src/pluginUtils";
|
||||||
|
import moment from "moment";
|
||||||
|
import { ButtonMenuActions } from "../util/buttonMenuActions";
|
||||||
|
|
||||||
|
export const PostButtonRolesCmd = reactionRolesCmd({
|
||||||
|
trigger: "reaction_roles post",
|
||||||
|
permission: "can_manage",
|
||||||
|
|
||||||
|
signature: {
|
||||||
|
button_group: ct.string(),
|
||||||
|
},
|
||||||
|
|
||||||
|
async run({ message: msg, args, pluginData }) {
|
||||||
|
const cfg = pluginData.config.get();
|
||||||
|
const group = cfg.button_groups[args.button_group];
|
||||||
|
|
||||||
|
if (!group) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, `No button group matches the name **${args.button_group}**`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const channel = pluginData.guild.channels.resolve(group.channel_id);
|
||||||
|
if (!channel) {
|
||||||
|
await sendErrorMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel,
|
||||||
|
`The ID ${group.channel_id} does not match a channel on the server`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttons: MessageButton[] = [];
|
||||||
|
for (const button of Object.values(group.default_buttons)) {
|
||||||
|
let customId = "";
|
||||||
|
if ((await pluginData.guild.roles.fetch(button.role_or_menu)) != null) {
|
||||||
|
// TODO: Make universal, currently can only handle custom emoji and not default ones
|
||||||
|
customId = `${args.button_group}::${ButtonMenuActions.GRANT_ROLE}::${button.role_or_menu}`;
|
||||||
|
} else {
|
||||||
|
customId = `${args.button_group}::${ButtonMenuActions.OPEN_MENU}::${button.role_or_menu}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const btn = new MessageButton()
|
||||||
|
.setLabel(button.label)
|
||||||
|
.setStyle("PRIMARY")
|
||||||
|
.setType("BUTTON")
|
||||||
|
.setCustomID(customId);
|
||||||
|
|
||||||
|
const emo = pluginData.client.emojis.resolve(button.emoji);
|
||||||
|
if (emo) btn.setEmoji(emo);
|
||||||
|
|
||||||
|
buttons.push(btn);
|
||||||
|
}
|
||||||
|
const row = new MessageActionRow().addComponents(buttons);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await (channel as TextChannel).send({ content: group.message, components: [row], split: false });
|
||||||
|
} catch (e) {
|
||||||
|
sendErrorMessage(pluginData, msg.channel, `Error trying to post message: ${e}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await sendSuccessMessage(pluginData, msg.channel, `Successfully posted message in <#${channel.id}>`);
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,80 @@
|
||||||
|
import { Interaction, MessageComponentInteraction, MessageComponentInteractionCollector } from "discord.js";
|
||||||
|
import { LogType } from "src/data/LogType";
|
||||||
|
import { pluginInfo } from "src/plugins/Automod/info";
|
||||||
|
import { LogsPlugin } from "src/plugins/Logs/LogsPlugin";
|
||||||
|
import { reactionRolesEvt } from "../types";
|
||||||
|
import { ButtonMenuActions } from "../util/buttonMenuActions";
|
||||||
|
|
||||||
|
export const ButtonInteractionEvt = reactionRolesEvt({
|
||||||
|
event: "interaction",
|
||||||
|
|
||||||
|
async listener(meta) {
|
||||||
|
const int = meta.args.interaction.isMessageComponent()
|
||||||
|
? (meta.args.interaction as MessageComponentInteraction)
|
||||||
|
: null;
|
||||||
|
if (!int) return;
|
||||||
|
const cfg = meta.pluginData.config.get();
|
||||||
|
const split = int.customID.split("::");
|
||||||
|
const [groupName, action, roleOrMenu] = [split[0], split[1], split[2]];
|
||||||
|
|
||||||
|
const group = cfg.button_groups[groupName];
|
||||||
|
if (!group) {
|
||||||
|
await sendEphemeralReply(int, `A configuration error was encountered, please contact the Administrators!`);
|
||||||
|
meta.pluginData
|
||||||
|
.getPlugin(LogsPlugin)
|
||||||
|
.log(
|
||||||
|
LogType.BOT_ALERT,
|
||||||
|
`**A configuration error occured** on buttons for message ${int.message.id}, group **${groupName}** not found in config`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that detected action is known by us
|
||||||
|
if (!(<any>Object).values(ButtonMenuActions).includes(action)) {
|
||||||
|
await sendEphemeralReply(int, `A internal error was encountered, please contact the Administrators!`);
|
||||||
|
meta.pluginData
|
||||||
|
.getPlugin(LogsPlugin)
|
||||||
|
.log(
|
||||||
|
LogType.BOT_ALERT,
|
||||||
|
`**A internal error occured** on buttons for message ${int.message.id}, action **${action}** is not known`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === ButtonMenuActions.GRANT_ROLE) {
|
||||||
|
const role = await meta.pluginData.guild.roles.fetch(roleOrMenu);
|
||||||
|
if (!role) {
|
||||||
|
await sendEphemeralReply(int, `A configuration error was encountered, please contact the Administrators!`);
|
||||||
|
meta.pluginData
|
||||||
|
.getPlugin(LogsPlugin)
|
||||||
|
.log(
|
||||||
|
LogType.BOT_ALERT,
|
||||||
|
`**A configuration error occured** on buttons for message ${int.message.id}, group **${groupName}** not found in config`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const member = await meta.pluginData.guild.members.fetch(int.user.id);
|
||||||
|
if (member.roles.cache.has(role.id)) {
|
||||||
|
await member.roles.remove(role, `Button Roles on message ${int.message.id}`);
|
||||||
|
await sendEphemeralReply(int, `You have removed the role <@&${role.id}>`);
|
||||||
|
} else {
|
||||||
|
await member.roles.add(role, `Button Roles on message ${int.message.id}`);
|
||||||
|
await sendEphemeralReply(int, `You have added the role <@&${role.id}>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Send ephemeral reply with buttons that are part of the selected menu
|
||||||
|
if (action === ButtonMenuActions.OPEN_MENU) {
|
||||||
|
console.log("Disable TSLint error");
|
||||||
|
}
|
||||||
|
|
||||||
|
await sendEphemeralReply(int, split.join("\n")); // TODO: Remove debug output
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
async function sendEphemeralReply(interaction: MessageComponentInteraction, message: string) {
|
||||||
|
await interaction.reply(message, { ephemeral: true });
|
||||||
|
}
|
|
@ -4,7 +4,30 @@ import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { GuildReactionRoles } from "../../data/GuildReactionRoles";
|
import { GuildReactionRoles } from "../../data/GuildReactionRoles";
|
||||||
import { Queue } from "../../Queue";
|
import { Queue } from "../../Queue";
|
||||||
|
|
||||||
|
const ButtonOpts = t.type({
|
||||||
|
label: t.string,
|
||||||
|
emoji: t.string,
|
||||||
|
role_or_menu: t.string,
|
||||||
|
});
|
||||||
|
export type TButtonOpts = t.TypeOf<typeof ButtonOpts>;
|
||||||
|
|
||||||
|
const MenuButtonOpts = t.type({
|
||||||
|
label: t.string,
|
||||||
|
emoji: t.string,
|
||||||
|
role: t.string,
|
||||||
|
});
|
||||||
|
export type TMenuButtonOpts = t.TypeOf<typeof MenuButtonOpts>;
|
||||||
|
|
||||||
|
const ButtonPairOpts = t.type({
|
||||||
|
channel_id: t.string,
|
||||||
|
message: t.string,
|
||||||
|
default_buttons: t.record(t.string, ButtonOpts),
|
||||||
|
button_menus: t.record(t.string, t.record(t.string, MenuButtonOpts)),
|
||||||
|
});
|
||||||
|
export type TButtonPairOpts = t.TypeOf<typeof ButtonPairOpts>;
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const ConfigSchema = t.type({
|
||||||
|
button_groups: t.record(t.string, ButtonPairOpts),
|
||||||
auto_refresh_interval: t.number,
|
auto_refresh_interval: t.number,
|
||||||
remove_user_reactions: t.boolean,
|
remove_user_reactions: t.boolean,
|
||||||
can_manage: t.boolean,
|
can_manage: t.boolean,
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
export enum ButtonMenuActions {
|
||||||
|
OPEN_MENU = "goto",
|
||||||
|
GRANT_ROLE = "grant",
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue