aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Sebastiaan Zeeff <[email protected]>2019-12-04 14:59:18 +0100
committerGravatar Sebastiaan Zeeff <[email protected]>2019-12-04 14:59:18 +0100
commit00a421f193041b8fda30d2123cefb24219ec6b67 (patch)
tree7d5441e882463cabcab7601d787c22751afdce9e
parentMerge 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__.py23
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)