Example #1
0
    async def convert(self, ctx, body: str):
        # If the input is in the format <#123> then it is a text channel.
        if body.startswith("<#") and body.endswith(">"):
            sf_str = body[2:-1]
            if sf_str.isdigit():
                sf = int(sf_str)
                channel = alg.find(lambda c: c.id == sf, ctx.guild.channels)

                if channel:
                    return channel

            raise commands.BadArgument("Unable to access that channel. Make "
                                       "sure that it exists, and that I have "
                                       "access to it, and try again.")

        # Otherwise, it could be a text channel, a category or a voice channel.
        # We need to hunt for it manually.
        else:
            to_search = {*ctx.guild.channels, *ctx.guild.categories}
            channel = alg.find(lambda c: c.name == body, to_search)
            if channel:
                return channel

            # Attempt case insensitive searching
            body = body.lower()
            channel = alg.find(lambda c: c.name.lower() == body, to_search)
            if channel:
                return channel
            raise commands.BadArgument("No channel matching input was found.")
Example #2
0
    async def smoke_a_pipe(content, guild_members=None):
        """
        Takes some input string. If the string ends in `| [discord mention]`,
        we return the left hand side of the pipe, and the user, as a
        tuple. Otherwise, we return the input and None as the result.
        """
        guild_members = guild_members or []

        if "|" in content:
            query, _, mention = content.rpartition("|")

            query = query.rstrip()
            mention = mention.strip()

            mention_match = re.match(r"^<@!?(\d+)>$", mention)
            if mention_match:
                mention = int(mention_match.group(1))

            if isinstance(mention, int) or mention.isdigit():
                user = alg.find(lambda u: u.id == int(mention), guild_members)
            elif mention:
                user = alg.find(
                    lambda u: u.display_name.lower() == mention.lower(), guild_members
                )
            else:
                user = None
        else:
            query, user = content, None

        return query, user
Example #3
0
    def find_unit(self, name: str) -> typing.Optional[UnitModel]:
        """
        Looks for a unit with a matching name, and returns it.

        If one does not exist, we return None.
        """
        return alg.find(lambda c: c == name, self.conversions)
Example #4
0
def get_category(category: UnitCategoryModel) -> Optional[UnitCollectionModel]:
    """
    Gets the given collection of measurement quantities for the given
    dimensionality of measurement.
    """
    res = alg.find(lambda c: c.unit_type == category, _models)
    return res
Example #5
0
    async def f(self, ctx, *, reason=None):
        try:
            await ctx.message.delete()
            bucket = self.buckets.get(ctx.channel)

            # Get the last 10 recent messages. If the bucket message
            # is in there, then update, else, delete the old message if
            # possible and then resend the new one. If the bucket is too
            # old, start anew.
            if bucket:
                msg = bucket.message.id
                most_recent = await ctx.channel.history(limit=10).flatten()
                new_msg = alg.find(lambda m: m.id == msg, most_recent)

                if new_msg:
                    bucket.message = new_msg
                else:
                    try:
                        await bucket.message.delete()
                        bucket.message = None
                    except:
                        del self.buckets[ctx.channel]
                        bucket = None
                    else:
                        return await self.append_to_bucket(bucket, ctx.author)

            if not bucket:
                colour = alg.rand_colour()

                if reason is None:
                    message = await ctx.send(embed=discord.Embed(
                        description=f"{ctx.author} paid their respects.",
                        colour=colour,
                    ))
                else:
                    message = await ctx.send(embed=discord.Embed(
                        description=f"{ctx.author} paid their respects for"
                        f" {reason}"))

                if ENABLE_REACT:
                    await message.add_reaction(
                        "\N{REGIONAL INDICATOR SYMBOL LETTER F}")

                f_bucket = F(collections.MutableOrderedSet({ctx.author}),
                             message, colour, ctx)

                self.buckets[ctx.channel] = f_bucket
                destroy_bucket_later(self, ctx.channel)
            else:
                await self.append_to_bucket(bucket, ctx.author)
        except BaseException:
            traceback.print_exc()
Example #6
0
    async def on_message(cls, message):
        """
        On message, check for any binds. If we have a valid bind, first
        check to see whether we can make webhooks or not. If we can, we should
        generate a webhook that impersonates the user context.
        """
        author = message.author
        content = message.content

        # Cases where we should refuse to run.
        if message.guild is None:
            return
        if not message.guild.me.guild_permissions.manage_webhooks:
            return
        elif author.bot:
            return

        def pred(bind):
            """Matches the use of a Discord bind."""
            bind_whitespace = (f"{bind}\n", f"{bind} ")
            return content == bind or any(
                content.startswith(b) for b in bind_whitespace)

        bind = alg.find(pred, cls.binds)

        if not bind:
            return

        bind_result = cls.binds[bind]
        if isinstance(bind_result, tuple):
            bind_result = random.choice(bind_result)

        # If we matched a bind, remove it.
        message.content = message.content[len(bind):].lstrip()
        message.content += f" {bind_result}"
        await cls.delete_and_copy_handle_with_webhook(message)
Example #7
0
    async def __lookup_online(self, bot, code_point: int):
        """
        Looks up the code point online to get the Unicode object.
        If nothing is returned, then we assume it is not found.
        """
        conn = await self.acquire_http()
        url = _make_fileformat_url(code_point)
        resp = await conn.get(url)
        if resp.status == 404:
            return None
        elif resp.status != 200:
            raise errors.HttpError(resp)

        content = await resp.text()
        soup = bs4.BeautifulSoup(content)
        """
        <!-- Expects to find this somewhere -->
        
        <tr class="row0">
            <td>Name</td>
            <td>&lt;control&gt;</td>
        </tr>
        <tr class="row1">
            <td>Block</td>
            <td><a href="/info/unicode/block/basic_latin/index.htm">Basic Latin
                </a></td>
        </tr>
        <tr class="row0">
            <td>Category</td>
            <td><a href="/info/unicode/category/Cc/index.htm">Other, Control 
                [Cc]</a></td>
        </tr>
        <tr class="row1">
            <td>Combine</td>
            <td>0</td>
        </tr>
        <tr class="row0">
            <td>BIDI</td>
            <td>Paragraph Separator [B]</td>
        </tr>
        
        <tr class="row1">
            <td>Mirror</td>
            <td>N</td>
        </tr>
        
        <tr class="row0">
            <td>Old name</td>
            <td>LINE FEED (LF)</td>
        </tr>
        
        <tr class="row1">
            <td valign="top">Index entries</td>
            <td>eol<br />LINE FEED<br />line, new<br />new line<br />end of 
            line<br />lf<br />line, end of<br />nl<br /></td>
        </tr>        
        """
        name: bs4.Tag = soup.find(name="td", text="Name")
        old_name: bs4.Tag = soup.find(name="td", text="Old name")
        bidi: bs4.Tag = soup.find(name="td", text="BIDI")
        idxs: bs4.Tag = soup.find(name="td", text="Index entries")
        category: bs4.Tag = soup.find(name="td", text="Category")

        # Name resolution order.
        def resolve(tag) -> str:
            if not tag:
                return ""
            else:
                sib = tag.find_next_sibling()
                return sib.text if sib else ""

        name = resolve(name)

        if name == "<control>":
            # Force resolving another name first.
            nro = (resolve(old_name), resolve(bidi),
                   resolve(idxs).splitlines(), name)
        else:
            nro = (name, resolve(old_name), resolve(bidi),
                   resolve(idxs).splitlines())

        name: str = alg.find(bool, nro, "UNKNOWN")
        category: str = resolve(category)
        category = re.findall("\[(.*)\]", category)
        category: str = category[0] if category else "??"

        return self.Unicode(name, category, code_point)
Example #8
0
    async def convert(self, ctx, body: str):
        if body.startswith("<") and body.endswith(">"):
            tb = body[1:-1]

            if tb.startswith("@&"):
                return await commands.RoleConverter().convert(ctx, body)
            elif tb.startswith("@") and tb[1:2].isdigit() or tb[1:2] == "!":
                return await commands.MemberConverter().convert(ctx, body)
            elif tb.startswith("#"):
                return await commands.TextChannelConverter().convert(ctx, body)
        else:
            try:
                return await commands.EmojiConverter().convert(ctx, body)
            except:
                pass

            try:
                return await GuildChannelCategoryConverter().convert(ctx, body)
            except:
                pass

            try:
                return await commands.PartialEmojiConverter().convert(
                    ctx, body)
            except:
                pass

        # Attempt to find in whatever we can look in. Don't bother looking
        # outside this guild though, as I plan to keep data between guilds
        # separate for privacy reasons.

        if ctx.guild:
            all_strings = [
                *ctx.guild.members,
                *ctx.guild.channels,
                *ctx.guild.categories,
                *ctx.guild.roles,
                *ctx.guild.emojis,
            ]

            def search(obj):
                if getattr(obj, "display_name", "") == body:
                    return True
                if str(obj) == body or obj.name == body:
                    return True
                return False

            # Match case first, as a role and member, say, may share the same
            # name barr the case difference, and this could lead to unwanted
            # or unexpected results. The issue is this will get slower as a
            # server gets larger, generally.
            result = alg.find(search, all_strings)
            if not result:
                # Try again not matching case.
                def search(obj):
                    _body = body.lower()

                    if getattr(obj, "display_name", "").lower() == _body:
                        return True
                    if str(obj).lower() == _body:
                        return True
                    if obj.name.lower() == _body:
                        return True
                    return False

                result = alg.find(search, all_strings)

            if not result:
                raise commands.BadArgument(f"Could not resolve `{body}`")
            else:
                return result