|
|
|
|
@ -13,7 +13,7 @@ from collections import namedtuple
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
from random import SystemRandom
|
|
|
|
|
from string import ascii_letters, digits
|
|
|
|
|
from typing import TYPE_CHECKING, Union
|
|
|
|
|
from typing import TYPE_CHECKING, Union, Tuple, List, Optional, Iterable, Sequence, Dict
|
|
|
|
|
|
|
|
|
|
import aiohttp
|
|
|
|
|
import discord
|
|
|
|
|
@ -25,6 +25,7 @@ from redbot.core import (
|
|
|
|
|
VersionInfo,
|
|
|
|
|
checks,
|
|
|
|
|
commands,
|
|
|
|
|
errors,
|
|
|
|
|
i18n,
|
|
|
|
|
)
|
|
|
|
|
from .utils.predicates import MessagePredicate
|
|
|
|
|
@ -59,7 +60,9 @@ class CoreLogic:
|
|
|
|
|
self.bot.register_rpc_handler(self._version_info)
|
|
|
|
|
self.bot.register_rpc_handler(self._invite_url)
|
|
|
|
|
|
|
|
|
|
async def _load(self, cog_names: list):
|
|
|
|
|
async def _load(
|
|
|
|
|
self, cog_names: Iterable[str]
|
|
|
|
|
) -> Tuple[List[str], List[str], List[str], List[str]]:
|
|
|
|
|
"""
|
|
|
|
|
Loads cogs by name.
|
|
|
|
|
Parameters
|
|
|
|
|
@ -69,11 +72,12 @@ class CoreLogic:
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
tuple
|
|
|
|
|
3 element tuple of loaded, failed, and not found cogs.
|
|
|
|
|
4-tuple of loaded, failed, not found and already loaded cogs.
|
|
|
|
|
"""
|
|
|
|
|
failed_packages = []
|
|
|
|
|
loaded_packages = []
|
|
|
|
|
notfound_packages = []
|
|
|
|
|
alreadyloaded_packages = []
|
|
|
|
|
|
|
|
|
|
bot = self.bot
|
|
|
|
|
|
|
|
|
|
@ -98,6 +102,8 @@ class CoreLogic:
|
|
|
|
|
try:
|
|
|
|
|
self._cleanup_and_refresh_modules(spec.name)
|
|
|
|
|
await bot.load_extension(spec)
|
|
|
|
|
except errors.PackageAlreadyLoaded:
|
|
|
|
|
alreadyloaded_packages.append(name)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
log.exception("Package loading failed", exc_info=e)
|
|
|
|
|
|
|
|
|
|
@ -109,9 +115,10 @@ class CoreLogic:
|
|
|
|
|
await bot.add_loaded_package(name)
|
|
|
|
|
loaded_packages.append(name)
|
|
|
|
|
|
|
|
|
|
return loaded_packages, failed_packages, notfound_packages
|
|
|
|
|
return loaded_packages, failed_packages, notfound_packages, alreadyloaded_packages
|
|
|
|
|
|
|
|
|
|
def _cleanup_and_refresh_modules(self, module_name: str):
|
|
|
|
|
@staticmethod
|
|
|
|
|
def _cleanup_and_refresh_modules(module_name: str) -> None:
|
|
|
|
|
"""Interally reloads modules so that changes are detected"""
|
|
|
|
|
splitted = module_name.split(".")
|
|
|
|
|
|
|
|
|
|
@ -123,6 +130,7 @@ class CoreLogic:
|
|
|
|
|
else:
|
|
|
|
|
importlib._bootstrap._exec(lib.__spec__, lib)
|
|
|
|
|
|
|
|
|
|
# noinspection PyTypeChecker
|
|
|
|
|
modules = itertools.accumulate(splitted, "{}.{}".format)
|
|
|
|
|
for m in modules:
|
|
|
|
|
maybe_reload(m)
|
|
|
|
|
@ -131,7 +139,10 @@ class CoreLogic:
|
|
|
|
|
for child_name, lib in children.items():
|
|
|
|
|
importlib._bootstrap._exec(lib.__spec__, lib)
|
|
|
|
|
|
|
|
|
|
def _get_package_strings(self, packages: list, fmt: str, other: tuple = None):
|
|
|
|
|
@staticmethod
|
|
|
|
|
def _get_package_strings(
|
|
|
|
|
packages: List[str], fmt: str, other: Optional[Tuple[str, ...]] = None
|
|
|
|
|
) -> str:
|
|
|
|
|
"""
|
|
|
|
|
Gets the strings needed for the load, unload and reload commands
|
|
|
|
|
"""
|
|
|
|
|
@ -147,7 +158,7 @@ class CoreLogic:
|
|
|
|
|
final_string = fmt.format(**form)
|
|
|
|
|
return final_string
|
|
|
|
|
|
|
|
|
|
async def _unload(self, cog_names: list):
|
|
|
|
|
async def _unload(self, cog_names: Iterable[str]) -> Tuple[List[str], List[str]]:
|
|
|
|
|
"""
|
|
|
|
|
Unloads cogs with the given names.
|
|
|
|
|
|
|
|
|
|
@ -175,14 +186,16 @@ class CoreLogic:
|
|
|
|
|
|
|
|
|
|
return unloaded_packages, failed_packages
|
|
|
|
|
|
|
|
|
|
async def _reload(self, cog_names):
|
|
|
|
|
async def _reload(
|
|
|
|
|
self, cog_names: Sequence[str]
|
|
|
|
|
) -> Tuple[List[str], List[str], List[str], List[str]]:
|
|
|
|
|
await self._unload(cog_names)
|
|
|
|
|
|
|
|
|
|
loaded, load_failed, not_found = await self._load(cog_names)
|
|
|
|
|
loaded, load_failed, not_found, already_loaded = await self._load(cog_names)
|
|
|
|
|
|
|
|
|
|
return loaded, load_failed, not_found
|
|
|
|
|
return loaded, load_failed, not_found, already_loaded
|
|
|
|
|
|
|
|
|
|
async def _name(self, name: str = None):
|
|
|
|
|
async def _name(self, name: Optional[str] = None) -> str:
|
|
|
|
|
"""
|
|
|
|
|
Gets or sets the bot's username.
|
|
|
|
|
|
|
|
|
|
@ -201,7 +214,7 @@ class CoreLogic:
|
|
|
|
|
|
|
|
|
|
return self.bot.user.name
|
|
|
|
|
|
|
|
|
|
async def _prefixes(self, prefixes: list = None):
|
|
|
|
|
async def _prefixes(self, prefixes: Optional[Sequence[str]] = None) -> List[str]:
|
|
|
|
|
"""
|
|
|
|
|
Gets or sets the bot's global prefixes.
|
|
|
|
|
|
|
|
|
|
@ -220,7 +233,8 @@ class CoreLogic:
|
|
|
|
|
await self.bot.db.prefix.set(prefixes)
|
|
|
|
|
return await self.bot.db.prefix()
|
|
|
|
|
|
|
|
|
|
async def _version_info(self):
|
|
|
|
|
@classmethod
|
|
|
|
|
async def _version_info(cls) -> Dict[str, str]:
|
|
|
|
|
"""
|
|
|
|
|
Version information for Red and discord.py
|
|
|
|
|
|
|
|
|
|
@ -231,7 +245,7 @@ class CoreLogic:
|
|
|
|
|
"""
|
|
|
|
|
return {"redbot": __version__, "discordpy": discord.__version__}
|
|
|
|
|
|
|
|
|
|
async def _invite_url(self):
|
|
|
|
|
async def _invite_url(self) -> str:
|
|
|
|
|
"""
|
|
|
|
|
Generates the invite URL for the bot.
|
|
|
|
|
|
|
|
|
|
@ -248,11 +262,8 @@ class CoreLogic:
|
|
|
|
|
class Core(commands.Cog, CoreLogic):
|
|
|
|
|
"""Commands related to core functions"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, bot):
|
|
|
|
|
super().__init__(bot)
|
|
|
|
|
|
|
|
|
|
@commands.command(hidden=True)
|
|
|
|
|
async def ping(self, ctx):
|
|
|
|
|
async def ping(self, ctx: commands.Context):
|
|
|
|
|
"""Pong."""
|
|
|
|
|
await ctx.send("Pong.")
|
|
|
|
|
|
|
|
|
|
@ -313,7 +324,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
passed = self.get_bot_uptime()
|
|
|
|
|
await ctx.send("Been up for: **{}** (since {} UTC)".format(passed, since))
|
|
|
|
|
|
|
|
|
|
def get_bot_uptime(self, *, brief=False):
|
|
|
|
|
def get_bot_uptime(self, *, brief: bool = False):
|
|
|
|
|
# Courtesy of Danny
|
|
|
|
|
now = datetime.datetime.utcnow()
|
|
|
|
|
delta = now - self.bot.uptime
|
|
|
|
|
@ -416,7 +427,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@commands.command()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def traceback(self, ctx, public: bool = False):
|
|
|
|
|
async def traceback(self, ctx: commands.Context, public: bool = False):
|
|
|
|
|
"""Sends to the owner the last command exception that has occurred
|
|
|
|
|
|
|
|
|
|
If public (yes is specified), it will be sent to the chat instead"""
|
|
|
|
|
@ -433,14 +444,14 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@commands.command()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def invite(self, ctx):
|
|
|
|
|
async def invite(self, ctx: commands.Context):
|
|
|
|
|
"""Show's Red's invite url"""
|
|
|
|
|
await ctx.author.send(await self._invite_url())
|
|
|
|
|
|
|
|
|
|
@commands.command()
|
|
|
|
|
@commands.guild_only()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def leave(self, ctx):
|
|
|
|
|
async def leave(self, ctx: commands.Context):
|
|
|
|
|
"""Leaves server"""
|
|
|
|
|
await ctx.send("Are you sure you want me to leave this server? (y/n)")
|
|
|
|
|
|
|
|
|
|
@ -460,7 +471,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@commands.command()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def servers(self, ctx):
|
|
|
|
|
async def servers(self, ctx: commands.Context):
|
|
|
|
|
"""Lists and allows to leave servers"""
|
|
|
|
|
guilds = sorted(list(self.bot.guilds), key=lambda s: s.name.lower())
|
|
|
|
|
msg = ""
|
|
|
|
|
@ -502,18 +513,21 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@commands.command()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def load(self, ctx, *, cog_name: str):
|
|
|
|
|
async def load(self, ctx: commands.Context, *cogs: str):
|
|
|
|
|
"""Loads packages"""
|
|
|
|
|
|
|
|
|
|
cog_names = [c.strip() for c in cog_name.split(" ")]
|
|
|
|
|
async with ctx.typing():
|
|
|
|
|
loaded, failed, not_found = await self._load(cog_names)
|
|
|
|
|
loaded, failed, not_found, already_loaded = await self._load(cogs)
|
|
|
|
|
|
|
|
|
|
if loaded:
|
|
|
|
|
fmt = "Loaded {packs}."
|
|
|
|
|
formed = self._get_package_strings(loaded, fmt)
|
|
|
|
|
await ctx.send(formed)
|
|
|
|
|
|
|
|
|
|
if already_loaded:
|
|
|
|
|
fmt = "The package{plural} {packs} {other} already loaded."
|
|
|
|
|
formed = self._get_package_strings(already_loaded, fmt, ("is", "are"))
|
|
|
|
|
await ctx.send(formed)
|
|
|
|
|
|
|
|
|
|
if failed:
|
|
|
|
|
fmt = (
|
|
|
|
|
"Failed to load package{plural} {packs}. Check your console or "
|
|
|
|
|
@ -529,12 +543,9 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@commands.command()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def unload(self, ctx, *, cog_name: str):
|
|
|
|
|
async def unload(self, ctx: commands.Context, *cogs: str):
|
|
|
|
|
"""Unloads packages"""
|
|
|
|
|
|
|
|
|
|
cog_names = [c.strip() for c in cog_name.split(" ")]
|
|
|
|
|
|
|
|
|
|
unloaded, failed = await self._unload(cog_names)
|
|
|
|
|
unloaded, failed = await self._unload(cogs)
|
|
|
|
|
|
|
|
|
|
if unloaded:
|
|
|
|
|
fmt = "Package{plural} {packs} {other} unloaded."
|
|
|
|
|
@ -548,10 +559,10 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@commands.command(name="reload")
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def reload(self, ctx, *cogs: str):
|
|
|
|
|
async def reload(self, ctx: commands.Context, *cogs: str):
|
|
|
|
|
"""Reloads packages"""
|
|
|
|
|
async with ctx.typing():
|
|
|
|
|
loaded, failed, not_found = await self._reload(cogs)
|
|
|
|
|
loaded, failed, not_found, already_loaded = await self._reload(cogs)
|
|
|
|
|
|
|
|
|
|
if loaded:
|
|
|
|
|
fmt = "Package{plural} {packs} {other} reloaded."
|
|
|
|
|
@ -570,34 +581,30 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@commands.command(name="shutdown")
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def _shutdown(self, ctx, silently: bool = False):
|
|
|
|
|
async def _shutdown(self, ctx: commands.Context, silently: bool = False):
|
|
|
|
|
"""Shuts down the bot"""
|
|
|
|
|
wave = "\N{WAVING HAND SIGN}"
|
|
|
|
|
skin = "\N{EMOJI MODIFIER FITZPATRICK TYPE-3}"
|
|
|
|
|
try: # We don't want missing perms to stop our shutdown
|
|
|
|
|
with contextlib.suppress(discord.HTTPException):
|
|
|
|
|
if not silently:
|
|
|
|
|
await ctx.send(_("Shutting down... ") + wave + skin)
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
await ctx.bot.shutdown()
|
|
|
|
|
|
|
|
|
|
@commands.command(name="restart")
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def _restart(self, ctx, silently: bool = False):
|
|
|
|
|
async def _restart(self, ctx: commands.Context, silently: bool = False):
|
|
|
|
|
"""Attempts to restart Red
|
|
|
|
|
|
|
|
|
|
Makes Red quit with exit code 26
|
|
|
|
|
The restart is not guaranteed: it must be dealt
|
|
|
|
|
with by the process manager in use"""
|
|
|
|
|
try:
|
|
|
|
|
with contextlib.suppress(discord.HTTPException):
|
|
|
|
|
if not silently:
|
|
|
|
|
await ctx.send(_("Restarting..."))
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
await ctx.bot.shutdown(restart=True)
|
|
|
|
|
|
|
|
|
|
@commands.group(name="set")
|
|
|
|
|
async def _set(self, ctx):
|
|
|
|
|
async def _set(self, ctx: commands.Context):
|
|
|
|
|
"""Changes Red's settings"""
|
|
|
|
|
if ctx.invoked_subcommand is None:
|
|
|
|
|
if ctx.guild:
|
|
|
|
|
@ -629,7 +636,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
@_set.command()
|
|
|
|
|
@checks.guildowner()
|
|
|
|
|
@commands.guild_only()
|
|
|
|
|
async def adminrole(self, ctx, *, role: discord.Role):
|
|
|
|
|
async def adminrole(self, ctx: commands.Context, *, role: discord.Role):
|
|
|
|
|
"""Sets the admin role for this server"""
|
|
|
|
|
await ctx.bot.db.guild(ctx.guild).admin_role.set(role.id)
|
|
|
|
|
await ctx.send(_("The admin role for this guild has been set."))
|
|
|
|
|
@ -637,7 +644,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
@_set.command()
|
|
|
|
|
@checks.guildowner()
|
|
|
|
|
@commands.guild_only()
|
|
|
|
|
async def modrole(self, ctx, *, role: discord.Role):
|
|
|
|
|
async def modrole(self, ctx: commands.Context, *, role: discord.Role):
|
|
|
|
|
"""Sets the mod role for this server"""
|
|
|
|
|
await ctx.bot.db.guild(ctx.guild).mod_role.set(role.id)
|
|
|
|
|
await ctx.send(_("The mod role for this guild has been set."))
|
|
|
|
|
@ -645,7 +652,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
@_set.command(aliases=["usebotcolor"])
|
|
|
|
|
@checks.guildowner()
|
|
|
|
|
@commands.guild_only()
|
|
|
|
|
async def usebotcolour(self, ctx):
|
|
|
|
|
async def usebotcolour(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
Toggle whether to use the bot owner-configured colour for embeds.
|
|
|
|
|
|
|
|
|
|
@ -663,7 +670,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
@_set.command()
|
|
|
|
|
@checks.guildowner()
|
|
|
|
|
@commands.guild_only()
|
|
|
|
|
async def serverfuzzy(self, ctx):
|
|
|
|
|
async def serverfuzzy(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
Toggle whether to enable fuzzy command search for the server.
|
|
|
|
|
|
|
|
|
|
@ -679,7 +686,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@_set.command()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def fuzzy(self, ctx):
|
|
|
|
|
async def fuzzy(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
Toggle whether to enable fuzzy command search in DMs.
|
|
|
|
|
|
|
|
|
|
@ -695,7 +702,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@_set.command(aliases=["color"])
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def colour(self, ctx, *, colour: discord.Colour = None):
|
|
|
|
|
async def colour(self, ctx: commands.Context, *, colour: discord.Colour = None):
|
|
|
|
|
"""
|
|
|
|
|
Sets a default colour to be used for the bot's embeds.
|
|
|
|
|
|
|
|
|
|
@ -713,7 +720,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@_set.command()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def avatar(self, ctx, url: str):
|
|
|
|
|
async def avatar(self, ctx: commands.Context, url: str):
|
|
|
|
|
"""Sets Red's avatar"""
|
|
|
|
|
async with aiohttp.ClientSession() as session:
|
|
|
|
|
async with session.get(url) as r:
|
|
|
|
|
@ -737,7 +744,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
@_set.command(name="game")
|
|
|
|
|
@checks.bot_in_a_guild()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def _game(self, ctx, *, game: str = None):
|
|
|
|
|
async def _game(self, ctx: commands.Context, *, game: str = None):
|
|
|
|
|
"""Sets Red's playing status"""
|
|
|
|
|
|
|
|
|
|
if game:
|
|
|
|
|
@ -751,7 +758,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
@_set.command(name="listening")
|
|
|
|
|
@checks.bot_in_a_guild()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def _listening(self, ctx, *, listening: str = None):
|
|
|
|
|
async def _listening(self, ctx: commands.Context, *, listening: str = None):
|
|
|
|
|
"""Sets Red's listening status"""
|
|
|
|
|
|
|
|
|
|
status = ctx.bot.guilds[0].me.status if len(ctx.bot.guilds) > 0 else discord.Status.online
|
|
|
|
|
@ -765,7 +772,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
@_set.command(name="watching")
|
|
|
|
|
@checks.bot_in_a_guild()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def _watching(self, ctx, *, watching: str = None):
|
|
|
|
|
async def _watching(self, ctx: commands.Context, *, watching: str = None):
|
|
|
|
|
"""Sets Red's watching status"""
|
|
|
|
|
|
|
|
|
|
status = ctx.bot.guilds[0].me.status if len(ctx.bot.guilds) > 0 else discord.Status.online
|
|
|
|
|
@ -779,7 +786,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
@_set.command()
|
|
|
|
|
@checks.bot_in_a_guild()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def status(self, ctx, *, status: str):
|
|
|
|
|
async def status(self, ctx: commands.Context, *, status: str):
|
|
|
|
|
"""Sets Red's status
|
|
|
|
|
|
|
|
|
|
Available statuses:
|
|
|
|
|
@ -808,7 +815,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
@_set.command()
|
|
|
|
|
@checks.bot_in_a_guild()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def stream(self, ctx, streamer=None, *, stream_title=None):
|
|
|
|
|
async def stream(self, ctx: commands.Context, streamer=None, *, stream_title=None):
|
|
|
|
|
"""Sets Red's streaming status
|
|
|
|
|
Leaving both streamer and stream_title empty will clear it."""
|
|
|
|
|
|
|
|
|
|
@ -829,7 +836,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@_set.command(name="username", aliases=["name"])
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def _username(self, ctx, *, username: str):
|
|
|
|
|
async def _username(self, ctx: commands.Context, *, username: str):
|
|
|
|
|
"""Sets Red's username"""
|
|
|
|
|
try:
|
|
|
|
|
await self._name(name=username)
|
|
|
|
|
@ -848,7 +855,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
@_set.command(name="nickname")
|
|
|
|
|
@checks.admin()
|
|
|
|
|
@commands.guild_only()
|
|
|
|
|
async def _nickname(self, ctx, *, nickname: str = None):
|
|
|
|
|
async def _nickname(self, ctx: commands.Context, *, nickname: str = None):
|
|
|
|
|
"""Sets Red's nickname"""
|
|
|
|
|
try:
|
|
|
|
|
await ctx.guild.me.edit(nick=nickname)
|
|
|
|
|
@ -859,7 +866,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@_set.command(aliases=["prefixes"])
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def prefix(self, ctx, *prefixes):
|
|
|
|
|
async def prefix(self, ctx: commands.Context, *prefixes: str):
|
|
|
|
|
"""Sets Red's global prefix(es)"""
|
|
|
|
|
if not prefixes:
|
|
|
|
|
await ctx.send_help()
|
|
|
|
|
@ -870,7 +877,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
@_set.command(aliases=["serverprefixes"])
|
|
|
|
|
@checks.admin()
|
|
|
|
|
@commands.guild_only()
|
|
|
|
|
async def serverprefix(self, ctx, *prefixes):
|
|
|
|
|
async def serverprefix(self, ctx: commands.Context, *prefixes: str):
|
|
|
|
|
"""Sets Red's server prefix(es)"""
|
|
|
|
|
if not prefixes:
|
|
|
|
|
await ctx.bot.db.guild(ctx.guild).prefix.set([])
|
|
|
|
|
@ -882,7 +889,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@_set.command()
|
|
|
|
|
@commands.cooldown(1, 60 * 10, commands.BucketType.default)
|
|
|
|
|
async def owner(self, ctx):
|
|
|
|
|
async def owner(self, ctx: commands.Context):
|
|
|
|
|
"""Sets Red's main owner"""
|
|
|
|
|
# According to the Python docs this is suitable for cryptographic use
|
|
|
|
|
random = SystemRandom()
|
|
|
|
|
@ -926,7 +933,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@_set.command()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def token(self, ctx, token: str):
|
|
|
|
|
async def token(self, ctx: commands.Context, token: str):
|
|
|
|
|
"""Change bot token."""
|
|
|
|
|
|
|
|
|
|
if not isinstance(ctx.channel, discord.DMChannel):
|
|
|
|
|
@ -1071,7 +1078,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@commands.command()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def backup(self, ctx, backup_path: str = None):
|
|
|
|
|
async def backup(self, ctx: commands.Context, backup_path: str = None):
|
|
|
|
|
"""Creates a backup of all data for the instance."""
|
|
|
|
|
from redbot.core.data_manager import basic_config, instance_name
|
|
|
|
|
from redbot.core.drivers.red_json import JSON
|
|
|
|
|
@ -1134,7 +1141,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
tar.add(str(f), recursive=False)
|
|
|
|
|
print(str(backup_file))
|
|
|
|
|
await ctx.send(
|
|
|
|
|
_("A backup has been made of this instance. It is at {}.").format((backup_file))
|
|
|
|
|
_("A backup has been made of this instance. It is at {}.").format(backup_file)
|
|
|
|
|
)
|
|
|
|
|
await ctx.send(_("Would you like to receive a copy via DM? (y/n)"))
|
|
|
|
|
|
|
|
|
|
@ -1157,7 +1164,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@commands.command()
|
|
|
|
|
@commands.cooldown(1, 60, commands.BucketType.user)
|
|
|
|
|
async def contact(self, ctx, *, message: str):
|
|
|
|
|
async def contact(self, ctx: commands.Context, *, message: str):
|
|
|
|
|
"""Sends a message to the owner"""
|
|
|
|
|
guild = ctx.message.guild
|
|
|
|
|
owner = discord.utils.get(ctx.bot.get_all_members(), id=ctx.bot.owner_id)
|
|
|
|
|
@ -1200,7 +1207,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(
|
|
|
|
|
_("I cannot send your message, I'm unable to find my owner... *sigh*")
|
|
|
|
|
)
|
|
|
|
|
except:
|
|
|
|
|
except discord.HTTPException:
|
|
|
|
|
await ctx.send(_("I'm unable to deliver your message. Sorry."))
|
|
|
|
|
else:
|
|
|
|
|
await ctx.send(_("Your message has been sent."))
|
|
|
|
|
@ -1212,14 +1219,14 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(
|
|
|
|
|
_("I cannot send your message, I'm unable to find my owner... *sigh*")
|
|
|
|
|
)
|
|
|
|
|
except:
|
|
|
|
|
except discord.HTTPException:
|
|
|
|
|
await ctx.send(_("I'm unable to deliver your message. Sorry."))
|
|
|
|
|
else:
|
|
|
|
|
await ctx.send(_("Your message has been sent."))
|
|
|
|
|
|
|
|
|
|
@commands.command()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def dm(self, ctx, user_id: int, *, message: str):
|
|
|
|
|
async def dm(self, ctx: commands.Context, user_id: int, *, message: str):
|
|
|
|
|
"""Sends a DM to a user
|
|
|
|
|
|
|
|
|
|
This command needs a user id to work.
|
|
|
|
|
@ -1253,7 +1260,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
await destination.send(embed=e)
|
|
|
|
|
except:
|
|
|
|
|
except discord.HTTPException:
|
|
|
|
|
await ctx.send(
|
|
|
|
|
_("Sorry, I couldn't deliver your message to {}").format(destination)
|
|
|
|
|
)
|
|
|
|
|
@ -1263,7 +1270,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
response = "{}\nMessage:\n\n{}".format(description, message)
|
|
|
|
|
try:
|
|
|
|
|
await destination.send("{}\n{}".format(box(response), content))
|
|
|
|
|
except:
|
|
|
|
|
except discord.HTTPException:
|
|
|
|
|
await ctx.send(
|
|
|
|
|
_("Sorry, I couldn't deliver your message to {}").format(destination)
|
|
|
|
|
)
|
|
|
|
|
@ -1272,7 +1279,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@commands.group()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def whitelist(self, ctx):
|
|
|
|
|
async def whitelist(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
Whitelist management commands.
|
|
|
|
|
"""
|
|
|
|
|
@ -1290,7 +1297,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(_("User added to whitelist."))
|
|
|
|
|
|
|
|
|
|
@whitelist.command(name="list")
|
|
|
|
|
async def whitelist_list(self, ctx):
|
|
|
|
|
async def whitelist_list(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
Lists whitelisted users.
|
|
|
|
|
"""
|
|
|
|
|
@ -1304,7 +1311,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(box(page))
|
|
|
|
|
|
|
|
|
|
@whitelist.command(name="remove")
|
|
|
|
|
async def whitelist_remove(self, ctx, user: discord.User):
|
|
|
|
|
async def whitelist_remove(self, ctx: commands.Context, user: discord.User):
|
|
|
|
|
"""
|
|
|
|
|
Removes user from whitelist.
|
|
|
|
|
"""
|
|
|
|
|
@ -1321,7 +1328,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(_("User was not in the whitelist."))
|
|
|
|
|
|
|
|
|
|
@whitelist.command(name="clear")
|
|
|
|
|
async def whitelist_clear(self, ctx):
|
|
|
|
|
async def whitelist_clear(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
Clears the whitelist.
|
|
|
|
|
"""
|
|
|
|
|
@ -1330,19 +1337,19 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
|
|
|
|
|
@commands.group()
|
|
|
|
|
@checks.is_owner()
|
|
|
|
|
async def blacklist(self, ctx):
|
|
|
|
|
async def blacklist(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
blacklist management commands.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
@blacklist.command(name="add")
|
|
|
|
|
async def blacklist_add(self, ctx, user: discord.User):
|
|
|
|
|
async def blacklist_add(self, ctx: commands.Context, user: discord.User):
|
|
|
|
|
"""
|
|
|
|
|
Adds a user to the blacklist.
|
|
|
|
|
"""
|
|
|
|
|
if await ctx.bot.is_owner(user):
|
|
|
|
|
ctx.send(_("You cannot blacklist an owner!"))
|
|
|
|
|
await ctx.send(_("You cannot blacklist an owner!"))
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
async with ctx.bot.db.blacklist() as curr_list:
|
|
|
|
|
@ -1352,7 +1359,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(_("User added to blacklist."))
|
|
|
|
|
|
|
|
|
|
@blacklist.command(name="list")
|
|
|
|
|
async def blacklist_list(self, ctx):
|
|
|
|
|
async def blacklist_list(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
Lists blacklisted users.
|
|
|
|
|
"""
|
|
|
|
|
@ -1366,7 +1373,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(box(page))
|
|
|
|
|
|
|
|
|
|
@blacklist.command(name="remove")
|
|
|
|
|
async def blacklist_remove(self, ctx, user: discord.User):
|
|
|
|
|
async def blacklist_remove(self, ctx: commands.Context, user: discord.User):
|
|
|
|
|
"""
|
|
|
|
|
Removes user from blacklist.
|
|
|
|
|
"""
|
|
|
|
|
@ -1383,7 +1390,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(_("User was not in the blacklist."))
|
|
|
|
|
|
|
|
|
|
@blacklist.command(name="clear")
|
|
|
|
|
async def blacklist_clear(self, ctx):
|
|
|
|
|
async def blacklist_clear(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
Clears the blacklist.
|
|
|
|
|
"""
|
|
|
|
|
@ -1393,14 +1400,14 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
@commands.group()
|
|
|
|
|
@commands.guild_only()
|
|
|
|
|
@checks.admin_or_permissions(administrator=True)
|
|
|
|
|
async def localwhitelist(self, ctx):
|
|
|
|
|
async def localwhitelist(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
Whitelist management commands.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
@localwhitelist.command(name="add")
|
|
|
|
|
async def localwhitelist_add(self, ctx, *, user_or_role: str):
|
|
|
|
|
async def localwhitelist_add(self, ctx: commands.Context, *, user_or_role: str):
|
|
|
|
|
"""
|
|
|
|
|
Adds a user or role to the whitelist.
|
|
|
|
|
"""
|
|
|
|
|
@ -1421,7 +1428,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(_("Role added to whitelist."))
|
|
|
|
|
|
|
|
|
|
@localwhitelist.command(name="list")
|
|
|
|
|
async def localwhitelist_list(self, ctx):
|
|
|
|
|
async def localwhitelist_list(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
Lists whitelisted users and roles.
|
|
|
|
|
"""
|
|
|
|
|
@ -1435,7 +1442,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(box(page))
|
|
|
|
|
|
|
|
|
|
@localwhitelist.command(name="remove")
|
|
|
|
|
async def localwhitelist_remove(self, ctx, *, user_or_role: str):
|
|
|
|
|
async def localwhitelist_remove(self, ctx: commands.Context, *, user_or_role: str):
|
|
|
|
|
"""
|
|
|
|
|
Removes user or role from whitelist.
|
|
|
|
|
"""
|
|
|
|
|
@ -1465,7 +1472,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(_("Role was not in the whitelist."))
|
|
|
|
|
|
|
|
|
|
@localwhitelist.command(name="clear")
|
|
|
|
|
async def localwhitelist_clear(self, ctx):
|
|
|
|
|
async def localwhitelist_clear(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
Clears the whitelist.
|
|
|
|
|
"""
|
|
|
|
|
@ -1475,14 +1482,14 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
@commands.group()
|
|
|
|
|
@commands.guild_only()
|
|
|
|
|
@checks.admin_or_permissions(administrator=True)
|
|
|
|
|
async def localblacklist(self, ctx):
|
|
|
|
|
async def localblacklist(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
blacklist management commands.
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
@localblacklist.command(name="add")
|
|
|
|
|
async def localblacklist_add(self, ctx, *, user_or_role: str):
|
|
|
|
|
async def localblacklist_add(self, ctx: commands.Context, *, user_or_role: str):
|
|
|
|
|
"""
|
|
|
|
|
Adds a user or role to the blacklist.
|
|
|
|
|
"""
|
|
|
|
|
@ -1495,7 +1502,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
user = True
|
|
|
|
|
|
|
|
|
|
if user and await ctx.bot.is_owner(obj):
|
|
|
|
|
ctx.send(_("You cannot blacklist an owner!"))
|
|
|
|
|
await ctx.send(_("You cannot blacklist an owner!"))
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
async with ctx.bot.db.guild(ctx.guild).blacklist() as curr_list:
|
|
|
|
|
@ -1508,7 +1515,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(_("Role added to blacklist."))
|
|
|
|
|
|
|
|
|
|
@localblacklist.command(name="list")
|
|
|
|
|
async def localblacklist_list(self, ctx):
|
|
|
|
|
async def localblacklist_list(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
Lists blacklisted users and roles.
|
|
|
|
|
"""
|
|
|
|
|
@ -1522,7 +1529,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(box(page))
|
|
|
|
|
|
|
|
|
|
@localblacklist.command(name="remove")
|
|
|
|
|
async def localblacklist_remove(self, ctx, *, user_or_role: str):
|
|
|
|
|
async def localblacklist_remove(self, ctx: commands.Context, *, user_or_role: str):
|
|
|
|
|
"""
|
|
|
|
|
Removes user or role from blacklist.
|
|
|
|
|
"""
|
|
|
|
|
@ -1552,7 +1559,7 @@ class Core(commands.Cog, CoreLogic):
|
|
|
|
|
await ctx.send(_("Role was not in the blacklist."))
|
|
|
|
|
|
|
|
|
|
@localblacklist.command(name="clear")
|
|
|
|
|
async def localblacklist_clear(self, ctx):
|
|
|
|
|
async def localblacklist_clear(self, ctx: commands.Context):
|
|
|
|
|
"""
|
|
|
|
|
Clears the blacklist.
|
|
|
|
|
"""
|
|
|
|
|
|