feat(setup): add configurator step

This commit is contained in:
Romain J 2020-06-03 18:24:38 +02:00
parent 9020fe7201
commit 79ca4f95d6
5 changed files with 343 additions and 11 deletions

View file

@ -2,8 +2,35 @@
<project version="4">
<component name="ChangeListManager">
<list default="true" id="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" name="5ed57ed9960f35191182a924 core" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.github/issue_template.md" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/dictionaries/romain.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/discord.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/inspectionProfiles/Project_Default.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/inspectionProfiles/profiles_settings.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/modules.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/tuxbot-bot-rewrite.iml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/vcs.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/setup.cfg" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/setup.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/__init__.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/__main__.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/cogs/images/__init__.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/cogs/images/images.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/cogs/logs/__init__.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/cogs/logs/logs.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/cogs/network/__init__.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/cogs/network/network.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/core/__init__.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/core/bot.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/core/config.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/core/models/__init__.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/core/utils/functions/cli.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/core/utils/functions/extra.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/tuxbot/setup.py" beforeDir="false" />
</list>
<list id="a3abf5c0-7587-46e4-8f09-88e34a1ab8a4" name="5ed41911b012e33f68a07e7a i18n" comment="" />
<list id="6566fca1-2e90-48bb-9e74-dd3badbaca99" name="Default Changelist" comment="" />
@ -35,7 +62,7 @@
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="last_opened_file_path" value="$PROJECT_DIR$/tuxbot/cogs/network" />
<property name="node.js.detected.package.eslint" value="true" />
<property name="node.js.detected.package.tslint" value="true" />
<property name="node.js.path.for.package.eslint" value="project" />
@ -54,8 +81,8 @@
<recent name="$PROJECT_DIR$/tuxbot/core" />
</key>
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$" />
<recent name="$PROJECT_DIR$/tuxbot/cogs/network" />
<recent name="$PROJECT_DIR$" />
<recent name="$PROJECT_DIR$/tuxbot/cogs" />
<recent name="$PROJECT_DIR$/utils/locales" />
<recent name="$PROJECT_DIR$/cogs" />
@ -93,7 +120,7 @@
</task>
<task id="5ed41911b012e33f68a07e7a" summary="i18n">
<changelist id="a3abf5c0-7587-46e4-8f09-88e34a1ab8a4" name="5ed41911b012e33f68a07e7a i18n" comment="" />
<created>1591139389877</created>
<created>1591200420454</created>
<option name="issue" value="true" />
<url>https://trello.com/c/vK0cBbF2/38-i18n</url>
<option name="number" value="38" />
@ -105,7 +132,7 @@
</task>
<task active="true" id="5ed57ed9960f35191182a924" summary="core">
<changelist id="c97c8a30-7573-4dcd-a0d4-5bf94b8ddbbd" name="5ed57ed9960f35191182a924 core" comment="" />
<created>1591139389877</created>
<created>1591200420454</created>
<option name="issue" value="true" />
<url>https://trello.com/c/SafaMBht/40-core</url>
<option name="number" value="40" />
@ -114,7 +141,7 @@
<workItem from="1591049956280" duration="4910000" />
<workItem from="1591054878071" duration="1039000" />
<workItem from="1591088657371" duration="4107000" />
<workItem from="1591128560850" duration="9119000" />
<workItem from="1591128560850" duration="24277000" />
</task>
<option name="localTasksCounter" value="2" />
<option name="createBranch" value="false" />
@ -182,10 +209,10 @@
<screen x="1920" y="0" width="1920" height="1080" />
</state>
<state x="2440" y="156" width="873" height="799" key="com.intellij.openapi.editor.actions.MultiplePasteAction$ClipboardContentChooser/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1590155739870" />
<state x="2673" y="469" key="com.intellij.openapi.vcs.update.UpdateOrStatusOptionsDialogupdate-v2" timestamp="1590879398033">
<state x="2673" y="469" key="com.intellij.openapi.vcs.update.UpdateOrStatusOptionsDialogupdate-v2" timestamp="1591199362509">
<screen x="1920" y="0" width="1920" height="1080" />
</state>
<state x="2673" y="469" key="com.intellij.openapi.vcs.update.UpdateOrStatusOptionsDialogupdate-v2/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1590879398033" />
<state x="2673" y="469" key="com.intellij.openapi.vcs.update.UpdateOrStatusOptionsDialogupdate-v2/1920.0.1920.1080/0.29.1920.1051@1920.0.1920.1080" timestamp="1591199362509" />
<state x="2584" y="164" width="592" height="783" key="find.popup" timestamp="1589983672115">
<screen x="1920" y="0" width="1920" height="1080" />
</state>

View file

@ -8,7 +8,7 @@ It is preferable to install the bot on a dedicated user. If you don't know how t
- Python 3.7 or greater
- Pip
- Git
- JRE 11
- JRE 11 (voice support)
### Operating systems

View file

@ -0,0 +1,22 @@
{
"dm": {
"description": "Webhook url for DMs events",
"value": "str"
},
"mentions": {
"description": "Webhook url for mentions events",
"value": "str"
},
"guilds": {
"description": "Webhook url for guilds events",
"value": "str"
},
"errors": {
"description": "Webhook url for errors events",
"value": "str"
},
"gateway": {
"description": "Webhook url for gateway events",
"value": "str"
}
}

View file

@ -0,0 +1,6 @@
{
"ipinfo": {
"description": "API token for ipinfo.io",
"value": "str"
}
}

View file

@ -1,2 +1,279 @@
import json
import logging
import os
import re
import sys
from pathlib import Path
from typing import NoReturn, Union, List
import appdirs
import click
from colorama import Fore, Style, init
init()
app_dir = appdirs.AppDirs("Tuxbot-bot")
config_dir = Path(app_dir.user_config_dir)
try:
config_dir.mkdir(parents=True, exist_ok=True)
except PermissionError:
print(f"mkdir: cannot create directory '{config_dir}': Permission denied")
sys.exit(1)
config_file = config_dir / "config.json"
def load_existing_config() -> dict:
if not config_file.exists():
return {}
with config_file.open() as fs:
return json.load(fs)
instances_data = load_existing_config()
if not instances_data:
instances_list = []
else:
instances_list = list(instances_data.keys())
def save_config(name, data, delete=False):
_config = load_existing_config()
if delete and name in _config:
_config.pop(name)
else:
_config[name] = data
with config_file.open("w") as fs:
json.dump(_config, fs, indent=4)
def get_name() -> str:
name = ""
while not name:
print(
"What name do you want to give this instance?\n"
"(valid characters: A-Z, a-z, 0-9, _, -)"
)
name = input("> ")
if re.fullmatch(r"[a-zA-Z0-9_\-]*", name) is None:
print()
print(
Fore.RED
+ "ERROR: Invalid characters provided"
+ Style.RESET_ALL
)
name = ""
return name
def get_data_dir(instance_name: str) -> Path:
data_path = Path(app_dir.user_data_dir) / "data" / instance_name
data_path_input = ""
print()
def make_data_dir(path: Path) -> Union[Path, str]:
try:
path.mkdir(parents=True, exist_ok=True)
except OSError:
print()
print(
Fore.RED
+ f"mkdir: cannot create directory '{path}':"
f" Permission denied"
+ Style.RESET_ALL
)
path = ""
return path
while not data_path_input:
print(
"where do you want to save the configurations?\n"
"Press [enter] to keep the default path"
)
print()
print(f"Default: {data_path}")
data_path_input = input("> ")
if data_path_input != '':
data_path_input = Path(data_path_input)
try:
exists = data_path_input.exists()
except OSError:
print()
print(
Fore.RED
+ "Impossible to verify the validity of the path, "
"make sure it does not contain any invalid characters."
+ Style.RESET_ALL
)
data_path_input = ""
exists = False
if data_path_input and not exists:
data_path_input = make_data_dir(data_path_input)
else:
data_path_input = make_data_dir(data_path)
print()
print(
f"You have chosen {data_path_input} to be your config directory for "
f"`{instance_name}` instance"
)
if not click.confirm("Please confirm", default=True):
print("Rerun the process to redo this configuration.")
sys.exit(0)
(data_path_input / 'core').mkdir(parents=True, exist_ok=True)
(data_path_input / 'cogs').mkdir(parents=True, exist_ok=True)
return data_path_input
def get_token() -> str:
token = ""
while not token:
print(
"Please enter the bot token\n"
"(you can find it at https://discord.com/developers/applications)"
)
token = input("> ")
if re.fullmatch(r"([a-zA-Z0-9]{24}\.[a-zA-Z0-9_]{6}\.[a-zA-Z0-9_\-]{27}|mfa\.[a-zA-Z0-9_\-]{84})", token) is None:
print(
Fore.RED
+ "ERROR: Invalid token provided"
+ Style.RESET_ALL
)
token = ""
return token
def get_prefixes() -> List[str]:
print("Choice a (or multiple) prefix for the bot")
prefixes = [input('> ')]
while click.confirm("Add another prefix ?", default=False):
prefixes.append(input('> '))
return prefixes
def additional_config() -> dict:
p = Path(r'tuxbot/cogs').glob('**/additional_config.json')
datas = {}
for file in p:
print()
cog_name = str(file.parent).split('/')[-1]
datas[cog_name] = {}
with file.open('r') as f:
data = json.load(f)
print(f"\n==Configuration for `{cog_name}` module==")
for key, value in data.items():
print()
print(value['description'])
datas[cog_name][key] = input('> ')
return datas
def finish_setup(data_dir: Path) -> NoReturn:
print("Now, it's time to finish this setup by giving bot informations\n")
token = get_token()
print()
prefixes = get_prefixes()
mentionable = click.confirm("Does the bot answer if it's mentioned?", default=True)
cogs_config = additional_config()
core_file = data_dir / 'core' / 'settings.json'
core = {
'token': token,
'prefixes': prefixes,
'mentionable': mentionable,
}
with core_file.open("w") as fs:
json.dump(core, fs, indent=4)
for cog, data in cogs_config.items():
data_cog_dir = data_dir / 'cogs' / cog
data_cog_dir.mkdir(parents=True, exist_ok=True)
data_cog_file = data_cog_dir / 'settings.json'
with data_cog_file.open("w") as fs:
json.dump(data, fs, indent=4)
def basic_setup() -> NoReturn:
print("Hi ! it's time for you to give me informations about you instance")
name = get_name()
data_dir = get_data_dir(name)
configs = load_existing_config()
instance_config = configs[name] if name in instances_list else {}
instance_config["DATA_PATH"] = str(data_dir.resolve())
instance_config["IS_RUNNING"] = False
if name in instances_list:
print()
print(
Fore.RED
+ f"WARNING: An instance named `{name}` already exists "
f"Continuing will overwrite this instance configs."
+ Style.RESET_ALL
)
if not click.confirm("Are you sure you want to continue?",
default=False):
print("Abandon...")
sys.exit(0)
save_config(name, instance_config)
print("\n"*4)
finish_setup(data_dir)
print()
print(
f"Instance successfully created! "
f"You can now run `tuxbot {name}` to launch this instance"
)
def setup():
...
try:
"""Create a new instance."""
level = logging.DEBUG
base_logger = logging.getLogger("tux")
base_logger.setLevel(level)
formatter = logging.Formatter(
"[{asctime}] [{levelname}] {name}: {message}",
datefmt="%Y-%m-%d %H:%M:%S", style="{"
)
stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setFormatter(formatter)
base_logger.addHandler(stdout_handler)
basic_setup()
except KeyboardInterrupt:
print("Exiting...")
if __name__ == "__main__":
setup()