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
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]
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." )
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
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!")
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))
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
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
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}`.')
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)
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)
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)
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
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)
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))
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)
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}")
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.")
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]
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
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!")
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)
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
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
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!")
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
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))
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.")
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