示例#1
0
    async def prefix(self, ctx, *, prefix: str = None):
        if prefix is None:
            await ctx.send(Embed(f"The prefix for this server is `{ctx.prefix}`."))
            return

        if (await ctx.message.member.guild_permissions()).administrator is False:
            raise commands.MissingPermissions(["administrator"])

        if len(prefix) > 10:
            await ctx.send(ErrorEmbed("The chosen prefix is too long."))
            return

        if prefix == self.bot.config.DEFAULT_PREFIX:
            prefix = None

        await tools.get_data(self.bot, ctx.guild.id)
        async with self.bot.pool.acquire() as conn:
            await conn.execute("UPDATE data SET prefix=$1 WHERE guild=$2", prefix, ctx.guild.id)

        await self.bot.state.set(f"prefix:{ctx.guild.id}", "" if prefix is None else prefix)

        await ctx.send(
            Embed(
                "Successfully changed the prefix to "
                f"`{self.bot.config.DEFAULT_PREFIX if prefix is None else prefix}`.",
            )
        )
    async def confirmation(self, ctx):
        data = await tools.get_user_settings(self.bot, ctx.author.id)

        if not data or data[0] is True:
            async with self.bot.pool.acquire() as conn:
                await conn.execute(
                    "INSERT INTO account VALUES ($1, $2, NULL) ON CONFLICT (identifier) DO UPDATE "
                    "SET confirmation=$2",
                    ctx.author.id,
                    False,
                )

            await ctx.send(
                Embed(
                    "Confirmation messages are disabled. To send messages to another server, "
                    f"either use `{ctx.prefix}new <message>` or `{ctx.prefix}send <server ID> "
                    "<message>`.", ))
            return

        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                "UPDATE account SET confirmation=$1 WHERE identifier=$2",
                True,
                ctx.author.id,
            )

        await ctx.send(Embed("Confirmation messages are enabled."))
示例#3
0
    async def confirmation(self, ctx):
        data = await tools.get_user_settings(self.bot, ctx.author.id)

        if not data or data[0] is True:
            async with self.bot.pool.acquire() as conn:
                if not data:
                    await conn.execute(
                        "INSERT INTO preference (identifier, confirmation) VALUES ($1, $2)",
                        ctx.author.id,
                        False,
                    )
                else:
                    await conn.execute(
                        "UPDATE preference SET confirmation=$1 WHERE identifier=$2",
                        False,
                        ctx.author.id,
                    )

            await ctx.send(embed=Embed(
                description=
                "Confirmation messages are disabled. To send messages to another server, either use "
                f"`{ctx.prefix}new <message>` or `{ctx.prefix}send <server ID> <message>`.",
            ))
            return

        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                "UPDATE preference SET confirmation=$1 WHERE identifier=$2",
                True,
                ctx.author.id,
            )

        await ctx.send(embed=Embed(
            description="Confirmation messages are enabled."))
示例#4
0
    async def viewsnippet(self, ctx, *, name: str = None):
        if name:
            async with self.bot.pool.acquire() as conn:
                res = await conn.fetchrow(
                    "SELECT name, content FROM snippet WHERE name=$1 AND guild=$2",
                    name.lower(),
                    ctx.guild.id,
                )

            if not res:
                await ctx.send(embed=ErrorEmbed(
                    description="A snippet with that name was not found."))
                return

            embed = Embed(title="Snippet")
            embed.add_field(name="Name", value=res[0], inline=False)
            embed.add_field(name="Content", value=res[1], inline=False)
            await ctx.send(embed=embed)
            return

        async with self.bot.pool.acquire() as conn:
            res = await conn.fetch(
                "SELECT name, content FROM snippet WHERE guild=$1",
                ctx.guild.id)

        if not res:
            await ctx.send(embed=Embed(
                description="No snippet has been added yet."))
            return

        all_pages = []
        for chunk in [res[i:i + 10] for i in range(0, len(res), 10)]:
            page = Embed(title="Snippets")

            for snippet in chunk:
                page.add_field(
                    name=snippet[0],
                    value=snippet[1][:97] +
                    "..." if len(snippet[1]) > 100 else snippet[1],
                    inline=False,
                )

            page.set_footer(text="Use the reactions to flip pages.")
            all_pages.append(page)

        if len(all_pages) == 1:
            embed = all_pages[0]
            embed.set_footer(text=discord.Embed.Empty)
            await ctx.send(embed=embed)
            return

        await tools.create_paginator(self.bot, ctx, all_pages)
示例#5
0
    async def accessrole(self, ctx, roles: commands.Greedy[RoleConverter] = None, *, check=None):
        if roles is None:
            roles = []

        if check:
            await ctx.send(ErrorEmbed("The role(s) are not found. Please try again."))
            return

        if len(roles) > 10:
            await ctx.send(
                ErrorEmbed(
                    "There can at most be 10 roles. Try using the command again but specify fewer "
                    "roles."
                )
            )
            return

        msg = await ctx.send(Embed("Updating roles..."))

        old_data = await tools.get_data(self.bot, ctx.guild.id)

        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                "UPDATE data SET accessrole=$1 WHERE guild=$2",
                [role.id for role in roles],
                ctx.guild.id,
            )

        data = await tools.get_data(self.bot, ctx.guild.id)
        category = await ctx.guild.get_channel(data[2])

        if category and roles:
            try:
                for role in old_data[3]:
                    role = await ctx.guild.get_role(role)

                    if role:
                        await category.set_permissions(target=role, overwrite=None)

                for role, permission in (await self._get_overwrites(ctx, data[3])).items():
                    await category.set_permissions(target=role, overwrite=permission)
            except Forbidden:
                await msg.edit(
                    ErrorEmbed(
                        "The role(s) are updated successfully. The permission overwrites for the "
                        "category failed to be changed. Update my permissions and try again or set "
                        "the overwrites manually."
                    )
                )
                return

        await msg.edit(Embed("The role(s) are updated successfully."))
示例#6
0
    async def ping(self, ctx):
        start = time.time()
        shard = ctx.guild.shard_id if ctx.guild else 0

        msg = await ctx.send(embed=Embed(description="Checking latency..."))

        await msg.edit(
            embed=Embed(
                title="Pong!",
                description=f"Gateway latency: {round((await self.bot.statuses())[shard].latency, 2)}ms.\n"
                f"HTTP API latency: {round((time.time() - start) * 1000, 2)}ms.",
            )
        )
示例#7
0
    async def sql(self, ctx, *, query: str):
        async with self.bot.pool.acquire() as conn:
            try:
                res = await conn.fetch(query)
            except Exception:
                await ctx.send(embed=ErrorEmbed(
                    description=f"```py\n{traceback.format_exc()}```"))
                return

        if res:
            await ctx.send(embed=Embed(description=f"```{res}```"))
            return

        await ctx.send(embed=Embed(description="No results to fetch."))
示例#8
0
    async def snippetclear(self, ctx):
        async with self.bot.pool.acquire() as conn:
            await conn.execute("DELETE FROM snippet WHERE guild=$1",
                               ctx.guild.id)

        await ctx.send(embed=Embed(
            description="All snippets were removed successfully."))
示例#9
0
    async def _send_guilds(self, ctx, guilds, title):
        if len(guilds) == 0:
            await ctx.send(embed=ErrorEmbed(
                description="No such guild was found."))
            return

        all_pages = []

        for chunk in [guilds[i:i + 20] for i in range(0, len(guilds), 20)]:
            page = Embed(title=title)

            for guild in chunk:
                if page.description == discord.Embed.Empty:
                    page.description = guild
                else:
                    page.description += f"\n{guild}"

            page.set_footer(text="Use the reactions to flip pages.")
            all_pages.append(page)

        if len(all_pages) == 1:
            embed = all_pages[0]
            embed.set_footer(text=discord.Embed.Empty)
            await ctx.send(embed=embed)
            return

        await tools.create_paginator(self.bot, ctx, all_pages)
示例#10
0
    async def stats(self, ctx):
        total_seconds = int((datetime.utcnow() - await self.bot.started()).total_seconds())
        hours, remainder = divmod(total_seconds, 3600)
        minutes, seconds = divmod(remainder, 60)
        days, hours = divmod(hours, 24)

        bot_user = await self.bot.real_user()

        embed = Embed(
            "ModMail Statistics",
            f"Visit the bot status page [here]({self.bot.config.BASE_URI}/status) for more "
            "information.",
        )
        embed.add_field("Owner", "CHamburr#2591")
        embed.add_field("Bot Version", self.bot.version)
        if days:
            embed.add_field("Uptime", f"{days}d {hours}h {minutes}m {seconds}s")
        else:
            embed.add_field("Uptime", f"{hours}h {minutes}m {seconds}s")
        embed.add_field("Clusters", self.bot.cluster_count)
        if ctx.guild:
            embed.add_field("Shards", f"{ctx.guild.shard_id + 1}/{await self.bot.shard_count()}")
        else:
            embed.add_field("Shards", f"0/{await self.bot.shard_count()}")
        embed.add_field("Servers", str(await self.bot.state.scard("guild_keys")))
        embed.add_field("CPU Usage", f"{psutil.cpu_percent(interval=None)}%")
        embed.add_field("RAM Usage", f"{psutil.virtual_memory().percent}%")
        embed.add_field("Python Version", platform.python_version())
        embed.set_thumbnail(bot_user.avatar_url)

        await ctx.send(embed)
示例#11
0
 async def support(self, ctx):
     await ctx.send(
         embed=Embed(
             title="Support Server",
             description="https://discord.gg/wjWJwJB",
         )
     )
示例#12
0
    async def banserver(self, ctx, *, guild: GuildConverter):
        async with self.bot.pool.acquire() as conn:
            await conn.execute("INSERT INTO ban VALUES ($1, $2)", guild.id, 1)

        await self.bot.state.sadd("banned_guilds", guild.id)

        await ctx.send(Embed("Successfully banned that server from the bot."))
示例#13
0
    async def sharedservers(self, ctx, *, user: UserConverter):
        guilds = [
            f"{guild.name} `{guild.id}` ({guild.member_count} members)"
            for guild in [
                await self.bot.get_guild(int(guild))
                for guild in await tools.get_user_guilds(self.bot, user) or []
            ] if guild is not None
        ]

        if len(guilds) == 0:
            await ctx.send(ErrorEmbed("No such guild was found."))
            return

        all_pages = []

        for chunk in [guilds[i:i + 20] for i in range(0, len(guilds), 20)]:
            page = Embed(title="Shared Servers")

            for guild in chunk:
                if page.description == discord.Embed.Empty:
                    page.description = guild
                else:
                    page.description += f"\n{guild}"

            page.set_footer("Use the reactions to flip pages.")
            all_pages.append(page)

        await tools.create_paginator(self.bot, ctx, all_pages)
示例#14
0
    async def viewpremium(self, ctx):
        async with self.bot.pool.acquire() as conn:
            res = await conn.fetchrow(
                "SELECT guild FROM premium WHERE identifier=$1", ctx.author.id
            )

        if not res or not res[0]:
            await ctx.send(Embed("You have not assigned premium to any server."))
            return

        guilds = []
        for guild_id in res[0]:
            guild = await self.bot.get_guild(guild_id)
            guilds.append(f"{guild.name if guild else 'Unknown server'} `{guild_id}`")

        await ctx.send(Embed("Premium Servers", "\n".join(guilds)))
示例#15
0
    async def premiumassign(self, ctx, *, guild: GuildConverter):
        async with self.bot.pool.acquire() as conn:
            res = await conn.fetchrow(
                "SELECT identifier FROM premium WHERE $1=any(guild)", guild.id
            )

        if res:
            await ctx.send(ErrorEmbed("That server already has premium."))
            return

        async with self.bot.pool.acquire() as conn:
            res = await conn.fetchrow(
                "SELECT array_length(guild, 1) FROM premium WHERE identifier=$1", ctx.author.id
            )

        if res[0] and res[0] >= await tools.get_premium_slots(self.bot, ctx.author.id):
            await ctx.send(
                ErrorEmbed(
                    "You have reached the maximum number of slots that can be assigned. Please "
                    "upgrade your premium to increase the slots."
                )
            )
            return

        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                "UPDATE premium SET guild=array_append(guild, $1) WHERE identifier=$2",
                guild.id,
                ctx.author.id,
            )

        await ctx.send(Embed("That server now has premium."))
示例#16
0
    async def pingrole(self, ctx, roles: commands.Greedy[PingRoleConverter] = None):
        if roles is None:
            roles = []

        role_ids = []
        for role in roles:
            if not isinstance(role, Role):
                role = role.lower()
                role = role.replace("@", "", 1)

                if role == "everyone":
                    role_ids.append(ctx.guild.id)
                elif role == "here":
                    role_ids.append(-1)
                else:
                    await ctx.send(ErrorEmbed("The role(s) are not found. Please try again."))
                    return
            else:
                role_ids.append(role.id)

        if len(role_ids) > 10:
            await ctx.send(
                ErrorEmbed(
                    "There can at most be 10 roles. Try using the command again but specify fewer "
                    "roles."
                )
            )
            return

        async with self.bot.pool.acquire() as conn:
            await conn.execute("UPDATE data SET pingrole=$1 WHERE guild=$2", role_ids, ctx.guild.id)

        await ctx.send(Embed("The role(s) are updated successfully."))
示例#17
0
    async def premiumstatus(self, ctx):
        async with self.bot.pool.acquire() as conn:
            res = await conn.fetchrow(
                "SELECT identifier FROM premium WHERE $1=any(guild)", ctx.guild.id
            )

        await ctx.send(Embed(f"This server has premium. Offered by: <@{res[0]}>."))
示例#18
0
    async def userinfo(self, ctx, *, member: MemberConverter = None):
        if member is None:
            member = ctx.message.member

        roles = [role.name for role in await member.roles()]

        embed = Embed(title="User Information")
        embed.add_field(name="Name", value=str(member))
        embed.add_field(name="ID", value=member.id)
        embed.add_field(name="Nickname",
                        value=member.nick if member.nick else "*Not set*")
        embed.add_field(
            name="Avatar",
            value=f"[Link]({member.avatar_url_as(static_format='png')})")
        embed.add_field(name="Joined Server",
                        value=member.joined_at.replace(
                            microsecond=0) if member.joined_at else "Unknown")
        embed.add_field(name="Account Created",
                        value=member.created_at.replace(microsecond=0))
        embed.add_field(name="Roles",
                        value=f"{len(roles)} roles"
                        if len(", ".join(roles)) > 1000 else ", ".join(roles))
        embed.set_thumbnail(url=member.avatar_url)

        await ctx.send(embed=embed)
示例#19
0
 async def website(self, ctx):
     await ctx.send(
         embed=Embed(
             title="Website",
             description="https://modmail.xyz",
         )
     )
示例#20
0
    async def stats(self, ctx):
        total_seconds = int((datetime.utcnow() - await self.bot.started()).total_seconds())
        hours, remainder = divmod(total_seconds, 3600)
        minutes, seconds = divmod(remainder, 60)
        days, hours = divmod(hours, 24)

        bot_user = await self.bot.real_user()

        embed = Embed(
            title=f"{bot_user.name} Statistics",
            description="Visit the bot status page [here](https://status.modmail.xyz) for more information.",
        )
        embed.add_field(name="Owner", value="CHamburr#2591")
        embed.add_field(name="Bot Version", value=self.bot.version)
        if days:
            embed.add_field(name="Uptime", value=f"{days}d {hours}h {minutes}m {seconds}s")
        else:
            embed.add_field(name="Uptime", value=f"{hours}h {minutes}m {seconds}s")
        embed.add_field(name="Clusters", value=self.bot.cluster_count)
        if ctx.guild:
            embed.add_field(name="Shards", value=f"{ctx.guild.shard_id + 1}/{await self.bot.shard_count()}")
        else:
            embed.add_field(name="Shards", value=f"0/{await self.bot.shard_count()}")
        embed.add_field(name="Servers", value=str(await self.bot.state.scard("guild_keys")))
        embed.add_field(name="Channels", value=str(await self.bot.state.scard("channel_keys")))
        embed.add_field(name="Users", value=str(await self.bot.state.scard("user_keys")))
        embed.add_field(name="CPU Usage", value=f"{psutil.cpu_percent(interval=None)}%")
        embed.add_field(name="RAM Usage", value=f"{psutil.virtual_memory().percent}%")
        embed.add_field(name="Platform", value=" ".join(distro.linux_distribution()[:2]))
        embed.add_field(name="Python Version", value=platform.python_version())
        embed.set_thumbnail(url=bot_user.avatar_url)

        await ctx.send(embed=embed)
示例#21
0
 async def invite(self, ctx):
     await ctx.send(
         embed=Embed(
             title="Invite Link",
             description="https://modmail.xyz/invite",
         )
     )
示例#22
0
    async def banuser(self, ctx, *, user: UserConverter):
        async with self.bot.pool.acquire() as conn:
            await conn.execute("INSERT INTO ban VALUES ($1, $2)", user.id, 0)

        await self.bot.state.sadd("banned_users", user.id)

        await ctx.send(Embed("Successfully banned that user from the bot."))
示例#23
0
    async def serverinfo(self, ctx):
        guild = await self.bot.get_guild(ctx.guild.id)

        embed = Embed(title="Server Information")
        embed.add_field(name="Name", value=guild.name)
        embed.add_field(name="ID", value=guild.id)
        embed.add_field(
            name="Owner",
            value=f"<@{guild.owner_id}>" if guild.owner_id else "Unknown")
        embed.add_field(
            name="Icon",
            value=f"[Link]({guild.icon_url_as(static_format='png')})"
            if guild.icon else "*Not set*")
        embed.add_field(name="Server Created",
                        value=guild.created_at.replace(microsecond=0))
        embed.add_field(name="Members", value=guild.member_count)
        embed.add_field(name="Channels",
                        value=str(len(await guild.channels())))
        embed.add_field(name="Roles", value=str(len(await guild.roles())))
        embed.add_field(name="Emojis", value=str(len(await guild.emojis())))

        if guild.icon:
            embed.set_thumbnail(url=guild.icon_url)

        await ctx.send(embed=embed)
示例#24
0
    async def userinfo(self, ctx, *, member: MemberConverter = None):
        if member is None:
            member = ctx.message.member

        roles = [f"<@&{role}>" for role in member._roles]
        if len(roles) == 0:
            roles.append("*No roles*")

        embed = Embed(title="User Information")
        embed.add_field("Name", str(member))
        embed.add_field("ID", member.id)
        embed.add_field("Nickname", member.nick if member.nick else "*Not set*")
        embed.add_field("Avatar", f"[Link]({member.avatar_url_as(static_format='png')})")
        embed.add_field(
            "Joined Server",
            member.joined_at.replace(microsecond=0) if member.joined_at else "Unknown",
        )
        embed.add_field("Account Created", member.created_at.replace(microsecond=0))
        embed.add_field(
            "Roles",
            f"{len(roles)} roles" if len(", ".join(roles)) > 1000 else ", ".join(roles),
        )
        embed.set_thumbnail(member.avatar_url)

        await ctx.send(embed)
示例#25
0
 async def source(self, ctx):
     await ctx.send(
         embed=Embed(
             title="GitHub Repository",
             description="https://github.com/chamburr/modmail",
         )
     )
示例#26
0
 async def bash(self, ctx, *, command: str):
     try:
         output = subprocess.check_output(
             command.split(), stderr=subprocess.STDOUT).decode("utf-8")
         await ctx.send(Embed(f"```py\n{output}\n```"))
     except Exception as error:
         await ctx.send(
             ErrorEmbed(f"```py\n{error.__class__.__name__}: {error}\n```"))
示例#27
0
    async def _eval(self, ctx, *, body: str):
        env = {
            "bot": self.bot,
            "ctx": ctx,
            "channel": ctx.channel,
            "author": ctx.author,
            "guild": ctx.guild,
            "message": ctx.message,
        }
        env.update(globals())

        if body.startswith("```") and body.endswith("```"):
            body = "\n".join(body.split("\n")[1:-1])
        body = body.strip("` \n")

        try:
            exec(f"async def func():\n{textwrap.indent(body, '  ')}", env)
        except Exception as e:
            await ctx.send(embed=ErrorEmbed(
                description=f"```py\n{e.__class__.__name__}: {e}\n```"))
            return

        func = env["func"]
        stdout = io.StringIO()

        try:
            with redirect_stdout(stdout):
                ret = await func()
        except Exception:
            await ctx.send(embed=ErrorEmbed(
                description=
                f"```py\n{stdout.getvalue()}{traceback.format_exc()}\n```"))
            return

        try:
            await ctx.message.add_reaction("✅")
        except discord.Forbidden:
            pass

        value = stdout.getvalue()

        if ret is not None:
            await ctx.send(embed=Embed(description=f"```py\n{value}{ret}\n```")
                           )
        elif value is not None:
            await ctx.send(embed=Embed(description=f"```py\n{value}\n```"))
示例#28
0
    async def setup(self, ctx):
        msg = await ctx.send(Embed("Setting up..."))

        data = await tools.get_data(self.bot, ctx.guild.id)
        if await ctx.guild.get_channel(data[2]):
            await msg.edit(ErrorEmbed("The bot has already been set up."))
            return

        overwrites = await self._get_overwrites(ctx, data[3])
        category = await ctx.guild.create_category(name="ModMail", overwrites=overwrites)
        logging_channel = await ctx.guild.create_text_channel(name="modmail-log", category=category)

        async with self.bot.pool.acquire() as conn:
            await conn.execute(
                "UPDATE data SET category=$1, logging=$2 WHERE guild=$3",
                category.id,
                logging_channel.id,
                ctx.guild.id,
            )

        await msg.edit(
            Embed(
                "Premium",
                "Please consider purchasing premium! It is the best way you can show support to "
                "us. You will get access to premium features including greeting and closing "
                "messages, advanced logging that includes chat history, as well as the snippet "
                "functionality. You will also receive priority support in our server. For more "
                f"information, see `{ctx.prefix}premium`.",
            )
        )

        await ctx.send(
            Embed(
                "Setup",
                "Everything has been set up! Next up, you can give your staff access to ModMail "
                f"commands using `{ctx.prefix}accessrole [roles]` (by default, any user with the "
                f"administrator permission has full access). You can also test things out by "
                f"direct messaging me. Check out more information and configurations with "
                f"`{ctx.prefix}help`.",
            )
        )
示例#29
0
    async def snippetremove(self, ctx, *, name: str):
        async with self.bot.pool.acquire() as conn:
            res = await conn.execute(
                "DELETE FROM snippet WHERE name=$1 AND guild=$2", name,
                ctx.guild.id)

        if res == "DELETE 0":
            await ctx.send(
                ErrorEmbed("A snippet with that name was not found."))
            return

        await ctx.send(Embed("The snippet was removed successfully."))
示例#30
0
    async def closeall(self, ctx, *, reason: str = None):
        for channel in await ctx.guild.text_channels():
            if tools.is_modmail_channel(channel):
                msg = copy.copy(ctx.message)
                msg.channel = channel
                new_ctx = await self.bot.get_context(msg, cls=type(ctx))
                await self.close_channel(new_ctx, reason)

        try:
            await ctx.send(Embed("All channels are successfully closed."))
        except discord.HTTPException:
            pass