aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/cogs/help_channels.py57
1 files changed, 48 insertions, 9 deletions
diff --git a/bot/cogs/help_channels.py b/bot/cogs/help_channels.py
index ef58ca9a1..3dea3b013 100644
--- a/bot/cogs/help_channels.py
+++ b/bot/cogs/help_channels.py
@@ -478,6 +478,45 @@ class HelpChannels(Scheduler, commands.Cog):
self.schedule_task(channel.id, data)
+ async def move_to_bottom_position(self, channel: discord.TextChannel, category_id: int, **options) -> None:
+ """
+ Move the `channel` to the bottom position of `category` and edit channel attributes.
+
+ To ensure "stable sorting", we use the `bulk_channel_update` endpoint and provide the current
+ positions of the other channels in the category as-is. This should make sure that the channel
+ really ends up at the bottom of the category.
+
+ If `options` are provided, the channel will be edited after the move is completed. This is the
+ same order of operations that `discord.TextChannel.edit` uses. For information on available
+ options, see the documention on `discord.TextChannel.edit`. While possible, position-related
+ options should be avoided, as it may interfere with the category move we perform.
+ """
+ # Get a fresh copy of the category from the bot to avoid the cache mismatch issue we had.
+ category = await self.try_get_channel(category_id)
+
+ payload = [{"id": c.id, "position": c.position} for c in category.channels]
+
+ # Calculate the bottom position based on the current highest position in the category. If the
+ # category is currently empty, we simply use the current position of the channel to avoid making
+ # unnecessary changes to positions in the guild.
+ bottom_position = payload[-1]["position"] + 1 if payload else channel.position
+
+ payload.append(
+ {
+ "id": channel.id,
+ "position": bottom_position,
+ "parent_id": category.id,
+ "lock_permissions": True,
+ }
+ )
+
+ # We use d.py's method to ensure our request is processed by d.py's rate limit manager
+ await self.bot.http.bulk_channel_update(category.guild.id, payload)
+
+ # Now that the channel is moved, we can edit the other attributes
+ if options:
+ await channel.edit(**options)
+
async def move_to_available(self) -> None:
"""Make a channel available."""
log.trace("Making a channel available.")
@@ -489,10 +528,10 @@ class HelpChannels(Scheduler, commands.Cog):
log.trace(f"Moving #{channel} ({channel.id}) to the Available category.")
- await channel.edit(
+ await self.move_to_bottom_position(
+ channel=channel,
+ category_id=constants.Categories.help_available,
name=f"{AVAILABLE_EMOJI}{NAME_SEPARATOR}{self.get_clean_channel_name(channel)}",
- category=self.available_category,
- sync_permissions=True,
topic=AVAILABLE_TOPIC,
)
@@ -506,10 +545,10 @@ class HelpChannels(Scheduler, commands.Cog):
"""
log.info(f"Moving #{channel} ({channel.id}) to the Dormant category.")
- await channel.edit(
+ await self.move_to_bottom_position(
+ channel=channel,
+ category_id=constants.Categories.help_dormant,
name=self.get_clean_channel_name(channel),
- category=self.dormant_category,
- sync_permissions=True,
topic=DORMANT_TOPIC,
)
@@ -540,10 +579,10 @@ class HelpChannels(Scheduler, commands.Cog):
"""Make a channel in-use and schedule it to be made dormant."""
log.info(f"Moving #{channel} ({channel.id}) to the In Use category.")
- await channel.edit(
+ await self.move_to_bottom_position(
+ channel=channel,
+ category_id=constants.Categories.help_in_use,
name=f"{IN_USE_UNANSWERED_EMOJI}{NAME_SEPARATOR}{self.get_clean_channel_name(channel)}",
- category=self.in_use_category,
- sync_permissions=True,
topic=IN_USE_TOPIC,
)