diff options
Diffstat (limited to '')
| -rw-r--r-- | bot/converters.py | 85 | ||||
| -rw-r--r-- | bot/errors.py | 7 | ||||
| -rw-r--r-- | bot/exts/fun/duck_pond.py | 5 | ||||
| -rw-r--r-- | bot/exts/info/information.py | 14 | ||||
| -rw-r--r-- | bot/exts/moderation/infraction/_scheduler.py | 21 | ||||
| -rw-r--r-- | bot/exts/moderation/infraction/_utils.py | 22 | ||||
| -rw-r--r-- | bot/exts/moderation/infraction/infractions.py | 35 | ||||
| -rw-r--r-- | bot/exts/moderation/infraction/management.py | 25 | ||||
| -rw-r--r-- | bot/exts/moderation/watchchannels/bigbrother.py | 12 | ||||
| -rw-r--r-- | bot/exts/recruitment/talentpool/_cog.py | 18 | 
10 files changed, 78 insertions, 166 deletions
diff --git a/bot/converters.py b/bot/converters.py index 595809517..37eb91c7f 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -2,7 +2,6 @@ import logging  import re  import typing as t  from datetime import datetime -from functools import partial  from ssl import CertificateError  import dateutil.parser @@ -439,29 +438,6 @@ class HushDurationConverter(Converter):          return duration -def proxy_user(user_id: str) -> discord.Object: -    """ -    Create a proxy user object from the given id. - -    Used when a Member or User object cannot be resolved. -    """ -    log.trace(f"Attempting to create a proxy user for the user id {user_id}.") - -    try: -        user_id = int(user_id) -    except ValueError: -        log.debug(f"Failed to create proxy user {user_id}: could not convert to int.") -        raise BadArgument(f"User ID `{user_id}` is invalid - could not convert to an integer.") - -    user = discord.Object(user_id) -    user.mention = user.id -    user.display_name = f"<@{user.id}>" -    user.avatar_url_as = lambda static_format: None -    user.bot = False - -    return user - -  class UserMentionOrID(UserConverter):      """      Converts to a `discord.User`, but only if a mention or userID is provided. @@ -480,64 +456,6 @@ class UserMentionOrID(UserConverter):              raise BadArgument(f"`{argument}` is not a User mention or a User ID.") -class FetchedUser(UserConverter): -    """ -    Converts to a `discord.User` or, if it fails, a `discord.Object`. - -    Unlike the default `UserConverter`, which only does lookups via the global user cache, this -    converter attempts to fetch the user via an API call to Discord when the using the cache is -    unsuccessful. - -    If the fetch also fails and the error doesn't imply the user doesn't exist, then a -    `discord.Object` is returned via the `user_proxy` converter. - -    The lookup strategy is as follows (in order): - -    1. Lookup by ID. -    2. Lookup by mention. -    3. Lookup by name#discrim -    4. Lookup by name -    5. Lookup via API -    6. Create a proxy user with discord.Object -    """ - -    async def convert(self, ctx: Context, arg: str) -> t.Union[discord.User, discord.Object]: -        """Convert the `arg` to a `discord.User` or `discord.Object`.""" -        try: -            return await super().convert(ctx, arg) -        except BadArgument: -            pass - -        try: -            user_id = int(arg) -            log.trace(f"Fetching user {user_id}...") -            return await ctx.bot.fetch_user(user_id) -        except ValueError: -            log.debug(f"Failed to fetch user {arg}: could not convert to int.") -            raise BadArgument(f"The provided argument can't be turned into integer: `{arg}`") -        except discord.HTTPException as e: -            # If the Discord error isn't `Unknown user`, return a proxy instead -            if e.code != 10013: -                log.info(f"Failed to fetch user, returning a proxy instead: status {e.status}") -                return proxy_user(arg) - -            log.debug(f"Failed to fetch user {arg}: user does not exist.") -            raise BadArgument(f"User `{arg}` does not exist") - - -def _snowflake_from_regex(pattern: t.Pattern, arg: str) -> int: -    """ -    Extract the snowflake from `arg` using a regex `pattern` and return it as an int. - -    The snowflake is expected to be within the first capture group in `pattern`. -    """ -    match = pattern.match(arg) -    if not match: -        raise BadArgument(f"Mention {str!r} is invalid.") - -    return int(match.group(1)) - -  class Infraction(Converter):      """      Attempts to convert a given infraction ID into an infraction. @@ -568,5 +486,4 @@ class Infraction(Converter):  Expiry = t.Union[Duration, ISODateTime] -FetchedMember = t.Union[discord.Member, FetchedUser] -UserMention = partial(_snowflake_from_regex, RE_USER_MENTION) +MemberOrUser = t.Union[discord.Member, discord.User] diff --git a/bot/errors.py b/bot/errors.py index 5785faa44..08396ec3e 100644 --- a/bot/errors.py +++ b/bot/errors.py @@ -1,6 +1,6 @@ -from typing import Hashable, Union +from typing import Hashable -from discord import Member, User +from bot.converters import MemberOrUser  class LockedResourceError(RuntimeError): @@ -30,7 +30,8 @@ class InvalidInfractedUserError(Exception):          `user` -- User or Member which is invalid      """ -    def __init__(self, user: Union[Member, User], reason: str = "User infracted is a bot."): +    def __init__(self, user: MemberOrUser, reason: str = "User infracted is a bot."): +          self.user = user          self.reason = reason diff --git a/bot/exts/fun/duck_pond.py b/bot/exts/fun/duck_pond.py index d02912545..7f7e4585c 100644 --- a/bot/exts/fun/duck_pond.py +++ b/bot/exts/fun/duck_pond.py @@ -3,11 +3,12 @@ import logging  from typing import Union  import discord -from discord import Color, Embed, Member, Message, RawReactionActionEvent, TextChannel, User, errors +from discord import Color, Embed, Message, RawReactionActionEvent, TextChannel, errors  from discord.ext.commands import Cog, Context, command  from bot import constants  from bot.bot import Bot +from bot.converters import MemberOrUser  from bot.utils.checks import has_any_role  from bot.utils.messages import count_unique_users_reaction, send_attachments  from bot.utils.webhooks import send_webhook @@ -36,7 +37,7 @@ class DuckPond(Cog):              log.exception(f"Failed to fetch webhook with id `{self.webhook_id}`")      @staticmethod -    def is_staff(member: Union[User, Member]) -> bool: +    def is_staff(member: MemberOrUser) -> bool:          """Check if a specific member or user is staff."""          if hasattr(member, "roles"):              for role in member.roles: diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py index 85d3c0e73..a9ea403f7 100644 --- a/bot/exts/info/information.py +++ b/bot/exts/info/information.py @@ -12,7 +12,7 @@ from discord.ext.commands import BucketType, Cog, Context, Paginator, command, g  from bot import constants  from bot.api import ResponseCodeError  from bot.bot import Bot -from bot.converters import FetchedMember +from bot.converters import MemberOrUser  from bot.decorators import in_whitelist  from bot.errors import NonExistentRoleError  from bot.pagination import LinePaginator @@ -220,7 +220,7 @@ class Information(Cog):          await ctx.send(embed=embed)      @command(name="user", aliases=["user_info", "member", "member_info", "u"]) -    async def user_info(self, ctx: Context, user: FetchedMember = None) -> None: +    async def user_info(self, ctx: Context, user: MemberOrUser = None) -> None:          """Returns info about a user."""          if user is None:              user = ctx.author @@ -235,7 +235,7 @@ class Information(Cog):              embed = await self.create_user_embed(ctx, user)              await ctx.send(embed=embed) -    async def create_user_embed(self, ctx: Context, user: FetchedMember) -> Embed: +    async def create_user_embed(self, ctx: Context, user: MemberOrUser) -> Embed:          """Creates an embed containing information on the `user`."""          on_server = bool(ctx.guild.get_member(user.id)) @@ -311,7 +311,7 @@ class Information(Cog):          return embed -    async def basic_user_infraction_counts(self, user: FetchedMember) -> Tuple[str, str]: +    async def basic_user_infraction_counts(self, user: MemberOrUser) -> Tuple[str, str]:          """Gets the total and active infraction counts for the given `member`."""          infractions = await self.bot.api_client.get(              'bot/infractions', @@ -328,7 +328,7 @@ class Information(Cog):          return "Infractions", infraction_output -    async def expanded_user_infraction_counts(self, user: FetchedMember) -> Tuple[str, str]: +    async def expanded_user_infraction_counts(self, user: MemberOrUser) -> Tuple[str, str]:          """          Gets expanded infraction counts for the given `member`. @@ -369,7 +369,7 @@ class Information(Cog):          return "Infractions", "\n".join(infraction_output) -    async def user_nomination_counts(self, user: FetchedMember) -> Tuple[str, str]: +    async def user_nomination_counts(self, user: MemberOrUser) -> Tuple[str, str]:          """Gets the active and historical nomination counts for the given `member`."""          nominations = await self.bot.api_client.get(              'bot/nominations', @@ -394,7 +394,7 @@ class Information(Cog):          return "Nominations", "\n".join(output) -    async def user_messages(self, user: FetchedMember) -> Tuple[Union[bool, str], Tuple[str, str]]: +    async def user_messages(self, user: MemberOrUser) -> Tuple[Union[bool, str], Tuple[str, str]]:          """          Gets the amount of messages for `member`. diff --git a/bot/exts/moderation/infraction/_scheduler.py b/bot/exts/moderation/infraction/_scheduler.py index 8286d3635..3c5e5d3bf 100644 --- a/bot/exts/moderation/infraction/_scheduler.py +++ b/bot/exts/moderation/infraction/_scheduler.py @@ -13,8 +13,8 @@ from bot import constants  from bot.api import ResponseCodeError  from bot.bot import Bot  from bot.constants import Colours +from bot.converters import MemberOrUser  from bot.exts.moderation.infraction import _utils -from bot.exts.moderation.infraction._utils import UserSnowflake  from bot.exts.moderation.modlog import ModLog  from bot.utils import messages, scheduling, time  from bot.utils.channel import is_mod_channel @@ -115,7 +115,7 @@ class InfractionScheduler:          self,          ctx: Context,          infraction: _utils.Infraction, -        user: UserSnowflake, +        user: MemberOrUser,          action_coro: t.Optional[t.Awaitable] = None,          user_reason: t.Optional[str] = None,          additional_info: str = "", @@ -165,17 +165,10 @@ class InfractionScheduler:              dm_result = f"{constants.Emojis.failmail} "              dm_log_text = "\nDM: **Failed**" -            # Sometimes user is a discord.Object; make it a proper user. -            try: -                if not isinstance(user, (discord.Member, discord.User)): -                    user = await self.bot.fetch_user(user.id) -            except discord.HTTPException as e: -                log.error(f"Failed to DM {user.id}: could not fetch user (status {e.status})") -            else: -                # Accordingly display whether the user was successfully notified via DM. -                if await _utils.notify_infraction(user, infr_type.replace("_", " ").title(), expiry, user_reason, icon): -                    dm_result = ":incoming_envelope: " -                    dm_log_text = "\nDM: Sent" +            # Accordingly display whether the user was successfully notified via DM. +            if await _utils.notify_infraction(user, infr_type.replace("_", " ").title(), expiry, user_reason, icon): +                dm_result = ":incoming_envelope: " +                dm_log_text = "\nDM: Sent"          end_msg = ""          if infraction["actor"] == self.bot.user.id: @@ -264,7 +257,7 @@ class InfractionScheduler:              self,              ctx: Context,              infr_type: str, -            user: UserSnowflake, +            user: MemberOrUser,              send_msg: bool = True      ) -> None:          """ diff --git a/bot/exts/moderation/infraction/_utils.py b/bot/exts/moderation/infraction/_utils.py index a4059a6e9..9d94bca2d 100644 --- a/bot/exts/moderation/infraction/_utils.py +++ b/bot/exts/moderation/infraction/_utils.py @@ -7,6 +7,7 @@ from discord.ext.commands import Context  from bot.api import ResponseCodeError  from bot.constants import Colours, Icons +from bot.converters import MemberOrUser  from bot.errors import InvalidInfractedUserError  log = logging.getLogger(__name__) @@ -24,8 +25,6 @@ INFRACTION_ICONS = {  RULES_URL = "https://pythondiscord.com/pages/rules"  # Type aliases -UserObject = t.Union[discord.Member, discord.User] -UserSnowflake = t.Union[UserObject, discord.Object]  Infraction = t.Dict[str, t.Union[str, int, bool]]  APPEAL_EMAIL = "[email protected]" @@ -45,7 +44,7 @@ INFRACTION_DESCRIPTION_TEMPLATE = (  ) -async def post_user(ctx: Context, user: UserSnowflake) -> t.Optional[dict]: +async def post_user(ctx: Context, user: MemberOrUser) -> t.Optional[dict]:      """      Create a new user in the database. @@ -53,14 +52,11 @@ async def post_user(ctx: Context, user: UserSnowflake) -> t.Optional[dict]:      """      log.trace(f"Attempting to add user {user.id} to the database.") -    if not isinstance(user, (discord.Member, discord.User)): -        log.debug("The user being added to the DB is not a Member or User object.") -      payload = { -        'discriminator': int(getattr(user, 'discriminator', 0)), +        'discriminator': int(user.discriminator),          'id': user.id,          'in_guild': False, -        'name': getattr(user, 'name', 'Name unknown'), +        'name': user.name,          'roles': []      } @@ -75,7 +71,7 @@ async def post_user(ctx: Context, user: UserSnowflake) -> t.Optional[dict]:  async def post_infraction(          ctx: Context, -        user: UserSnowflake, +        user: MemberOrUser,          infr_type: str,          reason: str,          expires_at: datetime = None, @@ -118,7 +114,7 @@ async def post_infraction(  async def get_active_infraction(          ctx: Context, -        user: UserSnowflake, +        user: MemberOrUser,          infr_type: str,          send_msg: bool = True  ) -> t.Optional[dict]: @@ -153,7 +149,7 @@ async def get_active_infraction(  async def notify_infraction( -        user: UserObject, +        user: MemberOrUser,          infr_type: str,          expires_at: t.Optional[str] = None,          reason: t.Optional[str] = None, @@ -189,7 +185,7 @@ async def notify_infraction(  async def notify_pardon( -        user: UserObject, +        user: MemberOrUser,          title: str,          content: str,          icon_url: str = Icons.user_verified @@ -207,7 +203,7 @@ async def notify_pardon(      return await send_private_embed(user, embed) -async def send_private_embed(user: UserObject, embed: discord.Embed) -> bool: +async def send_private_embed(user: MemberOrUser, embed: discord.Embed) -> bool:      """      A helper method for sending an embed to a user's DMs. diff --git a/bot/exts/moderation/infraction/infractions.py b/bot/exts/moderation/infraction/infractions.py index f19323c7c..48ffbd773 100644 --- a/bot/exts/moderation/infraction/infractions.py +++ b/bot/exts/moderation/infraction/infractions.py @@ -10,11 +10,10 @@ from discord.ext.commands import Context, command  from bot import constants  from bot.bot import Bot  from bot.constants import Event -from bot.converters import Duration, Expiry, FetchedMember +from bot.converters import Duration, Expiry, MemberOrUser  from bot.decorators import respect_role_hierarchy  from bot.exts.moderation.infraction import _utils  from bot.exts.moderation.infraction._scheduler import InfractionScheduler -from bot.exts.moderation.infraction._utils import UserSnowflake  from bot.utils.messages import format_user  log = logging.getLogger(__name__) @@ -54,7 +53,7 @@ class Infractions(InfractionScheduler, commands.Cog):      # region: Permanent infractions      @command() -    async def warn(self, ctx: Context, user: FetchedMember, *, reason: t.Optional[str] = None) -> None: +    async def warn(self, ctx: Context, user: MemberOrUser, *, reason: t.Optional[str] = None) -> None:          """Warn a user for the given reason."""          if not isinstance(user, Member):              await ctx.send(":x: The user doesn't appear to be on the server.") @@ -67,7 +66,7 @@ class Infractions(InfractionScheduler, commands.Cog):          await self.apply_infraction(ctx, infraction, user)      @command() -    async def kick(self, ctx: Context, user: FetchedMember, *, reason: t.Optional[str] = None) -> None: +    async def kick(self, ctx: Context, user: MemberOrUser, *, reason: t.Optional[str] = None) -> None:          """Kick a user for the given reason."""          if not isinstance(user, Member):              await ctx.send(":x: The user doesn't appear to be on the server.") @@ -79,7 +78,7 @@ class Infractions(InfractionScheduler, commands.Cog):      async def ban(          self,          ctx: Context, -        user: FetchedMember, +        user: MemberOrUser,          duration: t.Optional[Expiry] = None,          *,          reason: t.Optional[str] = None @@ -95,7 +94,7 @@ class Infractions(InfractionScheduler, commands.Cog):      async def purgeban(          self,          ctx: Context, -        user: FetchedMember, +        user: MemberOrUser,          duration: t.Optional[Expiry] = None,          *,          reason: t.Optional[str] = None @@ -111,7 +110,7 @@ class Infractions(InfractionScheduler, commands.Cog):      async def voiceban(          self,          ctx: Context, -        user: FetchedMember, +        user: MemberOrUser,          duration: t.Optional[Expiry] = None,          *,          reason: t.Optional[str] @@ -129,7 +128,7 @@ class Infractions(InfractionScheduler, commands.Cog):      @command(aliases=["mute"])      async def tempmute(          self, ctx: Context, -        user: FetchedMember, +        user: MemberOrUser,          duration: t.Optional[Expiry] = None,          *,          reason: t.Optional[str] = None @@ -163,7 +162,7 @@ class Infractions(InfractionScheduler, commands.Cog):      async def tempban(          self,          ctx: Context, -        user: FetchedMember, +        user: MemberOrUser,          duration: Expiry,          *,          reason: t.Optional[str] = None @@ -189,7 +188,7 @@ class Infractions(InfractionScheduler, commands.Cog):      async def tempvoiceban(              self,              ctx: Context, -            user: FetchedMember, +            user: MemberOrUser,              duration: Expiry,              *,              reason: t.Optional[str] @@ -215,7 +214,7 @@ class Infractions(InfractionScheduler, commands.Cog):      # region: Permanent shadow infractions      @command(hidden=True) -    async def note(self, ctx: Context, user: FetchedMember, *, reason: t.Optional[str] = None) -> None: +    async def note(self, ctx: Context, user: MemberOrUser, *, reason: t.Optional[str] = None) -> None:          """Create a private note for a user with the given reason without notifying the user."""          infraction = await _utils.post_infraction(ctx, user, "note", reason, hidden=True, active=False)          if infraction is None: @@ -224,7 +223,7 @@ class Infractions(InfractionScheduler, commands.Cog):          await self.apply_infraction(ctx, infraction, user)      @command(hidden=True, aliases=['shadowban', 'sban']) -    async def shadow_ban(self, ctx: Context, user: FetchedMember, *, reason: t.Optional[str] = None) -> None: +    async def shadow_ban(self, ctx: Context, user: MemberOrUser, *, reason: t.Optional[str] = None) -> None:          """Permanently ban a user for the given reason without notifying the user."""          await self.apply_ban(ctx, user, reason, hidden=True) @@ -235,7 +234,7 @@ class Infractions(InfractionScheduler, commands.Cog):      async def shadow_tempban(          self,          ctx: Context, -        user: FetchedMember, +        user: MemberOrUser,          duration: Expiry,          *,          reason: t.Optional[str] = None @@ -261,17 +260,17 @@ class Infractions(InfractionScheduler, commands.Cog):      # region: Remove infractions (un- commands)      @command() -    async def unmute(self, ctx: Context, user: FetchedMember) -> None: +    async def unmute(self, ctx: Context, user: MemberOrUser) -> None:          """Prematurely end the active mute infraction for the user."""          await self.pardon_infraction(ctx, "mute", user)      @command() -    async def unban(self, ctx: Context, user: FetchedMember) -> None: +    async def unban(self, ctx: Context, user: MemberOrUser) -> None:          """Prematurely end the active ban infraction for the user."""          await self.pardon_infraction(ctx, "ban", user)      @command(aliases=("uvban",)) -    async def unvoiceban(self, ctx: Context, user: FetchedMember) -> None: +    async def unvoiceban(self, ctx: Context, user: MemberOrUser) -> None:          """Prematurely end the active voice ban infraction for the user."""          await self.pardon_infraction(ctx, "voice_ban", user) @@ -320,7 +319,7 @@ class Infractions(InfractionScheduler, commands.Cog):      async def apply_ban(          self,          ctx: Context, -        user: UserSnowflake, +        user: MemberOrUser,          reason: t.Optional[str],          purge_days: t.Optional[int] = 0,          **kwargs @@ -376,7 +375,7 @@ class Infractions(InfractionScheduler, commands.Cog):          await bb_cog.apply_unwatch(ctx, user, bb_reason, send_message=False)      @respect_role_hierarchy(member_arg=2) -    async def apply_voice_ban(self, ctx: Context, user: UserSnowflake, reason: t.Optional[str], **kwargs) -> None: +    async def apply_voice_ban(self, ctx: Context, user: MemberOrUser, reason: t.Optional[str], **kwargs) -> None:          """Apply a voice ban infraction with kwargs passed to `post_infraction`."""          if await _utils.get_active_infraction(ctx, user, "voice_ban"):              return diff --git a/bot/exts/moderation/infraction/management.py b/bot/exts/moderation/infraction/management.py index 3094159cd..641ad0410 100644 --- a/bot/exts/moderation/infraction/management.py +++ b/bot/exts/moderation/infraction/management.py @@ -12,7 +12,7 @@ from discord.utils import escape_markdown  from bot import constants  from bot.bot import Bot -from bot.converters import Expiry, Infraction, Snowflake, UserMention, allowed_strings, proxy_user +from bot.converters import Expiry, Infraction, MemberOrUser, Snowflake, UserMentionOrID, allowed_strings  from bot.exts.moderation.infraction.infractions import Infractions  from bot.exts.moderation.modlog import ModLog  from bot.pagination import LinePaginator @@ -201,29 +201,34 @@ class ModManagement(commands.Cog):      # region: Search infractions      @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: +    async def infraction_search_group(self, ctx: Context, query: t.Union[UserMentionOrID, Snowflake, str]) -> None:          """Searches for infractions in the database."""          if isinstance(query, int):              await self.search_user(ctx, discord.Object(query)) -        else: +        elif isinstance(query, str):              await self.search_reason(ctx, query) +        else: +            await self.search_user(ctx, query)      @infraction_search_group.command(name="user", aliases=("member", "id")) -    async def search_user(self, ctx: Context, user: t.Union[discord.User, proxy_user]) -> None: +    async def search_user(self, ctx: Context, user: t.Union[MemberOrUser, discord.Object]) -> None:          """Search for infractions by member."""          infraction_list = await self.bot.api_client.get(              'bot/infractions/expanded',              params={'user__id': str(user.id)}          ) -        user = self.bot.get_user(user.id) -        if not user and infraction_list: -            # Use the user data retrieved from the DB for the username. -            user = infraction_list[0]["user"] -            user = escape_markdown(user["name"]) + f"#{user['discriminator']:04}" +        if isinstance(user, (discord.Member, discord.User)): +            user_str = escape_markdown(str(user)) +        else: +            if infraction_list: +                user = infraction_list[0]["user"] +                user_str = escape_markdown(user["name"]) + f"#{user['discriminator']:04}" +            else: +                user_str = str(user.id)          embed = discord.Embed( -            title=f"Infractions for {user} ({len(infraction_list)} total)", +            title=f"Infractions for {user_str} ({len(infraction_list)} total)",              colour=discord.Colour.orange()          )          await self.send_infraction_list(ctx, embed, infraction_list) diff --git a/bot/exts/moderation/watchchannels/bigbrother.py b/bot/exts/moderation/watchchannels/bigbrother.py index c6ee844ef..3aa253fea 100644 --- a/bot/exts/moderation/watchchannels/bigbrother.py +++ b/bot/exts/moderation/watchchannels/bigbrother.py @@ -6,7 +6,7 @@ from discord.ext.commands import Cog, Context, group, has_any_role  from bot.bot import Bot  from bot.constants import Channels, MODERATION_ROLES, Webhooks -from bot.converters import FetchedMember +from bot.converters import MemberOrUser  from bot.exts.moderation.infraction._utils import post_infraction  from bot.exts.moderation.watchchannels._watchchannel import WatchChannel @@ -60,7 +60,7 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"):      @bigbrother_group.command(name='watch', aliases=('w',), root_aliases=('watch',))      @has_any_role(*MODERATION_ROLES) -    async def watch_command(self, ctx: Context, user: FetchedMember, *, reason: str) -> None: +    async def watch_command(self, ctx: Context, user: MemberOrUser, *, reason: str) -> None:          """          Relay messages sent by the given `user` to the `#big-brother` channel. @@ -71,11 +71,11 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"):      @bigbrother_group.command(name='unwatch', aliases=('uw',), root_aliases=('unwatch',))      @has_any_role(*MODERATION_ROLES) -    async def unwatch_command(self, ctx: Context, user: FetchedMember, *, reason: str) -> None: +    async def unwatch_command(self, ctx: Context, user: MemberOrUser, *, reason: str) -> None:          """Stop relaying messages by the given `user`."""          await self.apply_unwatch(ctx, user, reason) -    async def apply_watch(self, ctx: Context, user: FetchedMember, reason: str) -> None: +    async def apply_watch(self, ctx: Context, user: MemberOrUser, reason: str) -> None:          """          Add `user` to watched users and apply a watch infraction with `reason`. @@ -94,7 +94,7 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"):              await ctx.send(f":x: {user} is already being watched.")              return -        # FetchedUser instances don't have a roles attribute +        # discord.User instances don't have a roles attribute          if hasattr(user, "roles") and any(role.id in MODERATION_ROLES for role in user.roles):              await ctx.send(f":x: I'm sorry {ctx.author}, I'm afraid I can't do that. I must be kind to my masters.")              return @@ -125,7 +125,7 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"):          await ctx.send(msg) -    async def apply_unwatch(self, ctx: Context, user: FetchedMember, reason: str, send_message: bool = True) -> None: +    async def apply_unwatch(self, ctx: Context, user: MemberOrUser, reason: str, send_message: bool = True) -> None:          """          Remove `user` from watched users and mark their infraction as inactive with `reason`. diff --git a/bot/exts/recruitment/talentpool/_cog.py b/bot/exts/recruitment/talentpool/_cog.py index 80bd48534..5c1a1cd3f 100644 --- a/bot/exts/recruitment/talentpool/_cog.py +++ b/bot/exts/recruitment/talentpool/_cog.py @@ -6,13 +6,13 @@ from typing import Union  import discord  from async_rediscache import RedisCache -from discord import Color, Embed, Member, PartialMessage, RawReactionActionEvent, User +from discord import Color, Embed, Member, PartialMessage, RawReactionActionEvent  from discord.ext.commands import Cog, Context, group, has_any_role  from bot.api import ResponseCodeError  from bot.bot import Bot  from bot.constants import Channels, Emojis, Guild, MODERATION_ROLES, Roles, STAFF_ROLES, Webhooks -from bot.converters import FetchedMember +from bot.converters import MemberOrUser  from bot.exts.moderation.watchchannels._watchchannel import WatchChannel  from bot.exts.recruitment.talentpool._review import Reviewer  from bot.pagination import LinePaginator @@ -178,7 +178,7 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"):      @nomination_group.command(name='forcewatch', aliases=('fw', 'forceadd', 'fa'), root_aliases=("forcenominate",))      @has_any_role(*MODERATION_ROLES) -    async def force_watch_command(self, ctx: Context, user: FetchedMember, *, reason: str = '') -> None: +    async def force_watch_command(self, ctx: Context, user: MemberOrUser, *, reason: str = '') -> None:          """          Adds the given `user` to the talent pool, from any channel. @@ -188,7 +188,7 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"):      @nomination_group.command(name='watch', aliases=('w', 'add', 'a'), root_aliases=("nominate",))      @has_any_role(*STAFF_ROLES) -    async def watch_command(self, ctx: Context, user: FetchedMember, *, reason: str = '') -> None: +    async def watch_command(self, ctx: Context, user: MemberOrUser, *, reason: str = '') -> None:          """          Adds the given `user` to the talent pool. @@ -207,7 +207,7 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"):          await self._watch_user(ctx, user, reason) -    async def _watch_user(self, ctx: Context, user: FetchedMember, reason: str) -> None: +    async def _watch_user(self, ctx: Context, user: MemberOrUser, reason: str) -> None:          """Adds the given user to the talent pool."""          if user.bot:              await ctx.send(f":x: I'm sorry {ctx.author}, I'm afraid I can't do that. I only watch humans.") @@ -271,7 +271,7 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"):      @nomination_group.command(name='history', aliases=('info', 'search'))      @has_any_role(*MODERATION_ROLES) -    async def history_command(self, ctx: Context, user: FetchedMember) -> None: +    async def history_command(self, ctx: Context, user: MemberOrUser) -> None:          """Shows the specified user's nomination history."""          result = await self.bot.api_client.get(              self.api_endpoint, @@ -300,7 +300,7 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"):      @nomination_group.command(name='unwatch', aliases=('end', ), root_aliases=("unnominate",))      @has_any_role(*MODERATION_ROLES) -    async def unwatch_command(self, ctx: Context, user: FetchedMember, *, reason: str) -> None: +    async def unwatch_command(self, ctx: Context, user: MemberOrUser, *, reason: str) -> None:          """          Ends the active nomination of the specified user with the given reason. @@ -323,7 +323,7 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"):      @nomination_edit_group.command(name='reason')      @has_any_role(*MODERATION_ROLES) -    async def edit_reason_command(self, ctx: Context, nomination_id: int, actor: FetchedMember, *, reason: str) -> None: +    async def edit_reason_command(self, ctx: Context, nomination_id: int, actor: MemberOrUser, *, reason: str) -> None:          """Edits the reason of a specific nominator in a specific active nomination."""          if len(reason) > REASON_MAX_CHARS:              await ctx.send(f":x: Maxiumum allowed characters for the reason is {REASON_MAX_CHARS}.") @@ -417,7 +417,7 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"):          await ctx.message.add_reaction(Emojis.check_mark)      @Cog.listener() -    async def on_member_ban(self, guild: Guild, user: Union[User, Member]) -> None: +    async def on_member_ban(self, guild: Guild, user: Union[MemberOrUser]) -> None:          """Remove `user` from the talent pool after they are banned."""          await self.unwatch(user.id, "User was banned.")  |