diff options
| author | 2020-12-10 15:58:19 +0200 | |
|---|---|---|
| committer | 2020-12-10 15:58:19 +0200 | |
| commit | 97b9c7d997a0cb2afd619dd2c1878603d2db578f (patch) | |
| tree | 8b93156b96fd105c561b71dfc2dc999f4c9ff144 | |
| parent | Use Snowflake converter for snowflake command (diff) | |
| parent | Merge pull request #1322 from python-discord/swfarnsworth/developer_command (diff) | |
Merge branch 'master' into ks123/snowflake-command
| -rw-r--r-- | .github/CODEOWNERS | 13 | ||||
| -rw-r--r-- | .github/review-policy.yml | 3 | ||||
| -rw-r--r-- | bot/exts/help_channels/_cog.py | 44 | ||||
| -rw-r--r-- | bot/exts/moderation/infraction/management.py | 2 | ||||
| -rw-r--r-- | bot/exts/moderation/infraction/superstarify.py | 41 | ||||
| -rw-r--r-- | bot/exts/moderation/verification.py | 18 |
6 files changed, 78 insertions, 43 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 642676078..73e303325 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,6 +1,3 @@ -# Request Dennis for any PR -* @Den4200 - # Extensions **/bot/exts/backend/sync/** @MarkKoz **/bot/exts/filters/*token_remover.py @MarkKoz @@ -9,8 +6,8 @@ bot/exts/info/codeblock/** @MarkKoz bot/exts/utils/extensions.py @MarkKoz bot/exts/utils/snekbox.py @MarkKoz @Akarys42 bot/exts/help_channels/** @MarkKoz @Akarys42 -bot/exts/moderation/** @Akarys42 @mbaruh -bot/exts/info/** @Akarys42 @mbaruh +bot/exts/moderation/** @Akarys42 @mbaruh @Den4200 +bot/exts/info/** @Akarys42 @mbaruh @Den4200 bot/exts/filters/** @mbaruh # Utils @@ -26,9 +23,9 @@ tests/bot/exts/test_cogs.py @MarkKoz tests/** @Akarys42 # CI & Docker -.github/workflows/** @MarkKoz @Akarys42 @SebastiaanZ -Dockerfile @MarkKoz @Akarys42 -docker-compose.yml @MarkKoz @Akarys42 +.github/workflows/** @MarkKoz @Akarys42 @SebastiaanZ @Den4200 +Dockerfile @MarkKoz @Akarys42 @Den4200 +docker-compose.yml @MarkKoz @Akarys42 @Den4200 # Tools Pipfile* @Akarys42 diff --git a/.github/review-policy.yml b/.github/review-policy.yml new file mode 100644 index 000000000..421b30f8a --- /dev/null +++ b/.github/review-policy.yml @@ -0,0 +1,3 @@ +remote: python-discord/.github +path: review-policies/core-developers.yml +ref: main diff --git a/bot/exts/help_channels/_cog.py b/bot/exts/help_channels/_cog.py index e22d4663e..983c5d183 100644 --- a/bot/exts/help_channels/_cog.py +++ b/bot/exts/help_channels/_cog.py @@ -145,22 +145,17 @@ class HelpChannels(commands.Cog): Make the current in-use help channel dormant. Make the channel dormant if the user passes the `dormant_check`, - delete the message that invoked this, - and reset the send permissions cooldown for the user who started the session. + delete the message that invoked this. """ log.trace("close command invoked; checking if the channel is in-use.") - if ctx.channel.category == self.in_use_category: - if await self.dormant_check(ctx): - await _cooldown.remove_cooldown_role(ctx.author) - # Ignore missing task when cooldown has passed but the channel still isn't dormant. - if ctx.author.id in self.scheduler: - self.scheduler.cancel(ctx.author.id) - - await self.move_to_dormant(ctx.channel, "command") - self.scheduler.cancel(ctx.channel.id) - else: + if ctx.channel.category != self.in_use_category: log.debug(f"{ctx.author} invoked command 'dormant' outside an in-use help channel") + return + + if await self.dormant_check(ctx): + await self.move_to_dormant(ctx.channel, "command") + self.scheduler.cancel(ctx.channel.id) async def get_available_candidate(self) -> discord.TextChannel: """ @@ -368,12 +363,13 @@ class HelpChannels(commands.Cog): """ log.info(f"Moving #{channel} ({channel.id}) to the Dormant category.") - await _caches.claimants.delete(channel.id) await self.move_to_bottom_position( channel=channel, category_id=constants.Categories.help_dormant, ) + await self.unclaim_channel(channel) + self.bot.stats.incr(f"help.dormant_calls.{caller}") in_use_time = await _channel.get_in_use_time(channel.id) @@ -397,6 +393,28 @@ class HelpChannels(commands.Cog): self.channel_queue.put_nowait(channel) self.report_stats() + async def unclaim_channel(self, channel: discord.TextChannel) -> None: + """ + Mark the channel as unclaimed and remove the cooldown role from the claimant if needed. + + The role is only removed if they have no claimed channels left once the current one is unclaimed. + This method also handles canceling the automatic removal of the cooldown role. + """ + claimant_id = await _caches.claimants.pop(channel.id) + + # Ignore missing task when cooldown has passed but the channel still isn't dormant. + if claimant_id in self.scheduler: + self.scheduler.cancel(claimant_id) + + claimant = self.bot.get_guild(constants.Guild.id).get_member(claimant_id) + if claimant is None: + log.info(f"{claimant_id} left the guild during their help session; the cooldown role won't be removed") + return + + # Remove the cooldown role if the claimant has no other channels left + if not any(claimant.id == user_id for _, user_id in await _caches.claimants.items()): + await _cooldown.remove_cooldown_role(claimant) + async def move_to_in_use(self, channel: discord.TextChannel) -> None: """Make a channel in-use and schedule it to be made dormant.""" log.info(f"Moving #{channel} ({channel.id}) to the In Use category.") diff --git a/bot/exts/moderation/infraction/management.py b/bot/exts/moderation/infraction/management.py index c58410f8c..b3783cd60 100644 --- a/bot/exts/moderation/infraction/management.py +++ b/bot/exts/moderation/infraction/management.py @@ -197,7 +197,7 @@ class ModManagement(commands.Cog): # endregion # region: Search infractions - @infraction_group.group(name="search", invoke_without_command=True) + @infraction_group.group(name="search", aliases=('s',), invoke_without_command=True) async def infraction_search_group(self, ctx: Context, query: t.Union[UserMention, Snowflake, str]) -> None: """Searches for infractions in the database.""" if isinstance(query, int): diff --git a/bot/exts/moderation/infraction/superstarify.py b/bot/exts/moderation/infraction/superstarify.py index 96dfb562f..ffc470c54 100644 --- a/bot/exts/moderation/infraction/superstarify.py +++ b/bot/exts/moderation/infraction/superstarify.py @@ -104,14 +104,14 @@ class Superstarify(InfractionScheduler, Cog): await self.reapply_infraction(infraction, action) - @command(name="superstarify", aliases=("force_nick", "star")) + @command(name="superstarify", aliases=("force_nick", "star", "starify")) async def superstarify( self, ctx: Context, member: Member, duration: Expiry, *, - reason: str = None, + reason: str = '', ) -> None: """ Temporarily force a random superstar name (like Taylor Swift) to be the user's nickname. @@ -128,16 +128,16 @@ class Superstarify(InfractionScheduler, Cog): Alternatively, an ISO 8601 timestamp can be provided for the duration. - An optional reason can be provided. If no reason is given, the original name will be shown - in a generated reason. + An optional reason can be provided, which would be added to a message stating their old nickname + and linking to the nickname policy. """ if await _utils.get_active_infraction(ctx, member, "superstar"): return # Post the infraction to the API old_nick = member.display_name - reason = reason or f"old nick: {old_nick}" - infraction = await _utils.post_infraction(ctx, member, "superstar", reason, duration, active=True) + infraction_reason = f'Old nickname: {old_nick}. {reason}' + infraction = await _utils.post_infraction(ctx, member, "superstar", infraction_reason, duration, active=True) id_ = infraction["id"] forced_nick = self.get_nick(id_, member.id) @@ -152,37 +152,38 @@ class Superstarify(InfractionScheduler, Cog): old_nick = escape_markdown(old_nick) forced_nick = escape_markdown(forced_nick) - superstar_reason = f"Your nickname didn't comply with our [nickname policy]({NICKNAME_POLICY_URL})." nickname_info = textwrap.dedent(f""" Old nickname: `{old_nick}` New nickname: `{forced_nick}` """).strip() + user_message = ( + f"Your previous nickname, **{old_nick}**, " + f"was so bad that we have decided to change it. " + f"Your new nickname will be **{forced_nick}**.\n\n" + "{reason}" + f"You will be unable to change your nickname until **{expiry_str}**. " + "If you're confused by this, please read our " + f"[official nickname policy]({NICKNAME_POLICY_URL})." + ).format + successful = await self.apply_infraction( ctx, infraction, member, action(), - user_reason=superstar_reason, + user_reason=user_message(reason=f'**Additional details:** {reason}\n\n' if reason else ''), additional_info=nickname_info ) - # Send an embed with the infraction information to the invoking context if - # superstar was successful. + # Send an embed with to the invoking context if superstar was successful. if successful: log.trace(f"Sending superstar #{id_} embed.") embed = Embed( - title="Congratulations!", + title="Superstarified!", colour=constants.Colours.soft_orange, - description=( - f"Your previous nickname, **{old_nick}**, " - f"was so bad that we have decided to change it. " - f"Your new nickname will be **{forced_nick}**.\n\n" - f"You will be unable to change your nickname until **{expiry_str}**.\n\n" - "If you're confused by this, please read our " - f"[official nickname policy]({NICKNAME_POLICY_URL})." - ) + description=user_message(reason='') ) await ctx.send(embed=embed) - @command(name="unsuperstarify", aliases=("release_nick", "unstar")) + @command(name="unsuperstarify", aliases=("release_nick", "unstar", "unstarify")) async def unsuperstarify(self, ctx: Context, member: Member) -> None: """Remove the superstarify infraction and allow the user to change their nickname.""" await self.pardon_infraction(ctx, "superstar", member) diff --git a/bot/exts/moderation/verification.py b/bot/exts/moderation/verification.py index c599156d0..c42c6588f 100644 --- a/bot/exts/moderation/verification.py +++ b/bot/exts/moderation/verification.py @@ -756,7 +756,7 @@ class Verification(Cog): log.trace(f"Bumping verification stats in category: {category}") self.bot.stats.incr(f"verification.{category}") - @command(name='accept', aliases=('verify', 'verified', 'accepted'), hidden=True) + @command(name='accept', aliases=('verified', 'accepted'), hidden=True) @has_no_roles(constants.Roles.verified) @in_whitelist(channels=(constants.Channels.verification,)) async def accept_command(self, ctx: Context, *_) -> None: # We don't actually care about the args @@ -848,6 +848,22 @@ class Verification(Cog): else: return True + @command(name='verify') + @has_any_role(*constants.MODERATION_ROLES) + async def apply_developer_role(self, ctx: Context, user: discord.Member) -> None: + """Command for moderators to apply the Developer role to any user.""" + log.trace(f'verify command called by {ctx.author} for {user.id}.') + developer_role = self.bot.get_guild(constants.Guild.id).get_role(constants.Roles.verified) + + if developer_role in user.roles: + log.trace(f'{user.id} is already a developer, aborting.') + await ctx.send(f'{constants.Emojis.cross_mark} {user} is already a developer.') + return + + await user.add_roles(developer_role) + log.trace(f'Developer role successfully applied to {user.id}') + await ctx.send(f'{constants.Emojis.check_mark} Developer role applied to {user}.') + # endregion |