aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Hassan Abouelela <[email protected]>2022-05-07 18:20:59 +0400
committerGravatar GitHub <[email protected]>2022-05-07 18:20:59 +0400
commit6cf922b00115f452fff57aa0820e606f9a02d1b4 (patch)
tree81b629f1387b007daacff2eeaad253666da02315
parentRemove Explicit Support For Standalone Banners (diff)
parentAdded Messages Content to the `!intents` tag (#2159) (diff)
Merge branch 'main' into multiple-banners
-rw-r--r--bot/exts/backend/sync/_cog.py26
-rw-r--r--bot/exts/info/doc/_cog.py2
-rw-r--r--bot/exts/moderation/modpings.py16
-rw-r--r--bot/exts/utils/thread_bumper.py41
-rw-r--r--bot/resources/tags/intents.md2
-rw-r--r--bot/resources/tags/or-gotcha.md1
6 files changed, 62 insertions, 26 deletions
diff --git a/bot/exts/backend/sync/_cog.py b/bot/exts/backend/sync/_cog.py
index 85266340b..433ff5024 100644
--- a/bot/exts/backend/sync/_cog.py
+++ b/bot/exts/backend/sync/_cog.py
@@ -1,11 +1,10 @@
import asyncio
-import datetime
from typing import Any, Dict
from botcore.site_api import ResponseCodeError
from discord import Member, Role, User
from discord.ext import commands
-from discord.ext.commands import Cog, Context, errors
+from discord.ext.commands import Cog, Context
from bot import constants
from bot.bot import Bot
@@ -13,6 +12,7 @@ from bot.exts.backend.sync import _syncers
from bot.log import get_logger
log = get_logger(__name__)
+MAX_ATTEMPTS = 3
class Sync(Cog):
@@ -29,16 +29,20 @@ class Sync(Cog):
if guild is None:
return
- log.info("Waiting for guild to be chunked to start syncers.")
- end = datetime.datetime.now() + datetime.timedelta(minutes=30)
- while not guild.chunked:
+ attempts = 0
+ while True:
+ attempts += 1
+ if guild.chunked:
+ log.info("Guild was found to be chunked after %d attempt(s).", attempts)
+ break
+
+ if attempts == MAX_ATTEMPTS:
+ log.info("Guild not chunked after %d attempts, calling chunk manually.", MAX_ATTEMPTS)
+ await guild.chunk()
+ break
+
+ log.info("Attempt %d/%d: Guild not yet chunked, checking again in 10s.", attempts, MAX_ATTEMPTS)
await asyncio.sleep(10)
- if datetime.datetime.now() > end:
- # More than 30 minutes have passed while trying, abort
- raise errors.ExtensionFailed(
- self.__class__.__name__,
- RuntimeError("The guild was not chunked in time, not loading sync cog.")
- )
log.info("Starting syncers.")
for syncer in (_syncers.RoleSyncer, _syncers.UserSyncer):
diff --git a/bot/exts/info/doc/_cog.py b/bot/exts/info/doc/_cog.py
index 079bfc942..dece44063 100644
--- a/bot/exts/info/doc/_cog.py
+++ b/bot/exts/info/doc/_cog.py
@@ -431,7 +431,7 @@ class DocCog(commands.Cog):
async def refresh_command(self, ctx: commands.Context) -> None:
"""Refresh inventories and show the difference."""
old_inventories = set(self.base_urls)
- with ctx.typing():
+ async with ctx.typing():
await self.refresh_inventories()
new_inventories = set(self.base_urls)
diff --git a/bot/exts/moderation/modpings.py b/bot/exts/moderation/modpings.py
index e82099c88..bdefea91b 100644
--- a/bot/exts/moderation/modpings.py
+++ b/bot/exts/moderation/modpings.py
@@ -13,6 +13,7 @@ from bot.constants import Colours, Emojis, Guild, Icons, MODERATION_ROLES, Roles
from bot.converters import Expiry
from bot.log import get_logger
from bot.utils import time
+from bot.utils.members import get_or_fetch_member
log = get_logger(__name__)
@@ -57,18 +58,29 @@ class ModPings(Cog):
log.trace("Applying the moderators role to the mod team where necessary.")
for mod in mod_team.members:
- if mod in pings_on: # Make sure that on-duty mods aren't in the cache.
+ if mod in pings_on: # Make sure that on-duty mods aren't in the redis cache.
if mod.id in pings_off:
await self.pings_off_mods.delete(mod.id)
continue
- # Keep the role off only for those in the cache.
+ # Keep the role off only for those in the redis cache.
if mod.id not in pings_off:
await self.reapply_role(mod)
else:
expiry = isoparse(pings_off[mod.id])
self._role_scheduler.schedule_at(expiry, mod.id, self.reapply_role(mod))
+ # At this stage every entry in `pings_off` is expected to have a scheduled task, but that might not be the case
+ # if the discord.py cache is missing members, or if the ID belongs to a former moderator.
+ for mod_id, expiry_iso in pings_off.items():
+ if mod_id not in self._role_scheduler:
+ mod = await get_or_fetch_member(self.guild, mod_id)
+ # Make sure the member is still a moderator and doesn't have the pingable role.
+ if mod is None or mod.get_role(Roles.mod_team) is None or mod.get_role(Roles.moderators) is not None:
+ await self.pings_off_mods.delete(mod_id)
+ else:
+ self._role_scheduler.schedule_at(isoparse(expiry_iso), mod_id, self.reapply_role(mod))
+
async def reschedule_modpings_schedule(self) -> None:
"""Reschedule moderators schedule ping."""
await self.bot.wait_until_guild_available()
diff --git a/bot/exts/utils/thread_bumper.py b/bot/exts/utils/thread_bumper.py
index ee0636b37..743919d4e 100644
--- a/bot/exts/utils/thread_bumper.py
+++ b/bot/exts/utils/thread_bumper.py
@@ -2,6 +2,7 @@ import typing as t
import discord
from async_rediscache import RedisCache
+from botcore.site_api import ResponseCodeError
from discord.ext import commands
from bot import constants
@@ -11,6 +12,7 @@ from bot.pagination import LinePaginator
from bot.utils import channel
log = get_logger(__name__)
+THREAD_BUMP_ENDPOINT = "bot/bumped-threads"
class ThreadBumper(commands.Cog):
@@ -45,7 +47,7 @@ class ThreadBumper(commands.Cog):
thread.name,
thread.id
)
- await self.threads_to_bump.delete(thread.id)
+ await self.bot.api_client.delete(f"{THREAD_BUMP_ENDPOINT}/{thread.id}")
else:
await thread.edit(archived=False)
@@ -54,18 +56,23 @@ class ThreadBumper(commands.Cog):
await self.bot.wait_until_guild_available()
threads_to_maybe_bump = []
- for thread_id, _ in await self.threads_to_bump.items():
+ for thread_id in await self.bot.api_client.get(THREAD_BUMP_ENDPOINT):
try:
thread = await channel.get_or_fetch_channel(thread_id)
except discord.NotFound:
log.info("Thread %d has been deleted, removing from bumped threads.", thread_id)
- await self.threads_to_bump.delete(thread_id)
+ await self.bot.api_client.delete(f"{THREAD_BUMP_ENDPOINT}/{thread_id}")
+ continue
+
+ if not isinstance(thread, discord.Thread):
+ await self.bot.api_client.delete(f"{THREAD_BUMP_ENDPOINT}/{thread_id}")
continue
if thread.archived:
threads_to_maybe_bump.append(thread)
- await self.unarchive_threads_not_manually_archived(threads_to_maybe_bump)
+ if threads_to_maybe_bump:
+ await self.unarchive_threads_not_manually_archived(threads_to_maybe_bump)
@commands.group(name="bump")
async def thread_bump_group(self, ctx: commands.Context) -> None:
@@ -82,10 +89,15 @@ class ThreadBumper(commands.Cog):
else:
raise commands.BadArgument("You must provide a thread, or run this command within a thread.")
- if await self.threads_to_bump.contains(thread.id):
+ try:
+ await self.bot.api_client.get(f"{THREAD_BUMP_ENDPOINT}/{thread.id}")
+ except ResponseCodeError as e:
+ if e.status != 404:
+ raise
+ else:
raise commands.BadArgument("This thread is already in the bump list.")
- await self.threads_to_bump.set(thread.id, "sentinel")
+ await self.bot.api_client.post(THREAD_BUMP_ENDPOINT, data={"thread_id": thread.id})
await ctx.send(f":ok_hand:{thread.mention} has been added to the bump list.")
@thread_bump_group.command(name="remove", aliases=("r", "rem", "d", "del", "delete"))
@@ -97,21 +109,23 @@ class ThreadBumper(commands.Cog):
else:
raise commands.BadArgument("You must provide a thread, or run this command within a thread.")
- if not await self.threads_to_bump.contains(thread.id):
+ try:
+ await self.bot.api_client.get(f"{THREAD_BUMP_ENDPOINT}/{thread.id}")
+ except ResponseCodeError:
raise commands.BadArgument("This thread is not in the bump list.")
- await self.threads_to_bump.delete(thread.id)
+ await self.bot.api_client.delete(f"{THREAD_BUMP_ENDPOINT}/{thread.id}")
await ctx.send(f":ok_hand: {thread.mention} has been removed from the bump list.")
@thread_bump_group.command(name="list", aliases=("get",))
async def list_all_threads_in_bump_list(self, ctx: commands.Context) -> None:
"""List all the threads in the bump list."""
- lines = [f"<#{k}>" for k, _ in await self.threads_to_bump.items()]
+ lines = [f"<#{thread_id}>" for thread_id in await self.bot.api_client.get(THREAD_BUMP_ENDPOINT)]
embed = discord.Embed(
title="Threads in the bump list",
colour=constants.Colours.blue
)
- await LinePaginator.paginate(lines, ctx, embed)
+ await LinePaginator.paginate(lines, ctx, embed, max_lines=10)
@commands.Cog.listener()
async def on_thread_update(self, _: discord.Thread, after: discord.Thread) -> None:
@@ -123,7 +137,12 @@ class ThreadBumper(commands.Cog):
if not after.archived:
return
- if await self.threads_to_bump.contains(after.id):
+ try:
+ await self.bot.api_client.get(f"{THREAD_BUMP_ENDPOINT}/{after.id}")
+ except ResponseCodeError as e:
+ if e.status != 404:
+ raise
+ else:
await self.unarchive_threads_not_manually_archived([after])
async def cog_check(self, ctx: commands.Context) -> bool:
diff --git a/bot/resources/tags/intents.md b/bot/resources/tags/intents.md
index 464caf0ba..aa49d59ae 100644
--- a/bot/resources/tags/intents.md
+++ b/bot/resources/tags/intents.md
@@ -1,6 +1,6 @@
**Using intents in discord.py**
-Intents are a feature of Discord that tells the gateway exactly which events to send your bot. By default, discord.py has all intents enabled, except for the `Members` and `Presences` intents, which are needed for events such as `on_member` and to get members' statuses.
+Intents are a feature of Discord that tells the gateway exactly which events to send your bot. By default discord.py has all intents enabled except for `Members`, `Message Content`, and `Presences`. These are needed for features such as `on_member` events, to get access to message content, and to get members' statuses.
To enable one of these intents, you need to first go to the [Discord developer portal](https://discord.com/developers/applications), then to the bot page of your bot's application. Scroll down to the `Privileged Gateway Intents` section, then enable the intents that you need.
diff --git a/bot/resources/tags/or-gotcha.md b/bot/resources/tags/or-gotcha.md
index d75a73d78..25ade8620 100644
--- a/bot/resources/tags/or-gotcha.md
+++ b/bot/resources/tags/or-gotcha.md
@@ -1,5 +1,6 @@
When checking if something is equal to one thing or another, you might think that this is possible:
```py
+# Incorrect...
if favorite_fruit == 'grapefruit' or 'lemon':
print("That's a weird favorite fruit to have.")
```