3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-16 22:21:51 +00:00

fix: modal id conflicts causing collectors to respond to unrelated submissions

This commit is contained in:
Obliie 2023-07-16 00:12:13 +01:00
parent 454bec6c9f
commit 7f2f2c8f98
No known key found for this signature in database
GPG key ID: 9189A18F0D5B547E
5 changed files with 87 additions and 74 deletions

View file

@ -11,10 +11,11 @@ import humanizeDuration from "humanize-duration";
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import { canActOn } from "src/pluginUtils"; import { canActOn } from "src/pluginUtils";
import { ModActionsPlugin } from "src/plugins/ModActions/ModActionsPlugin"; import { ModActionsPlugin } from "src/plugins/ModActions/ModActionsPlugin";
import { logger } from "../../../logger";
import { convertDelayStringToMS, renderUserUsername } from "../../../utils"; import { convertDelayStringToMS, renderUserUsername } from "../../../utils";
import { CaseArgs } from "../../Cases/types"; import { CaseArgs } from "../../Cases/types";
import { MODAL_TIMEOUT } from "../commands/ModMenuUserCtxCmd"; import { MODAL_TIMEOUT } from "../commands/ModMenuUserCtxCmd";
import { ContextMenuPluginType } from "../types"; import { ContextMenuPluginType, ModMenuActionType } from "../types";
async function banAction( async function banAction(
pluginData: GuildPluginData<ContextMenuPluginType>, pluginData: GuildPluginData<ContextMenuPluginType>,
@ -24,7 +25,7 @@ async function banAction(
interaction: ButtonInteraction | ContextMenuCommandInteraction, interaction: ButtonInteraction | ContextMenuCommandInteraction,
submitInteraction: ModalSubmitInteraction, submitInteraction: ModalSubmitInteraction,
) { ) {
const interactionToReply = interaction instanceof ButtonInteraction ? interaction : submitInteraction; const interactionToReply = interaction.isButton() ? interaction : submitInteraction;
const executingMember = await pluginData.guild.members.fetch(interaction.user.id); const executingMember = await pluginData.guild.members.fetch(interaction.user.id);
const userCfg = await pluginData.config.getMatchingConfig({ const userCfg = await pluginData.config.getMatchingConfig({
channelId: interaction.channelId, channelId: interaction.channelId,
@ -68,7 +69,8 @@ export async function launchBanActionModal(
interaction: ButtonInteraction | ContextMenuCommandInteraction, interaction: ButtonInteraction | ContextMenuCommandInteraction,
target: string, target: string,
) { ) {
const modal = new ModalBuilder().setCustomId("ban").setTitle("Ban"); const modalId = `${ModMenuActionType.WARN}:${interaction.id}`;
const modal = new ModalBuilder().setCustomId(modalId).setTitle("Ban");
const durationIn = new TextInputBuilder() const durationIn = new TextInputBuilder()
.setCustomId("duration") .setCustomId("duration")
.setLabel("Duration (Optional)") .setLabel("Duration (Optional)")
@ -84,17 +86,19 @@ export async function launchBanActionModal(
modal.addComponents(durationRow, reasonRow); modal.addComponents(durationRow, reasonRow);
await interaction.showModal(modal); await interaction.showModal(modal);
const submitted: ModalSubmitInteraction = await interaction.awaitModalSubmit({ time: MODAL_TIMEOUT }); await interaction
if (submitted) { .awaitModalSubmit({ time: MODAL_TIMEOUT, filter: (i) => i.customId == modalId })
if (interaction instanceof ButtonInteraction) { .then(async (submitted) => {
await submitted.deferUpdate(); if (interaction.isButton()) {
} else { await submitted.deferUpdate();
await submitted.deferReply({ ephemeral: true }); } else if (interaction.isContextMenuCommand()) {
} await submitted.deferReply({ ephemeral: true });
}
const duration = submitted.fields.getTextInputValue("duration"); const duration = submitted.fields.getTextInputValue("duration");
const reason = submitted.fields.getTextInputValue("reason"); const reason = submitted.fields.getTextInputValue("reason");
await banAction(pluginData, duration, reason, target, interaction, submitted); await banAction(pluginData, duration, reason, target, interaction, submitted);
} })
.catch((err) => logger.error(`Ban modal interaction failed: ${err}`));
} }

View file

@ -1,15 +1,9 @@
import { import { ActionRowBuilder, ButtonInteraction, ModalBuilder, TextInputBuilder, TextInputStyle } from "discord.js";
ActionRowBuilder,
ButtonInteraction,
ModalBuilder,
ModalSubmitInteraction,
TextInputBuilder,
TextInputStyle,
} from "discord.js";
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import { logger } from "../../../logger";
import { UtilityPlugin } from "../../../plugins/Utility/UtilityPlugin"; import { UtilityPlugin } from "../../../plugins/Utility/UtilityPlugin";
import { MODAL_TIMEOUT } from "../commands/ModMenuUserCtxCmd"; import { MODAL_TIMEOUT } from "../commands/ModMenuUserCtxCmd";
import { ContextMenuPluginType } from "../types"; import { ContextMenuPluginType, ModMenuActionType } from "../types";
export async function cleanAction( export async function cleanAction(
pluginData: GuildPluginData<ContextMenuPluginType>, pluginData: GuildPluginData<ContextMenuPluginType>,
@ -42,22 +36,25 @@ export async function launchCleanActionModal(
interaction: ButtonInteraction, interaction: ButtonInteraction,
target: string, target: string,
) { ) {
const modal = new ModalBuilder().setCustomId("clean").setTitle("Clean"); const modalId = `${ModMenuActionType.CLEAN}:${interaction.id}`;
const modal = new ModalBuilder().setCustomId(modalId).setTitle("Clean");
const amountIn = new TextInputBuilder().setCustomId("amount").setLabel("Amount").setStyle(TextInputStyle.Short); const amountIn = new TextInputBuilder().setCustomId("amount").setLabel("Amount").setStyle(TextInputStyle.Short);
const amountRow = new ActionRowBuilder<TextInputBuilder>().addComponents(amountIn); const amountRow = new ActionRowBuilder<TextInputBuilder>().addComponents(amountIn);
modal.addComponents(amountRow); modal.addComponents(amountRow);
await interaction.showModal(modal); await interaction.showModal(modal);
const submitted: ModalSubmitInteraction = await interaction.awaitModalSubmit({ time: MODAL_TIMEOUT }); await interaction
if (submitted) { .awaitModalSubmit({ time: MODAL_TIMEOUT, filter: (i) => i.customId == modalId })
await submitted.deferUpdate(); .then(async (submitted) => {
await submitted.deferUpdate();
const amount = submitted.fields.getTextInputValue("amount"); const amount = submitted.fields.getTextInputValue("amount");
if (isNaN(Number(amount))) { if (isNaN(Number(amount))) {
interaction.editReply({ content: `Error: Amount '${amount}' is invalid`, embeds: [], components: [] }); interaction.editReply({ content: `Error: Amount '${amount}' is invalid`, embeds: [], components: [] });
return; return;
} }
await cleanAction(pluginData, Number(amount), target, interaction); await cleanAction(pluginData, Number(amount), target, interaction);
} })
.catch((err) => logger.error(`Clean modal interaction failed: ${err}`));
} }

View file

@ -12,12 +12,13 @@ import { GuildPluginData } from "knub";
import { canActOn } from "src/pluginUtils"; import { canActOn } from "src/pluginUtils";
import { ModActionsPlugin } from "src/plugins/ModActions/ModActionsPlugin"; import { ModActionsPlugin } from "src/plugins/ModActions/ModActionsPlugin";
import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError"; import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
import { logger } from "../../../logger";
import { convertDelayStringToMS } from "../../../utils"; import { convertDelayStringToMS } from "../../../utils";
import { CaseArgs } from "../../Cases/types"; import { CaseArgs } from "../../Cases/types";
import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogsPlugin } from "../../Logs/LogsPlugin";
import { MutesPlugin } from "../../Mutes/MutesPlugin"; import { MutesPlugin } from "../../Mutes/MutesPlugin";
import { MODAL_TIMEOUT } from "../commands/ModMenuUserCtxCmd"; import { MODAL_TIMEOUT } from "../commands/ModMenuUserCtxCmd";
import { ContextMenuPluginType } from "../types"; import { ContextMenuPluginType, ModMenuActionType } from "../types";
async function muteAction( async function muteAction(
pluginData: GuildPluginData<ContextMenuPluginType>, pluginData: GuildPluginData<ContextMenuPluginType>,
@ -27,7 +28,7 @@ async function muteAction(
interaction: ButtonInteraction | ContextMenuCommandInteraction, interaction: ButtonInteraction | ContextMenuCommandInteraction,
submitInteraction: ModalSubmitInteraction, submitInteraction: ModalSubmitInteraction,
) { ) {
const interactionToReply = interaction instanceof ButtonInteraction ? interaction : submitInteraction; const interactionToReply = interaction.isButton() ? interaction : submitInteraction;
const executingMember = await pluginData.guild.members.fetch(interaction.user.id); const executingMember = await pluginData.guild.members.fetch(interaction.user.id);
const userCfg = await pluginData.config.getMatchingConfig({ const userCfg = await pluginData.config.getMatchingConfig({
channelId: interaction.channelId, channelId: interaction.channelId,
@ -91,7 +92,8 @@ export async function launchMuteActionModal(
interaction: ButtonInteraction | ContextMenuCommandInteraction, interaction: ButtonInteraction | ContextMenuCommandInteraction,
target: string, target: string,
) { ) {
const modal = new ModalBuilder().setCustomId("mute").setTitle("Mute"); const modalId = `${ModMenuActionType.MUTE}:${interaction.id}`;
const modal = new ModalBuilder().setCustomId(modalId).setTitle("Mute");
const durationIn = new TextInputBuilder() const durationIn = new TextInputBuilder()
.setCustomId("duration") .setCustomId("duration")
.setLabel("Duration (Optional)") .setLabel("Duration (Optional)")
@ -107,17 +109,19 @@ export async function launchMuteActionModal(
modal.addComponents(durationRow, reasonRow); modal.addComponents(durationRow, reasonRow);
await interaction.showModal(modal); await interaction.showModal(modal);
const submitted: ModalSubmitInteraction = await interaction.awaitModalSubmit({ time: MODAL_TIMEOUT }); await interaction
if (submitted) { .awaitModalSubmit({ time: MODAL_TIMEOUT, filter: (i) => i.customId == modalId })
if (interaction instanceof ButtonInteraction) { .then(async (submitted) => {
await submitted.deferUpdate(); if (interaction.isButton()) {
} else { await submitted.deferUpdate();
await submitted.deferReply({ ephemeral: true }); } else if (interaction.isContextMenuCommand()) {
} await submitted.deferReply({ ephemeral: true });
}
const duration = submitted.fields.getTextInputValue("duration"); const duration = submitted.fields.getTextInputValue("duration");
const reason = submitted.fields.getTextInputValue("reason"); const reason = submitted.fields.getTextInputValue("reason");
await muteAction(pluginData, duration, reason, target, interaction, submitted); await muteAction(pluginData, duration, reason, target, interaction, submitted);
} })
.catch((err) => logger.error(`Mute modal interaction failed: ${err}`));
} }

View file

@ -11,11 +11,12 @@ import { GuildPluginData } from "knub";
import { canActOn } from "src/pluginUtils"; import { canActOn } from "src/pluginUtils";
import { ModActionsPlugin } from "src/plugins/ModActions/ModActionsPlugin"; import { ModActionsPlugin } from "src/plugins/ModActions/ModActionsPlugin";
import { CaseTypes } from "../../../data/CaseTypes"; import { CaseTypes } from "../../../data/CaseTypes";
import { logger } from "../../../logger";
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin"; import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
import { renderUserUsername } from "../../../utils"; import { renderUserUsername } from "../../../utils";
import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogsPlugin } from "../../Logs/LogsPlugin";
import { MODAL_TIMEOUT } from "../commands/ModMenuUserCtxCmd"; import { MODAL_TIMEOUT } from "../commands/ModMenuUserCtxCmd";
import { ContextMenuPluginType } from "../types"; import { ContextMenuPluginType, ModMenuActionType } from "../types";
async function noteAction( async function noteAction(
pluginData: GuildPluginData<ContextMenuPluginType>, pluginData: GuildPluginData<ContextMenuPluginType>,
@ -24,7 +25,7 @@ async function noteAction(
interaction: ButtonInteraction | ContextMenuCommandInteraction, interaction: ButtonInteraction | ContextMenuCommandInteraction,
submitInteraction: ModalSubmitInteraction, submitInteraction: ModalSubmitInteraction,
) { ) {
const interactionToReply = interaction instanceof ButtonInteraction ? interaction : submitInteraction; const interactionToReply = interaction.isButton() ? interaction : submitInteraction;
const executingMember = await pluginData.guild.members.fetch(interaction.user.id); const executingMember = await pluginData.guild.members.fetch(interaction.user.id);
const userCfg = await pluginData.config.getMatchingConfig({ const userCfg = await pluginData.config.getMatchingConfig({
channelId: interaction.channelId, channelId: interaction.channelId,
@ -79,22 +80,25 @@ export async function launchNoteActionModal(
interaction: ButtonInteraction | ContextMenuCommandInteraction, interaction: ButtonInteraction | ContextMenuCommandInteraction,
target: string, target: string,
) { ) {
const modal = new ModalBuilder().setCustomId("note").setTitle("Note"); const modalId = `${ModMenuActionType.NOTE}:${interaction.id}`;
const modal = new ModalBuilder().setCustomId(modalId).setTitle("Note");
const reasonIn = new TextInputBuilder().setCustomId("reason").setLabel("Note").setStyle(TextInputStyle.Paragraph); const reasonIn = new TextInputBuilder().setCustomId("reason").setLabel("Note").setStyle(TextInputStyle.Paragraph);
const reasonRow = new ActionRowBuilder<TextInputBuilder>().addComponents(reasonIn); const reasonRow = new ActionRowBuilder<TextInputBuilder>().addComponents(reasonIn);
modal.addComponents(reasonRow); modal.addComponents(reasonRow);
await interaction.showModal(modal); await interaction.showModal(modal);
const submitted: ModalSubmitInteraction = await interaction.awaitModalSubmit({ time: MODAL_TIMEOUT }); await interaction
if (submitted) { .awaitModalSubmit({ time: MODAL_TIMEOUT, filter: (i) => i.customId == modalId })
if (interaction instanceof ButtonInteraction) { .then(async (submitted) => {
await submitted.deferUpdate(); if (interaction.isButton()) {
} else { await submitted.deferUpdate();
await submitted.deferReply({ ephemeral: true }); } else if (interaction.isContextMenuCommand()) {
} await submitted.deferReply({ ephemeral: true });
}
const reason = submitted.fields.getTextInputValue("reason"); const reason = submitted.fields.getTextInputValue("reason");
await noteAction(pluginData, reason, target, interaction, submitted); await noteAction(pluginData, reason, target, interaction, submitted);
} })
.catch((err) => logger.error(`Note modal interaction failed: ${err}`));
} }

View file

@ -10,10 +10,11 @@ import {
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import { canActOn } from "src/pluginUtils"; import { canActOn } from "src/pluginUtils";
import { ModActionsPlugin } from "src/plugins/ModActions/ModActionsPlugin"; import { ModActionsPlugin } from "src/plugins/ModActions/ModActionsPlugin";
import { logger } from "../../../logger";
import { renderUserUsername } from "../../../utils"; import { renderUserUsername } from "../../../utils";
import { CaseArgs } from "../../Cases/types"; import { CaseArgs } from "../../Cases/types";
import { MODAL_TIMEOUT } from "../commands/ModMenuUserCtxCmd"; import { MODAL_TIMEOUT } from "../commands/ModMenuUserCtxCmd";
import { ContextMenuPluginType } from "../types"; import { ContextMenuPluginType, ModMenuActionType } from "../types";
async function warnAction( async function warnAction(
pluginData: GuildPluginData<ContextMenuPluginType>, pluginData: GuildPluginData<ContextMenuPluginType>,
@ -22,7 +23,7 @@ async function warnAction(
interaction: ButtonInteraction | ContextMenuCommandInteraction, interaction: ButtonInteraction | ContextMenuCommandInteraction,
submitInteraction: ModalSubmitInteraction, submitInteraction: ModalSubmitInteraction,
) { ) {
const interactionToReply = interaction instanceof ButtonInteraction ? interaction : submitInteraction; const interactionToReply = interaction.isButton() ? interaction : submitInteraction;
const executingMember = await pluginData.guild.members.fetch(interaction.user.id); const executingMember = await pluginData.guild.members.fetch(interaction.user.id);
const userCfg = await pluginData.config.getMatchingConfig({ const userCfg = await pluginData.config.getMatchingConfig({
channelId: interaction.channelId, channelId: interaction.channelId,
@ -71,22 +72,25 @@ export async function launchWarnActionModal(
interaction: ButtonInteraction | ContextMenuCommandInteraction, interaction: ButtonInteraction | ContextMenuCommandInteraction,
target: string, target: string,
) { ) {
const modal = new ModalBuilder().setCustomId("warn").setTitle("Warn"); const modalId = `${ModMenuActionType.WARN}:${interaction.id}`;
const modal = new ModalBuilder().setCustomId(modalId).setTitle("Warn");
const reasonIn = new TextInputBuilder().setCustomId("reason").setLabel("Reason").setStyle(TextInputStyle.Paragraph); const reasonIn = new TextInputBuilder().setCustomId("reason").setLabel("Reason").setStyle(TextInputStyle.Paragraph);
const reasonRow = new ActionRowBuilder<TextInputBuilder>().addComponents(reasonIn); const reasonRow = new ActionRowBuilder<TextInputBuilder>().addComponents(reasonIn);
modal.addComponents(reasonRow); modal.addComponents(reasonRow);
await interaction.showModal(modal); await interaction.showModal(modal);
const submitted: ModalSubmitInteraction = await interaction.awaitModalSubmit({ time: MODAL_TIMEOUT }); await interaction
if (submitted) { .awaitModalSubmit({ time: MODAL_TIMEOUT, filter: (i) => i.customId == modalId })
if (interaction instanceof ButtonInteraction) { .then(async (submitted) => {
await submitted.deferUpdate(); if (interaction.isButton()) {
} else { await submitted.deferUpdate();
await submitted.deferReply({ ephemeral: true }); } else if (interaction.isContextMenuCommand()) {
} await submitted.deferReply({ ephemeral: true });
}
const reason = submitted.fields.getTextInputValue("reason"); const reason = submitted.fields.getTextInputValue("reason");
await warnAction(pluginData, reason, target, interaction, submitted); await warnAction(pluginData, reason, target, interaction, submitted);
} })
.catch((err) => logger.error(`Mute modal interaction failed: ${err}`));
} }