mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'dev' into enhancement/auto_log-dash
This commit is contained in:
commit
5699aa40e8
@ -2,11 +2,16 @@
|
|||||||
## --- [4.0.20] - 2022/TBD
|
## --- [4.0.20] - 2022/TBD
|
||||||
### New features
|
### New features
|
||||||
- Add option to run command before backup. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/536))
|
- Add option to run command before backup. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/536))
|
||||||
|
- Make Config.json editable from panel. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/532))
|
||||||
|
- Managed config.json refector (See MR for details). ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/485))
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
- Fix local java server imports. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/529))
|
- Fix local java server imports. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/529))
|
||||||
- Fix Schedule Restore | Add Backup Config Preservation. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/533))
|
- Fix Schedule Restore | Add Backup Config Preservation. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/533))
|
||||||
- Rework `/public` Route. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/538))
|
- Rework `/public` Route. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/538))
|
||||||
### Tweaks
|
### Tweaks
|
||||||
|
- Hide stats DB directory from files tree. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/530))
|
||||||
|
- Make it so file tree doesn't reload on upload/delete. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/541))
|
||||||
|
- Add upload completed feedback to file upload. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/541))
|
||||||
- Added further login screen customisation settings. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/531))
|
- Added further login screen customisation settings. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/531))
|
||||||
- Set backup filename to use same time as schedule. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/534))
|
- Set backup filename to use same time as schedule. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/534))
|
||||||
- Move Schedules to from DB to Queue Datatype. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/535))
|
- Move Schedules to from DB to Queue Datatype. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/535))
|
||||||
|
@ -46,6 +46,14 @@ class ManagementController:
|
|||||||
def get_crafty_api_key():
|
def get_crafty_api_key():
|
||||||
return HelpersManagement.get_secret_api_key()
|
return HelpersManagement.get_secret_api_key()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set_cookie_secret(key):
|
||||||
|
HelpersManagement.set_cookie_secret(key)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def add_crafty_row():
|
||||||
|
HelpersManagement.create_crafty_row()
|
||||||
|
|
||||||
# **********************************************************************************
|
# **********************************************************************************
|
||||||
# Commands Methods
|
# Commands Methods
|
||||||
# **********************************************************************************
|
# **********************************************************************************
|
||||||
|
@ -43,6 +43,7 @@ class AuditLog(BaseModel):
|
|||||||
# **********************************************************************************
|
# **********************************************************************************
|
||||||
class CraftySettings(BaseModel):
|
class CraftySettings(BaseModel):
|
||||||
secret_api_key = CharField(default="")
|
secret_api_key = CharField(default="")
|
||||||
|
cookie_secret = CharField(default="")
|
||||||
login_photo = CharField(default="login_1.jpg")
|
login_photo = CharField(default="login_1.jpg")
|
||||||
login_opacity = IntegerField(default=100)
|
login_opacity = IntegerField(default=100)
|
||||||
|
|
||||||
@ -204,9 +205,22 @@ class HelpersManagement:
|
|||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_crafty_row():
|
||||||
|
CraftySettings.insert(
|
||||||
|
{
|
||||||
|
CraftySettings.secret_api_key: "",
|
||||||
|
CraftySettings.cookie_secret: "",
|
||||||
|
CraftySettings.login_photo: "login_1.jpg",
|
||||||
|
CraftySettings.login_opacity: 100,
|
||||||
|
}
|
||||||
|
).execute()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def set_secret_api_key(key):
|
def set_secret_api_key(key):
|
||||||
CraftySettings.insert(secret_api_key=key).execute()
|
CraftySettings.update({CraftySettings.secret_api_key: key}).where(
|
||||||
|
CraftySettings.id == 1
|
||||||
|
).execute()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_secret_api_key():
|
def get_secret_api_key():
|
||||||
@ -215,6 +229,19 @@ class HelpersManagement:
|
|||||||
)
|
)
|
||||||
return settings[0].secret_api_key
|
return settings[0].secret_api_key
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_cookie_secret():
|
||||||
|
settings = CraftySettings.select(CraftySettings.cookie_secret).where(
|
||||||
|
CraftySettings.id == 1
|
||||||
|
)
|
||||||
|
return settings[0].cookie_secret
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set_cookie_secret(key):
|
||||||
|
CraftySettings.update({CraftySettings.cookie_secret: key}).where(
|
||||||
|
CraftySettings.id == 1
|
||||||
|
).execute()
|
||||||
|
|
||||||
# **********************************************************************************
|
# **********************************************************************************
|
||||||
# Config Methods
|
# Config Methods
|
||||||
# **********************************************************************************
|
# **********************************************************************************
|
||||||
|
@ -78,6 +78,7 @@ class Helpers:
|
|||||||
self.websocket_helper = WebSocketHelper(self)
|
self.websocket_helper = WebSocketHelper(self)
|
||||||
self.translation = Translation(self)
|
self.translation = Translation(self)
|
||||||
self.update_available = False
|
self.update_available = False
|
||||||
|
self.ignored_names = ["crafty_managed.txt", "db_stats"]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def auto_installer_fix(ex):
|
def auto_installer_fix(ex):
|
||||||
@ -376,6 +377,64 @@ class Helpers:
|
|||||||
|
|
||||||
return default_return
|
return default_return
|
||||||
|
|
||||||
|
def set_settings(self, data):
|
||||||
|
try:
|
||||||
|
with open(self.settings_file, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(data, f, indent=4)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.critical(
|
||||||
|
f"Config File Error: Unable to read {self.settings_file} due to {e}"
|
||||||
|
)
|
||||||
|
Console.critical(
|
||||||
|
f"Config File Error: Unable to read {self.settings_file} due to {e}"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_master_config():
|
||||||
|
# Make changes for users' local config.json files here. As of 4.0.20
|
||||||
|
# Config.json was removed from the repo to make it easier for users
|
||||||
|
# To make non-breaking changes to the file.
|
||||||
|
return {
|
||||||
|
"http_port": 8000,
|
||||||
|
"https_port": 8443,
|
||||||
|
"language": "en_EN",
|
||||||
|
"cookie_expire": 30,
|
||||||
|
"show_errors": True,
|
||||||
|
"history_max_age": 7,
|
||||||
|
"stats_update_frequency": 30,
|
||||||
|
"delete_default_json": False,
|
||||||
|
"show_contribute_link": True,
|
||||||
|
"virtual_terminal_lines": 70,
|
||||||
|
"max_log_lines": 700,
|
||||||
|
"max_audit_entries": 300,
|
||||||
|
"disabled_language_files": [],
|
||||||
|
"stream_size_GB": 1,
|
||||||
|
"keywords": ["help", "chunk"],
|
||||||
|
"allow_nsfw_profile_pictures": False,
|
||||||
|
"enable_user_self_delete": False,
|
||||||
|
"reset_secrets_on_next_boot": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_all_settings(self):
|
||||||
|
try:
|
||||||
|
with open(self.settings_file, "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
data = {}
|
||||||
|
logger.critical(
|
||||||
|
f"Config File Error: Unable to read {self.settings_file} due to {e}"
|
||||||
|
)
|
||||||
|
Console.critical(
|
||||||
|
f"Config File Error: Unable to read {self.settings_file} due to {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_subdir(server_path, root_dir):
|
def is_subdir(server_path, root_dir):
|
||||||
server_path = os.path.realpath(server_path)
|
server_path = os.path.realpath(server_path)
|
||||||
@ -947,8 +1006,7 @@ class Helpers:
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@staticmethod
|
def generate_tree(self, folder, output=""):
|
||||||
def generate_tree(folder, output=""):
|
|
||||||
dir_list = []
|
dir_list = []
|
||||||
unsorted_files = []
|
unsorted_files = []
|
||||||
file_list = os.listdir(folder)
|
file_list = os.listdir(folder)
|
||||||
@ -965,18 +1023,22 @@ class Helpers:
|
|||||||
rel = os.path.join(folder, raw_filename)
|
rel = os.path.join(folder, raw_filename)
|
||||||
dpath = os.path.join(folder, filename)
|
dpath = os.path.join(folder, filename)
|
||||||
if os.path.isdir(rel):
|
if os.path.isdir(rel):
|
||||||
output += f"""<li class="tree-item" data-path="{dpath}">
|
if filename not in self.ignored_names:
|
||||||
\n<div id="{dpath}" data-path="{dpath}" data-name="{filename}" class="tree-caret tree-ctx-item tree-folder">
|
output += f"""<li id="{dpath}li" class="tree-item"
|
||||||
<span id="{dpath}span" class="files-tree-title" data-path="{dpath}" data-name="{filename}" onclick="getDirView(event)">
|
data-path="{dpath}">
|
||||||
<i style="color: var(--info);" class="far fa-folder"></i>
|
\n<div id="{dpath}" data-path="{dpath}" data-name="{filename}"
|
||||||
<i style="color: var(--info);" class="far fa-folder-open"></i>
|
class="tree-caret tree-ctx-item tree-folder">
|
||||||
{filename}
|
<span id="{dpath}span" class="files-tree-title" data-path="{dpath}"
|
||||||
</span>
|
data-name="{filename}" onclick="getDirView(event)">
|
||||||
</div><li>
|
<i style="color: var(--info);" class="far fa-folder"></i>
|
||||||
\n"""
|
<i style="color: var(--info);" class="far fa-folder-open"></i>
|
||||||
|
{filename}
|
||||||
|
</span>
|
||||||
|
</div><li>
|
||||||
|
\n"""
|
||||||
else:
|
else:
|
||||||
if filename != "crafty_managed.txt":
|
if filename not in self.ignored_names:
|
||||||
output += f"""<li
|
output += f"""<li id="{dpath}li"
|
||||||
class="d-block tree-ctx-item tree-file tree-item"
|
class="d-block tree-ctx-item tree-file tree-item"
|
||||||
data-path="{dpath}"
|
data-path="{dpath}"
|
||||||
data-name="{filename}"
|
data-name="{filename}"
|
||||||
@ -984,8 +1046,7 @@ class Helpers:
|
|||||||
<i class="far fa-file"></i></span>{filename}</li>"""
|
<i class="far fa-file"></i></span>{filename}</li>"""
|
||||||
return output
|
return output
|
||||||
|
|
||||||
@staticmethod
|
def generate_dir(self, folder, output=""):
|
||||||
def generate_dir(folder, output=""):
|
|
||||||
|
|
||||||
dir_list = []
|
dir_list = []
|
||||||
unsorted_files = []
|
unsorted_files = []
|
||||||
@ -1004,17 +1065,21 @@ class Helpers:
|
|||||||
dpath = os.path.join(folder, filename)
|
dpath = os.path.join(folder, filename)
|
||||||
rel = os.path.join(folder, raw_filename)
|
rel = os.path.join(folder, raw_filename)
|
||||||
if os.path.isdir(rel):
|
if os.path.isdir(rel):
|
||||||
output += f"""<li class="tree-item" data-path="{dpath}">
|
if filename not in self.ignored_names:
|
||||||
\n<div id="{dpath}" data-path="{dpath}" data-name="{filename}" class="tree-caret tree-ctx-item tree-folder">
|
output += f"""<li id="{dpath}li" class="tree-item"
|
||||||
<span id="{dpath}span" class="files-tree-title" data-path="{dpath}" data-name="{filename}" onclick="getDirView(event)">
|
data-path="{dpath}">
|
||||||
<i style="color: var(--info);" class="far fa-folder"></i>
|
\n<div id="{dpath}" data-path="{dpath}" data-name="{filename}"
|
||||||
<i style="color: var(--info);" class="far fa-folder-open"></i>
|
class="tree-caret tree-ctx-item tree-folder">
|
||||||
{filename}
|
<span id="{dpath}span" class="files-tree-title" data-path="{dpath}"
|
||||||
</span>
|
data-name="{filename}" onclick="getDirView(event)">
|
||||||
</div><li>"""
|
<i style="color: var(--info);" class="far fa-folder"></i>
|
||||||
|
<i style="color: var(--info);" class="far fa-folder-open"></i>
|
||||||
|
{filename}
|
||||||
|
</span>
|
||||||
|
</div><li>"""
|
||||||
else:
|
else:
|
||||||
if filename != "crafty_managed.txt":
|
if filename not in self.ignored_names:
|
||||||
output += f"""<li
|
output += f"""<li id="{dpath}li"
|
||||||
class="d-block tree-ctx-item tree-file tree-item"
|
class="d-block tree-ctx-item tree-file tree-item"
|
||||||
data-path="{dpath}"
|
data-path="{dpath}"
|
||||||
data-name="{filename}"
|
data-name="{filename}"
|
||||||
|
@ -244,6 +244,41 @@ class Controller:
|
|||||||
exec_user["user_id"], "support_status_update", results
|
exec_user["user_id"], "support_status_update", results
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_config_diff(self):
|
||||||
|
master_config = Helpers.get_master_config()
|
||||||
|
try:
|
||||||
|
user_config = self.helper.get_all_settings()
|
||||||
|
except:
|
||||||
|
# Call helper to set updated config.
|
||||||
|
Console.warning("No Config found. Setting Default Config.json")
|
||||||
|
user_config = master_config
|
||||||
|
keys = list(user_config.keys())
|
||||||
|
keys.sort()
|
||||||
|
sorted_data = {i: user_config[i] for i in keys}
|
||||||
|
self.helper.set_settings(user_config)
|
||||||
|
return
|
||||||
|
items_to_del = []
|
||||||
|
|
||||||
|
# Iterate through user's config.json and check for
|
||||||
|
# Keys/values that need to be removed
|
||||||
|
for key in user_config:
|
||||||
|
if key not in master_config.keys():
|
||||||
|
items_to_del.append(key)
|
||||||
|
|
||||||
|
# Remove key/values from user config that were staged
|
||||||
|
for item in items_to_del[:]:
|
||||||
|
del user_config[item]
|
||||||
|
|
||||||
|
# Add new keys to user config.
|
||||||
|
for key, value in master_config.items():
|
||||||
|
if key not in user_config.keys():
|
||||||
|
user_config[key] = value
|
||||||
|
# Call helper to set updated config.
|
||||||
|
keys = list(user_config.keys())
|
||||||
|
keys.sort()
|
||||||
|
sorted_data = {i: user_config[i] for i in keys}
|
||||||
|
self.helper.set_settings(sorted_data)
|
||||||
|
|
||||||
def send_log_status(self):
|
def send_log_status(self):
|
||||||
try:
|
try:
|
||||||
return self.log_stats
|
return self.log_stats
|
||||||
|
@ -8,9 +8,10 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class DatabaseBuilder:
|
class DatabaseBuilder:
|
||||||
def __init__(self, database, helper, users_helper):
|
def __init__(self, database, helper, users_helper, management_helper):
|
||||||
self.database = database
|
self.database = database
|
||||||
self.helper = helper
|
self.helper = helper
|
||||||
|
self.management_helper = management_helper
|
||||||
self.users_helper = users_helper
|
self.users_helper = users_helper
|
||||||
|
|
||||||
def default_settings(self):
|
def default_settings(self):
|
||||||
@ -29,6 +30,8 @@ class DatabaseBuilder:
|
|||||||
manager=None,
|
manager=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.management_helper.create_crafty_row()
|
||||||
|
|
||||||
def is_fresh_install(self):
|
def is_fresh_install(self):
|
||||||
try:
|
try:
|
||||||
num_user = self.users_helper.get_user_total()
|
num_user = self.users_helper.get_user_total()
|
||||||
|
@ -100,7 +100,7 @@ class FileHandler(BaseHandler):
|
|||||||
self.write(
|
self.write(
|
||||||
Helpers.get_os_understandable_path(path)
|
Helpers.get_os_understandable_path(path)
|
||||||
+ "\n"
|
+ "\n"
|
||||||
+ Helpers.generate_tree(path)
|
+ self.helper.generate_tree(path)
|
||||||
)
|
)
|
||||||
self.finish()
|
self.finish()
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ class FileHandler(BaseHandler):
|
|||||||
self.write(
|
self.write(
|
||||||
Helpers.get_os_understandable_path(path)
|
Helpers.get_os_understandable_path(path)
|
||||||
+ "\n"
|
+ "\n"
|
||||||
+ Helpers.generate_dir(path)
|
+ self.helper.generate_dir(path)
|
||||||
)
|
)
|
||||||
self.finish()
|
self.finish()
|
||||||
|
|
||||||
|
@ -858,35 +858,6 @@ class PanelHandler(BaseHandler):
|
|||||||
page_data["roles"] = self.controller.roles.get_all_roles()
|
page_data["roles"] = self.controller.roles.get_all_roles()
|
||||||
page_data["auth-servers"][user.user_id] = super_auth_servers
|
page_data["auth-servers"][user.user_id] = super_auth_servers
|
||||||
page_data["managed_users"] = []
|
page_data["managed_users"] = []
|
||||||
page_data["backgrounds"] = []
|
|
||||||
cached_split = self.controller.cached_login.split("/")
|
|
||||||
|
|
||||||
if len(cached_split) == 1:
|
|
||||||
page_data["backgrounds"].append(
|
|
||||||
self.controller.cached_login
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
page_data["backgrounds"].append(cached_split[1])
|
|
||||||
if "login_1.jpg" not in page_data["backgrounds"]:
|
|
||||||
page_data["backgrounds"].append("login_1.jpg")
|
|
||||||
self.helper.ensure_dir_exists(
|
|
||||||
os.path.join(
|
|
||||||
self.controller.project_root,
|
|
||||||
"app/frontend/static/assets/images/auth/custom",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
for item in os.listdir(
|
|
||||||
os.path.join(
|
|
||||||
self.controller.project_root,
|
|
||||||
"app/frontend/static/assets/images/auth/custom",
|
|
||||||
)
|
|
||||||
):
|
|
||||||
if item not in page_data["backgrounds"]:
|
|
||||||
page_data["backgrounds"].append(item)
|
|
||||||
page_data["background"] = self.controller.cached_login
|
|
||||||
page_data[
|
|
||||||
"login_opacity"
|
|
||||||
] = self.controller.management.get_login_opacity()
|
|
||||||
else:
|
else:
|
||||||
page_data["managed_users"] = self.controller.users.get_managed_users(
|
page_data["managed_users"] = self.controller.users.get_managed_users(
|
||||||
exec_user["user_id"]
|
exec_user["user_id"]
|
||||||
@ -899,8 +870,65 @@ class PanelHandler(BaseHandler):
|
|||||||
exec_user["user_id"]
|
exec_user["user_id"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
page_data["active_link"] = "panel_config"
|
||||||
template = "panel/panel_config.html"
|
template = "panel/panel_config.html"
|
||||||
|
|
||||||
|
elif page == "config_json":
|
||||||
|
if exec_user["superuser"]:
|
||||||
|
with open(self.helper.settings_file, "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
page_data["config-json"] = data
|
||||||
|
page_data["availables_languages"] = []
|
||||||
|
page_data["all_languages"] = []
|
||||||
|
|
||||||
|
for file in sorted(
|
||||||
|
os.listdir(
|
||||||
|
os.path.join(self.helper.root_dir, "app", "translations")
|
||||||
|
)
|
||||||
|
):
|
||||||
|
if file.endswith(".json"):
|
||||||
|
if file.split(".")[0] not in self.helper.get_setting(
|
||||||
|
"disabled_language_files"
|
||||||
|
):
|
||||||
|
page_data["availables_languages"].append(file.split(".")[0])
|
||||||
|
page_data["all_languages"].append(file.split(".")[0])
|
||||||
|
|
||||||
|
page_data["active_link"] = "config_json"
|
||||||
|
template = "panel/config_json.html"
|
||||||
|
|
||||||
|
elif page == "custom_login":
|
||||||
|
if exec_user["superuser"]:
|
||||||
|
page_data["backgrounds"] = []
|
||||||
|
cached_split = self.controller.cached_login.split("/")
|
||||||
|
|
||||||
|
if len(cached_split) == 1:
|
||||||
|
page_data["backgrounds"].append(self.controller.cached_login)
|
||||||
|
else:
|
||||||
|
page_data["backgrounds"].append(cached_split[1])
|
||||||
|
if "login_1.jpg" not in page_data["backgrounds"]:
|
||||||
|
page_data["backgrounds"].append("login_1.jpg")
|
||||||
|
self.helper.ensure_dir_exists(
|
||||||
|
os.path.join(
|
||||||
|
self.controller.project_root,
|
||||||
|
"app/frontend/static/assets/images/auth/custom",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for item in os.listdir(
|
||||||
|
os.path.join(
|
||||||
|
self.controller.project_root,
|
||||||
|
"app/frontend/static/assets/images/auth/custom",
|
||||||
|
)
|
||||||
|
):
|
||||||
|
if item not in page_data["backgrounds"]:
|
||||||
|
page_data["backgrounds"].append(item)
|
||||||
|
page_data["background"] = self.controller.cached_login
|
||||||
|
page_data[
|
||||||
|
"login_opacity"
|
||||||
|
] = self.controller.management.get_login_opacity()
|
||||||
|
|
||||||
|
page_data["active_link"] = "custom_login"
|
||||||
|
template = "panel/custom_login.html"
|
||||||
|
|
||||||
elif page == "add_user":
|
elif page == "add_user":
|
||||||
page_data["new_user"] = True
|
page_data["new_user"] = True
|
||||||
page_data["user"] = {}
|
page_data["user"] = {}
|
||||||
@ -957,7 +985,9 @@ class PanelHandler(BaseHandler):
|
|||||||
os.listdir(os.path.join(self.helper.root_dir, "app", "translations"))
|
os.listdir(os.path.join(self.helper.root_dir, "app", "translations"))
|
||||||
):
|
):
|
||||||
if file.endswith(".json"):
|
if file.endswith(".json"):
|
||||||
if file not in self.helper.get_setting("disabled_language_files"):
|
if file.split(".")[0] not in self.helper.get_setting(
|
||||||
|
"disabled_language_files"
|
||||||
|
):
|
||||||
if file != str(page_data["languages"][0] + ".json"):
|
if file != str(page_data["languages"][0] + ".json"):
|
||||||
page_data["languages"].append(file.split(".")[0])
|
page_data["languages"].append(file.split(".")[0])
|
||||||
|
|
||||||
@ -1168,7 +1198,9 @@ class PanelHandler(BaseHandler):
|
|||||||
os.listdir(os.path.join(self.helper.root_dir, "app", "translations"))
|
os.listdir(os.path.join(self.helper.root_dir, "app", "translations"))
|
||||||
):
|
):
|
||||||
if file.endswith(".json"):
|
if file.endswith(".json"):
|
||||||
if file not in self.helper.get_setting("disabled_language_files"):
|
if file.split(".")[0] not in self.helper.get_setting(
|
||||||
|
"disabled_language_files"
|
||||||
|
):
|
||||||
if file != str(page_data["languages"][0] + ".json"):
|
if file != str(page_data["languages"][0] + ".json"):
|
||||||
page_data["languages"].append(file.split(".")[0])
|
page_data["languages"].append(file.split(".")[0])
|
||||||
|
|
||||||
@ -1720,6 +1752,41 @@ class PanelHandler(BaseHandler):
|
|||||||
self.tasks_manager.reload_schedule_from_db()
|
self.tasks_manager.reload_schedule_from_db()
|
||||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=backup")
|
self.redirect(f"/panel/server_detail?id={server_id}&subpage=backup")
|
||||||
|
|
||||||
|
elif page == "config_json":
|
||||||
|
try:
|
||||||
|
data = {}
|
||||||
|
with open(self.helper.settings_file, "r", encoding="utf-8") as f:
|
||||||
|
keys = json.load(f).keys()
|
||||||
|
this_uuid = self.get_argument("uuid")
|
||||||
|
for key in keys:
|
||||||
|
arg_data = self.get_argument(key)
|
||||||
|
if arg_data.startswith(this_uuid):
|
||||||
|
arg_data = arg_data.split(",")
|
||||||
|
arg_data.pop(0)
|
||||||
|
data[key] = arg_data
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
data[key] = int(arg_data)
|
||||||
|
except:
|
||||||
|
if arg_data == "True":
|
||||||
|
data[key] = True
|
||||||
|
elif arg_data == "False":
|
||||||
|
data[key] = False
|
||||||
|
else:
|
||||||
|
data[key] = arg_data
|
||||||
|
keys = list(data.keys())
|
||||||
|
keys.sort()
|
||||||
|
sorted_data = {i: data[i] for i in keys}
|
||||||
|
with open(self.helper.settings_file, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(sorted_data, f, indent=4)
|
||||||
|
except Exception as e:
|
||||||
|
logger.critical(
|
||||||
|
"Config File Error: Unable to read "
|
||||||
|
f"{self.helper.settings_file} due to {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.redirect("/panel/config_json")
|
||||||
|
|
||||||
if page == "new_schedule":
|
if page == "new_schedule":
|
||||||
server_id = self.check_server_id()
|
server_id = self.check_server_id()
|
||||||
if not server_id:
|
if not server_id:
|
||||||
|
@ -11,6 +11,7 @@ import tornado.escape
|
|||||||
import tornado.locale
|
import tornado.locale
|
||||||
import tornado.httpserver
|
import tornado.httpserver
|
||||||
|
|
||||||
|
from app.classes.models.management import HelpersManagement
|
||||||
from app.classes.shared.console import Console
|
from app.classes.shared.console import Console
|
||||||
from app.classes.shared.helpers import Helpers
|
from app.classes.shared.helpers import Helpers
|
||||||
from app.classes.shared.main_controller import Controller
|
from app.classes.shared.main_controller import Controller
|
||||||
@ -110,10 +111,13 @@ class Webserver:
|
|||||||
https_port = self.helper.get_setting("https_port")
|
https_port = self.helper.get_setting("https_port")
|
||||||
|
|
||||||
debug_errors = self.helper.get_setting("show_errors")
|
debug_errors = self.helper.get_setting("show_errors")
|
||||||
cookie_secret = self.helper.get_setting("cookie_secret")
|
try:
|
||||||
|
cookie_secret = HelpersManagement.get_cookie_secret()
|
||||||
if cookie_secret is False:
|
except:
|
||||||
|
cookie_secret = False
|
||||||
|
if cookie_secret is False or cookie_secret == "":
|
||||||
cookie_secret = self.helper.random_string_generator(32)
|
cookie_secret = self.helper.random_string_generator(32)
|
||||||
|
HelpersManagement.set_cookie_secret(cookie_secret)
|
||||||
|
|
||||||
if not http_port:
|
if not http_port:
|
||||||
http_port = 8000
|
http_port = 8000
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"http_port": 8000,
|
|
||||||
"https_port": 8443,
|
|
||||||
"language": "en_EN",
|
|
||||||
"cookie_expire": 30,
|
|
||||||
"cookie_secret": "random",
|
|
||||||
"apikey_secret": "random",
|
|
||||||
"show_errors": true,
|
|
||||||
"history_max_age": 7,
|
|
||||||
"stats_update_frequency": 30,
|
|
||||||
"delete_default_json": false,
|
|
||||||
"show_contribute_link": true,
|
|
||||||
"virtual_terminal_lines": 70,
|
|
||||||
"max_log_lines": 700,
|
|
||||||
"max_audit_entries": 300,
|
|
||||||
"disabled_language_files": [
|
|
||||||
"lol_EN.json",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"stream_size_GB": 1,
|
|
||||||
"keywords": [
|
|
||||||
"help",
|
|
||||||
"chunk"
|
|
||||||
],
|
|
||||||
"allow_nsfw_profile_pictures": false,
|
|
||||||
"enable_user_self_delete": false
|
|
||||||
}
|
|
320
app/frontend/templates/panel/config_json.html
Normal file
320
app/frontend/templates/panel/config_json.html
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
{% extends ../base.html %}
|
||||||
|
|
||||||
|
{% block meta %}
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
{% block title %}Crafty Controller - {{ translate('panelConfig', 'pageTitle', data['lang']) }}{% end %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.10/css/bootstrap-select.min.css">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="content-wrapper">
|
||||||
|
<!-- Page Title Header Starts-->
|
||||||
|
<div class="row page-title-header">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="page-header">
|
||||||
|
<h4 class="page-title">
|
||||||
|
{{ translate('panelConfig', 'title', data['lang']) }}
|
||||||
|
<br />
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Page Title Header Ends-->
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12 grid-margin">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
|
{% if data['superuser'] %}
|
||||||
|
{% include "parts/crafty_config_list.html %}
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
<!-- Page Title Header Starts-->
|
||||||
|
<div class="row page-title-header">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="page-header">
|
||||||
|
<!-- TODO: Translate the following -->
|
||||||
|
<h4 class="page-title">Config.json</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- Page Title Header Ends-->
|
||||||
|
|
||||||
|
<form id="config-form" class="forms-sample" method="post" action="/panel/config_json">
|
||||||
|
{% raw xsrf_form_html() %}
|
||||||
|
|
||||||
|
{% for item in data['config-json'].items() %}
|
||||||
|
{% if item[0] == "reset_secrets_on_next_boot" %}
|
||||||
|
<div class="form-group" style="background: rgba(243, 21, 6, 0.3); outline: 1px solid red; padding: 10px;">
|
||||||
|
{% else %}
|
||||||
|
<div class="form-group">
|
||||||
|
{% end %}
|
||||||
|
<label class="form" for="{{item[0]}}">{{item[0]}}
|
||||||
|
<small class="text-muted ml-1">
|
||||||
|
</small> </label><br />
|
||||||
|
{% if item[0] == 'language' %}
|
||||||
|
<select name="{{item[0]}}" class="form-control">
|
||||||
|
{% for lang in data['availables_languages'] %}
|
||||||
|
{% if lang == item[1] %}
|
||||||
|
<option selected>{{lang}}</option>
|
||||||
|
{% else %}
|
||||||
|
<option>{{lang}}</option>
|
||||||
|
{% end %}
|
||||||
|
{% end %}
|
||||||
|
</select>
|
||||||
|
{% elif item[0] == 'disabled_language_files' %}
|
||||||
|
<div class="input-group">
|
||||||
|
<button type="button" class="btn btn-outline-default custom-picker" onclick="$('option', $('#lang_select')).each(function(element) {
|
||||||
|
$(this).removeAttr('selected').prop('selected', false); $('.selectpicker').selectpicker('refresh')
|
||||||
|
});">Enable all Languages</button>
|
||||||
|
<select id="lang_select" class="form-control selectpicker show-tick" data-icon-base="fas" data-tick-icon="fa-check" multiple data-style="custom-picker">
|
||||||
|
{% for lang in data['all_languages'] %}
|
||||||
|
{% if lang in item[1] %}
|
||||||
|
<option selected>{{lang}}</option>
|
||||||
|
{% else %}
|
||||||
|
<option>{{lang}}</option>
|
||||||
|
{% end %}
|
||||||
|
{% end %}
|
||||||
|
</select>
|
||||||
|
<textarea id="disabled_lang" name="{{item[0]}}" class="form-control list hidden" rows="{{ len(data['all_languages']) }}" value="{{','.join(item[1])}}" hidden>{{','.join(item[1])}}</textarea>
|
||||||
|
</div>
|
||||||
|
{% elif isinstance(item[1], list) %}
|
||||||
|
<textarea value="{{','.join(item[1])}}" type="text" name="{{item[0]}}" class="form-control list">{{','.join(item[1])}}</textarea>
|
||||||
|
{% elif isinstance(item[1], bool) %}
|
||||||
|
<div style="margin-left: 30px;">
|
||||||
|
{% if item[1] == True %}
|
||||||
|
<input type="radio" class="form-check-input" name="{{item[0]}}" id="True" value="True" checked>
|
||||||
|
<label for="True">True</label><br>
|
||||||
|
<input type="radio" class="form-check-input" name="{{item[0]}}" id="False" value="False">
|
||||||
|
<label for="False">False</label>
|
||||||
|
{% else %}
|
||||||
|
<input type="radio" class="form-check-input" name="{{item[0]}}" id="True" value="True">
|
||||||
|
<label for="True">True</label><br>
|
||||||
|
<input type="radio" class="form-check-input" name="{{item[0]}}" id="False" value="False" checked>
|
||||||
|
<label for="False">False</label>
|
||||||
|
{% end %}
|
||||||
|
</div>
|
||||||
|
{% elif isinstance(item[1], int) %}
|
||||||
|
<input type="number" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}" step="1" min="0" required>
|
||||||
|
{% else %}
|
||||||
|
<input type="text" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}" step="2" min="0" required>
|
||||||
|
{% end %}
|
||||||
|
</div>
|
||||||
|
{% end %}
|
||||||
|
<button class="btn btn-success" type="submit">Submit</button> <span id="submit-status"></span>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.custom-picker {
|
||||||
|
border: 1px solid var(--outline);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu.inner {
|
||||||
|
display: inline-block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover-body {
|
||||||
|
color: white !important;
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"] {
|
||||||
|
-ms-transform: scale(1.5);
|
||||||
|
/* IE 9 */
|
||||||
|
-webkit-transform: scale(1.5);
|
||||||
|
/* Chrome, Safari, Opera */
|
||||||
|
transform: scale(1.5);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<!-- content-wrapper ends -->
|
||||||
|
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
<script>
|
||||||
|
$("#config-form").submit(function (e) {
|
||||||
|
let uuid = uuidv4();
|
||||||
|
var token = getCookie("_xsrf")
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
$("#submit-status").html('<i class="fa fa-spinner fa-spin"></i>');
|
||||||
|
/* Convert multiple select to text list */
|
||||||
|
let selected_Lang = $('#lang_select').val();
|
||||||
|
$('#disabled_lang').val(selected_Lang);
|
||||||
|
|
||||||
|
let class_list = document.getElementsByClassName("list");
|
||||||
|
let form_json = convertFormToJSON($("#config-form"));
|
||||||
|
for (let i = 0; i < class_list.length; i++) {
|
||||||
|
let str = String($(class_list.item(i)).val())
|
||||||
|
form_json[$(class_list.item(i)).attr("name")] = uuid + "," + str.replace(/\s/g, '');
|
||||||
|
};
|
||||||
|
form_json['uuid'] = uuid;
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
headers: { 'X-XSRFToken': token },
|
||||||
|
dataType: "text",
|
||||||
|
url: '/panel/config_json',
|
||||||
|
data: form_json,
|
||||||
|
success: function (data) {
|
||||||
|
$("#submit-status").html('<i class="fa fa-check"></i>');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function uuidv4() {
|
||||||
|
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
|
||||||
|
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function convertFormToJSON(form) {
|
||||||
|
const array = $(form).serializeArray(); // Encodes the set of form elements as an array of names and values.
|
||||||
|
const json = {};
|
||||||
|
$.each(array, function () {
|
||||||
|
json[this.name] = this.value || "";
|
||||||
|
});
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
$('[data-toggle="popover"]').popover();
|
||||||
|
if ($(window).width() < 1000) {
|
||||||
|
$('.too_small').popover("show");
|
||||||
|
$('.too_small2').popover("show");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
$(window).ready(function () {
|
||||||
|
$('body').click(function () {
|
||||||
|
$('.too_small').popover("hide");
|
||||||
|
$('.too_small2').popover("hide");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$(window).resize(function () {
|
||||||
|
// This will execute whenever the window is resized
|
||||||
|
if ($(window).width() < 1000) {
|
||||||
|
$('.too_small').popover("show");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('.too_small').popover("hide");
|
||||||
|
} // New width
|
||||||
|
if ($(window).width() < 1000) {
|
||||||
|
$('.too_small2').popover("show");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('.too_small2').popover("hide");
|
||||||
|
} // New width
|
||||||
|
});
|
||||||
|
$('#file').change(function () {
|
||||||
|
console.log("File changed");
|
||||||
|
if ($('#file').val()) {
|
||||||
|
$('#upload-button').prop("disabled", false);
|
||||||
|
console.log("File changed good");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
console.log('ready for JS!');
|
||||||
|
$('.selectpicker').selectpicker("refresh");
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".show_button").click(function () {
|
||||||
|
console.log("showing key");
|
||||||
|
api_key = $(this).attr("data-id");
|
||||||
|
bootbox.alert({
|
||||||
|
backdrop: true,
|
||||||
|
title: '',
|
||||||
|
message: api_key,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.clear-comm').click(function () {
|
||||||
|
var token = getCookie("_xsrf")
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
headers: { 'X-XSRFToken': token },
|
||||||
|
url: '/ajax/clear_comm',
|
||||||
|
success: function (data) {
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
$('.delete-photo').click(function () {
|
||||||
|
var token = getCookie("_xsrf")
|
||||||
|
let photo = $('#photo').find(":selected").val();
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
headers: { 'X-XSRFToken': token },
|
||||||
|
url: '/ajax/delete_photo?photo=' + photo,
|
||||||
|
success: function (data) {
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
$('.select-photo').click(function () {
|
||||||
|
var token = getCookie("_xsrf")
|
||||||
|
let photo = $('#photo').find(":selected").val();
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
headers: { 'X-XSRFToken': token },
|
||||||
|
url: '/ajax/select_photo?photo=' + photo,
|
||||||
|
success: function (data) {
|
||||||
|
window.location.reload();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
var file;
|
||||||
|
function sendFile() {
|
||||||
|
file = $("#file")[0].files[0]
|
||||||
|
document.getElementById("upload_input").innerHTML = '<div class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>'
|
||||||
|
let xmlHttpRequest = new XMLHttpRequest();
|
||||||
|
let token = getCookie("_xsrf")
|
||||||
|
let fileName = file.name
|
||||||
|
let target = '/upload'
|
||||||
|
let mimeType = file.type
|
||||||
|
let size = file.size
|
||||||
|
let type = 'background'
|
||||||
|
|
||||||
|
xmlHttpRequest.open('POST', target, true);
|
||||||
|
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
|
||||||
|
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
|
||||||
|
xmlHttpRequest.setRequestHeader('X-Content-Length', size);
|
||||||
|
xmlHttpRequest.setRequestHeader('X-Content-Disposition', 'attachment; filename="' + fileName + '"');
|
||||||
|
xmlHttpRequest.setRequestHeader('X-Content-Upload-Type', type);
|
||||||
|
xmlHttpRequest.setRequestHeader('X-FileName', fileName);
|
||||||
|
xmlHttpRequest.addEventListener('load', (event) => {
|
||||||
|
if (event.target.responseText == 'success') {
|
||||||
|
console.log('Upload for file', file.name, 'was successful!')
|
||||||
|
document.getElementById("upload_input").innerHTML = '<div class="card-header header-sm d-flex justify-content-between align-items-center"><span id="file-uploaded" style="color: gray;">' + fileName + '</span> 🔒</div>';
|
||||||
|
setTimeout(function () {
|
||||||
|
window.location.reload();
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert('Upload failed with response: ' + event.target.responseText);
|
||||||
|
doUpload = false;
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
xmlHttpRequest.addEventListener('error', (e) => {
|
||||||
|
console.error('Error while uploading file', file.name + '.', 'Event:', e)
|
||||||
|
}, false);
|
||||||
|
xmlHttpRequest.send(file);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.10/js/bootstrap-select.min.js">
|
||||||
|
</script>
|
||||||
|
{% end %}
|
391
app/frontend/templates/panel/custom_login.html
Normal file
391
app/frontend/templates/panel/custom_login.html
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
{% extends ../base.html %}
|
||||||
|
|
||||||
|
{% block meta %}
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
{% block title %}Crafty Controller - {{ translate('customLogin', 'pageTitle', data['lang']) }}{% end %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="content-wrapper">
|
||||||
|
<!-- Page Title Header Starts-->
|
||||||
|
<div class="row page-title-header">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="page-header">
|
||||||
|
<h4 class="page-title">
|
||||||
|
{{ translate('panelConfig', 'title', data['lang']) }}
|
||||||
|
<br />
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Page Title Header Ends-->
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12 grid-margin">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
|
|
||||||
|
{% if data['superuser'] %}
|
||||||
|
{% include "parts/crafty_config_list.html %}
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
<!-- Page Title Header Starts-->
|
||||||
|
<div class="row page-title-header">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="page-header">
|
||||||
|
<!-- TODO: Translate the following -->
|
||||||
|
<h4 class="page-title">{{ translate('customLogin', 'customLoginPage', data['lang']) }}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- Page Title Header Ends-->
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12 col-lg-12 grid-margin stretch-card">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h4>{{ translate('customLogin', 'loginImage', data['lang']) }}</h4>
|
||||||
|
<hr>
|
||||||
|
<form class="form-row" name="zip" method="post" class="server-wizard" onSubmit="wait_msg(true)">
|
||||||
|
{% raw xsrf_form_html() %}
|
||||||
|
<input type="hidden" value="import_zip" name="create_type">
|
||||||
|
<div class="col form-group">
|
||||||
|
<span id="upload_input"><input type="file" class="form-control-file" id="file" name="file"
|
||||||
|
multiple="false" required></span>
|
||||||
|
</div>
|
||||||
|
<div class="col form-group">
|
||||||
|
<button type="button" class="btn btn-info" id="upload-button" onclick="sendFile()"
|
||||||
|
disabled>UPLOAD</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<hr>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<div>
|
||||||
|
<h6>{{ translate('customLogin', 'preview', data['lang']) }}:</h6>
|
||||||
|
<form id="photo_form">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="photo" class="col-sm-6 col-form-label">Selected Background Image</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<select class="form-select form-control form-control-lg select-css form-control-plaintext"
|
||||||
|
id="photo" name="photo" form="photo_form" onchange="updateBackgroundPreview()">
|
||||||
|
{% for image in data["backgrounds"] %}
|
||||||
|
<option value="{{image}}">{{image}}</option>
|
||||||
|
{% end %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="photo_loading" class="form-group" hidden>
|
||||||
|
<div class="progress">
|
||||||
|
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
|
||||||
|
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i
|
||||||
|
class="fa-solid fa-spinner"></i></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-3" for="formControlRange">{{ translate('customLogin', 'loginOpacity',
|
||||||
|
data['lang']) }}</label>
|
||||||
|
<label class="col-sm-1" id="opacityValue">{{ data['login_opacity'] }}%</label>
|
||||||
|
<div class="range col-sm-8">
|
||||||
|
<input type="range" class="form-control-range" id="modal_opacity" name="modal_opacity"
|
||||||
|
onchange="previewOpacity()" min="0" max="100" value="{{ data['login_opacity'] }}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="login_preview" style="position: relative;">
|
||||||
|
<img id="bg-preview" src="../../static/assets/images/auth/{{ data['background'] }}"
|
||||||
|
class="img-fluid" alt="Responsive image">
|
||||||
|
<div id="login-form-preview">
|
||||||
|
<div id="login-form-background" class="auto-form-wrapper login-modal">
|
||||||
|
<div class="text-center auto-form-logo">
|
||||||
|
<img src="/static/assets/images/logo_long.svg">
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
#login-form-preview {
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
overflow: hidden;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%) translateY(-50%);
|
||||||
|
max-width: 90%;
|
||||||
|
max-height: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auto-form-wrapper {
|
||||||
|
background: rgb(34, 36, 55, 1);
|
||||||
|
padding: 2rem 2rem 0.5rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
-webkit-box-shadow: 0 -25px 37.7px 11.3px rgb(8 143 220 / 7%);
|
||||||
|
box-shadow: 0 -25px 37.7px 11.3px rgb(8 143 220 / 7%);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*.auto-form-logo {
|
||||||
|
background: #222437;
|
||||||
|
padding: 0rem;
|
||||||
|
margin: 0.5rem 0rem;
|
||||||
|
border-radius: 0.2rem;
|
||||||
|
color: #fff;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
.login-modal {
|
||||||
|
border-radius: 0.4rem !important;
|
||||||
|
box-shadow: 0 8px 12px 0 hsla(0, 0%, 0%, 0.2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-text-input {
|
||||||
|
border: none !important;
|
||||||
|
background-color: hsl(234, 30%, 45%);
|
||||||
|
color: var(--white) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-text-input:hover,
|
||||||
|
.login-text-input:focus {
|
||||||
|
background-color: hsl(234, 30%, 39%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-input {
|
||||||
|
border-radius: 0.4rem !important;
|
||||||
|
box-shadow: 0 8px 12px 0 hsla(0, 0%, 0%, 0.2);
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-input:hover,
|
||||||
|
.login-input:focus {
|
||||||
|
box-shadow: 0 12px 16px 0 hsla(0, 0%, 0%, 0.4);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="login_form_data">
|
||||||
|
<input type="hidden" name="_xsrf"
|
||||||
|
value="2|1d603267|809fb6bd82f677d440e484dde7c3a310|1671726040" disabled>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="label">Username</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control login-text-input login-input"
|
||||||
|
placeholder="Username" name="username" id="username" required="true" disabled>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="label">Password</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="password" class="form-control login-text-input login-input"
|
||||||
|
placeholder="Password" name="password" id="password" required="true" disabled>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button class="login-input btn btn-primary submit-btn btn-block" disabled>Log
|
||||||
|
In</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<fieldset style="color: red; text-align: center;">
|
||||||
|
<span></span>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="form-group d-flex justify-content-between">
|
||||||
|
<div class="form-check form-check-flat mt-0">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<a href="#" class="text-small forgot-password" disabled>Forgot Password</a>
|
||||||
|
</div>
|
||||||
|
<div class="text-block text-center my-3">
|
||||||
|
<span class="text-small font-weight-semibold"><a
|
||||||
|
href="https://craftycontrol.com/">Crafty Control
|
||||||
|
4.0.20</a> </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button class="btn btn-outline-success select-photo" type="button">{{
|
||||||
|
translate('customLogin',
|
||||||
|
'apply', data['lang']) }}</button>
|
||||||
|
<button class="btn btn-outline-danger delete-photo" type="button">{{
|
||||||
|
translate('customLogin',
|
||||||
|
'delete', data['lang']) }}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.popover-body {
|
||||||
|
color: white !important;
|
||||||
|
;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<!-- content-wrapper ends -->
|
||||||
|
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
$('[data-toggle="popover"]').popover();
|
||||||
|
if ($(window).width() < 1000) {
|
||||||
|
$('.too_small').popover("show");
|
||||||
|
$('.too_small2').popover("show");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
$(window).ready(function () {
|
||||||
|
$('body').click(function () {
|
||||||
|
$('.too_small').popover("hide");
|
||||||
|
$('.too_small2').popover("hide");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$(window).resize(function () {
|
||||||
|
// This will execute whenever the window is resized
|
||||||
|
if ($(window).width() < 1000) {
|
||||||
|
$('.too_small').popover("show");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('.too_small').popover("hide");
|
||||||
|
} // New width
|
||||||
|
if ($(window).width() < 1000) {
|
||||||
|
$('.too_small2').popover("show");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('.too_small2').popover("hide");
|
||||||
|
} // New width
|
||||||
|
});
|
||||||
|
$('#file').change(function () {
|
||||||
|
console.log("File changed");
|
||||||
|
if ($('#file').val()) {
|
||||||
|
$('#upload-button').prop("disabled", false);
|
||||||
|
console.log("File changed good");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
console.log('ready for JS!')
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".show_button").click(function () {
|
||||||
|
console.log("showing key");
|
||||||
|
api_key = $(this).attr("data-id");
|
||||||
|
bootbox.alert({
|
||||||
|
backdrop: true,
|
||||||
|
title: '',
|
||||||
|
message: api_key,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.delete-photo').click(function () {
|
||||||
|
var token = getCookie("_xsrf")
|
||||||
|
let photo = $('#photo').find(":selected").val();
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
headers: { 'X-XSRFToken': token },
|
||||||
|
url: '/ajax/delete_photo?photo=' + encodeURIComponent(photo),
|
||||||
|
success: function (data) {
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
$('.select-photo').click(function () {
|
||||||
|
var token = getCookie("_xsrf")
|
||||||
|
let photo = $('#photo').find(":selected").val();
|
||||||
|
let opacity = $('#modal_opacity').val();
|
||||||
|
let enc_photo = encodeURIComponent(photo);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
headers: { 'X-XSRFToken': token },
|
||||||
|
url: '/ajax/select_photo?photo=' + enc_photo + '&opacity=' + opacity,
|
||||||
|
success: function (data) {
|
||||||
|
window.location.reload();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
let opacity = parseInt($("#modal_opacity").val());
|
||||||
|
document.getElementById('login-form-background').style.background = 'rgb(34, 36, 55, ' + (opacity / 100) + ')';
|
||||||
|
});
|
||||||
|
|
||||||
|
function previewOpacity() {
|
||||||
|
let opacity = parseInt($("#modal_opacity").val())
|
||||||
|
console.debug("Selected Opacity = " + opacity + "%");
|
||||||
|
document.getElementById('opacityValue').innerHTML = (opacity) + "%";
|
||||||
|
document.getElementById('login-form-background').style.background = 'rgb(34, 36, 55, ' + (opacity / 100) + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBackgroundSelect() {
|
||||||
|
$("#photo").val($("#try_photo").val()).change();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBackgroundPreview() {
|
||||||
|
var img = document.getElementById('bg-preview');
|
||||||
|
if ($("#photo").val() == "login_1.jpg") {
|
||||||
|
var src_path = "../../static/assets/images/auth/".concat($("#photo").val());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var src_path = "../../static/assets/images/auth/custom/".concat($("#photo").val());
|
||||||
|
}
|
||||||
|
img.src = src_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
var file;
|
||||||
|
function sendFile() {
|
||||||
|
file = $("#file")[0].files[0]
|
||||||
|
document.getElementById("upload_input").innerHTML = '<div class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>';
|
||||||
|
let xmlHttpRequest = new XMLHttpRequest();
|
||||||
|
let token = getCookie("_xsrf")
|
||||||
|
let fileName = file.name
|
||||||
|
let target = '/upload'
|
||||||
|
let mimeType = file.type
|
||||||
|
let size = file.size
|
||||||
|
let type = 'background'
|
||||||
|
|
||||||
|
xmlHttpRequest.open('POST', target, true);
|
||||||
|
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
|
||||||
|
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
|
||||||
|
xmlHttpRequest.setRequestHeader('X-Content-Length', size);
|
||||||
|
xmlHttpRequest.setRequestHeader('X-Content-Disposition', 'attachment; filename="' + fileName + '"');
|
||||||
|
xmlHttpRequest.setRequestHeader('X-Content-Upload-Type', type);
|
||||||
|
xmlHttpRequest.setRequestHeader('X-FileName', fileName);
|
||||||
|
xmlHttpRequest.addEventListener('load', (event) => {
|
||||||
|
if (event.target.responseText == 'success') {
|
||||||
|
console.log('Upload for file', file.name, 'was successful!')
|
||||||
|
document.getElementById("upload_input").innerHTML = '<div class="card-header header-sm d-flex justify-content-between align-items-center"><span id="file-uploaded" style="color: gray;">' + fileName + '</span> 🔒</div>';
|
||||||
|
setTimeout(function () {
|
||||||
|
window.location.reload();
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert('Upload failed with response: ' + event.target.responseText);
|
||||||
|
doUpload = false;
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
xmlHttpRequest.addEventListener('error', (e) => {
|
||||||
|
console.error('Error while uploading file', file.name + '.', 'Event:', e)
|
||||||
|
}, false);
|
||||||
|
xmlHttpRequest.send(file);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{% end %}
|
@ -8,16 +8,16 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
|
|
||||||
<!-- Page Title Header Starts-->
|
<!-- Page Title Header Starts-->
|
||||||
<div class="row page-title-header">
|
<div class="row page-title-header">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<!-- TODO: Translate the following -->
|
<h4 class="page-title">
|
||||||
<h4 class="page-title">{{ translate('panelConfig', 'pageTitle', data['lang']) }}</h4>
|
{{ translate('panelConfig', 'title', data['lang']) }}
|
||||||
|
<br />
|
||||||
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- Page Title Header Ends-->
|
<!-- Page Title Header Ends-->
|
||||||
|
|
||||||
@ -26,6 +26,23 @@
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
|
|
||||||
|
{% if data['superuser'] %}
|
||||||
|
{% include "parts/crafty_config_list.html %}
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
<!-- Page Title Header Starts-->
|
||||||
|
<div class="row page-title-header">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="page-header">
|
||||||
|
<!-- TODO: Translate the following -->
|
||||||
|
<h4 class="page-title">{{ translate('panelConfig', 'pageTitle', data['lang']) }}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- Page Title Header Ends-->
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12 col-lg-12 grid-margin stretch-card">
|
<div class="col-md-12 col-lg-12 grid-margin stretch-card">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
@ -33,9 +50,7 @@
|
|||||||
<h4 class="card-title"><i class="fas fa-users"></i> {{ translate('panelConfig', 'users', data['lang'])
|
<h4 class="card-title"><i class="fas fa-users"></i> {{ translate('panelConfig', 'users', data['lang'])
|
||||||
}}</h4>
|
}}</h4>
|
||||||
{% if data['user_data']['hints'] %}
|
{% if data['user_data']['hints'] %}
|
||||||
<span class="too_small" title="{{ translate('dashboard', 'cannotSee', data['lang']) }}" ,
|
<span class="too_small" title="{{ translate('dashboard', 'cannotSee', data['lang']) }}" , data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}" , data-placement="top"></span>
|
||||||
data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}" ,
|
|
||||||
data-placement="top"></span>
|
|
||||||
{% end %}
|
{% end %}
|
||||||
<!-- TODO: Translate the following -->
|
<!-- TODO: Translate the following -->
|
||||||
<div><a class="nav-link" href="/panel/add_user"><i class="fas fa-plus-circle"></i> {{
|
<div><a class="nav-link" href="/panel/add_user"><i class="fas fa-plus-circle"></i> {{
|
||||||
@ -133,9 +148,7 @@
|
|||||||
<h4 class="card-title"><i class="fas fa-user-tag"></i> {{ translate('panelConfig', 'roles',
|
<h4 class="card-title"><i class="fas fa-user-tag"></i> {{ translate('panelConfig', 'roles',
|
||||||
data['lang']) }}</h4>
|
data['lang']) }}</h4>
|
||||||
{% if data['user_data']['hints'] %}
|
{% if data['user_data']['hints'] %}
|
||||||
<span class="too_small2" title="{{ translate('dashboard', 'cannotSee', data['lang']) }}" ,
|
<span class="too_small2" title="{{ translate('dashboard', 'cannotSee', data['lang']) }}" , data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}" , data-placement="top"></span>
|
||||||
data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}" ,
|
|
||||||
data-placement="top"></span>
|
|
||||||
{% end %}
|
{% end %}
|
||||||
<div><a class="nav-link" href="/panel/add_role"><i class="fas fa-plus-circle"></i> {{
|
<div><a class="nav-link" href="/panel/add_role"><i class="fas fa-plus-circle"></i> {{
|
||||||
translate('panelConfig', 'newRole', data['lang']) }}</a></div>
|
translate('panelConfig', 'newRole', data['lang']) }}</a></div>
|
||||||
@ -224,185 +237,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-12 col-lg-12 grid-margin stretch-card">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
|
||||||
<h4>{{ translate('panelConfig', 'customLoginPage', data['lang']) }}</h4>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<h4>{{ translate('panelConfig', 'loginImage', data['lang']) }}</h4>
|
|
||||||
<hr>
|
|
||||||
<form class="form-row" name="zip" method="post" class="server-wizard" onSubmit="wait_msg(true)">
|
|
||||||
{% raw xsrf_form_html() %}
|
|
||||||
<input type="hidden" value="import_zip" name="create_type">
|
|
||||||
<div class="col form-group">
|
|
||||||
<span id="upload_input"><input type="file" class="form-control-file" id="file" name="file"
|
|
||||||
multiple="false" required></span>
|
|
||||||
</div>
|
|
||||||
<div class="col form-group">
|
|
||||||
<button type="button" class="btn btn-info" id="upload-button" onclick="sendFile()"
|
|
||||||
disabled>UPLOAD</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<hr>
|
|
||||||
<hr />
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div>
|
|
||||||
<h6>{{ translate('panelConfig', 'preview', data['lang']) }}:</h6>
|
|
||||||
<form id="photo_form">
|
|
||||||
<div class="form-group row">
|
|
||||||
<label for="photo" class="col-sm-6 col-form-label">Selected Background Image</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<select class="form-select form-control form-control-lg select-css form-control-plaintext"
|
|
||||||
id="photo" name="photo" form="photo_form" onchange="updateBackgroundPreview()">
|
|
||||||
{% for image in data["backgrounds"] %}
|
|
||||||
<option value="{{image}}">{{image}}</option>
|
|
||||||
{% end %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="photo_loading" class="form-group" hidden>
|
|
||||||
<div class="progress">
|
|
||||||
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
|
|
||||||
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i
|
|
||||||
class="fa-solid fa-spinner"></i></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-3" for="formControlRange">{{ translate('panelConfig', 'loginOpacity',
|
|
||||||
data['lang']) }}</label>
|
|
||||||
<label class="col-sm-1" id="opacityValue">{{ data['login_opacity'] }}%</label>
|
|
||||||
<div class="range col-sm-8">
|
|
||||||
<input type="range" class="form-control-range" id="modal_opacity" name="modal_opacity"
|
|
||||||
onchange="previewOpacity()" min="0" max="100" value="{{ data['login_opacity'] }}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="login_preview" style="position: relative;">
|
|
||||||
<img id="bg-preview" src="../../static/assets/images/auth/{{ data['background'] }}"
|
|
||||||
class="img-fluid" alt="Responsive image">
|
|
||||||
<div id="login-form-preview">
|
|
||||||
<div id="login-form-background" class="auto-form-wrapper login-modal">
|
|
||||||
<div class="text-center auto-form-logo">
|
|
||||||
<img src="/static/assets/images/logo_long.svg">
|
|
||||||
</div>
|
|
||||||
<style>
|
|
||||||
#login-form-preview {
|
|
||||||
display: flex;
|
|
||||||
position: absolute;
|
|
||||||
overflow: hidden;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%) translateY(-50%);
|
|
||||||
max-width: 90%;
|
|
||||||
max-height: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.auto-form-wrapper {
|
|
||||||
background: rgb(34, 36, 55, 1);
|
|
||||||
padding: 2rem 2rem 0.5rem;
|
|
||||||
border-radius: 4px;
|
|
||||||
-webkit-box-shadow: 0 -25px 37.7px 11.3px rgb(8 143 220 / 7%);
|
|
||||||
box-shadow: 0 -25px 37.7px 11.3px rgb(8 143 220 / 7%);
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*.auto-form-logo {
|
|
||||||
background: #222437;
|
|
||||||
padding: 0rem;
|
|
||||||
margin: 0.5rem 0rem;
|
|
||||||
border-radius: 0.2rem;
|
|
||||||
color: #fff;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
.login-modal {
|
|
||||||
border-radius: 0.4rem !important;
|
|
||||||
box-shadow: 0 8px 12px 0 hsla(0, 0%, 0%, 0.2) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-text-input {
|
|
||||||
border: none !important;
|
|
||||||
background-color: hsl(234, 30%, 45%);
|
|
||||||
color: var(--white) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-text-input:hover,
|
|
||||||
.login-text-input:focus {
|
|
||||||
background-color: hsl(234, 30%, 39%) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-input {
|
|
||||||
border-radius: 0.4rem !important;
|
|
||||||
box-shadow: 0 8px 12px 0 hsla(0, 0%, 0%, 0.2);
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-input:hover,
|
|
||||||
.login-input:focus {
|
|
||||||
box-shadow: 0 12px 16px 0 hsla(0, 0%, 0%, 0.4);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div id="login_form_data">
|
|
||||||
<input type="hidden" name="_xsrf"
|
|
||||||
value="2|1d603267|809fb6bd82f677d440e484dde7c3a310|1671726040" disabled>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="label">Username</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control login-text-input login-input"
|
|
||||||
placeholder="Username" name="username" id="username" required="true" disabled>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="label">Password</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="password" class="form-control login-text-input login-input"
|
|
||||||
placeholder="Password" name="password" id="password" required="true" disabled>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<button class="login-input btn btn-primary submit-btn btn-block" disabled>Log
|
|
||||||
In</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<fieldset style="color: red; text-align: center;">
|
|
||||||
<span></span>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<div class="form-group d-flex justify-content-between">
|
|
||||||
<div class="form-check form-check-flat mt-0">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<a href="#" class="text-small forgot-password" disabled>Forgot Password</a>
|
|
||||||
</div>
|
|
||||||
<div class="text-block text-center my-3">
|
|
||||||
<span class="text-small font-weight-semibold"><a
|
|
||||||
href="https://craftycontrol.com/">Crafty Control
|
|
||||||
4.0.20</a> </span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<button class="btn btn-outline-success select-photo" type="button">{{
|
|
||||||
translate('panelConfig',
|
|
||||||
'apply', data['lang']) }}</button>
|
|
||||||
<button class="btn btn-outline-danger delete-photo" type="button">{{
|
|
||||||
translate('panelConfig',
|
|
||||||
'delete', data['lang']) }}</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% end %}
|
{% end %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -461,116 +295,5 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script>
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
console.log('ready for JS!')
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".show_button").click(function () {
|
|
||||||
console.log("showing key");
|
|
||||||
api_key = $(this).attr("data-id");
|
|
||||||
bootbox.alert({
|
|
||||||
backdrop: true,
|
|
||||||
title: '',
|
|
||||||
message: api_key,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.delete-photo').click(function () {
|
|
||||||
var token = getCookie("_xsrf")
|
|
||||||
let photo = $('#photo').find(":selected").val();
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
headers: { 'X-XSRFToken': token },
|
|
||||||
url: '/ajax/delete_photo?photo=' + encodeURIComponent(photo),
|
|
||||||
success: function (data) {
|
|
||||||
location.reload();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
$('.select-photo').click(function () {
|
|
||||||
var token = getCookie("_xsrf")
|
|
||||||
let photo = $('#photo').find(":selected").val();
|
|
||||||
let opacity = $('#modal_opacity').val();
|
|
||||||
let enc_photo = encodeURIComponent(photo);
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
headers: { 'X-XSRFToken': token },
|
|
||||||
url: '/ajax/select_photo?photo=' + enc_photo + '&opacity=' + opacity,
|
|
||||||
success: function (data) {
|
|
||||||
window.location.reload();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
let opacity = parseInt($("#modal_opacity").val());
|
|
||||||
document.getElementById('login-form-background').style.background = 'rgb(34, 36, 55, ' + (opacity / 100) + ')';
|
|
||||||
});
|
|
||||||
|
|
||||||
function previewOpacity() {
|
|
||||||
let opacity = parseInt($("#modal_opacity").val())
|
|
||||||
console.debug("Selected Opacity = " + opacity + "%");
|
|
||||||
document.getElementById('opacityValue').innerHTML = (opacity) + "%";
|
|
||||||
document.getElementById('login-form-background').style.background = 'rgb(34, 36, 55, ' + (opacity / 100) + ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateBackgroundSelect() {
|
|
||||||
$("#photo").val($("#try_photo").val()).change();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateBackgroundPreview() {
|
|
||||||
var img = document.getElementById('bg-preview');
|
|
||||||
if ($("#photo").val() == "login_1.jpg") {
|
|
||||||
var src_path = "../../static/assets/images/auth/".concat($("#photo").val());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var src_path = "../../static/assets/images/auth/custom/".concat($("#photo").val());
|
|
||||||
}
|
|
||||||
img.src = src_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
var file;
|
|
||||||
function sendFile() {
|
|
||||||
file = $("#file")[0].files[0]
|
|
||||||
document.getElementById("upload_input").innerHTML = '<div class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>';
|
|
||||||
let xmlHttpRequest = new XMLHttpRequest();
|
|
||||||
let token = getCookie("_xsrf")
|
|
||||||
let fileName = file.name
|
|
||||||
let target = '/upload'
|
|
||||||
let mimeType = file.type
|
|
||||||
let size = file.size
|
|
||||||
let type = 'background'
|
|
||||||
|
|
||||||
xmlHttpRequest.open('POST', target, true);
|
|
||||||
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
|
|
||||||
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
|
|
||||||
xmlHttpRequest.setRequestHeader('X-Content-Length', size);
|
|
||||||
xmlHttpRequest.setRequestHeader('X-Content-Disposition', 'attachment; filename="' + fileName + '"');
|
|
||||||
xmlHttpRequest.setRequestHeader('X-Content-Upload-Type', type);
|
|
||||||
xmlHttpRequest.setRequestHeader('X-FileName', fileName);
|
|
||||||
xmlHttpRequest.addEventListener('load', (event) => {
|
|
||||||
if (event.target.responseText == 'success') {
|
|
||||||
console.log('Upload for file', file.name, 'was successful!')
|
|
||||||
document.getElementById("upload_input").innerHTML = '<div class="card-header header-sm d-flex justify-content-between align-items-center"><span id="file-uploaded" style="color: gray;">' + fileName + '</span> 🔒</div>';
|
|
||||||
setTimeout(function () {
|
|
||||||
window.location.reload();
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
alert('Upload failed with response: ' + event.target.responseText);
|
|
||||||
doUpload = false;
|
|
||||||
}
|
|
||||||
}, false);
|
|
||||||
xmlHttpRequest.addEventListener('error', (e) => {
|
|
||||||
console.error('Error while uploading file', file.name + '.', 'Event:', e)
|
|
||||||
}, false);
|
|
||||||
xmlHttpRequest.send(file);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{% end %}
|
{% end %}
|
14
app/frontend/templates/panel/parts/crafty_config_list.html
Normal file
14
app/frontend/templates/panel/parts/crafty_config_list.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<ul class="nav nav-tabs col-md-12 tab-simple-styled" role="tablist" style="margin-top: 0;">
|
||||||
|
<li class="nav-item term-nav-item">
|
||||||
|
<a class="nav-link {% if data['active_link'] == 'panel_config' %}active{% end %}" href="/panel/panel_config" role="tab" aria-selected="false">
|
||||||
|
<i class="fas fa-file-signature"></i>Panel Config</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item term-nav-item">
|
||||||
|
<a class="nav-link {% if data['active_link'] == 'config_json' %}active{% end %}" href="/panel/config_json" role="tab" aria-selected="false">
|
||||||
|
<i class="fas fa-file-signature"></i>Config.json</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item term-nav-item">
|
||||||
|
<a class="nav-link {% if data['active_link'] == 'custom_login' %}active{% end %}" href="/panel/custom_login" role="tab" aria-selected="false">
|
||||||
|
<i class="fas fa-file-signature"></i>Custom Login</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
@ -697,7 +697,7 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendFile(file, path, serverId, left, onProgress) {
|
async function sendFile(file, path, serverId, left, i, onProgress) {
|
||||||
let xmlHttpRequest = new XMLHttpRequest();
|
let xmlHttpRequest = new XMLHttpRequest();
|
||||||
let token = getCookie("_xsrf")
|
let token = getCookie("_xsrf")
|
||||||
let fileName = file.name
|
let fileName = file.name
|
||||||
@ -719,7 +719,36 @@
|
|||||||
onProgress(Math.floor(event.loaded / event.total * 100)), false);
|
onProgress(Math.floor(event.loaded / event.total * 100)), false);
|
||||||
xmlHttpRequest.addEventListener('load', (event) => {
|
xmlHttpRequest.addEventListener('load', (event) => {
|
||||||
if (event.target.responseText == 'success') {
|
if (event.target.responseText == 'success') {
|
||||||
console.log('Upload for file', file.name, 'was successful!')
|
console.log('Upload for file', file.name, 'was successful!');
|
||||||
|
let caught = false;
|
||||||
|
try {
|
||||||
|
var par_el = document.getElementById(path + "ul");
|
||||||
|
var items = par_el.children;
|
||||||
|
} catch {
|
||||||
|
caught = true;
|
||||||
|
var par_el = document.getElementById("files-tree");
|
||||||
|
var items = par_el.children;
|
||||||
|
}
|
||||||
|
let name = file.name;
|
||||||
|
console.log(par_el)
|
||||||
|
let full_path = path + '/' + name
|
||||||
|
let flag = false;
|
||||||
|
for (var k = 0; k < items.length; ++k) {
|
||||||
|
if ($(items[k]).attr("data-name") == name) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!flag) {
|
||||||
|
if (caught) {
|
||||||
|
$(par_el).append('<li id=' + '"' + full_path.toString() + 'li' + '"' + 'class="d-block tree-ctx-item tree-file tree-item" data-path=' + '"' + full_path.toString() + '"' + ' data-name=' + '"' + name.toString() + '"' + ' onclick="clickOnFile(event)" ><span style="margin-right: 6px;"><i class="far fa-file"></i></span>' + name + '</li>');
|
||||||
|
} else {
|
||||||
|
$(par_el).append('<li id=' + '"' + full_path.toString() + 'li' + '"' + 'class="tree-ctx-item tree-file tree-item" data-path=' + '"' + full_path.toString() + '"' + ' data-name=' + '"' + name.toString() + '"' + ' onclick="clickOnFile(event)" ><span style="margin-right: 6px;"><i class="far fa-file"></i></span>' + name + '</li>');
|
||||||
|
}
|
||||||
|
setTreeViewContext();
|
||||||
|
}
|
||||||
|
$(`#upload-progress-bar-${i + 1}`).removeClass("progress-bar-striped");
|
||||||
|
$(`#upload-progress-bar-${i + 1}`).addClass("bg-success");
|
||||||
|
$(`#upload-progress-bar-${i + 1}`).html('<i style="color: black;" class="fas fa-box-check"></i>')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
alert('Upload failed with response: ' + event.target.responseText);
|
alert('Upload failed with response: ' + event.target.responseText);
|
||||||
@ -735,7 +764,7 @@
|
|||||||
let uploadWaitDialog;
|
let uploadWaitDialog;
|
||||||
let doUpload = true;
|
let doUpload = true;
|
||||||
|
|
||||||
function uploadFilesE(event) {
|
async function uploadFilesE(event) {
|
||||||
path = event.target.parentElement.getAttribute('data-path');
|
path = event.target.parentElement.getAttribute('data-path');
|
||||||
$(function () {
|
$(function () {
|
||||||
var uploadHtml = "<div>" +
|
var uploadHtml = "<div>" +
|
||||||
@ -795,7 +824,7 @@
|
|||||||
`;
|
`;
|
||||||
$('#upload-progress-bar-parent').append(progressHtml);
|
$('#upload-progress-bar-parent').append(progressHtml);
|
||||||
|
|
||||||
sendFile(files.files[i], path, serverId, nFiles - i - 1, (progress) => {
|
await sendFile(files.files[i], path, serverId, nFiles - i - 1, i, (progress) => {
|
||||||
$(`#upload-progress-bar-${i + 1}`).attr('aria-valuenow', progress)
|
$(`#upload-progress-bar-${i + 1}`).attr('aria-valuenow', progress)
|
||||||
$(`#upload-progress-bar-${i + 1}`).css('width', progress + '%')
|
$(`#upload-progress-bar-${i + 1}`).css('width', progress + '%')
|
||||||
});
|
});
|
||||||
@ -996,7 +1025,6 @@
|
|||||||
function hideUploadBox() {
|
function hideUploadBox() {
|
||||||
if (!uploadWaitDialog) return;
|
if (!uploadWaitDialog) return;
|
||||||
uploadWaitDialog.modal('hide');
|
uploadWaitDialog.modal('hide');
|
||||||
getTreeView();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createFileE(event) {
|
function createFileE(event) {
|
||||||
@ -1074,7 +1102,8 @@
|
|||||||
callback: function (result) {
|
callback: function (result) {
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
deleteFile(path, function () {
|
deleteFile(path, function () {
|
||||||
getTreeView()
|
el = document.getElementById(path + "li");
|
||||||
|
$(el).remove();
|
||||||
document.getElementById('files-tree-nav').style.display = 'none';
|
document.getElementById('files-tree-nav').style.display = 'none';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1102,7 +1131,8 @@
|
|||||||
callback: function (result) {
|
callback: function (result) {
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
deleteDir(path, function () {
|
deleteDir(path, function () {
|
||||||
getTreeView()
|
el = document.getElementById(path + "li");
|
||||||
|
$(el).remove();
|
||||||
document.getElementById('files-tree-nav').style.display = 'none';
|
document.getElementById('files-tree-nav').style.display = 'none';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
16
app/migrations/20230129_secrets_shh.py
Normal file
16
app/migrations/20230129_secrets_shh.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Generated by database migrator
|
||||||
|
import peewee
|
||||||
|
|
||||||
|
|
||||||
|
def migrate(migrator, database, **kwargs):
|
||||||
|
migrator.add_columns("crafty_settings", cookie_secret=peewee.CharField(default=""))
|
||||||
|
"""
|
||||||
|
Write your migrations here.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def rollback(migrator, database, **kwargs):
|
||||||
|
migrator.drop_columns("crafty_settings", ["cookie_secret"])
|
||||||
|
"""
|
||||||
|
Write your rollback migrations here.
|
||||||
|
"""
|
@ -213,6 +213,8 @@
|
|||||||
"assignedRoles": "Assigned Roles",
|
"assignedRoles": "Assigned Roles",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"clearComms": "Clear Un-executed Commands",
|
"clearComms": "Clear Un-executed Commands",
|
||||||
|
"select": "Select",
|
||||||
|
"apply": "Apply",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"enabled": "Enabled",
|
"enabled": "Enabled",
|
||||||
@ -228,6 +230,9 @@
|
|||||||
"superConfirmTitle": "Enable superuser? Are you sure?",
|
"superConfirmTitle": "Enable superuser? Are you sure?",
|
||||||
"user": "User",
|
"user": "User",
|
||||||
"users": "Users",
|
"users": "Users",
|
||||||
|
"title": "Crafty Configuration"
|
||||||
|
},
|
||||||
|
"customLogin": {
|
||||||
"customLoginPage": "Customise the Login Page",
|
"customLoginPage": "Customise the Login Page",
|
||||||
"loginImage": "Upload a background image for the login screen.",
|
"loginImage": "Upload a background image for the login screen.",
|
||||||
"backgroundUpload": "Background Upload",
|
"backgroundUpload": "Background Upload",
|
||||||
@ -235,8 +240,10 @@
|
|||||||
"loginOpacity": "Select the Login Window Opacity",
|
"loginOpacity": "Select the Login Window Opacity",
|
||||||
"select": "Select",
|
"select": "Select",
|
||||||
"apply": "Apply",
|
"apply": "Apply",
|
||||||
|
"delete": "Delete",
|
||||||
"selectImage": "Select an image",
|
"selectImage": "Select an image",
|
||||||
"preview": "Preview"
|
"preview": "Preview",
|
||||||
|
"pageTitle": "Custom Login Page"
|
||||||
},
|
},
|
||||||
"rolesConfig": {
|
"rolesConfig": {
|
||||||
"config": "Role Config",
|
"config": "Role Config",
|
||||||
|
@ -18,16 +18,6 @@ if [ ! "$(ls -A --ignore=.gitkeep ./app/config)" ]; then
|
|||||||
else
|
else
|
||||||
# Keep version file up to date with image
|
# Keep version file up to date with image
|
||||||
cp -f ./app/config_original/version.json ./app/config/version.json
|
cp -f ./app/config_original/version.json ./app/config/version.json
|
||||||
|
|
||||||
# Compare if user's config is different from image, and show differences.
|
|
||||||
echo "\033[36mWrapper | \033[35m🏗️ Checking for config.json changes..."
|
|
||||||
cp -f ./app/config_original/config.json ./app/config/config_image_template
|
|
||||||
if [ "$(diff -q ./app/config/config.json ./app/config/config_image_template)" ]; then
|
|
||||||
echo "\033[36mWrapper | \033[33m👷 We've found differences in your local config, please review!,"
|
|
||||||
echo "\033[36m | \033[33m (This could be an outdated config.json)"
|
|
||||||
else
|
|
||||||
echo "\033[36mWrapper | \033[32m✅ Config good! Proceeding..."
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
19
main.py
19
main.py
@ -14,6 +14,7 @@ from app.classes.shared.import3 import Import3
|
|||||||
from app.classes.shared.console import Console
|
from app.classes.shared.console import Console
|
||||||
from app.classes.shared.helpers import Helpers
|
from app.classes.shared.helpers import Helpers
|
||||||
from app.classes.models.users import HelperUsers
|
from app.classes.models.users import HelperUsers
|
||||||
|
from app.classes.models.management import HelpersManagement
|
||||||
from app.classes.shared.import_helper import ImportHelpers
|
from app.classes.shared.import_helper import ImportHelpers
|
||||||
|
|
||||||
console = Console()
|
console = Console()
|
||||||
@ -53,6 +54,9 @@ def do_intro():
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
Console.magenta(intro)
|
Console.magenta(intro)
|
||||||
|
if not helper.check_file_exists(helper.settings_file):
|
||||||
|
Console.debug("No settings file detected. Creating one.")
|
||||||
|
helper.set_settings(Helpers.get_master_config())
|
||||||
|
|
||||||
|
|
||||||
def setup_logging(debug=True):
|
def setup_logging(debug=True):
|
||||||
@ -121,7 +125,8 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
# do our installer stuff
|
# do our installer stuff
|
||||||
user_helper = HelperUsers(database, helper)
|
user_helper = HelperUsers(database, helper)
|
||||||
installer = DatabaseBuilder(database, helper, user_helper)
|
management_helper = HelpersManagement(database, helper)
|
||||||
|
installer = DatabaseBuilder(database, helper, user_helper, management_helper)
|
||||||
FRESH_INSTALL = installer.is_fresh_install()
|
FRESH_INSTALL = installer.is_fresh_install()
|
||||||
|
|
||||||
if FRESH_INSTALL:
|
if FRESH_INSTALL:
|
||||||
@ -135,10 +140,22 @@ if __name__ == "__main__":
|
|||||||
installer.default_settings()
|
installer.default_settings()
|
||||||
else:
|
else:
|
||||||
Console.debug("Existing install detected")
|
Console.debug("Existing install detected")
|
||||||
|
Console.info("Checking for reset secret flag")
|
||||||
|
if helper.get_setting("reset_secrets_on_next_boot"):
|
||||||
|
Console.info("Found Reset")
|
||||||
|
management_helper.set_secret_api_key(str(helper.random_string_generator(64)))
|
||||||
|
management_helper.set_cookie_secret(str(helper.random_string_generator(32)))
|
||||||
|
helper.set_setting("reset_secrets_on_next_boot", False)
|
||||||
|
else:
|
||||||
|
Console.info("No flag found. Secrets are staying")
|
||||||
file_helper = FileHelpers(helper)
|
file_helper = FileHelpers(helper)
|
||||||
import_helper = ImportHelpers(helper, file_helper)
|
import_helper = ImportHelpers(helper, file_helper)
|
||||||
# now the tables are created, we can load the tasks_manager and server controller
|
# now the tables are created, we can load the tasks_manager and server controller
|
||||||
controller = Controller(database, helper, file_helper, import_helper)
|
controller = Controller(database, helper, file_helper, import_helper)
|
||||||
|
Console.info("Checking for remote changes to config.json")
|
||||||
|
controller.get_config_diff()
|
||||||
|
Console.info("Remote change complete.")
|
||||||
|
|
||||||
import3 = Import3(helper, controller)
|
import3 = Import3(helper, controller)
|
||||||
tasks_manager = TasksManager(helper, controller)
|
tasks_manager = TasksManager(helper, controller)
|
||||||
tasks_manager.start_webserver()
|
tasks_manager.start_webserver()
|
||||||
|
Loading…
Reference in New Issue
Block a user