Пример #1
0
    async def set_name(self, ctx, *, name: str):
        """Set new display name"""
        if not repo_u.exists(ctx.author.id):
            return await ctx.author.send(f"Register with `{self.p}register`")
        if repo_u.get_attribute(ctx.author.id, "restricted") == 1:
            return await ctx.author.send("You are forbidden to alter your settings.")
        name = self.sanitise(name, limit=32)
        u = repo_u.get_by_nickname(name)
        if u is not None:
            return await ctx.author.send("This name is already used by someone.")
        # fmt: off
        disallowed = (
            "(", ")", "*", "/", "@", "\\", "_", "`",
            "\u200B", "\u200C", "\u200D", "\u2028", "\u2060", "\uFEFF",
            # guild emojis
            "<:", "<a:",
        )
        # fmt: on
        for char in disallowed:
            if char in name:
                return await ctx.author.send("The name contains forbidden characters.")

        before = repo_u.get_attribute(ctx.author.id, "nickname")
        repo_u.set(ctx.author.id, key="nickname", value=name)
        await ctx.author.send(f"Your nickname was changed to **{name}**")
        await self.event.user(ctx, f"Nickname changed from **{before}** to **{name}**.")
Пример #2
0
    async def user_edit(self, ctx, member: discord.Member, key: str,
                        value: str):
        """Edit user"""
        if (ctx.author.id != config["admin id"]
                and repo_u.get_attribute(member.id, "mod") == 1):
            return await ctx.send(
                "> You do not have permission to alter mod accounts")
        if ctx.author.id != config["admin id"] and member.id == config[
                "admin id"]:
            return await ctx.send(
                "> You do not have permission to alter admin account")

        if key in ("mod", "readonly", "restricted"):
            try:
                value = int(value)
            except ValueError:
                raise errors.BadArgument("Value has to be integer.")
        elif key.startswith("home_id:"):
            try:
                value = int(value)
            except ValueError:
                raise errors.BadArgument("Value has to be integer.")

        repo_u.set(discord_id=member.id, key=key, value=value)
        await self.event.sudo(ctx, f"{member.id} updated: {key} = {value}.")
Пример #3
0
    async def on_message(self, message: discord.Message):
        # ignore non-textchannel sources
        if not isinstance(message.channel, discord.TextChannel):
            return

        # do not act if author is bot
        if message.author.bot:
            return

        # get wormhole
        db_w = repo_w.get(message.channel.id)

        if db_w is None:
            return

        # get additional information
        db_b = repo_b.get(db_w.beam)

        # check for attributes
        # fmt: off
        if db_b.active == 0 \
        or db_w.active == 0 \
        or repo_u.get_attribute(message.author.id, "readonly") == 1:
            return await self.delete(message)
        # fmt: on

        # do not act if message is bot command
        if message.content.startswith(config["prefix"]):
            return await self.delete(message)

        # get wormhole channel objects
        if db_b.name not in self.wormholes or len(
                self.wormholes[db_b.name]) == 0:
            self.reconnect(db_b.name)

        # process incoming message
        content = await self._process(message)

        # convert attachments to links
        first_line = True
        if message.attachments:
            for f in message.attachments:
                # don't add newline if message has only attachments
                if first_line:
                    content += " " + f.url
                    first_line = False
                else:
                    content += "\n" + f.url

        if len(content) < 1:
            return

        # count the message
        self._update_stats(message)

        # send the message
        await self.send(message=message,
                        text=content,
                        files=message.attachments)
Пример #4
0
    async def user_remove(self, ctx, member_id: int):
        """Remove user"""
        if ctx.author.id != config["admin id"] and repo_u.get_attribute(
                member_id, "mod") == 1:
            return await ctx.send(
                "> You do not have permission to alter mod accounts")
        if ctx.author.id != config["admin id"] and member_id == config[
                "admin id"]:
            return await ctx.send(
                "> You do not have permission to alter admin account")

        repo_u.delete(member_id)
        await self.event.sudo(ctx, f"User **{member_id}** removed.")
Пример #5
0
    async def set_home(self, ctx):
        """Set current channel as your home wormhole"""
        if not repo_u.exists(ctx.author.id):
            return await ctx.author.send(f"Register with `{self.p}register`")
        if repo_u.get_attribute(ctx.author.id, "restricted") == 1:
            return await ctx.author.send("You are forbidden to alter your settings.")
        if not isinstance(ctx.channel, discord.TextChannel) or not repo_w.exists(ctx.channel.id):
            return await ctx.author.send("Home has to be a wormhole")

        beam_name = repo_w.get(ctx.channel.id).beam
        repo_u.set(ctx.author.id, key=f"home_id:{beam_name}", value=ctx.channel.id)
        await ctx.author.send("Home set to " + ctx.channel.mention)
        await self.event.user(
            ctx, f"Home in **{beam_name}** set to **{ctx.channel.id}** ({ctx.guild.name})."
        )
Пример #6
0
    def _update_stats(self, message: discord.Message):
        """Increment wormhole's statistics"""
        # try to get author's home wormhole
        beam_name = repo_w.get_attribute(message.channel.id, "beam")
        channel_id = repo_u.get_attribute(message.author.id,
                                          f"home_id:{beam_name}")
        if channel_id is None:
            # user is not registered, use current wormhole
            channel_id = message.channel.id

        current = repo_w.get_attribute(channel_id, "messages")
        repo_w.set(channel_id, "messages", current + 1)

        beam_name = repo_w.get_attribute(message.channel.id, "beam")
        if beam_name in self.transferred:
            self.transferred[beam_name] += 1
        else:
            self.transferred[beam_name] = 1
Пример #7
0
    async def _process(self, message: discord.Message):
        """Escape mentions and apply anonymity"""
        content = message.content

        users = re.findall(r"<@!?[0-9]+>", content)
        roles = re.findall(r"<@&[0-9]+>", content)
        channels = re.findall(r"<#[0-9]+>", content)
        emojis = re.findall(r"<:[a-zA-Z0-9_]+:[0-9]+>", content)

        # prevent tagging
        for u in users:
            try:
                # Get discord user tags. If they're registered, translate to
                # their ((nickname)); it will be converted on send.
                user_id = int(
                    u.replace("<@!", "").replace("<@", "").replace(">", ""))
                nickname = repo_u.get_attribute(user_id, "nickname")
                if nickname is not None:
                    user = "******" + nickname + "))"
                else:
                    user = str(self.bot.get_user(user_id))
            except Exception as e:
                user = "******"
                await self.event.user(message,
                                      "Problem in user retrieval:\n>>>{e}")
            content = content.replace(u, user)
        for r in roles:
            try:
                role = message.guild.get_role(
                    int(r.replace("<@&", "").replace(">", ""))).name
            except Exception as e:
                role = "unknown-role"
                await self.event.user(message,
                                      "Problem in role retrieval:\n>>>{e}")
            content = content.replace(r, role)
        # convert channel tags to universal names
        for channel in channels:
            try:
                ch = self.bot.get_channel(
                    int(channel.replace("<#", "").replace(">", "")))
                channel_name = self.sanitise(ch.name)
                guild_name = self.sanitise(ch.guild.name)
                content = content.replace(
                    channel, f"__**{guild_name}/{channel_name}**__")
            except Exception as e:
                await self.event.user(message,
                                      "Problem in channel retrieval:\n>>>{e}")
        # remove unavailable emojis
        for emoji in emojis:
            emoji_ = emoji.replace("<:", "").replace(">", "")
            emoji_name = emoji_.split(":")[0]
            emoji_id = int(emoji_.split(":")[1])
            if self.bot.get_emoji(emoji_id) is None:
                content = content.replace(emoji, ":" + emoji_name + ":")

        # line preprocessor for codeblocks
        if "```" in content:
            backticks = re.findall(r"```[a-z0-9]*", content)
            for b in backticks:
                content = content.replace(f" {b}", f"\n{b}", 1)
                content = content.replace(f"{b} ", f"{b}\n", 1)

        # apply prefixes
        content_ = content.split("\n")
        content = ""
        p = self._get_prefix(message)
        code = False
        for i in range(len(content_)):
            if i == 1:
                # use fill icon instead of guild one
                p = self._get_prefix(message, first_line=False)
            line = content_[i]
            # add prefix if message starts with code block
            if i == 0 and line.startswith("```"):
                content += self._get_prefix(message) + "\n"
            if line.startswith("```"):
                code = True
            if code:
                content += line + "\n"
            else:
                content += p + line + "\n"
            if line.endswith("```") and code:
                code = False

        return content.replace("@", "@_")
Пример #8
0
    async def send(
        self,
        *,
        message: discord.Message,
        text: str,
        files: list = None,
    ):
        """Distribute the message"""
        deleted_original = False

        # get variables
        messages = [message]
        db_w = repo_w.get(message.channel.id)
        db_b = repo_b.get(db_w.beam)

        # access control
        if db_b.active == 0:
            return
        if db_w.active == 0 or db_w.readonly == 1:
            return
        if repo_u.get_attribute(message.author.id, "readonly") == 1:
            return

        # remove the original, if possible
        manage_messages_perm = message.guild.me.permissions_in(
            message.channel).manage_messages
        if manage_messages_perm and db_b.replace == 1 and not files:
            try:
                messages[0] = message.author
                await self.delete(message)
                deleted_original = True
            except discord.Forbidden:
                pass

        # limit message length
        text = text[:1024]

        # update wormhole list
        if db_b.name not in self.wormholes.keys():
            self.reconnect(db_b.name)
        wormholes = self.wormholes[db_b.name]

        users = self._get_users_from_tags(beam_name=db_b.name, text=text)

        # replicate messages
        tasks = []
        for wormhole in wormholes:
            task = asyncio.ensure_future(
                self.replicate(
                    wormhole,
                    message,
                    messages,
                    users,
                    text,
                    files,
                    db_b,
                    manage_messages_perm,
                ))
            tasks.append(task)
        await asyncio.gather(*tasks, return_exceptions=True)

        # add checkmark to original, if it hasn't been deleted
        if not deleted_original:
            await message.add_reaction("✅")

        # save message objects in case of editing/deletion
        if db_b.timeout > 0:
            self.sent.append(messages)
            await asyncio.sleep(db_b.timeout)
            self.sent.remove(messages)
Пример #9
0
def is_mod(ctx: commands.Context):
    return is_admin(ctx) or repo_u.get_attribute(ctx.author.id, "mod") == 1