|
1
|
|
|
import os |
|
2
|
|
|
import requests |
|
3
|
|
|
import asyncio |
|
4
|
|
|
import datetime |
|
5
|
|
|
import copy |
|
6
|
|
|
import random |
|
7
|
|
|
import io |
|
8
|
|
|
import textwrap |
|
9
|
|
|
import traceback |
|
10
|
|
|
from typing import Optional |
|
11
|
|
|
from contextlib import redirect_stdout |
|
12
|
|
|
import discord |
|
13
|
|
|
from discord.ext import commands |
|
14
|
|
|
from utils.global_utils import send_or_hastebin, cleanup_code, send_embedded |
|
15
|
|
|
|
|
16
|
|
|
|
|
17
|
|
|
class GlobalChannel(commands.Converter): |
|
18
|
|
|
async def convert(self, ctx, argument): |
|
19
|
|
|
try: |
|
20
|
|
|
return await commands.TextChannelConverter().convert(ctx, argument) |
|
21
|
|
|
except commands.BadArgument: |
|
22
|
|
|
# Not found... so fall back to ID + global lookup |
|
23
|
|
|
try: |
|
24
|
|
|
channel_id = int(argument, base=10) |
|
25
|
|
|
except ValueError: |
|
26
|
|
|
raise commands.BadArgument(f"Could not find a channel by ID {argument!r}.") |
|
27
|
|
|
else: |
|
28
|
|
|
channel = ctx.bot.get_channel(channel_id) |
|
29
|
|
|
if channel is None: |
|
30
|
|
|
raise commands.BadArgument(f"Could not find a channel by ID {argument!r}.") |
|
31
|
|
|
return |
|
32
|
|
|
|
|
33
|
|
|
|
|
34
|
|
|
class admin(commands.Cog): |
|
35
|
|
|
"""admin commands on which mortals will **never** lay an eye upon""" |
|
36
|
|
|
|
|
37
|
|
|
def __init__(self, bot): |
|
38
|
|
|
self.bot = bot |
|
39
|
|
|
self._last_result = None |
|
40
|
|
|
|
|
41
|
|
|
@commands.command(name="load", hidden=True) |
|
42
|
|
|
@commands.is_owner() |
|
43
|
|
|
async def loadcog(self, ctx, cog: str = None): |
|
44
|
|
|
""" loads the cog to the bot""" |
|
45
|
|
|
if cog is None: |
|
46
|
|
|
await ctx.send("Please enter a cog to load it") |
|
47
|
|
|
else: |
|
48
|
|
|
msg = await ctx.send(f"Loading cog `{cog}`... :arrows_counterclockwise:") |
|
49
|
|
|
try: |
|
50
|
|
|
self.bot.load_extension(f"cogs.{cog}") |
|
51
|
|
|
await msg.edit(content="Cog loaded successfully! :white_check_mark:") |
|
52
|
|
|
except Exception as e: |
|
53
|
|
|
await msg.edit(content=f"**Error** {e.__class__.__name__} - {e}") |
|
54
|
|
|
|
|
55
|
|
|
@commands.command(name="unload", hidden=True) |
|
56
|
|
|
@commands.is_owner() |
|
57
|
|
|
async def unloadcog(self, ctx, cog: str = None): |
|
58
|
|
|
"""unloads the cog from the bot""" |
|
59
|
|
|
if cog is None: |
|
60
|
|
|
await ctx.send("Please enter a cog to unload it") |
|
61
|
|
|
else: |
|
62
|
|
|
msg = await ctx.send(f"Unloading cog `{cog}`... :arrows_counterclockwise:") |
|
63
|
|
|
try: |
|
64
|
|
|
self.bot.unload_extension(f"cogs.{cog}") |
|
65
|
|
|
await msg.edit(content="Cog unloaded successfully! :white_check_mark:") |
|
66
|
|
|
except Exception as e: |
|
67
|
|
|
await msg.edit(content=f"**Error** {e.__class__.__name__} - {e}") |
|
68
|
|
|
|
|
69
|
|
|
@commands.command(name="reload", hidden=True) |
|
70
|
|
|
@commands.is_owner() |
|
71
|
|
|
async def reloadcog(self, ctx, cog: str = None): |
|
72
|
|
|
"""reloads a cog""" |
|
73
|
|
|
if cog is None: |
|
74
|
|
|
await ctx.send("Please enter a cog to reload it") |
|
75
|
|
|
else: |
|
76
|
|
|
msg = await ctx.send(f"Reloading cog `{cog}`... :arrows_counterclockwise:") |
|
77
|
|
|
try: |
|
78
|
|
|
self.bot.reload_extension(f"cogs.{cog}") |
|
79
|
|
|
await msg.edit(content="Cog reloaded successfully! :white_check_mark:") |
|
80
|
|
|
except Exception as e: |
|
81
|
|
|
await msg.edit(content=f"**Error** {e.__class__.__name__} - {e}") |
|
82
|
|
|
|
|
83
|
|
|
@commands.command(name="eval", hidden=True) |
|
84
|
|
|
@commands.is_owner() |
|
85
|
|
|
@commands.bot_has_permissions(send_messages=True) |
|
86
|
|
|
async def _eval(self, ctx, *, code: str): |
|
87
|
|
|
""" |
|
88
|
|
|
Evaluates python code in a single line or code block |
|
89
|
|
|
|
|
90
|
|
|
Blatantly stolen from: |
|
91
|
|
|
https://github.com/Rapptz/RoboDanny/blob/rewrite/cogs/admin.py |
|
92
|
|
|
""" |
|
93
|
|
|
env = { |
|
94
|
|
|
"bot": self.bot, |
|
95
|
|
|
"ctx": ctx, |
|
96
|
|
|
"channel": ctx.channel, |
|
97
|
|
|
"author": ctx.author, |
|
98
|
|
|
"guild": ctx.guild, |
|
99
|
|
|
"message": ctx.message, |
|
100
|
|
|
"_": self._last_result, |
|
101
|
|
|
} |
|
102
|
|
|
|
|
103
|
|
|
env.update(globals()) |
|
104
|
|
|
code = cleanup_code(code) |
|
105
|
|
|
stdout = io.StringIO() |
|
106
|
|
|
to_compile = f'async def func():\n{textwrap.indent(code, " ")}' |
|
107
|
|
|
|
|
108
|
|
|
try: |
|
109
|
|
|
exec(to_compile, env) |
|
110
|
|
|
except Exception as e: |
|
111
|
|
|
return await ctx.send(f"```py\n{e.__class__.__name__}: {e}\n```") |
|
112
|
|
|
|
|
113
|
|
|
func = env["func"] |
|
114
|
|
|
try: |
|
115
|
|
|
with redirect_stdout(stdout): |
|
116
|
|
|
ret = await func() |
|
117
|
|
|
except Exception as e: |
|
118
|
|
|
value = stdout.getvalue() |
|
119
|
|
|
await ctx.send(f"```py\n{value}{traceback.format_exc()}\n```") |
|
120
|
|
|
else: |
|
121
|
|
|
value = stdout.getvalue() |
|
122
|
|
|
try: |
|
123
|
|
|
await ctx.message.add_reaction("\u2705") |
|
124
|
|
|
except: |
|
125
|
|
|
pass |
|
126
|
|
|
|
|
127
|
|
|
if ret is None: |
|
128
|
|
|
if value: |
|
129
|
|
|
await send_or_hastebin(ctx, content=value, code="py") |
|
130
|
|
|
else: |
|
131
|
|
|
self._last_result = ret |
|
132
|
|
|
await send_or_hastebin(ctx, f"{value}{ret}", code="py") |
|
133
|
|
|
|
|
134
|
|
|
@commands.command(hidden=True, aliases=["ext"]) |
|
135
|
|
|
async def extensions(self, ctx): |
|
136
|
|
|
"""Lists the currently loaded extensions.""" |
|
137
|
|
|
await send_embedded(ctx, "\n".join(sorted([i for i in self.bot.extensions.keys()]))) |
|
138
|
|
|
|
|
139
|
|
|
@commands.command(hidden=True) |
|
140
|
|
|
@commands.is_owner() |
|
141
|
|
|
async def spam(self, ctx, amount, *, content: str): |
|
142
|
|
|
"""spams a message to the channel""" |
|
143
|
|
|
await ctx.message.delete() |
|
144
|
|
|
for spam in range(int(amount)): |
|
145
|
|
|
await ctx.send(content) |
|
146
|
|
|
|
|
147
|
|
|
@commands.command(hidden=True) |
|
148
|
|
|
@commands.is_owner() |
|
149
|
|
|
async def botsay(self, ctx, channel: Optional[GlobalChannel], embed: bool = False, *, stuff: str): |
|
150
|
|
|
"""bot says whatever you type wit ability to embed and select a channel""" |
|
151
|
|
|
msg = copy.copy(ctx.message) |
|
152
|
|
|
channel = channel or ctx.channel |
|
153
|
|
|
msg.channel = channel |
|
154
|
|
|
msg.content = stuff |
|
155
|
|
|
new = await self.bot.get_context(msg, cls=type(ctx)) |
|
156
|
|
|
if embed: |
|
157
|
|
|
await send_embedded(new, stuff) |
|
158
|
|
|
else: |
|
159
|
|
|
await new.send(stuff) |
|
160
|
|
|
|
|
161
|
|
|
@commands.command(hidden=True) |
|
162
|
|
|
@commands.is_owner() |
|
163
|
|
|
async def sudo(self, ctx, channel: Optional[GlobalChannel], who: discord.User, *, command: str): |
|
164
|
|
|
"""run a command as someone else""" |
|
165
|
|
|
msg = copy.copy(ctx.message) |
|
166
|
|
|
channel = channel or ctx.channel |
|
167
|
|
|
msg.channel = channel |
|
168
|
|
|
msg.author = channel.guild.get_member(who.id) or who |
|
169
|
|
|
msg.content = ctx.prefix + command |
|
170
|
|
|
new = await self.bot.get_context(msg, cls=type(ctx)) |
|
171
|
|
|
await self.bot.invoke(new) |
|
172
|
|
|
|
|
173
|
|
|
|
|
174
|
|
|
def setup(bot): |
|
175
|
|
|
bot.add_cog(admin(bot)) |
|
176
|
|
|
|