diff options
| -rw-r--r-- | bot/cogs/help_channels.py | 57 |
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, ) |