diff options
author | 2019-12-04 14:59:18 +0100 | |
---|---|---|
committer | 2019-12-04 14:59:18 +0100 | |
commit | 00a421f193041b8fda30d2123cefb24219ec6b67 (patch) | |
tree | 7d5441e882463cabcab7601d787c22751afdce9e | |
parent | Merge pull request #305 from python-discord/exclude-draft-prs (diff) |
Add context manager to safely unlock role mentionability
Currently, our regualar roles are not mentionable by default. This
means that features that rely on roles to keep track of users that
want to receive announcements, like the AoC Day Countdown, don't
actually ping the users subscribed to it. The solution is obviously
that the bot should unlock prior to making the announcement.
However, this is complicated by the fact that there needs to be a
sufficient delay. both between unlocking and sending the message
and between sending the message and locking the role again. If not,
Discord's not done synchronizing across all servers and some users
won't receive a ping.
To make this easier, I have implemented a context manager that takes
an instance of `discord.Role` and an optional `delay` (default: 5s)
that yields a context in which the role is unlocked. This context
manager also makes sure that the role is locked even if an exception
occured within the unlocked context.
-rw-r--r-- | bot/utils/__init__.py | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/bot/utils/__init__.py b/bot/utils/__init__.py index 0aa50af6..25fd4b96 100644 --- a/bot/utils/__init__.py +++ b/bot/utils/__init__.py @@ -1,4 +1,5 @@ import asyncio +import contextlib import re import string from typing import List @@ -127,3 +128,25 @@ def replace_many( return replacement.lower() return regex.sub(_repl, sentence) + + +async def unlocked_role(role: discord.Role, delay: int = 5) -> None: + """ + Create a context in which `role` is unlocked, relocking it automatically after use. + + A configurable `delay` is added before yielding the context and directly after exiting the + context to allow the role settings change to properly propagate at Discord's end. This + prevents things like role mentions from failing because of synchronization issues. + + Usage: + >>> async with unlocked_role(role, delay=5): + ... await ctx.send(f"Hey {role.mention}, free pings for everyone!") + """ + await role.edit(mentionable=True) + await asyncio.sleep(delay) + try: + yield + finally: + await asyncio.sleep(delay) + await role.edit(mentionable=False) |