Пример #1
0
    async def update_guild_prefix(self, ctx, prefix):
        """Updates the command prefix for the Discord server.

        .. Note::
            Requires `administrator` privilege.

        :param ctx: The invocation context.
        :param prefix: The command prefix to update to.
        """
        user = DiscordUser(ctx.author)
        if len(prefix) > 3:
            embed = quickembed.error(
                desc='Prefix can not be longer than 3 characters', user=user)
        else:
            user.update_guild_info(ctx.guild, prefix)
            stored_prefix = user.guild_info(ctx.guild.id)['prefix']
            if prefix == stored_prefix:
                embed = quickembed.success(
                    desc='Prefix updated to **{}**'.format(stored_prefix),
                    user=user,
                )
            else:
                embed = quickembed.error(desc='Failed to update prefix',
                                         user=user)
        await ctx.send(embed=embed)
Пример #2
0
    async def unmute_member(self, ctx, member: discord.Member):
        """Unmutes a member by removing their `Muted` role.

        .. Note::
            Requires `Manage Roles` privilege.

        .. Note::
            A `Muted` role must exist with the proper permissions.
            It's a simple role that can only read the channels and not send messages.

        :param ctx: The invocation context.
        :param member:
        """
        user = DiscordUser(ctx.author)
        role = discord.utils.find(lambda r: r.name == 'Muted', ctx.guild.roles)
        if not role:
            embed = quickembed.error(desc='`Muted` role does not exist',
                                     user=user)
        elif role in member.roles:
            await member.remove_roles(role)
            embed = quickembed.success(desc='Unmuted {}'.format(member),
                                       user=user)
        else:
            embed = quickembed.error(
                desc='{} is already unmuted'.format(member), user=user)
        await ctx.send(embed=embed)
Пример #3
0
    async def rate_match(self, ctx, *args):
        """Adds a 0-5 star rating to a `Match`.

        .. Note:
            If no `match_id` is provided, the rating will be added to the most recently closed `Match`.

        :param ctx: The invocation context.
        :param args: Must be either `[rating]` or `[match_id] [rating]`. Rating must be between 0-5.
        :return:
        """
        user = DiscordUser(ctx.author)
        try:
            if len(args) == 1:
                match_id = None
                rating = float(args[0])
            else:
                match_id = int(args[0])
                rating = float(args[1])
        except Exception:
            msg = ('Invalid `!rate` command\n'
                   '`!rate [rating]` (rates last match)\n'
                   '`!rate [match_id] [rating]`')
            embed = quickembed.error(desc=msg, user=user)
            await ctx.send(embed=embed)
            return
        if not match_id:
            rows = user.search_match_by_recent_completed()
            if not rows:
                msg = 'No current match set to rate'
                embed = quickembed.error(desc=msg, user=user)
                await ctx.send(embed=embed)
                return
            match_id = rows[0].id
        response = user.rate_match(match_id, rating)
        if response['success']:
            match = Match(match_id)
            stars = ''
            for i in range(1, 6):
                if rating >= i:
                    stars += '★'
                else:
                    stars += '☆'
            msg = 'Rated `Match {}` {} ({})\n{}'.format(
                match_id, stars, rating, match.info_text_short())
            embed = quickembed.success(desc=msg, user=user)
        else:
            msg = response['message']
            embed = quickembed.error(desc=msg, user=user)
        await ctx.send(embed=embed)
Пример #4
0
    async def open_matches(self, ctx):
        """Lists the available `Match`es to bet on.

        .. Note:
            If the number of available `Match`es exceeds 5, they will be displayed with their `short view`.
            If it does not exceed 5, their full details will be displayed as individual messages.

        :param ctx: The invocation context.
        """
        user = DiscordUser(ctx.author)
        rows = user.search_match_by_open_bets()
        if len(rows) > 5:
            embed = quickembed.info(
                desc='Short View - Use `!match [id]` for full view')
            embed.set_author(name='Open Bet Matches')
            for row in rows:
                match = Match(row.id)
                embed.add_field(
                    name='[Match {}]'.format(match.id),
                    value='{}'.format(match.info_text_short()),
                    inline=True,
                )
            await ctx.send(embed=embed)
        elif len(rows) > 0:
            for row in rows:
                await ctx.send(embed=Match(row.id).info_embed())
        else:
            await ctx.send(embed=quickembed.error(
                desc='No open bet matches available', user=user))
Пример #5
0
    async def register_user(self, ctx):
        """Registers the Discord user and provides a response.

        If the user is already registered, they will be notified. Otherwise, a confirmation request is created before
        registering the account. The user will have 15 seconds to respond with a `[Y/N]`. If `[Y]`, the account will
        attempt to register, the response is then delivered. If `[N]`, the request is cancelled.

        :param ctx: The invocation context.
        """
        embed = None
        user = DiscordUser(ctx.author)
        if user.is_registered():
            embed = quickembed.success(
                desc='Your Discord is already registered', user=user)
        else:
            text_question = (
                '[Y/N]\nYour Discord is not linked to an existing '
                'Matches account (http://idleuser.com/projects/matches)\n'
                'Would you like to register a new account?')
            embed_question = quickembed.question(user=user, desc=text_question)
            await ctx.send(embed=embed_question)
            confirm = await self.bot.wait_for('message',
                                              check=checks.confirm(ctx.author),
                                              timeout=15.0)
            confirm.content = confirm.content.upper()
            if confirm.content == 'Y':
                response = user.register()
                if response['success']:
                    user.refresh()
                    embed = quickembed.success(desc=response['message'],
                                               user=user)
                    logger.info('`{}` registered'.format(user.username))
                else:
                    embed = quickembed.error(desc=response['message'],
                                             user=user)
                    logger.warning('`{}` failed to register - {}'.format(
                        user.username, response['message']))
            elif confirm.content == 'N':
                embed = quickembed.error(user=user,
                                         desc='Account registration cancelled')
        if embed:
            await ctx.send(embed=embed)
Пример #6
0
    async def recent_match_info(self, ctx):
        """Displays details for the last completed `Match`.

        :param ctx: The invocation context.
        """
        user = DiscordUser(ctx.author)
        rows = user.search_match_by_recent_completed()
        if rows:
            embed = Match(rows[0].id).info_embed()
        else:
            embed = quickembed.error(desc='No match found', user=user)
        await ctx.send(embed=embed)
Пример #7
0
    async def match_info(self, ctx, match_id=None):
        """Display info the `Match`.

        :param ctx: The invocation context.
        :param match_id: The `Match` id.
        """
        user = DiscordUser(ctx.author)
        try:
            match_id = int(match_id)
        except Exception as e:
            match_id = None
            logger.debug('match_info: {}'.format(e))
            msg = 'Invalid `!match` command\n`!match [match_id]`'
            await ctx.send(embed=quickembed.error(desc=msg, user=user))
        if match_id:
            rows = user.search_match_by_id(match_id)
            if rows:
                await ctx.send(embed=Match(rows[0].id).info_embed())
            else:
                await ctx.send(embed=quickembed.error(
                    desc='Match `{}` not found'.format(match_id), user=user))
Пример #8
0
    async def superstar_tweets(self, ctx, name, limit=1):
        """Displays the last tweets a Superstar has posted.

        .. note::
            A 30 seconds timer is set to prevent spamming.

        :param ctx: The invocation context.
        :param name: The name of the `Superstar` to search for.
        :param limit: The amount of messages to get. Must be 1-5. Default is 1.
        """
        user = DiscordUser(ctx.author)
        embed = None
        try:
            limit = 1 if limit < 1 else limit
            limit = 5 if limit > 5 else limit
        except Exception as e:
            logger.debug('superstar_tweets:{}'.format(e))
            embed = quickembed.error(
                desc='Invalid `!tweets` command\n`!tweets [superstar]`', user=user
            )
        if not embed:
            rows = user.search_superstar_by_name(name)
            if not rows:
                embed = quickembed.error(
                    desc='Unable to find superstar `{}`'.format(name), user=user
                )
                await ctx.send(embed=embed)
            else:
                superstar = Superstar(rows[0].id)
                if superstar.twitter_id:
                    tweets = self.latest_tweets(superstar.twitter_id, limit)
                    for tweet in tweets:
                        await ctx.send(
                            'https://twitter.com/statuses/{}'.format(tweet.id)
                        )
                else:
                    embed = quickembed.error(
                        desc='Unable to find Tweets for `{}`'.format(superstar.name),
                    )
        await ctx.send(embed=embed)
Пример #9
0
    async def user_join_royalrumble(self, ctx):
        """TODO: Enters the user into the current Royal Rumble event by providing them an entry number.

        :param ctx: The invocation context.
        """
        user = DiscordUser(ctx.author)
        response = user.join_royalrumble()
        if response['success']:
            embed = quickembed.success(desc='Entry Number: `{}`'.format(
                response['message']),
                                       user=user)
        else:
            embed = quickembed.error(desc=response['message'], user=user)
        await ctx.send(embed=embed)
Пример #10
0
    async def superstar_info(self, ctx, *, name):
        """Displays the `Superstar`'s information.

        .. Note:
            If the `name` matches multiple `Superstar`s, a list of the matching `Superstar`s is presented.
            The requester would then have to select one of the options available.

        :param ctx: The invocation context.
        :param name: The name of the `Superstar`.
        """
        user = DiscordUser(ctx.author)
        superstar_list = user.search_superstar_by_name(name)
        if not superstar_list:
            embed = quickembed.error(
                desc="Unable to find Superstars matching '{}'".format(name),
                user=user)
        else:
            if len(superstar_list) > 1:
                msg = 'Select Superstar from List ...\n```'
                for i, e in enumerate(superstar_list):
                    msg = msg + '{}. {}\n'.format(i + 1, e.name)
                msg = msg + '```'
                await ctx.send(embed=quickembed.question(desc=msg, user=user))
                response = await self.bot.wait_for('message',
                                                   check=checks.is_number(
                                                       ctx.author),
                                                   timeout=15.0)
                try:
                    index = int(response.content)
                    embed = Superstar(superstar_list[index -
                                                     1].id).info_embed()
                except (ValueError, IndexError):
                    embed = quickembed.error(desc='Invalid index', user=user)
            else:
                embed = Superstar(superstar_list[0].id).info_embed()
        await ctx.send(embed=embed)
Пример #11
0
    async def add_discord_command(self, ctx, command, *, response):
        """Inserts a quick chatroom command.

        :param ctx: The invocation context.
        :param command: The command name to add.
        :param response: The response for the command.
        """
        user = DiscordUser(ctx.author)
        command = '!{}'.format(command.strip('!'))
        res = user.add_chatroom_command(command, response)
        if res['success']:
            embed = quickembed.success(
                desc='Command `{}` updated'.format(command), user=user)
        else:
            embed = quickembed.error(desc='Failed', user=user)
        await ctx.send(embed=embed)
Пример #12
0
    async def change_volume(self, ctx, volume: int):
        """Updates the current audio player's volume.

        .. Note::
            The volume received is divided by 100 because the player's volume value must be a float
            between 0 and 1. Think of the input as a percentage.

        :param ctx: The invocation context.
        :param volume: The percentage of the audio. Should be 0-100.
        """
        user = DiscordUser(ctx.author)
        if ctx.voice_client is None:
            await ctx.send(embed=quickembed.error(
                desc='Not connected to a voice channel', user=user))
        ctx.voice_client.source.volume = volume / 100
        await ctx.send(embed=quickembed.info(
            desc='Changed volume to {}%'.format(volume), user=user))
Пример #13
0
    async def update_discord_command(self, ctx, command, *, response):
        """Updates a quick chatroom command.

        .. Note::
            Only the bot owner can use this.

        :param ctx: The invocation context.
        :param command: The command name to update.
        :param response: The updated response for the command.
        """
        user = DiscordUser(ctx.author)
        command = '!{}'.format(command.strip('!'))
        res = user.update_chatroom_command(command, response)
        if res['success']:
            embed = quickembed.success(
                desc='Command `{}` updated'.format(command), user=user)
        else:
            embed = quickembed.error(desc='Failed', user=user)
        await ctx.send(embed=embed)
Пример #14
0
    async def ensure_voice(self, ctx):
        """Checks if the voice channel can be started.

        .. Note::
            * The requester must be in a voice channel.
            * Stops a current player if it currently exists.

        :param ctx: The invocation context.
        """
        if ctx.voice_client is None:
            if ctx.author.voice:
                await ctx.author.voice.channel.connect()
            else:
                await ctx.send(embed=quickembed.error(
                    desc='You must be in a voice channel to use that command',
                    user=DiscordUser(ctx.author),
                ))
                raise commands.CommandError(
                    'Author not connected to a voice channel')
        elif ctx.voice_client.is_playing():
            ctx.voice_client.stop()
Пример #15
0
    async def scheduler_pending(self, ctx):
        """Displays a list of pending alert messages.

        .. note::
            Only the bot owner can use this.

        :param ctx: The invocation context.
        """
        if self.scheduled_payloads.items():
            user = DiscordUser(ctx.author)
            embed = quickembed.info(desc="Today's Scheduled Alerts (PT)",
                                    user=user)
            embed.add_field(
                name='\u200b',
                value='\n'.join([
                    '{1} - **{0}**'.format(k, v['task_datetime'])
                    for k, v in self.scheduled_payloads.items()
                ]),
            )
        else:
            embed = quickembed.error(desc='Nothing scheduled for today')
        await ctx.send(embed=embed)
Пример #16
0
    async def user_current_bets(self, ctx):
        """Displays the user's current bets for `Match`es.

        :param ctx: The invocation context.
        """
        user = DiscordUser(ctx.author)
        bets = user.current_bets()
        if bets:
            msg = "```{}```".format('\n'.join([
                'Match {}\n\t{:,} points on {}\n\t'
                'Potential Winnings: {:,} ({}%)'.format(
                    bet['match_id'],
                    bet['points'],
                    bet['contestants'],
                    bet['potential_cut_points'],
                    bet['potential_cut_pct'] * 100,
                ) for bet in bets
            ]))
            embed = quickembed.general(desc='Current Bets', user=user)
            embed.add_field(name='\u200b', value=msg, inline=False)
        else:
            embed = quickembed.error(desc='No current bets placed', user=user)
        await ctx.send(embed=embed)
Пример #17
0
async def on_command_error(ctx, error):
    """Called when an error through a command occurs. Common instances are handled appropriately.

    If error is not handled, the error is raised.

    :param ctx: The invocation context.
    :param error: The command error.
    """
    msg = None
    if isinstance(error, commands.CommandNotFound):
        return
    elif isinstance(error, commands.CommandOnCooldown):
        msg = 'Slow down! Try again in {:.1f} seconds.'.format(
            error.retry_after)
    elif isinstance(error, GuildNotOriginError):
        logger.error('GuildNotOriginError: {0.command} - '
                     '{0.guild.name}(0.guild.id) - '
                     '{0.author}'.format(ctx))
        return
    elif isinstance(error, UserNotRegisteredError):
        msg = (
            'Your Discord is not linked to an existing Matches account.\n'
            'Use `!register` or visit http://idleuser.com/projects/matches to link '
            'to your existing account.')
    elif isinstance(error, commands.CommandError):
        logger.error('CommandError: {0} - '
                     '{1.guild.name}({1.guild.id}) - '
                     '{1.author} - {1.command}'.format(error, ctx))
        return
    elif isinstance(error, commands.CommandInvokeError):
        if isinstance(error.original, asyncio.TimeoutError):
            msg = 'Took too long to confirm. Try again.'
    if msg:
        await ctx.send(
            embed=quickembed.error(desc=msg, user=DiscordUser(ctx.author)))
    else:
        raise error
Пример #18
0
    async def donate_bucks(self, ctx, amount: int, member: discord.Member):
        """Sends another user FJBucks from their own wallet.

        .. Important::
            Work in progress.

        :param ctx: The invocation context.
        :param amount: The amount of FJBucks to send
        :param member: The Discord member to send to.
        """
        user = DiscordUser(ctx.author)
        recipient = DiscordUser(member)
        if not recipient.is_registered():
            embed = quickembed.error(desc='{} is not registered'.format(
                recipient.name),
                                     user=user)
        else:
            recipient.fjbucks_transaction(amount, 'owner authorized')
            embed = quickembed.success(
                desc='Donated **{} FJBucks** to {}'.format(
                    amount, recipient.name),
                user=user,
            )
        await ctx.send(embed=embed)
Пример #19
0
    async def place_match_bet(self, ctx, *args):
        """Places a `Match` bet.

        .. Note:
            A bet requires:
            * The `bet amount`
            * The `match_id`
            * The `team`
            The user can provide them sequentially:
                !bet [bet_amount] [match_id] [team]
            Or they can insert a `Superstar`'s name (`Match` contestant):
                 !bet [bet_amount] [contestant]

            The `match_id` and `team` is found by cross-referencing the `Superstar` name with open-bet `Match`
            contestants.

        :param ctx: The invocation context.
        :param args: Must be either `[bet_amount] [match_id] [team]` or `[bet_amount] [contestant]`
        """
        user = DiscordUser(ctx.author)
        bet = None
        match_id = None
        team = None
        superstar_name = None
        try:
            bet = int(args[0].replace(',', ''))
            if len(args) == 3 and args[1].isdigit() and args[2].isdigit():
                match_id = int(args[1])
                team = int(args[2])
            elif len(args) > 1:
                superstar_name = ' '.join(args[1:])
                rows = user.search_match_by_open_bets_and_superstar_name(
                    superstar_name)
                match_id = rows[
                    0].id if rows else False  # use first match found
                if not match_id:
                    embed = quickembed.error(
                        desc='Unable to find an open match for contestant `{}`'
                        .format(superstar_name),
                        user=user,
                    )
                    await ctx.send(embed=embed)
                    return
            else:
                raise
        except Exception as e:
            logger.debug('place_match_bet: {}'.format(e))
            msg = ('Invalid `!bet` command\n'
                   '`!bet [bet_amount] [contestant]`\n'
                   '`!bet [bet_amount] [match_id] [team]`')
            await ctx.send(embed=quickembed.error(desc=msg, user=user))

            return
        match = Match(match_id)
        if not team and superstar_name:
            team = match.team_by_contestant(superstar_name)
        response = user.validate_bet(match_id, team, bet)
        if response['success']:
            question_embed = quickembed.question(desc='[Y/N] Place this bet?',
                                                 user=user)
            question_embed.add_field(name='Info',
                                     value=match.info_text_short(),
                                     inline=False)
            question_embed.add_field(name='Betting',
                                     value='{:,}'.format(bet),
                                     inline=True)
            question_embed.add_field(name='Betting On',
                                     value=match.teams[team]['members'],
                                     inline=True)
            await ctx.send(embed=question_embed)
            confirm = await self.bot.wait_for('message',
                                              check=checks.confirm(ctx.author),
                                              timeout=15.0)
            confirm.content = confirm.content.upper()
            if confirm.content == 'Y':
                response = user.place_bet(match_id, team, bet)
                if response['success']:
                    msg = 'Placed `{:,}` point bet on `{}`'.format(
                        bet, match.teams[team]['members'])
                    embed = quickembed.success(desc=msg, user=user)
                else:
                    embed = quickembed.error(desc=response['message'],
                                             user=user)
            elif confirm.content == 'N':
                embed = quickembed.error(desc='Bet cancelled', user=user)
        else:
            embed = quickembed.error(desc=response['message'], user=user)

        await ctx.send(embed=embed)