import argparse import shlex from typing import Optional, List, NamedTuple, Dict from redbot.core.commands import RoleConverter, Context, BadArgument import discord _RoleConverter = RoleConverter() class NoExitParser(argparse.ArgumentParser): def error(self, message): raise BadArgument() class RoleSyntaxConverter(NamedTuple): parsed: Dict[str, List[discord.Role]] @classmethod async def convert(cls, ctx: Context, argument: str): parser = NoExitParser(description="Role management syntax help", add_help=False, allow_abbrev=True) parser.add_argument("--add", nargs="*", dest="add", default=[]) parser.add_argument("--remove", nargs="*", dest="remove", default=[]) try: vals = vars(parser.parse_args(shlex.split(argument))) except Exception: raise BadArgument() if not vals["add"] and not vals["remove"]: raise BadArgument("Must provide at least one action") for attr in ("add", "remove"): vals[attr] = [await _RoleConverter.convert(ctx, r) for r in vals[attr]] return cls(vals) class ComplexActionConverter(NamedTuple): """ --has-all roles --has-none roles --has-any roles --has-no-roles --has-exactly-nroles --has-more-than-nroles --has-less-than-nroles --has-perm permissions --any-perm permissions --not-perm permissions --above role --below role --add roles --remove roles --only-humans --only-bots --everyone """ parsed: dict @classmethod 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="any", default=[]) parser.add_argument("--has-all", nargs="*", dest="all", 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("--add", nargs="*", dest="add", default=[]) parser.add_argument("--remove", nargs="*", dest="remove", default=[]) parser.add_argument("--has-exactly-nroles", dest="quantity", type=int) 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("--only-humans", action="store_true", default=False, dest="humans") hum_or_bot.add_argument("--only-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 vals["add"] and not vals["remove"]: raise BadArgument("Must provide at least one action") if not any( ( vals["humans"], vals["everyone"], vals["bots"], vals["any"], vals["all"], 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 ("any", "all", "none", "add", "remove"): vals[attr] = [await _RoleConverter.convert(ctx, r) for r in vals[attr]] for attr in ("below", "above"): if vals[attr] is None: continue vals[attr] = await _RoleConverter.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(vals) class ComplexSearchConverter(NamedTuple): """ --has-all roles --has-none roles --has-any roles --has-no-roles --has-exactly-nroles --has-more-than-nroles --has-less-than-nroles --only-humans --only-bots --above role --below role --has-perm permissions --any-perm permissions --not-perm permissions --everyone --csv """ parsed: dict @classmethod 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="any", default=[]) parser.add_argument("--has-all", nargs="*", dest="all", 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("--only-humans", action="store_true", default=False, dest="humans") hum_or_bot.add_argument("--only-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["any"], vals["all"], 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 ("any", "all", "none"): vals[attr] = [await _RoleConverter.convert(ctx, r) for r in vals[attr]] for attr in ("below", "above"): if vals[attr] is None: continue vals[attr] = await _RoleConverter.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(vals)