예제 #1
0
    def __init__(self, source, **kwargs):
        EmojiB = namedtuple("EmojiB", "emoji position explain")
        help_dict_emoji = {'\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\ufe0f':
                           EmojiB("<:before_fast_check:754948796139569224>", First(0),
                                  "Goes to the first page."),

                           '\N{BLACK LEFT-POINTING TRIANGLE}\ufe0f':
                           EmojiB("<:before_check:754948796487565332>", First(1),
                                  "Goes to the previous page."),

                           '\N{BLACK RIGHT-POINTING TRIANGLE}\ufe0f':
                           EmojiB("<:next_check:754948796361736213>", Last(1),
                                  "Goes to the next page."),

                           '\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\ufe0f':
                           EmojiB("<:next_fast_check:754948796391227442>", Last(2),
                                  "Goes to the last page."),

                           '\N{BLACK SQUARE FOR STOP}\ufe0f':
                           EmojiB("<:stop_check:754948796365930517>", Last(0),
                                  "Remove this message."),

                           '<:information_pp:754948796454010900>':
                           EmojiB("<:information_pp:754948796454010900>", Last(4),
                                  "Shows this infomation message.")}
        super().__init__(source, dict_emoji=help_dict_emoji, **kwargs)
예제 #2
0
class MyPagesMenu(MenuPages, inherit_buttons=False):
    def __init__(self, source, **kwargs):
        super().__init__(source,
                         clear_reactions_after=True,
                         timeout=120.0,
                         **kwargs)

    def _skip_double_triangle_buttons(self):
        max_pages = self._source.get_max_pages()
        if max_pages is None:
            return True
        return max_pages <= 2

    @button(cfg['EMOJIS'].get(
        'FIRST_PAGE',
        '\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\ufe0f'),
            position=First(0),
            skip_if=_skip_double_triangle_buttons)
    async def go_to_first_page(self, payload):
        """go to the first page"""
        await self.show_page(0)

    @button(cfg['EMOJIS'].get('PREVIOUS_PAGE',
                              '\N{BLACK LEFT-POINTING TRIANGLE}\ufe0f'),
            position=First(1))
    async def go_to_previous_page(self, payload):
        """go to the previous page"""
        await self.show_checked_page(self.current_page - 1)

    @button(cfg['EMOJIS'].get('NEXT_PAGE',
                              '\N{BLACK RIGHT-POINTING TRIANGLE}\ufe0f'),
            position=Last(1))
    async def go_to_next_page(self, payload):
        """go to the next page"""
        await self.show_checked_page(self.current_page + 1)

    @button(cfg['EMOJIS'].get(
        'LAST_PAGE',
        '\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\ufe0f'),
            position=Last(2),
            skip_if=_skip_double_triangle_buttons)
    async def go_to_last_page(self, payload):
        """go to the last page"""
        # The call here is safe because it's guarded by skip_if
        await self.show_page(self._source.get_max_pages() - 1)

    @button(cfg['EMOJIS'].get('STOP_PAGES', '\N{BLACK SQUARE FOR STOP}\ufe0f'),
            position=Last(0))
    async def stop_pages(self, payload):
        """stops the pagination session."""
        self.stop()
예제 #3
0
class BaseMenu(menus.views.ViewMenuPages):
    def __init__(self, source, **kwargs):
        # to not allow spamming of certain buttons
        self.lock = asyncio.Lock()
        super().__init__(source, **kwargs)
        self.default_emojis = (
            "\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\ufe0f",
            "\N{BLACK LEFT-POINTING TRIANGLE}\ufe0f",
            "\N{BLACK RIGHT-POINTING TRIANGLE}\ufe0f",
            "\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\ufe0f",
            "\N{BLACK SQUARE FOR STOP}\ufe0f")

        for emoji in self.buttons:
            if emoji.name not in self.default_emojis:
                continue
            self.remove_button(emoji)

    # buttons for pagination

    @button(DRIGHT_POINT,
            position=First(0),
            skip_if=menus.MenuPages._skip_double_triangle_buttons)
    async def go_to_first_page(self, payload):
        """go to the first page"""
        await self.show_page(0)

    @button(LEFT_POINT, position=First(1))
    async def go_to_previous_page(self, payload):
        """go to the previous page"""
        await self.show_checked_page(self.current_page - 1)

    @button(RIGHT_POINT, position=Last(0))
    async def go_to_next_page(self, payload):
        """go to the next page"""
        await self.show_checked_page(self.current_page + 1)

    @button(DLEFT_POINT,
            position=Last(1),
            skip_if=menus.MenuPages._skip_double_triangle_buttons)
    async def go_to_last_page(self, payload):
        """go to the last page"""
        # The call here is safe because it's guarded by skip_if
        await self.show_page(self._source.get_max_pages() - 1)

    @button(STOP, position=Last(2))
    async def stop_pages(self, payload):
        """stops the pagination session."""
        self.stop()
예제 #4
0
    def __init__(self, source, dict_emoji=None, **kwargs):
        super().__init__(source,
                         delete_message_after=kwargs.pop(
                             'delete_message_after', True),
                         **kwargs)
        self.info = False

        # Remind me to redo this dumb code
        EmojiB = namedtuple("EmojiB", "emoji position explain")
        def_dict_emoji = {
            '\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\ufe0f':
            EmojiB("<:before_fast_check:754948796139569224>", First(0),
                   "Goes to the first page."),
            '\N{BLACK LEFT-POINTING TRIANGLE}\ufe0f':
            EmojiB("<:before_check:754948796487565332>", First(1),
                   "Goes to the previous page."),
            '\N{BLACK RIGHT-POINTING TRIANGLE}\ufe0f':
            EmojiB("<:next_check:754948796361736213>", Last(1),
                   "Goes to the next page."),
            '\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\ufe0f':
            EmojiB("<:next_fast_check:754948796391227442>", Last(2),
                   "Goes to the last page."),
            '\N{BLACK SQUARE FOR STOP}\ufe0f':
            EmojiB("<:stop_check:754948796365930517>", Last(0),
                   "Remove this message.")
        }
        self.dict_emoji = dict_emoji or def_dict_emoji
        for emoji in self.buttons:
            callback = self.buttons[emoji].action
            if emoji.name not in self.dict_emoji:
                continue
            new_but = self.dict_emoji[emoji.name]
            new_button = Button(new_but.emoji,
                                callback,
                                position=new_but.position)
            del self.dict_emoji[emoji.name]
            self.dict_emoji[new_but.emoji] = new_but
            self.add_button(new_button)
            self.remove_button(emoji)
예제 #5
0
파일: poll.py 프로젝트: SirThane/BattleMaps
class Confirm(Menu):
    class Buttons:
        yes = b"\xE2\x9C\x85".decode("utf8")  # ✅  :white_check_mark:
        no = b"\xE2\x9D\x8C".decode("utf8")  # ❌  :x:

    def __init__(self, message, *args, **kwargs):
        self.message = message
        super().__init__(*args, **kwargs)

    @button(Buttons.yes, position=First(0))
    async def choice_yes(self, payload: RawReactionActionEvent):
        pass

    @button(Buttons.yes, position=Last(0))
    async def choice_yes(self, payload: RawReactionActionEvent):
        pass
예제 #6
0
파일: menu.py 프로젝트: Urumasi/rubbergod
class AuthorOnlyPagedMenu(BlockingPagedMenu, inherit_buttons=False):
    """
    Menu that allows react control only for the message owner or admins.
    """
    bot: Bot
    ctx: Context
    message: Message
    author: MemberLike = None

    def __init__(self, source, **kwargs):
        super().__init__(source, **kwargs)

    async def start(self, ctx: Context, *, channel=None, wait=False):
        assert (hasattr(ctx, "author") and ctx.author
                ), "ctx.author does not exists or is falsy, that's unexpected"

        self.author = ctx.author
        await super().start(ctx, channel=channel, wait=wait)

    @staticmethod
    def _is_add_event(payload: discord.RawReactionActionEvent) -> bool:
        return hasattr(payload,
                       "event_type") and payload.event_type == "REACTION_ADD"

    def _is_author_or_admin(self,
                            payload: discord.RawReactionActionEvent) -> bool:
        return hasattr(payload,
                       "user_id") and (payload.user_id == self.author.id
                                       or payload.user_id in config.admin_ids)

    async def _try_remove_reaction(self,
                                   payload: discord.RawReactionActionEvent):
        if self.ctx.message.guild and self.ctx.message.guild.me.guild_permissions.manage_messages:
            # try removing the reaction afterwards
            try:
                await self.message.remove_reaction(payload.emoji,
                                                   payload.member)
            except (discord.DiscordException, AttributeError):
                pass

    async def _checks(self,
                      payload: discord.RawReactionActionEvent,
                      remove_react_after=True) -> bool:
        """Checks it's reaction ADD event and message ownership.
        Additionally allows for the users react removal.
        """
        if self._is_add_event(payload):
            if remove_react_after:
                asyncio.ensure_future(self._try_remove_reaction(payload),
                                      loop=self.bot.loop)
            if self._is_author_or_admin(payload):
                return True
        return False

    def _check_fast_forward(self):
        return self._source.get_max_pages() < 3

    @button("\N{BLACK LEFT-POINTING TRIANGLE}\ufe0f", position=First(1))
    async def go_to_previous_page(self, payload):
        """go to the previous page"""
        if await self._checks(payload):
            await self.show_checked_page(self.current_page - 1)

    @button("\N{BLACK RIGHT-POINTING TRIANGLE}\ufe0f", position=Last(0))
    async def go_to_next_page(self, payload):
        """go to the next page"""
        if await self._checks(payload):
            await self.show_checked_page(self.current_page + 1)

    @button(
        "\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\ufe0f",
        position=First(0),
        skip_if=_check_fast_forward,
    )
    async def go_to_first_page(self, payload):
        """go to the first page"""
        if await self._checks(payload):
            await self.show_page(0)

    @button(
        "\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\ufe0f",
        position=Last(1),
        skip_if=_check_fast_forward,
    )
    async def go_to_last_page(self, payload):
        """go to the last page"""
        # The call here is safe because it's guarded by skip_if
        if await self._checks(payload):
            await self.show_page(self._source.get_max_pages() - 1)

    @button("\N{BLACK SQUARE FOR STOP}\ufe0f", position=Last(2))
    async def stop_pages(self, payload):
        """stops the pagination session."""
        if await self._checks(payload):
            self.stop()
예제 #7
0
class RoboPages(menus.MenuPages, inherit_buttons=False):
    def __init__(self, source, *args, **kwargs):
        super().__init__(source=source, check_embeds=True, *args, **kwargs)
        self.input_lock = asyncio.Lock()

    async def finalize(self, timed_out):
        try:
            if timed_out:
                await self.message.clear_reactions()
            else:
                await self.message.delete()
        except discord.HTTPException:
            pass

    def _skip_when(self):
        return self.source.get_max_pages() <= 2

    def _skip_when_short(self):
        return self.source.get_max_pages() <= 1

    # Disabling because discord-ext-menus paginate on both reaction add and remove.

    # async def remove_reaction(self, emoji, payload):
    #     user = self.bot.get_user(payload.user_id)
    #     try:
    #         await self.message.remove_reaction(emoji, user)
    #     except discord.Forbidden:
    #         pass

    @menus.button('<:first:855373614642888714>',
                  position=First(0),
                  skip_if=_skip_when)
    async def rewind(self, payload):
        """Goes to first page."""
        await self.show_page(0)

    @menus.button('<:previous:855373614299086859>',
                  position=First(1),
                  skip_if=_skip_when_short)
    async def back(self, payload):
        """Goes to the previous page."""
        await self.show_checked_page(self.current_page - 1)

    @menus.button('<:stop:855373614618116097>', position=First(2))
    async def stop_menu(self, payload):
        """Removes this message."""
        self.stop()

    @menus.button('<:next:855373615012380692>',
                  position=Last(0),
                  skip_if=_skip_when_short)
    async def forward(self, payload):
        """Goes to the next page."""
        await self.show_checked_page(self.current_page + 1)

    @menus.button('<:last:855373614907129876>',
                  position=Last(1),
                  skip_if=_skip_when)
    async def fastforward(self, payload):
        """Goes to the last page."""
        await self.show_page(self._source.get_max_pages() - 1)

    @menus.button('<:info:855373614625587241>', position=Last(2))
    async def show_information_page(self, payload):
        """Shows this message."""
        embed = discord.Embed(title='Paginator Help',
                              description=' Hello! Welcome to the Help Page.',
                              colour=0xce0037)

        messages = []
        for (emoji, button) in self.buttons.items():
            messages.append(f'{emoji}: {button.action.__doc__}')

        embed.add_field(name='What are these reactions for?',
                        value='\n'.join(messages),
                        inline=False)
        embed.set_footer(text=f'We were on page {self.current_page + 1}.')
        await self.message.edit(content=None, embed=embed)

        async def go_back_to_current_page():
            await asyncio.sleep(15.0)
            await self.show_page(self.current_page)

        self.bot.loop.create_task(go_back_to_current_page())

    @menus.button('<:number:855414332300591146>',
                  position=Last(3),
                  lock=False,
                  skip_if=_skip_when)
    async def numbered_page(self, payload):
        """Lets you go to a page by typing its number."""
        if self.input_lock.locked():
            return

        async with self.input_lock:
            channel = self.message.channel
            author_id = payload.user_id
            to_delete = []
            to_delete.append(await
                             channel.send('What page do you want to go?'))

            def check(msg: discord.Message):
                return msg.author.id == author_id and channel == msg.channel and msg.content.isdigit(
                )

            try:
                msg = await self.bot.wait_for('message',
                                              check=check,
                                              timeout=20.0)
            except asyncio.TimeoutError:
                to_delete.append(await channel.send('Took too long.'))
                await asyncio.sleep(5.0)
            else:
                page = int(msg.content)
                to_delete.append(msg)
                await self.show_checked_page(page - 1)

            try:
                await channel.delete_messages(to_delete)
            except Exception:
                pass

    async def send_initial_message(self, ctx, channel):
        # Have to do this because apparently setting inherit_buttons to False
        # didn't do anything.
        reactions = {
            '\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\ufe0f',
            '\N{BLACK LEFT-POINTING TRIANGLE}\ufe0f',
            '\N{BLACK RIGHT-POINTING TRIANGLE}\ufe0f',
            '\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}\ufe0f',
            '\N{BLACK SQUARE FOR STOP}\ufe0f'
        }
        for reaction in reactions:
            try:
                self.remove_button(reaction)
            except discord.HTTPException:
                pass
        return await super().send_initial_message(ctx, channel)