示例#1
0
文件: parsers.py 项目: Sunkek/sunbot
async def parse_reaction_role_pair(text, ctx):
    try:
        emote, role = text.split()
    except ValueError:
        raise BadArgument("Must provide an emote and a role")
    try:
        emote = await PartialEmojiConverter().convert(ctx, emote)
        name = re.search(RE_EMOTE_NAME, str(emote))
        emote = re.sub(name.group(1), "_",
                       str(emote))  # Wiping emote name to make it compact
    except PartialEmojiConversionFailure:
        emote = str(bytes(str(emote), "utf-8")[:4],
                    "utf-8")[0]  # Stripping skintones and other modifiers
    role = await RoleConverter().convert(ctx, role)
    return emote, role
示例#2
0
    async def get_valid_types(bot: Bot) -> list:
        """
        Try to get a list of valid filter list types.

        Raise a BadArgument if the API can't respond.
        """
        try:
            valid_types = await bot.api_client.get('bot/filter-lists/get-types'
                                                   )
        except ResponseCodeError:
            raise BadArgument(
                "Cannot validate list_type: Unable to fetch valid types from API."
            )

        return [enum for enum, classname in valid_types]
示例#3
0
    async def convert(self, ctx: Context, duration: str) -> datetime:
        """
        Converts a `duration` string to a datetime object that's `duration` in the future.

        The converter supports the same symbols for each unit of time as its parent class.
        """
        delta = await super().convert(ctx, duration)
        now = datetime.utcnow()

        try:
            return now + delta
        except ValueError:
            raise BadArgument(
                f"`{duration}` results in a datetime outside the supported range."
            )
示例#4
0
def parse_relativedelta(
    argument: str, *, allowed_units: Optional[List[str]] = None
) -> Optional[relativedelta]:
    """
    This converts a user provided string into a datetime with offset from NOW

    The units should be in order from largest to smallest.
    This works with or without whitespace.

    Parameters
    ----------
    argument : str
        The user provided input
    allowed_units : Optional[List[str]]
        If provided, you can constrain a user to expressing the amount of time
        in specific units. The units you can chose to provide are the same as the
        parser understands. (``years``, ``months``, ``weeks``, ``days``, ``hours``, ``minutes``, ``seconds``)

    Returns
    -------
    Optional[dateutil.relativedelta.relativedelta]
        If matched, the relativedelta which was parsed. This can return `None`

    Raises
    ------
    BadArgument
        If the argument passed uses a unit not allowed, but understood
        or if the value is out of bounds.
    """
    allowed_units = allowed_units or [
        "years",
        "months",
        "weeks",
        "days",
        "hours",
        "minutes",
        "seconds",
    ]
    params = _parse_and_match(argument, allowed_units)
    if params:
        try:
            delta = relativedelta(**params)
        except OverflowError:
            raise BadArgument(
                _("The time set is way too high, consider setting something reasonable.")
            )
        return delta
    return None
示例#5
0
 async def setteam(self, ctx, team_type, team_number: int):
     """Sets an association with your team in the database."""
     team_type = team_type.casefold()
     with db.Session() as session:
         dbcheck = session.query(TeamNumbers).filter_by(
             user_id=ctx.author.id,
             team_number=team_number,
             team_type=team_type).one_or_none()
         if dbcheck is None:
             dbtransaction = TeamNumbers(user_id=ctx.author.id,
                                         team_number=team_number,
                                         team_type=team_type)
             session.add(dbtransaction)
             await ctx.send("Team number set!")
         else:
             raise BadArgument("You are already associated with that team!")
示例#6
0
	async def raw(self, ctx, team_num: int):
		"""
		Get raw TBA API output for a team.
		This command is really only useful for development.
		"""
		team_data = self.parser.get_team(team_num)
		try:
			getattr(team_data, "Errors")
		except tbapi.InvalidKeyError:
			e = discord.Embed(color=blurple)
			e.set_author(name='FIRST® Robotics Competition Team {}'.format(team_num), url='https://www.thebluealliance.com/team/{}'.format(team_num), icon_url='http://i.imgur.com/V8nrobr.png')
			e.add_field(name='Raw Data', value=team_data.flatten())
			e.set_footer(text='Triggered by ' + ctx.author.display_name)
			await ctx.send(embed=e)
		else:
			raise BadArgument('Team {} does not exist.'.format(team_num))
示例#7
0
    async def convert(self, ctx, argument) -> discord.Role:

        guild = ctx.guild
        if not guild:
            raise NoPrivateMessage()

        match = self._get_id_match(argument) or re.match(
            r'<@&([0-9]+)>$', argument)
        if match:
            result = discord.utils.get(guild.roles, id=int(match.group(1)))
        else:
            result = discord.utils.find(
                lambda r: r.name.lower() == argument.lower(), guild.roles)
        if result is None:
            raise BadArgument('Role "{}" not found.'.format(argument))
        return result
示例#8
0
    def __init__(self, argument):
        now = datetime.utcnow()
        dt, status = self.calendar.parseDT(argument, sourceTime=now)
        if not status.hasDateOrTime:
            raise BadArgument(
                'invalid time provided, try e.g. "tomorrow" or "3 days"')

        if not status.hasTime:
            # replace it with the current time
            dt = dt.replace(hour=now.hour,
                            minute=now.minute,
                            second=now.second,
                            microsecond=now.microsecond)

        self.dt = dt
        self._past = dt < now
示例#9
0
    async def linkscrubconfig(self, ctx, *, link_role: SafeRoleConverter):
        """
        Set a role that users must have in order to post links.
        This accepts the safe default role conventions that the memberconfig command does.
        """
        if link_role >= ctx.author.top_role:
            raise BadArgument('Link role cannot be higher than your top role!')

        with db.Session() as session:
            settings = session.query(GuildMessageLinks).filter_by(guild_id=ctx.guild.id).one_or_none()
            if settings is None:
                settings = GuildMessageLinks(guild_id=ctx.guild.id, role_id=link_role.id)
                session.add(settings)
            else:
                settings.role_id = link_role.id
        await ctx.send(f'Link role set as `{link_role.name}`.')
示例#10
0
    async def snowflake(self, ctx: Context, *snowflakes: Snowflake) -> None:
        """Get Discord snowflake creation time."""
        if len(snowflakes) > 1 and await has_no_roles_check(ctx, *STAFF_ROLES):
            raise BadArgument("Cannot process more than one snowflake in one invocation.")

        for snowflake in snowflakes:
            created_at = snowflake_time(snowflake)
            embed = Embed(
                description=f"**Created at {created_at}** ({time_since(created_at, max_units=3)}).",
                colour=Colour.blue()
            )
            embed.set_author(
                name=f"Snowflake: {snowflake}",
                icon_url="https://github.com/twitter/twemoji/blob/master/assets/72x72/2744.png?raw=true"
            )
            await ctx.send(embed=embed)
示例#11
0
    async def convert(cls, ctx, arg):
        parser = NoExitParser(description="Bulk role setting syntax help",
                              add_help=False)

        for name in ("sticky", "selfrem", "selfadd"):
            add_bool_arg(parser, name)

        try:
            parsed = parser.parse_args(shlex.split(arg))
        except Exception:
            raise BadArgument("Settings:\n"
                              "    --(no-)selfadd\n"
                              "    --(no-)selfrem\n"
                              "    --(no-)sticky")

        return cls(parsed.selfadd, parsed.selfrem, parsed.sticky)
示例#12
0
 async def teamsfor(self, ctx, user: discord.Member = None):
     """Allows you to see the teams for the mentioned user. If no user is mentioned, your teams are displayed."""
     if user is None:
         user = ctx.author
     teams = await TeamNumbers.get_by_user(user_id=user.id)
     if len(teams) == 0:
         raise BadArgument(
             "Couldn't find any team associations for that user!")
     else:
         e = discord.Embed(type='rich')
         e.title = 'Teams for {}'.format(user.display_name)
         e.description = "Teams: \n"
         for i in teams:
             e.description = "{} {} Team {} \n".format(
                 e.description, i.team_type.upper(), i.team_number)
         await ctx.send(embed=e)
示例#13
0
    async def convert(ctx, sub: str):
        sub = sub.lower()

        if not sub.startswith("r/"):
            sub = f"r/{sub}"

        resp = await ctx.bot.http_session.get(
            "https://www.reddit.com/subreddits/search.json", params={"q": sub})

        json = await resp.json()
        if not json["data"]["children"]:
            raise BadArgument(
                f"The subreddit `{sub}` either doesn't exist, or it has no posts."
            )

        return sub
示例#14
0
 async def teamsfor(self, ctx, user: discord.Member = None):
     """Allows you to see the teams for the mentioned user. If no user is mentioned, your teams are displayed."""
     if user is None:
         user = ctx.author
     with db.Session() as session:
         teams = session.query(TeamNumbers).filter_by(user_id=user.id).order_by("team_type desc",
                                                                                "team_number asc").all()
         if len(teams) is 0:
             raise BadArgument("Couldn't find any team associations for that user!")
         else:
             e = discord.Embed(type='rich')
             e.title = 'Teams for {}'.format(user.display_name)
             e.description = "Teams: \n"
             for i in teams:
                 e.description = "{} {} Team {} \n".format(e.description, i.team_type.upper(), i.team_number)
             await ctx.send(embed=e)
示例#15
0
    async def memberconfig(self, ctx, *, member_role: SafeRoleConverter):
        """
        Set the member role for the guild.
        The member role is the role used for the timeout command. It should be a role that all members of the server have.
        """
        if member_role >= ctx.author.top_role:
            raise BadArgument('member role cannot be higher than your top role!')

        with db.Session() as session:
            settings = session.query(MemberRole).filter_by(id=ctx.guild.id).one_or_none()
            if settings is None:
                settings = MemberRole(id=ctx.guild.id, member_role=member_role.id)
                session.add(settings)
            else:
                settings.member_role = member_role.id
        await ctx.send('Member role set as `{}`.'.format(member_role.name))
示例#16
0
    async def roll(self,
                   ctx,
                   modifiers: Greedy[Modifier],
                   vs: OppositionSigil = None,
                   opposition: Opposition = None):
        """Roll with optional modifiers and opposition.

        MODIFIERS

          Zero or more modifiers may be given, each starting with a "+" or "-",
          e.g., "+3" or "-1".

        OPPOSITION

          At most one opposition may be given. If no opposition is given, the
          roll simply generates shifts vs 0. If opposition is given, the result
          will be either failure, success, or success with style.

        EXAMPLES

          !roll
              Roll with no modifier and no opposition.

          !roll +2
              Roll with a +2 modifier and no opposition.

          !roll +1 vs 3
              Roll with a +1 modifier and an opposition of 3.

          !roll -1 +2 vs 3
              Roll with a +1 modifier (−1 + +2) and an opposition of 3.
        """
        if vs is not None and opposition is None:
            raise BadArgument('Found "vs" but no opposition')

        player = ctx.author

        context = RollContext(modifiers=tuple(modifiers),
                              opposition=opposition)

        roll = DICE_POOL.roll(context)

        message = f'{ROLL_EMOJI} {player.mention} \[{ctx.message.content}\]  {roll.description()}\n\n'
        message += f'```\n{roll.dice_display()}```\n'
        message += f'({roll.explanation()})'

        await ctx.send(message)
示例#17
0
    async def convert(self, ctx: Context, arg: str) -> t.Optional[dict]:
        """Attempts to convert `arg` into an infraction `dict`."""
        if arg in ("l", "last", "recent"):
            params = {"actor__id": ctx.author.id, "ordering": "-inserted_at"}

            infractions = await ctx.bot.api_client.get("bot/infractions",
                                                       params=params)

            if not infractions:
                raise BadArgument(
                    "Couldn't find most recent infraction; you have never given an infraction."
                )
            else:
                return infractions[0]

        else:
            return await ctx.bot.api_client.get(f"bot/infractions/{arg}")
示例#18
0
    async def timezone(self, ctx, team_num: int):
        """
        Get the timezone of a team based on the team number.
        """

        team_data = self.parser.get_team(team_num)
        try:
            getattr(team_data, "Errors")
        except tbapi.InvalidKeyError:
            location = '{0.city}, {0.state_prov} {0.country}'.format(team_data)
            gmaps = googlemaps.Client(key=self.gmaps_key)
            geolocator = Nominatim()
            geolocation = geolocator.geocode(location)
            timezone = gmaps.timezone(location="{}, {}".format(
                geolocation.latitude, geolocation.longitude),
                                      language="json")
            utc_offset = int(timezone["rawOffset"]) / 3600
            if timezone["dstOffset"] == 3600:
                utc_offset += 1
            utc_timedelta = timedelta(hours=utc_offset)
            currentUTCTime = datetime.datetime.utcnow()
            currentTime = currentUTCTime + utc_timedelta
            current_hour = currentTime.hour
            current_hour_original = current_hour
            dayTime = "AM"
            if current_hour > 12:
                current_hour -= 12
                dayTime = "PM"
            elif current_hour == 12:
                dayTime = "PM"
            elif current_hour == 0:
                current_hour = 12
                dayTime = "AM"
            current_minute = currentTime.minute
            if current_minute < 10:
                current_minute = "0{}".format(current_minute)
            current_second = currentTime.second
            if current_second < 10:
                current_second = "0{}".format(current_second)
            await ctx.send(
                "Timezone: {0} UTC{1:+g} \nCurrent Time: {2}:{3}:{4} {5} ({6}:{3}:{4})"
                .format(timezone["timeZoneName"], utc_offset, current_hour,
                        current_minute, current_second, dayTime,
                        current_hour_original))
        else:
            raise BadArgument('Team {} does not exist.'.format(team_num))
    async def convert(self, ctx, argument):
        try:
            return await super().convert(ctx, argument)
        except BadArgument:
            arg = argument.lower()

            def predicate(m):
                return (m.name.lower() == arg
                        or (m.nick and m.nick.lower() == arg)
                        or str(m).lower() == arg)

            member = discord.utils.find(predicate, ctx.guild.members)

            if member:
                return member

            raise BadArgument(f"{config.NO} I couldn't find that person.")
示例#20
0
 async def convert(self, ctx: DiscordContext, argument):
     if is_url(argument) and self.ignore_urls:
         return self.many and [] or None
     if self.many:
         pool_names = argument.split()
     else:
         pool_names = [argument]
     if self.avail_only:
         obj = ctx.user_data.available_pools
     elif self.moderated_only:
         obj = ctx.user_data.moderated_pools
     else:
         obj = MemeImagePool.objects
     pools = obj.filter(name__in=pool_names)
     if len(pools) == 0:
         raise BadArgument("no matching pools found!")
     return self.many and pools or pools[0]
示例#21
0
    async def convert(self, ctx, argument):
        user = None
        match = ID_MATCHER.match(argument)
        if match is not None:
            argument = match.group(1)
        try:
            user = await UserConverter().convert(ctx, argument)
        except BadArgument:
            try:
                user = await Utils.get_user(
                    await RangedInt(min=20000000000000000, max=9223372036854775807).convert(ctx, argument))
            except (ValueError, HTTPException):
                pass

        if user is None or (self.id_only and str(user.id) != argument):
            raise BadArgument("user_not_found")
        return user
示例#22
0
 async def safe_message_fetch(ctx,
                              menu=None,
                              channel=None,
                              message_id=None):
     """Used to safely get a message and raise an error message cannot be found"""
     try:
         if menu:
             channel = ctx.guild.get_channel(menu.channel_id)
             return await channel.fetch_message(menu.message_id)
         else:
             if channel:
                 return await channel.fetch_message(message_id)
             else:
                 return await ctx.message.channel.fetch_message(message_id)
     except discord.HTTPException:
         raise BadArgument(
             "That message does not exist or is not in this channel!")
示例#23
0
 async def locknickname(self, ctx, member: discord.Member, *, name: str):
     """Locks a members nickname to a particular string, in essence revoking nickname change perms"""
     try:
         await member.edit(nick=name)
     except discord.Forbidden:
         raise BadArgument(f"Dozer is not elevated high enough to change {member}'s nickname")
     lock = NicknameLock(
         guild_id=ctx.guild.id,
         member_id=member.id,
         locked_name=name,
         timeout=time.time()
     )
     await lock.update_or_add()
     e = discord.Embed(color=blurple)
     e.add_field(name='Success!', value=f"**{member}**'s nickname has been locked to **{name}**")
     e.set_footer(text='Triggered by ' + ctx.author.display_name)
     await ctx.send(embed=e)
示例#24
0
	async def convert(self, ctx, arg):
		try:
			return await super().convert(ctx, arg)
		except BadArgument as e:
			roles = ctx.guild.roles if ctx.guild else []
			for r in roles:
				name = r.name
				# Remove characters like emojis for better matching
				for c in [c for c in name if not ctx.bot.isascii(c)]:
					name = name.replace(c, '')
				if fuzz.ratio(arg.lower(), name.strip().lower()) >= 80:
					return r
			# If we get here, either there's no role that matches it or fuzzy wuzzy wasn't a woman so let's just try utils.find
			match = utils.find(lambda r: r.name.lower() == arg.lower(), ctx.guild.roles)
			if match == None:
				raise BadArgument('Role not found.')
			return match
示例#25
0
    def __init__(self, argument):
        now = datetime.utcnow()
        dt, status = self.calendar.parseDT(argument, sourceTime=now)
        if not status.hasDateOrTime:
            raise BadArgument(
                'L\'orario specificato non è valido, prova per esempio "tomorrow" oppure "3 days".'
            )

        if not status.hasTime:
            # replace it with the current time
            dt = dt.replace(hour=now.hour,
                            minute=now.minute,
                            second=now.second,
                            microsecond=now.microsecond)

        self.dt = dt
        self._past = dt < now
示例#26
0
    def from_str(cls,
                 arg: str,
                 platform_list: Sequence[str] = None) -> Platform:
        """Return a Platform instance.

        Args:
            arg: A platform name.
            platform_list: A List of all platforms as strings.

        """
        arg_lower = arg.lower()
        if platform_list is not None and arg_lower in platform_list:
            return cls(value=arg_lower, platform_list=platform_list)
        elif arg_lower in cls.default_list:
            return cls(value=arg_lower)
        else:
            raise BadArgument(f"Can't find {arg_lower} platform, sorry!")
示例#27
0
    async def convert(ctx: Context, tag_content: str) -> str:
        """
        Ensure tag_content is non-empty and contains at least one non-whitespace character.

        If tag_content is valid, return the stripped version.
        """
        tag_content = tag_content.strip()

        # The tag contents should not be empty, or filled with whitespace.
        if not tag_content:
            log.warning(
                f"{ctx.author} tried to create a tag containing only whitespace. "
                "Rejecting the request.")
            raise BadArgument(
                "Tag contents should not be empty, or filled with whitespace.")

        return tag_content
示例#28
0
	async def team(self, ctx, team_num: int):
		"""Get information on an FRC team by number."""
		team_data = self.parser.get_team(team_num)
		try:
			getattr(team_data, "Errors")
		except tbapi.InvalidKeyError:
			e = discord.Embed(color=blurple)
			e.set_author(name='FIRST® Robotics Competition Team {}'.format(team_num), url='https://www.thebluealliance.com/team/{}'.format(team_num), icon_url='http://i.imgur.com/V8nrobr.png')
			e.add_field(name='Name', value=team_data.nickname)
			e.add_field(name='Rookie Year', value=team_data.rookie_year)
			e.add_field(name='Location', value='{0.city}, {0.state_prov} {0.postal_code}, {0.country}'.format(team_data))
			e.add_field(name='Website', value=team_data.website)
			e.add_field(name='TBA Link', value='https://www.thebluealliance.com/team/{}'.format(team_num))
			e.set_footer(text='Triggered by ' + ctx.author.display_name)
			await ctx.send(embed=e)
		else:
			raise BadArgument("Couldn't find data for team {}".format(team_num))
示例#29
0
    async def convert(self, ctx: Context, duration: str) -> relativedelta:
        """
        Converts a `duration` string to a relativedelta object.

        The converter supports the following symbols for each unit of time:
        - years: `Y`, `y`, `year`, `years`
        - months: `m`, `month`, `months`
        - weeks: `w`, `W`, `week`, `weeks`
        - days: `d`, `D`, `day`, `days`
        - hours: `H`, `h`, `hour`, `hours`
        - minutes: `M`, `minute`, `minutes`
        - seconds: `S`, `s`, `second`, `seconds`

        The units need to be provided in descending order of magnitude.
        """
        if not (delta := parse_duration_string(duration)):
            raise BadArgument(f"`{duration}` is not a valid duration string.")
示例#30
0
    def __init__(self, argument):
        now = datetime.utcnow()
        dt, status = self.calendar.parseDT(argument, sourceTime=now)
        if not status.hasDateOrTime:
            raise BadArgument(
                'Tiempo inválido proveído, intenta con "tomorrow" o con "3 days".'
            )

        if not status.hasTime:
            # replace it with the current time
            dt = dt.replace(hour=now.hour,
                            minute=now.minute,
                            second=now.second,
                            microsecond=now.microsecond)

        self.dt = dt
        self._past = dt < now