aboutsummaryrefslogtreecommitdiff
path: root/modules/admin.py
blob: c07b594338a342cac360162821bbcc0d498c0069 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import re
from typing import Dict, List, Pattern

import discord
from discord import Color, Embed
from discord.ext import commands
from discord.ext.commands import Bot, command, Context as CommandContext, is_owner

from util import load_all_modules

REPLACEMENTS: Dict[Pattern, str] = {
    re.compile(r'<@!?(?P<id>[0-9]+)>'): '(guild.get_member({id}) if guild is not None '
                                        'else client.get_user({id}))',
    re.compile(r'<#(?P<id>[0-9]+)>'): '(discord.utils.get(all_channels, id={id}))',
    re.compile(r'<@&(?P<id>[0-9]+)>'): '(discord.utils.get(all_roles, id={id}))',
    # Maybe later emoji support
}


async def handle_eval(message: discord.Message, client: discord.Client, to_eval: str):
    channel: discord.TextChannel = message.channel
    author: discord.Member = message.author

    all_channels: List[discord.Guild] = []
    all_roles: List[discord.Role] = []
    for guild in client.guilds:
        guild: discord.Guild = guild  # for type hints
        all_channels += guild.channels
        all_roles += guild.roles

    variables = {
        'message': message,
        'author': author,
        'channel': channel,
        'all_channels': all_channels,
        'all_roles': all_roles,
        'client': client,
        'discord': discord,
        'print': (lambda *text: client.loop.create_task(channel.send(' '.join(text)))),
        'guild': channel.guild if hasattr(channel, 'guild') else None,
    }
    if channel.guild is not None:
        variables['guild'] = channel.guild
    lines: List[str] = to_eval.strip().split('\n')
    lines[-1] = 'return ' + lines[-1]
    block: str = '\n'.join(' ' + line for line in lines)
    code = f"async def code({', '.join(variables.keys())}):\n" \
           f"{block}"

    for regex, replacement in REPLACEMENTS.items():
        code = re.sub(regex, lambda match: replacement.format(**match.groupdict()), code)

    _globals, _locals = {}, {}
    try:
        exec(code, _globals, _locals)
    except Exception as e:
        await message.channel.send(
            embed=discord.Embed(color=discord.Color.red(),
                                description="Compiler Error: `%s`" % (str(e))))
        return
    result = {**_globals, **_locals}
    try:
        result = await result["code"](**variables)
    except Exception as e:
        await message.channel.send(
            embed=discord.Embed(color=discord.Color.red(),
                                description="Runtime Error: `%s`" % (str(e))))
        return

    return await channel.send(
        embed=Embed(
            color=Color.red(),
            description="📥 Evaluation success: ```py\n%r\n```" % result))


class AdminCog(commands.Cog, object):
    def __init__(self, bot: commands.Bot):
        self.bot: commands.Bot = bot

    @command()
    @is_owner()
    async def eval(self, ctx: CommandContext, *, to_eval: str = None):
        if to_eval is None:
            return await ctx.send(
                embed=Embed(
                    description="<Insert generic insult about your stupidity here>",
                    color=Color.red()))
        await handle_eval(ctx.message, self.bot, to_eval)

    async def on_ready(self):
        print('-' * 50)
        print('Name:   ' + self.bot.user.name)
        print('Guilds: ' + ', '.join(guild.name for guild in self.bot.guilds))
        print('-' * 50)

    @command()
    @is_owner()
    async def reload(self, ctx: CommandContext, *extensions):
        for extension in (extensions or self.bot.extensions.copy().keys()):
            self.bot.unload_extension(extension)
        await ctx.send(
            embed=Embed(
                color=Color.red(),
                description='Unloaded extensions', ))
        if len(extensions) == 0:
            load_all_modules(self.bot)
        else:
            for extension in extensions:
                try:
                    self.bot.load_extension(extension)
                except Exception as e:
                    print(e)
                    await ctx.send(
                        embed=Embed(
                            title=f"Failed to load module `{extension}`",
                            color=Color.red()))
        await ctx.send(
            embed=Embed(
                title=f"Reloaded {len(extensions) or len(self.bot.extensions)} extension(s)",
                color=Color.green()))


def setup(bot: Bot):
    bot.add_cog(AdminCog(bot))