Beispiel #1
0
    async def convert(self, ctx: commands.Context,
                      argument: str) -> discord.Role:
        try:
            member = await super().convert(ctx, argument)
        except BadArgument:
            guild = ctx.guild
            result = []
            for m in process.extract(
                    argument,
                {m: unidecode(m.display_name)
                 for m in guild.members},
                    limit=None,
                    score_cutoff=75,
            ):
                result.append((m[2], m[1]))

            if not result:
                raise BadArgument(f'Member "{argument}" not found.' if self.
                                  response else None)

            sorted_result = sorted(result, key=lambda r: r[1], reverse=True)
            member = sorted_result[0][0]
        return member
Beispiel #2
0
    async def convert(cls, ctx: Context, argument: str):

        start: datetime
        command: Optional[str] = None
        recur: Optional[timedelta] = None

        # Blame iOS smart punctuation,
        # and end users who use it for this (minor) perf loss
        argument = argument.replace("—", "--")

        command, *arguments = argument.split(" -- ")
        if arguments:
            argument = " -- ".join(arguments)
        else:
            command = None

        parser = NoExitParser(description="Scheduler event parsing", add_help=False)
        parser.add_argument(
            "-q", "--quiet", action="store_true", dest="quiet", default=False
        )
        parser.add_argument("--every", nargs="*", dest="every", default=[])
        if not command:
            parser.add_argument("command", nargs="*")
        at_or_in = parser.add_mutually_exclusive_group()
        at_or_in.add_argument("--start-at", nargs="*", dest="at", default=[])
        at_or_in.add_argument("--start-in", nargs="*", dest="in", default=[])

        try:
            vals = vars(parser.parse_args(argument.split(" ")))
        except Exception as exc:
            raise BadArgument() from exc

        if not (vals["at"] or vals["in"]):
            raise BadArgument("You must provide one of `--start-in` or `--start-at`")

        if not command and not vals["command"]:
            raise BadArgument("You have to provide a command to run")

        command = command or " ".join(vals["command"])

        for delta in ("in", "every"):
            if vals[delta]:
                parsed = parse_timedelta(" ".join(vals[delta]))
                if not parsed:
                    raise BadArgument("I couldn't understand that time interval")

                if delta == "in":
                    start = datetime.now(timezone.utc) + parsed
                else:
                    recur = parsed
                    if recur.total_seconds() < 60:
                        raise BadArgument(
                            "You can't schedule something to happen that frequently, "
                            "I'll get ratelimited."
                        )

        if vals["at"]:
            try:
                start = parse_time(" ".join(vals["at"]))
            except Exception:
                raise BadArgument("I couldn't understand that starting time.") from None

        return cls(command=command, start=start, recur=recur, quiet=vals["quiet"])
Beispiel #3
0
    async def convert(self, ctx, argument):
        argument = argument.replace("—", "--")
        parser = NoExitParser(description="Pokecord Search", add_help=False)

        pokemon = parser.add_mutually_exclusive_group()
        pokemon.add_argument("--name",
                             "--n",
                             nargs="*",
                             dest="names",
                             default=[])
        pokemon.add_argument("--level",
                             "--l",
                             nargs="*",
                             dest="level",
                             type=int,
                             default=0)
        pokemon.add_argument("--id",
                             "--i",
                             nargs="*",
                             dest="id",
                             type=int,
                             default=0)
        pokemon.add_argument("--variant",
                             "--v",
                             nargs="*",
                             dest="variant",
                             default=[])
        pokemon.add_argument("--gender",
                             "--g",
                             nargs="*",
                             dest="gender",
                             default=[])
        pokemon.add_argument("--iv", nargs="*", dest="iv", type=int, default=0)
        pokemon.add_argument("--type",
                             "--t",
                             nargs="*",
                             dest="type",
                             default=[])

        try:
            vals = vars(parser.parse_args(argument.split(" ")))
        except Exception as error:
            raise BadArgument() from error

        if not any([
                vals["names"],
                vals["level"],
                vals["id"],
                vals["variant"],
                vals["gender"],
                vals["iv"],
                vals["type"],
        ]):
            raise BadArgument(
                "You must provide one of `--name`, `--level`, `--id`, `--variant`, `--iv`, `--gender` or `--type``"
            )

        vals["names"] = " ".join(vals["names"])
        vals["variant"] = " ".join(vals["variant"])
        vals["gender"] = " ".join(vals["gender"])
        vals["type"] = " ".join(vals["type"])
        return vals
 async def convert(self, ctx: commands.Converter, argument: str) -> str:
     command = ctx.bot.get_command(argument)
     if command:
         raise BadArgument(f"`{argument}` is already a registered command.")
     return "".join(argument.split())
Beispiel #5
0
 def error(self, message):
     # Specifically not a parser error, which we have custom handling for.
     raise BadArgument() from None
Beispiel #6
0
 def parse_accage(cls, accage: int):
     if not account_age_checker(accage):
         raise BadArgument("Days must be less than Discord's creation date")
Beispiel #7
0
    def parser(self, ctx: Context):
        if self.account_age:
            if not isinstance(self.account_age, int):
                raise BadArgument(
                    "Account age days must be int, not {}".format(
                        type(self.account_age).__name__))
            if not account_age_checker(self.account_age):
                raise BadArgument(
                    "Account age days must be less than Discord's creation date"
                )

        if self.join_age:
            if not isinstance(self.join_age, int):
                raise BadArgument("Join age days must be int, not {}".format(
                    type(self.join_age).__name__))
            if not join_age_checker(ctx, self.join_age):
                raise BadArgument(
                    "Join age days must be less than this guild's creation date"
                )

        if self.maximum_entries:
            if not isinstance(self.maximum_entries, int):
                raise BadArgument("Maximum entries must be int, not {}".format(
                    type(self.maximum_entries).__name__))

        if self.name:
            if not isinstance(self.name, str):
                raise BadArgument("Name must be str, not {}".format(
                    type(self.name).__name__))
            if len(self.name) > 25:
                raise BadArgument(
                    "Name must be under 25 characters, your raffle name had {}"
                    .format(len(self.name)))
            for char in self.name:
                if char == "_":
                    # We want to allow underscores
                    continue
                if not char.isalnum():
                    index = self.name.index(char)
                    marker = (
                        f"{self.name}\n{' ' * (index)}^\n"
                        f"Characters must be alphanumeric or underscores, not \"{char}\""
                    )
                    raise RaffleSyntaxError(
                        f"In \"name\" field, character {index+1}\n\n{marker}")
        else:
            raise RequiredKeyError("name")

        if self.description:
            if not isinstance(self.description, str):
                raise BadArgument("Description must be str, not {}".format(
                    type(self.description).__name__))

        if self.roles_needed_to_enter:
            if not isinstance(self.roles_needed_to_enter, list):
                raise BadArgument(
                    "Roles must be a list of Discord role IDs, not {}".format(
                        type(self.roles_needed_to_enter).__name__))
            for r in self.roles_needed_to_enter:
                if not ctx.guild.get_role(r):
                    raise UnknownEntityError(r, "role")

        if self.prevented_users:
            if not isinstance(self.prevented_users, list):
                raise BadArgument(
                    "Prevented users must be a list of Discord user IDs, not {}"
                    .format(type(self.prevented_users).__name__))
            for u in self.prevented_users:
                if not ctx.bot.get_user(u):
                    raise UnknownEntityError(u, "user")

        if self.allowed_users:
            if not isinstance(self.allowed_users, list):
                raise BadArgument(
                    "Allowed users must be a list of Discord user IDs, not {}".
                    format(type(self.allowed_users).__name__))
            for u in self.allowed_users:
                if not ctx.bot.get_user(u):
                    raise UnknownEntityError(u, "user")

        if self.end_message:
            if not isinstance(self.end_message, str):
                # Will render {} without quotes, best not to include the type.__name__ here
                raise BadArgument("End message must be str")
            try:
                # This will raise BadArgument
                self.end_message.format(winner=RaffleSafeMember(
                    discord.Member),
                                        raffle=r"{raffle}")
            except KeyError as e:
                raise BadArgument(
                    f"{e} was an unexpected argument in your end_message block"
                )

        if self.on_end_action:
            valid_actions = ("end", "remove_winner", "keep_winner")
            if not isinstance(self.on_end_action,
                              str) or self.on_end_action not in valid_actions:
                raise BadArgument(
                    "on_end_action must be one of 'end', 'remove_winner', or 'keep_winner'"
                )
 async def convert(cls, ctx: Context, argument: str):
     if argument.lower() in PLATFORMS:
         return PLATFORMS[argument.lower()]
     raise BadArgument("Platform isn't found, please specify either psn, xbox or pc.")
 async def convert(cls, ctx: Context, argument: str):
     if argument.lower() in REGIONS:
         return REGIONS[argument.lower()]
     raise BadArgument("Region not found, please specify either na, eu or asia.")
Beispiel #10
0
 def get_content(self, data: dict, *, content: str = None) -> Optional[str]:
     content = data.pop("content", content)
     if content is not None and not self.allow_content:
         raise BadArgument("The `content` field is not supported for this command.")
     return content
Beispiel #11
0
class SteamUser:
    """SteamCommunity profile"""
    def __init__(self, steam: API, player_id: str):
        self._steam = steam
        self._user = self._steam["ISteamUser"]
        self._player = self._steam["IPlayerService"]
        self._userdata = self._user.GetPlayerSummaries(
            player_id)["response"]["players"][0]
        self._bandata = self._user.GetPlayerBans(player_id)["players"][0]
        self._personastate = self._userdata.get("personastate", 0)
        visibilites = {
            1: _("Private"),
            2: _("Friends only"),
            3: _("Public"),  # Friends of friends
            4: _("Users only"),
            5: _("Public"),
        }
        acctypes = ["I", "U", "M", "G", "A", "P", "C", "g", "T", "", "a"]

        self.steamid64 = self._userdata.get("steamid")
        self.createdat = self._userdata.get("timecreated")
        self.personaname = self._userdata.get("personaname")
        self.profileurl = self._userdata.get("profileurl")
        self.avatar32 = self._userdata.get("avatar")
        self.avatar64 = self._userdata.get("avatarmedium")
        self.avatar184 = self._userdata.get("avatarfull")
        self.visibility = visibilites[self._userdata.get(
            "communityvisibilitystate", 1)]
        self.hasprofile = bool(self._userdata.get("profilestate"))
        self.lastlogoff = self._userdata.get("lastlogoff")
        self.comments = self._userdata.get("commentpermission")

        self.realname = self._userdata.get("realname")
        self.clanid = self._userdata.get("primaryclanid")
        self.gameid = self._userdata.get("gameid")
        gameserver = self._userdata.get("gameserverip")
        self.gameserver = gameserver if gameserver != any(["0.0.0.0:0", None
                                                           ]) else None
        self.gameextrainfo = self._userdata.get("gameextrainfo")
        self.country = self._userdata.get("loccountrycode")
        self.state = self._userdata.get("locstatecode")
        self.cityid = self._userdata.get("loccityid")

        self.level = self._player.GetSteamLevel(player_id)["response"].get(
            "player_level", 0)

        self.communitybanned = self._bandata.get("CommunityBanned")
        self.VACbanned = self._bandata.get("VACBanned")
        self.VACbans = self._bandata.get("NumberOfVACBans")
        self.sincelastban = self._bandata.get("DaysSinceLastBan")
        self.gamebans = self._bandata.get("NumberOfGameBans")
        economyban = self._bandata.get("EconomyBan")
        self.economyban = economyban if economyban != "none" else None

        self.iduniverse = int(self.steamid64) >> 56
        self.idpart = int(self.steamid64) & 0b1
        self.accountnumber = (int(self.steamid64)
                              & 0b11111111111111111111111111111110) >> 1
        self.accountid = int(
            self.steamid64) & 0b11111111111111111111111111111111
        self.idinstance = (
            int(self.steamid64)
            & 0b1111111111111111111100000000000000000000000000000000) >> 32
        self.idtype = (
            int(self.steamid64)
            & 0b11110000000000000000000000000000000000000000000000000000) >> 52

        self.steamid = "STEAM_{}:{}:{}".format(self.iduniverse, self.idpart,
                                               self.accountnumber)
        self.sid3 = "[{}:{}:{}]".format(acctypes[self.idtype], self.iduniverse,
                                        self.accountid)

    @classmethod
    async def convert(cls, ctx, argument):
        steam = ctx.cog.steam
        if "ISteamUser" not in list(steam._interfaces.keys()):
            raise BadArgument(_("ApiKey not set or incorrect."))
        userapi = steam["ISteamUser"]
        argument = argument.replace("\\", "/")
        if (url_parsed := urlparse(argument)).scheme in ["http", "https"]:
            if url_parsed.netloc != "steamcommunity.com":
                raise BadArgument(
                    _("{} is not a Steam Community domain name.").format(
                        url_parsed.netloc))
            argument = PurePosixPath(url_parsed.path).name
        if argument.isdigit():
            id64 = argument
        else:
            if argument.startswith("STEAM_"):
                try:
                    id64 = SteamID.from_text(argument).as_64()
                except SteamIDError:
                    raise BadArgument(_("Incorrect SteamID32 provided."))
            else:
                try:
                    id64 = (userapi.ResolveVanityURL(argument).get(
                        "response", {}).get("steamid", ""))
                except JSONDecodeError:
                    raise BadArgument(
                        _("Unable to resolve {} into SteamID. "
                          "Check your input or try again later.").format(
                              argument))
        if not id64.isnumeric():
            raise BadArgument(
                _("User with SteamID {} not found.").format(argument))
        async with ctx.typing():
            try:
                profile = await ctx.bot.loop.run_in_executor(
                    None, SteamUser, steam, id64)
            except IndexError:
                raise BadArgument(
                    _("Unable to get profile for {} ({}). Check your input or try again later."
                      ).format(argument, id64))
        return profile
Beispiel #12
0
 def check_data_type(self, ctx: commands.Context, data, *, data_type=dict):
     if not isinstance(data, data_type):
         raise BadArgument(
             f"This doesn't seem to be properly formatted embed {self.conversion_type.upper()}. "
             f"Refer to the link on `{ctx.clean_prefix}help {ctx.command.qualified_name}`."
         )
Beispiel #13
0
class StringToEmbed(Converter):
    def __init__(
        self, *, conversion_type: str = "json", validate: bool = True, content: bool = False
    ):
        self.CONVERSION_TYPES = {
            "json": self.load_from_json,
            "yaml": self.load_from_yaml,
        }

        self.validate = validate
        self.conversion_type = conversion_type.lower()
        self.allow_content = content
        try:
            self.converter = self.CONVERSION_TYPES[self.conversion_type]
        except KeyError as exc:
            raise ValueError(
                f"{conversion_type} is not a valid conversion type for Embed conversion."
            ) from exc

    async def convert(self, ctx: commands.Context, argument: str) -> discord.Embed:
        data = argument.strip("`")
        data = await self.converter(ctx, data)
        content = self.get_content(data)

        if data.get("embed"):
            data = data["embed"]
        elif data.get("embeds"):
            data = data.get("embeds")[0]
        self.check_data_type(ctx, data)

        fields = await self.create_embed(ctx, data, content=content)
        content = fields["content"]
        embed = fields["embed"]
        if self.validate:
            await self.validate_embed(ctx, embed, content=content)
        return embed

    def check_data_type(self, ctx: commands.Context, data, *, data_type=dict):
        if not isinstance(data, data_type):
            raise BadArgument(
                f"This doesn't seem to be properly formatted embed {self.conversion_type.upper()}. "
                f"Refer to the link on `{ctx.clean_prefix}help {ctx.command.qualified_name}`."
            )

    async def load_from_json(self, ctx: commands.Context, data: str, **kwargs) -> dict:
        try:
            data = json.loads(data)
        except json.decoder.JSONDecodeError as error:
            await self.embed_convert_error(ctx, "JSON Parse Error", error)
        self.check_data_type(ctx, data, **kwargs)
        return data

    async def load_from_yaml(self, ctx: commands.Context, data: str, **kwargs) -> dict:
        try:
            data = yaml.safe_load(data)
        except Exception as error:
            await self.embed_convert_error(ctx, "YAML Parse Error", error)
        self.check_data_type(ctx, data, **kwargs)
        return data

    def get_content(self, data: dict, *, content: str = None) -> Optional[str]:
        content = data.pop("content", content)
        if content is not None and not self.allow_content:
            raise BadArgument("The `content` field is not supported for this command.")
        return content

    async def create_embed(
        self, ctx: commands.Context, data: dict, *, content: str = None
    ) -> Dict[str, Union[discord.Embed, str]]:
        content = self.get_content(data, content=content)

        if timestamp := data.get("timestamp"):
            data["timestamp"] = timestamp.strip("Z")
        try:
            e = discord.Embed.from_dict(data)
            length = len(e)
            if length > 6000:
                raise BadArgument(
                    f"Embed size exceeds Discord limit of 6000 characters ({length})."
                )
        except BadArgument:
            raise
        except Exception as error:
            await self.embed_convert_error(ctx, "Embed Parse Error", error)
        return {"embed": e, "content": content}
Beispiel #14
0
 async def convert(self, ctx: Context, arg: str) -> datetime.datetime:
     parsed = dateparser.parse(arg)
     if parsed is None:
         raise BadArgument("Unrecognized date/time.")
     return parsed
Beispiel #15
0
    async def convert(self, ctx, argument):
        argument = argument.replace("—", "--")
        parser = NoExitParser(description="Giveaway Created", add_help=False)

        # Required Arguments

        parser.add_argument("--prize", "--p", dest="prize", nargs="*", default=[])

        timer = parser.add_mutually_exclusive_group()
        timer.add_argument("--duration", "--d", dest="duration", nargs="*", default=[])
        timer.add_argument("--end", "--e", dest="end", nargs="*", default=[])

        # Optional Arguments
        parser.add_argument("--channel", dest="channel", default=None, nargs="?")
        parser.add_argument("--roles", "--r", "--restrict", dest="roles", nargs="*", default=[])
        parser.add_argument("--multiplier", "--m", dest="multi", default=None, type=int, nargs="?")
        parser.add_argument("--multi-roles", "--mr", nargs="*", dest="multi-roles", default=[])
        parser.add_argument("--joined", dest="joined", default=None, type=int, nargs="?")
        parser.add_argument("--created", dest="created", default=None, type=int, nargs="?")
        parser.add_argument("--blacklist", dest="blacklist", nargs="*", default=[])
        parser.add_argument("--winners", dest="winners", default=None, type=int, nargs="?")
        parser.add_argument("--mentions", dest="mentions", nargs="*", default=[])
        parser.add_argument("--description", dest="description", default=[], nargs="*")
        parser.add_argument("--emoji", dest="emoji", default=None, nargs="*")

        # Setting arguments
        parser.add_argument("--multientry", action="store_true")
        parser.add_argument("--notify", action="store_true")
        parser.add_argument("--congratulate", action="store_true")
        parser.add_argument("--announce", action="store_true")
        parser.add_argument("--ateveryone", action="store_true")
        parser.add_argument("--athere", action="store_true")
        parser.add_argument("--show-requirements", action="store_true")

        # Integrations
        parser.add_argument("--cost", dest="cost", default=None, type=int, nargs="?")
        parser.add_argument("--level-req", dest="levelreq", default=None, type=int, nargs="?")
        parser.add_argument("--rep-req", dest="repreq", default=None, type=int, nargs="?")
        parser.add_argument("--tatsu-level", default=None, type=int, nargs="?")
        parser.add_argument("--tatsu-rep", default=None, type=int, nargs="?")
        parser.add_argument("--mee6-level", default=None, type=int, nargs="?")
        parser.add_argument("--amari-level", default=None, type=int, nargs="?")
        parser.add_argument("--amari-weekly-xp", default=None, type=int, nargs="?")

        try:
            vals = vars(parser.parse_args(argument.split(" ")))
        except Exception as error:
            raise BadArgument(
                "Could not parse flags correctly, ensure flags are correctly used."
            ) from error

        if not vals["prize"]:
            raise BadArgument("You must specify a prize. Use `--prize` or `-p`")  #

        if not any([vals["duration"], vals["end"]]):
            raise BadArgument(
                "You must specify a duration or end date. Use `--duration` or `-d` or `--end` or `-e`"
            )

        nums = [vals["cost"], vals["joined"], vals["created"], vals["winners"]]
        for val in nums:
            if val is None:
                continue
            if val < 1:
                raise BadArgument("Number must be greater than 0")

        valid_multi_roles = []
        for role in vals["multi-roles"]:
            try:
                role = await RoleConverter().convert(ctx, role)
                valid_multi_roles.append(role.id)
            except BadArgument:
                raise BadArgument(f"The role {role} does not exist within this server.")
        vals["multi-roles"] = valid_multi_roles

        valid_exclusive_roles = []
        for role in vals["roles"]:
            try:
                role = await RoleConverter().convert(ctx, role)
                valid_exclusive_roles.append(role.id)
            except BadArgument:
                raise BadArgument(f"The role {role} does not exist within this server.")
        vals["roles"] = valid_exclusive_roles

        valid_blacklist_roles = []
        for role in vals["blacklist"]:
            try:
                role = await RoleConverter().convert(ctx, role)
                valid_blacklist_roles.append(role.id)
            except BadArgument:
                raise BadArgument(f"The role {role} does not exist within this server.")
        vals["blacklist"] = valid_blacklist_roles = []

        valid_mentions = []
        for role in vals["mentions"]:
            try:
                role = await RoleConverter().convert(ctx, role)
                valid_mentions.append(role.id)
            except BadArgument:
                raise BadArgument(f"The role {role} does not exist within this server.")
        vals["mentions"] = valid_mentions

        if vals["channel"]:
            try:
                vals["channel"] = await TextChannelConverter().convert(ctx, vals["channel"])
            except BadArgument:
                raise BadArgument("Invalid channel.")

        if vals["levelreq"] or vals["repreq"]:
            cog = ctx.bot.get_cog("Leveler")
            if not cog:
                raise BadArgument("Leveler cog not loaded.")
            if not hasattr(cog, "db"):
                raise BadArgument(
                    "This may be the wrong leveling cog. Ensure you are using Fixators."
                )

        if vals["tatsu_level"] or vals["tatsu_rep"]:
            token = await ctx.bot.get_shared_api_tokens("tatsumaki")
            if not token.get("authorization"):
                raise BadArgument(
                    f"You do not have a valid Tatsumaki API token. Check `{ctx.clean_prefix}gw integrations` for more info."
                )

        if vals["amari_level"] or vals["amari_weekly_xp"]:
            token = await ctx.bot.get_shared_api_tokens("amari")
            if not token.get("authorization"):
                raise BadArgument(
                    f"You do not have a valid Amari API token. Check `{ctx.clean_prefix}gw integrations` for more info."
                )

        if (vals["multi"] or vals["multi-roles"]) and not (vals["multi"] and vals["multi-roles"]):
            raise BadArgument(
                "You must specify a multiplier and roles. Use `--multiplier` or `-m` and `--multi-roles` or `-mr`"
            )

        if (
            (vals["ateveryone"] or vals["athere"])
            and not ctx.channel.permissions_for(ctx.me).mention_everyone
            and not ctx.channel.permissions_for(ctx.author).mention_everyone
        ):
            raise BadArgument(
                "You do not have permission to mention everyone. Please ensure the bot and you have `Mention Everyone` permission."
            )

        if vals["description"]:
            vals["description"] = " ".join(vals["description"])
            if len(vals["description"]) > 1000:
                raise BadArgument("Description must be less than 1000 characters.")

        if vals["emoji"]:
            vals["emoji"] = " ".join(vals["emoji"]).rstrip().lstrip()
            custom = False
            try:
                vals["emoji"] = await EmojiConverter().convert(ctx, vals["emoji"])
                custom = True
            except Exception:
                vals["emoji"] = str(vals["emoji"]).replace("\N{VARIATION SELECTOR-16}", "")
            try:
                await ctx.message.add_reaction(vals["emoji"])
                await ctx.message.remove_reaction(vals["emoji"], ctx.me)
            except Exception:
                raise BadArgument("Invalid emoji.")
            if custom:
                vals["emoji"] = vals["emoji"].id

        vals["prize"] = " ".join(vals["prize"])
        if vals["duration"]:
            tc = TimedeltaConverter()
            try:
                vals["duration"] = await tc.convert(ctx, " ".join(vals["duration"]))
            except BadArgument:
                raise BadArgument("Invalid duration. Use `--duration` or `-d`")
        else:
            try:
                time = dateparser.parse(" ".join(vals["end"]))
                if time.tzinfo is None:
                    time = time.replace(tzinfo=timezone.utc)
                if datetime.now(timezone.utc) > time:
                    raise BadArgument("End date must be in the future.")
                time = time - datetime.now(timezone.utc)
                vals["duration"] = time
            except Exception:
                raise BadArgument(
                    "Invalid end date. Use `--end` or `-e`. Ensure to pass a timezone, otherwise it defaults to UTC."
                )

        return vals
Beispiel #16
0
 async def convert(self, ctx: commands.Context, argument: str) -> discord.Member:
     member = await super().convert(ctx, argument)
     if member.bot:
         raise BadArgument("Keep bots out of this. We aren't susceptible to human diseases.")
     return member
Beispiel #17
0
        if matches:
            urls.extend(match.group(1) for match in matches)
        if emojis:
            for emoji in emojis:
                ext = "gif" if emoji.group(2) else "png"
                url = "https://cdn.discordapp.com/emojis/{id}.{ext}?v=1".format(
                    id=emoji.group(3), ext=ext)
                urls.append(url)
        if mentions:
            for mention in mentions:
                user = ctx.guild.get_member(int(mention.group(1)))
                if user is not None:
                    url = IMAGE_LINKS.search(
                        str(user.avatar_url_as(format="png")))
                    urls.append(url.group(1))
        if not urls and ids:
            for possible_id in ids:
                if user := ctx.guild.get_member(int(possible_id.group(0))):
                    url = IMAGE_LINKS.search(
                        str(user.avatar_url_as(format="png")))
                    urls.append(url.group(1))
        if attachments:
            urls.extend(attachment.url for attachment in attachments)
        if not urls and ctx.guild:
            if user := ctx.guild.get_member_named(argument):
                url = user.avatar_url_as(format="png")
                urls.append(url)
        if not urls:
            raise BadArgument("No images found.")
        return urls[0]
Beispiel #18
0
    async def convert(self, ctx: Context, argument: str) -> int:
        if argument.isnumeric() and len(argument) >= 17:
            return int(argument)

        raise BadArgument(_("{} doesn't look like a valid message ID.").format(argument))
Beispiel #19
0
 def parse_joinage(cls, ctx: Context, new_join_age: int):
     guildage = (now - ctx.guild.created_at).days
     if not join_age_checker(ctx, new_join_age):
         raise BadArgument(
             "Days must be less than this guild's creation date ({} days)".
             format(guildage))
Beispiel #20
0
    def parse(self, argument: str):
        """Parse natural language argument list."""
        mat = re.search(PAT_OBS_LINK, argument)
        if mat and mat["url"]:
            return argument
        try:
            arg_normalized = re.sub(r"((^| )(id|not)) ?by ", r"\2\3-by ",
                                    argument, re.I)
            arg_normalized = re.sub(r"((^| )in ?prj) ", r"\2in-prj ",
                                    arg_normalized, re.I)
            arg_normalized = re.sub(r"((^| )added ?(on|since|until)) ",
                                    r"\2added-\3 ", arg_normalized, re.I)
            tokens = shlex.split(arg_normalized, posix=False)
        except ValueError as err:
            raise BadArgument(err.args[0]) from err
        opts = []
        macro_by = ""
        macro_from = ""
        macro_of = ""
        expanded_tokens = []
        # - macro expansions are allowed anywhere in the taxon argument, but
        #   otherwise only when not immediately after an option token
        #   - e.g. `--of rg birds` will expand the `rg` macro, but `--from home`
        #     will not expand the `home` macro
        suppress_macro = False
        arg_count = 0
        expected_args = ARGPARSE_ARGS
        for _token in tokens:
            tok = _token.lower()
            argument_expected = False

            is_unix_arg = False
            if tok in expected_args:
                tok = f"--{tok}"
            if re.match(r"--", tok):
                is_unix_arg = True
                arg_count += 1
                # Every option token expects at least one argument.
                argument_expected = True
                if tok == "--of":
                    # Ignore "--of" after it is explicitly inserted.
                    expected_args = REMAINING_ARGS
                    suppress_macro = False
                else:
                    suppress_macro = True
                # Insert at head of explicit "opt" any collected opt macro
                # expansions. This allows them to be combined in the same query,
                # e.g.
                #   `reverse birds opt observed_on=2021-06-13` ->
                #   `--of birds --opt order=asc observed_on=2021-06-13`
                if tok == "--opt" and opts:
                    expanded_tokens.extend(["--opt", *opts])
                    opts = []
                    continue
                # Discard any prior macro expansions of these; see note below
                if tok == "--by":
                    macro_by = ""
                if tok == "--from":
                    macro_from = ""
                if tok == "--of":
                    macro_of = ""
            if not suppress_macro:
                if tok in MACROS:
                    macro = MACROS[tok]
                    if macro:
                        # Collect any expansions and continue:
                        _macro_opt_args = macro.get("opt")
                        if _macro_opt_args:
                            opts.extend(_macro_opt_args)
                        _macro_by = macro.get("by")
                        if _macro_by:
                            macro_by = _macro_by
                        _macro_from = macro.get("from")
                        if _macro_from:
                            macro_from = _macro_from
                        _macro_of = macro.get("of")
                        if _macro_of:
                            macro_of = _macro_of
                        continue
            # If it's an ordinary word token appearing before all other args,
            # then it's treated implicitly as first word of the "--of" argument,
            # which is inserted here.
            if arg_count == 0:
                arg_count += 1
                expanded_tokens.append("--of")
                macro_of = ""
                expected_args = REMAINING_ARGS
            # Append the unix option token (downcased) or ordinary word
            expanded_tokens.append(tok if is_unix_arg else _token)
            # Macros allowed again after first non-ARGS token is consumed:
            if not argument_expected:
                suppress_macro = False

        # Handle collected arguments that were not already
        # inserted into filtered_args above by appending them:
        if opts:
            expanded_tokens.extend(["--opt", *opts])
        # Note: There can only be one of macro_by, macro_from, or macro_of until we support
        # multiple users / places / taxa, so the last user, place, or taxon given wins,
        # superseding anything given earlier in the query.
        if macro_by:
            expanded_tokens.extend(["--by", macro_by])
        if macro_from:
            expanded_tokens.extend(["--from", macro_from])
        if macro_of:
            expanded_tokens.extend(["--of", macro_of])
        # Treat any unexpanded args before the first option keyword
        # argument as implicit "--of" option arguments:
        if not re.match(r"^--", expanded_tokens[0]):
            expanded_tokens.insert(0, "--of")
        argument_normalized = " ".join(expanded_tokens)
        return super().parse(argument_normalized)
Beispiel #21
0
 async def convert(self, ctx: commands.Context, argument: str) -> str:
     if argument.lower() not in ["kick", "ban"]:
         raise BadArgument(
             "This is not a valid action. The valid actions are kick and ban. For roles, supply a role."
         )
     return argument.lower()
Beispiel #22
0
 def __getattr__(self, *_args):
     raise BadArgument(r"Your `{winner}` received an unexpected attribute")
Beispiel #23
0
    async def convert(self, ctx, argument):
        argument = argument.replace("—", "--")
        parser = NoExitParser(description="Targeter argument parser", add_help=False)

        # Nicknames / Usernames
        names = parser.add_argument_group()
        names.add_argument("--nick", nargs="*", dest="nick", default=[])
        names.add_argument("--user", nargs="*", dest="user", default=[])
        names.add_argument("--name", nargs="*", dest="name", default=[])

        names.add_argument("--not-nick", nargs="*", dest="not-nick", default=[])
        names.add_argument("--not-user", nargs="*", dest="not-user", default=[])
        names.add_argument("--not-name", nargs="*", dest="not-name", default=[])

        names.add_argument("--a-nick", dest="a-nick", action="store_true")
        names.add_argument("--no-nick", dest="no-nick", action="store_true")

        discs = parser.add_mutually_exclusive_group()
        discs.add_argument("--disc", nargs="*", dest="disc", default=[])
        discs.add_argument("--not-disc", nargs="*", dest="ndisc", default=[])

        # Roles
        parser.add_argument("--roles", nargs="*", dest="roles", default=[])
        parser.add_argument("--any-role", nargs="*", dest="any-role", default=[])

        parser.add_argument("--not-roles", nargs="*", dest="not-roles", default=[])
        parser.add_argument("--not-any-role", nargs="*", dest="not-any-role", default=[])

        single = parser.add_mutually_exclusive_group()
        single.add_argument("--a-role", dest="a-role", action="store_true")
        single.add_argument("--no-role", dest="no-role", action="store_true")

        # Date stuff
        jd = parser.add_argument_group()
        jd.add_argument("--joined-on", nargs="*", dest="joined-on", default=[])
        jd.add_argument("--joined-before", nargs="*", dest="joined-be", default=[])
        jd.add_argument("--joined-after", nargs="*", dest="joined-af", default="")

        cd = parser.add_argument_group()
        cd.add_argument("--created-on", nargs="*", dest="created-on", default=[])
        cd.add_argument("--created-before", nargs="*", dest="created-be", default=[])
        cd.add_argument("--created-after", nargs="*", dest="created-af", default=[])

        # Status / Activity / Device / Just Basically Profile Stuff
        parser.add_argument("--status", nargs="*", dest="status", default=[])
        parser.add_argument("--device", nargs="*", dest="device", default=[])

        bots = parser.add_mutually_exclusive_group()
        bots.add_argument("--only-bots", dest="bots", action="store_true")
        bots.add_argument("--no-bots", dest="nbots", action="store_true")

        parser.add_argument("--activity-type", nargs="*", dest="at", default=[])
        parser.add_argument("--activity", nargs="*", dest="a", default=[])

        at = parser.add_mutually_exclusive_group()
        at.add_argument("--no-activity", dest="na", action="store_true")
        at.add_argument("--an-activity", dest="aa", action="store_true")

        # Permissions
        parser.add_argument("--perms", nargs="*", dest="perms", default=[])
        parser.add_argument("--any-perm", nargs="*", dest="any-perm", default=[])

        parser.add_argument("--not-perms", nargs="*", dest="not-perms", default=[])
        parser.add_argument("--not-any-perm", nargs="*", dest="not-any-perm", default=[])

        # Extra
        parser.add_argument("--format", nargs="*", dest="format", default=["menu"])

        try:
            vals = vars(parser.parse_args(argument.split(" ")))
        except Exception as exc:
            raise BadArgument() from exc

        try:
            for key, value in vals.items():
                if type(value) == list:
                    split_words = value
                    word_list = []
                    tmp = ""
                    for word in split_words:
                        if not word.startswith('"') and not word.endswith('"') and not tmp:
                            if word.startswith(r"\""):
                                word = word[1:]
                            word_list.append(word)
                        else:
                            echanged = False
                            if word.endswith(r"\""):
                                word = word[:-2] + '"'
                                echanged = True

                            schanged = False
                            if word.startswith(r"\""):
                                word = word[1:]
                                schanged = True
                            if word.startswith('"') and not schanged:
                                if word.startswith('"') and word.endswith('"') and len(word) > 1:
                                    word_list.append(word)
                                else:
                                    if tmp.endswith(" "):
                                        word_list.append(tmp)
                                        tmp = ""
                                        continue
                                    tmp += word[1:] + " "
                            elif word.endswith('"') and not echanged:
                                tmp += word[:-1]
                                word_list.append(tmp)
                                tmp = ""
                            else:
                                if schanged or echanged:
                                    word_list.append(word)
                                    continue
                                tmp += word + " "
                    if tmp:
                        raise BadArgument("A quote was started but never finished.")
                    vals[key] = word_list
        except Exception as e:
            raise BadArgument(str(e))

        if any(s for s in vals["status"] if not s.lower() in ["online", "dnd", "idle", "offline"]):
            raise BadArgument(
                "Invalid status.  Must be either `online`, `dnd`, `idle` or `offline`."
            )

        # Useeeeeeeeeeeeeeeeeeeernames (and Stuff)
        if vals["disc"]:
            new = []
            for disc in vals["disc"]:
                if len(disc) != 4:
                    raise BadArgument("Discriminators must have the length of 4")
                try:
                    new.append(int(disc))
                except ValueError:
                    raise BadArgument("Discriminators must be valid integers")
            vals["disc"] = new

        if vals["ndisc"]:
            new = []
            for disc in vals["ndisc"]:
                if len(disc) != 4:
                    raise BadArgument("Discriminators must have the length of 4")
                try:
                    new.append(int(disc))
                except ValueError:
                    raise BadArgument("Discriminators must be valid integers")
            vals["ndisc"] = new

        # Rooooooooooooooooles

        rc = RoleConverter()
        new = []
        for role in vals["roles"]:
            r = await rc.convert(ctx, role)
            if not r:
                raise BadArgument(f"Couldn't find a role matching: {role}")
            new.append(r)
        vals["roles"] = new

        new = []
        for role in vals["any-role"]:
            r = await rc.convert(ctx, role)
            if not r:
                raise BadArgument(f"Couldn't find a role matching: {role}")
            new.append(r)
        vals["any-role"] = new

        new = []
        for role in vals["not-roles"]:
            r = await rc.convert(ctx, role)
            if not r:
                raise BadArgument(f"Couldn't find a role matching: {role}")
            new.append(r)
        vals["not-roles"] = new

        new = []
        for role in vals["not-any-role"]:
            r = await rc.convert(ctx, role)
            if not r:
                raise BadArgument(f"Couldn't find a role matching: {role}")
            new.append(r)
        vals["not-any-role"] = new

        # Daaaaaaaaaaaaaaaaaates

        if vals["joined-on"]:
            try:
                vals["joined-on"] = parse(" ".join(vals["joined-on"]))
            except:
                raise BadArgument("Failed to parse --joined-on argument")

        if vals["joined-be"]:
            try:
                vals["joined-be"] = parse(" ".join(vals["joined-be"]))
            except:
                raise BadArgument("Failed to parse --joined-be argument")

        if vals["joined-af"]:
            try:
                vals["joined-af"] = parse(" ".join(vals["joined-af"]))
            except:
                raise BadArgument("Failed to parse --joined-after argument")

        if vals["created-on"]:
            try:
                vals["created-on"] = parse(" ".join(vals["created-on"]))
            except:
                raise BadArgument("Failed to parse --created-on argument")

        if vals["created-be"]:
            try:
                vals["created-be"] = parse(" ".join(vals["created-be"]))
            except:
                raise BadArgument("Failed to parse --created-be argument")

        if vals["created-af"]:
            try:
                vals["created-af"] = parse(" ".join(vals["created-af"]))
            except:
                raise BadArgument("Failed to parse --created-af argument")

        # Actiiiiiiiiiiiiiiiiivities
        if vals["device"]:
            if not all(d in ["desktop", "mobile", "web"] for d in vals["device"]):
                raise BadArgument("Bad device.  Must be `desktop`, `mobile` or `web`.")

        if vals["at"]:
            at = discord.ActivityType
            switcher = {
                "unknown": at.unknown,
                "playing": at.playing,
                "streaming": at.streaming,
                "listening": at.listening,
                "watching": at.watching,
                "competing": at.competing,
            }
            if not all([a.lower() in switcher for a in vals["at"]]):
                raise BadArgument(
                    "Invalid Activity Type.  Must be either `unknown`, `playing`, `streaming`, `listening`, `competing` or `watching`."
                )
            new = [switcher[name.lower()] for name in vals["at"]]
            vals["at"] = new

        new = []
        for perm in vals["perms"]:
            perm = perm.replace(" ", "_")
            if not perm.lower() in PERMS:
                raise BadArgument(
                    f"Invalid permission.  Run `{ctx.prefix}target permissions` to see a list of valid permissions."
                )
            new.append(perm)
        vals["perms"] = new

        new = []
        for perm in vals["any-perm"]:
            perm = perm.replace(" ", "_")
            if not perm.lower() in PERMS:
                raise BadArgument(
                    f"Invalid permission.  Run `{ctx.prefix}target permissions` to see a list of valid permissions."
                )
            new.append(perm)
        vals["any-perm"] = new

        new = []
        for perm in vals["not-perms"]:
            perm = perm.replace(" ", "_")
            if not perm.lower() in PERMS:
                raise BadArgument(
                    f"Invalid permission.  Run `{ctx.prefix}target permissions` to see a list of valid permissions."
                )
            new.append(perm)
        vals["not-perms"] = new

        new = []
        for perm in vals["not-any-perm"]:
            perm = perm.replace(" ", "_")
            if not perm.lower() in PERMS:
                raise BadArgument(
                    f"Invalid permission.  Run `{ctx.prefix}target permissions` to see a list of valid permissions."
                )
            new.append(perm)
        vals["not-any-perm"] = new

        if vals["format"]:
            if not vals["format"][0].lower() in ["menu", "csv"]:
                raise BadArgument(
                    "Invalid format.  Must be `csv` for a CSV file or `menu` for in an embed."
                )
            vals["format"] = vals["format"][0].lower()

        return vals
Beispiel #24
0
 async def convert(self, ctx: Context, argument: str):
     if len(argument) > 256:
         raise BadArgument("Your title must be 256 characters or fewer.")
     return argument
Beispiel #25
0
 async def convert(cls, context: Context, argument: str):
     if argument.isdigit():
         raise BadArgument("Event names must contain at least 1 non-numeric value")
     return cls(argument)
Beispiel #26
0
 def error(self, message):
     raise BadArgument("Query not understood") from None
Beispiel #27
0
    async def convert(cls, ctx: Context, argument: str):
        parser = NoExitParser(description="Role management syntax help",
                              add_help=False)
        parser.add_argument("--has-any", nargs="*", dest="hasany", default=[])
        parser.add_argument("--has-all", nargs="*", dest="hasall", default=[])
        parser.add_argument("--has-none", nargs="*", dest="none", default=[])
        parser.add_argument("--has-no-roles",
                            action="store_true",
                            default=False,
                            dest="noroles")
        parser.add_argument("--has-perms",
                            nargs="*",
                            dest="hasperm",
                            default=[])
        parser.add_argument("--any-perm",
                            nargs="*",
                            dest="anyperm",
                            default=[])
        parser.add_argument("--not-perm",
                            nargs="*",
                            dest="notperm",
                            default=[])
        parser.add_argument("--csv", action="store_true", default=False)
        parser.add_argument("--has-exactly-nroles",
                            dest="quantity",
                            type=int,
                            default=None)
        parser.add_argument("--has-more-than-nroles",
                            dest="gt",
                            type=int,
                            default=None)
        parser.add_argument("--has-less-than-nroles",
                            dest="lt",
                            type=int,
                            default=None)
        parser.add_argument("--above", dest="above", type=str, default=None)
        parser.add_argument("--below", dest="below", type=str, default=None)
        hum_or_bot = parser.add_mutually_exclusive_group()
        hum_or_bot.add_argument("--humans",
                                action="store_true",
                                default=False,
                                dest="humans")
        hum_or_bot.add_argument("--bots",
                                action="store_true",
                                default=False,
                                dest="bots")
        hum_or_bot.add_argument("--everyone",
                                action="store_true",
                                default=False,
                                dest="everyone")
        try:
            vals = vars(parser.parse_args(shlex.split(argument)))
        except Exception:
            raise BadArgument()

        if not any((
                vals["humans"],
                vals["everyone"],
                vals["bots"],
                vals["hasany"],
                vals["hasall"],
                vals["none"],
                vals["hasperm"],
                vals["notperm"],
                vals["anyperm"],
                vals["noroles"],
                bool(vals["quantity"] is not None),
                bool(vals["gt"] is not None),
                bool(vals["lt"] is not None),
                vals["above"],
                vals["below"],
        )):
            raise BadArgument(
                "You need to provide at least 1 search criterion")

        for attr in ("hasany", "hasall", "none"):
            vals[attr] = [
                await _role_converter_instance.convert(ctx, r)
                for r in vals[attr]
            ]

        for attr in ("below", "above"):
            if vals[attr] is None:
                continue
            vals[attr] = await _role_converter_instance.convert(
                ctx, vals[attr])

        for attr in ("hasperm", "anyperm", "notperm"):

            vals[attr] = [
                i.replace("_",
                          " ").lower().replace(" ",
                                               "_").replace("server", "guild")
                for i in vals[attr]
            ]
            if any(perm not in dir(discord.Permissions)
                   for perm in vals[attr]):
                raise BadArgument("You gave an invalid permission")

        return cls(ctx=ctx, **vals)
Beispiel #28
0
def non_numeric(arg: str) -> str:
    if arg.isdigit():
        raise BadArgument(
            "Event names must contain at least 1 non-numeric value")
    return arg
Beispiel #29
0
 def error(self, message):
     raise BadArgument()
Beispiel #30
0
class RawUserIds(Converter):
    async def convert(self, ctx, argument):
        if match := _id_regex.match(argument) or _mention_regex.match(argument):
            return int(match.group(1))

        raise BadArgument("{} doesn't look like a valid user ID.").format(argument)