feat: Add timeout and interaction control to captcha modal

Set a 10-minute timeout for the `CaptchaModal` to prevent it from hanging indefinitely. Implemented a `wait()` method within the modal, allowing the calling function to asynchronously wait for submission or timeout. This enables proper flow control for the upload process.

Restricted the "Solve Captcha" button in `CaptchaView` to only be clickable by the user who initiated the command, preventing unauthorized interaction.
This commit is contained in:
Slipstream 2025-05-21 11:50:19 -06:00
parent 04c2dd75b9
commit bfd0d606ab
Signed by: slipstream
GPG Key ID: 13E498CE010AC6FD

View File

@ -12,7 +12,8 @@ import discord.ui
class CaptchaModal(discord.ui.Modal, title="Solve Image Captcha"):
def __init__(self, captcha_id: str):
super().__init__()
# Set the modal timeout to 10 minutes to match the view's timeout for consistency
super().__init__(timeout=600)
self.captcha_id = captcha_id
self.solution = discord.ui.TextInput(
label="Captcha Solution",
@ -22,20 +23,43 @@ class CaptchaModal(discord.ui.Modal, title="Solve Image Captcha"):
max_length=100
)
self.add_item(self.solution)
self.interaction = None
self.is_submitted = asyncio.Event()
async def on_submit(self, interaction: discord.Interaction):
# This method will be called when the user submits the modal
# The actual file upload logic will be handled by the calling function
await interaction.response.defer(ephemeral=True) # Defer the response to prevent interaction timeout
# Store the interaction for later use
self.interaction = interaction
await interaction.response.defer(ephemeral=True) # Defer the response to prevent interaction timeout
# Set the event to signal that the modal has been submitted
self.is_submitted.set()
async def wait(self) -> bool:
"""Wait for the modal to be submitted or time out.
Returns:
bool: True if the modal timed out, False if it was submitted.
"""
try:
await asyncio.wait_for(self.is_submitted.wait(), timeout=self.timeout)
return False # Modal was submitted
except asyncio.TimeoutError:
return True # Modal timed out
class CaptchaView(discord.ui.View):
def __init__(self, modal: CaptchaModal):
def __init__(self, modal: CaptchaModal, original_interactor_id: int):
super().__init__(timeout=600) # 10 minutes timeout
self.modal = modal
self.original_interactor_id = original_interactor_id
@discord.ui.button(label="Solve Captcha", style=discord.ButtonStyle.primary)
async def solve_button(self, interaction: discord.Interaction, button: discord.ui.Button):
# Check if the user interacting is the original user who initiated the command
if interaction.user.id != self.original_interactor_id:
await interaction.response.send_message("Only the user who initiated this command can solve the captcha.", ephemeral=True)
return
await interaction.response.send_modal(self.modal)