From edb18d5f5be3d1dfcfdcfa72bcbf0915e321b895 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Mon, 1 Nov 2021 17:16:05 +0000 Subject: Add thread archive time enum to constants --- bot/constants.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bot/constants.py b/bot/constants.py index 36b917734..93da6a906 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -683,10 +683,22 @@ class VideoPermission(metaclass=YAMLGetter): default_permission_duration: int +class ThreadArchiveTimes(Enum): + HOUR = 60 + DAY = 1440 + THREE_DAY = 4230 + WEEK = 10080 + + # Debug mode DEBUG_MODE: bool = _CONFIG_YAML["debug"] == "true" FILE_LOGS: bool = _CONFIG_YAML["file_logs"].lower() == "true" +if DEBUG_MODE: + DEFAULT_THREAD_ARCHIVE_TIME = ThreadArchiveTimes.HOUR.value +else: + DEFAULT_THREAD_ARCHIVE_TIME = ThreadArchiveTimes.WEEK.value + # Paths BOT_DIR = os.path.dirname(__file__) PROJECT_ROOT = os.path.abspath(os.path.join(BOT_DIR, os.pardir)) -- cgit v1.2.3 From 292a500d9ebb51b8efc023baf39b76d98d05cae0 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Mon, 1 Nov 2021 17:19:36 +0000 Subject: Refactor make_review to return nominee too --- bot/exts/recruitment/talentpool/_cog.py | 2 +- bot/exts/recruitment/talentpool/_review.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bot/exts/recruitment/talentpool/_cog.py b/bot/exts/recruitment/talentpool/_cog.py index 2fafaec97..699d60f42 100644 --- a/bot/exts/recruitment/talentpool/_cog.py +++ b/bot/exts/recruitment/talentpool/_cog.py @@ -483,7 +483,7 @@ class TalentPool(Cog, name="Talentpool"): @has_any_role(*MODERATION_ROLES) async def get_review(self, ctx: Context, user_id: int) -> None: """Get the user's review as a markdown file.""" - review = (await self.reviewer.make_review(user_id))[0] + review, _, _ = await self.reviewer.make_review(user_id) if review: file = discord.File(StringIO(review), f"{user_id}_review.md") await ctx.send(file=file) diff --git a/bot/exts/recruitment/talentpool/_review.py b/bot/exts/recruitment/talentpool/_review.py index d880c524c..6b5fae3b1 100644 --- a/bot/exts/recruitment/talentpool/_review.py +++ b/bot/exts/recruitment/talentpool/_review.py @@ -78,14 +78,14 @@ class Reviewer: async def post_review(self, user_id: int, update_database: bool) -> None: """Format the review of a user and post it to the nomination voting channel.""" - review, reviewed_emoji = await self.make_review(user_id) + review, reviewed_emoji, nominee = await self.make_review(user_id) if not review: return guild = self.bot.get_guild(Guild.id) channel = guild.get_channel(Channels.nomination_voting) - log.trace(f"Posting the review of {user_id}") + log.trace(f"Posting the review of {nominee} ({nominee.id})") messages = await self._bulk_send(channel, review) await pin_no_system_message(messages[0]) @@ -113,14 +113,14 @@ class Reviewer: return "", None guild = self.bot.get_guild(Guild.id) - member = await get_or_fetch_member(guild, user_id) + nominee = await get_or_fetch_member(guild, user_id) - if not member: + if not nominee: return ( f"I tried to review the user with ID `{user_id}`, but they don't appear to be on the server :pensive:" - ), None + ), None, None - opening = f"{member.mention} ({member}) for Helper!" + opening = f"{nominee.mention} ({nominee}) for Helper!" current_nominations = "\n\n".join( f"**<@{entry['actor']}>:** {entry['reason'] or '*no reason given*'}" @@ -128,7 +128,7 @@ class Reviewer: ) current_nominations = f"**Nominated by:**\n{current_nominations}" - review_body = await self._construct_review_body(member) + review_body = await self._construct_review_body(nominee) reviewed_emoji = self._random_ducky(guild) vote_request = ( @@ -138,7 +138,7 @@ class Reviewer: ) review = "\n\n".join((opening, current_nominations, review_body, vote_request)) - return review, reviewed_emoji + return review, reviewed_emoji, nominee async def archive_vote(self, message: PartialMessage, passed: bool) -> None: """Archive this vote to #nomination-archive.""" -- cgit v1.2.3 From c217c3ef658954f2d491529a2a5c2085a285c229 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Mon, 1 Nov 2021 17:20:42 +0000 Subject: Manage nomination threads This change creates a thread while posting the nomination, and then archives it once the nomination is concluded. --- bot/exts/recruitment/talentpool/_review.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/bot/exts/recruitment/talentpool/_review.py b/bot/exts/recruitment/talentpool/_review.py index 6b5fae3b1..bc5cccda1 100644 --- a/bot/exts/recruitment/talentpool/_review.py +++ b/bot/exts/recruitment/talentpool/_review.py @@ -15,7 +15,7 @@ from discord.ext.commands import Context from bot.api import ResponseCodeError from bot.bot import Bot -from bot.constants import Channels, Colours, Emojis, Guild +from bot.constants import Channels, Colours, DEFAULT_THREAD_ARCHIVE_TIME, Emojis, Guild, Roles from bot.log import get_logger from bot.utils.members import get_or_fetch_member from bot.utils.messages import count_unique_users_reaction, pin_no_system_message @@ -95,6 +95,12 @@ class Reviewer: for reaction in (reviewed_emoji, "\N{THUMBS UP SIGN}", "\N{THUMBS DOWN SIGN}"): await last_message.add_reaction(reaction) + thread = await last_message.create_thread( + name=f"Nomination - {nominee}", + auto_archive_duration=DEFAULT_THREAD_ARCHIVE_TIME + ) + await thread.send(fr"<@&{Roles.mod_team}> <@&{Roles.admins}>") + if update_database: nomination = self._pool.cache.get(user_id) await self.bot.api_client.patch(f"bot/nominations/{nomination['id']}", json={"reviewed": True}) @@ -210,6 +216,13 @@ class Reviewer: colour=colour )) + # Thread channel IDs are the same as the message ID of the parent message. + nomination_thread = message.guild.get_thread(message.id) + if not nomination_thread: + log.warning(f"Could not find a thread linked to {message.channel.id}-{message.id}") + return + await nomination_thread.edit(archived=True) + for message_ in messages: await message_.delete() -- cgit v1.2.3 From 6bd2a56d43d70476d18c5fd66da20d8cf1518373 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Mon, 1 Nov 2021 18:52:03 +0000 Subject: Update nomination message regex --- bot/exts/recruitment/talentpool/_review.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bot/exts/recruitment/talentpool/_review.py b/bot/exts/recruitment/talentpool/_review.py index bc5cccda1..8b61a0eb5 100644 --- a/bot/exts/recruitment/talentpool/_review.py +++ b/bot/exts/recruitment/talentpool/_review.py @@ -36,9 +36,8 @@ MAX_MESSAGE_SIZE = 2000 MAX_EMBED_SIZE = 4000 # Regex for finding the first message of a nomination, and extracting the nominee. -# Historic nominations will have 2 role mentions at the start, new ones won't, optionally match for this. NOMINATION_MESSAGE_REGEX = re.compile( - r"(?:<@&\d+> <@&\d+>\n)*?<@!?(\d+?)> \(.+#\d{4}\) for Helper!\n\n\*\*Nominated by:\*\*", + r"<@!?(\d+)> \(.+#\d{4}\) for Helper!\n\n", re.MULTILINE ) -- cgit v1.2.3 From 0a4ba0b5d6341bc8cef13a30e35af5b4dc24248b Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Thu, 4 Nov 2021 15:50:14 +0000 Subject: Supress NotFound when archiving a nomination This supresses both the mesage deleteions and the thread archive, so that if they are removed before the code can get to them, it does not raise an error. --- bot/exts/recruitment/talentpool/_review.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bot/exts/recruitment/talentpool/_review.py b/bot/exts/recruitment/talentpool/_review.py index 8b61a0eb5..fab126408 100644 --- a/bot/exts/recruitment/talentpool/_review.py +++ b/bot/exts/recruitment/talentpool/_review.py @@ -10,7 +10,7 @@ from typing import List, Optional, Union import arrow from dateutil.parser import isoparse -from discord import Embed, Emoji, Member, Message, NoMoreItems, PartialMessage, TextChannel +from discord import Embed, Emoji, Member, Message, NoMoreItems, NotFound, PartialMessage, TextChannel from discord.ext.commands import Context from bot.api import ResponseCodeError @@ -220,10 +220,13 @@ class Reviewer: if not nomination_thread: log.warning(f"Could not find a thread linked to {message.channel.id}-{message.id}") return - await nomination_thread.edit(archived=True) for message_ in messages: - await message_.delete() + with contextlib.suppress(NotFound): + await message_.delete() + + with contextlib.suppress(NotFound): + await nomination_thread.edit(archived=True) async def _construct_review_body(self, member: Member) -> str: """Formats the body of the nomination, with details of activity, infractions, and previous nominations.""" -- cgit v1.2.3 From e62ff5b4d0cd811e40d54e94ae5ae6d48f934624 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Wed, 1 Dec 2021 00:19:42 +0000 Subject: Ensure a nomination archival emoji isn't from the bot This is most relevant in local dev testing where the Emojis.check_mark could be the same as the Emojis.incident_actioned or Emojis.incident_unactioned, which would cause the bot to attempt to archive the post_review invocation if it was posted in the nomination voting channel. --- bot/exts/recruitment/talentpool/_cog.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bot/exts/recruitment/talentpool/_cog.py b/bot/exts/recruitment/talentpool/_cog.py index 699d60f42..615a95d20 100644 --- a/bot/exts/recruitment/talentpool/_cog.py +++ b/bot/exts/recruitment/talentpool/_cog.py @@ -516,6 +516,9 @@ class TalentPool(Cog, name="Talentpool"): if payload.channel_id != Channels.nomination_voting: return + if payload.user_id == self.bot.user.id: + return + message: PartialMessage = self.bot.get_channel(payload.channel_id).get_partial_message(payload.message_id) emoji = str(payload.emoji) -- cgit v1.2.3 From 96911a9c9b6e833e68fb2ead081d12da4ca5ffd9 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Wed, 1 Dec 2021 00:54:31 +0000 Subject: Fix emoji reaction error in reviewer Using a :eyes: style emoji string in a ctx.add_reaciton call will error. Discord expects either a unicode emoji, or a custom emoji. --- bot/exts/recruitment/talentpool/_review.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/exts/recruitment/talentpool/_review.py b/bot/exts/recruitment/talentpool/_review.py index fab126408..eced33738 100644 --- a/bot/exts/recruitment/talentpool/_review.py +++ b/bot/exts/recruitment/talentpool/_review.py @@ -375,10 +375,10 @@ class Reviewer: @staticmethod def _random_ducky(guild: Guild) -> Union[Emoji, str]: - """Picks a random ducky emoji. If no duckies found returns :eyes:.""" + """Picks a random ducky emoji. If no duckies found returns 👀.""" duckies = [emoji for emoji in guild.emojis if emoji.name.startswith("ducky")] if not duckies: - return ":eyes:" + return "\N{EYES}" return random.choice(duckies) @staticmethod -- cgit v1.2.3 From 108bf3276b49de4e6153a2c7f96c731907e3ca37 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Wed, 1 Dec 2021 01:04:14 +0000 Subject: Always return a review string for a given nomination --- bot/exts/recruitment/talentpool/_cog.py | 7 ++----- bot/exts/recruitment/talentpool/_review.py | 6 +++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/bot/exts/recruitment/talentpool/_cog.py b/bot/exts/recruitment/talentpool/_cog.py index 615a95d20..ce0b2862f 100644 --- a/bot/exts/recruitment/talentpool/_cog.py +++ b/bot/exts/recruitment/talentpool/_cog.py @@ -484,11 +484,8 @@ class TalentPool(Cog, name="Talentpool"): async def get_review(self, ctx: Context, user_id: int) -> None: """Get the user's review as a markdown file.""" review, _, _ = await self.reviewer.make_review(user_id) - if review: - file = discord.File(StringIO(review), f"{user_id}_review.md") - await ctx.send(file=file) - else: - await ctx.send(f"There doesn't appear to be an active nomination for {user_id}") + file = discord.File(StringIO(review), f"{user_id}_review.md") + await ctx.send(file=file) @nomination_group.command(aliases=('review',)) @has_any_role(*MODERATION_ROLES) diff --git a/bot/exts/recruitment/talentpool/_review.py b/bot/exts/recruitment/talentpool/_review.py index eced33738..a68169351 100644 --- a/bot/exts/recruitment/talentpool/_review.py +++ b/bot/exts/recruitment/talentpool/_review.py @@ -104,8 +104,8 @@ class Reviewer: nomination = self._pool.cache.get(user_id) await self.bot.api_client.patch(f"bot/nominations/{nomination['id']}", json={"reviewed": True}) - async def make_review(self, user_id: int) -> typing.Tuple[str, Optional[Emoji]]: - """Format a generic review of a user and return it with the reviewed emoji.""" + async def make_review(self, user_id: int) -> typing.Tuple[str, Optional[Emoji], Optional[Member]]: + """Format a generic review of a user and return it with the reviewed emoji and the user themselves.""" log.trace(f"Formatting the review of {user_id}") # Since `cache` is a defaultdict, we should take care @@ -115,7 +115,7 @@ class Reviewer: nomination = self._pool.cache.get(user_id) if not nomination: log.trace(f"There doesn't appear to be an active nomination for {user_id}") - return "", None + return f"There doesn't appear to be an active nomination for {user_id}", None, None guild = self.bot.get_guild(Guild.id) nominee = await get_or_fetch_member(guild, user_id) -- cgit v1.2.3 From 8c89ef922c5445f93e26e69ea4a65e5a2ceaf79e Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Wed, 1 Dec 2021 01:05:17 +0000 Subject: Use presence of a nominee as check for pending reviews --- bot/exts/recruitment/talentpool/_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/recruitment/talentpool/_review.py b/bot/exts/recruitment/talentpool/_review.py index a68169351..110ac47bc 100644 --- a/bot/exts/recruitment/talentpool/_review.py +++ b/bot/exts/recruitment/talentpool/_review.py @@ -78,7 +78,7 @@ class Reviewer: async def post_review(self, user_id: int, update_database: bool) -> None: """Format the review of a user and post it to the nomination voting channel.""" review, reviewed_emoji, nominee = await self.make_review(user_id) - if not review: + if not nominee: return guild = self.bot.get_guild(Guild.id) -- cgit v1.2.3 From 6af87373ee3b97509d67ab611780c7e7892f4545 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Wed, 1 Dec 2021 01:05:36 +0000 Subject: Remove redundant Union in a type hint --- bot/exts/recruitment/talentpool/_cog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/recruitment/talentpool/_cog.py b/bot/exts/recruitment/talentpool/_cog.py index ce0b2862f..8fa0be5b1 100644 --- a/bot/exts/recruitment/talentpool/_cog.py +++ b/bot/exts/recruitment/talentpool/_cog.py @@ -498,7 +498,7 @@ class TalentPool(Cog, name="Talentpool"): await ctx.message.add_reaction(Emojis.check_mark) @Cog.listener() - async def on_member_ban(self, guild: Guild, user: Union[MemberOrUser]) -> None: + async def on_member_ban(self, guild: Guild, user: MemberOrUser) -> None: """Remove `user` from the talent pool after they are banned.""" await self.end_nomination(user.id, "User was banned.") -- cgit v1.2.3