Skip to content

Commit

Permalink
[RoleTools] 1.5.15 Cleanup some errors
Browse files Browse the repository at this point in the history
- Prevent setting max_values on select menus higher than the number of available options.
- Don't error on editing existing button and select menus with a message stating which existing messages failed to edit correctly.
- Add missing reason for not applying/removing roles in select menus response.
- Give more information to the user when trying to send or edit buttons/select menus with incorrectly created views.
  • Loading branch information
TrustyJAID committed Dec 14, 2024
1 parent 5a38cc7 commit 0813485
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 23 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ TrustyJAID's Cogs for [Red-DiscordBot](https://github.com/Cog-Creators/Red-Disc
| Reddit | 1.2.0 | <details><summary>A cog to post updates from reddit.</summary>Reddit commands for getting updates on specified subreddits.</details> | TrustyJAID |
| Rekt | 1.0.0 | <details><summary>Get REKT</summary>Are you REKT?</details> | TrustyJAID |
| ReTrigger | 2.29.1 | <details><summary>Trigger events via Regular Expressions!</summary>Trigger events based on regex! Check out <https://regex101.com/> and <https://github.com/TrustyJAID/Trusty-cogs/blob/master/retrigger/README.md> for help setting up the cog. Note: This cog can become quite resource heavy. Optional features are available if the requirements are present such as pillow for image resizing and pytesseract to scan images for text (OCR).</details> | TrustyJAID |
| RoleTools | 1.5.14 | <details><summary>Various role related tools.</summary>Various role utility commands. Including Reaction roles, Sticky roles, and Auto role.</details> | TrustyJAID |
| RoleTools | 1.5.15 | <details><summary>Various role related tools.</summary>Various role utility commands. Including Reaction roles, Sticky roles, and Auto role.</details> | TrustyJAID |
| runescape | 1.5.2 | <details><summary>Show your Runescape stats in discord!</summary>A cog to grab Runescape and OSRS stats and profile information.</details> | TrustyJAID |
| ServerStats | 1.8.0 | <details><summary>A plethora of potentially useful commands for any bot owner.</summary>A plethora of potentially useful commands for any bot owner. Includes a way to track the bot joining new servers, find cheaters on global economies, get user avatars and even larger emojis.</details> | TrustyJAID and Preda |
| Spotify | 1.7.3 | <details><summary>Control Spotify through Discord!</summary>This cog allows you to control Spotify via OAuth through the bot on discord. Use `[p]spotify` to see available commands.</details> | TrustyJAID and NeuroAssassin |
Expand Down
23 changes: 22 additions & 1 deletion roletools/buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from redbot.core import commands
from redbot.core.commands import Context
from redbot.core.i18n import Translator
from redbot.core.utils.chat_formatting import pagify

from .abc import RoleToolsMixin
from .components import ButtonRole, RoleToolsView
Expand Down Expand Up @@ -152,6 +153,7 @@ async def create_button(
role_id=role.id,
name=name.lower(),
)
failed_fixes = []
for message_id in button_settings["messages"]:
# fix old buttons with the new one when interacted with
replacement_view = self.views.get(ctx.guild.id, {}).get(message_id, None)
Expand All @@ -160,11 +162,30 @@ async def create_button(
for item in replacement_view.children:
if item.custom_id == custom_id:
replacement_view.remove_item(item)
replacement_view.add_item(button)
try:
replacement_view.add_item(button)
except ValueError:
failed_fixes.append(message_id)
button.replace_label(ctx.guild)
view = RoleToolsView(self, timeout=180.0)
view.add_item(button)
await ctx.send("Here is how your button will look.", view=view)
if failed_fixes:
msg = ""
for view_id in failed_fixes:
channel_id, message_id = view_id.split("-")
channel = ctx.guild.get_channel(int(channel_id))
if channel is None:
continue
message = discord.PartialMessage(channel=channel, id=int(message_id))
msg += f"- {message.jump_url}\n"
pages = []
full_msg = _(
"The following existing buttons could not be edited with the new settings.\n{failed}"
).format(failed=msg)
for page in pagify(full_msg):
pages.append(page)
await ctx.send_interactive(pages)
await self.confirm_selfassignable(ctx, [role])

@buttons.command(name="delete", aliases=["del", "remove"])
Expand Down
17 changes: 15 additions & 2 deletions roletools/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ async def callback(self, interaction: discord.Interaction):
missing_role = False
pending = False
wait = None
config = self.view.cog.config
for role_id in role_ids:
role = guild.get_role(role_id)
if role is None:
Expand All @@ -255,7 +256,7 @@ async def callback(self, interaction: discord.Interaction):
# # even if it's your own code
# ## Especially if it's your own code
continue
config = self.view.cog.config

if role not in interaction.user.roles:
if not await config.role(role).selfassignable():
msg += _(
Expand All @@ -278,6 +279,10 @@ async def callback(self, interaction: discord.Interaction):
interaction.user, [role], _("Role Selection")
)
if response:
reason = response[0].reason
msg += _("The {role} role could not be given because: {reason}").format(
role=role.mention, reason=reason
)
continue
added_roles.append(role)
elif role in interaction.user.roles:
Expand All @@ -287,7 +292,15 @@ async def callback(self, interaction: discord.Interaction):
).format(role=role.mention)
continue
# log.debug("Removing role from %s in %s", interaction.user.name, guild)
await self.view.cog.remove_roles(interaction.user, [role], _("Role Selection"))
response = await self.view.cog.remove_roles(
interaction.user, [role], _("Role Selection")
)
if response:
reason = response[0].reason
msg += _("The {role} role could not be removed because: {reason}").format(
role=role.mention, reason=reason
)
continue
removed_roles.append(role)
if wait is not None:
msg += _(
Expand Down
121 changes: 114 additions & 7 deletions roletools/messages.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import List, Optional, Set
from typing import List, Optional

import discord
from red_commons.logging import getLogger
Expand Down Expand Up @@ -82,7 +82,28 @@ async def send_message(
for button in buttons:
new_view.add_item(button)
content = text[:2000] if text else None
msg = await channel.send(content=content, view=new_view)
try:
msg = await channel.send(content=content, view=new_view)
except discord.HTTPException as e:
log.exception(
"Error sending message in channel %s in guild %s",
channel.id,
channel.guild.id,
)
await ctx.send(
_("There was an error sending to {channel}. Reason: {reason}").format(
channel=channel.mention, reason=e.text
)
)
# Right now this just displays discord's error message but could probably
# be improved to parse the error and display to the user which component
# is actually erroring. This requires accessing private attributes
# in d.py though so I will skip it for now. Namely only item._rendered_row
# contains the actual row with reference to the item we could convert to components
# but I don't think I can accurately match that back to the actual object.
# TODO: Parse discord's error with the following regex
# In (?P<key>components\.(?P<row>\d)\.components\.(?P<column>\d)\.(?P<attribute>\w+))
return
message_key = f"{msg.channel.id}-{msg.id}"

await self.save_settings(
Expand Down Expand Up @@ -172,11 +193,31 @@ async def edit_message(
new_view.add_item(select_menu)
for button in buttons:
new_view.add_item(button)
await message.edit(view=new_view)
failed_to_edit = None
try:
await message.edit(view=new_view)
except discord.HTTPException as e:
failed_to_edit = e.text
log.exception(
"Error editing message %s in channel %s in guild %s",
message.id,
message.channel.id,
message.guild.id,
)
message_key = f"{message.channel.id}-{message.id}"
await self.check_and_replace_existing(ctx.guild.id, message_key)
await self.save_settings(ctx.guild, message_key, buttons=buttons, select_menus=menus)
self.views[ctx.guild.id][message_key] = new_view
if failed_to_edit:
await ctx.send(
_(
"There was an error editing the message. "
"It's possible the emojis were deleted or there was some "
"misconfiguration with the view. You may need to rebuild things "
"from scratch with the changes. Reason: {reason}"
).format(reason=failed_to_edit)
)
return
await ctx.send(_("Message edited."))

@roletools_message.command(
Expand Down Expand Up @@ -221,7 +262,20 @@ async def send_select(
for select in menus:
new_view.add_item(select)
content = text[:2000] if text else None
msg = await channel.send(content=content, view=new_view)
try:
msg = await channel.send(content=content, view=new_view)
except discord.HTTPException as e:
log.exception(
"Error sending message in channel %s in guild %s",
channel.id,
channel.guild.id,
)
await ctx.send(
_("There was an error sending to {channel}. Reason: {reason}").format(
channel=channel.mention, reason=e.text
)
)
return
message_key = f"{msg.channel.id}-{msg.id}"

await self.save_settings(ctx.guild, message_key, buttons=[], select_menus=menus)
Expand Down Expand Up @@ -259,12 +313,32 @@ async def edit_with_select(
new_view = RoleToolsView(self)
for select_menu in menus:
new_view.add_item(select_menu)
await message.edit(view=new_view)
failed_to_edit = None
try:
await message.edit(view=new_view)
except discord.HTTPException as e:
failed_to_edit = e.text
log.exception(
"Error editing message %s in channel %s in guild %s",
message.id,
message.channel.id,
message.guild.id,
)
message_key = f"{message.channel.id}-{message.id}"
await self.check_and_replace_existing(ctx.guild.id, message_key)

await self.save_settings(ctx.guild, message_key, buttons=[], select_menus=menus)
self.views[ctx.guild.id][message_key] = new_view
if failed_to_edit:
await ctx.send(
_(
"There was an error editing the message. "
"It's possible the emojis were deleted or there was some "
"misconfiguration with the view. You may need to rebuild things "
"from scratch with the changes. Reason: {reason}"
).format(reason=failed_to_edit)
)
return
await ctx.send(_("Message edited."))

@roletools_message.command(
Expand Down Expand Up @@ -303,7 +377,20 @@ async def send_buttons(
for button in buttons:
new_view.add_item(button)
content = text[:2000] if text else None
msg = await channel.send(content=content, view=new_view)
try:
msg = await channel.send(content=content, view=new_view)
except discord.HTTPException as e:
log.exception(
"Error sending message in channel %s in guild %s",
channel.id,
channel.guild.id,
)
await ctx.send(
_("There was an error sending to {channel}. Reason: {reason}").format(
channel=channel.mention, reason=e.text
)
)
return
message_key = f"{msg.channel.id}-{msg.id}"

await self.save_settings(ctx.guild, message_key, buttons=buttons, select_menus=[])
Expand Down Expand Up @@ -337,10 +424,30 @@ async def edit_with_buttons(
new_view = RoleToolsView(self)
for button in buttons:
new_view.add_item(button)
await message.edit(view=new_view)
failed_to_edit = None
try:
await message.edit(view=new_view)
except discord.HTTPException as e:
failed_to_edit = e.text
log.exception(
"Error editing message %s in channel %s in guild %s",
message.id,
message.channel.id,
message.guild.id,
)
message_key = f"{message.channel.id}-{message.id}"
await self.check_and_replace_existing(ctx.guild.id, message_key)

await self.save_settings(ctx.guild, message_key, buttons=buttons, select_menus=[])
self.views[ctx.guild.id][message_key] = new_view
if failed_to_edit:
await ctx.send(
_(
"There was an error editing the message. "
"It's possible the emojis were deleted or there was some "
"misconfiguration with the view. You may need to rebuild things "
"from scratch with the changes. Reason: {reason}"
).format(reason=failed_to_edit)
)
return
await ctx.send(_("Message edited."))
2 changes: 1 addition & 1 deletion roletools/roletools.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class RoleTools(
"""

__author__ = ["TrustyJAID"]
__version__ = "1.5.14"
__version__ = "1.5.15"

def __init__(self, bot: Red):
self.bot = bot
Expand Down
37 changes: 26 additions & 11 deletions roletools/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from redbot.core import commands
from redbot.core.commands import Context
from redbot.core.i18n import Translator
from redbot.core.utils.chat_formatting import humanize_list
from redbot.core.utils.chat_formatting import humanize_list, pagify

from .abc import RoleToolsMixin
from .components import RoleToolsView, SelectRole, SelectRoleOption
Expand Down Expand Up @@ -144,18 +144,16 @@ async def create_select_menu(
msg = _("The name should be less than 70 characters long.")
await ctx.send(msg)
return
min_values = extras.min_values
max_values = extras.max_values
if min_values is None:
min_values = 1
if max_values is None:
max_values = len(options)
min_values = max(min(25, getattr(extras, "min_values", 1) or 1), 0)
max_values = max(
min(len(options), getattr(extras, "max_values", len(options)) or len(options)), 1
)
messages = []
custom_id = f"RTSelect-{name.lower()}-{ctx.guild.id}"
select_menu_settings = {
"options": [o.name for o in options],
"min_values": max(min(25, min_values), 0),
"max_values": max(min(25, max_values), 0),
"min_values": min_values,
"max_values": max_values,
"placeholder": extras.placeholder,
"name": name.lower(),
"messages": messages,
Expand All @@ -176,6 +174,7 @@ async def create_select_menu(
options=options,
placeholder=extras.placeholder,
)
failed_fixes = []
for message_id in select_menu_settings["messages"]:
# fix old menus with the new one when interacted with
replacement_view = self.views.get(ctx.guild.id, {}).get(message_id, None)
Expand All @@ -188,14 +187,30 @@ async def create_select_menu(
replacement_view.add_item(select_menus)
except ValueError:
log.error("Error editing old menu on Select Menu %s", custom_id)
failed_fixes.append(message_id)
continue

select_menus.update_options(ctx.guild)
view = RoleToolsView(self, timeout=180.0)
view.add_item(select_menus)

msg_str = _("Here is how your select menu will look.")
msg = await ctx.send(msg_str, view=view)
await ctx.send(msg_str, view=view)
if failed_fixes:
msg = ""
for view_id in failed_fixes:
channel_id, message_id = view_id.split("-")
channel = ctx.guild.get_channel(int(channel_id))
if channel is None:
continue
message = discord.PartialMessage(channel=channel, id=int(message_id))
msg += f"- {message.jump_url}\n"
pages = []
full_msg = _(
"The following existing select menus could not be edited with the new settings.\n{failed}"
).format(failed=msg)
for page in pagify(full_msg):
pages.append(page)
await ctx.send_interactive(pages)

@select.command(name="delete", aliases=["del", "remove"])
async def delete_select_menu(self, ctx: Context, *, name: str) -> None:
Expand Down

0 comments on commit 0813485

Please sign in to comment.