diff --git a/.gitignore b/.gitignore index f4ca4c697..c39171c95 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ __pycache__ data !data/trivia/* !data/audio/playlists/* +*.exe +*.dll \ No newline at end of file diff --git a/cogs/alias.py b/cogs/alias.py new file mode 100644 index 000000000..209e22189 --- /dev/null +++ b/cogs/alias.py @@ -0,0 +1,122 @@ +import discord +from discord.ext import commands +from .utils import checks +from .utils.chat_formatting import * +from .utils.dataIO import fileIO +from .utils import checks +from __main__ import send_cmd_help +import os + +class Alias: + def __init__(self,bot): + self.bot = bot + self.aliases = fileIO("data/alias/aliases.json","load") + + @commands.group(pass_context=True) + @checks.mod_or_permissions(manage_server=True) + async def alias(self,ctx): + """Manage per-server aliases for commands""" + if ctx.invoked_subcommand is None: + await send_cmd_help(ctx) + + @alias.command(name="add",pass_context=True) + async def _add_alias(self,ctx,command : str,*,to_execute): + """Add an alias for a command + + Example: !alias add test penis @TwentySix""" + server = ctx.message.server + if self.get_prefix(to_execute) == False: + to_execute = self.bot.command_prefix[0] + to_execute + if server.id not in self.aliases: + self.aliases[server.id] = {} + #curr_aliases = self.aliases[server.id] + if command not in self.bot.commands: + self.aliases[server.id][command] = to_execute + fileIO("data/alias/aliases.json","save",self.aliases) + await self.bot.say("Alias '{}' added.".format(command)) + else: + await self.bot.say("Cannot add '{}' because it's a real bot command.".format(command)) + + @alias.command(name="help",pass_context=True) + async def _help_alias(self,ctx,command): + """Tries to execute help for the base command of the alias""" + server = ctx.message.server + if server.id in self.aliases: + server_aliases = self.aliases[server.id] + if command in server_aliases: + help_cmd = server_aliases[command].split(" ")[0] + new_content = self.bot.command_prefix[0] + new_content += "help " + new_content += help_cmd[len(self.get_prefix(help_cmd)):] + message = ctx.message + message.content = new_content + await self.bot.process_commands(message) + else: + await self.bot.say("That alias doesn't exist.") + + @alias.command(name="show",pass_context=True) + async def _show_alias(self,ctx,command): + """Shows what command the alias executes.""" + server = ctx.message.server + if server.id in self.aliases: + server_aliases = self.aliases[server.id] + if command in server_aliases: + await self.bot.say(box(server_aliases[command])) + else: + await self.bot.say("That alias doesn't exist.") + + @alias.command(name="del",pass_context=True) + async def _del_alias(self,ctx,command : str): + """Deletes an alias""" + server = ctx.message.server + if server.id in self.aliases: + self.aliases[server.id].pop(command,None) + fileIO("data/alias/aliases.json","save",self.aliases) + await self.bot.say("Alias '{}' deleted.".format(command)) + + async def check_aliases(self,message): + if message.author.id == self.bot.user.id or len(message.content) < 2 or message.channel.is_private: + return + + msg = message.content + server = message.server + prefix = self.get_prefix(msg) + + if prefix and server.id in self.aliases: + aliaslist = self.aliases[server.id] + alias = msg[len(prefix):].split(" ")[0] + args = msg[len(self.first_word(message.content)):] + if alias in aliaslist.keys(): + content = aliaslist[alias] + args + new_message = message + new_message.content = content + await self.bot.process_commands(new_message) + + def first_word(self,msg): + return msg.split(" ")[0] + + def get_prefix(self, msg): + for p in self.bot.command_prefix: + if msg.startswith(p): + return p + return False + +def check_folder(): + if not os.path.exists("data/alias"): + print("Creating data/alias folder...") + os.makedirs("data/alias") + +def check_file(): + aliases = {} + + f = "data/alias/aliases.json" + if not fileIO(f, "check"): + print("Creating default alias's aliases.json...") + fileIO(f, "save", aliases) + +def setup(bot): + check_folder() + check_file() + n = Alias(bot) + bot.add_listener(n.check_aliases, "on_message") + bot.add_cog(n) \ No newline at end of file diff --git a/cogs/mod.py b/cogs/mod.py index dd9685991..c9c84f84a 100644 --- a/cogs/mod.py +++ b/cogs/mod.py @@ -2,9 +2,10 @@ import discord from discord.ext import commands from .utils import checks from .utils.dataIO import fileIO -from __main__ import send_cmd_help +from __main__ import send_cmd_help, settings import os import logging +import json class Mod: """Moderation tools.""" @@ -16,6 +17,56 @@ class Mod: self.ignore_list = fileIO("data/mod/ignorelist.json", "load") self.filter = fileIO("data/mod/filter.json", "load") + # HEY, YOU THERE, READ THIS + # In order to save modified BOT settings you MUST: + # 1) use self.bot_settings to GET the current settings + # THEN + # 2) Use checks.save_bot_settings(modified_bot_settings) + # 3) Don't blame me (Will), blame the other guy (not 26) + @property + def bot_settings(self): + settings = {} + with open("data/red/settings.json", "r") as f: + settings = json.loads(f.read()) + if settings == {}: + raise RuntimeError("Settings not found.") + return settings + + @commands.group(pass_context=True) + @checks.admin_or_permissions(manage_server=True) + async def modset(self,ctx): + """Manages server administration settings.""" + if ctx.invoked_subcommand is None: + send_cmd_help(ctx) + + @modset.command(name="adminrole",pass_context=True) + async def _modset_adminrole(self,ctx,role_name : str): + """Sets the admin role for this server, case insensitive.""" + sid = ctx.message.server.id + settings = self.bot_settings + if sid in settings: + settings[sid]["ADMIN_ROLE"] = role_name + else: + settings[sid] = {"ADMIN_ROLE":role_name,"MOD_ROLE":""} + settings[sid]["MOD_ROLE"] = settings["default"]["MOD_ROLE"] + await self.bot.say("Remember to set modrole too.") + await self.bot.say("Admin role set to '{}'".format(role_name)) + checks.save_bot_settings(settings) + + @modset.command(name="modrole",pass_context=True) + async def _modset_modrole(self,ctx,role_name : str): + """Sets the mod role for this server, case insensitive.""" + sid = ctx.message.server.id + settings = self.bot_settings + if sid in settings: + settings[sid]["MOD_ROLE"] = role_name + else: + settings[sid] = {"MOD_ROLE":role_name,"ADMIN_ROLE":""} + settings[sid]["ADMIN_ROLE"] = settings["default"]["ADMIN_ROLE"] + await self.bot.say("Remember to set adminrole too.") + await self.bot.say("Mod role set to '{}'".format(role_name)) + checks.save_bot_settings(settings) + @commands.command(no_pm=True, pass_context=True) @checks.admin_or_permissions(kick_members=True) async def kick(self, ctx, user : discord.Member): diff --git a/cogs/utils/chat_formatting.py b/cogs/utils/chat_formatting.py new file mode 100644 index 000000000..79631b77f --- /dev/null +++ b/cogs/utils/chat_formatting.py @@ -0,0 +1,17 @@ +def bold(text): + return "**"+str(text)+"**" + +def italics(text): + return "*"+str(text)+"*" + +def strikethrough(text): + return "~~"+str(text)+"~~" + +def underline(text): + return "__"+str(text)+"__" + +def box(text): + return "```"+str(text)+"```" + +def inline(text): + return "`"+str(text)+"`" \ No newline at end of file diff --git a/cogs/utils/checks.py b/cogs/utils/checks.py index d480579ce..e62282e73 100644 --- a/cogs/utils/checks.py +++ b/cogs/utils/checks.py @@ -13,8 +13,9 @@ import json try: with open("data/red/settings.json", "r") as f: settings = json.loads(f.read()) -except: - settings = {"OWNER" : False, "ADMIN_ROLE" : False, "MOD_ROLE" : False} +except Exception as e: + print(e) + settings = {"OWNER" : False, "default":{"ADMIN_ROLE" : False, "MOD_ROLE" : False}} def is_owner_check(ctx): return ctx.message.author.id == settings["OWNER"] @@ -32,6 +33,17 @@ def is_owner(): # the permissions required for them. # Of course, the owner will always be able to execute commands. +def save_bot_settings(bot_settings=settings): + with open("data/red/settings.json", "w") as f: + f.write(json.dumps(bot_settings,sort_keys=True,indent=4,separators=(',',':'))) + +def update_old_settings(): + mod = settings["MOD_ROLE"] + admin = settings["ADMIN_ROLE"] + del settings["MOD_ROLE"] + del settings["ADMIN_ROLE"] + settings["default"] = {"MOD_ROLE":mod,"ADMIN_ROLE":admin} + def check_permissions(ctx, perms): if is_owner_check(ctx): return True @@ -55,12 +67,30 @@ def role_or_permissions(ctx, check, **perms): def mod_or_permissions(**perms): def predicate(ctx): - return role_or_permissions(ctx, lambda r: r.name in (settings["MOD_ROLE"], settings["ADMIN_ROLE"]), **perms) + if "default" not in settings: + update_old_settings() + if admin_or_permissions(**perms): + return True + sid = ctx.message.server.id + if sid not in settings: + mod_role = settings["default"]["MOD_ROLE"].lower() + admin_role = settings["default"]["ADMIN_ROLE"].lower() + else: + mod_role = settings[sid]["MOD_ROLE"].lower() + admin_role = settings[sid]["ADMIN_ROLE"].lower() + return role_or_permissions(ctx, lambda r: r.name.lower() in (mod_role,admin_role), **perms) return commands.check(predicate) def admin_or_permissions(**perms): def predicate(ctx): - return role_or_permissions(ctx, lambda r: r.name == settings["ADMIN_ROLE"], **perms) + if "default" not in settings: + update_old_settings() + sid = ctx.message.server.id + if sid not in settings: + admin_role = settings["default"]["ADMIN_ROLE"] + else: + admin_role = settings[sid]["ADMIN_ROLE"] + return role_or_permissions(ctx, lambda r: r.name.lower() == admin_role.lower(), **perms) return commands.check(predicate) diff --git a/red.py b/red.py index 84b0f696f..197ce68a2 100644 --- a/red.py +++ b/red.py @@ -195,7 +195,7 @@ async def prefix(*prefixes): data = load_settings() data["PREFIXES"] = list(prefixes) with open("data/red/settings.json", "w") as f: - f.write(json.dumps(data)) + f.write(json.dumps(data)) if len(prefixes) > 1: await bot.say("Prefixes set") else: @@ -280,9 +280,13 @@ def user_allowed(message): if checks.settings["OWNER"] == author.id: return True if not message.channel.is_private: - if discord.utils.get(author.roles, name=checks.settings["ADMIN_ROLE"]) is not None: - return True - if discord.utils.get(author.roles, name=checks.settings["MOD_ROLE"]) is not None: + sid = message.server.id + if sid in checks.settings: + names = (checks.settings[sid]["ADMIN_ROLE"],checks.settings[sid]["MOD_ROLE"]) + else: + names = (checks.settings["default"]["ADMIN_ROLE"],checks.settings["default"]["MOD_ROLE"]) + + if None not in map(lambda name: discord.utils.get(author.roles,name=name),names): return True if author.id in mod.blacklist_list: @@ -345,7 +349,7 @@ def check_folders(): def check_configs(): settings_path = "data/red/settings.json" - settings = {"EMAIL" : "EmailHere", "PASSWORD" : "PasswordHere", "OWNER" : "id_here", "PREFIXES" : [], "ADMIN_ROLE" : "Transistor", "MOD_ROLE" : "Process"} + settings = {"EMAIL" : "EmailHere", "PASSWORD" : "PasswordHere", "OWNER" : "id_here", "PREFIXES" : [], "default":{"ADMIN_ROLE" : "Transistor", "MOD_ROLE" : "Process"}} if not os.path.isfile(settings_path): print("Red - First run configuration") @@ -379,13 +383,13 @@ def check_configs(): print("\nInput the admin role's name. Anyone with this role will be able to use the bot's admin commands") print("Leave blank for default name (Transistor)") - settings["ADMIN_ROLE"] = input("\nAdmin role> ") - if settings["ADMIN_ROLE"] == "": settings["ADMIN_ROLE"] = "Transistor" + settings["default"]["ADMIN_ROLE"] = input("\nAdmin role> ") + if settings["default"]["ADMIN_ROLE"] == "": settings["default"]["ADMIN_ROLE"] = "Transistor" print("\nInput the moderator role's name. Anyone with this role will be able to use the bot's mod commands") print("Leave blank for default name (Process)") - settings["MOD_ROLE"] = input("\nAdmin role> ") - if settings["MOD_ROLE"] == "": settings["MOD_ROLE"] = "Process" + settings["default"]["MOD_ROLE"] = input("\nAdmin role> ") + if settings["default"]["MOD_ROLE"] == "": settings["default"]["MOD_ROLE"] = "Process" with open(settings_path, "w") as f: f.write(json.dumps(settings)) @@ -478,6 +482,7 @@ def main(): set_logger() settings = load_settings() checks.settings["OWNER"] = settings["OWNER"] + checks.save_bot_settings(checks.settings) load_cogs() bot.command_prefix = settings["PREFIXES"] yield from bot.login(settings["EMAIL"], settings["PASSWORD"])