Esempio n. 1
0
    async def checkin_exempt(self,
                             ctx: commands.Context,
                             user: MemberConverter2 = None,
                             val: BooleanConverter = None):
        """!kazhelp
        description: |
            Check or set exemptions from check-ins.

            Users who are exempt from check-ins will not appear in a {{!checkin report}}.
        parameters:
            - name: user
              type: "@mention"
              optional: true
              description: The user to check (as an @mention or a Discord ID).
            - name: val
              type: '"yes" or "no"'
              optional: true
              description: "If not specified, check a user's exemption status. If specified, change
                that user's exemption status."
        examples:
            - command: .checkin exempt
              description: Get a list of exempt users.
            - command: .checkin exempt @JaneDoe
              description: Check if JaneDoe is exempt from check-ins.
            - command: .checkin exempt @JaneDoe yes
              description: Set JaneDoe as exempt from check-ins.
        """
        self.c.cleanup_exempt(self.server)
        if user is None:
            exempt_users = self.c.get_exempt_users()
            if exempt_users:
                full_msg = "**Exempt from check-ins**\n{}"\
                    .format('\n'.join(user_mention(u.discord_id) for u in exempt_users))
            else:
                full_msg = "**No users are exempt from check-ins.**"
            for msg in split_chunks_on(full_msg, Limits.MESSAGE):
                await self.bot.say(msg[:Limits.MESSAGE])
        elif val is None:
            member_ = user  # type: discord.Member  # IDE type detection
            if self.c.get_user(member_).is_exempt:
                await self.bot.say("{} is **exempt** from check-ins.".format(
                    member_.mention))
            else:
                await self.bot.say(
                    "{} is **not** exempt from check-ins.".format(
                        member_.mention))
        else:
            member_ = user  # type: discord.Member  # IDE type detection
            self.c.set_user_exempt(member_, val)
            await self.bot.say("{} has been set {} from check-ins.".format(
                member_.mention, "**exempt**" if val else "**not** exempt"))
Esempio n. 2
0
 async def send_embed_list(self, title: str, contents: str):
     contents_split = split_chunks_on(contents, Limits.EMBED_FIELD_VALUE)
     em = discord.Embed(color=0x80AAFF, title=title)
     sep = '-'
     num_fields = 0
     max_fields = (Limits.EMBED_TOTAL - len(title) - 2) \
         // (Limits.EMBED_FIELD_VALUE + len(sep))
     for say_str in contents_split:
         if num_fields >= max_fields:
             await self.bot.say(embed=em)
             em = discord.Embed(color=theme.solarized.cyan, title=title)
             num_fields = 0
         em.add_field(name=sep, value=say_str, inline=False)
         num_fields += 1
     await self.bot.say(embed=em)
Esempio n. 3
0
    def _render(self, parsed: List[WikiStructure]) -> List[str]:
        items = []
        msg_break = False
        for i in parsed:
            if isinstance(i, WikiMessageBreak):
                pass
            elif isinstance(i, WikiImage):
                items.append(i.url)
            elif isinstance(i, WikiSection):
                if i.heading:
                    text = '**{}**\n\n{}'.format(i.heading, i.text.strip())
                else:
                    text = self._MESSAGE_SPACER + i.text.strip()

                split_text = split_chunks_on(text, Limits.MESSAGE)
                items.extend(split_text)
            else:
                items.append(
                    "**[WARNING] UNKNOWN WIKI STRUCTURE DURING RENDERING")
        return items
Esempio n. 4
0
    async def _whois_search(self, ctx, user: str):
        logger.info("whois: searching for name match")
        members = [
            m for m in ctx.message.server.members
            if (m.nick and user.lower() in m.nick.lower())
            or user.lower() in m.name.lower()
        ]
        if members:
            member_list_str = ', '.join(str(m) for m in members)
            logger.debug("Found {:d} users: {}".format(len(members),
                                                       member_list_str))

            s = '**{:d} users found**\n'.format(len(members)) +\
                '\n'.join("{0.mention} ID {0.id}".format(m) for m in members)
            for part in split_chunks_on(s, maxlen=Limits.MESSAGE):
                await self.bot.say(part)
            return True
        else:
            await self.bot.say("No matching user found.")
            return False
Esempio n. 5
0
    async def report(self, ctx: commands.Context, min_badges: int = 1):
        """!kazhelp
        description: "Show a report of member badge counts."
        parameters:
            - name: min_badges
              optional: true
              type: number
              description: |
                Minimum number of badges a user needs to have to be included in the report.
        """
        if min_badges < 1:
            raise commands.BadArgument("`min` must be at least 1.")

        report_lines = [
            "**Badge report (minimum {:d} badges)**".format(min_badges)
        ]
        for u, n in self.c.query_badge_report(min_badges):
            report_lines.append("{} - {:d} badges".format(
                user_mention(u.discord_id), n))

        for msg in split_chunks_on('\n'.join(report_lines),
                                   maxlen=Limits.MESSAGE):
            await self.bot.say(msg)
Esempio n. 6
0
 def _render_embed(
         self,
         parsed: List[WikiStructure]) -> List[Union[str, EmbedSplitter]]:
     items = []
     msg_break = False
     for i in parsed:
         if isinstance(i, WikiMessageBreak):
             msg_break = True
         elif isinstance(i, WikiImage):
             msg_break = False
             items.append(i.url)
         elif isinstance(i, WikiSection):
             heading = i.heading or EmbedSplitter.Empty
             desc = i.text.strip()
             if msg_break or not items or not isinstance(
                     items[-1], EmbedSplitter):
                 if len(desc) <= Limits.EMBED_DESC:
                     items.append(
                         EmbedSplitter(title=heading, description=desc))
                 else:
                     desc_split = split_chunks_on(desc,
                                                  Limits.EMBED_FIELD_VALUE)
                     items.append(
                         EmbedSplitter(title=heading,
                                       description=desc_split.pop(0)))
                     for s in desc_split:
                         items[-1].add_field(name=self._MESSAGE_SPACER,
                                             value=s,
                                             inline=False)
             else:
                 items[-1].add_field(name=heading, value=desc, inline=False)
             msg_break = False
         else:
             items.append(
                 "**[WARNING] UNKNOWN WIKI STRUCTURE DURING RENDERING")
     return items
Esempio n. 7
0
    async def send_message(self,
                           destination,
                           contents=None,
                           *,
                           tts=False,
                           embed: Union[discord.Embed, EmbedSplitter] = None,
                           auto_split=True,
                           split='word') -> Sequence[discord.Message]:
        """
        Send a message. This method wraps the :meth:`discord.Client.send_message` method and adds
        automatic message splitting if a message is too long for one line.

        No parsing of Markdown is done for message splitting; this behaviour may break intended
        formatting. For messages which may contain formatting, it is suggested you parse and split
        the message instead of relying on auto-splitting.

        See also :meth:`kaztron.utils.split_chunks_on` and :meth:`kaztron.utils.natural_split` for
        manual control of splitting behaviour. See also :meth:`kaztron.utils.split_code_chunks_on`
        for splitting Markdown code blocks manually.

        See also :cls:`kaztron.utils.embeds.EmbedSplitter` for similar functionality in splitting
        embeds.

        :param destination: he location to send the message (Channel, PrivateChannel, User, etc.)
        :param contents: The content of the message to send. If this is missing, then the ``embed``
            parameter must be present.
        :param tts: Indicates if the message should be sent using text-to-speech.
        :param embed: The rich embed for the content. Also accepts EmbedSplitter instances, for
            automatic splitting - in this case, the EmbedSplitter will be finalized by this method.
        :param auto_split: Whether to auto-split messages that exceed the maximum message length.
        :param split: What to split on: 'word' or 'line'. 'Line' should only be used for messages
            known to contain many line breaks, as otherwise auto-splitting is likely to fail.
        """

        # prepare text contents
        if not contents or not auto_split:
            content_chunks = (contents, )
        else:
            if split == 'word':
                content_chunks = natural_split(contents, Limits.MESSAGE)
            elif split == 'line':
                content_chunks = split_chunks_on(contents,
                                                 Limits.MESSAGE,
                                                 split_char='\n')
            else:
                raise ValueError(
                    '`split` argument must be \'word\' or \'line\'')

        # prepare embed
        try:
            embed_list = embed.finalize()
        except AttributeError:
            embed_list = (embed, )

        # strategy: output all text chunks before starting to output embed chunks
        # so the last text chunk will have the first embed chunk attached
        # this is because non-split messages usually have the embed appear after the msg -
        # should be fairly rare for both msg and embed to be split
        msg_list = []
        for content_chunk in content_chunks[:-1]:
            msg_list.append(await self.bot.send_message(destination,
                                                        content_chunk,
                                                        tts=tts))

        msg_list.append(await self.bot.send_message(destination,
                                                    content_chunks[-1],
                                                    tts=tts,
                                                    embed=embed_list[0]))

        for embed_chunk in embed_list[1:]:
            msg_list.append(await self.bot.send_message(destination,
                                                        tts=tts,
                                                        embed=embed_chunk))
        return tuple(msg_list)