Skip to content

Commit ed59cf1

Browse files
committed
fixes
This solves: - `config get`: invalid form body - restores functionality after menu timeout.
1 parent 700e4cf commit ed59cf1

File tree

2 files changed

+150
-18
lines changed

2 files changed

+150
-18
lines changed

cogs/utility.py

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from subprocess import PIPE
1414
from textwrap import indent
1515
from typing import Union
16+
import typing
1617

1718
import discord
1819
from discord.enums import ActivityType, Status
@@ -898,21 +899,44 @@ async def config_get(self, ctx, *, key: str.lower = None):
898899
)
899900

900901
else:
901-
embed = discord.Embed(
902-
color=self.bot.main_color,
903-
description="Here is a list of currently set configuration variable(s).",
904-
)
905-
embed.set_author(
906-
name="Current config(s):",
907-
icon_url=self.bot.user.display_avatar.url if self.bot.user.display_avatar else None,
908-
)
909-
config = self.bot.config.filter_default(self.bot.config)
910-
911-
for name, value in config.items():
912-
if name in self.bot.config.public_keys:
913-
embed.add_field(name=name, value=f"`{value}`", inline=False)
902+
# Build one or more embeds, each with up to 25 fields
903+
base_desc = "Here is a list of currently set configuration variable(s)."
904+
author_name = "Current config(s):"
905+
icon = self.bot.user.display_avatar.url if self.bot.user.display_avatar else None
914906

915-
return await ctx.send(embed=embed)
907+
config = self.bot.config.filter_default(self.bot.config)
908+
items = [(name, value) for name, value in config.items() if name in self.bot.config.public_keys]
909+
910+
embeds: list[discord.Embed] = []
911+
chunk: list[tuple[str, typing.Any]] = []
912+
for pair in items:
913+
chunk.append(pair)
914+
if len(chunk) == 15:
915+
e = discord.Embed(color=self.bot.main_color, description=base_desc)
916+
e.set_author(name=author_name, icon_url=icon)
917+
for name, value in chunk:
918+
e.add_field(name=name, value=f"`{value}`", inline=False)
919+
embeds.append(e)
920+
chunk = []
921+
922+
if chunk:
923+
e = discord.Embed(color=self.bot.main_color, description=base_desc)
924+
e.set_author(name=author_name, icon_url=icon)
925+
for name, value in chunk:
926+
e.add_field(name=name, value=f"`{value}`", inline=False)
927+
embeds.append(e)
928+
929+
# Send one or many embeds depending on count.
930+
# In the single-key branch above, variable 'embed' exists; in this multi branch, we only use 'embeds'.
931+
if key:
932+
return await ctx.send(embed=embed)
933+
else:
934+
if not embeds:
935+
return await ctx.send("No public configuration keys are set.")
936+
# Use the existing paginator consistently
937+
paginator = EmbedPaginatorSession(ctx, *embeds)
938+
await paginator.run()
939+
return
916940

917941
@config.command(name="help", aliases=["info"])
918942
@checks.has_permissions(PermissionLevel.OWNER)

core/thread.py

Lines changed: 112 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2218,7 +2218,18 @@ async def find(
22182218
try:
22192219
await thread.wait_until_ready()
22202220
except asyncio.CancelledError:
2221-
logger.warning("Thread for %s cancelled.", recipient)
2221+
# Improve logging: include username and user ID when possible
2222+
try:
2223+
if recipient is not None:
2224+
label = f"{recipient} ({recipient.id})"
2225+
elif recipient_id is not None:
2226+
user = await self.bot.get_or_fetch_user(recipient_id)
2227+
label = f"{user} ({recipient_id})" if user else f"User ({recipient_id})"
2228+
else:
2229+
label = "Unknown User"
2230+
except Exception:
2231+
label = f"User ({recipient_id})" if recipient_id is not None else "Unknown User"
2232+
logger.warning("Thread for %s cancelled.", label)
22222233
return thread
22232234
else:
22242235
# If the thread is snoozed (channel is None), return it for restoration
@@ -2335,7 +2346,12 @@ async def create(
23352346
try:
23362347
await thread.wait_until_ready()
23372348
except asyncio.CancelledError:
2338-
logger.warning("Thread for %s cancelled, abort creating.", recipient)
2349+
# Improve logging to include username and ID
2350+
try:
2351+
label = f"{recipient} ({recipient.id})"
2352+
except Exception:
2353+
label = f"User ({getattr(recipient, 'id', 'unknown')})"
2354+
logger.warning("Thread for %s cancelled, abort creating.", label)
23392355
return thread
23402356
else:
23412357
if thread.channel and self.bot.get_channel(thread.channel.id):
@@ -2350,7 +2366,18 @@ async def create(
23502366

23512367
self.cache[recipient.id] = thread
23522368

2353-
if (message or not manual_trigger) and self.bot.config["confirm_thread_creation"]:
2369+
# Determine if the advanced thread-creation menu is enabled; if so and the user
2370+
# initiated via DM, we defer confirmation until AFTER the user selects an option.
2371+
adv_menu_enabled = self.bot.config.get("thread_creation_menu_enabled") and bool(
2372+
self.bot.config.get("thread_creation_menu_options")
2373+
)
2374+
user_initiated_dm = (creator is None or creator == recipient) and manual_trigger
2375+
2376+
if (
2377+
(message or not manual_trigger)
2378+
and self.bot.config["confirm_thread_creation"]
2379+
and not (adv_menu_enabled and user_initiated_dm)
2380+
):
23542381
if not manual_trigger:
23552382
destination = recipient
23562383
else:
@@ -2416,7 +2443,6 @@ async def create(
24162443
submenus = self.bot.config.get("thread_creation_menu_submenus") or {}
24172444

24182445
# Minimal inline view implementation (avoid importing plugin code)
2419-
import discord
24202446

24212447
thread.ready = False # not ready yet
24222448

@@ -2459,6 +2485,69 @@ async def callback(self, interaction: discord.Interaction):
24592485
# Fallback to provided category (from outer scope) or main category
24602486
fallback_category = category or self.outer_thread.bot.main_category
24612487
use_category = sel_category or fallback_category
2488+
# If confirmation is enabled, prompt now (after option selection)
2489+
try:
2490+
if self.outer_thread.bot.config.get("confirm_thread_creation"):
2491+
dest = message.channel if manual_trigger else recipient
2492+
view = ConfirmThreadCreationView()
2493+
view.add_item(
2494+
AcceptButton(
2495+
"accept-thread-creation",
2496+
self.outer_thread.bot.config["confirm_thread_creation_accept"],
2497+
)
2498+
)
2499+
view.add_item(
2500+
DenyButton(
2501+
"deny-thread-creation",
2502+
self.outer_thread.bot.config["confirm_thread_creation_deny"],
2503+
)
2504+
)
2505+
confirm = await dest.send(
2506+
embed=discord.Embed(
2507+
title=self.outer_thread.bot.config["confirm_thread_creation_title"],
2508+
description=self.outer_thread.bot.config["confirm_thread_response"],
2509+
color=self.outer_thread.bot.main_color,
2510+
),
2511+
view=view,
2512+
)
2513+
await view.wait()
2514+
if view.value is None:
2515+
# Timed out
2516+
self.outer_thread.cancelled = True
2517+
try:
2518+
await dest.send(
2519+
embed=discord.Embed(
2520+
title=self.outer_thread.bot.config["thread_cancelled"],
2521+
description="Timed out",
2522+
color=self.outer_thread.bot.error_color,
2523+
)
2524+
)
2525+
await confirm.edit(view=None)
2526+
except Exception:
2527+
pass
2528+
elif view.value is False:
2529+
self.outer_thread.cancelled = True
2530+
try:
2531+
await dest.send(
2532+
embed=discord.Embed(
2533+
title=self.outer_thread.bot.config["thread_cancelled"],
2534+
color=self.outer_thread.bot.error_color,
2535+
)
2536+
)
2537+
except Exception:
2538+
pass
2539+
if self.outer_thread.cancelled:
2540+
# Clear pending/menu state and cache
2541+
try:
2542+
setattr(self.outer_thread, "_pending_menu", False)
2543+
self.outer_thread.manager.cache.pop(self.outer_thread.id, None)
2544+
except Exception:
2545+
pass
2546+
return
2547+
except Exception:
2548+
# If confirm step fails, proceed to create thread to avoid dead-ends
2549+
logger.warning("Confirm step failed after menu selection; continuing.")
2550+
24622551
self.outer_thread.bot.loop.create_task(
24632552
self.outer_thread.setup(
24642553
creator=creator,
@@ -2555,6 +2644,8 @@ async def on_timeout(self):
25552644
self.outer_thread.manager.cache.pop(self.outer_thread.id, None)
25562645
except Exception:
25572646
pass
2647+
# Clear pending menu flag so a new message can recreate a fresh thread
2648+
setattr(self.outer_thread, "_pending_menu", False)
25582649
self.outer_thread.cancelled = True
25592650
else:
25602651
try:
@@ -2563,6 +2654,18 @@ async def on_timeout(self):
25632654
)
25642655
except Exception:
25652656
pass
2657+
# Allow subsequent messages to trigger a new menu/thread by clearing state
2658+
setattr(self.outer_thread, "_pending_menu", False)
2659+
try:
2660+
self.outer_thread.manager.cache.pop(self.outer_thread.id, None)
2661+
except Exception:
2662+
pass
2663+
self.outer_thread.cancelled = True
2664+
# Ensure view is stopped to release any internal tasks
2665+
try:
2666+
self.stop()
2667+
except Exception:
2668+
pass
25662669

25672670
# Send DM prompt
25682671
try:
@@ -2571,6 +2674,11 @@ async def on_timeout(self):
25712674
menu_msg = await recipient.send(embed=embed, view=menu_view)
25722675
# mark thread as pending menu selection
25732676
thread._pending_menu = True
2677+
# Explicitly attach the message to the view for safety in callbacks
2678+
try:
2679+
menu_view.message = menu_msg
2680+
except Exception:
2681+
pass
25742682
except Exception:
25752683
logger.warning(
25762684
"Failed to send thread-creation menu DM, falling back to immediate thread creation."

0 commit comments

Comments
 (0)