Red-DiscordBot/cogs/utils/settings.py
Twentysix 27bdce7f32 [Core] CLI flags, env vars login, revamped setup, in. selfbot support, etc (#513)
Startup flags: can be started and configured without ever doing the interactive setup
Changed default settings format so that all unset values are None
Removed new cogs prompt
Removed `LOGIN_TYPE` from settings.json. It now defaults to token and fallbacks to email/password
Smarter initial setup: only asks for the settings that are actually missing
For the first installation all default cogs are loaded
Startup flag that allows settings to be memory-only
Initial selfbot support
Only reset login credentials (on confirmation) instead of deleting the whole file in case of login failure
Revamped main screen
Made sure that nothing blows up when you run Red on Windows without `chcp 65001`
Possibility of setting credentials in the environment variables `RED_TOKEN` / `RED_EMAIL` `RED_PASSWORD`. They will take priority over the configuration stored on disk.
2016-12-11 00:16:20 +01:00

282 lines
9.6 KiB
Python

from .dataIO import dataIO
from copy import deepcopy
import discord
import os
import argparse
default_path = "data/red/settings.json"
class Settings:
def __init__(self, path=default_path):
self.path = path
self.check_folders()
self.default_settings = {
"TOKEN": None,
"EMAIL": None,
"PASSWORD": None,
"OWNER": None,
"PREFIXES": [],
"default": {"ADMIN_ROLE": "Transistor",
"MOD_ROLE": "Process",
"PREFIXES": []}
}
self.memory_only = False
if not dataIO.is_valid_json(self.path):
self.bot_settings = deepcopy(self.default_settings)
self.save_settings()
else:
current = dataIO.load_json(self.path)
if current.keys() != self.default_settings.keys():
for key in self.default_settings.keys():
if key not in current.keys():
current[key] = self.default_settings[key]
print("Adding " + str(key) +
" field to red settings.json")
dataIO.save_json(self.path, current)
self.bot_settings = dataIO.load_json(self.path)
if "default" not in self.bot_settings:
self.update_old_settings_v1()
if "LOGIN_TYPE" in self.bot_settings:
self.update_old_settings_v2()
self.parse_cmd_arguments()
def parse_cmd_arguments(self):
parser = argparse.ArgumentParser(description="Red - Discord Bot")
parser.add_argument("--owner", help="ID of the owner. Only who hosts "
"Red should be owner, this has "
"security implications")
parser.add_argument("--prefix", "-p", action="append",
help="Global prefix. Can be multiple")
parser.add_argument("--admin-role", help="Role seen as admin role by "
"Red")
parser.add_argument("--mod-role", help="Role seen as mod role by Red")
parser.add_argument("--no-prompt",
action="store_true",
help="Disables console inputs. Features requiring "
"console interaction could be disabled as a "
"result")
parser.add_argument("--self-bot",
action='store_true',
help="Specifies if Red should log in as selfbot")
parser.add_argument("--memory-only",
action="store_true",
help="Arguments passed and future edits to the "
"settings will not be saved to disk")
parser.add_argument("--debug",
action="store_true",
help="Enables debug mode")
args = parser.parse_args()
if args.owner:
self.owner = args.owner
if args.prefix:
self.prefixes = sorted(args.prefix, reverse=True)
if args.admin_role:
self.default_admin = args.admin_role
if args.mod_role:
self.default_mod = args.mod_role
self.no_prompt = args.no_prompt
self.self_bot = args.self_bot
self.memory_only = args.memory_only
self.debug = args.debug
self.save_settings()
def check_folders(self):
folders = ("data", os.path.dirname(self.path), "cogs", "cogs/utils")
for folder in folders:
if not os.path.exists(folder):
print("Creating " + folder + " folder...")
os.makedirs(folder)
def save_settings(self):
if not self.memory_only:
dataIO.save_json(self.path, self.bot_settings)
def update_old_settings_v1(self):
# This converts the old settings format
mod = self.bot_settings["MOD_ROLE"]
admin = self.bot_settings["ADMIN_ROLE"]
del self.bot_settings["MOD_ROLE"]
del self.bot_settings["ADMIN_ROLE"]
self.bot_settings["default"] = {"MOD_ROLE": mod,
"ADMIN_ROLE": admin,
"PREFIXES": []
}
self.save_settings()
def update_old_settings_v2(self):
# The joys of backwards compatibility
settings = self.bot_settings
if settings["EMAIL"] == "EmailHere":
settings["EMAIL"] = None
if settings["PASSWORD"] == "":
settings["PASSWORD"] = None
if settings["LOGIN_TYPE"] == "token":
settings["TOKEN"] = settings["EMAIL"]
settings["EMAIL"] = None
settings["PASSWORD"] = None
else:
settings["TOKEN"] = None
del settings["LOGIN_TYPE"]
self.save_settings()
@property
def owner(self):
return self.bot_settings["OWNER"]
@owner.setter
def owner(self, value):
self.bot_settings["OWNER"] = value
@property
def token(self):
return os.environ.get("RED_TOKEN", self.bot_settings["TOKEN"])
@token.setter
def token(self, value):
self.bot_settings["TOKEN"] = value
self.bot_settings["EMAIL"] = None
self.bot_settings["PASSWORD"] = None
@property
def email(self):
return os.environ.get("RED_EMAIL", self.bot_settings["EMAIL"])
@email.setter
def email(self, value):
self.bot_settings["EMAIL"] = value
self.bot_settings["TOKEN"] = None
@property
def password(self):
return os.environ.get("RED_PASSWORD", self.bot_settings["PASSWORD"])
@password.setter
def password(self, value):
self.bot_settings["PASSWORD"] = value
@property
def login_credentials(self):
if self.token:
return (self.token,)
elif self.email and self.password:
return (self.email, self.password)
else:
return tuple()
@property
def prefixes(self):
return self.bot_settings["PREFIXES"]
@prefixes.setter
def prefixes(self, value):
assert isinstance(value, list)
self.bot_settings["PREFIXES"] = value
@property
def default_admin(self):
if "default" not in self.bot_settings:
self.update_old_settings()
return self.bot_settings["default"].get("ADMIN_ROLE", "")
@default_admin.setter
def default_admin(self, value):
if "default" not in self.bot_settings:
self.update_old_settings()
self.bot_settings["default"]["ADMIN_ROLE"] = value
@property
def default_mod(self):
if "default" not in self.bot_settings:
self.update_old_settings_v1()
return self.bot_settings["default"].get("MOD_ROLE", "")
@default_mod.setter
def default_mod(self, value):
if "default" not in self.bot_settings:
self.update_old_settings_v1()
self.bot_settings["default"]["MOD_ROLE"] = value
@property
def servers(self):
ret = {}
server_ids = list(
filter(lambda x: str(x).isdigit(), self.bot_settings))
for server in server_ids:
ret.update({server: self.bot_settings[server]})
return ret
def get_server(self, server):
if server is None:
return self.bot_settings["default"].copy()
assert isinstance(server, discord.Server)
return self.bot_settings.get(server.id,
self.bot_settings["default"]).copy()
def get_server_admin(self, server):
if server is None:
return self.default_admin
assert isinstance(server, discord.Server)
if server.id not in self.bot_settings:
return self.default_admin
return self.bot_settings[server.id].get("ADMIN_ROLE", "")
def set_server_admin(self, server, value):
if server is None:
return
assert isinstance(server, discord.Server)
if server.id not in self.bot_settings:
self.add_server(server.id)
self.bot_settings[server.id]["ADMIN_ROLE"] = value
self.save_settings()
def get_server_mod(self, server):
if server is None:
return self.default_mod
assert isinstance(server, discord.Server)
if server.id not in self.bot_settings:
return self.default_mod
return self.bot_settings[server.id].get("MOD_ROLE", "")
def set_server_mod(self, server, value):
if server is None:
return
assert isinstance(server, discord.Server)
if server.id not in self.bot_settings:
self.add_server(server.id)
self.bot_settings[server.id]["MOD_ROLE"] = value
self.save_settings()
def get_server_prefixes(self, server):
if server is None or server.id not in self.bot_settings:
return self.prefixes
return self.bot_settings[server.id].get("PREFIXES", [])
def set_server_prefixes(self, server, prefixes):
if server is None:
return
assert isinstance(server, discord.Server)
if server.id not in self.bot_settings:
self.add_server(server.id)
self.bot_settings[server.id]["PREFIXES"] = prefixes
self.save_settings()
def get_prefixes(self, server):
"""Returns server's prefixes if set, otherwise global ones"""
p = self.get_server_prefixes(server)
return p if p else self.prefixes
def add_server(self, sid):
self.bot_settings[sid] = self.bot_settings["default"].copy()
self.save_settings()