コード例 #1
0
 async def update_pushboard(self, guild_id):
     guild_config = await self.get_guild_config(guild_id)
     if not guild_config.updates_toggle:
         return
     if not guild_config.pushboard:
         return
     sql = "SELECT DISTINCT clan_tag FROM clans WHERE guild_id = $1"
     fetch = await self.bot.pool.fetch(sql, guild_id)
     clans = await self.bot.coc.get_clans((n[0] for n in fetch)).flatten()
     players = []
     for n in clans:
         players.extend(p for p in n.itermembers)
     sql = ("SELECT player_tag, current_trophies, current_attack_wins - starting_attack_wins AS attacks "
            "FROM players "
            "WHERE player_tag = ANY($1::TEXT[]) "
            "ORDER BY current_trophies "
            "LIMIT 100")
     fetch = await self.bot.pool.fetch(sql, [n.tag for n in players])
     db_players = [DatabasePlayer(bot=self.bot, record=n) for n in fetch]
     players = {n.tag: n for n in players if n.tag in set(x.player_tag for x in db_players)}
     message_count = math.ceil(len(db_players) / 20)
     messages = await self.get_updates_messages(guild_id, number_of_msg=message_count)
     if not messages:
         return
     for i, v in enumerate(messages):
         player_data = db_players[i * 20: (i + 1) * 20]
         table = CLYTable()
         for x, y in enumerate(player_data):
             index = i * 20 + x
             if guild_config.pushboard_render == 2:
                 table.add_row([index,
                                y.current_trophies,
                                players.get(y.player_tag, MockPlayer()).name])
             else:
                 table.add_row([index,
                                y.current_trophies,
                                y.attacks,
                                players.get(y.player_tag, MockPlayer()).name])
         fmt = table.render_option_2() if \
             guild_config.pushboard_render == 2 else table.render_option_1()
         e = discord.Embed(color=self.bot.color,
                           description=fmt,
                           timestamp=datetime.utcnow())
         e.set_author(name=guild_config.pushboard_title or "Trophy Push Leaderboard",
                      icon_url=guild_config.icon_url or "https://cdn.discordapp.com/emojis/"
                                                        "592028799768592405.png?v=1")
         e.set_footer(text="Last Updated")
         await v.edit(embed=e, content=None)
コード例 #2
0
    async def update_global_board(self):
        query = """SELECT player_tag, donations
                   FROM players 
                   WHERE season_id=$1
                   ORDER BY donations DESC NULLS LAST
                   LIMIT 100;
                """
        fetch_top_players = await self.bot.pool.fetch(
            query, await self.bot.seasonconfig.get_season_id())

        players = await self.bot.coc.get_players(
            (n[0] for n in fetch_top_players)).flatten()

        top_players = {
            n.tag: n
            for n in players
            if n.tag in set(x['player_tag'] for x in fetch_top_players)
        }

        messages = await self.get_board_messages(663683345108172830,
                                                 number_of_msg=5)
        if not messages:
            return

        for i, v in enumerate(messages):
            player_data = fetch_top_players[i * 20:(i + 1) * 20]
            table = CLYTable()

            for x, y in enumerate(player_data):
                index = i * 20 + x
                table.add_row(
                    [index, y[1],
                     top_players.get(y['player_tag'], mock).name])

            fmt = table.donationboard_2()

            e = discord.Embed(colour=self.bot.colour,
                              description=fmt,
                              timestamp=datetime.utcnow())
            e.set_author(name="Global Donationboard",
                         icon_url=self.bot.user.avatar_url)
            e.set_footer(text='Last Updated')
            await v.edit(embed=e, content=None)
コード例 #3
0
    async def remove_event(self, ctx, *, event_name: str = None):
        """Removes a currently running event.

        **Parameters**
        :key: The event name to remove.

        **Format**
        :information_source: `+remove event EVENT_NAME`

        **Example**
        :white_check_mark: `+remove event my special event`

        **Required Permissions**
        :warning: Manage Server
        """
        if event_name:
            # Event name provided
            query = """DELETE FROM events
                       WHERE guild_id = $1 
                       AND event_name = $2
                       RETURNING id;
                    """
            fetch = await self.bot.pool.fetchrow(query, ctx.guild.id,
                                                 event_name)
            if fetch:
                return await ctx.send(f"{event_name} has been removed.")

        # No event name provided or I didn't understand the name I was given
        query = """SELECT id, event_name, start 
                   FROM events
                   WHERE guild_id = $1 
                   ORDER BY start"""
        fetch = await self.bot.pool.fetch(query, ctx.guild.id)
        if len(fetch) == 0 or not fetch:
            return await ctx.send(
                "I have no events to remove. You should create one... then remove it."
            )
        elif len(fetch) == 1:
            query = "DELETE FROM events WHERE id = $1"
            await ctx.db.execute(query, fetch[0]['id'])
            return await ctx.send(f"{fetch[0]['event_name']} has been removed."
                                  )

        table = CLYTable()
        fmt = f"Events on {ctx.guild}:\n\n"
        reactions = []
        counter = 0
        for event in fetch:
            days_until = event['start'].date() - datetime.datetime.utcnow(
            ).date()
            table.add_row([counter, days_until.days, event['event_name']])
            counter += 1
            reactions.append(f"{counter}\N{combining enclosing keycap}")
        render = table.events_list()
        fmt += f'{render}\n\nPlease select the reaction that corresponds with the event you would ' \
               f'like to remove.'
        e = discord.Embed(colour=self.bot.colour, description=fmt)
        msg = await ctx.send(embed=e)
        for r in reactions:
            await msg.add_reaction(r)

        def check(r, u):
            return str(
                r
            ) in reactions and u.id == ctx.author.id and r.message.id == msg.id

        try:
            r, u = await self.bot.wait_for('reaction_add',
                                           check=check,
                                           timeout=60.0)
        except asyncio.TimeoutError:
            await msg.clear_reactions()
            return await ctx.send(
                "We'll just hang on to all the events we have for now.")

        index = reactions.index(str(r))
        query = "DELETE FROM events WHERE id = $1"
        await ctx.db.execute(query, fetch[index]['id'])
        await msg.delete()
        ctx.bot.utils.event_config.invalidate(ctx.bot.utils, ctx.guild.id)
        self.bot.dispatch('event_register')
        return await ctx.send(f"{fetch[index]['event_name']} has been removed."
                              )
コード例 #4
0
    async def get_board_fmt(self, guild_id, season_id, board_type):
        board_config = await self.bot.utils.get_board_configs(
            guild_id, board_type)
        if not board_config:
            board_config = SlimDummyBoardConfig(
                board_type, 2, f"{board_type.capitalize()}Board", None,
                'donations' if board_type == "donation" else "trophies")
        else:
            board_config = board_config[0]

        clans = await self.bot.get_clans(guild_id)

        players = []
        for n in clans:
            players.extend(p for p in n.itermembers)

        top_players = await self.bot.donationboard.get_top_players(
            players,
            board_type,
            board_config.sort_by,
            False,
            season_id=season_id)

        if not top_players:
            e = discord.Embed(colour=self.bot.colour, title='No Data Found.')
            return [e]

        players = {
            n.tag: n
            for n in players
            if n.tag in set(x['player_tag'] for x in top_players)
        }

        message_count = math.ceil(len(top_players) / 20)

        embeds = []
        for i in range(message_count):
            player_data = top_players[i * 20:(i + 1) * 20]
            table = CLYTable()

            for x, y in enumerate(player_data):
                index = i * 20 + x
                if board_config.render == 2:
                    table.add_row(
                        [index, y[1],
                         players.get(y['player_tag'], mock).name])
                else:
                    table.add_row([
                        index, y[1], y[2],
                        players.get(y['player_tag'], mock).name
                    ])

            render = get_render_type(board_config, table)
            fmt = render()

            e = discord.Embed(colour=self.bot.donationboard.get_colour(
                board_type, False),
                              description=fmt,
                              timestamp=datetime.utcnow())
            e.set_author(name=board_config.title,
                         icon_url=board_config.icon_url
                         or 'https://cdn.discordapp.com/'
                         'emojis/592028799768592405.png?v=1')
            e.set_footer(
                text=
                f'Historical {board_type.capitalize()}Board; Season {season_id} - Page {i+1}/{message_count}'
            )
            embeds.append(e)

        return embeds
コード例 #5
0
class TablePaginator(Pages):
    def __init__(self, ctx, data, title=None, page_count=1, rows_per_table=20, description=''):
        super().__init__(ctx, entries=[i for i in range(page_count)], per_page=1)
        self.table = CLYTable()
        self.data = [(i, v) for (i, v) in enumerate(data)]
        self.entries = [None for _ in range(page_count)]
        self.rows_per_table = rows_per_table
        self.title = title
        self.message = None
        self.ctx = ctx
        self.description = description
        if getattr(ctx, 'config', None):
            try:
                self.icon_url = ctx.config.icon_url or ctx.guild.icon_url
                self.title = ctx.config.title or title
            except AttributeError:
                self.icon_url = ctx.guild.icon_url
        else:
            self.icon_url = ctx.guild.icon_url

    async def get_page(self, page):
        try:
            entry = self.entries[page - 1]
            if entry:
                return entry
        except IndexError:
            pass

        if not self.message:
            self.message = await self.channel.send('Loading...')
        else:
            await self.message.edit(content='Loading...', embed=None)

        entry = await self.prepare_entry(page)
        self.entries[page - 1] = entry
        return self.entries[page - 1]

    async def prepare_entry(self, page):
        self.table.clear_rows()
        base = (page - 1) * self.rows_per_table
        data = self.data[base:base + self.rows_per_table]
        for n in data:
            self.table.add_row(n)

        render = get_render_type(self.ctx.config, self.table)
        return render()

    async def get_embed(self, entries, page, *, first=False):
        if self.maximum_pages > 1:
            if self.show_entry_count:
                text = f'Page {page}/{self.maximum_pages} ({len(self.entries)} entries)'
            else:
                text = f'Page {page}/{self.maximum_pages}'

            self.embed.set_footer(text=text)

        self.embed.description = self.description + entries

        self.embed.set_author(
            name=textwrap.shorten(self.title, width=240, placeholder='...'),
            icon_url=self.icon_url
        )

        return self.embed

    async def show_page(self, page, *, first=False):
        self.current_page = page
        entries = await self.get_page(page)
        embed = await self.get_embed(entries, page, first=first)

        if not self.message:
            self.message = await self.ctx.send("Loading...")

        if not self.paginating:
            return await self.message.edit(content=None, embed=embed)

        await self.message.edit(content=None, embed=embed)

        if not first:
            return

        for (reaction, _) in self.reaction_emojis:
            if self.maximum_pages == 2 and reaction in ('\u23ed', '\u23ee'):
                # no |<< or >>| buttons if we only have two pages
                # we can't forbid it if someone ends up using it but remove
                # it from the default set
                continue

            await self.message.add_reaction(reaction)
コード例 #6
0
    async def update_board(self, channel_id):
        config = await self.bot.utils.board_config(channel_id)

        if not config:
            return
        if not config.toggle:
            return
        if not config.channel:
            return

        if config.in_event:
            query = """SELECT DISTINCT clan_tag FROM clans WHERE channel_id=$1 AND in_event=$2"""
            fetch = await self.bot.pool.fetch(query, channel_id,
                                              config.in_event)
        else:
            query = "SELECT DISTINCT clan_tag FROM clans WHERE channel_id=$1"
            fetch = await self.bot.pool.fetch(query, channel_id)

        clans = await self.bot.coc.get_clans((n[0] for n in fetch)).flatten()

        players = []
        for n in clans:
            players.extend(p for p in n.itermembers)

        try:
            top_players = await self.get_top_players(players, config.type,
                                                     config.sort_by,
                                                     config.in_event)
        except:
            log.error(
                f"{clans} channelid: {channel_id}, guildid: {config.guild_id},"
                f" sort: {config.sort_by}, event: {config.in_event}, type: {config.type}"
            )
            return
        players = {
            n.tag: n
            for n in players
            if n.tag in set(x['player_tag'] for x in top_players)
        }

        message_count = math.ceil(len(top_players) / 20)

        messages = await self.get_board_messages(channel_id,
                                                 number_of_msg=message_count)
        if not messages:
            return

        for i, v in enumerate(messages):
            player_data = top_players[i * 20:(i + 1) * 20]
            table = CLYTable()

            for x, y in enumerate(player_data):
                index = i * 20 + x
                if config.render == 2:
                    table.add_row(
                        [index, y[1],
                         players.get(y['player_tag'], mock).name])
                else:
                    table.add_row([
                        index, y[1], y[2],
                        players.get(y['player_tag'], mock).name
                    ])

            render = get_render_type(config, table)
            fmt = render()

            e = discord.Embed(colour=self.get_colour(config.type,
                                                     config.in_event),
                              description=fmt,
                              timestamp=datetime.utcnow())
            e.set_author(name=f'Event in Progress!'
                         if config.in_event else config.title,
                         icon_url=config.icon_url
                         or 'https://cdn.discordapp.com/'
                         'emojis/592028799768592405.png?v=1')
            e.set_footer(text='Last Updated')
            await v.edit(embed=e, content=None)
コード例 #7
0
    async def edit_event(self, ctx, *, event_name: str = None):
        """Edit a variety of settings for the current event.

        **Parameters**
        :key: Event name

        **Format**
        :information_source: `+edit event EVENT_NAME`

        **Example**
        :white_check_mark: `+edit event Donation Bot Event`

        **Required Permissions**
        :warning: Manage Server
        """
        if event_name:
            query = """SELECT id FROM events 
                       WHERE guild_id = $1 
                       AND event_name = $2"""
            fetch = await self.bot.pool.fetchrow(query, ctx.guild.id, event_name)
            if fetch:
                event_id = fetch['id']
            else:
                # ideally this would just display a list of events and let the user pick, but I
                # couldn't figure out the proper sequence of if event_name/if event_id
                return await ctx.send("There is no event on this server with that name. Try `+edit event` "
                                      "to pick from a list of events on this server.")
        else:
            # No event name provided or I didn't understand the name I was given
            query = """SELECT id, event_name, start 
                               FROM events
                               WHERE guild_id = $1 
                               ORDER BY start"""
            fetch = await self.bot.pool.fetch(query, ctx.guild.id)
            if len(fetch) == 0 or not fetch:
                return await ctx.send("There are no events currently set up on this server. "
                                      "Try `+add event`")
            elif len(fetch) == 1:
                event_id = fetch[0]['id']
            else:
                table = CLYTable()
                fmt = f"Events on {ctx.guild}:\n\n"
                reactions = []
                counter = 0
                for event in fetch:
                    days_until = event['start'].date() - datetime.datetime.utcnow().date()
                    table.add_row([counter, days_until.days, event['event_name']])
                    counter += 1
                    reactions.append(f"{counter}\N{combining enclosing keycap}")
                render = table.events_list()
                fmt += f'{render}\n\nPlease select the reaction that corresponds with the event you would ' \
                       f'like to remove.'
                e = discord.Embed(colour=self.bot.colour,
                                  description=fmt)
                msg = await ctx.send(embed=e)
                for r in reactions:
                    await msg.add_reaction(r)

                def check(r, u):
                    return str(r) in reactions and u.id == ctx.author.id and r.message.id == msg.id

                try:
                    r, u = await self.bot.wait_for('reaction_add', check=check, timeout=60.0)
                except asyncio.TimeoutError:
                    await msg.clear_reactions()
                    return await ctx.send("I feel like I'm being ignored. MAybe try again later?")

                index = reactions.index(str(r))
                event_id = fetch[index]['id']

            # Now that we have the event_id, let's edit things
            query = """SELECT event_name, start, finish 
                       FROM events
                       WHERE id = $1"""
            event = await self.bot.pool.fetchrow(query, event_id)

            def check_author(m):
                return m.author == ctx.author

            answer = await ctx.prompt(f"Event Name: **{event['event_name']}**\n"
                                      f"Would you like to edit the event name?")
            if answer:
                try:
                    await ctx.send('Please enter the new name for this event.')
                    response = await ctx.bot.wait_for('message', check=check_author, timeout=60.0)
                    new_event_name = response.content
                except asyncio.TimeoutError:
                    new_event_name = event['event_name']
            else:
                new_event_name = event['event_name']
            answer = await ctx.prompt(f"Start Date: **{event['start'].date()}\n"
                                      f"Would you like to edit the date?")
            if answer:
                try:
                    await ctx.send('Please enter the new start date.  (YYYY-MM-DD)')
                    response = await ctx.bot.wait_for('message', check=check_author, timeout=60.0)
                    new_start_date = await DateConverter().convert(ctx, response.clean_content)
                except (ValueError, commands.BadArgument):
                    await ctx.send('Date must be in the YYYY-MM-DD format. I\'m going to keep '
                                   'the current start date and you can change it later if you like.')
                    new_start_date = event['start'].date()
                except asyncio.TimeoutError:
                    await ctx.send('Seems as though you don\'t really know the answer. I\'m just going '
                                   'to keep the date I have for now.')
                    new_start_date = event['start'].date()
            else:
                new_start_date = event['start'].date()
            answer = await ctx.prompt(f"Start Time: **{event['start'].time()}\n"
                                      f"Would you like to edit the time?")
            if answer:
                try:
                    await ctx.send('Please enter the new start time. (Please provide HH:MM in UTC)')
                    response = await ctx.bot.wait_for('message', check=check_author, timeout=60.0)
                    hour, minute = map(int, response.content.split(':'))
                    if hour < 13:
                        try:
                            await ctx.send('And is that AM or PM?')
                            response = await ctx.bot.wait_for('message', check=check_author, timeout=60.0)
                            if response.content.lower() == 'pm':
                                hour += 12
                        except asyncio.TimeoutError:
                            if hour < 6:
                                await ctx.send('Well I\'ll just go with PM then.')
                                hour += 12
                            else:
                                await ctx.send('I\'m going to assume you want AM.')
                    new_start_time = datetime.time(hour, minute)
                except asyncio.TimeoutError:
                    await ctx.send('Time\'s up my friend. Start time will remain the same!')
                    new_start_time = event['start'].time()
            else:
                new_start_time = event['start'].time()
            answer = await ctx.prompt(f"End Date: **{event['finish'].date()}\n"
                                      f"Would you like to edit the date?")
            if answer:
                try:
                    await ctx.send('Please enter the new end date.  (YYYY-MM-DD)')
                    response = await ctx.bot.wait_for('message', check=check_author, timeout=60.0)
                    new_end_date = await DateConverter().convert(ctx, response.clean_content)
                except (ValueError, commands.BadArgument):
                    await ctx.send('Date must be in the YYYY-MM-DD format. I\'m going to keep '
                                   'the current end date and you can change it later if you like.')
                    new_end_date = event['finish'].date()
                except asyncio.TimeoutError:
                    await ctx.send('Seems as though you don\'t really know the answer. I\'m just going '
                                   'to keep the date I have for now.')
                    new_end_date = event['finish'].date()
            else:
                new_end_date = event['finish'].date()
            answer = await ctx.prompt(f"End Time: **{event['finish'].time()}\n"
                                      f"Would you like to edit the time?")
            if answer:
                try:
                    await ctx.send('Please enter the new end time. (Please provide HH:MM in UTC)')
                    response = await ctx.bot.wait_for('message', check=check_author, timeout=60.0)
                    hour, minute = map(int, response.content.split(':'))
                    if hour < 13:
                        try:
                            await ctx.send('And is that AM or PM?')
                            response = await ctx.bot.wait_for('message', check=check_author, timeout=60.0)
                            if response.content.lower() == 'pm':
                                hour += 12
                        except asyncio.TimeoutError:
                            if hour < 6:
                                await ctx.send('Well I\'ll just go with PM then.')
                                hour += 12
                            else:
                                await ctx.send('I\'m going to assume you want AM.')
                    new_end_time = datetime.time(hour, minute)
                except asyncio.TimeoutError:
                    await ctx.send('Time\'s up my friend. Start time will remain the same!')
                    new_end_time = event['finish'].time()
            else:
                new_end_time = event['finish'].time()

            # Assemble answers and update db
            new_start = datetime.datetime.combine(new_start_date, new_start_time)
            new_finish = datetime.datetime.combine(new_end_date, new_end_time)
            query = """UPDATE events 
                       SET event_name = $1, start = $2, finish = $3 
                       WHERE id = $4"""
            await ctx.db.execute(query, new_event_name, new_start, new_finish, event_id)

            fmt = (f'**Event Info:**\n\n{new_event_name}\n{new_start.strftime("%d %b %Y %H:%M")}\n'
                   f'{new_finish.strftime("%d %b %Y %H:%M")}')
            e = discord.Embed(colour=discord.Colour.green(),
                              description=fmt)
            await ctx.send(embed=e)
            self.bot.dispatch('event_register')