From 119c34535ca30bdacab1d55820747a652258b6bf Mon Sep 17 00:00:00 2001 From: computergeek125 Date: Sun, 10 Apr 2022 17:46:07 -0500 Subject: [PATCH 01/19] Removed fn, reduced queries in login flow --- app/classes/shared/main_models.py | 9 +++------ app/classes/web/public_handler.py | 19 ++++++------------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/app/classes/shared/main_models.py b/app/classes/shared/main_models.py index 8079f7d9..c110ca9a 100644 --- a/app/classes/shared/main_models.py +++ b/app/classes/shared/main_models.py @@ -10,7 +10,7 @@ Users = Users try: # pylint: disable=unused-import - from peewee import SqliteDatabase, fn + from peewee import SqliteDatabase from playhouse.shortcuts import model_to_dict except ModuleNotFoundError as err: @@ -20,11 +20,8 @@ logger = logging.getLogger(__name__) peewee_logger = logging.getLogger("peewee") peewee_logger.setLevel(logging.INFO) database = SqliteDatabase( - helper.db_path - # This is commented out after presenting issues when - # moving from SQLiteDatabase to SqliteQueueDatabase - # //TODO Enable tuning - # pragmas={"journal_mode": "wal", "cache_size": -1024 * 10} + helper.db_path, + pragmas={"journal_mode": "wal", "cache_size": -1024 * 10} ) diff --git a/app/classes/web/public_handler.py b/app/classes/web/public_handler.py index a91482ef..41083afc 100644 --- a/app/classes/web/public_handler.py +++ b/app/classes/web/public_handler.py @@ -1,9 +1,8 @@ import logging -from app.classes.models.users import Users +from app.classes.models.users import helper_users from app.classes.shared.authentication import authentication from app.classes.shared.helpers import helper -from app.classes.shared.main_models import fn from app.classes.web.base_handler import BaseHandler try: @@ -107,9 +106,8 @@ class PublicHandler(BaseHandler): entered_password = bleach.clean(self.get_argument("password")) # pylint: disable=no-member - user_data = Users.get_or_none( - fn.Lower(Users.username) == entered_username.lower() - ) + user_id = helper_users.get_user_id_by_name(entered_username.lower()) + user_data = helper_users.get_user_model(user_id) # if we don't have a user if not user_data: @@ -152,14 +150,9 @@ class PublicHandler(BaseHandler): ) # record this login - q = ( - Users.select() - .where(Users.username == entered_username.lower()) - .get() - ) - q.last_ip = self.get_remote_ip() - q.last_login = helper.get_time_as_string() - q.save() + user_data.last_ip = self.get_remote_ip() + user_data.last_login = helper.get_time_as_string() + user_data.save() # log this login self.controller.management.add_to_audit_log( From 42ca4bb973c4c385ca6990e5de149ea81eaeebd3 Mon Sep 17 00:00:00 2001 From: computergeek125 Date: Mon, 11 Apr 2022 00:23:55 -0500 Subject: [PATCH 02/19] Refactored the yes to not pass objects in import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge Conflicts ᴙ Us --- .../controllers/crafty_perms_controller.py | 22 +- .../controllers/management_controller.py | 69 ++-- app/classes/controllers/roles_controller.py | 42 +-- .../controllers/server_perms_controller.py | 56 +-- app/classes/controllers/servers_controller.py | 103 +++--- app/classes/controllers/users_controller.py | 109 +++--- app/classes/minecraft/mc_ping.py | 20 +- app/classes/minecraft/serverjars.py | 46 +-- app/classes/minecraft/stats.py | 31 +- app/classes/models/base_model.py | 7 + app/classes/models/crafty_permissions.py | 72 ++-- app/classes/models/management.py | 102 +++--- app/classes/models/roles.py | 47 +-- app/classes/models/server_permissions.py | 89 ++--- app/classes/models/servers.py | 115 +++--- app/classes/models/users.py | 77 ++-- app/classes/shared/authentication.py | 52 ++- app/classes/shared/command.py | 47 ++- app/classes/shared/console.py | 3 - app/classes/shared/file_helpers.py | 24 +- app/classes/shared/helpers.py | 116 +++--- app/classes/shared/import3.py | 34 +- app/classes/shared/main_controller.py | 273 +++++++------- app/classes/shared/main_models.py | 52 +-- app/classes/shared/migration.py | 45 ++- app/classes/shared/permission_helper.py | 7 +- app/classes/shared/server.py | 333 +++++++++--------- app/classes/shared/tasks.py | 143 ++++---- app/classes/shared/translation.py | 17 +- app/classes/web/ajax_handler.py | 88 +++-- app/classes/web/base_handler.py | 18 +- app/classes/web/file_handler.py | 155 ++++---- app/classes/web/http_handler.py | 12 +- app/classes/web/panel_handler.py | 104 +++--- app/classes/web/public_handler.py | 30 +- app/classes/web/server_handler.py | 58 ++- app/classes/web/status_handler.py | 5 +- app/classes/web/tornado_handler.py | 64 ++-- app/classes/web/upload_handler.py | 43 +-- app/classes/web/websocket_handler.py | 28 +- app/classes/web/websocket_helper.py | 12 +- main.py | 42 ++- requirements.txt | 2 +- 43 files changed, 1289 insertions(+), 1525 deletions(-) create mode 100644 app/classes/models/base_model.py diff --git a/app/classes/controllers/crafty_perms_controller.py b/app/classes/controllers/crafty_perms_controller.py index f47324b2..cee677da 100644 --- a/app/classes/controllers/crafty_perms_controller.py +++ b/app/classes/controllers/crafty_perms_controller.py @@ -1,7 +1,7 @@ import logging from app.classes.models.crafty_permissions import ( - crafty_permissions, + Permissions_Crafty, Enum_Permissions_Crafty, ) from app.classes.models.users import ApiKeys @@ -12,25 +12,25 @@ logger = logging.getLogger(__name__) class Crafty_Perms_Controller: @staticmethod def list_defined_crafty_permissions(): - permissions_list = crafty_permissions.get_permissions_list() + permissions_list = Permissions_Crafty.get_permissions_list() return permissions_list @staticmethod def get_mask_crafty_permissions(user_id): - permissions_mask = crafty_permissions.get_crafty_permissions_mask(user_id) + permissions_mask = Permissions_Crafty.get_crafty_permissions_mask(user_id) return permissions_mask @staticmethod def set_permission( permission_mask, permission_tested: Enum_Permissions_Crafty, value ): - return crafty_permissions.set_permission( + return Permissions_Crafty.set_permission( permission_mask, permission_tested, value ) @staticmethod def can_create_server(user_id): - return crafty_permissions.can_add_in_crafty( + return Permissions_Crafty.can_add_in_crafty( user_id, Enum_Permissions_Crafty.Server_Creation ) @@ -52,22 +52,22 @@ class Crafty_Perms_Controller: @staticmethod def list_all_crafty_permissions_quantity_limits(): - return crafty_permissions.get_all_permission_quantity_list() + return Permissions_Crafty.get_all_permission_quantity_list() @staticmethod def list_crafty_permissions_quantity_limits(user_id): - return crafty_permissions.get_permission_quantity_list(user_id) + return Permissions_Crafty.get_permission_quantity_list(user_id) @staticmethod def get_crafty_permissions_list(user_id): - permissions_mask = crafty_permissions.get_crafty_permissions_mask(user_id) - permissions_list = crafty_permissions.get_permissions(permissions_mask) + permissions_mask = Permissions_Crafty.get_crafty_permissions_mask(user_id) + permissions_list = Permissions_Crafty.get_permissions(permissions_mask) return permissions_list @staticmethod def add_server_creation(user_id): - return crafty_permissions.add_server_creation(user_id) + return Permissions_Crafty.add_server_creation(user_id) @staticmethod def get_api_key_permissions_list(key: ApiKeys): - return crafty_permissions.get_api_key_permissions_list(key) + return Permissions_Crafty.get_api_key_permissions_list(key) diff --git a/app/classes/controllers/management_controller.py b/app/classes/controllers/management_controller.py index f591dbfc..5aa59cf8 100644 --- a/app/classes/controllers/management_controller.py +++ b/app/classes/controllers/management_controller.py @@ -1,60 +1,59 @@ import logging -from app.classes.models.management import management_helper -from app.classes.models.servers import servers_helper +from app.classes.models.management import helpers_management +from app.classes.models.servers import helper_servers logger = logging.getLogger(__name__) class Management_Controller: + def __init__(self, management_helper): + self.management_helper = management_helper # ********************************************************************************** # Host_Stats Methods # ********************************************************************************** @staticmethod def get_latest_hosts_stats(): - return management_helper.get_latest_hosts_stats() + return helpers_management.get_latest_hosts_stats() # ********************************************************************************** # Commands Methods # ********************************************************************************** @staticmethod def get_unactioned_commands(): - return management_helper.get_unactioned_commands() + return helpers_management.get_unactioned_commands() - @staticmethod - def send_command(user_id, server_id, remote_ip, command): - server_name = servers_helper.get_server_friendly_name(server_id) + def send_command(self, user_id, server_id, remote_ip, command): + server_name = helper_servers.get_server_friendly_name(server_id) # Example: Admin issued command start_server for server Survival - management_helper.add_to_audit_log( + self.management_helper.add_to_audit_log( user_id, f"issued command {command} for server {server_name}", server_id, remote_ip, ) - management_helper.add_command(server_id, user_id, remote_ip, command) + helpers_management.add_command(server_id, user_id, remote_ip, command) @staticmethod def mark_command_complete(command_id=None): - return management_helper.mark_command_complete(command_id) + return helpers_management.mark_command_complete(command_id) # ********************************************************************************** # Audit_Log Methods # ********************************************************************************** @staticmethod def get_actity_log(): - return management_helper.get_actity_log() + return helpers_management.get_actity_log() - @staticmethod - def add_to_audit_log(user_id, log_msg, server_id=None, source_ip=None): - return management_helper.add_to_audit_log( + def add_to_audit_log(self, user_id, log_msg, server_id=None, source_ip=None): + return self.management_helper.add_to_audit_log( user_id, log_msg, server_id, source_ip ) - @staticmethod - def add_to_audit_log_raw(user_name, user_id, server_id, log_msg, source_ip): - return management_helper.add_to_audit_log_raw( + def add_to_audit_log_raw(self, user_name, user_id, server_id, log_msg, source_ip): + return self.management_helper.add_to_audit_log_raw( user_name, user_id, server_id, log_msg, source_ip ) @@ -72,7 +71,7 @@ class Management_Controller: comment=None, enabled=True, ): - return management_helper.create_scheduled_task( + return helpers_management.create_scheduled_task( server_id, action, interval, @@ -85,63 +84,61 @@ class Management_Controller: @staticmethod def delete_scheduled_task(schedule_id): - return management_helper.delete_scheduled_task(schedule_id) + return helpers_management.delete_scheduled_task(schedule_id) @staticmethod def update_scheduled_task(schedule_id, updates): - return management_helper.update_scheduled_task(schedule_id, updates) + return helpers_management.update_scheduled_task(schedule_id, updates) @staticmethod def get_scheduled_task(schedule_id): - return management_helper.get_scheduled_task(schedule_id) + return helpers_management.get_scheduled_task(schedule_id) @staticmethod def get_scheduled_task_model(schedule_id): - return management_helper.get_scheduled_task_model(schedule_id) + return helpers_management.get_scheduled_task_model(schedule_id) @staticmethod def get_child_schedules(sch_id): - return management_helper.get_child_schedules(sch_id) + return helpers_management.get_child_schedules(sch_id) @staticmethod def get_schedules_by_server(server_id): - return management_helper.get_schedules_by_server(server_id) + return helpers_management.get_schedules_by_server(server_id) @staticmethod def get_schedules_all(): - return management_helper.get_schedules_all() + return helpers_management.get_schedules_all() @staticmethod def get_schedules_enabled(): - return management_helper.get_schedules_enabled() + return helpers_management.get_schedules_enabled() # ********************************************************************************** # Backups Methods # ********************************************************************************** @staticmethod def get_backup_config(server_id): - return management_helper.get_backup_config(server_id) + return helpers_management.get_backup_config(server_id) - @staticmethod def set_backup_config( + self, server_id: int, backup_path: str = None, max_backups: int = None, excluded_dirs: list = None, compress: bool = False, ): - return management_helper.set_backup_config( + return self.management_helper.set_backup_config( server_id, backup_path, max_backups, excluded_dirs, compress ) @staticmethod def get_excluded_backup_dirs(server_id: int): - return management_helper.get_excluded_backup_dirs(server_id) + return helpers_management.get_excluded_backup_dirs(server_id) - @staticmethod - def add_excluded_backup_dir(server_id: int, dir_to_add: str): - management_helper.add_excluded_backup_dir(server_id, dir_to_add) + def add_excluded_backup_dir(self, server_id: int, dir_to_add: str): + self.management_helper.add_excluded_backup_dir(server_id, dir_to_add) - @staticmethod - def del_excluded_backup_dir(server_id: int, dir_to_del: str): - management_helper.del_excluded_backup_dir(server_id, dir_to_del) + def del_excluded_backup_dir(self, server_id: int, dir_to_del: str): + self.management_helper.del_excluded_backup_dir(server_id, dir_to_del) diff --git a/app/classes/controllers/roles_controller.py b/app/classes/controllers/roles_controller.py index f3bcbad8..d370b557 100644 --- a/app/classes/controllers/roles_controller.py +++ b/app/classes/controllers/roles_controller.py @@ -1,25 +1,26 @@ import logging -from app.classes.models.roles import roles_helper -from app.classes.models.server_permissions import server_permissions -from app.classes.models.users import users_helper -from app.classes.shared.helpers import helper +from app.classes.models.roles import helper_roles +from app.classes.models.server_permissions import Permissions_Servers +from app.classes.shared.helpers import Helpers logger = logging.getLogger(__name__) class Roles_Controller: + def __init__(self, users_helper): + self.users_helper = users_helper @staticmethod def get_all_roles(): - return roles_helper.get_all_roles() + return helper_roles.get_all_roles() @staticmethod def get_roleid_by_name(role_name): - return roles_helper.get_roleid_by_name(role_name) + return helper_roles.get_roleid_by_name(role_name) @staticmethod def get_role(role_id): - return roles_helper.get_role(role_id) + return helper_roles.get_role(role_id) @staticmethod def update_role(role_id: str, role_data=None, permissions_mask: str = "00000000"): @@ -37,41 +38,40 @@ class Roles_Controller: removed_servers = base_data["servers"].difference(role_data["servers"]) elif base_data[key] != role_data[key]: up_data[key] = role_data[key] - up_data["last_update"] = helper.get_time_as_string() + up_data["last_update"] = Helpers.get_time_as_string() logger.debug( f"role: {role_data} +server:{added_servers} -server{removed_servers}" ) for server in added_servers: - server_permissions.get_or_create(role_id, server, permissions_mask) + Permissions_Servers.get_or_create(role_id, server, permissions_mask) for server in base_data["servers"]: - server_permissions.update_role_permission(role_id, server, permissions_mask) + Permissions_Servers.update_role_permission(role_id, server, permissions_mask) # TODO: This is horribly inefficient and we should be using bulk queries # but im going for functionality at this point - server_permissions.delete_roles_permissions(role_id, removed_servers) + Permissions_Servers.delete_roles_permissions(role_id, removed_servers) if up_data: - roles_helper.update_role(role_id, up_data) + helper_roles.update_role(role_id, up_data) @staticmethod def add_role(role_name): - return roles_helper.add_role(role_name) + return helper_roles.add_role(role_name) - @staticmethod - def remove_role(role_id): + def remove_role(self, role_id): role_data = Roles_Controller.get_role_with_servers(role_id) - server_permissions.delete_roles_permissions(role_id, role_data["servers"]) - users_helper.remove_roles_from_role_id(role_id) - return roles_helper.remove_role(role_id) + Permissions_Servers.delete_roles_permissions(role_id, role_data["servers"]) + self.users_helper.remove_roles_from_role_id(role_id) + return helper_roles.remove_role(role_id) @staticmethod def role_id_exists(role_id): - return roles_helper.role_id_exists(role_id) + return helper_roles.role_id_exists(role_id) @staticmethod def get_role_with_servers(role_id): - role = roles_helper.get_role(role_id) + role = helper_roles.get_role(role_id) if role: - servers_query = server_permissions.get_servers_from_role(role_id) + servers_query = Permissions_Servers.get_servers_from_role(role_id) # TODO: this query needs to be narrower servers = set() for s in servers_query: diff --git a/app/classes/controllers/server_perms_controller.py b/app/classes/controllers/server_perms_controller.py index 9da02d08..942bf61b 100644 --- a/app/classes/controllers/server_perms_controller.py +++ b/app/classes/controllers/server_perms_controller.py @@ -1,13 +1,13 @@ import logging from app.classes.models.server_permissions import ( - server_permissions, + Permissions_Servers, Enum_Permissions_Server, ) -from app.classes.models.users import users_helper, ApiKeys -from app.classes.models.roles import roles_helper -from app.classes.models.servers import servers_helper -from app.classes.shared.main_models import db_helper +from app.classes.models.users import helper_users, ApiKeys +from app.classes.models.roles import helper_roles +from app.classes.models.servers import helper_servers +from app.classes.shared.main_models import db_shortcuts logger = logging.getLogger(__name__) @@ -15,100 +15,100 @@ logger = logging.getLogger(__name__) class Server_Perms_Controller: @staticmethod def get_server_user_list(server_id): - return server_permissions.get_server_user_list(server_id) + return Permissions_Servers.get_server_user_list(server_id) @staticmethod def list_defined_permissions(): - permissions_list = server_permissions.get_permissions_list() + permissions_list = Permissions_Servers.get_permissions_list() return permissions_list @staticmethod def get_mask_permissions(role_id, server_id): - permissions_mask = server_permissions.get_permissions_mask(role_id, server_id) + permissions_mask = Permissions_Servers.get_permissions_mask(role_id, server_id) return permissions_mask @staticmethod def get_role_permissions(role_id): - permissions_list = server_permissions.get_role_permissions_list(role_id) + permissions_list = Permissions_Servers.get_role_permissions_list(role_id) return permissions_list @staticmethod def add_role_server(server_id, role_id, rs_permissions="00000000"): - return server_permissions.add_role_server(server_id, role_id, rs_permissions) + return Permissions_Servers.add_role_server(server_id, role_id, rs_permissions) @staticmethod def get_server_roles(server_id): - return server_permissions.get_server_roles(server_id) + return Permissions_Servers.get_server_roles(server_id) @staticmethod def backup_role_swap(old_server_id, new_server_id): - role_list = server_permissions.get_server_roles(old_server_id) + role_list = Permissions_Servers.get_server_roles(old_server_id) for role in role_list: - server_permissions.add_role_server( + Permissions_Servers.add_role_server( new_server_id, role.role_id, - server_permissions.get_permissions_mask( + Permissions_Servers.get_permissions_mask( int(role.role_id), int(old_server_id) ), ) - # server_permissions.add_role_server(new_server_id, role.role_id,"00001000") + # Permissions_Servers.add_role_server(new_server_id, role.role_id,"00001000") # ********************************************************************************** # Servers Permissions Methods # ********************************************************************************** @staticmethod def get_permissions_mask(role_id, server_id): - return server_permissions.get_permissions_mask(role_id, server_id) + return Permissions_Servers.get_permissions_mask(role_id, server_id) @staticmethod def set_permission( permission_mask, permission_tested: Enum_Permissions_Server, value ): - return server_permissions.set_permission( + return Permissions_Servers.set_permission( permission_mask, permission_tested, value ) @staticmethod def get_role_permissions_list(role_id): - return server_permissions.get_role_permissions_list(role_id) + return Permissions_Servers.get_role_permissions_list(role_id) @staticmethod def get_user_id_permissions_list(user_id: str, server_id: str): - return server_permissions.get_user_id_permissions_list(user_id, server_id) + return Permissions_Servers.get_user_id_permissions_list(user_id, server_id) @staticmethod def get_api_key_id_permissions_list(key_id: str, server_id: str): - key = users_helper.get_user_api_key(key_id) - return server_permissions.get_api_key_permissions_list(key, server_id) + key = helper_users.get_user_api_key(key_id) + return Permissions_Servers.get_api_key_permissions_list(key, server_id) @staticmethod def get_api_key_permissions_list(key: ApiKeys, server_id: str): - return server_permissions.get_api_key_permissions_list(key, server_id) + return Permissions_Servers.get_api_key_permissions_list(key, server_id) @staticmethod def get_authorized_servers_stats_from_roles(user_id): - user_roles = users_helper.get_user_roles_id(user_id) + user_roles = helper_users.get_user_roles_id(user_id) roles_list = [] role_server = [] authorized_servers = [] server_data = [] for u in user_roles: - roles_list.append(roles_helper.get_role(u.role_id)) + roles_list.append(helper_roles.get_role(u.role_id)) for r in roles_list: - role_test = server_permissions.get_role_servers_from_role_id( + role_test = Permissions_Servers.get_role_servers_from_role_id( r.get("role_id") ) for t in role_test: role_server.append(t) for s in role_server: - authorized_servers.append(servers_helper.get_server_data_by_id(s.server_id)) + authorized_servers.append(helper_servers.get_server_data_by_id(s.server_id)) for s in authorized_servers: - latest = servers_helper.get_latest_server_stats(s.get("server_id")) + latest = helper_servers.get_latest_server_stats(s.get("server_id")) server_data.append( - {"server_data": s, "stats": db_helper.return_rows(latest)[0]} + {"server_data": s, "stats": db_shortcuts.return_rows(latest)[0]} ) return server_data diff --git a/app/classes/controllers/servers_controller.py b/app/classes/controllers/servers_controller.py index b7c09935..14124e7a 100644 --- a/app/classes/controllers/servers_controller.py +++ b/app/classes/controllers/servers_controller.py @@ -3,25 +3,27 @@ import logging import json from app.classes.controllers.roles_controller import Roles_Controller -from app.classes.models.servers import servers_helper -from app.classes.models.users import users_helper, ApiKeys +from app.classes.models.servers import helper_servers +from app.classes.models.users import helper_users, ApiKeys from app.classes.models.server_permissions import ( - server_permissions, + Permissions_Servers, Enum_Permissions_Server, ) -from app.classes.shared.helpers import helper -from app.classes.shared.main_models import db_helper +from app.classes.shared.helpers import Helpers +from app.classes.shared.main_models import db_shortcuts logger = logging.getLogger(__name__) class Servers_Controller: + def __init__(self, servers_helper): + self.servers_helper = servers_helper # ********************************************************************************** # Generic Servers Methods # ********************************************************************************** - @staticmethod def create_server( + self, name: str, server_uuid: str, server_dir: str, @@ -33,7 +35,7 @@ class Servers_Controller: server_type: str, server_port=25565, ): - return servers_helper.create_server( + return self.servers_helper.create_server( name, server_uuid, server_dir, @@ -48,60 +50,59 @@ class Servers_Controller: @staticmethod def get_server_obj(server_id): - return servers_helper.get_server_obj(server_id) + return helper_servers.get_server_obj(server_id) @staticmethod def update_server(server_obj): - return servers_helper.update_server(server_obj) + return helper_servers.update_server(server_obj) @staticmethod def set_download(server_id): - return servers_helper.set_download(server_id) + return helper_servers.set_download(server_id) @staticmethod def finish_download(server_id): - return servers_helper.finish_download(server_id) + return helper_servers.finish_download(server_id) @staticmethod def get_download_status(server_id): - return servers_helper.get_download_status(server_id) + return helper_servers.get_download_status(server_id) - @staticmethod - def remove_server(server_id): - roles_list = server_permissions.get_roles_from_server(server_id) + def remove_server(self, server_id): + roles_list = Permissions_Servers.get_roles_from_server(server_id) for role in roles_list: role_id = role.role_id role_data = Roles_Controller.get_role_with_servers(role_id) role_data["servers"] = {server_id} - server_permissions.delete_roles_permissions(role_id, role_data["servers"]) - server_permissions.remove_roles_of_server(server_id) - servers_helper.remove_server(server_id) + Permissions_Servers.delete_roles_permissions(role_id, role_data["servers"]) + Permissions_Servers.remove_roles_of_server(server_id) + self.servers_helper.remove_server(server_id) @staticmethod def get_server_data_by_id(server_id): - return servers_helper.get_server_data_by_id(server_id) + return helper_servers.get_server_data_by_id(server_id) # ********************************************************************************** # Servers Methods # ********************************************************************************** @staticmethod def get_all_defined_servers(): - return servers_helper.get_all_defined_servers() + return helper_servers.get_all_defined_servers() @staticmethod def get_authorized_servers(user_id): server_data = [] - user_roles = users_helper.user_role_query(user_id) + user_roles = helper_users.user_role_query(user_id) for us in user_roles: - role_servers = server_permissions.get_role_servers_from_role_id(us.role_id) + role_servers = Permissions_Servers.get_role_servers_from_role_id(us.role_id) for role in role_servers: - server_data.append(servers_helper.get_server_data_by_id(role.server_id)) + server_data.append(helper_servers.get_server_data_by_id(role.server_id)) return server_data @staticmethod def get_all_servers_stats(): - return servers_helper.get_all_servers_stats() + return helper_servers.get_all_servers_stats() @staticmethod def get_authorized_servers_stats_api_key(api_key: ApiKeys): @@ -111,8 +112,8 @@ class Servers_Controller: ) for s in authorized_servers: - latest = servers_helper.get_latest_server_stats(s.get("server_id")) - key_permissions = server_permissions.get_api_key_permissions_list( + latest = helper_servers.get_latest_server_stats(s.get("server_id")) + key_permissions = Permissions_Servers.get_api_key_permissions_list( api_key, s.get("server_id") ) if Enum_Permissions_Server.Commands in key_permissions: @@ -122,7 +123,7 @@ class Servers_Controller: server_data.append( { "server_data": s, - "stats": db_helper.return_rows(latest)[0], + "stats": db_shortcuts.return_rows(latest)[0], "user_command_permission": user_command_permission, } ) @@ -134,9 +135,9 @@ class Servers_Controller: authorized_servers = Servers_Controller.get_authorized_servers(user_id) for s in authorized_servers: - latest = servers_helper.get_latest_server_stats(s.get("server_id")) + latest = helper_servers.get_latest_server_stats(s.get("server_id")) # TODO - user_permissions = server_permissions.get_user_id_permissions_list( + user_permissions = Permissions_Servers.get_user_id_permissions_list( user_id, s.get("server_id") ) if Enum_Permissions_Server.Commands in user_permissions: @@ -146,7 +147,7 @@ class Servers_Controller: server_data.append( { "server_data": s, - "stats": db_helper.return_rows(latest)[0], + "stats": db_shortcuts.return_rows(latest)[0], "user_command_permission": user_command_permission, } ) @@ -155,28 +156,28 @@ class Servers_Controller: @staticmethod def get_server_friendly_name(server_id): - return servers_helper.get_server_friendly_name(server_id) + return helper_servers.get_server_friendly_name(server_id) # ********************************************************************************** # Servers_Stats Methods # ********************************************************************************** @staticmethod def get_server_stats_by_id(server_id): - return servers_helper.get_server_stats_by_id(server_id) + return helper_servers.get_server_stats_by_id(server_id) @staticmethod def server_id_exists(server_id): - return servers_helper.server_id_exists(server_id) + return helper_servers.server_id_exists(server_id) @staticmethod def get_server_type_by_id(server_id): - return servers_helper.get_server_type_by_id(server_id) + return helper_servers.get_server_type_by_id(server_id) @staticmethod def server_id_authorized(server_id_a, user_id): - user_roles = users_helper.user_role_query(user_id) + user_roles = helper_users.user_role_query(user_id) for role in user_roles: - for server_id_b in server_permissions.get_role_servers_from_role_id( + for server_id_b in Permissions_Servers.get_role_servers_from_role_id( role.role_id ): if str(server_id_a) == str(server_id_b.server_id): @@ -185,7 +186,7 @@ class Servers_Controller: @staticmethod def is_crashed(server_id): - return servers_helper.is_crashed(server_id) + return helper_servers.is_crashed(server_id) @staticmethod def server_id_authorized_api_key(server_id: str, api_key: ApiKeys) -> bool: @@ -194,42 +195,40 @@ class Servers_Controller: # There is no view server permission # permission_helper.both_have_perm(api_key) - @staticmethod - def set_update(server_id, value): - return servers_helper.set_update(server_id, value) + def set_update(self, server_id, value): + return self.servers_helper.set_update(server_id, value) @staticmethod def get_TTL_without_player(server_id): - return servers_helper.get_TTL_without_player(server_id) + return helper_servers.get_TTL_without_player(server_id) @staticmethod def can_stop_no_players(server_id, time_limit): - return servers_helper.can_stop_no_players(server_id, time_limit) + return helper_servers.can_stop_no_players(server_id, time_limit) - @staticmethod - def set_waiting_start(server_id, value): - servers_helper.set_waiting_start(server_id, value) + def set_waiting_start(self, server_id, value): + self.servers_helper.set_waiting_start(server_id, value) @staticmethod def get_waiting_start(server_id): - return servers_helper.get_waiting_start(server_id) + return helper_servers.get_waiting_start(server_id) @staticmethod def get_update_status(server_id): - return servers_helper.get_update_status(server_id) + return helper_servers.get_update_status(server_id) # ********************************************************************************** # Servers Helpers Methods # ********************************************************************************** @staticmethod def get_banned_players(server_id): - stats = servers_helper.get_server_stats_by_id(server_id) + stats = helper_servers.get_server_stats_by_id(server_id) server_path = stats["server_id"]["path"] path = os.path.join(server_path, "banned-players.json") try: with open( - helper.get_os_understandable_path(path), encoding="utf-8" + Helpers.get_os_understandable_path(path), encoding="utf-8" ) as file: content = file.read() file.close() @@ -240,7 +239,7 @@ class Servers_Controller: return json.loads(content) def check_for_old_logs(self): - servers = servers_helper.get_all_defined_servers() + servers = helper_servers.get_all_defined_servers() for server in servers: logs_path = os.path.split(server["log_path"])[0] latest_log_file = os.path.split(server["log_path"])[1] @@ -253,9 +252,9 @@ class Servers_Controller: ) for log_file in log_files: log_file_path = os.path.join(logs_path, log_file) - if helper.check_file_exists( + if Helpers.check_file_exists( log_file_path - ) and helper.is_file_older_than_x_days( + ) and Helpers.is_file_older_than_x_days( log_file_path, logs_delete_after ): os.remove(log_file_path) diff --git a/app/classes/controllers/users_controller.py b/app/classes/controllers/users_controller.py index 2c5a907a..0a7d1f63 100644 --- a/app/classes/controllers/users_controller.py +++ b/app/classes/controllers/users_controller.py @@ -1,61 +1,62 @@ import logging from typing import Optional -from app.classes.models.users import users_helper +from app.classes.models.users import helper_users from app.classes.models.crafty_permissions import ( - crafty_permissions, + Permissions_Crafty, Enum_Permissions_Crafty, ) -from app.classes.shared.helpers import helper -from app.classes.shared.authentication import authentication logger = logging.getLogger(__name__) class Users_Controller: + def __init__(self, helper, users_helper, authentication): + self.helper = helper + self.users_helper = users_helper + self.authentication = authentication # ********************************************************************************** # Users Methods # ********************************************************************************** @staticmethod def get_all_users(): - return users_helper.get_all_users() + return helper_users.get_all_users() @staticmethod def get_id_by_name(username): - return users_helper.get_user_id_by_name(username) + return helper_users.get_user_id_by_name(username) @staticmethod def get_user_lang_by_id(user_id): - return users_helper.get_user_lang_by_id(user_id) + return helper_users.get_user_lang_by_id(user_id) @staticmethod def get_user_by_id(user_id): - return users_helper.get_user(user_id) + return helper_users.get_user(user_id) @staticmethod def update_server_order(user_id, user_server_order): - users_helper.update_server_order(user_id, user_server_order) + helper_users.update_server_order(user_id, user_server_order) @staticmethod def get_server_order(user_id): - return users_helper.get_server_order(user_id) + return helper_users.get_server_order(user_id) @staticmethod def user_query(user_id): - return users_helper.user_query(user_id) + return helper_users.user_query(user_id) @staticmethod def set_support_path(user_id, support_path): - users_helper.set_support_path(user_id, support_path) + helper_users.set_support_path(user_id, support_path) - @staticmethod - def update_user(user_id: str, user_data=None, user_crafty_data=None): + def update_user(self, user_id: str, user_data=None, user_crafty_data=None): if user_crafty_data is None: user_crafty_data = {} if user_data is None: user_data = {} - base_data = users_helper.get_user(user_id) + base_data = helper_users.get_user(user_id) up_data = {} added_roles = set() removed_roles = set() @@ -67,15 +68,15 @@ class Users_Controller: removed_roles = base_data["roles"].difference(user_data["roles"]) elif key == "password": if user_data["password"] is not None and user_data["password"] != "": - up_data["password"] = helper.encode_pass(user_data["password"]) + up_data["password"] = self.helper.encode_pass(user_data["password"]) elif base_data[key] != user_data[key]: up_data[key] = user_data[key] - up_data["last_update"] = helper.get_time_as_string() + up_data["last_update"] = self.helper.get_time_as_string() up_data["lang"] = user_data["lang"] up_data["hints"] = user_data["hints"] logger.debug(f"user: {user_data} +role:{added_roles} -role:{removed_roles}") for role in added_roles: - users_helper.get_or_create(user_id=user_id, role_id=role) + helper_users.get_or_create(user_id=user_id, role_id=role) permissions_mask = user_crafty_data.get("permissions_mask", "000") if "server_quantity" in user_crafty_data: @@ -94,7 +95,7 @@ class Users_Controller: limit_user_creation = 0 limit_role_creation = 0 - crafty_permissions.add_or_update_user( + Permissions_Crafty.add_or_update_user( user_id, permissions_mask, limit_server_creation, @@ -102,19 +103,19 @@ class Users_Controller: limit_role_creation, ) - users_helper.delete_user_roles(user_id, removed_roles) + self.users_helper.delete_user_roles(user_id, removed_roles) - users_helper.update_user(user_id, up_data) + self.users_helper.update_user(user_id, up_data) - @staticmethod def add_user( + self, username, password, email="default@example.com", enabled: bool = True, superuser: bool = False, ): - return users_helper.add_user( + return self.users_helper.add_user( username, password=password, email=email, @@ -130,7 +131,7 @@ class Users_Controller: enabled: bool = True, superuser: bool = False, ): - return users_helper.add_rawpass_user( + return helper_users.add_rawpass_user( username, password=password, email=email, @@ -138,35 +139,31 @@ class Users_Controller: superuser=superuser, ) - @staticmethod - def remove_user(user_id): - return users_helper.remove_user(user_id) + def remove_user(self, user_id): + return self.users_helper.remove_user(user_id) @staticmethod def user_id_exists(user_id): - return users_helper.user_id_exists(user_id) + return helper_users.user_id_exists(user_id) @staticmethod def set_prepare(user_id): - return users_helper.set_prepare(user_id) + return helper_users.set_prepare(user_id) @staticmethod def stop_prepare(user_id): - return users_helper.stop_prepare(user_id) + return helper_users.stop_prepare(user_id) - @staticmethod - def get_user_id_by_api_token(token: str) -> str: - token_data = authentication.check_no_iat(token) + def get_user_id_by_api_token(self, token: str) -> str: + token_data = self.authentication.check_no_iat(token) return token_data["user_id"] - @staticmethod - def get_user_by_api_token(token: str): - _, _, user = authentication.check(token) + def get_user_by_api_token(self, token: str): + _, _, user = self.authentication.check(token) return user - @staticmethod - def get_api_key_by_token(token: str): - key, _, _ = authentication.check(token) + def get_api_key_by_token(self, token: str): + key, _, _ = self.authentication.check(token) return key # ********************************************************************************** @@ -175,23 +172,21 @@ class Users_Controller: @staticmethod def get_user_roles_id(user_id): - return users_helper.get_user_roles_id(user_id) + return helper_users.get_user_roles_id(user_id) @staticmethod def get_user_roles_names(user_id): - return users_helper.get_user_roles_names(user_id) + return helper_users.get_user_roles_names(user_id) - @staticmethod - def add_role_to_user(user_id, role_id): - return users_helper.add_role_to_user(user_id, role_id) + def add_role_to_user(self, user_id, role_id): + return self.users_helper.add_role_to_user(user_id, role_id) - @staticmethod - def add_user_roles(user): - return users_helper.add_user_roles(user) + def add_user_roles(self, user): + return self.users_helper.add_user_roles(user) @staticmethod def user_role_query(user_id): - return users_helper.user_role_query(user_id) + return helper_users.user_role_query(user_id) # ********************************************************************************** # Api Keys Methods @@ -199,28 +194,26 @@ class Users_Controller: @staticmethod def get_user_api_keys(user_id: str): - return users_helper.get_user_api_keys(user_id) + return helper_users.get_user_api_keys(user_id) @staticmethod def get_user_api_key(key_id: str): - return users_helper.get_user_api_key(key_id) + return helper_users.get_user_api_key(key_id) - @staticmethod def add_user_api_key( + self, name: str, user_id: str, superuser: bool = False, server_permissions_mask: Optional[str] = None, crafty_permissions_mask: Optional[str] = None, ): - return users_helper.add_user_api_key( + return self.users_helper.add_user_api_key( name, user_id, superuser, server_permissions_mask, crafty_permissions_mask ) - @staticmethod - def delete_user_api_keys(user_id: str): - return users_helper.delete_user_api_keys(user_id) + def delete_user_api_keys(self, user_id: str): + return self.users_helper.delete_user_api_keys(user_id) - @staticmethod - def delete_user_api_key(key_id: str): - return users_helper.delete_user_api_key(key_id) + def delete_user_api_key(self, key_id: str): + return self.users_helper.delete_user_api_key(key_id) diff --git a/app/classes/minecraft/mc_ping.py b/app/classes/minecraft/mc_ping.py index b540fac5..31c248f6 100644 --- a/app/classes/minecraft/mc_ping.py +++ b/app/classes/minecraft/mc_ping.py @@ -9,13 +9,13 @@ import uuid import random from app.classes.minecraft.bedrock_ping import BedrockPing -from app.classes.shared.console import console logger = logging.getLogger(__name__) class Server: - def __init__(self, data): + def __init__(self, console, data): + self.console = console self.description = data.get("description") # print(self.description) if isinstance(self.description, dict): @@ -32,19 +32,19 @@ class Server: if "extra" in description.keys(): for e in description["extra"]: # Conversion format code needed only for Java Version - lines.append(get_code_format("reset")) + lines.append(get_code_format(self.console, "reset")) if "bold" in e.keys(): - lines.append(get_code_format("bold")) + lines.append(get_code_format(self.console, "bold")) if "italic" in e.keys(): - lines.append(get_code_format("italic")) + lines.append(get_code_format(self.console, "italic")) if "underlined" in e.keys(): - lines.append(get_code_format("underlined")) + lines.append(get_code_format(self.console, "underlined")) if "strikethrough" in e.keys(): - lines.append(get_code_format("strikethrough")) + lines.append(get_code_format(self.console, "strikethrough")) if "obfuscated" in e.keys(): - lines.append(get_code_format("obfuscated")) + lines.append(get_code_format(self.console, "obfuscated")) if "color" in e.keys(): - lines.append(get_code_format(e["color"])) + lines.append(get_code_format(self.console, e["color"])) # Then append the text if "text" in e.keys(): if e["text"] == "\n": @@ -95,7 +95,7 @@ class Player: return self.name -def get_code_format(format_name): +def get_code_format(console, format_name): root_dir = os.path.abspath(os.path.curdir) format_file = os.path.join(root_dir, "app", "config", "motd_format.json") try: diff --git a/app/classes/minecraft/serverjars.py b/app/classes/minecraft/serverjars.py index 01ad1fb1..9a57f66f 100644 --- a/app/classes/minecraft/serverjars.py +++ b/app/classes/minecraft/serverjars.py @@ -3,24 +3,17 @@ import threading import time import shutil import logging +import requests from datetime import datetime from app.classes.controllers.servers_controller import Servers_Controller -from app.classes.models.server_permissions import server_permissions -from app.classes.shared.helpers import helper -from app.classes.web.websocket_helper import websocket_helper +from app.classes.models.server_permissions import Permissions_Servers logger = logging.getLogger(__name__) -try: - import requests - -except ModuleNotFoundError as err: - helper.auto_installer_fix(err) - - class ServerJars: - def __init__(self): + def __init__(self, helper): + self.helper = helper self.base_url = "https://serverjars.com" def _get_api_result(self, call_url: str): @@ -50,9 +43,8 @@ class ServerJars: return api_response - @staticmethod - def _read_cache(): - cache_file = helper.serverjar_cache + def _read_cache(self): + cache_file = self.helper.serverjar_cache cache = {} try: with open(cache_file, "r", encoding="utf-8") as f: @@ -109,8 +101,8 @@ class ServerJars: def refresh_cache(self): - cache_file = helper.serverjar_cache - cache_old = helper.is_file_older_than_x_days(cache_file) + cache_file = self.helper.serverjar_cache + cache_old = self.helper.is_file_older_than_x_days(cache_file) # debug override # cache_old = True @@ -166,6 +158,7 @@ class ServerJars: def download_jar(self, server, version, path, server_id): update_thread = threading.Thread( + name=f"server_download-{server_id}-{server}-{version}", target=self.a_download_jar, daemon=True, args=(server, version, path, server_id), @@ -176,7 +169,7 @@ class ServerJars: # delaying download for server register to finish time.sleep(3) fetch_url = f"{self.base_url}/api/fetchJar/{server}/{version}" - server_users = server_permissions.get_server_user_list(server_id) + server_users = Permissions_Servers.get_server_user_list(server_id) # We need to make sure the server is registered before # we submit a db update for it's stats. @@ -184,11 +177,11 @@ class ServerJars: try: Servers_Controller.set_download(server_id) for user in server_users: - websocket_helper.broadcast_user(user, "send_start_reload", {}) + self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {}) break - except: - logger.debug("server not registered yet. Delaying download.") + except Exception as ex: + logger.debug(f"server not registered yet. Delaying download - {ex}") # open a file stream with requests.get(fetch_url, timeout=2, stream=True) as r: @@ -198,24 +191,21 @@ class ServerJars: Servers_Controller.finish_download(server_id) for user in server_users: - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user, "notification", "Executable download finished" ) time.sleep(3) - websocket_helper.broadcast_user(user, "send_start_reload", {}) + self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {}) return True except Exception as e: logger.error(f"Unable to save jar to {path} due to error:{e}") Servers_Controller.finish_download(server_id) - server_users = server_permissions.get_server_user_list(server_id) + server_users = Permissions_Servers.get_server_user_list(server_id) for user in server_users: - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user, "notification", "Executable download finished" ) time.sleep(3) - websocket_helper.broadcast_user(user, "send_start_reload", {}) + self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {}) return False - - -server_jar_obj = ServerJars() diff --git a/app/classes/minecraft/stats.py b/app/classes/minecraft/stats.py index b4db5515..c70fec3a 100644 --- a/app/classes/minecraft/stats.py +++ b/app/classes/minecraft/stats.py @@ -6,14 +6,15 @@ import psutil from app.classes.minecraft.mc_ping import ping from app.classes.models.management import Host_Stats -from app.classes.models.servers import servers_helper -from app.classes.shared.helpers import helper +from app.classes.models.servers import helper_servers +from app.classes.shared.helpers import Helpers logger = logging.getLogger(__name__) class Stats: - def __init__(self, controller): + def __init__(self, helper, controller): + self.helper = helper self.controller = controller def get_node_stats(self): @@ -30,8 +31,8 @@ class Stats: "cpu_cur_freq": round(cpu_freq[0], 2), "cpu_max_freq": cpu_freq[2], "mem_percent": psutil.virtual_memory()[2], - "mem_usage": helper.human_readable_file_size(psutil.virtual_memory()[3]), - "mem_total": helper.human_readable_file_size(psutil.virtual_memory()[0]), + "mem_usage": Helpers.human_readable_file_size(psutil.virtual_memory()[3]), + "mem_total": Helpers.human_readable_file_size(psutil.virtual_memory()[0]), "disk_data": self._all_disk_usage(), } # server_stats = self.get_servers_stats() @@ -60,7 +61,7 @@ class Stats: with p.oneshot(): process_stats = { "cpu_usage": real_cpu, - "memory_usage": helper.human_readable_file_size(p.memory_info()[0]), + "memory_usage": Helpers.human_readable_file_size(p.memory_info()[0]), "mem_percentage": round(p.memory_percent(), 0), } return process_stats @@ -84,7 +85,7 @@ class Stats: # print(templ % ("Device", "Total", "Used", "Free", "Use ", "Type","Mount")) for part in psutil.disk_partitions(all=False): - if helper.is_os_windows(): + if Helpers.is_os_windows(): if "cdrom" in part.opts or part.fstype == "": # skip cd-rom drives with no disk in it; they may raise # ENOENT, pop-up a Windows GUI error for a non-ready @@ -94,9 +95,9 @@ class Stats: disk_data.append( { "device": part.device, - "total": helper.human_readable_file_size(usage.total), - "used": helper.human_readable_file_size(usage.used), - "free": helper.human_readable_file_size(usage.free), + "total": Helpers.human_readable_file_size(usage.total), + "used": Helpers.human_readable_file_size(usage.used), + "free": Helpers.human_readable_file_size(usage.free), "percent_used": int(usage.percent), "fs": part.fstype, "mount": part.mountpoint, @@ -110,15 +111,15 @@ class Stats: total_size = 0 - total_size = helper.get_dir_size(server_path) + total_size = Helpers.get_dir_size(server_path) - level_total_size = helper.human_readable_file_size(total_size) + level_total_size = Helpers.human_readable_file_size(total_size) return level_total_size def get_server_players(self, server_id): - server = servers_helper.get_server_data_by_id(server_id) + server = helper_servers.get_server_data_by_id(server_id) logger.info(f"Getting players for server {server}") @@ -131,7 +132,7 @@ class Stats: server_port = server["server_port"] logger.debug("Pinging {internal_ip} on port {server_port}") - if servers_helper.get_server_type_by_id(server_id) != "minecraft-bedrock": + if helper_servers.get_server_type_by_id(server_id) != "minecraft-bedrock": int_mc_ping = ping(internal_ip, int(server_port)) ping_data = {} @@ -232,7 +233,7 @@ class Stats: # ).execute() # delete old data - max_age = helper.get_setting("history_max_age") + max_age = self.helper.get_setting("history_max_age") now = datetime.datetime.now() last_week = now.day - max_age diff --git a/app/classes/models/base_model.py b/app/classes/models/base_model.py new file mode 100644 index 00000000..3353494e --- /dev/null +++ b/app/classes/models/base_model.py @@ -0,0 +1,7 @@ +import peewee + +database_proxy = peewee.DatabaseProxy() + +class BaseModel(peewee.Model): + class Meta: + database = database_proxy diff --git a/app/classes/models/crafty_permissions.py b/app/classes/models/crafty_permissions.py index 665dad87..13e89a6b 100644 --- a/app/classes/models/crafty_permissions.py +++ b/app/classes/models/crafty_permissions.py @@ -1,35 +1,21 @@ import logging - -from app.classes.shared.helpers import helper -from app.classes.shared.permission_helper import permission_helper -from app.classes.models.users import Users, ApiKeys, users_helper - -try: - from peewee import ( - SqliteDatabase, - Model, - ForeignKeyField, - CharField, - IntegerField, - DoesNotExist, - ) - from enum import Enum - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) - -logger = logging.getLogger(__name__) -peewee_logger = logging.getLogger("peewee") -peewee_logger.setLevel(logging.INFO) -database = SqliteDatabase( - helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10} +from enum import Enum +from peewee import ( + ForeignKeyField, + CharField, + IntegerField, + DoesNotExist, ) +from app.classes.models.base_model import BaseModel +from app.classes.models.users import Users, ApiKeys, helper_users + +logger = logging.getLogger(__name__) # ********************************************************************************** # User_Crafty Class # ********************************************************************************** -class User_Crafty(Model): +class User_Crafty(BaseModel): user_id = ForeignKeyField(Users, backref="users_crafty") permissions = CharField(default="00000000") limit_server_creation = IntegerField(default=-1) @@ -41,7 +27,6 @@ class User_Crafty(Model): class Meta: table_name = "user_crafty" - database = database # ********************************************************************************** @@ -68,7 +53,7 @@ class Permissions_Crafty: def get_permissions(permissions_mask): permissions_list = [] for member in Enum_Permissions_Crafty.__members__.items(): - if crafty_permissions.has_permission(permissions_mask, member[1]): + if Permissions_Crafty.has_permission(permissions_mask, member[1]): permissions_list.append(member[1]) return permissions_list @@ -95,7 +80,7 @@ class Permissions_Crafty: @staticmethod def get_crafty_permissions_mask(user_id): permissions_mask = "" - user_crafty = crafty_permissions.get_User_Crafty(user_id) + user_crafty = Permissions_Crafty.get_User_Crafty(user_id) permissions_mask = user_crafty.permissions return permissions_mask @@ -110,7 +95,7 @@ class Permissions_Crafty: @staticmethod def get_permission_quantity_list(user_id): - user_crafty = crafty_permissions.get_User_Crafty(user_id) + user_crafty = Permissions_Crafty.get_User_Crafty(user_id) quantity_list = { Enum_Permissions_Crafty.Server_Creation.name: user_crafty.limit_server_creation, # pylint: disable=line-too-long Enum_Permissions_Crafty.User_Config.name: user_crafty.limit_user_creation, @@ -140,7 +125,7 @@ class Permissions_Crafty: User_Crafty.created_role: 0, } ).execute() - user_crafty = crafty_permissions.get_User_Crafty(user_id) + user_crafty = Permissions_Crafty.get_User_Crafty(user_id) return user_crafty @staticmethod @@ -180,7 +165,7 @@ class Permissions_Crafty: @staticmethod def get_created_quantity_list(user_id): - user_crafty = crafty_permissions.get_User_Crafty(user_id) + user_crafty = Permissions_Crafty.get_User_Crafty(user_id) quantity_list = { Enum_Permissions_Crafty.Server_Creation.name: user_crafty.created_server, Enum_Permissions_Crafty.User_Config.name: user_crafty.created_user, @@ -190,15 +175,15 @@ class Permissions_Crafty: @staticmethod def get_crafty_limit_value(user_id, permission): - quantity_list = crafty_permissions.get_permission_quantity_list(user_id) + quantity_list = Permissions_Crafty.get_permission_quantity_list(user_id) return quantity_list[permission] @staticmethod def can_add_in_crafty(user_id, permission): - user_crafty = crafty_permissions.get_User_Crafty(user_id) - can = crafty_permissions.has_permission(user_crafty.permissions, permission) - limit_list = crafty_permissions.get_permission_quantity_list(user_id) - quantity_list = crafty_permissions.get_created_quantity_list(user_id) + user_crafty = Permissions_Crafty.get_User_Crafty(user_id) + can = Permissions_Crafty.has_permission(user_crafty.permissions, permission) + limit_list = Permissions_Crafty.get_permission_quantity_list(user_id) + quantity_list = Permissions_Crafty.get_created_quantity_list(user_id) return can and ( (quantity_list[permission.name] < limit_list[permission.name]) or limit_list[permission.name] == -1 @@ -206,29 +191,26 @@ class Permissions_Crafty: @staticmethod def add_server_creation(user_id): - user_crafty = crafty_permissions.get_User_Crafty(user_id) + user_crafty = Permissions_Crafty.get_User_Crafty(user_id) user_crafty.created_server += 1 User_Crafty.save(user_crafty) return user_crafty.created_server @staticmethod def get_api_key_permissions_list(key: ApiKeys): - user = users_helper.get_user(key.user_id) + user = helper_users.get_user(key.user_id) if user["superuser"] and key.superuser: - return crafty_permissions.get_permissions_list() + return Permissions_Crafty.get_permissions_list() else: if user["superuser"]: user_permissions_mask = "111" else: - user_permissions_mask = crafty_permissions.get_crafty_permissions_mask( + user_permissions_mask = Permissions_Crafty.get_crafty_permissions_mask( user["user_id"] ) key_permissions_mask: str = key.crafty_permissions - permissions_mask = permission_helper.combine_masks( + permissions_mask = helper_users.combine_masks( user_permissions_mask, key_permissions_mask ) - permissions_list = crafty_permissions.get_permissions(permissions_mask) + permissions_list = Permissions_Crafty.get_permissions(permissions_mask) return permissions_list - - -crafty_permissions = Permissions_Crafty() diff --git a/app/classes/models/management.py b/app/classes/models/management.py index 0d33e547..27a4e8c5 100644 --- a/app/classes/models/management.py +++ b/app/classes/models/management.py @@ -1,42 +1,29 @@ import logging import datetime +from peewee import ( + ForeignKeyField, + CharField, + IntegerField, + DateTimeField, + FloatField, + TextField, + AutoField, + BooleanField, +) +from playhouse.shortcuts import model_to_dict -from app.classes.models.users import Users, users_helper +from app.classes.models.base_model import BaseModel +from app.classes.models.users import Users, helper_users from app.classes.models.servers import Servers -from app.classes.models.server_permissions import server_permissions -from app.classes.shared.helpers import helper -from app.classes.shared.main_models import db_helper -from app.classes.web.websocket_helper import websocket_helper - -try: - from peewee import ( - SqliteDatabase, - Model, - ForeignKeyField, - CharField, - IntegerField, - DateTimeField, - FloatField, - TextField, - AutoField, - BooleanField, - ) - from playhouse.shortcuts import model_to_dict - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) +from app.classes.models.server_permissions import Permissions_Servers +from app.classes.shared.main_models import db_shortcuts logger = logging.getLogger(__name__) -peewee_logger = logging.getLogger("peewee") -peewee_logger.setLevel(logging.INFO) -database = SqliteDatabase( - helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10} -) # ********************************************************************************** # Audit_Log Class # ********************************************************************************** -class Audit_Log(Model): +class Audit_Log(BaseModel): audit_id = AutoField() created = DateTimeField(default=datetime.datetime.now) user_name = CharField(default="") @@ -47,14 +34,11 @@ class Audit_Log(Model): ) # When auditing global events, use server ID 0 log_msg = TextField(default="") - class Meta: - database = database - # ********************************************************************************** # Host_Stats Class # ********************************************************************************** -class Host_Stats(Model): +class Host_Stats(BaseModel): time = DateTimeField(default=datetime.datetime.now, index=True) boot_time = CharField(default="") cpu_usage = FloatField(default=0) @@ -68,13 +52,12 @@ class Host_Stats(Model): class Meta: table_name = "host_stats" - database = database # ********************************************************************************** # Commands Class # ********************************************************************************** -class Commands(Model): +class Commands(BaseModel): command_id = AutoField() created = DateTimeField(default=datetime.datetime.now) server_id = ForeignKeyField(Servers, backref="server", index=True) @@ -85,13 +68,12 @@ class Commands(Model): class Meta: table_name = "commands" - database = database # ********************************************************************************** # Webhooks Class # ********************************************************************************** -class Webhooks(Model): +class Webhooks(BaseModel): id = AutoField() name = CharField(max_length=64, unique=True, index=True) method = CharField(default="POST") @@ -101,13 +83,12 @@ class Webhooks(Model): class Meta: table_name = "webhooks" - database = database # ********************************************************************************** # Schedules Class # ********************************************************************************** -class Schedules(Model): +class Schedules(BaseModel): schedule_id = IntegerField(unique=True, primary_key=True) server_id = ForeignKeyField(Servers, backref="schedule_server") enabled = BooleanField() @@ -124,13 +105,12 @@ class Schedules(Model): class Meta: table_name = "schedules" - database = database # ********************************************************************************** # Backups Class # ********************************************************************************** -class Backups(Model): +class Backups(BaseModel): excluded_dirs = CharField(null=True) max_backups = IntegerField() server_id = ForeignKeyField(Servers, backref="backups_server") @@ -138,10 +118,12 @@ class Backups(Model): class Meta: table_name = "backups" - database = database class helpers_management: + def __init__(self, database, helper): + self.database = database + self.helper = helper # ********************************************************************************** # Host_Stats Methods @@ -185,18 +167,17 @@ class helpers_management: @staticmethod def get_actity_log(): q = Audit_Log.select() - return db_helper.return_db_rows(q) + return db_shortcuts.return_db_rows(q) - @staticmethod - def add_to_audit_log(user_id, log_msg, server_id=None, source_ip=None): + def add_to_audit_log(self, user_id, log_msg, server_id=None, source_ip=None): logger.debug(f"Adding to audit log User:{user_id} - Message: {log_msg} ") - user_data = users_helper.get_user(user_id) + user_data = helper_users.get_user(user_id) audit_msg = f"{str(user_data['username']).capitalize()} {log_msg}" - server_users = server_permissions.get_server_user_list(server_id) + server_users = Permissions_Servers.get_server_user_list(server_id) for user in server_users: - websocket_helper.broadcast_user(user, "notification", audit_msg) + self.helper.websocket_helper.broadcast_user(user, "notification", audit_msg) Audit_Log.insert( { @@ -210,17 +191,16 @@ class helpers_management: # deletes records when they're more than 100 ordered = Audit_Log.select().order_by(+Audit_Log.created) for item in ordered: - if not helper.get_setting("max_audit_entries"): + if not self.helper.get_setting("max_audit_entries"): max_entries = 300 else: - max_entries = helper.get_setting("max_audit_entries") + max_entries = self.helper.get_setting("max_audit_entries") if Audit_Log.select().count() > max_entries: Audit_Log.delete().where(Audit_Log.audit_id == item.audit_id).execute() else: return - @staticmethod - def add_to_audit_log_raw(user_name, user_id, server_id, log_msg, source_ip): + def add_to_audit_log_raw(self, user_name, user_id, server_id, log_msg, source_ip): Audit_Log.insert( { Audit_Log.user_name: user_name, @@ -234,10 +214,10 @@ class helpers_management: ordered = Audit_Log.select().order_by(+Audit_Log.created) for item in ordered: # configurable through app/config/config.json - if not helper.get_setting("max_audit_entries"): + if not self.helper.get_setting("max_audit_entries"): max_entries = 300 else: - max_entries = helper.get_setting("max_audit_entries") + max_entries = self.helper.get_setting("max_audit_entries") if Audit_Log.select().count() > max_entries: Audit_Log.delete().where(Audit_Log.audit_id == item.audit_id).execute() else: @@ -354,8 +334,8 @@ class helpers_management: } return conf - @staticmethod def set_backup_config( + self, server_id: int, backup_path: str = None, max_backups: int = None, @@ -381,7 +361,7 @@ class helpers_management: conf["excluded_dirs"] = dirs_to_exclude conf["compress"] = compress if not new_row: - with database.atomic(): + with self.database.atomic(): if backup_path is not None: u1 = ( Servers.update(backup_path=backup_path) @@ -395,7 +375,7 @@ class helpers_management: ) logger.debug(f"Updating existing backup record. {u1}+{u2} rows affected") else: - with database.atomic(): + with self.database.atomic(): conf["server_id"] = server_id if backup_path is not None: Servers.update(backup_path=backup_path).where( @@ -404,8 +384,9 @@ class helpers_management: Backups.create(**conf) logger.debug("Creating new backup record.") - def get_excluded_backup_dirs(self, server_id: int): - excluded_dirs = self.get_backup_config(server_id)["excluded_dirs"] + @staticmethod + def get_excluded_backup_dirs(server_id: int): + excluded_dirs = helpers_management.get_backup_config(server_id)["excluded_dirs"] if excluded_dirs is not None and excluded_dirs != "": dir_list = excluded_dirs.split(",") else: @@ -441,6 +422,3 @@ class helpers_management: Commands.update({Commands.executed: True}).where( Commands.executed == False # pylint: disable=singleton-comparison ).execute() - - -management_helper = helpers_management() diff --git a/app/classes/models/roles.py b/app/classes/models/roles.py index ff705e96..261f2479 100644 --- a/app/classes/models/roles.py +++ b/app/classes/models/roles.py @@ -1,33 +1,22 @@ import logging import datetime +from peewee import ( + CharField, + DoesNotExist, + AutoField, + DateTimeField, +) +from playhouse.shortcuts import model_to_dict -from app.classes.shared.helpers import helper - -try: - from peewee import ( - SqliteDatabase, - Model, - CharField, - DoesNotExist, - AutoField, - DateTimeField, - ) - from playhouse.shortcuts import model_to_dict - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) +from app.classes.models.base_model import BaseModel +from app.classes.shared.helpers import Helpers logger = logging.getLogger(__name__) -peewee_logger = logging.getLogger("peewee") -peewee_logger.setLevel(logging.INFO) -database = SqliteDatabase( - helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10} -) # ********************************************************************************** # Roles Class # ********************************************************************************** -class Roles(Model): +class Roles(BaseModel): role_id = AutoField() created = DateTimeField(default=datetime.datetime.now) last_update = DateTimeField(default=datetime.datetime.now) @@ -35,13 +24,15 @@ class Roles(Model): class Meta: table_name = "roles" - database = database # ********************************************************************************** # Roles Helpers # ********************************************************************************** class helper_roles: + def __init__(self, database): + self.database = database + @staticmethod def get_all_roles(): query = Roles.select() @@ -63,7 +54,7 @@ class helper_roles: role_id = Roles.insert( { Roles.role_name: role_name.lower(), - Roles.created: helper.get_time_as_string(), + Roles.created: Helpers.get_time_as_string(), } ).execute() return role_id @@ -72,17 +63,13 @@ class helper_roles: def update_role(role_id, up_data): return Roles.update(up_data).where(Roles.role_id == role_id).execute() - @staticmethod - def remove_role(role_id): - with database.atomic(): + def remove_role(self, role_id): + with self.database.atomic(): role = Roles.get(Roles.role_id == role_id) return role.delete_instance() @staticmethod def role_id_exists(role_id): - if not roles_helper.get_role(role_id): + if not helper_roles.get_role(role_id): return False return True - - -roles_helper = helper_roles() diff --git a/app/classes/models/server_permissions.py b/app/classes/models/server_permissions.py index 12f42b2f..f96eb716 100644 --- a/app/classes/models/server_permissions.py +++ b/app/classes/models/server_permissions.py @@ -1,36 +1,24 @@ +from enum import Enum import logging +from peewee import ( + ForeignKeyField, + CharField, + CompositeKey, + JOIN, +) +from app.classes.models.base_model import BaseModel from app.classes.models.servers import Servers from app.classes.models.roles import Roles -from app.classes.models.users import User_Roles, users_helper, ApiKeys, Users -from app.classes.shared.helpers import helper -from app.classes.shared.permission_helper import permission_helper - -try: - from peewee import ( - SqliteDatabase, - Model, - ForeignKeyField, - CharField, - CompositeKey, - JOIN, - ) - from enum import Enum - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) +from app.classes.models.users import User_Roles, helper_users, ApiKeys, Users +from app.classes.shared.permission_helper import PermissionHelper logger = logging.getLogger(__name__) -peewee_logger = logging.getLogger("peewee") -peewee_logger.setLevel(logging.INFO) -database = SqliteDatabase( - helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10} -) # ********************************************************************************** # Role Servers Class # ********************************************************************************** -class Role_Servers(Model): +class Role_Servers(BaseModel): role_id = ForeignKeyField(Roles, backref="role_server") server_id = ForeignKeyField(Servers, backref="role_server") permissions = CharField(default="00000000") @@ -38,7 +26,6 @@ class Role_Servers(Model): class Meta: table_name = "role_servers" primary_key = CompositeKey("role_id", "server_id") - database = database # ********************************************************************************** @@ -73,7 +60,7 @@ class Permissions_Servers: def get_permissions(permissions_mask): permissions_list = [] for member in Enum_Permissions_Server.__members__.items(): - if server_permissions.has_permission(permissions_mask, member[1]): + if Permissions_Servers.has_permission(permissions_mask, member[1]): permissions_list.append(member[1]) return permissions_list @@ -98,7 +85,7 @@ class Permissions_Servers: def get_token_permissions(permissions_mask, api_permissions_mask): permissions_list = [] for member in Enum_Permissions_Server.__members__.items(): - if permission_helper.both_have_perm( + if PermissionHelper.both_have_perm( permissions_mask, api_permissions_mask, member[1] ): permissions_list.append(member[1]) @@ -166,7 +153,7 @@ class Permissions_Servers: role_server = Role_Servers.get_or_none(Role_Servers.role_id == role_id) if role_server is not None: permissions_mask = role_server.permissions - permissions_list = server_permissions.get_permissions(permissions_mask) + permissions_list = Permissions_Servers.get_permissions(permissions_mask) return permissions_list @staticmethod @@ -193,24 +180,23 @@ class Permissions_Servers: @staticmethod def remove_roles_of_server(server_id): - with database.atomic(): - return ( - Role_Servers.delete() - .where(Role_Servers.server_id == server_id) - .execute() - ) + return ( + Role_Servers.delete() + .where(Role_Servers.server_id == server_id) + .execute() + ) @staticmethod def get_user_id_permissions_mask(user_id, server_id: str): - user = users_helper.get_user_model(user_id) - return server_permissions.get_user_permissions_mask(user, server_id) + user = helper_users.get_user_model(user_id) + return Permissions_Servers.get_user_permissions_mask(user, server_id) @staticmethod def get_user_permissions_mask(user: Users, server_id: str): if user.superuser: - permissions_mask = "1" * len(server_permissions.get_permissions_list()) + permissions_mask = "1" * len(Permissions_Servers.get_permissions_list()) else: - roles_list = users_helper.get_user_roles_id(user.user_id) + roles_list = helper_users.get_user_roles_id(user.user_id) role_server = ( Role_Servers.select() .where(Role_Servers.role_id.in_(roles_list)) @@ -220,7 +206,7 @@ class Permissions_Servers: try: permissions_mask = role_server[0].permissions except IndexError: - permissions_mask = "0" * len(server_permissions.get_permissions_list()) + permissions_mask = "0" * len(Permissions_Servers.get_permissions_list()) return permissions_mask @staticmethod @@ -242,32 +228,32 @@ class Permissions_Servers: @staticmethod def get_user_id_permissions_list(user_id, server_id: str): - user = users_helper.get_user_model(user_id) - return server_permissions.get_user_permissions_list(user, server_id) + user = helper_users.get_user_model(user_id) + return Permissions_Servers.get_user_permissions_list(user, server_id) @staticmethod def get_user_permissions_list(user: Users, server_id: str): if user.superuser: - permissions_list = server_permissions.get_permissions_list() + permissions_list = Permissions_Servers.get_permissions_list() else: - permissions_mask = server_permissions.get_user_permissions_mask( + permissions_mask = Permissions_Servers.get_user_permissions_mask( user, server_id ) - permissions_list = server_permissions.get_permissions(permissions_mask) + permissions_list = Permissions_Servers.get_permissions(permissions_mask) return permissions_list @staticmethod def get_api_key_id_permissions_list(key_id, server_id: str): key = ApiKeys.get(ApiKeys.token_id == key_id) - return server_permissions.get_api_key_permissions_list(key, server_id) + return Permissions_Servers.get_api_key_permissions_list(key, server_id) @staticmethod def get_api_key_permissions_list(key: ApiKeys, server_id: str): - user = users_helper.get_user(key.user_id) + user = helper_users.get_user(key.user_id) if user["superuser"] and key.superuser: - return server_permissions.get_permissions_list() + return Permissions_Servers.get_permissions_list() else: - roles_list = users_helper.get_user_roles_id(user["user_id"]) + roles_list = helper_users.get_user_roles_id(user["user_id"]) role_server = ( Role_Servers.select() .where(Role_Servers.role_id.in_(roles_list)) @@ -275,12 +261,9 @@ class Permissions_Servers: .execute() ) user_permissions_mask = role_server[0].permissions - key_permissions_mask = key.server_permissions - permissions_mask = permission_helper.combine_masks( + key_permissions_mask = key.Permissions_Servers + permissions_mask = PermissionHelper.combine_masks( user_permissions_mask, key_permissions_mask ) - permissions_list = server_permissions.get_permissions(permissions_mask) + permissions_list = Permissions_Servers.get_permissions(permissions_mask) return permissions_list - - -server_permissions = Permissions_Servers() diff --git a/app/classes/models/servers.py b/app/classes/models/servers.py index f00704fe..c93ff490 100644 --- a/app/classes/models/servers.py +++ b/app/classes/models/servers.py @@ -1,36 +1,24 @@ import logging import datetime +from peewee import ( + ForeignKeyField, + CharField, + AutoField, + DateTimeField, + BooleanField, + IntegerField, + FloatField, +) -from app.classes.shared.helpers import helper -from app.classes.shared.main_models import db_helper - -try: - from peewee import ( - SqliteDatabase, - Model, - ForeignKeyField, - CharField, - AutoField, - DateTimeField, - BooleanField, - IntegerField, - FloatField, - ) - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) +from app.classes.shared.main_models import db_shortcuts +from app.classes.models.base_model import BaseModel logger = logging.getLogger(__name__) -peewee_logger = logging.getLogger("peewee") -peewee_logger.setLevel(logging.INFO) -database = SqliteDatabase( - helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10} -) # ********************************************************************************** # Servers Class # ********************************************************************************** -class Servers(Model): +class Servers(BaseModel): server_id = AutoField() created = DateTimeField(default=datetime.datetime.now) server_uuid = CharField(default="", index=True) @@ -52,13 +40,12 @@ class Servers(Model): class Meta: table_name = "servers" - database = database # ********************************************************************************** # Servers Stats Class # ********************************************************************************** -class Server_Stats(Model): +class Server_Stats(BaseModel): stats_id = AutoField() created = DateTimeField(default=datetime.datetime.now) server_id = ForeignKeyField(Servers, backref="server", index=True) @@ -84,13 +71,14 @@ class Server_Stats(Model): class Meta: table_name = "server_stats" - database = database # ********************************************************************************** # Servers Class # ********************************************************************************** class helper_servers: + def __init__(self, database): + self.database = database # ********************************************************************************** # Generic Servers Methods @@ -139,16 +127,15 @@ class helper_servers: def update_server(server_obj): return server_obj.save() - @staticmethod - def remove_server(server_id): - with database.atomic(): + def remove_server(self, server_id): + with self.database.atomic(): Servers.delete().where(Servers.server_id == server_id).execute() @staticmethod def get_server_data_by_id(server_id): query = Servers.select().where(Servers.server_id == server_id).limit(1) try: - return db_helper.return_rows(query)[0] + return db_shortcuts.return_rows(query)[0] except IndexError: return {} @@ -158,11 +145,11 @@ class helper_servers: @staticmethod def get_all_defined_servers(): query = Servers.select() - return db_helper.return_rows(query) + return db_shortcuts.return_rows(query) @staticmethod def get_all_servers_stats(): - servers = servers_helper.get_all_defined_servers() + servers = helper_servers.get_all_defined_servers() server_data = [] try: for s in servers: @@ -175,7 +162,7 @@ class helper_servers: server_data.append( { "server_data": s, - "stats": db_helper.return_rows(latest)[0], + "stats": db_shortcuts.return_rows(latest)[0], "user_command_permission": True, } ) @@ -187,7 +174,7 @@ class helper_servers: @staticmethod def get_server_friendly_name(server_id): - server_data = servers_helper.get_server_data_by_id(server_id) + server_data = helper_servers.get_server_data_by_id(server_id) friendly_name = ( f"{server_data.get('server_name', None)} " f"with ID: {server_data.get('server_id', 0)}" @@ -214,34 +201,31 @@ class helper_servers: .order_by(Server_Stats.created.desc()) .limit(1) ) - return db_helper.return_rows(stats)[0] + return db_shortcuts.return_rows(stats)[0] @staticmethod def server_id_exists(server_id): - if not servers_helper.get_server_data_by_id(server_id): + if not helper_servers.get_server_data_by_id(server_id): return False return True @staticmethod def sever_crashed(server_id): - with database.atomic(): - Server_Stats.update(crashed=True).where( - Server_Stats.server_id == server_id - ).execute() + Server_Stats.update(crashed=True).where( + Server_Stats.server_id == server_id + ).execute() @staticmethod def set_download(server_id): - with database.atomic(): - Server_Stats.update(downloading=True).where( - Server_Stats.server_id == server_id - ).execute() + Server_Stats.update(downloading=True).where( + Server_Stats.server_id == server_id + ).execute() @staticmethod def finish_download(server_id): - with database.atomic(): - Server_Stats.update(downloading=False).where( - Server_Stats.server_id == server_id - ).execute() + Server_Stats.update(downloading=False).where( + Server_Stats.server_id == server_id + ).execute() @staticmethod def get_download_status(server_id): @@ -252,10 +236,9 @@ class helper_servers: @staticmethod def server_crash_reset(server_id): - with database.atomic(): - Server_Stats.update(crashed=False).where( - Server_Stats.server_id == server_id - ).execute() + Server_Stats.update(crashed=False).where( + Server_Stats.server_id == server_id + ).execute() @staticmethod def is_crashed(server_id): @@ -272,10 +255,9 @@ class helper_servers: Server_Stats.select().where(Server_Stats.server_id == server_id) except Exception as ex: logger.error(f"Database entry not found! {ex}") - with database.atomic(): - Server_Stats.update(updating=value).where( - Server_Stats.server_id == server_id - ).execute() + Server_Stats.update(updating=value).where( + Server_Stats.server_id == server_id + ).execute() @staticmethod def get_update_status(server_id): @@ -293,10 +275,9 @@ class helper_servers: except Exception as ex: logger.error(f"Database entry not found! {ex}") return - with database.atomic(): - Server_Stats.update(first_run=False).where( - Server_Stats.server_id == server_id - ).execute() + Server_Stats.update(first_run=False).where( + Server_Stats.server_id == server_id + ).execute() @staticmethod def get_first_run(server_id): @@ -325,7 +306,7 @@ class helper_servers: @staticmethod def can_stop_no_players(server_id, time_limit): can = False - ttl_no_players = servers_helper.get_TTL_without_player(server_id) + ttl_no_players = helper_servers.get_TTL_without_player(server_id) if (time_limit == -1) or (ttl_no_players > time_limit): can = True return can @@ -337,10 +318,9 @@ class helper_servers: Server_Stats.select().where(Server_Stats.server_id == server_id) except Exception as ex: logger.error(f"Database entry not found! {ex}") - with database.atomic(): - Server_Stats.update(waiting_start=value).where( - Server_Stats.server_id == server_id - ).execute() + Server_Stats.update(waiting_start=value).where( + Server_Stats.server_id == server_id + ).execute() @staticmethod def get_waiting_start(server_id): @@ -348,6 +328,3 @@ class helper_servers: Server_Stats.select().where(Server_Stats.server_id == server_id).get() ) return waiting_start.waiting_start - - -servers_helper = helper_servers() diff --git a/app/classes/models/users.py b/app/classes/models/users.py index f9e9f311..ee44114d 100644 --- a/app/classes/models/users.py +++ b/app/classes/models/users.py @@ -2,38 +2,28 @@ import logging import datetime from typing import Optional, Union -from app.classes.models.roles import Roles, roles_helper -from app.classes.shared.helpers import helper +from peewee import ( + ForeignKeyField, + CharField, + AutoField, + DateTimeField, + BooleanField, + CompositeKey, + DoesNotExist, + JOIN, +) +from playhouse.shortcuts import model_to_dict -try: - from peewee import ( - SqliteDatabase, - Model, - ForeignKeyField, - CharField, - AutoField, - DateTimeField, - BooleanField, - CompositeKey, - DoesNotExist, - JOIN, - ) - from playhouse.shortcuts import model_to_dict - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) +from app.classes.shared.helpers import Helpers +from app.classes.models.base_model import BaseModel +from app.classes.models.roles import Roles, helper_roles logger = logging.getLogger(__name__) -peewee_logger = logging.getLogger("peewee") -peewee_logger.setLevel(logging.INFO) -database = SqliteDatabase( - helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10} -) # ********************************************************************************** # Users Class # ********************************************************************************** -class Users(Model): +class Users(BaseModel): user_id = AutoField() created = DateTimeField(default=datetime.datetime.now) last_login = DateTimeField(default=datetime.datetime.now) @@ -53,13 +43,12 @@ class Users(Model): class Meta: table_name = "users" - database = database # ********************************************************************************** # API Keys Class # ********************************************************************************** -class ApiKeys(Model): +class ApiKeys(BaseModel): token_id = AutoField() name = CharField(default="", unique=True, index=True) created = DateTimeField(default=datetime.datetime.now) @@ -70,26 +59,28 @@ class ApiKeys(Model): class Meta: table_name = "api_keys" - database = database # ********************************************************************************** # User Roles Class # ********************************************************************************** -class User_Roles(Model): +class User_Roles(BaseModel): user_id = ForeignKeyField(Users, backref="user_role") role_id = ForeignKeyField(Roles, backref="user_role") class Meta: table_name = "user_roles" primary_key = CompositeKey("user_id", "role_id") - database = database # ********************************************************************************** # Users Helpers # ********************************************************************************** class helper_users: + def __init__(self, database, helper): + self.database = database + self.helper = helper + @staticmethod def get_by_id(user_id): return Users.get_by_id(user_id) @@ -137,7 +128,7 @@ class helper_users: if user: # I know it should apply it without setting it but I'm just making sure - user = users_helper.add_user_roles(user) + user = helper_users.add_user_roles(user) return user else: # logger.debug("user: ({}) {}".format(user_id, {})) @@ -155,11 +146,11 @@ class helper_users: @staticmethod def get_user_model(user_id: str) -> Users: user = Users.get(Users.user_id == user_id) - user = users_helper.add_user_roles(user) + user = helper_users.add_user_roles(user) return user - @staticmethod def add_user( + self, username: str, password: str = None, email: Optional[str] = None, @@ -167,7 +158,7 @@ class helper_users: superuser: bool = False, ) -> str: if password is not None: - pw_enc = helper.encode_pass(password) + pw_enc = self.helper.encode_pass(password) else: pw_enc = None user_id = Users.insert( @@ -177,7 +168,7 @@ class helper_users: Users.email: email, Users.enabled: enabled, Users.superuser: superuser, - Users.created: helper.get_time_as_string(), + Users.created: Helpers.get_time_as_string(), } ).execute() return user_id @@ -197,7 +188,7 @@ class helper_users: Users.email: email, Users.enabled: enabled, Users.superuser: superuser, - Users.created: helper.get_time_as_string(), + Users.created: Helpers.get_time_as_string(), } ).execute() return user_id @@ -230,9 +221,8 @@ class helper_users: final_users.append(suser.user_id) return final_users - @staticmethod - def remove_user(user_id): - with database.atomic(): + def remove_user(self, user_id): + with self.database.atomic(): User_Roles.delete().where(User_Roles.user_id == user_id).execute() user = Users.get(Users.user_id == user_id) return user.delete_instance() @@ -259,7 +249,7 @@ class helper_users: @staticmethod def user_id_exists(user_id): - if not users_helper.get_user(user_id): + if not helper_users.get_user(user_id): return False return True @@ -276,7 +266,7 @@ class helper_users: roles_list = [] roles = User_Roles.select().where(User_Roles.user_id == user_id) for r in roles: - roles_list.append(roles_helper.get_role(r.role_id)["role_id"]) + roles_list.append(helper_roles.get_role(r.role_id)["role_id"]) return roles_list @staticmethod @@ -284,7 +274,7 @@ class helper_users: roles_list = [] roles = User_Roles.select().where(User_Roles.user_id == user_id) for r in roles: - roles_list.append(roles_helper.get_role(r.role_id)["role_name"]) + roles_list.append(helper_roles.get_role(r.role_id)["role_name"]) return roles_list @staticmethod @@ -384,6 +374,3 @@ class helper_users: @staticmethod def delete_user_api_key(key_id: str): ApiKeys.delete().where(ApiKeys.token_id == key_id).execute() - - -users_helper = helper_users() diff --git a/app/classes/shared/authentication.py b/app/classes/shared/authentication.py index 5a3d334a..bab36c28 100644 --- a/app/classes/shared/authentication.py +++ b/app/classes/shared/authentication.py @@ -1,58 +1,50 @@ import logging import time from typing import Optional, Dict, Any, Tuple +import jwt +from jwt import PyJWTError -from app.classes.models.users import users_helper, ApiKeys -from app.classes.shared.helpers import helper - -try: - import jwt - from jwt import PyJWTError - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) +from app.classes.models.users import helper_users, ApiKeys logger = logging.getLogger(__name__) class Authentication: - def __init__(self): + def __init__(self, helper): + self.helper = helper self.secret = "my secret" - self.secret = helper.get_setting("apikey_secret", None) + self.secret = self.helper.get_setting("apikey_secret", None) if self.secret is None or self.secret == "random": - self.secret = helper.random_string_generator(64) - helper.set_setting("apikey_secret", self.secret) + self.secret = self.helper.random_string_generator(64) + self.helper.set_setting("apikey_secret", self.secret) - @staticmethod - def generate(user_id, extra=None): + def generate(self, user_id, extra=None): if extra is None: extra = {} jwt_encoded = jwt.encode( {"user_id": user_id, "iat": int(time.time()), **extra}, - authentication.secret, + self.secret, algorithm="HS256", ) return jwt_encoded - @staticmethod - def read(token): - return jwt.decode(token, authentication.secret, algorithms=["HS256"]) + def read(self, token): + return jwt.decode(token, self.secret, algorithms=["HS256"]) - @staticmethod - def check_no_iat(token) -> Optional[Dict[str, Any]]: + def check_no_iat(self, token) -> Optional[Dict[str, Any]]: try: - return jwt.decode(token, authentication.secret, algorithms=["HS256"]) + return jwt.decode(token, self.secret, algorithms=["HS256"]) except PyJWTError as error: logger.debug("Error while checking JWT token: ", exc_info=error) return None - @staticmethod def check( + self, token, ) -> Optional[Tuple[Optional[ApiKeys], Dict[str, Any], Dict[str, Any]]]: try: - data = jwt.decode(token, authentication.secret, algorithms=["HS256"]) + data = jwt.decode(token, self.secret, algorithms=["HS256"]) except PyJWTError as error: logger.debug("Error while checking JWT token: ", exc_info=error) return None @@ -60,11 +52,11 @@ class Authentication: key: Optional[ApiKeys] = None if "token_id" in data: key_id = data["token_id"] - key = users_helper.get_user_api_key(key_id) + key = helper_users.get_user_api_key(key_id) if key is None: return None user_id: str = data["user_id"] - user = users_helper.get_user(user_id) + user = helper_users.get_user(user_id) # TODO: Have a cache or something so we don't constantly # have to query the database if int(user.get("valid_tokens_from").timestamp()) < iat: @@ -73,9 +65,5 @@ class Authentication: else: return None - @staticmethod - def check_bool(token) -> bool: - return authentication.check(token) is not None - - -authentication = Authentication() + def check_bool(self, token) -> bool: + return self.check(token) is not None diff --git a/app/classes/shared/command.py b/app/classes/shared/command.py index 79243fc8..3a574ea5 100644 --- a/app/classes/shared/command.py +++ b/app/classes/shared/command.py @@ -4,22 +4,20 @@ import time import threading import logging -from app.classes.shared.console import console -from app.classes.shared.helpers import helper from app.classes.shared.import3 import import3 -from app.classes.web.websocket_helper import websocket_helper logger = logging.getLogger(__name__) class MainPrompt(cmd.Cmd): - def __init__(self, tasks_manager, migration_manager): + def __init__(self, helper, tasks_manager, migration_manager): super().__init__() + self.helper = helper + self.console = self.helper.console self.tasks_manager = tasks_manager self.migration_manager = migration_manager - - # overrides the default Prompt - prompt = f"Crafty Controller v{helper.get_version_string()} > " + # overrides the default Prompt + self.prompt = f"Crafty Controller v{self.helper.get_version_string()} > " # see MR !233 for pylint exemptino reason @staticmethod @@ -36,20 +34,20 @@ class MainPrompt(cmd.Cmd): elif line == "down": self.migration_manager.down() elif line == "done": - console.info(self.migration_manager.done) + self.console.info(self.migration_manager.done) elif line == "todo": - console.info(self.migration_manager.todo) + self.console.info(self.migration_manager.todo) elif line == "diff": - console.info(self.migration_manager.diff) + self.console.info(self.migration_manager.diff) elif line == "info": - console.info(f"Done: {self.migration_manager.done}") - console.info(f"FS: {self.migration_manager.todo}") - console.info(f"Todo: {self.migration_manager.diff}") + self.console.info(f"Done: {self.migration_manager.done}") + self.console.info(f"FS: {self.migration_manager.todo}") + self.console.info(f"Todo: {self.migration_manager.diff}") elif line.startswith("add "): migration_name = line[len("add ") :] self.migration_manager.create(migration_name, False) else: - console.info("Unknown migration command") + self.console.info("Unknown migration command") @staticmethod def do_threads(_line): @@ -67,24 +65,21 @@ class MainPrompt(cmd.Cmd): def universal_exit(self): logger.info("Stopping all server daemons / threads") - console.info( + self.console.info( "Stopping all server daemons / threads - This may take a few seconds" ) - websocket_helper.disconnect_all() - console.info("Waiting for main thread to stop") + self.helper.websocket_helper.disconnect_all() + self.console.info("Waiting for main thread to stop") while True: if self.tasks_manager.get_main_thread_run_status(): sys.exit(0) time.sleep(1) - @staticmethod - def help_exit(): - console.help("Stops the server if running, Exits the program") + def help_exit(self): + self.console.help("Stops the server if running, Exits the program") - @staticmethod - def help_migrations(): - console.help("Only for advanced users. Use with caution") + def help_migrations(self): + self.console.help("Only for advanced users. Use with caution") - @staticmethod - def help_import3(): - console.help("Import users and servers from Crafty 3") + def help_import3(self): + self.console.help("Import users and servers from Crafty 3") diff --git a/app/classes/shared/console.py b/app/classes/shared/console.py index bcaf17a6..f2c21967 100644 --- a/app/classes/shared/console.py +++ b/app/classes/shared/console.py @@ -69,6 +69,3 @@ class Console: def help(self, message): dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p") self.green(f"[+] Crafty: {dt} - HELP:\t{message}") - - -console = Console() diff --git a/app/classes/shared/file_helpers.py b/app/classes/shared/file_helpers.py index bc21da51..970e0f88 100644 --- a/app/classes/shared/file_helpers.py +++ b/app/classes/shared/file_helpers.py @@ -10,12 +10,13 @@ logger = logging.getLogger(__name__) class FileHelpers: allowed_quotes = ['"', "'", "`"] - def del_dirs(self, path): + @staticmethod + def del_dirs(path): path = pathlib.Path(path) for sub in path.iterdir(): if sub.is_dir(): # Delete folder if it is a folder - self.del_dirs(sub) + FileHelpers.del_dirs(sub) else: # Delete file if it is a file: sub.unlink() @@ -45,13 +46,15 @@ class FileHelpers: def copy_file(src_path, dest_path): shutil.copy(src_path, dest_path) - def move_dir(self, src_path, dest_path): - self.copy_dir(src_path, dest_path) - self.del_dirs(src_path) + @staticmethod + def move_dir(src_path, dest_path): + FileHelpers.copy_dir(src_path, dest_path) + FileHelpers.del_dirs(src_path) - def move_file(self, src_path, dest_path): - self.copy_file(src_path, dest_path) - self.del_file(src_path) + @staticmethod + def move_file(src_path, dest_path): + FileHelpers.copy_file(src_path, dest_path) + FileHelpers.del_file(src_path) @staticmethod def make_archive(path_to_destination, path_to_zip): @@ -109,7 +112,4 @@ class FileHelpers: f" - Error was: {e}" ) - return True - - -file_helper = FileHelpers() + return True \ No newline at end of file diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index 58f3f1fe..59ef52d7 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -19,10 +19,10 @@ from socket import gethostname from contextlib import suppress import psutil -from app.classes.shared.console import console from app.classes.shared.installer import installer -from app.classes.shared.file_helpers import file_helper -from app.classes.web.websocket_helper import websocket_helper +from app.classes.shared.file_helpers import FileHelpers +from app.classes.shared.translation import Translation +from app.classes.web.websocket_helper import WebSocketHelper logger = logging.getLogger(__name__) @@ -41,7 +41,8 @@ except ModuleNotFoundError as err: class Helpers: allowed_quotes = ['"', "'", "`"] - def __init__(self): + def __init__(self, console): + self.console = console self.root_dir = os.path.abspath(os.path.curdir) self.config_dir = os.path.join(self.root_dir, "app", "config") self.webroot = os.path.join(self.root_dir, "app", "frontend") @@ -61,17 +62,22 @@ class Helpers: self.passhasher = PasswordHasher() self.exiting = False + self.websocket_helper = WebSocketHelper(self) + self.translation = Translation(self) + @staticmethod def auto_installer_fix(ex): logger.critical(f"Import Error: Unable to load {ex.name} module", exc_info=True) print(f"Import Error: Unable to load {ex.name} module") installer.do_install() - def float_to_string(self, gbs: int): + @staticmethod + def float_to_string(gbs: int): s = str(float(gbs) * 1000).rstrip("0").rstrip(".") return s - def check_file_perms(self, path): + @staticmethod + def check_file_perms(path): try: open(path, "r", encoding="utf-8").close() logger.info(f"{path} is readable") @@ -79,8 +85,9 @@ class Helpers: except PermissionError: return False - def is_file_older_than_x_days(self, file, days=1): - if self.check_file_exists(file): + @staticmethod + def is_file_older_than_x_days(file, days=1): + if Helpers.check_file_exists(file): file_time = os.path.getmtime(file) # Check against 24 hours if (time.time() - file_time) / 3600 > 24 * days: @@ -193,14 +200,14 @@ class Helpers: else: logger.error(f"Config File Error: setting {key} does not exist") - console.error(f"Config File Error: setting {key} does not exist") + self.console.error(f"Config File Error: setting {key} does not exist") return default_return except Exception as e: logger.critical( f"Config File Error: Unable to read {self.settings_file} due to {e}" ) - console.critical( + self.console.critical( f"Config File Error: Unable to read {self.settings_file} due to {e}" ) @@ -217,7 +224,7 @@ class Helpers: else: logger.error(f"Config File Error: setting {key} does not exist") - console.error(f"Config File Error: setting {key} does not exist") + self.console.error(f"Config File Error: setting {key} does not exist") return default_return with open(self.settings_file, "w", encoding="utf-8") as f: @@ -227,11 +234,12 @@ class Helpers: logger.critical( f"Config File Error: Unable to read {self.settings_file} due to {e}" ) - console.critical( + self.console.critical( f"Config File Error: Unable to read {self.settings_file} due to {e}" ) - def get_local_ip(self): + @staticmethod + def get_local_ip(): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: # doesn't even have to be reachable @@ -252,7 +260,7 @@ class Helpers: version_data = json.load(f) except Exception as e: - console.critical(f"Unable to get version data! \n{e}") + self.console.critical(f"Unable to get version data! \n{e}") return version_data @@ -274,7 +282,6 @@ class Helpers: return data def get_version_string(self): - version_data = self.get_version() major = version_data.get("major", "?") minor = version_data.get("minor", "?") @@ -331,7 +338,8 @@ class Helpers: return line - def validate_traversal(self, base_path, filename): + @staticmethod + def validate_traversal(base_path, filename): logger.debug(f'Validating traversal ("{base_path}", "{filename}")') base = pathlib.Path(base_path).resolve() file = pathlib.Path(filename) @@ -342,8 +350,9 @@ class Helpers: else: raise ValueError("Path traversal detected") - def tail_file(self, file_name, number_lines=20): - if not self.check_file_exists(file_name): + @staticmethod + def tail_file(file_name, number_lines=20): + if not Helpers.check_file_exists(file_name): logger.warning(f"Unable to find file to tail: {file_name}") return [f"Unable to find file to tail: {file_name}"] @@ -392,8 +401,9 @@ class Helpers: logger.critical(f"Unable to write to {path} - Error: {e}") return False - def checkRoot(self): - if self.is_os_windows(): + @staticmethod + def checkRoot(): + if Helpers.is_os_windows(): if ctypes.windll.shell32.IsUserAnAdmin() == 1: return True else: @@ -404,7 +414,8 @@ class Helpers: else: return False - def unzipFile(self, zip_path): + @staticmethod + def unzipFile(zip_path): new_dir_list = zip_path.split("/") new_dir = "" for i in range(len(new_dir_list) - 1): @@ -413,8 +424,8 @@ class Helpers: else: new_dir += "/" + new_dir_list[i] - if helper.check_file_perms(zip_path) and os.path.isfile(zip_path): - helper.ensure_dir_exists(new_dir) + if Helpers.check_file_perms(zip_path) and os.path.isfile(zip_path): + Helpers.ensure_dir_exists(new_dir) tempDir = tempfile.mkdtemp() try: with zipfile.ZipFile(zip_path, "r") as zip_ref: @@ -429,7 +440,7 @@ class Helpers: for item in os.listdir(full_root_path): try: - file_helper.move_dir( + FileHelpers.move_dir( os.path.join(full_root_path, item), os.path.join(new_dir, item), ) @@ -447,7 +458,7 @@ class Helpers: logger.info("Checking app directory writable") - writeable = self.check_writeable(self.root_dir) + writeable = Helpers.check_writeable(self.root_dir) # if not writeable, let's bomb out if not writeable: @@ -459,13 +470,13 @@ class Helpers: with suppress(FileExistsError): os.makedirs(os.path.join(self.root_dir, "logs")) except Exception as e: - console.error(f"Failed to make logs directory with error: {e} ") + self.console.error(f"Failed to make logs directory with error: {e} ") # ensure the log file is there try: open(log_file, "a", encoding="utf-8").close() except Exception as e: - console.critical(f"Unable to open log file! {e}") + self.console.critical(f"Unable to open log file! {e}") sys.exit(1) # del any old session.lock file as this is a new session @@ -565,7 +576,7 @@ class Helpers: pid = data.get("pid") started = data.get("started") if psutil.pid_exists(pid): - console.critical( + self.console.critical( f"Another Crafty Controller agent seems to be running..." f"\npid: {pid} \nstarted on: {started}" ) @@ -580,7 +591,7 @@ class Helpers: except Exception as e: logger.error(f"Failed to locate existing session.lock with error: {e} ") - console.error( + self.console.error( f"Failed to locate existing session.lock with error: {e} " ) @@ -595,11 +606,12 @@ class Helpers: # because this is a recursive function, we will return bytes, # and set human readable later - def get_dir_size(self, path: str): + @staticmethod + def get_dir_size(path: str): total = 0 for entry in os.scandir(path): if entry.is_dir(follow_symlinks=False): - total += self.get_dir_size(entry.path) + total += Helpers.get_dir_size(entry.path) else: total += entry.stat(follow_symlinks=False).st_size return total @@ -613,11 +625,12 @@ class Helpers: ) ] - def get_human_readable_files_sizes(self, paths: list): + @staticmethod + def get_human_readable_files_sizes(paths: list): sizes = [] for p in paths: sizes.append( - {"path": p, "size": self.human_readable_file_size(os.stat(p).st_size)} + {"path": p, "size": Helpers.human_readable_file_size(os.stat(p).st_size)} ) return sizes @@ -633,10 +646,12 @@ class Helpers: b64_bytes = base64.decodebytes(s_bytes) return b64_bytes.decode("utf-8") - def create_uuid(self): + @staticmethod + def create_uuid(): return str(uuid.uuid4()) - def ensure_dir_exists(self, path): + @staticmethod + def ensure_dir_exists(path): """ ensures a directory exists @@ -662,7 +677,7 @@ class Helpers: cert_dir = os.path.join(self.config_dir, "web", "certs") # create a directory if needed - self.ensure_dir_exists(cert_dir) + Helpers.ensure_dir_exists(cert_dir) cert_file = os.path.join(cert_dir, "commander.cert.pem") key_file = os.path.join(cert_dir, "commander.key.pem") @@ -671,16 +686,16 @@ class Helpers: logger.info(f"SSL Key File is set to: {key_file}") # don't create new files if we already have them. - if self.check_file_exists(cert_file) and self.check_file_exists(key_file): + if Helpers.check_file_exists(cert_file) and Helpers.check_file_exists(key_file): logger.info("Cert and Key files already exists, not creating them.") return True - console.info("Generating a self signed SSL") + self.console.info("Generating a self signed SSL") logger.info("Generating a self signed SSL") # create a key pair logger.info("Generating a key pair. This might take a moment.") - console.info("Generating a key pair. This might take a moment.") + self.console.info("Generating a key pair. This might take a moment.") k = crypto.PKey() k.generate_key(crypto.TYPE_RSA, 4096) @@ -756,11 +771,11 @@ class Helpers: default_file = os.path.join(self.root_dir, "default.json") data = {} - if self.check_file_exists(default_file): + if Helpers.check_file_exists(default_file): with open(default_file, "r", encoding="utf-8") as f: data = json.load(f) - del_json = helper.get_setting("delete_default_json") + del_json = self.get_setting("delete_default_json") if del_json: os.remove(default_file) @@ -885,27 +900,25 @@ class Helpers:
  • """ return output - @staticmethod - def unzipServer(zip_path, user_id): - if helper.check_file_perms(zip_path): + def unzipServer(self, zip_path, user_id): + if Helpers.check_file_perms(zip_path): tempDir = tempfile.mkdtemp() with zipfile.ZipFile(zip_path, "r") as zip_ref: # extracts archive to temp directory zip_ref.extractall(tempDir) if user_id: - websocket_helper.broadcast_user( + self.websocket_helper.broadcast_user( user_id, "send_temp_path", {"path": tempDir} ) - @staticmethod - def backup_select(path, user_id): + def backup_select(self, path, user_id): if user_id: - websocket_helper.broadcast_user(user_id, "send_temp_path", {"path": path}) + self.websocket_helper.broadcast_user(user_id, "send_temp_path", {"path": path}) @staticmethod def unzip_backup_archive(backup_path, zip_name): zip_path = os.path.join(backup_path, zip_name) - if helper.check_file_perms(zip_path): + if Helpers.check_file_perms(zip_path): tempDir = tempfile.mkdtemp() with zipfile.ZipFile(zip_path, "r") as zip_ref: # extracts archive to temp directory @@ -937,7 +950,7 @@ class Helpers: @staticmethod def copy_files(source, dest): if os.path.isfile(source): - file_helper.copy_file(source, dest) + FileHelpers.copy_file(source, dest) logger.info("Copying jar %s to %s", source, dest) else: logger.info("Source jar does not exist.") @@ -974,6 +987,3 @@ class Helpers: return "en" else: return lang + "-" + region - - -helper = Helpers() diff --git a/app/classes/shared/import3.py b/app/classes/shared/import3.py index 404639d4..693fa810 100644 --- a/app/classes/shared/import3.py +++ b/app/classes/shared/import3.py @@ -2,16 +2,17 @@ import json import os import logging -from app.classes.controllers.users_controller import users_helper -from app.classes.shared.main_controller import Controller -from app.classes.shared.console import console +from app.classes.controllers.users_controller import helper_users logger = logging.getLogger(__name__) class import3: - def __init__(self): - self.controller = Controller() + def __init__(self, helper, controller): + self.helper = helper + self.console = self.helper.console + self.controller = controller + def start_import(self): folder = os.path.normpath( @@ -21,11 +22,11 @@ class import3: ) ) if not os.path.exists(folder): - console.info( + self.console.info( "Crafty cannot find the path you entered. " "Does Crafty's user have permission to access it?" ) - console.info("Please run the import3 command again and enter a valid path.") + self.console.info("Please run the import3 command again and enter a valid path.") else: with open(os.path.join(folder, "users.json"), encoding="utf-8") as f: user_json = json.loads(f.read()) @@ -34,16 +35,15 @@ class import3: self.import_users(user_json) self.import_servers(servers_json, self.controller) - @staticmethod - def import_users(json_data): + def import_users(self, json_data): # If there is only one user to import json needs to call the data differently if isinstance(json_data, list): for user in json_data: - users_helper.add_rawpass_user(user["username"], user["password"]) - console.info(f"Imported user {user['username']} from Crafty 3") + helper_users.add_rawpass_user(user["username"], user["password"]) + self.console.info(f"Imported user {user['username']} from Crafty 3") logger.info(f"Imported user {user['username']} from Crafty 3") else: - console.info( + self.console.info( "There is only one user detected. " "Cannot create duplicate Admin account." ) @@ -52,8 +52,7 @@ class import3: "Cannot create duplicate Admin account." ) - @staticmethod - def import_servers(json_data, controller): + def import_servers(self, json_data, controller): # If there is only one server to import json needs to call the data differently if isinstance(json_data, list): for server in json_data: @@ -65,7 +64,7 @@ class import3: max_mem=(int(server["memory_max"]) / 1000), port=server["server_port"], ) - console.info( + self.console.info( f"Imported server {server['server_name']}[{server['id']}] " f"from Crafty 3 to new server id {new_server_id}" ) @@ -82,7 +81,7 @@ class import3: max_mem=(int(json_data["memory_max"]) / 1000), port=json_data["server_port"], ) - console.info( + self.console.info( f"Imported server {json_data['server_name']}[{json_data['id']}] " f"from Crafty 3 to new server id {new_server_id}" ) @@ -90,6 +89,3 @@ class import3: f"Imported server {json_data['server_name']}[{json_data['id']}] " f"from Crafty 3 to new server id {new_server_id}" ) - - -import3 = import3() diff --git a/app/classes/shared/main_controller.py b/app/classes/shared/main_controller.py index 71a5f741..ba06e826 100644 --- a/app/classes/shared/main_controller.py +++ b/app/classes/shared/main_controller.py @@ -6,6 +6,10 @@ import time import logging import tempfile from typing import Union +from peewee import DoesNotExist +# TZLocal is set as a hidden import on win pipeline +from tzlocal import get_localzone +from apscheduler.schedulers.background import BackgroundScheduler from app.classes.controllers.crafty_perms_controller import Crafty_Perms_Controller from app.classes.controllers.management_controller import Management_Controller @@ -16,39 +20,34 @@ from app.classes.controllers.servers_controller import Servers_Controller from app.classes.models.server_permissions import Enum_Permissions_Server from app.classes.models.users import helper_users from app.classes.models.management import helpers_management -from app.classes.models.servers import servers_helper -from app.classes.shared.console import console -from app.classes.shared.helpers import helper +from app.classes.models.servers import helper_servers +from app.classes.shared.authentication import Authentication +from app.classes.shared.helpers import Helpers from app.classes.shared.server import Server -from app.classes.shared.file_helpers import file_helper +from app.classes.shared.file_helpers import FileHelpers from app.classes.minecraft.server_props import ServerProps -from app.classes.minecraft.serverjars import server_jar_obj +from app.classes.minecraft.serverjars import ServerJars from app.classes.minecraft.stats import Stats -from app.classes.web.websocket_helper import websocket_helper - -try: - from peewee import DoesNotExist - - # TZLocal is set as a hidden import on win pipeline - from tzlocal import get_localzone - from apscheduler.schedulers.background import BackgroundScheduler - -except ModuleNotFoundError as err: - helper.auto_installer_fix(err) logger = logging.getLogger(__name__) - class Controller: - def __init__(self): + def __init__(self, database, helper): + self.helper = helper + self.console = self.helper.console + self.server_jars = ServerJars(helper) + self.users_helper = helper_users(database, self.helper) + self.servers_helper = helper_servers(database) + self.management_helper = helpers_management(database, self.helper) + self.authentication = Authentication(self.helper) self.servers_list = [] - self.stats = Stats(self) + self.stats = Stats(self.helper, self) self.crafty_perms = Crafty_Perms_Controller() - self.management = Management_Controller() - self.roles = Roles_Controller() + self.management = Management_Controller(self.management_helper) + self.roles = Roles_Controller(self.users_helper) self.server_perms = Server_Perms_Controller() - self.servers = Servers_Controller() - self.users = Users_Controller() + self.servers = Servers_Controller(self.servers_helper) + self.users = Users_Controller(self.helper, self.users_helper, self.authentication) tz = get_localzone() self.support_scheduler = BackgroundScheduler(timezone=str(tz)) self.support_scheduler.start() @@ -83,28 +82,28 @@ class Controller: continue # if this server path no longer exists - let's warn and bomb out - if not helper.check_path_exists( - helper.get_os_understandable_path(s["path"]) + if not Helpers.check_path_exists( + Helpers.get_os_understandable_path(s["path"]) ): logger.warning( f"Unable to find server {s['server_name']} at path {s['path']}. " f"Skipping this server" ) - console.warning( + self.console.warning( f"Unable to find server {s['server_name']} at path {s['path']}. " f"Skipping this server" ) continue settings_file = os.path.join( - helper.get_os_understandable_path(s["path"]), "server.properties" + Helpers.get_os_understandable_path(s["path"]), "server.properties" ) # if the properties file isn't there, let's warn - if not helper.check_file_exists(settings_file): + if not Helpers.check_file_exists(settings_file): logger.error(f"Unable to find {settings_file}. Skipping this server.") - console.error(f"Unable to find {settings_file}. Skipping this server.") + self.console.error(f"Unable to find {settings_file}. Skipping this server.") continue settings = ServerProps(settings_file) @@ -112,7 +111,7 @@ class Controller: temp_server_dict = { "server_id": s.get("server_id"), "server_data_obj": s, - "server_obj": Server(self.stats), + "server_obj": Server(self.helper, self.management_helper, self.stats), "server_settings": settings.props, } @@ -127,7 +126,7 @@ class Controller: self.refresh_server_settings(s["server_id"]) - console.info( + self.console.info( f"Loaded Server: ID {s['server_id']}" + f" | Name: {s['server_name']}" + f" | Autostart: {s['auto_start']}" @@ -154,7 +153,7 @@ class Controller: self.users.set_prepare(exec_user["user_id"]) # pausing so on screen notifications can run for user time.sleep(7) - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( exec_user["user_id"], "notification", "Preparing your support logs" ) tempDir = tempfile.mkdtemp() @@ -195,12 +194,12 @@ class Controller: final_path += "_" + server["server_uuid"] os.mkdir(final_path) try: - file_helper.copy_file(server["log_path"], final_path) + FileHelpers.copy_file(server["log_path"], final_path) except Exception as e: logger.warning(f"Failed to copy file with error: {e}") # Copy crafty logs to archive dir full_log_name = os.path.join(crafty_path, "logs") - file_helper.copy_dir(os.path.join(self.project_root, "logs"), full_log_name) + FileHelpers.copy_dir(os.path.join(self.project_root, "logs"), full_log_name) self.support_scheduler.add_job( self.log_status, "interval", @@ -208,17 +207,17 @@ class Controller: id="logs_" + str(exec_user["user_id"]), args=[full_temp, tempZipStorage + ".zip", exec_user], ) - file_helper.make_archive(tempZipStorage, tempDir) + FileHelpers.make_archive(tempZipStorage, tempDir) - if len(websocket_helper.clients) > 0: - websocket_helper.broadcast_user( + if len(self.helper.websocket_helper.clients) > 0: + self.helper.websocket_helper.broadcast_user( exec_user["user_id"], "support_status_update", - helper.calc_percent(full_temp, tempZipStorage + ".zip"), + Helpers.calc_percent(full_temp, tempZipStorage + ".zip"), ) tempZipStorage += ".zip" - websocket_helper.broadcast_user(exec_user["user_id"], "send_logs_bootbox", {}) + self.helper.websocket_helper.broadcast_user(exec_user["user_id"], "send_logs_bootbox", {}) self.users.set_support_path(exec_user["user_id"], tempZipStorage) @@ -229,7 +228,7 @@ class Controller: def add_system_user(): helper_users.add_user( "system", - helper.random_string_generator(64), + Helpers.random_string_generator(64), "default@example.com", False, False, @@ -254,11 +253,11 @@ class Controller: svr.stop_crash_detection() def log_status(self, source_path, dest_path, exec_user): - results = helper.calc_percent(source_path, dest_path) + results = Helpers.calc_percent(source_path, dest_path) self.log_stats = results - if len(websocket_helper.clients) > 0: - websocket_helper.broadcast_user( + if len(self.helper.websocket_helper.clients) > 0: + self.helper.websocket_helper.broadcast_user( exec_user["user_id"], "support_status_update", results ) @@ -286,7 +285,7 @@ class Controller: @staticmethod def list_defined_servers(): - servers = servers_helper.get_all_defined_servers() + servers = helper_servers.get_all_defined_servers() return servers def list_running_servers(self): @@ -307,14 +306,14 @@ class Controller: def stop_all_servers(self): servers = self.list_running_servers() logger.info(f"Found {len(servers)} running server(s)") - console.info(f"Found {len(servers)} running server(s)") + self.console.info(f"Found {len(servers)} running server(s)") logger.info("Stopping All Servers") - console.info("Stopping All Servers") + self.console.info("Stopping All Servers") for s in servers: logger.info(f"Stopping Server ID {s['id']} - {s['name']}") - console.info(f"Stopping Server ID {s['id']} - {s['name']}") + self.console.info(f"Stopping Server ID {s['id']} - {s['name']}") self.stop_server(s["id"]) @@ -322,7 +321,7 @@ class Controller: time.sleep(2) logger.info("All Servers Stopped") - console.info("All Servers Stopped") + self.console.info("All Servers Stopped") def stop_server(self, server_id): # issue the stop command @@ -338,12 +337,12 @@ class Controller: max_mem: int, port: int, ): - server_id = helper.create_uuid() - server_dir = os.path.join(helper.servers_dir, server_id) - backup_path = os.path.join(helper.backup_path, server_id) - if helper.is_os_windows(): - server_dir = helper.wtol_path(server_dir) - backup_path = helper.wtol_path(backup_path) + server_id = Helpers.create_uuid() + server_dir = os.path.join(self.helper.servers_dir, server_id) + backup_path = os.path.join(self.helper.backup_path, server_id) + if Helpers.is_os_windows(): + server_dir = Helpers.wtol_path(server_dir) + backup_path = Helpers.wtol_path(backup_path) server_dir.replace(" ", "^ ") backup_path.replace(" ", "^ ") @@ -351,8 +350,8 @@ class Controller: full_jar_path = os.path.join(server_dir, server_file) # make the dir - perhaps a UUID? - helper.ensure_dir_exists(server_dir) - helper.ensure_dir_exists(backup_path) + Helpers.ensure_dir_exists(server_dir) + Helpers.ensure_dir_exists(backup_path) try: # do a eula.txt @@ -371,16 +370,16 @@ class Controller: logger.error(f"Unable to create required server files due to :{e}") return False - if helper.is_os_windows(): + if Helpers.is_os_windows(): server_command = ( - f"java -Xms{helper.float_to_string(min_mem)}M " - f"-Xmx{helper.float_to_string(max_mem)}M " + f"java -Xms{Helpers.float_to_string(min_mem)}M " + f"-Xmx{Helpers.float_to_string(max_mem)}M " f'-jar "{full_jar_path}" nogui' ) else: server_command = ( - f"java -Xms{helper.float_to_string(min_mem)}M " - f"-Xmx{helper.float_to_string(max_mem)}M " + f"java -Xms{Helpers.float_to_string(min_mem)}M " + f"-Xmx{Helpers.float_to_string(max_mem)}M " f"-jar {full_jar_path} nogui" ) server_log_file = f"{server_dir}/logs/latest.log" @@ -400,23 +399,23 @@ class Controller: ) # download the jar - server_jar_obj.download_jar(server, version, full_jar_path, new_id) + self.server_jars.download_jar(server, version, full_jar_path, new_id) return new_id @staticmethod def verify_jar_server(server_path: str, server_jar: str): - server_path = helper.get_os_understandable_path(server_path) - path_check = helper.check_path_exists(server_path) - jar_check = helper.check_file_exists(os.path.join(server_path, server_jar)) + server_path = Helpers.get_os_understandable_path(server_path) + path_check = Helpers.check_path_exists(server_path) + jar_check = Helpers.check_file_exists(os.path.join(server_path, server_jar)) if not path_check or not jar_check: return False return True @staticmethod def verify_zip_server(zip_path: str): - zip_path = helper.get_os_understandable_path(zip_path) - zip_check = helper.check_file_exists(zip_path) + zip_path = Helpers.get_os_understandable_path(zip_path) + zip_check = Helpers.check_file_exists(zip_path) if not zip_check: return False return True @@ -430,20 +429,20 @@ class Controller: max_mem: int, port: int, ): - server_id = helper.create_uuid() - new_server_dir = os.path.join(helper.servers_dir, server_id) - backup_path = os.path.join(helper.backup_path, server_id) - if helper.is_os_windows(): - new_server_dir = helper.wtol_path(new_server_dir) - backup_path = helper.wtol_path(backup_path) + server_id = Helpers.create_uuid() + new_server_dir = os.path.join(Helpers.servers_dir, server_id) + backup_path = os.path.join(Helpers.backup_path, server_id) + if Helpers.is_os_windows(): + new_server_dir = Helpers.wtol_path(new_server_dir) + backup_path = Helpers.wtol_path(backup_path) new_server_dir.replace(" ", "^ ") backup_path.replace(" ", "^ ") - helper.ensure_dir_exists(new_server_dir) - helper.ensure_dir_exists(backup_path) - server_path = helper.get_os_understandable_path(server_path) + Helpers.ensure_dir_exists(new_server_dir) + Helpers.ensure_dir_exists(backup_path) + server_path = Helpers.get_os_understandable_path(server_path) try: - file_helper.copy_dir(server_path, new_server_dir, True) + FileHelpers.copy_dir(server_path, new_server_dir, True) except shutil.Error as ex: logger.error(f"Server import failed with error: {ex}") @@ -464,16 +463,16 @@ class Controller: full_jar_path = os.path.join(new_server_dir, server_jar) - if helper.is_os_windows(): + if Helpers.is_os_windows(): server_command = ( - f"java -Xms{helper.float_to_string(min_mem)}M " - f"-Xmx{helper.float_to_string(max_mem)}M " + f"java -Xms{Helpers.float_to_string(min_mem)}M " + f"-Xmx{Helpers.float_to_string(max_mem)}M " f'-jar "{full_jar_path}" nogui' ) else: server_command = ( - f"java -Xms{helper.float_to_string(min_mem)}M " - f"-Xmx{helper.float_to_string(max_mem)}M " + f"java -Xms{Helpers.float_to_string(min_mem)}M " + f"-Xmx{Helpers.float_to_string(max_mem)}M " f"-jar {full_jar_path} nogui" ) server_log_file = f"{new_server_dir}/logs/latest.log" @@ -502,18 +501,18 @@ class Controller: max_mem: int, port: int, ): - server_id = helper.create_uuid() - new_server_dir = os.path.join(helper.servers_dir, server_id) - backup_path = os.path.join(helper.backup_path, server_id) - if helper.is_os_windows(): - new_server_dir = helper.wtol_path(new_server_dir) - backup_path = helper.wtol_path(backup_path) + server_id = Helpers.create_uuid() + new_server_dir = os.path.join(self.helper.servers_dir, server_id) + backup_path = os.path.join(self.helper.backup_path, server_id) + if Helpers.is_os_windows(): + new_server_dir = Helpers.wtol_path(new_server_dir) + backup_path = Helpers.wtol_path(backup_path) new_server_dir.replace(" ", "^ ") backup_path.replace(" ", "^ ") - tempDir = helper.get_os_understandable_path(zip_path) - helper.ensure_dir_exists(new_server_dir) - helper.ensure_dir_exists(backup_path) + tempDir = Helpers.get_os_understandable_path(zip_path) + Helpers.ensure_dir_exists(new_server_dir) + Helpers.ensure_dir_exists(backup_path) has_properties = False # extracts archive to temp directory for item in os.listdir(tempDir): @@ -521,11 +520,11 @@ class Controller: has_properties = True try: if not os.path.isdir(os.path.join(tempDir, item)): - file_helper.move_file( + FileHelpers.move_file( os.path.join(tempDir, item), os.path.join(new_server_dir, item) ) else: - file_helper.move_dir( + FileHelpers.move_dir( os.path.join(tempDir, item), os.path.join(new_server_dir, item) ) except Exception as ex: @@ -543,16 +542,16 @@ class Controller: full_jar_path = os.path.join(new_server_dir, server_jar) - if helper.is_os_windows(): + if Helpers.is_os_windows(): server_command = ( - f"java -Xms{helper.float_to_string(min_mem)}M " - f"-Xmx{helper.float_to_string(max_mem)}M " + f"java -Xms{Helpers.float_to_string(min_mem)}M " + f"-Xmx{Helpers.float_to_string(max_mem)}M " f'-jar "{full_jar_path}" nogui' ) else: server_command = ( - f"java -Xms{helper.float_to_string(min_mem)}M " - f"-Xmx{helper.float_to_string(max_mem)}M " + f"java -Xms{Helpers.float_to_string(min_mem)}M " + f"-Xmx{Helpers.float_to_string(max_mem)}M " f"-jar {full_jar_path} nogui" ) logger.debug("command: " + server_command) @@ -580,20 +579,20 @@ class Controller: def import_bedrock_server( self, server_name: str, server_path: str, server_exe: str, port: int ): - server_id = helper.create_uuid() - new_server_dir = os.path.join(helper.servers_dir, server_id) - backup_path = os.path.join(helper.backup_path, server_id) - if helper.is_os_windows(): - new_server_dir = helper.wtol_path(new_server_dir) - backup_path = helper.wtol_path(backup_path) + server_id = Helpers.create_uuid() + new_server_dir = os.path.join(self.helper.servers_dir, server_id) + backup_path = os.path.join(self.helper.backup_path, server_id) + if Helpers.is_os_windows(): + new_server_dir = Helpers.wtol_path(new_server_dir) + backup_path = Helpers.wtol_path(backup_path) new_server_dir.replace(" ", "^ ") backup_path.replace(" ", "^ ") - helper.ensure_dir_exists(new_server_dir) - helper.ensure_dir_exists(backup_path) - server_path = helper.get_os_understandable_path(server_path) + Helpers.ensure_dir_exists(new_server_dir) + Helpers.ensure_dir_exists(backup_path) + server_path = Helpers.get_os_understandable_path(server_path) try: - file_helper.copy_dir(server_path, new_server_dir, True) + FileHelpers.copy_dir(server_path, new_server_dir, True) except shutil.Error as ex: logger.error(f"Server import failed with error: {ex}") @@ -614,7 +613,7 @@ class Controller: full_jar_path = os.path.join(new_server_dir, server_exe) - if helper.is_os_windows(): + if Helpers.is_os_windows(): server_command = f'"{full_jar_path}"' else: server_command = f"./{server_exe}" @@ -635,25 +634,25 @@ class Controller: server_type="minecraft-bedrock", ) if os.name != "nt": - if helper.check_file_exists(full_jar_path): + if Helpers.check_file_exists(full_jar_path): os.chmod(full_jar_path, 0o2775) return new_id def import_bedrock_zip_server( self, server_name: str, zip_path: str, server_exe: str, port: int ): - server_id = helper.create_uuid() - new_server_dir = os.path.join(helper.servers_dir, server_id) - backup_path = os.path.join(helper.backup_path, server_id) - if helper.is_os_windows(): - new_server_dir = helper.wtol_path(new_server_dir) - backup_path = helper.wtol_path(backup_path) + server_id = Helpers.create_uuid() + new_server_dir = os.path.join(self.helper.servers_dir, server_id) + backup_path = os.path.join(self.helper.backup_path, server_id) + if Helpers.is_os_windows(): + new_server_dir = Helpers.wtol_path(new_server_dir) + backup_path = Helpers.wtol_path(backup_path) new_server_dir.replace(" ", "^ ") backup_path.replace(" ", "^ ") - tempDir = helper.get_os_understandable_path(zip_path) - helper.ensure_dir_exists(new_server_dir) - helper.ensure_dir_exists(backup_path) + tempDir = Helpers.get_os_understandable_path(zip_path) + Helpers.ensure_dir_exists(new_server_dir) + Helpers.ensure_dir_exists(backup_path) has_properties = False # extracts archive to temp directory for item in os.listdir(tempDir): @@ -661,11 +660,11 @@ class Controller: has_properties = True try: if not os.path.isdir(os.path.join(tempDir, item)): - file_helper.move_file( + FileHelpers.move_file( os.path.join(tempDir, item), os.path.join(new_server_dir, item) ) else: - file_helper.move_dir( + FileHelpers.move_dir( os.path.join(tempDir, item), os.path.join(new_server_dir, item) ) except Exception as ex: @@ -683,7 +682,7 @@ class Controller: full_jar_path = os.path.join(new_server_dir, server_exe) - if helper.is_os_windows(): + if Helpers.is_os_windows(): server_command = f'"{full_jar_path}"' else: server_command = f"./{server_exe}" @@ -704,7 +703,7 @@ class Controller: server_type="minecraft-bedrock", ) if os.name != "nt": - if helper.check_file_exists(full_jar_path): + if Helpers.check_file_exists(full_jar_path): os.chmod(full_jar_path, 0o2775) return new_id @@ -717,20 +716,20 @@ class Controller: server_data = self.servers.get_server_data_by_id(old_server_id) old_bu_path = server_data["backup_path"] Server_Perms_Controller.backup_role_swap(old_server_id, new_server_id) - if not helper.is_os_windows(): - backup_path = helper.validate_traversal(helper.backup_path, old_bu_path) - if helper.is_os_windows(): - backup_path = helper.validate_traversal( - helper.wtol_path(helper.backup_path), helper.wtol_path(old_bu_path) + if not Helpers.is_os_windows(): + backup_path = Helpers.validate_traversal(self.helper.backup_path, old_bu_path) + if Helpers.is_os_windows(): + backup_path = Helpers.validate_traversal( + Helpers.wtol_path(self.helper.backup_path), Helpers.wtol_path(old_bu_path) ) - backup_path = helper.wtol_path(str(backup_path)) + backup_path = Helpers.wtol_path(str(backup_path)) backup_path.replace(" ", "^ ") backup_path = Path(backup_path) backup_path_components = list(backup_path.parts) backup_path_components[-1] = new_uuid new_bu_path = pathlib.PurePath(os.path.join(*backup_path_components)) if os.path.isdir(new_bu_path): - if helper.validate_traversal(helper.backup_path, new_bu_path): + if Helpers.validate_traversal(self.helper.backup_path, new_bu_path): os.rmdir(new_bu_path) backup_path.rename(new_bu_path) @@ -762,7 +761,7 @@ class Controller: server_port, ) - if not helper.check_file_exists(os.path.join(server_dir, "crafty_managed.txt")): + if not Helpers.check_file_exists(os.path.join(server_dir, "crafty_managed.txt")): try: # place a file in the dir saying it's owned by crafty with open( @@ -795,7 +794,7 @@ class Controller: server_name = server_data["server_name"] logger.info(f"Deleting Server: ID {server_id} | Name: {server_name} ") - console.info(f"Deleting Server: ID {server_id} | Name: {server_name} ") + self.console.info(f"Deleting Server: ID {server_id} | Name: {server_name} ") srv_obj = s["server_obj"] running = srv_obj.check_running() @@ -804,8 +803,8 @@ class Controller: self.stop_server(server_id) if files: try: - file_helper.del_dirs( - helper.get_os_understandable_path( + FileHelpers.del_dirs( + Helpers.get_os_understandable_path( self.servers.get_server_data_by_id(server_id)["path"] ) ) @@ -814,11 +813,11 @@ class Controller: f"Unable to delete server files for server with ID: " f"{server_id} with error logged: {e}" ) - if helper.check_path_exists( + if Helpers.check_path_exists( self.servers.get_server_data_by_id(server_id)["backup_path"] ): - file_helper.del_dirs( - helper.get_os_understandable_path( + FileHelpers.del_dirs( + Helpers.get_os_understandable_path( self.servers.get_server_data_by_id(server_id)[ "backup_path" ] diff --git a/app/classes/shared/main_models.py b/app/classes/shared/main_models.py index c110ca9a..80ddbedf 100644 --- a/app/classes/shared/main_models.py +++ b/app/classes/shared/main_models.py @@ -1,51 +1,35 @@ import logging +from playhouse.shortcuts import model_to_dict -from app.classes.models.users import Users, users_helper -from app.classes.shared.helpers import helper -from app.classes.shared.console import console - -# To disable warning about unused import ; Users is imported from here in other places -# pylint: disable=self-assigning-variable -Users = Users - -try: - # pylint: disable=unused-import - from peewee import SqliteDatabase - from playhouse.shortcuts import model_to_dict - -except ModuleNotFoundError as err: - helper.auto_installer_fix(err) +# pylint: disable=unused-import +from app.classes.shared.helpers import Helpers logger = logging.getLogger(__name__) -peewee_logger = logging.getLogger("peewee") -peewee_logger.setLevel(logging.INFO) -database = SqliteDatabase( - helper.db_path, - pragmas={"journal_mode": "wal", "cache_size": -1024 * 10} -) - class db_builder: - @staticmethod - def default_settings(): + def __init__(self, database, helper, users_helper): + self.database = database + self.helper = helper + self.users_helper = users_helper + + def default_settings(self): logger.info("Fresh Install Detected - Creating Default Settings") - console.info("Fresh Install Detected - Creating Default Settings") - default_data = helper.find_default_password() + self.helper.console.info("Fresh Install Detected - Creating Default Settings") + default_data = self.helper.find_default_password() username = default_data.get("username", "admin") password = default_data.get("password", "crafty") - users_helper.add_user( + self.users_helper.add_user( username=username, password=password, email="default@example.com", superuser=True, ) - @staticmethod - def is_fresh_install(): + def is_fresh_install(self): try: - user = users_helper.get_by_id(1) + user = self.users_helper.get_by_id(1) if user: return False except: @@ -53,7 +37,6 @@ class db_builder: class db_shortcuts: - # ********************************************************************************** # Generic Databse Methods # ********************************************************************************** @@ -74,10 +57,3 @@ class db_shortcuts: def return_db_rows(model): data = [model_to_dict(row) for row in model] return data - - -# ********************************************************************************** -# Static Accessors -# ********************************************************************************** -installer = db_builder() -db_helper = db_shortcuts() diff --git a/app/classes/shared/migration.py b/app/classes/shared/migration.py index 10781965..abec3099 100644 --- a/app/classes/shared/migration.py +++ b/app/classes/shared/migration.py @@ -7,22 +7,16 @@ import os import re from functools import wraps from functools import cached_property +import peewee +from playhouse.migrate import ( + SqliteMigrator, + Operation, + SQL, + SqliteDatabase, + make_index_name, +) -from app.classes.shared.helpers import helper -from app.classes.shared.console import console - -try: - import peewee - from playhouse.migrate import ( - SqliteMigrator, - Operation, - SQL, - SqliteDatabase, - make_index_name, - ) - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) +from app.classes.shared.helpers import Helpers logger = logging.getLogger(__name__) @@ -303,13 +297,14 @@ class Migrator(object): class MigrationManager(object): filemask = re.compile(r"[\d]+_[^\.]+\.py$") - def __init__(self, database: t.Union[peewee.Database, peewee.Proxy]): + def __init__(self, database: t.Union[peewee.Database, peewee.Proxy], helper): """ Initializes the migration manager. """ if not isinstance(database, (peewee.Database, peewee.Proxy)): raise RuntimeError("Invalid database: {}".format(database)) self.database = database + self.helper = helper @cached_property def model(self) -> t.Type[MigrateHistory]: @@ -334,13 +329,13 @@ class MigrationManager(object): """ Scans migrations in the file system. """ - if not os.path.exists(helper.migration_dir): + if not os.path.exists(self.helper.migration_dir): logger.warning( - "Migration directory: {} does not exist.".format(helper.migration_dir) + "Migration directory: {} does not exist.".format(self.helper.migration_dir) ) - os.makedirs(helper.migration_dir) + os.makedirs(self.helper.migration_dir) return sorted( - f[:-3] for f in os.listdir(helper.migration_dir) if self.filemask.match(f) + f[:-3] for f in os.listdir(self.helper.migration_dir) if self.filemask.match(f) ) @property @@ -367,7 +362,7 @@ class MigrationManager(object): """ name = datetime.utcnow().strftime("%Y%m%d%H%M%S") + "_" + name filename = name + ".py" - path = os.path.join(helper.migration_dir, filename) + path = os.path.join(self.helper.migration_dir, filename) with open(path, "w") as f: f.write( MIGRATE_TEMPLATE.format( @@ -399,13 +394,13 @@ class MigrationManager(object): Runs all unapplied migrations. """ logger.info("Starting migrations") - console.info("Starting migrations") + self.helper.console.info("Starting migrations") done = [] diff = self.diff if not diff: logger.info("There is nothing to migrate") - console.info("There is nothing to migrate") + self.helper.console.info("There is nothing to migrate") return done migrator = self.migrator @@ -421,10 +416,10 @@ class MigrationManager(object): Reads a migration from a file. """ call_params = dict() - if helper.is_os_windows() and sys.version_info >= (3, 0): + if Helpers.is_os_windows() and sys.version_info >= (3, 0): # if system is windows - force utf-8 encoding call_params["encoding"] = "utf-8" - with open(os.path.join(helper.migration_dir, name + ".py"), **call_params) as f: + with open(os.path.join(self.helper.migration_dir, name + ".py"), **call_params) as f: code = f.read() scope = {} code = compile(code, "", "exec", dont_inherit=True) diff --git a/app/classes/shared/permission_helper.py b/app/classes/shared/permission_helper.py index 7874d792..686b738b 100644 --- a/app/classes/shared/permission_helper.py +++ b/app/classes/shared/permission_helper.py @@ -4,7 +4,7 @@ from enum import Enum class PermissionHelper: @staticmethod def both_have_perm(a: str, b: str, permission_tested: Enum): - return permission_helper.combine_perm_bool( + return PermissionHelper.combine_perm_bool( a[permission_tested.value], b[permission_tested.value] ) @@ -20,8 +20,5 @@ class PermissionHelper: def combine_masks(permission_mask_a: str, permission_mask_b: str) -> str: both_masks = zip(list(permission_mask_a), list(permission_mask_b)) return "".join( - map(lambda x: permission_helper.combine_perm(x[0], x[1]), both_masks) + map(lambda x: PermissionHelper.combine_perm(x[0], x[1]), both_masks) ) - - -permission_helper = PermissionHelper() diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index 7f846b6e..c74bd28e 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -8,28 +8,19 @@ import logging.config import subprocess import html import tempfile +import psutil +# TZLocal is set as a hidden import on win pipeline +from tzlocal import get_localzone +from apscheduler.schedulers.background import BackgroundScheduler from app.classes.minecraft.stats import Stats from app.classes.minecraft.mc_ping import ping, ping_bedrock -from app.classes.models.servers import Server_Stats, servers_helper -from app.classes.models.management import management_helper -from app.classes.models.users import users_helper -from app.classes.models.server_permissions import server_permissions -from app.classes.shared.helpers import helper -from app.classes.shared.console import console -from app.classes.shared.translation import translation -from app.classes.shared.file_helpers import file_helper -from app.classes.web.websocket_helper import websocket_helper - -try: - import psutil - - # TZLocal is set as a hidden import on win pipeline - from tzlocal import get_localzone - from apscheduler.schedulers.background import BackgroundScheduler - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) +from app.classes.models.servers import Server_Stats, helper_servers +from app.classes.models.management import helpers_management +from app.classes.models.users import helper_users +from app.classes.models.server_permissions import Permissions_Servers +from app.classes.shared.helpers import Helpers +from app.classes.shared.file_helpers import FileHelpers logger = logging.getLogger(__name__) @@ -37,11 +28,12 @@ logger = logging.getLogger(__name__) class ServerOutBuf: lines = {} - def __init__(self, proc, server_id): + def __init__(self, helper, proc, server_id): + self.helper = helper self.proc = proc self.server_id = str(server_id) # Buffers text for virtual_terminal_lines config number of lines - self.max_lines = helper.get_setting("virtual_terminal_lines") + self.max_lines = self.helper.get_setting("virtual_terminal_lines") self.line_buffer = "" ServerOutBuf.lines[self.server_id] = [] self.lsi = 0 @@ -79,13 +71,13 @@ class ServerOutBuf: def new_line_handler(self, new_line): new_line = re.sub("(\033\\[(0;)?[0-9]*[A-z]?(;[0-9])?m?)", " ", new_line) new_line = re.sub("[A-z]{2}\b\b", "", new_line) - highlighted = helper.log_colors(html.escape(new_line)) + highlighted = self.helper.log_colors(html.escape(new_line)) logger.debug("Broadcasting new virtual terminal line") # TODO: Do not send data to clients who do not have permission to view # this server's console - websocket_helper.broadcast_page_params( + self.helper.websocket_helper.broadcast_page_params( "/panel/server_detail", {"id": self.server_id}, "vterm_new_line", @@ -97,7 +89,10 @@ class ServerOutBuf: # Minecraft Server Class # ********************************************************************************** class Server: - def __init__(self, stats): + def __init__(self, helper, management_helper, stats): + self.helper = helper + self.management_helper = management_helper + self.console = self.helper.console # holders for our process self.process = None self.line = False @@ -121,14 +116,14 @@ class Server: ) self.is_backingup = False # Reset crash and update at initialization - servers_helper.server_crash_reset(self.server_id) - servers_helper.set_update(self.server_id, False) + helper_servers.server_crash_reset(self.server_id) + helper_servers.set_update(self.server_id, False) # ********************************************************************************** # Minecraft Server Management # ********************************************************************************** def reload_server_settings(self): - server_data = servers_helper.get_server_data_by_id(self.server_id) + server_data = helper_servers.get_server_data_by_id(self.server_id) self.settings = server_data def do_server_setup(self, server_data_obj): @@ -153,7 +148,7 @@ class Server: delay = int(self.settings["auto_start_delay"]) logger.info(f"Scheduling server {self.name} to start in {delay} seconds") - console.info(f"Scheduling server {self.name} to start in {delay} seconds") + self.console.info(f"Scheduling server {self.name} to start in {delay} seconds") self.server_scheduler.add_job( self.run_scheduled_server, @@ -163,10 +158,10 @@ class Server: ) def run_scheduled_server(self): - console.info(f"Starting server ID: {self.server_id} - {self.name}") + self.console.info(f"Starting server ID: {self.server_id} - {self.name}") logger.info(f"Starting server ID: {self.server_id} - {self.name}") # Sets waiting start to false since we're attempting to start the server. - servers_helper.set_waiting_start(self.server_id, False) + helper_servers.set_waiting_start(self.server_id, False) self.run_threaded_server(None) # remove the scheduled job since it's ran @@ -184,7 +179,7 @@ class Server: # Register an shedule for polling server stats when running logger.info(f"Polling server statistics {self.name} every {5} seconds") - console.info(f"Polling server statistics {self.name} every {5} seconds") + self.console.info(f"Polling server statistics {self.name} every {5} seconds") try: self.server_scheduler.add_job( self.realtime_stats, @@ -203,43 +198,43 @@ class Server: def setup_server_run_command(self): # configure the server - server_exec_path = helper.get_os_understandable_path( + server_exec_path = Helpers.get_os_understandable_path( self.settings["executable"] ) - self.server_command = helper.cmdparse(self.settings["execution_command"]) - self.server_path = helper.get_os_understandable_path(self.settings["path"]) + self.server_command = Helpers.cmdparse(self.settings["execution_command"]) + self.server_path = Helpers.get_os_understandable_path(self.settings["path"]) # let's do some quick checking to make sure things actually exists full_path = os.path.join(self.server_path, server_exec_path) - if not helper.check_file_exists(full_path): + if not Helpers.check_file_exists(full_path): logger.critical( f"Server executable path: {full_path} does not seem to exist" ) - console.critical( + self.console.critical( f"Server executable path: {full_path} does not seem to exist" ) - if not helper.check_path_exists(self.server_path): + if not Helpers.check_path_exists(self.server_path): logger.critical(f"Server path: {self.server_path} does not seem to exits") - console.critical(f"Server path: {self.server_path} does not seem to exits") + self.console.critical(f"Server path: {self.server_path} does not seem to exits") - if not helper.check_writeable(self.server_path): + if not Helpers.check_writeable(self.server_path): logger.critical(f"Unable to write/access {self.server_path}") - console.warning(f"Unable to write/access {self.server_path}") + self.console.critical(f"Unable to write/access {self.server_path}") def start_server(self, user_id): if not user_id: - user_lang = helper.get_setting("language") + user_lang = self.helper.get_setting("language") else: - user_lang = users_helper.get_user_lang_by_id(user_id) + user_lang = helper_users.get_user_lang_by_id(user_id) - if servers_helper.get_download_status(self.server_id): + if helper_servers.get_download_status(self.server_id): if user_id: - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user_id, "send_start_error", { - "error": translation.translate( + "error": self.helper.translation.translate( "error", "not-downloaded", user_lang ) }, @@ -253,18 +248,18 @@ class Server: # fail safe in case we try to start something already running if self.check_running(): logger.error("Server is already running - Cancelling Startup") - console.error("Server is already running - Cancelling Startup") + self.console.error("Server is already running - Cancelling Startup") return False if self.check_update(): logger.error("Server is updating. Terminating startup.") return False logger.info(f"Launching Server {self.name} with command {self.server_command}") - console.info(f"Launching Server {self.name} with command {self.server_command}") + self.console.info(f"Launching Server {self.name} with command {self.server_command}") # Checks for eula. Creates one if none detected. # If EULA is detected and not set to true we offer to set it true. - if helper.check_file_exists(os.path.join(self.settings["path"], "eula.txt")): + if Helpers.check_file_exists(os.path.join(self.settings["path"], "eula.txt")): f = open( os.path.join(self.settings["path"], "eula.txt"), "r", encoding="utf-8" ) @@ -288,7 +283,7 @@ class Server: if not e_flag: if user_id: - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user_id, "send_eula_bootbox", {"id": self.server_id} ) else: @@ -299,7 +294,7 @@ class Server: return False return False f.close() - if helper.is_os_windows(): + if Helpers.is_os_windows(): logger.info("Windows Detected") else: logger.info("Unix Detected") @@ -313,7 +308,7 @@ class Server: f = open( os.path.join( self.server_path, - servers_helper.get_server_data_by_id(self.server_id)["executable"], + helper_servers.get_server_data_by_id(self.server_id)["executable"], ), "r", encoding="utf-8", @@ -322,11 +317,11 @@ class Server: except: if user_id: - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user_id, "send_start_error", { - "error": translation.translate( + "error": self.helper.translation.translate( "error", "not-downloaded", user_lang ) }, @@ -334,8 +329,8 @@ class Server: return if ( - not helper.is_os_windows() - and servers_helper.get_server_type_by_id(self.server_id) + not Helpers.is_os_windows() + and helper_servers.get_server_type_by_id(self.server_id) == "minecraft-bedrock" ): logger.info( @@ -358,11 +353,11 @@ class Server: f"Server {self.name} failed to start with error code: {ex}" ) if user_id: - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user_id, "send_start_error", { - "error": translation.translate( + "error": self.helper.translation.translate( "error", "start-error", user_lang ).format(self.name, ex) }, @@ -382,11 +377,11 @@ class Server: # Checks for java on initial fail if os.system("java -version") == 32512: if user_id: - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user_id, "send_start_error", { - "error": translation.translate( + "error": self.helper.translation.translate( "error", "noJava", user_lang ).format(self.name) }, @@ -397,18 +392,18 @@ class Server: f"Server {self.name} failed to start with error code: {ex}" ) if user_id: - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user_id, "send_start_error", { - "error": translation.translate( + "error": self.helper.translation.translate( "error", "start-error", user_lang ).format(self.name, ex) }, ) return False - out_buf = ServerOutBuf(self.process, self.server_id) + out_buf = ServerOutBuf(self.helper, self.process, self.server_id) logger.debug(f"Starting virtual terminal listener for server {self.name}") threading.Thread( @@ -416,15 +411,15 @@ class Server: ).start() self.is_crashed = False - servers_helper.server_crash_reset(self.server_id) + helper_servers.server_crash_reset(self.server_id) self.start_time = str(datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")) if self.process.poll() is None: logger.info(f"Server {self.name} running with PID {self.process.pid}") - console.info(f"Server {self.name} running with PID {self.process.pid}") + self.console.info(f"Server {self.name} running with PID {self.process.pid}") self.is_crashed = False - servers_helper.server_crash_reset(self.server_id) + helper_servers.server_crash_reset(self.server_id) self.record_server_stats() check_internet_thread = threading.Thread( target=self.check_internet_thread, @@ -437,35 +432,35 @@ class Server: ) check_internet_thread.start() # Checks if this is the servers first run. - if servers_helper.get_first_run(self.server_id): - servers_helper.set_first_run(self.server_id) - loc_server_port = servers_helper.get_server_stats_by_id(self.server_id)[ + if helper_servers.get_first_run(self.server_id): + helper_servers.set_first_run(self.server_id) + loc_server_port = helper_servers.get_server_stats_by_id(self.server_id)[ "server_port" ] # Sends port reminder message. - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user_id, "send_start_error", { - "error": translation.translate( + "error": self.helper.translation.translate( "error", "portReminder", user_lang ).format(self.name, loc_server_port) }, ) - server_users = server_permissions.get_server_user_list(self.server_id) + server_users = Permissions_Servers.get_server_user_list(self.server_id) for user in server_users: if user != user_id: - websocket_helper.broadcast_user(user, "send_start_reload", {}) + self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {}) else: - server_users = server_permissions.get_server_user_list(self.server_id) + server_users = Permissions_Servers.get_server_user_list(self.server_id) for user in server_users: - websocket_helper.broadcast_user(user, "send_start_reload", {}) + self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {}) else: logger.warning( f"Server PID {self.process.pid} died right after starting " f"- is this a server config issue?" ) - console.warning( + self.console.critical( f"Server PID {self.process.pid} died right after starting " f"- is this a server config issue?" ) @@ -475,7 +470,7 @@ class Server: f"Server {self.name} has crash detection enabled " f"- starting watcher task" ) - console.info( + self.console.info( f"Server {self.name} has crash detection enabled " f"- starting watcher task" ) @@ -486,11 +481,11 @@ class Server: def check_internet_thread(self, user_id, user_lang): if user_id: - if not helper.check_internet(): - websocket_helper.broadcast_user( + if not Helpers.check_internet(): + self.helper.websocket_helper.broadcast_user( user_id, "send_start_error", - {"error": translation.translate("error", "internet", user_lang)}, + {"error": self.helper.translation.translate("error", "internet", user_lang)}, ) def stop_crash_detection(self): @@ -514,7 +509,7 @@ class Server: f"Server {self.name} has crash detection enabled " f"- starting watcher task" ) - console.info( + self.console.info( f"Server {self.name} has crash detection enabled " "- starting watcher task" ) @@ -547,7 +542,7 @@ class Server: running = self.check_running() if not running: logger.info(f"Can't stop server {self.name} if it's not running") - console.info(f"Can't stop server {self.name} if it's not running") + self.console.info(f"Can't stop server {self.name} if it's not running") return x = 0 @@ -563,7 +558,7 @@ class Server: f"seconds until force close)" ) logger.info(logstr) - console.info(logstr) + self.console.info(logstr) running = self.check_running() time.sleep(2) @@ -572,17 +567,17 @@ class Server: logger.info( f"Server {server_name} is still running - Forcing the process down" ) - console.info( + self.console.info( f"Server {server_name} is still running - Forcing the process down" ) self.kill() logger.info(f"Stopped Server {server_name} with PID {server_pid}") - console.info(f"Stopped Server {server_name} with PID {server_pid}") + self.console.info(f"Stopped Server {server_name} with PID {server_pid}") # massive resetting of variables self.cleanup_server_object() - server_users = server_permissions.get_server_user_list(self.server_id) + server_users = Permissions_Servers.get_server_user_list(self.server_id) # remove the stats polling job since server is stopped self.server_scheduler.remove_job("stats_" + str(self.server_id)) @@ -590,7 +585,7 @@ class Server: self.record_server_stats() for user in server_users: - websocket_helper.broadcast_user(user, "send_start_reload", {}) + self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {}) def restart_threaded_server(self, user_id): # if not already running, let's just start @@ -623,7 +618,7 @@ class Server: if not self.check_running() and command.lower() != "start": logger.warning(f'Server not running, unable to send command "{command}"') return False - console.info(f"COMMAND TIME: {command}") + self.console.info(f"COMMAND TIME: {command}") logger.debug(f"Sending command {command} to server") # send it @@ -647,7 +642,7 @@ class Server: f"The server {name} has crashed and will be restarted. " f"Restarting server" ) - console.warning( + self.console.critical( f"The server {name} has crashed and will be restarted. " f"Restarting server" ) @@ -658,7 +653,7 @@ class Server: f"The server {name} has crashed, " f"crash detection is disabled and it will not be restarted" ) - console.critical( + self.console.critical( f"The server {name} has crashed, " f"crash detection is disabled and it will not be restarted" ) @@ -710,7 +705,7 @@ class Server: self.server_scheduler.remove_job("c_" + str(self.server_id)) return - servers_helper.sever_crashed(self.server_id) + helper_servers.sever_crashed(self.server_id) # if we haven't tried to restart more 3 or more times if self.restart_count <= 3: @@ -727,21 +722,21 @@ class Server: f"Server {self.name} has been restarted {self.restart_count}" f" times. It has crashed, not restarting." ) - console.critical( + self.console.critical( f"Server {self.name} has been restarted {self.restart_count}" f" times. It has crashed, not restarting." ) self.restart_count = 0 self.is_crashed = True - servers_helper.sever_crashed(self.server_id) + helper_servers.sever_crashed(self.server_id) # cancel the watcher task self.server_scheduler.remove_job("c_" + str(self.server_id)) def remove_watcher_thread(self): logger.info("Removing old crash detection watcher thread") - console.info("Removing old crash detection watcher thread") + self.console.info("Removing old crash detection watcher thread") self.server_scheduler.remove_job("c_" + str(self.server_id)) def agree_eula(self, user_id): @@ -765,7 +760,7 @@ class Server: f"Starting Backup Thread for server {self.settings['server_name']}." ) if self.server_path is None: - self.server_path = helper.get_os_understandable_path(self.settings["path"]) + self.server_path = Helpers.get_os_understandable_path(self.settings["path"]) logger.info( "Backup Thread - Local server path not defined. " "Setting local server path variable." @@ -787,26 +782,26 @@ class Server: logger.info(f"Backup Thread started for server {self.settings['server_name']}.") def a_backup_server(self): - if len(websocket_helper.clients) > 0: - websocket_helper.broadcast_page_params( + if len(self.helper.websocket_helper.clients) > 0: + self.helper.websocket_helper.broadcast_page_params( "/panel/server_detail", {"id": str(self.server_id)}, "backup_reload", {"percent": 0, "total_files": 0}, ) logger.info(f"Starting server {self.name} (ID {self.server_id}) backup") - server_users = server_permissions.get_server_user_list(self.server_id) + server_users = Permissions_Servers.get_server_user_list(self.server_id) for user in server_users: - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user, "notification", - translation.translate( - "notify", "backupStarted", users_helper.get_user_lang_by_id(user) + self.helper.translation.translate( + "notify", "backupStarted", helper_users.get_user_lang_by_id(user) ).format(self.name), ) time.sleep(3) - conf = management_helper.get_backup_config(self.server_id) - helper.ensure_dir_exists(self.settings["backup_path"]) + conf = helpers_management.get_backup_config(self.server_id) + self.helper.ensure_dir_exists(self.settings["backup_path"]) try: backup_filename = ( f"{self.settings['backup_path']}/" @@ -827,23 +822,23 @@ class Server: args=[tempDir + "/", backup_filename + ".zip"], ) # pylint: disable=unexpected-keyword-arg - file_helper.copy_dir(self.server_path, tempDir, dirs_exist_ok=True) - excluded_dirs = management_helper.get_excluded_backup_dirs(self.server_id) - server_dir = helper.get_os_understandable_path(self.settings["path"]) + FileHelpers.copy_dir(self.server_path, tempDir, dirs_exist_ok=True) + excluded_dirs = helpers_management.get_excluded_backup_dirs(self.server_id) + server_dir = Helpers.get_os_understandable_path(self.settings["path"]) for my_dir in excluded_dirs: # Take the full path of the excluded dir and replace the # server path with the temp path, this is so that we're # only deleting excluded dirs from the temp path # and not the server path - excluded_dir = helper.get_os_understandable_path(my_dir).replace( - server_dir, helper.get_os_understandable_path(tempDir) + excluded_dir = Helpers.get_os_understandable_path(my_dir).replace( + server_dir, Helpers.get_os_understandable_path(tempDir) ) # Next, check to see if it is a directory if os.path.isdir(excluded_dir): # If it is a directory, # recursively delete the entire directory from the backup - file_helper.del_dirs(excluded_dir) + FileHelpers.del_dirs(excluded_dir) else: # If not, just remove the file os.remove(excluded_dir) @@ -851,15 +846,15 @@ class Server: logger.debug( "Found compress backup to be true. Calling compressed archive" ) - file_helper.make_compressed_archive( - helper.get_os_understandable_path(backup_filename), tempDir + FileHelpers.make_compressed_archive( + Helpers.get_os_understandable_path(backup_filename), tempDir ) else: logger.debug( "Found compress backup to be false. Calling NON-compressed archive" ) - file_helper.make_archive( - helper.get_os_understandable_path(backup_filename), tempDir + FileHelpers.make_archive( + Helpers.get_os_understandable_path(backup_filename), tempDir ) while ( @@ -870,29 +865,29 @@ class Server: oldfile = backup_list[0] oldfile_path = f"{conf['backup_path']}/{oldfile['path']}" logger.info(f"Removing old backup '{oldfile['path']}'") - os.remove(helper.get_os_understandable_path(oldfile_path)) + os.remove(Helpers.get_os_understandable_path(oldfile_path)) self.is_backingup = False - file_helper.del_dirs(tempDir) + FileHelpers.del_dirs(tempDir) logger.info(f"Backup of server: {self.name} completed") self.server_scheduler.remove_job("backup_" + str(self.server_id)) results = {"percent": 100, "total_files": 0, "current_file": 0} - if len(websocket_helper.clients) > 0: - websocket_helper.broadcast_page_params( + if len(self.helper.websocket_helper.clients) > 0: + self.helper.websocket_helper.broadcast_page_params( "/panel/server_detail", {"id": str(self.server_id)}, "backup_status", results, ) - server_users = server_permissions.get_server_user_list(self.server_id) + server_users = Permissions_Servers.get_server_user_list(self.server_id) for user in server_users: - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user, "notification", - translation.translate( + self.helper.translation.translate( "notify", "backupComplete", - users_helper.get_user_lang_by_id(user), + helper_users.get_user_lang_by_id(user), ).format(self.name), ) time.sleep(3) @@ -903,8 +898,8 @@ class Server: ) self.server_scheduler.remove_job("backup_" + str(self.server_id)) results = {"percent": 100, "total_files": 0, "current_file": 0} - if len(websocket_helper.clients) > 0: - websocket_helper.broadcast_page_params( + if len(self.helper.websocket_helper.clients) > 0: + self.helper.websocket_helper.broadcast_page_params( "/panel/server_detail", {"id": str(self.server_id)}, "backup_status", @@ -914,10 +909,10 @@ class Server: return def backup_status(self, source_path, dest_path): - results = helper.calc_percent(source_path, dest_path) + results = Helpers.calc_percent(source_path, dest_path) self.backup_stats = results - if len(websocket_helper.clients) > 0: - websocket_helper.broadcast_page_params( + if len(self.helper.websocket_helper.clients) > 0: + self.helper.websocket_helper.broadcast_page_params( "/panel/server_detail", {"id": str(self.server_id)}, "backup_status", @@ -932,19 +927,19 @@ class Server: def list_backups(self): if self.settings["backup_path"]: - if helper.check_path_exists( - helper.get_os_understandable_path(self.settings["backup_path"]) + if Helpers.check_path_exists( + Helpers.get_os_understandable_path(self.settings["backup_path"]) ): - files = helper.get_human_readable_files_sizes( - helper.list_dir_by_date( - helper.get_os_understandable_path(self.settings["backup_path"]) + files = Helpers.get_human_readable_files_sizes( + Helpers.list_dir_by_date( + Helpers.get_os_understandable_path(self.settings["backup_path"]) ) ) return [ { "path": os.path.relpath( f["path"], - start=helper.get_os_understandable_path( + start=Helpers.get_os_understandable_path( self.settings["backup_path"] ), ), @@ -961,7 +956,7 @@ class Server: return [] def jar_update(self): - servers_helper.set_update(self.server_id, True) + helper_servers.set_update(self.server_id, True) update_thread = threading.Thread( target=self.a_jar_update, daemon=True, name=f"exe_update_{self.name}" ) @@ -969,7 +964,7 @@ class Server: def check_update(self): - if servers_helper.get_server_stats_by_id(self.server_id)["updating"]: + if helper_servers.get_server_stats_by_id(self.server_id)["updating"]: return True else: return False @@ -987,13 +982,13 @@ class Server: self.stop_threaded_server() else: wasStarted = False - if len(websocket_helper.clients) > 0: + if len(self.helper.websocket_helper.clients) > 0: # There are clients self.check_update() message = ( ' UPDATING...' ) - websocket_helper.broadcast_page( + self.helper.websocket_helper.broadcast_page( "/panel/server_detail", "update_button_status", { @@ -1003,9 +998,9 @@ class Server: "string": message, }, ) - websocket_helper.broadcast_page("/panel/dashboard", "send_start_reload", {}) + self.helper.websocket_helper.broadcast_page("/panel/dashboard", "send_start_reload", {}) backup_dir = os.path.join( - helper.get_os_understandable_path(self.settings["path"]), + Helpers.get_os_understandable_path(self.settings["path"]), "crafty_executable_backups", ) # checks if backup directory already exists @@ -1028,37 +1023,37 @@ class Server: logger.info(f"No old backups found for server: {self.name}") current_executable = os.path.join( - helper.get_os_understandable_path(self.settings["path"]), + Helpers.get_os_understandable_path(self.settings["path"]), self.settings["executable"], ) # copies to backup dir - helper.copy_files(current_executable, backup_executable) + Helpers.copy_files(current_executable, backup_executable) # boolean returns true for false for success - downloaded = helper.download_file( + downloaded = Helpers.download_file( self.settings["executable_update_url"], current_executable ) - while servers_helper.get_server_stats_by_id(self.server_id)["updating"]: + while helper_servers.get_server_stats_by_id(self.server_id)["updating"]: if downloaded and not self.is_backingup: logger.info("Executable updated successfully. Starting Server") - servers_helper.set_update(self.server_id, False) - if len(websocket_helper.clients) > 0: + helper_servers.set_update(self.server_id, False) + if len(self.helper.websocket_helper.clients) > 0: # There are clients self.check_update() - server_users = server_permissions.get_server_user_list( + server_users = Permissions_Servers.get_server_user_list( self.server_id ) for user in server_users: - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user, "notification", "Executable update finished for " + self.name, ) time.sleep(3) - websocket_helper.broadcast_page( + self.helper.websocket_helper.broadcast_page( "/panel/server_detail", "update_button_status", { @@ -1067,18 +1062,18 @@ class Server: "wasRunning": wasStarted, }, ) - websocket_helper.broadcast_page( + self.helper.websocket_helper.broadcast_page( "/panel/dashboard", "send_start_reload", {} ) - server_users = server_permissions.get_server_user_list(self.server_id) + server_users = Permissions_Servers.get_server_user_list(self.server_id) for user in server_users: - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user, "notification", "Executable update finished for " + self.name, ) - management_helper.add_to_audit_log_raw( + self.management_helper.add_to_audit_log_raw( "Alert", "-1", self.server_id, @@ -1089,9 +1084,9 @@ class Server: self.start_server() elif not downloaded and not self.is_backingup: time.sleep(5) - server_users = server_permissions.get_server_user_list(self.server_id) + server_users = Permissions_Servers.get_server_user_list(self.server_id) for user in server_users: - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user, "notification", "Executable update failed for " @@ -1134,8 +1129,8 @@ class Server: "icon": raw_ping_result.get("icon"), } ) - if len(websocket_helper.clients) > 0: - websocket_helper.broadcast_page_params( + if len(self.helper.websocket_helper.clients) > 0: + self.helper.websocket_helper.broadcast_page_params( "/panel/server_detail", {"id": str(self.server_id)}, "update_server_details", @@ -1163,16 +1158,16 @@ class Server: self.record_server_stats() - if (len(servers_ping) > 0) & (len(websocket_helper.clients) > 0): + if (len(servers_ping) > 0) & (len(self.helper.websocket_helper.clients) > 0): try: - websocket_helper.broadcast_page( + self.helper.websocket_helper.broadcast_page( "/panel/dashboard", "update_server_status", servers_ping ) - websocket_helper.broadcast_page( + self.helper.websocket_helper.broadcast_page( "/status", "update_server_status", servers_ping ) except: - console.warning("Can't broadcast server status to websocket") + self.console.critical("Can't broadcast server status to websocket") def get_servers_stats(self): @@ -1181,7 +1176,7 @@ class Server: logger.info("Getting Stats for Server " + self.name + " ...") server_id = self.server_id - server = servers_helper.get_server_data_by_id(server_id) + server = helper_servers.get_server_data_by_id(server_id) logger.debug(f"Getting stats for server: {server_id}") @@ -1200,7 +1195,7 @@ class Server: server_name = server.get("server_name", f"ID#{server_id}") logger.debug("Pinging server '{server}' on {internal_ip}:{server_port}") - if servers_helper.get_server_type_by_id(server_id) == "minecraft-bedrock": + if helper_servers.get_server_type_by_id(server_id) == "minecraft-bedrock": int_mc_ping = ping_bedrock(internal_ip, int(server_port)) else: int_mc_ping = ping(internal_ip, int(server_port)) @@ -1212,7 +1207,7 @@ class Server: if int_mc_ping: int_data = True if ( - servers_helper.get_server_type_by_id(server["server_id"]) + helper_servers.get_server_type_by_id(server["server_id"]) == "minecraft-bedrock" ): ping_data = Stats.parse_server_RakNet_ping(int_mc_ping) @@ -1261,7 +1256,7 @@ class Server: def get_server_players(self): - server = servers_helper.get_server_data_by_id(self.server_id) + server = helper_servers.get_server_data_by_id(self.server_id) logger.info(f"Getting players for server {server}") @@ -1274,7 +1269,7 @@ class Server: server_port = server["server_port"] logger.debug("Pinging {internal_ip} on port {server_port}") - if servers_helper.get_server_type_by_id(self.server_id) != "minecraft-bedrock": + if helper_servers.get_server_type_by_id(self.server_id) != "minecraft-bedrock": int_mc_ping = ping(internal_ip, int(server_port)) ping_data = {} @@ -1288,7 +1283,7 @@ class Server: def get_raw_server_stats(self, server_id): try: - server = servers_helper.get_server_obj(server_id) + server = helper_servers.get_server_obj(server_id) except: return { "id": server_id, @@ -1310,10 +1305,10 @@ class Server: } server_stats = {} - server = servers_helper.get_server_obj(server_id) + server = helper_servers.get_server_obj(server_id) if not server: return {} - server_dt = servers_helper.get_server_data_by_id(server_id) + server_dt = helper_servers.get_server_data_by_id(server_id) logger.debug(f"Getting stats for server: {server_id}") @@ -1334,7 +1329,7 @@ class Server: server_port = server_dt["server_port"] logger.debug(f"Pinging server '{self.name}' on {internal_ip}:{server_port}") - if servers_helper.get_server_type_by_id(server_id) == "minecraft-bedrock": + if helper_servers.get_server_type_by_id(server_id) == "minecraft-bedrock": int_mc_ping = ping_bedrock(internal_ip, int(server_port)) else: int_mc_ping = ping(internal_ip, int(server_port)) @@ -1345,7 +1340,7 @@ class Server: # otherwise people have gotten confused. if self.check_running(): # if we got a good ping return, let's parse it - if servers_helper.get_server_type_by_id(server_id) != "minecraft-bedrock": + if helper_servers.get_server_type_by_id(server_id) != "minecraft-bedrock": if int_mc_ping: int_data = True ping_data = Stats.parse_server_ping(int_mc_ping) @@ -1461,7 +1456,7 @@ class Server: ).execute() # delete old data - max_age = helper.get_setting("history_max_age") + max_age = self.helper.get_setting("history_max_age") now = datetime.datetime.now() last_week = now.day - max_age diff --git a/app/classes/shared/tasks.py b/app/classes/shared/tasks.py index edb9e14e..42725157 100644 --- a/app/classes/shared/tasks.py +++ b/app/classes/shared/tasks.py @@ -4,24 +4,14 @@ import logging import threading import asyncio import datetime +from tzlocal import get_localzone +from apscheduler.events import EVENT_JOB_EXECUTED +from apscheduler.schedulers.background import BackgroundScheduler +from apscheduler.triggers.cron import CronTrigger -from app.classes.controllers.users_controller import Users_Controller -from app.classes.minecraft.serverjars import server_jar_obj -from app.classes.models.management import management_helper -from app.classes.models.users import users_helper -from app.classes.shared.helpers import helper -from app.classes.shared.console import console +from app.classes.models.management import helpers_management +from app.classes.models.users import helper_users from app.classes.web.tornado_handler import Webserver -from app.classes.web.websocket_helper import websocket_helper - -try: - from tzlocal import get_localzone - from apscheduler.events import EVENT_JOB_EXECUTED - from apscheduler.schedulers.background import BackgroundScheduler - from apscheduler.triggers.cron import CronTrigger - -except ModuleNotFoundError as err: - helper.auto_installer_fix(err) logger = logging.getLogger("apscheduler") scheduler_intervals = { @@ -41,14 +31,15 @@ scheduler_intervals = { class TasksManager: - def __init__(self, controller): + def __init__(self, helper, controller): + self.helper = helper self.controller = controller - self.tornado = Webserver(controller, self) + self.tornado = Webserver(helper, controller, self) self.tz = get_localzone() self.scheduler = BackgroundScheduler(timezone=str(self.tz)) - self.users_controller = Users_Controller() + self.users_controller = self.controller.users self.webserver_thread = threading.Thread( target=self.tornado.run_tornado, daemon=True, name="tornado_thread" @@ -78,7 +69,7 @@ class TasksManager: return self.main_thread_exiting def reload_schedule_from_db(self): - jobs = management_helper.get_schedules_enabled() + jobs = helpers_management.get_schedules_enabled() logger.info("Reload from DB called. Current enabled schedules: ") for item in jobs: logger.info(f"JOB: {item}") @@ -86,7 +77,7 @@ class TasksManager: def command_watcher(self): while True: # select any commands waiting to be processed - commands = management_helper.get_unactioned_commands() + commands = helpers_management.get_unactioned_commands() for c in commands: try: svr = self.controller.get_server_obj(c.server_id) @@ -95,7 +86,7 @@ class TasksManager: "Server value requested does note exist! " "Purging item from waiting commands." ) - management_helper.mark_command_complete(c.command_id) + helpers_management.mark_command_complete(c.command_id) user_id = c.user_id command = c.command @@ -116,19 +107,19 @@ class TasksManager: svr.jar_update() else: svr.send_command(command) - management_helper.mark_command_complete(c.command_id) + helpers_management.mark_command_complete(c.command_id) time.sleep(1) def _main_graceful_exit(self): try: - os.remove(helper.session_file) + os.remove(self.helper.session_file) self.controller.stop_all_servers() except: logger.info("Caught error during shutdown", exc_info=True) logger.info("***** Crafty Shutting Down *****\n\n") - console.info("***** Crafty Shutting Down *****\n\n") + self.helper.console.info("***** Crafty Shutting Down *****\n\n") self.main_thread_exiting = True def start_webserver(self): @@ -136,7 +127,7 @@ class TasksManager: def reload_webserver(self): self.tornado.stop_web_server() - console.info("Waiting 3 seconds") + self.helper.console.info("Waiting 3 seconds") time.sleep(3) self.webserver_thread = threading.Thread( target=self.tornado.run_tornado, daemon=True, name="tornado_thread" @@ -148,20 +139,20 @@ class TasksManager: def start_scheduler(self): logger.info("Launching Scheduler Thread...") - console.info("Launching Scheduler Thread...") + self.helper.console.info("Launching Scheduler Thread...") self.schedule_thread.start() logger.info("Launching command thread...") - console.info("Launching command thread...") + self.helper.console.info("Launching command thread...") self.command_thread.start() logger.info("Launching log watcher...") - console.info("Launching log watcher...") + self.helper.console.info("Launching log watcher...") self.log_watcher_thread.start() logger.info("Launching realtime thread...") - console.info("Launching realtime thread...") + self.helper.console.info("Launching realtime thread...") self.realtime_thread.start() def scheduler_thread(self): - schedules = management_helper.get_schedules_enabled() + schedules = helpers_management.get_schedules_enabled() self.scheduler.add_listener(self.schedule_watcher, mask=EVENT_JOB_EXECUTED) # self.scheduler.add_job( # self.scheduler.print_jobs, "interval", seconds=10, id="-1" @@ -173,7 +164,7 @@ class TasksManager: if schedule.cron_string != "": try: self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, CronTrigger.from_crontab( schedule.cron_string, timezone=str(self.tz) ), @@ -186,16 +177,16 @@ class TasksManager: ], ) except Exception as e: - console.error(f"Failed to schedule task with error: {e}.") - console.warning("Removing failed task from DB.") + self.helper.console.error(f"Failed to schedule task with error: {e}.") + self.helper.console.warning("Removing failed task from DB.") logger.error(f"Failed to schedule task with error: {e}.") logger.warning("Removing failed task from DB.") # remove items from DB if task fails to add to apscheduler - management_helper.delete_scheduled_task(schedule.schedule_id) + self.controller.management_helper.delete_scheduled_task(schedule.schedule_id) else: if schedule.interval_type == "hours": self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, "cron", minute=0, hour="*/" + str(schedule.interval), @@ -209,7 +200,7 @@ class TasksManager: ) elif schedule.interval_type == "minutes": self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, "cron", minute="*/" + str(schedule.interval), id=str(schedule.schedule_id), @@ -223,7 +214,7 @@ class TasksManager: elif schedule.interval_type == "days": curr_time = schedule.start_time.split(":") self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, "cron", day="*/" + str(schedule.interval), hour=curr_time[0], @@ -243,7 +234,7 @@ class TasksManager: logger.info(f"JOB: {item}") def schedule_job(self, job_data): - sch_id = management_helper.create_scheduled_task( + sch_id = helpers_management.create_scheduled_task( job_data["server_id"], job_data["action"], job_data["interval"], @@ -260,13 +251,13 @@ class TasksManager: # Checks to make sure some doofus didn't actually make the newly # created task a child of itself. if str(job_data["parent"]) == str(sch_id): - management_helper.update_scheduled_task(sch_id, {"parent": None}) + helpers_management.update_scheduled_task(sch_id, {"parent": None}) # Check to see if it's enabled and is not a chain reaction. if job_data["enabled"] and job_data["interval_type"] != "reaction": if job_data["cron_string"] != "": try: self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, CronTrigger.from_crontab( job_data["cron_string"], timezone=str(self.tz) ), @@ -279,16 +270,16 @@ class TasksManager: ], ) except Exception as e: - console.error(f"Failed to schedule task with error: {e}.") - console.warning("Removing failed task from DB.") + self.helper.console.error(f"Failed to schedule task with error: {e}.") + self.helper.console.warning("Removing failed task from DB.") logger.error(f"Failed to schedule task with error: {e}.") logger.warning("Removing failed task from DB.") # remove items from DB if task fails to add to apscheduler - management_helper.delete_scheduled_task(sch_id) + self.controller.management_helper.delete_scheduled_task(sch_id) else: if job_data["interval_type"] == "hours": self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, "cron", minute=0, hour="*/" + str(job_data["interval"]), @@ -302,7 +293,7 @@ class TasksManager: ) elif job_data["interval_type"] == "minutes": self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, "cron", minute="*/" + str(job_data["interval"]), id=str(sch_id), @@ -316,7 +307,7 @@ class TasksManager: elif job_data["interval_type"] == "days": curr_time = job_data["start_time"].split(":") self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, "cron", day="*/" + str(job_data["interval"]), hour=curr_time[0], @@ -335,18 +326,18 @@ class TasksManager: logger.info(f"JOB: {item}") def remove_all_server_tasks(self, server_id): - schedules = management_helper.get_schedules_by_server(server_id) + schedules = helpers_management.get_schedules_by_server(server_id) for schedule in schedules: if schedule.interval != "reaction": self.remove_job(schedule.schedule_id) def remove_job(self, sch_id): - job = management_helper.get_scheduled_task_model(sch_id) - for schedule in management_helper.get_child_schedules(sch_id): - management_helper.update_scheduled_task( + job = helpers_management.get_scheduled_task_model(sch_id) + for schedule in helpers_management.get_child_schedules(sch_id): + self.controller.management_helper.update_scheduled_task( schedule.schedule_id, {"parent": None} ) - management_helper.delete_scheduled_task(sch_id) + self.controller.management_helper.delete_scheduled_task(sch_id) if job.enabled and job.interval_type != "reaction": self.scheduler.remove_job(str(sch_id)) logger.info(f"Job with ID {sch_id} was deleted.") @@ -358,11 +349,11 @@ class TasksManager: ) def update_job(self, sch_id, job_data): - management_helper.update_scheduled_task(sch_id, job_data) + helpers_management.update_scheduled_task(sch_id, job_data) # Checks to make sure some doofus didn't actually make the newly # created task a child of itself. if str(job_data["parent"]) == str(sch_id): - management_helper.update_scheduled_task(sch_id, {"parent": None}) + helpers_management.update_scheduled_task(sch_id, {"parent": None}) try: if job_data["interval"] != "reaction": self.scheduler.remove_job(str(sch_id)) @@ -377,7 +368,7 @@ class TasksManager: if job_data["cron_string"] != "": try: self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, CronTrigger.from_crontab( job_data["cron_string"], timezone=str(self.tz) ), @@ -390,13 +381,13 @@ class TasksManager: ], ) except Exception as e: - console.error(f"Failed to schedule task with error: {e}.") - console.info("Removing failed task from DB.") - management_helper.delete_scheduled_task(sch_id) + self.helper.console.error(f"Failed to schedule task with error: {e}.") + self.helper.console.info("Removing failed task from DB.") + self.controller.management_helper.delete_scheduled_task(sch_id) else: if job_data["interval_type"] == "hours": self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, "cron", minute=0, hour="*/" + str(job_data["interval"]), @@ -410,7 +401,7 @@ class TasksManager: ) elif job_data["interval_type"] == "minutes": self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, "cron", minute="*/" + str(job_data["interval"]), id=str(sch_id), @@ -424,7 +415,7 @@ class TasksManager: elif job_data["interval_type"] == "days": curr_time = job_data["start_time"].split(":") self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, "cron", day="*/" + str(job_data["interval"]), hour=curr_time[0], @@ -450,10 +441,10 @@ class TasksManager: def schedule_watcher(self, event): if not event.exception: if str(event.job_id).isnumeric(): - task = management_helper.get_scheduled_task_model(int(event.job_id)) - management_helper.add_to_audit_log_raw( + task = helpers_management.get_scheduled_task_model(int(event.job_id)) + helpers_management.add_to_audit_log_raw( "system", - users_helper.get_user_id_by_name("system"), + helper_users.get_user_id_by_name("system"), task.server_id, f"Task with id {task.schedule_id} completed successfully", "127.0.0.1", @@ -465,7 +456,7 @@ class TasksManager: # check for any child tasks for this. It's kind of backward, # but this makes DB management a lot easier. One to one # instead of one to many. - for schedule in management_helper.get_child_schedules_by_server( + for schedule in helpers_management.get_child_schedules_by_server( task.schedule_id, task.server_id ): # event job ID's are strings so we need to look at @@ -476,7 +467,7 @@ class TasksManager: seconds=schedule.delay ) self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, "date", run_date=delaytime, id=str(schedule.schedule_id), @@ -496,11 +487,11 @@ class TasksManager: logger.error(f"Task failed with error: {event.exception}") def start_stats_recording(self): - stats_update_frequency = helper.get_setting("stats_update_frequency") + stats_update_frequency = self.helper.get_setting("stats_update_frequency") logger.info( f"Stats collection frequency set to {stats_update_frequency} seconds" ) - console.info( + self.helper.console.info( f"Stats collection frequency set to {stats_update_frequency} seconds" ) @@ -516,36 +507,36 @@ class TasksManager: def serverjar_cache_refresher(self): logger.info("Refreshing serverjars.com cache on start") - server_jar_obj.refresh_cache() + self.controller.server_jars.refresh_cache() logger.info("Scheduling Serverjars.com cache refresh service every 12 hours") self.scheduler.add_job( - server_jar_obj.refresh_cache, "interval", hours=12, id="serverjars" + self.controller.server_jars.refresh_cache, "interval", hours=12, id="serverjars" ) def realtime(self): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) - host_stats = management_helper.get_latest_hosts_stats() + host_stats = helpers_management.get_latest_hosts_stats() while True: if host_stats.get( "cpu_usage" - ) != management_helper.get_latest_hosts_stats().get( + ) != helpers_management.get_latest_hosts_stats().get( "cpu_usage" ) or host_stats.get( "mem_percent" - ) != management_helper.get_latest_hosts_stats().get( + ) != helpers_management.get_latest_hosts_stats().get( "mem_percent" ): # Stats are different - host_stats = management_helper.get_latest_hosts_stats() - if len(websocket_helper.clients) > 0: + host_stats = helpers_management.get_latest_hosts_stats() + if len(self.helper.websocket_helper.clients) > 0: # There are clients - websocket_helper.broadcast_page( + self.helper.websocket_helper.broadcast_page( "/panel/dashboard", "update_host_stats", { diff --git a/app/classes/shared/translation.py b/app/classes/shared/translation.py index 22ee1d81..b283a393 100644 --- a/app/classes/shared/translation.py +++ b/app/classes/shared/translation.py @@ -3,15 +3,13 @@ import logging import os import typing as t -from app.classes.shared.console import console -from app.classes.shared.helpers import helper - logger = logging.getLogger(__name__) class Translation: - def __init__(self): - self.translations_path = os.path.join(helper.root_dir, "app", "translations") + def __init__(self, helper): + self.helper = helper + self.translations_path = os.path.join(self.helper.root_dir, "app", "translations") self.cached_translation = None self.cached_translation_lang = None @@ -59,7 +57,7 @@ class Translation: f"Translation File Error: page {page} " f"does not exist for lang {language}" ) - console.error( + self.helper.console.error( f"Translation File Error: page {page} " f"does not exist for lang {language}" ) @@ -73,7 +71,7 @@ class Translation: f"Translation File Error: word {word} does not exist on page " f"{page} for lang {language}" ) - console.error( + self.helper.console.error( f"Translation File Error: word {word} does not exist on page " f"{page} for lang {language}" ) @@ -83,10 +81,7 @@ class Translation: logger.critical( f"Translation File Error: Unable to read {language_file} due to {e}" ) - console.critical( + self.helper.console.critical( f"Translation File Error: Unable to read {language_file} due to {e}" ) return None - - -translation = Translation() diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index eca70e88..bf8cb142 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -3,23 +3,15 @@ import html import re import logging import time +import bleach +import tornado.web +import tornado.escape from app.classes.models.server_permissions import Enum_Permissions_Server -from app.classes.shared.console import console -from app.classes.shared.helpers import helper -from app.classes.shared.translation import translation +from app.classes.shared.helpers import Helpers from app.classes.shared.server import ServerOutBuf -from app.classes.web.websocket_helper import websocket_helper from app.classes.web.base_handler import BaseHandler -try: - import bleach - import tornado.web - import tornado.escape - -except ModuleNotFoundError as ex: - helper.auto_installer_fix(ex) - logger = logging.getLogger(__name__) @@ -67,9 +59,9 @@ class AjaxHandler(BaseHandler): ) if full_log: - log_lines = helper.get_setting("max_log_lines") - data = helper.tail_file( - helper.get_os_understandable_path(server_data["log_path"]), + log_lines = self.helper.get_setting("max_log_lines") + data = Helpers.tail_file( + Helpers.get_os_understandable_path(server_data["log_path"]), log_lines, ) else: @@ -79,7 +71,7 @@ class AjaxHandler(BaseHandler): try: d = re.sub("(\033\\[(0;)?[0-9]*[A-z]?(;[0-9])?m?)|(> )", "", d) d = re.sub("[A-z]{2}\b\b", "", d) - line = helper.log_colors(html.escape(d)) + line = self.helper.log_colors(html.escape(d)) self.write(f"{line}
    ") # self.write(d.encode("utf-8")) @@ -87,7 +79,7 @@ class AjaxHandler(BaseHandler): logger.warning(f"Skipping Log Line due to error: {e}") elif page == "announcements": - data = helper.get_announcements() + data = Helpers.get_announcements() page_data["notify_data"] = data self.render_page("ajax/notify.html", page_data) @@ -95,9 +87,9 @@ class AjaxHandler(BaseHandler): path = self.get_argument("path", None) self.write( - helper.get_os_understandable_path(path) + Helpers.get_os_understandable_path(path) + "\n" - + helper.generate_zip_tree(path) + + Helpers.generate_zip_tree(path) ) self.finish() @@ -105,9 +97,9 @@ class AjaxHandler(BaseHandler): path = self.get_argument("path", None) self.write( - helper.get_os_understandable_path(path) + Helpers.get_os_understandable_path(path) + "\n" - + helper.generate_zip_dir(path) + + Helpers.generate_zip_dir(path) ) self.finish() @@ -175,7 +167,7 @@ class AjaxHandler(BaseHandler): onclick=""> {filename}
  • """ - self.write(helper.get_os_understandable_path(folder) + "\n" + output) + self.write(Helpers.get_os_understandable_path(folder) + "\n" + output) self.finish() elif page == "get_backup_dir": @@ -240,7 +232,7 @@ class AjaxHandler(BaseHandler): {filename}""" - self.write(helper.get_os_understandable_path(folder) + "\n" + output) + self.write(Helpers.get_os_understandable_path(folder) + "\n" + output) self.finish() elif page == "get_dir": @@ -252,13 +244,13 @@ class AjaxHandler(BaseHandler): else: server_id = bleach.clean(server_id) - if helper.validate_traversal( + if Helpers.validate_traversal( self.controller.servers.get_server_data_by_id(server_id)["path"], path ): self.write( - helper.get_os_understandable_path(path) + Helpers.get_os_understandable_path(path) + "\n" - + helper.generate_dir(path) + + Helpers.generate_dir(path) ) self.finish() @@ -291,7 +283,7 @@ class AjaxHandler(BaseHandler): if server_id is None: logger.warning("Server ID not found in send_command ajax call") - console.warning("Server ID not found in send_command ajax call") + self.helper.console.warning("Server ID not found in send_command ajax call") srv_obj = self.controller.get_server_obj(server_id) @@ -390,8 +382,8 @@ class AjaxHandler(BaseHandler): server_data = self.controller.servers.get_server_data_by_id(server_id) if server_data["type"] == "minecraft-java": backup_path = svr_obj.backup_path - if helper.validate_traversal(backup_path, zip_name): - tempDir = helper.unzip_backup_archive(backup_path, zip_name) + if Helpers.validate_traversal(backup_path, zip_name): + tempDir = Helpers.unzip_backup_archive(backup_path, zip_name) new_server = self.controller.import_zip_server( svr_obj.server_name, tempDir, @@ -410,8 +402,8 @@ class AjaxHandler(BaseHandler): else: backup_path = svr_obj.backup_path - if helper.validate_traversal(backup_path, zip_name): - tempDir = helper.unzip_backup_archive(backup_path, zip_name) + if Helpers.validate_traversal(backup_path, zip_name): + tempDir = Helpers.unzip_backup_archive(backup_path, zip_name) new_server = self.controller.import_bedrock_zip_server( svr_obj.server_name, tempDir, @@ -428,23 +420,23 @@ class AjaxHandler(BaseHandler): elif page == "unzip_server": path = self.get_argument("path", None) - if helper.check_file_exists(path): - helper.unzipServer(path, exec_user["user_id"]) + if Helpers.check_file_exists(path): + Helpers.unzipServer(path, exec_user["user_id"]) else: user_id = exec_user["user_id"] if user_id: time.sleep(5) user_lang = self.controller.users.get_user_lang_by_id(user_id) - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user_id, "send_start_error", - {"error": translation.translate("error", "no-file", user_lang)}, + {"error": self.helper.translation.translate("error", "no-file", user_lang)}, ) return elif page == "backup_select": path = self.get_argument("path", None) - helper.backup_select(path, exec_user["user_id"]) + self.helper.backup_select(path, exec_user["user_id"]) return @tornado.web.authenticated @@ -481,12 +473,12 @@ class AjaxHandler(BaseHandler): if not superuser: self.redirect("/panel/error?error=Unauthorized access to Backups") return - file_path = helper.get_os_understandable_path( + file_path = Helpers.get_os_understandable_path( self.get_body_argument("file_path", default=None, strip=True) ) server_id = self.get_argument("id", None) - console.warning(f"Delete {file_path} for server {server_id}") + self.helper.console.warning(f"Delete {file_path} for server {server_id}") if not self.check_server_id(server_id, "del_backup"): return @@ -495,21 +487,21 @@ class AjaxHandler(BaseHandler): server_info = self.controller.servers.get_server_data_by_id(server_id) if not ( - helper.in_path( - helper.get_os_understandable_path(server_info["path"]), file_path + Helpers.in_path( + Helpers.get_os_understandable_path(server_info["path"]), file_path ) - or helper.in_path( - helper.get_os_understandable_path(server_info["backup_path"]), + or Helpers.in_path( + Helpers.get_os_understandable_path(server_info["backup_path"]), file_path, ) - ) or not helper.check_file_exists(os.path.abspath(file_path)): + ) or not Helpers.check_file_exists(os.path.abspath(file_path)): logger.warning(f"Invalid path in del_backup ajax call ({file_path})") - console.warning(f"Invalid path in del_backup ajax call ({file_path})") + self.helper.console.warning(f"Invalid path in del_backup ajax call ({file_path})") return # Delete the file - if helper.validate_traversal( - helper.get_os_understandable_path(server_info["backup_path"]), file_path + if Helpers.validate_traversal( + Helpers.get_os_understandable_path(server_info["backup_path"]), file_path ): os.remove(file_path) @@ -566,7 +558,7 @@ class AjaxHandler(BaseHandler): logger.warning( f"Server ID not defined in {page_name} ajax call ({server_id})" ) - console.warning( + self.helper.console.warning( f"Server ID not defined in {page_name} ajax call ({server_id})" ) return @@ -578,7 +570,7 @@ class AjaxHandler(BaseHandler): logger.warning( f"Server ID not found in {page_name} ajax call ({server_id})" ) - console.warning( + self.helper.console.warning( f"Server ID not found in {page_name} ajax call ({server_id})" ) return diff --git a/app/classes/web/base_handler.py b/app/classes/web/base_handler.py index d8fe6c95..d06c0c78 100644 --- a/app/classes/web/base_handler.py +++ b/app/classes/web/base_handler.py @@ -1,21 +1,12 @@ import logging from typing import Union, List, Optional, Tuple, Dict, Any +import bleach +import tornado.web from app.classes.models.users import ApiKeys -from app.classes.shared.authentication import authentication -from app.classes.shared.main_controller import Controller -from app.classes.shared.helpers import helper - -try: - import tornado.web - import bleach - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) logger = logging.getLogger(__name__) - class BaseHandler(tornado.web.RequestHandler): nobleach = {bool, type(None)} @@ -23,8 +14,9 @@ class BaseHandler(tornado.web.RequestHandler): # noinspection PyAttributeOutsideInit def initialize( - self, controller: Controller = None, tasks_manager=None, translator=None + self, helper=None, controller=None, tasks_manager=None, translator=None ): + self.helper = helper self.controller = controller self.tasks_manager = tasks_manager self.translator = translator @@ -42,7 +34,7 @@ class BaseHandler(tornado.web.RequestHandler): def get_current_user( self, ) -> Optional[Tuple[Optional[ApiKeys], Dict[str, Any], Dict[str, Any]]]: - return authentication.check(self.get_cookie("token")) + return self.controller.authentication.check(self.get_cookie("token")) def autobleach(self, name, text): for r in self.redactables: diff --git a/app/classes/web/file_handler.py b/app/classes/web/file_handler.py index 49c45a9a..9f7634d6 100644 --- a/app/classes/web/file_handler.py +++ b/app/classes/web/file_handler.py @@ -1,23 +1,16 @@ import os import logging +import bleach +import tornado.web +import tornado.escape from app.classes.models.server_permissions import Enum_Permissions_Server -from app.classes.shared.console import console -from app.classes.shared.helpers import helper -from app.classes.shared.file_helpers import file_helper +from app.classes.shared.helpers import Helpers +from app.classes.shared.file_helpers import FileHelpers from app.classes.web.base_handler import BaseHandler - -try: - import bleach - import tornado.web - import tornado.escape - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) - + logger = logging.getLogger(__name__) - class FileHandler(BaseHandler): def render_page(self, template, page_data): self.render( @@ -54,7 +47,7 @@ class FileHandler(BaseHandler): if not superuser: self.redirect("/panel/error?error=Unauthorized access to Files") return - file_path = helper.get_os_understandable_path( + file_path = Helpers.get_os_understandable_path( self.get_argument("file_path", None) ) @@ -63,16 +56,16 @@ class FileHandler(BaseHandler): else: server_id = bleach.clean(server_id) - if not helper.in_path( - helper.get_os_understandable_path( + if not Helpers.in_path( + Helpers.get_os_understandable_path( self.controller.servers.get_server_data_by_id(server_id)["path"] ), file_path, - ) or not helper.check_file_exists(os.path.abspath(file_path)): + ) or not Helpers.check_file_exists(os.path.abspath(file_path)): logger.warning( f"Invalid path in get_file file file ajax call ({file_path})" ) - console.warning( + self.helper.self.helper.console.warning( f"Invalid path in get_file file file ajax call ({file_path})" ) return @@ -101,13 +94,13 @@ class FileHandler(BaseHandler): else: server_id = bleach.clean(server_id) - if helper.validate_traversal( + if Helpers.validate_traversal( self.controller.servers.get_server_data_by_id(server_id)["path"], path ): self.write( - helper.get_os_understandable_path(path) + Helpers.get_os_understandable_path(path) + "\n" - + helper.generate_tree(path) + + Helpers.generate_tree(path) ) self.finish() @@ -123,13 +116,13 @@ class FileHandler(BaseHandler): else: server_id = bleach.clean(server_id) - if helper.validate_traversal( + if Helpers.validate_traversal( self.controller.servers.get_server_data_by_id(server_id)["path"], path ): self.write( - helper.get_os_understandable_path(path) + Helpers.get_os_understandable_path(path) + "\n" - + helper.generate_dir(path) + + Helpers.generate_dir(path) ) self.finish() @@ -161,7 +154,7 @@ class FileHandler(BaseHandler): if not superuser: self.redirect("/panel/error?error=Unauthorized access to Files") return - file_parent = helper.get_os_understandable_path( + file_parent = Helpers.get_os_understandable_path( self.get_body_argument("file_parent", default=None, strip=True) ) file_name = self.get_body_argument("file_name", default=None, strip=True) @@ -172,16 +165,16 @@ class FileHandler(BaseHandler): else: server_id = bleach.clean(server_id) - if not helper.in_path( - helper.get_os_understandable_path( + if not Helpers.in_path( + Helpers.get_os_understandable_path( self.controller.servers.get_server_data_by_id(server_id)["path"] ), file_path, - ) or helper.check_file_exists(os.path.abspath(file_path)): + ) or Helpers.check_file_exists(os.path.abspath(file_path)): logger.warning( f"Invalid path in create_file file ajax call ({file_path})" ) - console.warning( + self.helper.self.helper.console.warning( f"Invalid path in create_file file ajax call ({file_path})" ) return @@ -195,7 +188,7 @@ class FileHandler(BaseHandler): if not superuser: self.redirect("/panel/error?error=Unauthorized access to Files") return - dir_parent = helper.get_os_understandable_path( + dir_parent = Helpers.get_os_understandable_path( self.get_body_argument("dir_parent", default=None, strip=True) ) dir_name = self.get_body_argument("dir_name", default=None, strip=True) @@ -206,16 +199,16 @@ class FileHandler(BaseHandler): else: server_id = bleach.clean(server_id) - if not helper.in_path( - helper.get_os_understandable_path( + if not Helpers.in_path( + Helpers.get_os_understandable_path( self.controller.servers.get_server_data_by_id(server_id)["path"] ), dir_path, - ) or helper.check_path_exists(os.path.abspath(dir_path)): + ) or Helpers.check_path_exists(os.path.abspath(dir_path)): logger.warning( f"Invalid path in create_dir file ajax call ({dir_path})" ) - console.warning( + self.helper.self.helper.console.warning( f"Invalid path in create_dir file ajax call ({dir_path})" ) return @@ -227,8 +220,8 @@ class FileHandler(BaseHandler): if not superuser: self.redirect("/panel/error?error=Unauthorized access to Files") return - path = helper.get_os_understandable_path(self.get_argument("path", None)) - helper.unzipFile(path) + path = Helpers.get_os_understandable_path(self.get_argument("path", None)) + Helpers.unzipFile(path) self.redirect(f"/panel/server_detail?id={server_id}&subpage=files") return @@ -259,11 +252,11 @@ class FileHandler(BaseHandler): if not superuser: self.redirect("/panel/error?error=Unauthorized access to Files") return - file_path = helper.get_os_understandable_path( + file_path = Helpers.get_os_understandable_path( self.get_body_argument("file_path", default=None, strip=True) ) - console.warning(f"Delete {file_path} for server {server_id}") + self.helper.self.helper.console.warning(f"Delete {file_path} for server {server_id}") if not self.check_server_id(server_id, "del_file"): return @@ -272,33 +265,33 @@ class FileHandler(BaseHandler): server_info = self.controller.servers.get_server_data_by_id(server_id) if not ( - helper.in_path( - helper.get_os_understandable_path(server_info["path"]), file_path + Helpers.in_path( + Helpers.get_os_understandable_path(server_info["path"]), file_path ) - or helper.in_path( - helper.get_os_understandable_path(server_info["backup_path"]), + or Helpers.in_path( + Helpers.get_os_understandable_path(server_info["backup_path"]), file_path, ) - ) or not helper.check_file_exists(os.path.abspath(file_path)): + ) or not Helpers.check_file_exists(os.path.abspath(file_path)): logger.warning(f"Invalid path in del_file file ajax call ({file_path})") - console.warning( + self.helper.console.warning( f"Invalid path in del_file file ajax call ({file_path})" ) return # Delete the file - file_helper.del_file(file_path) + FileHelpers.del_file(file_path) elif page == "del_dir": if not permissions["Files"] in user_perms: if not superuser: self.redirect("/panel/error?error=Unauthorized access to Files") return - dir_path = helper.get_os_understandable_path( + dir_path = Helpers.get_os_understandable_path( self.get_body_argument("dir_path", default=None, strip=True) ) - console.warning(f"Delete {dir_path} for server {server_id}") + self.helper.console.warning(f"Delete {dir_path} for server {server_id}") if not self.check_server_id(server_id, "del_dir"): return @@ -306,20 +299,20 @@ class FileHandler(BaseHandler): server_id = bleach.clean(server_id) server_info = self.controller.servers.get_server_data_by_id(server_id) - if not helper.in_path( - helper.get_os_understandable_path(server_info["path"]), dir_path - ) or not helper.check_path_exists(os.path.abspath(dir_path)): + if not Helpers.in_path( + Helpers.get_os_understandable_path(server_info["path"]), dir_path + ) or not Helpers.check_path_exists(os.path.abspath(dir_path)): logger.warning(f"Invalid path in del_file file ajax call ({dir_path})") - console.warning(f"Invalid path in del_file file ajax call ({dir_path})") + self.helper.console.warning(f"Invalid path in del_file file ajax call ({dir_path})") return # Delete the directory # os.rmdir(dir_path) # Would only remove empty directories - if helper.validate_traversal( - helper.get_os_understandable_path(server_info["path"]), dir_path + if Helpers.validate_traversal( + Helpers.get_os_understandable_path(server_info["path"]), dir_path ): # Removes also when there are contents - file_helper.del_dirs(dir_path) + FileHelpers.del_dirs(dir_path) @tornado.web.authenticated def put(self, page): @@ -350,7 +343,7 @@ class FileHandler(BaseHandler): file_contents = self.get_body_argument( "file_contents", default=None, strip=True ) - file_path = helper.get_os_understandable_path( + file_path = Helpers.get_os_understandable_path( self.get_body_argument("file_path", default=None, strip=True) ) @@ -359,16 +352,16 @@ class FileHandler(BaseHandler): else: server_id = bleach.clean(server_id) - if not helper.in_path( - helper.get_os_understandable_path( + if not Helpers.in_path( + Helpers.get_os_understandable_path( self.controller.servers.get_server_data_by_id(server_id)["path"] ), file_path, - ) or not helper.check_file_exists(os.path.abspath(file_path)): + ) or not Helpers.check_file_exists(os.path.abspath(file_path)): logger.warning( f"Invalid path in save_file file ajax call ({file_path})" ) - console.warning( + self.helper.console.warning( f"Invalid path in save_file file ajax call ({file_path})" ) return @@ -382,7 +375,7 @@ class FileHandler(BaseHandler): if not superuser: self.redirect("/panel/error?error=Unauthorized access to Files") return - item_path = helper.get_os_understandable_path( + item_path = Helpers.get_os_understandable_path( self.get_body_argument("item_path", default=None, strip=True) ) new_item_name = self.get_body_argument( @@ -396,35 +389,35 @@ class FileHandler(BaseHandler): if item_path is None or new_item_name is None: logger.warning("Invalid path(s) in rename_file file ajax call") - console.warning("Invalid path(s) in rename_file file ajax call") + self.helper.console.warning("Invalid path(s) in rename_file file ajax call") return - if not helper.in_path( - helper.get_os_understandable_path( + if not Helpers.in_path( + Helpers.get_os_understandable_path( self.controller.servers.get_server_data_by_id(server_id)["path"] ), item_path, - ) or not helper.check_path_exists(os.path.abspath(item_path)): + ) or not Helpers.check_path_exists(os.path.abspath(item_path)): logger.warning( f"Invalid old name path in rename_file file ajax call ({server_id})" ) - console.warning( + self.helper.console.warning( f"Invalid old name path in rename_file file ajax call ({server_id})" ) return new_item_path = os.path.join(os.path.split(item_path)[0], new_item_name) - if not helper.in_path( - helper.get_os_understandable_path( + if not Helpers.in_path( + Helpers.get_os_understandable_path( self.controller.servers.get_server_data_by_id(server_id)["path"] ), new_item_path, - ) or helper.check_path_exists(os.path.abspath(new_item_path)): + ) or Helpers.check_path_exists(os.path.abspath(new_item_path)): logger.warning( f"Invalid new name path in rename_file file ajax call ({server_id})" ) - console.warning( + self.helper.console.warning( f"Invalid new name path in rename_file file ajax call ({server_id})" ) return @@ -458,7 +451,7 @@ class FileHandler(BaseHandler): if not superuser: self.redirect("/panel/error?error=Unauthorized access to Files") return - item_path = helper.get_os_understandable_path( + item_path = Helpers.get_os_understandable_path( self.get_body_argument("item_path", default=None, strip=True) ) new_item_name = self.get_body_argument( @@ -472,35 +465,35 @@ class FileHandler(BaseHandler): if item_path is None or new_item_name is None: logger.warning("Invalid path(s) in rename_file file ajax call") - console.warning("Invalid path(s) in rename_file file ajax call") + self.helper.console.warning("Invalid path(s) in rename_file file ajax call") return - if not helper.in_path( - helper.get_os_understandable_path( + if not Helpers.in_path( + Helpers.get_os_understandable_path( self.controller.servers.get_server_data_by_id(server_id)["path"] ), item_path, - ) or not helper.check_path_exists(os.path.abspath(item_path)): + ) or not Helpers.check_path_exists(os.path.abspath(item_path)): logger.warning( f"Invalid old name path in rename_file file ajax call ({server_id})" ) - console.warning( + self.helper.console.warning( f"Invalid old name path in rename_file file ajax call ({server_id})" ) return new_item_path = os.path.join(os.path.split(item_path)[0], new_item_name) - if not helper.in_path( - helper.get_os_understandable_path( + if not Helpers.in_path( + Helpers.get_os_understandable_path( self.controller.servers.get_server_data_by_id(server_id)["path"] ), new_item_path, - ) or helper.check_path_exists(os.path.abspath(new_item_path)): + ) or Helpers.check_path_exists(os.path.abspath(new_item_path)): logger.warning( f"Invalid new name path in rename_file file ajax call ({server_id})" ) - console.warning( + self.helper.console.warning( f"Invalid new name path in rename_file file ajax call ({server_id})" ) return @@ -513,7 +506,7 @@ class FileHandler(BaseHandler): logger.warning( f"Server ID not defined in {page_name} file ajax call ({server_id})" ) - console.warning( + self.helper.console.warning( f"Server ID not defined in {page_name} file ajax call ({server_id})" ) return @@ -525,7 +518,7 @@ class FileHandler(BaseHandler): logger.warning( f"Server ID not found in {page_name} file ajax call ({server_id})" ) - console.warning( + self.helper.console.warning( f"Server ID not found in {page_name} file ajax call ({server_id})" ) return diff --git a/app/classes/web/http_handler.py b/app/classes/web/http_handler.py index e772b007..ca340c66 100644 --- a/app/classes/web/http_handler.py +++ b/app/classes/web/http_handler.py @@ -1,14 +1,8 @@ import logging +import requests -from app.classes.shared.helpers import helper from app.classes.web.base_handler import BaseHandler -try: - import requests - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) - logger = logging.getLogger(__name__) @@ -21,7 +15,7 @@ class HTTPHandler(BaseHandler): url = "https://" + url_list[0] else: url = "https://" + url - db_port = helper.get_setting("https_port") + db_port = self.helper.get_setting("https_port") try: resp = requests.get(url + ":" + str(port)) resp.raise_for_status() @@ -39,7 +33,7 @@ class HTTPHandlerPage(BaseHandler): url = "https://" + url_list[0] else: url = "https://" + url - db_port = helper.get_setting("https_port") + db_port = self.helper.get_setting("https_port") try: resp = requests.get(url + ":" + str(port)) resp.raise_for_status() diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index 6a15b6f8..4c29fc5b 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -6,29 +6,23 @@ from typing import Dict, Any, Tuple import json import logging import threading +import bleach +import libgravatar +import requests +import tornado.web +import tornado.escape +from tornado import iostream + +# TZLocal is set as a hidden import on win pipeline +from tzlocal import get_localzone +from cron_validator import CronValidator from app.classes.models.server_permissions import Enum_Permissions_Server from app.classes.models.crafty_permissions import Enum_Permissions_Crafty -from app.classes.models.management import management_helper -from app.classes.shared.authentication import authentication -from app.classes.shared.helpers import helper +from app.classes.models.management import helpers_management +from app.classes.shared.helpers import Helpers from app.classes.web.base_handler import BaseHandler -try: - import bleach - import libgravatar - import requests - import tornado.web - import tornado.escape - from tornado import iostream - - # TZLocal is set as a hidden import on win pipeline - from tzlocal import get_localzone - from cron_validator import CronValidator - -except ModuleNotFoundError as ex: - helper.auto_installer_fix(ex) - logger = logging.getLogger(__name__) @@ -268,7 +262,7 @@ class PanelHandler(BaseHandler): # todo: make this actually pull and compare version data "update_available": False, "serverTZ": get_localzone(), - "version_data": helper.get_version_string(), + "version_data": self.helper.get_version_string(), "user_data": exec_user, "user_role": exec_user_role, "user_crafty_permissions": exec_user_crafty_permissions, @@ -287,11 +281,11 @@ class PanelHandler(BaseHandler): }, "menu_servers": defined_servers, "hosts_data": self.controller.management.get_latest_hosts_stats(), - "show_contribute": helper.get_setting("show_contribute_link", True), + "show_contribute": self.helper.get_setting("show_contribute_link", True), "error": error, "time": formatted_time, "lang": self.controller.users.get_user_lang_by_id(exec_user["user_id"]), - "lang_page": helper.getLangPage( + "lang_page": Helpers.getLangPage( self.controller.users.get_user_lang_by_id(exec_user["user_id"]) ), "super_user": superuser, @@ -306,7 +300,7 @@ class PanelHandler(BaseHandler): else None, "superuser": superuser, } - if helper.get_setting("allow_nsfw_profile_pictures"): + if self.helper.get_setting("allow_nsfw_profile_pictures"): rating = "x" else: rating = "g" @@ -341,7 +335,7 @@ class PanelHandler(BaseHandler): template = "public/error.html" elif page == "credits": - with open(helper.credits_cache, encoding="utf-8") as credits_default_local: + with open(self.helper.credits_cache, encoding="utf-8") as credits_default_local: try: remote = requests.get( "https://craftycontrol.com/credits", allow_redirects=True @@ -585,7 +579,7 @@ class PanelHandler(BaseHandler): "/panel/error?error=Unauthorized access To Schedules" ) return - page_data["schedules"] = management_helper.get_schedules_by_server( + page_data["schedules"] = helpers_management.get_schedules_by_server( server_id ) @@ -635,7 +629,7 @@ class PanelHandler(BaseHandler): ).send_backup_status() # makes it so relative path is the only thing shown for file in page_data["exclusions"]: - if helper.is_os_windows(): + if Helpers.is_os_windows(): exclusions.append(file.replace(server_info["path"] + "\\", "")) else: exclusions.append(file.replace(server_info["path"] + "/", "")) @@ -645,7 +639,7 @@ class PanelHandler(BaseHandler): page_data["backup_list"] = server.list_backups() except: page_data["backup_list"] = [] - page_data["backup_path"] = helper.wtol_path(server_info["backup_path"]) + page_data["backup_path"] = Helpers.wtol_path(server_info["backup_path"]) def get_banned_players_html(): banned_players = self.controller.servers.get_banned_players(server_id) @@ -688,11 +682,11 @@ class PanelHandler(BaseHandler): server_info = self.controller.servers.get_server_data_by_id(server_id) backup_file = os.path.abspath( os.path.join( - helper.get_os_understandable_path(server_info["backup_path"]), file + Helpers.get_os_understandable_path(server_info["backup_path"]), file ) ) - if not helper.in_path( - helper.get_os_understandable_path(server_info["backup_path"]), + if not Helpers.in_path( + Helpers.get_os_understandable_path(server_info["backup_path"]), backup_file, ) or not os.path.isfile(backup_file): self.redirect("/panel/error?error=Invalid path detected") @@ -799,10 +793,10 @@ class PanelHandler(BaseHandler): else: page_data["super-disabled"] = "disabled" for file in sorted( - os.listdir(os.path.join(helper.root_dir, "app", "translations")) + os.listdir(os.path.join(self.helper.root_dir, "app", "translations")) ): if file.endswith(".json"): - if file not in helper.get_setting("disabled_language_files"): + if file not in self.helper.get_setting("disabled_language_files"): if file != str(page_data["languages"][0] + ".json"): page_data["languages"].append(file.split(".")[0]) @@ -810,7 +804,7 @@ class PanelHandler(BaseHandler): elif page == "add_schedule": server_id = self.get_argument("id", None) - page_data["schedules"] = management_helper.get_schedules_by_server( + page_data["schedules"] = helpers_management.get_schedules_by_server( server_id ) page_data["get_players"] = lambda: self.controller.stats.get_server_players( @@ -867,7 +861,7 @@ class PanelHandler(BaseHandler): elif page == "edit_schedule": server_id = self.get_argument("id", None) - page_data["schedules"] = management_helper.get_schedules_by_server( + page_data["schedules"] = helpers_management.get_schedules_by_server( server_id ) sch_id = self.get_argument("sch_id", None) @@ -979,10 +973,10 @@ class PanelHandler(BaseHandler): page_data["super-disabled"] = "disabled" for file in sorted( - os.listdir(os.path.join(helper.root_dir, "app", "translations")) + os.listdir(os.path.join(self.helper.root_dir, "app", "translations")) ): if file.endswith(".json"): - if file not in helper.get_setting("disabled_language_files"): + if file not in self.helper.get_setting("disabled_language_files"): if file != str(page_data["languages"][0] + ".json"): page_data["languages"].append(file.split(".")[0]) @@ -1150,7 +1144,7 @@ class PanelHandler(BaseHandler): template = "panel/activity_logs.html" elif page == "download_file": - file = helper.get_os_understandable_path(self.get_argument("path", "")) + file = Helpers.get_os_understandable_path(self.get_argument("path", "")) name = self.get_argument("name", "") server_id = self.check_server_id() @@ -1159,8 +1153,8 @@ class PanelHandler(BaseHandler): server_info = self.controller.servers.get_server_data_by_id(server_id) - if not helper.in_path( - helper.get_os_understandable_path(server_info["path"]), file + if not Helpers.in_path( + Helpers.get_os_understandable_path(server_info["path"]), file ) or not os.path.isfile(file): self.redirect("/panel/error?error=Invalid path detected") return @@ -1275,13 +1269,13 @@ class PanelHandler(BaseHandler): server_obj = self.controller.servers.get_server_obj(server_id) if superuser: server_path = self.get_argument("server_path", None) - if helper.is_os_windows(): + if Helpers.is_os_windows(): server_path.replace(" ", "^ ") - server_path = helper.wtol_path(server_path) + server_path = Helpers.wtol_path(server_path) log_path = self.get_argument("log_path", None) - if helper.is_os_windows(): + if Helpers.is_os_windows(): log_path.replace(" ", "^ ") - log_path = helper.wtol_path(log_path) + log_path = Helpers.wtol_path(log_path) executable = self.get_argument("executable", None) execution_command = self.get_argument("execution_command", None) server_ip = self.get_argument("server_ip", None) @@ -1312,12 +1306,12 @@ class PanelHandler(BaseHandler): server_obj.server_name = server_name if superuser: - if helper.validate_traversal( - helper.get_servers_root_dir(), server_path + if Helpers.validate_traversal( + self.helper.get_servers_root_dir(), server_path ): server_obj.path = server_path server_obj.log_path = log_path - if helper.validate_traversal(helper.get_servers_root_dir(), executable): + if Helpers.validate_traversal(self.helper.get_servers_root_dir(), executable): server_obj.executable = executable server_obj.execution_command = execution_command server_obj.server_ip = server_ip @@ -1362,9 +1356,9 @@ class PanelHandler(BaseHandler): checked = self.controller.management.get_excluded_backup_dirs(server_id) if superuser: backup_path = bleach.clean(self.get_argument("backup_path", None)) - if helper.is_os_windows(): + if Helpers.is_os_windows(): backup_path.replace(" ", "^ ") - backup_path = helper.wtol_path(backup_path) + backup_path = Helpers.wtol_path(backup_path) else: backup_path = server_obj.backup_path max_backups = bleach.clean(self.get_argument("max_backups", None)) @@ -1741,7 +1735,7 @@ class PanelHandler(BaseHandler): except: hints = False lang = bleach.clean( - self.get_argument("language"), helper.get_setting("language") + self.get_argument("language"), self.helper.get_setting("language") ) if superuser: @@ -1895,7 +1889,7 @@ class PanelHandler(BaseHandler): ) self.write( - authentication.generate(key.user_id.user_id, {"token_id": key.token_id}) + self.controller.authentication.generate(key.user_id.user_id, {"token_id": key.token_id}) ) self.finish() @@ -1914,7 +1908,7 @@ class PanelHandler(BaseHandler): enabled = int(float(self.get_argument("enabled", "0"))) hints = True lang = bleach.clean( - self.get_argument("lang", helper.get_setting("language")) + self.get_argument("lang", self.helper.get_setting("language")) ) # We don't want a non-super user to be able to create a super user. if superuser: @@ -2056,8 +2050,8 @@ class PanelHandler(BaseHandler): else: self.set_status(404) page_data = { - "lang": helper.get_setting("language"), - "lang_page": helper.getLangPage(helper.get_setting("language")), + "lang": self.helper.get_setting("language"), + "lang_page": Helpers.getLangPage(self.helper.get_setting("language")), } self.render( "public/404.html", translate=self.translator.translate, data=page_data @@ -2073,12 +2067,12 @@ class PanelHandler(BaseHandler): page_data = { # todo: make this actually pull and compare version data "update_available": False, - "version_data": helper.get_version_string(), + "version_data": self.helper.get_version_string(), "user_data": exec_user, "hosts_data": self.controller.management.get_latest_hosts_stats(), - "show_contribute": helper.get_setting("show_contribute_link", True), + "show_contribute": self.helper.get_setting("show_contribute_link", True), "lang": self.controller.users.get_user_lang_by_id(exec_user["user_id"]), - "lang_page": helper.getLangPage( + "lang_page": Helpers.getLangPage( self.controller.users.get_user_lang_by_id(exec_user["user_id"]) ), } diff --git a/app/classes/web/public_handler.py b/app/classes/web/public_handler.py index 41083afc..af642f2f 100644 --- a/app/classes/web/public_handler.py +++ b/app/classes/web/public_handler.py @@ -1,23 +1,17 @@ import logging +import bleach +from app.classes.shared.helpers import Helpers from app.classes.models.users import helper_users -from app.classes.shared.authentication import authentication -from app.classes.shared.helpers import helper from app.classes.web.base_handler import BaseHandler -try: - import bleach - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) - logger = logging.getLogger(__name__) class PublicHandler(BaseHandler): def set_current_user(self, user_id: str = None): - expire_days = helper.get_setting("cookie_expire") + expire_days = self.helper.get_setting("cookie_expire") # if helper comes back with false if not expire_days: @@ -25,7 +19,7 @@ class PublicHandler(BaseHandler): if user_id is not None: self.set_cookie( - "token", authentication.generate(user_id), expires_days=int(expire_days) + "token", self.controller.authentication.generate(user_id), expires_days=int(expire_days) ) else: self.clear_cookie("token") @@ -38,10 +32,10 @@ class PublicHandler(BaseHandler): error_msg = bleach.clean(self.get_argument("error_msg", "")) page_data = { - "version": helper.get_version_string(), + "version": self.helper.get_version_string(), "error": error, - "lang": helper.get_setting("language"), - "lang_page": helper.getLangPage(helper.get_setting("language")), + "lang": self.helper.get_setting("language"), + "lang_page": self.helper.getLangPage(self.helper.get_setting("language")), "query": "", } if self.request.query: @@ -87,10 +81,10 @@ class PublicHandler(BaseHandler): error_msg = bleach.clean(self.get_argument("error_msg", "")) page_data = { - "version": helper.get_version_string(), + "version": self.helper.get_version_string(), "error": error, - "lang": helper.get_setting("language"), - "lang_page": helper.getLangPage(helper.get_setting("language")), + "lang": self.helper.get_setting("language"), + "lang_page": self.helper.getLangPage(self.helper.get_setting("language")), "query": "", } if self.request.query: @@ -140,7 +134,7 @@ class PublicHandler(BaseHandler): self.redirect(f"/public/login?error_msg={error_msg}") return - login_result = helper.verify_pass(entered_password, user_data.password) + login_result = self.helper.verify_pass(entered_password, user_data.password) # Valid Login if login_result: @@ -151,7 +145,7 @@ class PublicHandler(BaseHandler): # record this login user_data.last_ip = self.get_remote_ip() - user_data.last_login = helper.get_time_as_string() + user_data.last_login = Helpers.get_time_as_string() user_data.save() # log this login diff --git a/app/classes/web/server_handler.py b/app/classes/web/server_handler.py index 293f2838..6e30f12d 100644 --- a/app/classes/web/server_handler.py +++ b/app/classes/web/server_handler.py @@ -1,23 +1,17 @@ import json import logging import os +import tornado.web +import tornado.escape +import bleach +import libgravatar +import requests -from app.classes.minecraft.serverjars import server_jar_obj from app.classes.models.crafty_permissions import Enum_Permissions_Crafty -from app.classes.shared.helpers import helper -from app.classes.shared.file_helpers import file_helper +from app.classes.shared.helpers import Helpers +from app.classes.shared.file_helpers import FileHelpers from app.classes.web.base_handler import BaseHandler -try: - import tornado.web - import tornado.escape - import bleach - import libgravatar - import requests - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) - logger = logging.getLogger(__name__) @@ -58,7 +52,7 @@ class ServerHandler(BaseHandler): template = "public/404.html" page_data = { - "version_data": helper.get_version_string(), + "version_data": self.helper.get_version_string(), "user_data": exec_user, "user_role": exec_user_role, "roles": list_roles, @@ -78,9 +72,9 @@ class ServerHandler(BaseHandler): }, "hosts_data": self.controller.management.get_latest_hosts_stats(), "menu_servers": defined_servers, - "show_contribute": helper.get_setting("show_contribute_link", True), + "show_contribute": self.helper.get_setting("show_contribute_link", True), "lang": self.controller.users.get_user_lang_by_id(exec_user["user_id"]), - "lang_page": helper.getLangPage( + "lang_page": Helpers.getLangPage( self.controller.users.get_user_lang_by_id(exec_user["user_id"]) ), "api_key": { @@ -95,7 +89,7 @@ class ServerHandler(BaseHandler): "superuser": superuser, } - if helper.get_setting("allow_nsfw_profile_pictures"): + if self.helper.get_setting("allow_nsfw_profile_pictures"): rating = "x" else: rating = "g" @@ -134,10 +128,10 @@ class ServerHandler(BaseHandler): ) return - page_data["online"] = helper.check_internet() - page_data["server_types"] = server_jar_obj.get_serverjar_data() + page_data["online"] = Helpers.check_internet() + page_data["server_types"] = self.controller.server_jars.get_serverjar_data() page_data["js_server_types"] = json.dumps( - server_jar_obj.get_serverjar_data() + self.controller.server_jars.get_serverjar_data() ) template = "server/wizard.html" @@ -171,9 +165,9 @@ class ServerHandler(BaseHandler): page_data = { "version_data": "version_data_here", # TODO "user_data": exec_user, - "show_contribute": helper.get_setting("show_contribute_link", True), + "show_contribute": self.helper.get_setting("show_contribute_link", True), "lang": self.controller.users.get_user_lang_by_id(exec_user["user_id"]), - "lang_page": helper.getLangPage( + "lang_page": Helpers.getLangPage( self.controller.users.get_user_lang_by_id(exec_user["user_id"]) ), } @@ -204,15 +198,15 @@ class ServerHandler(BaseHandler): server_data.get("server_name") + f" (Copy {name_counter})" ) - new_server_uuid = helper.create_uuid() + new_server_uuid = Helpers.create_uuid() while os.path.exists( - os.path.join(helper.servers_dir, new_server_uuid) + os.path.join(self.helper.servers_dir, new_server_uuid) ): - new_server_uuid = helper.create_uuid() - new_server_path = os.path.join(helper.servers_dir, new_server_uuid) + new_server_uuid = Helpers.create_uuid() + new_server_path = os.path.join(self.helper.servers_dir, new_server_uuid) # copy the old server - file_helper.copy_dir(server_data.get("path"), new_server_path) + FileHelpers.copy_dir(server_data.get("path"), new_server_path) # TODO get old server DB data to individual variables stop_command = server_data.get("stop_command") @@ -221,7 +215,7 @@ class ServerHandler(BaseHandler): ).replace(server_uuid, new_server_uuid) new_executable = server_data.get("executable") new_server_log_file = str( - helper.get_os_understandable_path(server_data.get("log_path")) + Helpers.get_os_understandable_path(server_data.get("log_path")) ).replace(server_uuid, new_server_uuid) server_port = server_data.get("server_port") server_type = server_data.get("type") @@ -299,7 +293,7 @@ class ServerHandler(BaseHandler): elif import_type == "import_zip": # here import_server_path means the zip path zip_path = bleach.clean(self.get_argument("root_path")) - good_path = helper.check_path_exists(zip_path) + good_path = Helpers.check_path_exists(zip_path) if not good_path: self.redirect("/panel/error?error=Temp path not found!") return @@ -322,7 +316,7 @@ class ServerHandler(BaseHandler): self.get_remote_ip(), ) # deletes temp dir - file_helper.del_dirs(zip_path) + FileHelpers.del_dirs(zip_path) else: if len(server_parts) != 2: self.redirect("/panel/error?error=Invalid server data") @@ -417,7 +411,7 @@ class ServerHandler(BaseHandler): elif import_type == "import_zip": # here import_server_path means the zip path zip_path = bleach.clean(self.get_argument("root_path")) - good_path = helper.check_path_exists(zip_path) + good_path = Helpers.check_path_exists(zip_path) if not good_path: self.redirect("/panel/error?error=Temp path not found!") return @@ -440,7 +434,7 @@ class ServerHandler(BaseHandler): self.get_remote_ip(), ) # deletes temp dir - file_helper.del_dirs(zip_path) + FileHelpers.del_dirs(zip_path) else: if len(server_parts) != 2: self.redirect("/panel/error?error=Invalid server data") diff --git a/app/classes/web/status_handler.py b/app/classes/web/status_handler.py index 980df3e4..f351c510 100644 --- a/app/classes/web/status_handler.py +++ b/app/classes/web/status_handler.py @@ -1,6 +1,5 @@ import logging -from app.classes.shared.helpers import helper from app.classes.web.base_handler import BaseHandler logger = logging.getLogger(__name__) @@ -9,8 +8,8 @@ logger = logging.getLogger(__name__) class StatusHandler(BaseHandler): def get(self): page_data = {} - page_data["lang"] = helper.get_setting("language") - page_data["lang_page"] = helper.getLangPage(helper.get_setting("language")) + page_data["lang"] = self.helper.get_setting("language") + page_data["lang_page"] = self.helper.getLangPage(self.helper.get_setting("language")) page_data["servers"] = self.controller.servers.get_all_servers_stats() running = 0 for srv in page_data["servers"]: diff --git a/app/classes/web/tornado_handler.py b/app/classes/web/tornado_handler.py index 65075850..1b3f6775 100644 --- a/app/classes/web/tornado_handler.py +++ b/app/classes/web/tornado_handler.py @@ -3,10 +3,15 @@ import sys import json import asyncio import logging +import tornado.web +import tornado.ioloop +import tornado.log +import tornado.template +import tornado.escape +import tornado.locale +import tornado.httpserver -from app.classes.shared.translation import translation -from app.classes.shared.console import console -from app.classes.shared.helpers import helper +from app.classes.shared.helpers import Helpers from app.classes.web.file_handler import FileHandler from app.classes.web.public_handler import PublicHandler from app.classes.web.panel_handler import PanelHandler @@ -31,26 +36,16 @@ from app.classes.web.upload_handler import UploadHandler from app.classes.web.http_handler import HTTPHandler, HTTPHandlerPage from app.classes.web.status_handler import StatusHandler -try: - import tornado.web - import tornado.ioloop - import tornado.log - import tornado.template - import tornado.escape - import tornado.locale - import tornado.httpserver - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) logger = logging.getLogger(__name__) class Webserver: - def __init__(self, controller, tasks_manager): + def __init__(self, helper, controller, tasks_manager): self.ioloop = None self.HTTP_Server = None self.HTTPS_Server = None + self.helper = helper self.controller = controller self.tasks_manager = tasks_manager self._asyncio_patch() @@ -103,16 +98,16 @@ class Webserver: def run_tornado(self): # let's verify we have an SSL cert - helper.create_self_signed_cert() + self.helper.create_self_signed_cert() - http_port = helper.get_setting("http_port") - https_port = helper.get_setting("https_port") + http_port = self.helper.get_setting("http_port") + https_port = self.helper.get_setting("https_port") - debug_errors = helper.get_setting("show_errors") - cookie_secret = helper.get_setting("cookie_secret") + debug_errors = self.helper.get_setting("show_errors") + cookie_secret = self.helper.get_setting("cookie_secret") if cookie_secret is False: - cookie_secret = helper.random_string_generator(32) + cookie_secret = self.helper.random_string_generator(32) if not http_port: http_port = 8000 @@ -122,10 +117,10 @@ class Webserver: cert_objects = { "certfile": os.path.join( - helper.config_dir, "web", "certs", "commander.cert.pem" + self.helper.config_dir, "web", "certs", "commander.cert.pem" ), "keyfile": os.path.join( - helper.config_dir, "web", "certs", "commander.key.pem" + self.helper.config_dir, "web", "certs", "commander.key.pem" ), } @@ -139,9 +134,10 @@ class Webserver: tornado.locale.set_default_locale("en_EN") handler_args = { + "helper": self.helper, "controller": self.controller, "tasks_manager": self.tasks_manager, - "translator": translation, + "translator": self.helper.translation, } handlers = [ (r"/", DefaultHandler, handler_args), @@ -168,8 +164,8 @@ class Webserver: app = tornado.web.Application( handlers, - template_path=os.path.join(helper.webroot, "templates"), - static_path=os.path.join(helper.webroot, "static"), + template_path=os.path.join(self.helper.webroot, "templates"), + static_path=os.path.join(self.helper.webroot, "static"), debug=debug_errors, cookie_secret=cookie_secret, xsrf_cookies=True, @@ -193,8 +189,8 @@ class Webserver: ] HTTPapp = tornado.web.Application( HTTPhanders, - template_path=os.path.join(helper.webroot, "templates"), - static_path=os.path.join(helper.webroot, "static"), + template_path=os.path.join(self.helper.webroot, "templates"), + static_path=os.path.join(self.helper.webroot, "static"), debug=debug_errors, cookie_secret=cookie_secret, xsrf_cookies=True, @@ -212,24 +208,24 @@ class Webserver: self.HTTPS_Server.listen(https_port) logger.info( - f"https://{helper.get_local_ip()}:{https_port} " + f"https://{Helpers.get_local_ip()}:{https_port} " f"is up and ready for connections." ) - console.info( - f"https://{helper.get_local_ip()}:{https_port} " + self.helper.console.info( + f"https://{Helpers.get_local_ip()}:{https_port} " f"is up and ready for connections." ) - console.info("Server Init Complete: Listening For Connections:") + self.helper.console.info("Server Init Complete: Listening For Connections:") self.ioloop = tornado.ioloop.IOLoop.current() self.ioloop.start() def stop_web_server(self): logger.info("Shutting Down Web Server") - console.info("Shutting Down Web Server") + self.helper.console.info("Shutting Down Web Server") self.ioloop.stop() self.HTTP_Server.stop() self.HTTPS_Server.stop() logger.info("Web Server Stopped") - console.info("Web Server Stopped") + self.helper.console.info("Web Server Stopped") diff --git a/app/classes/web/upload_handler.py b/app/classes/web/upload_handler.py index 02273a08..5222be34 100644 --- a/app/classes/web/upload_handler.py +++ b/app/classes/web/upload_handler.py @@ -1,22 +1,14 @@ import logging import os import time +import tornado.web +import tornado.options +import tornado.httpserver from app.classes.models.server_permissions import Enum_Permissions_Server -from app.classes.shared.helpers import helper -from app.classes.shared.console import console +from app.classes.shared.helpers import Helpers from app.classes.shared.main_controller import Controller -from app.classes.web.websocket_helper import websocket_helper from app.classes.web.base_handler import BaseHandler -from app.classes.shared.translation import translation - -try: - import tornado.web - import tornado.options - import tornado.httpserver - -except ModuleNotFoundError as ex: - helper.auto_installer_fix(ex) logger = logging.getLogger(__name__) @@ -26,8 +18,9 @@ class UploadHandler(BaseHandler): # noinspection PyAttributeOutsideInit def initialize( - self, controller: Controller = None, tasks_manager=None, translator=None + self, helper: Helpers = None, controller: Controller = None, tasks_manager=None, translator=None ): + self.helper = helper self.controller = controller self.tasks_manager = tasks_manager self.translator = translator @@ -40,7 +33,7 @@ class UploadHandler(BaseHandler): if api_key is not None: superuser = superuser and api_key.superuser user_id = exec_user["user_id"] - stream_size_value = helper.get_setting("stream_size_GB") + stream_size_value = self.helper.get_setting("stream_size_GB") MAX_STREAMED_SIZE = (1024 * 1024 * 1024) * stream_size_value @@ -50,11 +43,11 @@ class UploadHandler(BaseHandler): f"User with ID {user_id} attempted to upload a file that" f" exceeded the max body size." ) - websocket_helper.broadcast_user( + self.helper.websocket_helper.broadcast_user( user_id, "send_start_error", { - "error": translation.translate( + "error": self.helper.translation.translate( "error", "fileTooLarge", self.controller.users.get_user_lang_by_id(user_id), @@ -85,12 +78,12 @@ class UploadHandler(BaseHandler): if user_id is None: logger.warning("User ID not found in upload handler call") - console.warning("User ID not found in upload handler call") + self.helper.console.warning("User ID not found in upload handler call") self.do_upload = False if server_id is None: logger.warning("Server ID not found in upload handler call") - console.warning("Server ID not found in upload handler call") + self.helper.console.warning("Server ID not found in upload handler call") self.do_upload = False if Enum_Permissions_Server.Files not in exec_user_server_permissions: @@ -98,7 +91,7 @@ class UploadHandler(BaseHandler): f"User {user_id} tried to upload a file to " f"{server_id} without permissions!" ) - console.warning( + self.helper.console.warning( f"User {user_id} tried to upload a file to " f"{server_id} without permissions!" ) @@ -108,8 +101,8 @@ class UploadHandler(BaseHandler): filename = self.request.headers.get("X-FileName", None) full_path = os.path.join(path, filename) - if not helper.in_path( - helper.get_os_understandable_path( + if not Helpers.in_path( + Helpers.get_os_understandable_path( self.controller.servers.get_server_data_by_id(server_id)["path"] ), full_path, @@ -117,7 +110,7 @@ class UploadHandler(BaseHandler): print( user_id, server_id, - helper.get_os_understandable_path( + Helpers.get_os_understandable_path( self.controller.servers.get_server_data_by_id(server_id)["path"] ), full_path, @@ -126,7 +119,7 @@ class UploadHandler(BaseHandler): f"User {user_id} tried to upload a file to {server_id} " f"but the path is not inside of the server!" ) - console.warning( + self.helper.console.warning( f"User {user_id} tried to upload a file to {server_id} " f"but the path is not inside of the server!" ) @@ -148,13 +141,13 @@ class UploadHandler(BaseHandler): if self.do_upload: time.sleep(5) if files_left == 0: - websocket_helper.broadcast("close_upload_box", "success") + self.helper.websocket_helper.broadcast("close_upload_box", "success") self.finish("success") # Nope, I'm sending "success" self.f.close() else: time.sleep(5) if files_left == 0: - websocket_helper.broadcast("close_upload_box", "error") + self.helper.websocket_helper.broadcast("close_upload_box", "error") self.finish("error") def data_received(self, chunk): diff --git a/app/classes/web/websocket_handler.py b/app/classes/web/websocket_handler.py index ea583b96..54ceccca 100644 --- a/app/classes/web/websocket_handler.py +++ b/app/classes/web/websocket_handler.py @@ -2,16 +2,9 @@ import json import logging import asyncio from urllib.parse import parse_qsl +import tornado.websocket -from app.classes.shared.authentication import authentication -from app.classes.shared.helpers import helper -from app.classes.web.websocket_helper import websocket_helper - -try: - import tornado.websocket - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) +from app.classes.shared.helpers import Helpers logger = logging.getLogger(__name__) @@ -24,7 +17,8 @@ class SocketHandler(tornado.websocket.WebSocketHandler): translator = None io_loop = None - def initialize(self, controller=None, tasks_manager=None, translator=None): + def initialize(self, helper=None, controller=None, tasks_manager=None, translator=None): + self.helper = helper self.controller = controller self.tasks_manager = tasks_manager self.translator = translator @@ -39,11 +33,11 @@ class SocketHandler(tornado.websocket.WebSocketHandler): return remote_ip def get_user_id(self): - _, _, user = authentication.check(self.get_cookie("token")) + _, _, user = self.controller.authentication.check(self.get_cookie("token")) return user["user_id"] def check_auth(self): - return authentication.check_bool(self.get_cookie("token")) + return self.controller.authentication.check_bool(self.get_cookie("token")) # pylint: disable=arguments-differ def open(self): @@ -51,7 +45,7 @@ class SocketHandler(tornado.websocket.WebSocketHandler): if self.check_auth(): self.handle() else: - websocket_helper.send_message( + self.helper.websocket_helper.send_message( self, "notification", "Not authenticated for WebSocket connection" ) self.close() @@ -62,7 +56,7 @@ class SocketHandler(tornado.websocket.WebSocketHandler): "Someone tried to connect via WebSocket without proper authentication", self.get_remote_ip(), ) - websocket_helper.broadcast( + self.helper.websocket_helper.broadcast( "notification", "Someone tried to connect via WebSocket without proper authentication", ) @@ -74,10 +68,10 @@ class SocketHandler(tornado.websocket.WebSocketHandler): self.page = self.get_query_argument("page") self.page_query_params = dict( parse_qsl( - helper.remove_prefix(self.get_query_argument("page_query_params"), "?") + Helpers.remove_prefix(self.get_query_argument("page_query_params"), "?") ) ) - websocket_helper.add_client(self) + self.helper.websocket_helper.add_client(self) logger.debug("Opened WebSocket connection") # pylint: disable=arguments-renamed @@ -89,7 +83,7 @@ class SocketHandler(tornado.websocket.WebSocketHandler): logger.debug(f"Event Type: {message['event']}, Data: {message['data']}") def on_close(self): - websocket_helper.remove_client(self) + self.helper.websocket_helper.remove_client(self) logger.debug("Closed WebSocket connection") async def write_message_int(self, message): diff --git a/app/classes/web/websocket_helper.py b/app/classes/web/websocket_helper.py index 5e4f3289..0486f859 100644 --- a/app/classes/web/websocket_helper.py +++ b/app/classes/web/websocket_helper.py @@ -1,13 +1,12 @@ import json import logging -from app.classes.shared.console import console - logger = logging.getLogger(__name__) class WebSocketHelper: - def __init__(self): + def __init__(self, helper): + self.helper = helper self.clients = set() def add_client(self, client): @@ -101,10 +100,7 @@ class WebSocketHelper: ) def disconnect_all(self): - console.info("Disconnecting WebSocket clients") + self.helper.console.info("Disconnecting WebSocket clients") for client in self.clients: client.close() - console.info("Disconnected WebSocket clients") - - -websocket_helper = WebSocketHelper() + self.helper.console.info("Disconnected WebSocket clients") diff --git a/main.py b/main.py index 0ce9e31a..2775820d 100644 --- a/main.py +++ b/main.py @@ -5,9 +5,13 @@ import time import argparse import logging.config import signal -from app.classes.shared.console import console -from app.classes.shared.helpers import helper +import peewee +from app.classes.models.users import helper_users +from app.classes.shared.console import Console +from app.classes.shared.helpers import Helpers +console = Console() +helper = Helpers(console) if helper.checkRoot(): console.critical( "Root detected. Root/Admin access denied. " @@ -17,12 +21,15 @@ if helper.checkRoot(): console.critical("Crafty shutting down. Root/Admin access denied.") sys.exit(0) # pylint: disable=wrong-import-position -from app.classes.shared.main_models import installer, database -from app.classes.shared.tasks import TasksManager -from app.classes.shared.main_controller import Controller -from app.classes.shared.migration import MigrationManager - -from app.classes.shared.command import MainPrompt +try: + from app.classes.models.base_model import database_proxy + from app.classes.shared.main_models import db_builder + from app.classes.shared.tasks import TasksManager + from app.classes.shared.main_controller import Controller + from app.classes.shared.migration import MigrationManager + from app.classes.shared.command import MainPrompt +except ModuleNotFoundError as err: + helper.auto_installer_fix(err) def do_intro(): @@ -88,6 +95,8 @@ if __name__ == "__main__": # setting up the logger object logger = logging.getLogger(__name__) console.cyan(f"Logging set to: {logger.level}") + peewee_logger = logging.getLogger("peewee") + peewee_logger.setLevel(logging.INFO) # print our pretty start message do_intro() @@ -95,10 +104,19 @@ if __name__ == "__main__": # our session file, helps prevent multiple controller agents on the same machine. helper.create_session_file(ignore=args.ignore) - migration_manager = MigrationManager(database) + # start the database + database = peewee.SqliteDatabase( + helper.db_path, + pragmas={"journal_mode": "wal", "cache_size": -1024 * 10} + ) + database_proxy.initialize(database) + + migration_manager = MigrationManager(database, helper) migration_manager.up() # Automatically runs migrations # do our installer stuff + user_helper = helper_users(database, helper) + installer = db_builder(database, helper, user_helper) fresh_install = installer.is_fresh_install() if fresh_install: @@ -114,8 +132,8 @@ if __name__ == "__main__": console.debug("Existing install detected") # now the tables are created, we can load the tasks_manger and server controller - controller = Controller() - tasks_manager = TasksManager(controller) + controller = Controller(database, helper) + tasks_manager = TasksManager(helper, controller) tasks_manager.start_webserver() # slowing down reporting just for a 1/2 second so messages look cleaner @@ -151,7 +169,7 @@ if __name__ == "__main__": if not controller.check_system_user(): controller.add_system_user() - Crafty = MainPrompt(tasks_manager, migration_manager) + Crafty = MainPrompt(helper, tasks_manager, migration_manager) project_root = os.path.dirname(__file__) controller.set_project_root(project_root) diff --git a/requirements.txt b/requirements.txt index 5c02524d..26ecc613 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ bleach==4.1 cached_property==1.5.2 colorama==0.4 cron-validator==1.0.3 -cryptography==3.4 +cryptography==3.4.8 libgravatar==1.0.0 peewee==3.13 pexpect==4.8 From 19f2429a4c56ec11d4c14b78da837033570be3f0 Mon Sep 17 00:00:00 2001 From: Zedifus Date: Mon, 11 Apr 2022 11:08:36 +0100 Subject: [PATCH 03/19] =?UTF-8?q?Fix=20formatting=20to=20comply=20with=20?= =?UTF-8?q?=E2=AC=9BBlack?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/classes/controllers/roles_controller.py | 5 +++- app/classes/minecraft/serverjars.py | 13 +++++++-- app/classes/minecraft/stats.py | 4 ++- app/classes/models/base_model.py | 1 + app/classes/models/server_permissions.py | 4 +-- app/classes/shared/file_helpers.py | 2 +- app/classes/shared/helpers.py | 9 ++++-- app/classes/shared/import3.py | 5 ++-- app/classes/shared/main_controller.py | 29 ++++++++++++++----- app/classes/shared/main_models.py | 1 + app/classes/shared/migration.py | 12 ++++++-- app/classes/shared/server.py | 31 ++++++++++++++++----- app/classes/shared/tasks.py | 21 ++++++++++---- app/classes/shared/translation.py | 4 ++- app/classes/web/ajax_handler.py | 17 ++++++++--- app/classes/web/base_handler.py | 1 + app/classes/web/file_handler.py | 19 +++++++++---- app/classes/web/panel_handler.py | 12 ++++++-- app/classes/web/public_handler.py | 4 ++- app/classes/web/server_handler.py | 4 ++- app/classes/web/status_handler.py | 4 ++- app/classes/web/upload_handler.py | 6 +++- app/classes/web/websocket_handler.py | 4 ++- main.py | 3 +- 24 files changed, 160 insertions(+), 55 deletions(-) diff --git a/app/classes/controllers/roles_controller.py b/app/classes/controllers/roles_controller.py index d370b557..3c6f7c44 100644 --- a/app/classes/controllers/roles_controller.py +++ b/app/classes/controllers/roles_controller.py @@ -10,6 +10,7 @@ logger = logging.getLogger(__name__) class Roles_Controller: def __init__(self, users_helper): self.users_helper = users_helper + @staticmethod def get_all_roles(): return helper_roles.get_all_roles() @@ -45,7 +46,9 @@ class Roles_Controller: for server in added_servers: Permissions_Servers.get_or_create(role_id, server, permissions_mask) for server in base_data["servers"]: - Permissions_Servers.update_role_permission(role_id, server, permissions_mask) + Permissions_Servers.update_role_permission( + role_id, server, permissions_mask + ) # TODO: This is horribly inefficient and we should be using bulk queries # but im going for functionality at this point Permissions_Servers.delete_roles_permissions(role_id, removed_servers) diff --git a/app/classes/minecraft/serverjars.py b/app/classes/minecraft/serverjars.py index 9a57f66f..85f472a1 100644 --- a/app/classes/minecraft/serverjars.py +++ b/app/classes/minecraft/serverjars.py @@ -11,6 +11,7 @@ from app.classes.models.server_permissions import Permissions_Servers logger = logging.getLogger(__name__) + class ServerJars: def __init__(self, helper): self.helper = helper @@ -177,7 +178,9 @@ class ServerJars: try: Servers_Controller.set_download(server_id) for user in server_users: - self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {}) + self.helper.websocket_helper.broadcast_user( + user, "send_start_reload", {} + ) break except Exception as ex: @@ -195,7 +198,9 @@ class ServerJars: user, "notification", "Executable download finished" ) time.sleep(3) - self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {}) + self.helper.websocket_helper.broadcast_user( + user, "send_start_reload", {} + ) return True except Exception as e: logger.error(f"Unable to save jar to {path} due to error:{e}") @@ -206,6 +211,8 @@ class ServerJars: user, "notification", "Executable download finished" ) time.sleep(3) - self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {}) + self.helper.websocket_helper.broadcast_user( + user, "send_start_reload", {} + ) return False diff --git a/app/classes/minecraft/stats.py b/app/classes/minecraft/stats.py index c70fec3a..128dae81 100644 --- a/app/classes/minecraft/stats.py +++ b/app/classes/minecraft/stats.py @@ -61,7 +61,9 @@ class Stats: with p.oneshot(): process_stats = { "cpu_usage": real_cpu, - "memory_usage": Helpers.human_readable_file_size(p.memory_info()[0]), + "memory_usage": Helpers.human_readable_file_size( + p.memory_info()[0] + ), "mem_percentage": round(p.memory_percent(), 0), } return process_stats diff --git a/app/classes/models/base_model.py b/app/classes/models/base_model.py index 3353494e..28e5796e 100644 --- a/app/classes/models/base_model.py +++ b/app/classes/models/base_model.py @@ -2,6 +2,7 @@ import peewee database_proxy = peewee.DatabaseProxy() + class BaseModel(peewee.Model): class Meta: database = database_proxy diff --git a/app/classes/models/server_permissions.py b/app/classes/models/server_permissions.py index f96eb716..c66469aa 100644 --- a/app/classes/models/server_permissions.py +++ b/app/classes/models/server_permissions.py @@ -181,9 +181,7 @@ class Permissions_Servers: @staticmethod def remove_roles_of_server(server_id): return ( - Role_Servers.delete() - .where(Role_Servers.server_id == server_id) - .execute() + Role_Servers.delete().where(Role_Servers.server_id == server_id).execute() ) @staticmethod diff --git a/app/classes/shared/file_helpers.py b/app/classes/shared/file_helpers.py index 970e0f88..b6f4d223 100644 --- a/app/classes/shared/file_helpers.py +++ b/app/classes/shared/file_helpers.py @@ -112,4 +112,4 @@ class FileHelpers: f" - Error was: {e}" ) - return True \ No newline at end of file + return True diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index 59ef52d7..e3085c71 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -630,7 +630,10 @@ class Helpers: sizes = [] for p in paths: sizes.append( - {"path": p, "size": Helpers.human_readable_file_size(os.stat(p).st_size)} + { + "path": p, + "size": Helpers.human_readable_file_size(os.stat(p).st_size), + } ) return sizes @@ -913,7 +916,9 @@ class Helpers: def backup_select(self, path, user_id): if user_id: - self.websocket_helper.broadcast_user(user_id, "send_temp_path", {"path": path}) + self.websocket_helper.broadcast_user( + user_id, "send_temp_path", {"path": path} + ) @staticmethod def unzip_backup_archive(backup_path, zip_name): diff --git a/app/classes/shared/import3.py b/app/classes/shared/import3.py index 693fa810..b3854d12 100644 --- a/app/classes/shared/import3.py +++ b/app/classes/shared/import3.py @@ -13,7 +13,6 @@ class import3: self.console = self.helper.console self.controller = controller - def start_import(self): folder = os.path.normpath( input( @@ -26,7 +25,9 @@ class import3: "Crafty cannot find the path you entered. " "Does Crafty's user have permission to access it?" ) - self.console.info("Please run the import3 command again and enter a valid path.") + self.console.info( + "Please run the import3 command again and enter a valid path." + ) else: with open(os.path.join(folder, "users.json"), encoding="utf-8") as f: user_json = json.loads(f.read()) diff --git a/app/classes/shared/main_controller.py b/app/classes/shared/main_controller.py index ba06e826..3dde3e3c 100644 --- a/app/classes/shared/main_controller.py +++ b/app/classes/shared/main_controller.py @@ -7,6 +7,7 @@ import logging import tempfile from typing import Union from peewee import DoesNotExist + # TZLocal is set as a hidden import on win pipeline from tzlocal import get_localzone from apscheduler.schedulers.background import BackgroundScheduler @@ -31,6 +32,7 @@ from app.classes.minecraft.stats import Stats logger = logging.getLogger(__name__) + class Controller: def __init__(self, database, helper): self.helper = helper @@ -47,7 +49,9 @@ class Controller: self.roles = Roles_Controller(self.users_helper) self.server_perms = Server_Perms_Controller() self.servers = Servers_Controller(self.servers_helper) - self.users = Users_Controller(self.helper, self.users_helper, self.authentication) + self.users = Users_Controller( + self.helper, self.users_helper, self.authentication + ) tz = get_localzone() self.support_scheduler = BackgroundScheduler(timezone=str(tz)) self.support_scheduler.start() @@ -103,7 +107,9 @@ class Controller: # if the properties file isn't there, let's warn if not Helpers.check_file_exists(settings_file): logger.error(f"Unable to find {settings_file}. Skipping this server.") - self.console.error(f"Unable to find {settings_file}. Skipping this server.") + self.console.error( + f"Unable to find {settings_file}. Skipping this server." + ) continue settings = ServerProps(settings_file) @@ -217,7 +223,9 @@ class Controller: ) tempZipStorage += ".zip" - self.helper.websocket_helper.broadcast_user(exec_user["user_id"], "send_logs_bootbox", {}) + self.helper.websocket_helper.broadcast_user( + exec_user["user_id"], "send_logs_bootbox", {} + ) self.users.set_support_path(exec_user["user_id"], tempZipStorage) @@ -717,10 +725,13 @@ class Controller: old_bu_path = server_data["backup_path"] Server_Perms_Controller.backup_role_swap(old_server_id, new_server_id) if not Helpers.is_os_windows(): - backup_path = Helpers.validate_traversal(self.helper.backup_path, old_bu_path) + backup_path = Helpers.validate_traversal( + self.helper.backup_path, old_bu_path + ) if Helpers.is_os_windows(): backup_path = Helpers.validate_traversal( - Helpers.wtol_path(self.helper.backup_path), Helpers.wtol_path(old_bu_path) + Helpers.wtol_path(self.helper.backup_path), + Helpers.wtol_path(old_bu_path), ) backup_path = Helpers.wtol_path(str(backup_path)) backup_path.replace(" ", "^ ") @@ -761,7 +772,9 @@ class Controller: server_port, ) - if not Helpers.check_file_exists(os.path.join(server_dir, "crafty_managed.txt")): + if not Helpers.check_file_exists( + os.path.join(server_dir, "crafty_managed.txt") + ): try: # place a file in the dir saying it's owned by crafty with open( @@ -794,7 +807,9 @@ class Controller: server_name = server_data["server_name"] logger.info(f"Deleting Server: ID {server_id} | Name: {server_name} ") - self.console.info(f"Deleting Server: ID {server_id} | Name: {server_name} ") + self.console.info( + f"Deleting Server: ID {server_id} | Name: {server_name} " + ) srv_obj = s["server_obj"] running = srv_obj.check_running() diff --git a/app/classes/shared/main_models.py b/app/classes/shared/main_models.py index 80ddbedf..52509534 100644 --- a/app/classes/shared/main_models.py +++ b/app/classes/shared/main_models.py @@ -6,6 +6,7 @@ from app.classes.shared.helpers import Helpers logger = logging.getLogger(__name__) + class db_builder: def __init__(self, database, helper, users_helper): self.database = database diff --git a/app/classes/shared/migration.py b/app/classes/shared/migration.py index abec3099..0edc29e2 100644 --- a/app/classes/shared/migration.py +++ b/app/classes/shared/migration.py @@ -331,11 +331,15 @@ class MigrationManager(object): """ if not os.path.exists(self.helper.migration_dir): logger.warning( - "Migration directory: {} does not exist.".format(self.helper.migration_dir) + "Migration directory: {} does not exist.".format( + self.helper.migration_dir + ) ) os.makedirs(self.helper.migration_dir) return sorted( - f[:-3] for f in os.listdir(self.helper.migration_dir) if self.filemask.match(f) + f[:-3] + for f in os.listdir(self.helper.migration_dir) + if self.filemask.match(f) ) @property @@ -419,7 +423,9 @@ class MigrationManager(object): if Helpers.is_os_windows() and sys.version_info >= (3, 0): # if system is windows - force utf-8 encoding call_params["encoding"] = "utf-8" - with open(os.path.join(self.helper.migration_dir, name + ".py"), **call_params) as f: + with open( + os.path.join(self.helper.migration_dir, name + ".py"), **call_params + ) as f: code = f.read() scope = {} code = compile(code, "", "exec", dont_inherit=True) diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index c74bd28e..a40b3523 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -9,6 +9,7 @@ import subprocess import html import tempfile import psutil + # TZLocal is set as a hidden import on win pipeline from tzlocal import get_localzone from apscheduler.schedulers.background import BackgroundScheduler @@ -148,7 +149,9 @@ class Server: delay = int(self.settings["auto_start_delay"]) logger.info(f"Scheduling server {self.name} to start in {delay} seconds") - self.console.info(f"Scheduling server {self.name} to start in {delay} seconds") + self.console.info( + f"Scheduling server {self.name} to start in {delay} seconds" + ) self.server_scheduler.add_job( self.run_scheduled_server, @@ -216,7 +219,9 @@ class Server: if not Helpers.check_path_exists(self.server_path): logger.critical(f"Server path: {self.server_path} does not seem to exits") - self.console.critical(f"Server path: {self.server_path} does not seem to exits") + self.console.critical( + f"Server path: {self.server_path} does not seem to exits" + ) if not Helpers.check_writeable(self.server_path): logger.critical(f"Unable to write/access {self.server_path}") @@ -255,7 +260,9 @@ class Server: return False logger.info(f"Launching Server {self.name} with command {self.server_command}") - self.console.info(f"Launching Server {self.name} with command {self.server_command}") + self.console.info( + f"Launching Server {self.name} with command {self.server_command}" + ) # Checks for eula. Creates one if none detected. # If EULA is detected and not set to true we offer to set it true. @@ -450,11 +457,15 @@ class Server: server_users = Permissions_Servers.get_server_user_list(self.server_id) for user in server_users: if user != user_id: - self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {}) + self.helper.websocket_helper.broadcast_user( + user, "send_start_reload", {} + ) else: server_users = Permissions_Servers.get_server_user_list(self.server_id) for user in server_users: - self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {}) + self.helper.websocket_helper.broadcast_user( + user, "send_start_reload", {} + ) else: logger.warning( f"Server PID {self.process.pid} died right after starting " @@ -485,7 +496,11 @@ class Server: self.helper.websocket_helper.broadcast_user( user_id, "send_start_error", - {"error": self.helper.translation.translate("error", "internet", user_lang)}, + { + "error": self.helper.translation.translate( + "error", "internet", user_lang + ) + }, ) def stop_crash_detection(self): @@ -998,7 +1013,9 @@ class Server: "string": message, }, ) - self.helper.websocket_helper.broadcast_page("/panel/dashboard", "send_start_reload", {}) + self.helper.websocket_helper.broadcast_page( + "/panel/dashboard", "send_start_reload", {} + ) backup_dir = os.path.join( Helpers.get_os_understandable_path(self.settings["path"]), "crafty_executable_backups", diff --git a/app/classes/shared/tasks.py b/app/classes/shared/tasks.py index 42725157..ecd77f36 100644 --- a/app/classes/shared/tasks.py +++ b/app/classes/shared/tasks.py @@ -177,12 +177,16 @@ class TasksManager: ], ) except Exception as e: - self.helper.console.error(f"Failed to schedule task with error: {e}.") + self.helper.console.error( + f"Failed to schedule task with error: {e}." + ) self.helper.console.warning("Removing failed task from DB.") logger.error(f"Failed to schedule task with error: {e}.") logger.warning("Removing failed task from DB.") # remove items from DB if task fails to add to apscheduler - self.controller.management_helper.delete_scheduled_task(schedule.schedule_id) + self.controller.management_helper.delete_scheduled_task( + schedule.schedule_id + ) else: if schedule.interval_type == "hours": self.scheduler.add_job( @@ -270,7 +274,9 @@ class TasksManager: ], ) except Exception as e: - self.helper.console.error(f"Failed to schedule task with error: {e}.") + self.helper.console.error( + f"Failed to schedule task with error: {e}." + ) self.helper.console.warning("Removing failed task from DB.") logger.error(f"Failed to schedule task with error: {e}.") logger.warning("Removing failed task from DB.") @@ -381,7 +387,9 @@ class TasksManager: ], ) except Exception as e: - self.helper.console.error(f"Failed to schedule task with error: {e}.") + self.helper.console.error( + f"Failed to schedule task with error: {e}." + ) self.helper.console.info("Removing failed task from DB.") self.controller.management_helper.delete_scheduled_task(sch_id) else: @@ -511,7 +519,10 @@ class TasksManager: logger.info("Scheduling Serverjars.com cache refresh service every 12 hours") self.scheduler.add_job( - self.controller.server_jars.refresh_cache, "interval", hours=12, id="serverjars" + self.controller.server_jars.refresh_cache, + "interval", + hours=12, + id="serverjars", ) def realtime(self): diff --git a/app/classes/shared/translation.py b/app/classes/shared/translation.py index b283a393..17914eb8 100644 --- a/app/classes/shared/translation.py +++ b/app/classes/shared/translation.py @@ -9,7 +9,9 @@ logger = logging.getLogger(__name__) class Translation: def __init__(self, helper): self.helper = helper - self.translations_path = os.path.join(self.helper.root_dir, "app", "translations") + self.translations_path = os.path.join( + self.helper.root_dir, "app", "translations" + ) self.cached_translation = None self.cached_translation_lang = None diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index bf8cb142..88d5f435 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -283,7 +283,9 @@ class AjaxHandler(BaseHandler): if server_id is None: logger.warning("Server ID not found in send_command ajax call") - self.helper.console.warning("Server ID not found in send_command ajax call") + self.helper.console.warning( + "Server ID not found in send_command ajax call" + ) srv_obj = self.controller.get_server_obj(server_id) @@ -430,7 +432,11 @@ class AjaxHandler(BaseHandler): self.helper.websocket_helper.broadcast_user( user_id, "send_start_error", - {"error": self.helper.translation.translate("error", "no-file", user_lang)}, + { + "error": self.helper.translation.translate( + "error", "no-file", user_lang + ) + }, ) return @@ -496,12 +502,15 @@ class AjaxHandler(BaseHandler): ) ) or not Helpers.check_file_exists(os.path.abspath(file_path)): logger.warning(f"Invalid path in del_backup ajax call ({file_path})") - self.helper.console.warning(f"Invalid path in del_backup ajax call ({file_path})") + self.helper.console.warning( + f"Invalid path in del_backup ajax call ({file_path})" + ) return # Delete the file if Helpers.validate_traversal( - Helpers.get_os_understandable_path(server_info["backup_path"]), file_path + Helpers.get_os_understandable_path(server_info["backup_path"]), + file_path, ): os.remove(file_path) diff --git a/app/classes/web/base_handler.py b/app/classes/web/base_handler.py index d06c0c78..499cbb87 100644 --- a/app/classes/web/base_handler.py +++ b/app/classes/web/base_handler.py @@ -7,6 +7,7 @@ from app.classes.models.users import ApiKeys logger = logging.getLogger(__name__) + class BaseHandler(tornado.web.RequestHandler): nobleach = {bool, type(None)} diff --git a/app/classes/web/file_handler.py b/app/classes/web/file_handler.py index 9f7634d6..5118acf1 100644 --- a/app/classes/web/file_handler.py +++ b/app/classes/web/file_handler.py @@ -8,9 +8,10 @@ from app.classes.models.server_permissions import Enum_Permissions_Server from app.classes.shared.helpers import Helpers from app.classes.shared.file_helpers import FileHelpers from app.classes.web.base_handler import BaseHandler - + logger = logging.getLogger(__name__) + class FileHandler(BaseHandler): def render_page(self, template, page_data): self.render( @@ -256,7 +257,9 @@ class FileHandler(BaseHandler): self.get_body_argument("file_path", default=None, strip=True) ) - self.helper.self.helper.console.warning(f"Delete {file_path} for server {server_id}") + self.helper.self.helper.console.warning( + f"Delete {file_path} for server {server_id}" + ) if not self.check_server_id(server_id, "del_file"): return @@ -303,7 +306,9 @@ class FileHandler(BaseHandler): Helpers.get_os_understandable_path(server_info["path"]), dir_path ) or not Helpers.check_path_exists(os.path.abspath(dir_path)): logger.warning(f"Invalid path in del_file file ajax call ({dir_path})") - self.helper.console.warning(f"Invalid path in del_file file ajax call ({dir_path})") + self.helper.console.warning( + f"Invalid path in del_file file ajax call ({dir_path})" + ) return # Delete the directory @@ -389,7 +394,9 @@ class FileHandler(BaseHandler): if item_path is None or new_item_name is None: logger.warning("Invalid path(s) in rename_file file ajax call") - self.helper.console.warning("Invalid path(s) in rename_file file ajax call") + self.helper.console.warning( + "Invalid path(s) in rename_file file ajax call" + ) return if not Helpers.in_path( @@ -465,7 +472,9 @@ class FileHandler(BaseHandler): if item_path is None or new_item_name is None: logger.warning("Invalid path(s) in rename_file file ajax call") - self.helper.console.warning("Invalid path(s) in rename_file file ajax call") + self.helper.console.warning( + "Invalid path(s) in rename_file file ajax call" + ) return if not Helpers.in_path( diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index 4c29fc5b..42834d97 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -335,7 +335,9 @@ class PanelHandler(BaseHandler): template = "public/error.html" elif page == "credits": - with open(self.helper.credits_cache, encoding="utf-8") as credits_default_local: + with open( + self.helper.credits_cache, encoding="utf-8" + ) as credits_default_local: try: remote = requests.get( "https://craftycontrol.com/credits", allow_redirects=True @@ -1311,7 +1313,9 @@ class PanelHandler(BaseHandler): ): server_obj.path = server_path server_obj.log_path = log_path - if Helpers.validate_traversal(self.helper.get_servers_root_dir(), executable): + if Helpers.validate_traversal( + self.helper.get_servers_root_dir(), executable + ): server_obj.executable = executable server_obj.execution_command = execution_command server_obj.server_ip = server_ip @@ -1889,7 +1893,9 @@ class PanelHandler(BaseHandler): ) self.write( - self.controller.authentication.generate(key.user_id.user_id, {"token_id": key.token_id}) + self.controller.authentication.generate( + key.user_id.user_id, {"token_id": key.token_id} + ) ) self.finish() diff --git a/app/classes/web/public_handler.py b/app/classes/web/public_handler.py index af642f2f..72185279 100644 --- a/app/classes/web/public_handler.py +++ b/app/classes/web/public_handler.py @@ -19,7 +19,9 @@ class PublicHandler(BaseHandler): if user_id is not None: self.set_cookie( - "token", self.controller.authentication.generate(user_id), expires_days=int(expire_days) + "token", + self.controller.authentication.generate(user_id), + expires_days=int(expire_days), ) else: self.clear_cookie("token") diff --git a/app/classes/web/server_handler.py b/app/classes/web/server_handler.py index 6e30f12d..42f9cacd 100644 --- a/app/classes/web/server_handler.py +++ b/app/classes/web/server_handler.py @@ -203,7 +203,9 @@ class ServerHandler(BaseHandler): os.path.join(self.helper.servers_dir, new_server_uuid) ): new_server_uuid = Helpers.create_uuid() - new_server_path = os.path.join(self.helper.servers_dir, new_server_uuid) + new_server_path = os.path.join( + self.helper.servers_dir, new_server_uuid + ) # copy the old server FileHelpers.copy_dir(server_data.get("path"), new_server_path) diff --git a/app/classes/web/status_handler.py b/app/classes/web/status_handler.py index f351c510..71b29f62 100644 --- a/app/classes/web/status_handler.py +++ b/app/classes/web/status_handler.py @@ -9,7 +9,9 @@ class StatusHandler(BaseHandler): def get(self): page_data = {} page_data["lang"] = self.helper.get_setting("language") - page_data["lang_page"] = self.helper.getLangPage(self.helper.get_setting("language")) + page_data["lang_page"] = self.helper.getLangPage( + self.helper.get_setting("language") + ) page_data["servers"] = self.controller.servers.get_all_servers_stats() running = 0 for srv in page_data["servers"]: diff --git a/app/classes/web/upload_handler.py b/app/classes/web/upload_handler.py index 5222be34..990fc0fc 100644 --- a/app/classes/web/upload_handler.py +++ b/app/classes/web/upload_handler.py @@ -18,7 +18,11 @@ class UploadHandler(BaseHandler): # noinspection PyAttributeOutsideInit def initialize( - self, helper: Helpers = None, controller: Controller = None, tasks_manager=None, translator=None + self, + helper: Helpers = None, + controller: Controller = None, + tasks_manager=None, + translator=None, ): self.helper = helper self.controller = controller diff --git a/app/classes/web/websocket_handler.py b/app/classes/web/websocket_handler.py index 54ceccca..64648fd8 100644 --- a/app/classes/web/websocket_handler.py +++ b/app/classes/web/websocket_handler.py @@ -17,7 +17,9 @@ class SocketHandler(tornado.websocket.WebSocketHandler): translator = None io_loop = None - def initialize(self, helper=None, controller=None, tasks_manager=None, translator=None): + def initialize( + self, helper=None, controller=None, tasks_manager=None, translator=None + ): self.helper = helper self.controller = controller self.tasks_manager = tasks_manager diff --git a/main.py b/main.py index 2775820d..260d7937 100644 --- a/main.py +++ b/main.py @@ -106,8 +106,7 @@ if __name__ == "__main__": # start the database database = peewee.SqliteDatabase( - helper.db_path, - pragmas={"journal_mode": "wal", "cache_size": -1024 * 10} + helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10} ) database_proxy.initialize(database) From b5cac0e3855d42489181134a3d9187033b0669dd Mon Sep 17 00:00:00 2001 From: Zedifus Date: Mon, 11 Apr 2022 11:14:32 +0100 Subject: [PATCH 04/19] Fix remaining minor lint warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These can't be handled by ⬛black automatically --- app/classes/controllers/server_perms_controller.py | 4 +++- app/classes/minecraft/serverjars.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/classes/controllers/server_perms_controller.py b/app/classes/controllers/server_perms_controller.py index 942bf61b..a2e422aa 100644 --- a/app/classes/controllers/server_perms_controller.py +++ b/app/classes/controllers/server_perms_controller.py @@ -51,7 +51,9 @@ class Server_Perms_Controller: int(role.role_id), int(old_server_id) ), ) - # Permissions_Servers.add_role_server(new_server_id, role.role_id,"00001000") + # Permissions_Servers.add_role_server( + # new_server_id, role.role_id, "00001000" + # ) # ********************************************************************************** # Servers Permissions Methods diff --git a/app/classes/minecraft/serverjars.py b/app/classes/minecraft/serverjars.py index 85f472a1..c6b39607 100644 --- a/app/classes/minecraft/serverjars.py +++ b/app/classes/minecraft/serverjars.py @@ -3,8 +3,8 @@ import threading import time import shutil import logging -import requests from datetime import datetime +import requests from app.classes.controllers.servers_controller import Servers_Controller from app.classes.models.server_permissions import Permissions_Servers From d417950eae13d298c27eca9a67020d39376f1625 Mon Sep 17 00:00:00 2001 From: computergeek125 Date: Mon, 11 Apr 2022 20:34:46 -0500 Subject: [PATCH 05/19] fix fstrings, refactored console to static --- app/classes/minecraft/mc_ping.py | 24 +++++------ app/classes/minecraft/stats.py | 2 +- app/classes/shared/command.py | 26 ++++++------ app/classes/shared/console.py | 60 ++++++++++++++++----------- app/classes/shared/helpers.py | 26 ++++++------ app/classes/shared/import3.py | 16 ++++--- app/classes/shared/main_controller.py | 22 ++++------ app/classes/shared/migration.py | 5 ++- app/classes/shared/server.py | 56 +++++++++++-------------- app/classes/shared/tasks.py | 33 +++++++-------- app/classes/shared/translation.py | 8 ++-- app/classes/web/ajax_handler.py | 15 +++---- app/classes/web/file_handler.py | 41 ++++++++---------- app/classes/web/tornado_handler.py | 9 ++-- app/classes/web/upload_handler.py | 9 ++-- app/classes/web/websocket_helper.py | 6 ++- main.py | 30 +++++++------- 17 files changed, 190 insertions(+), 198 deletions(-) diff --git a/app/classes/minecraft/mc_ping.py b/app/classes/minecraft/mc_ping.py index 31c248f6..c15eabcf 100644 --- a/app/classes/minecraft/mc_ping.py +++ b/app/classes/minecraft/mc_ping.py @@ -9,13 +9,13 @@ import uuid import random from app.classes.minecraft.bedrock_ping import BedrockPing +from app.classes.shared.console import Console logger = logging.getLogger(__name__) class Server: - def __init__(self, console, data): - self.console = console + def __init__(self, data): self.description = data.get("description") # print(self.description) if isinstance(self.description, dict): @@ -32,19 +32,19 @@ class Server: if "extra" in description.keys(): for e in description["extra"]: # Conversion format code needed only for Java Version - lines.append(get_code_format(self.console, "reset")) + lines.append(get_code_format("reset")) if "bold" in e.keys(): - lines.append(get_code_format(self.console, "bold")) + lines.append(get_code_format("bold")) if "italic" in e.keys(): - lines.append(get_code_format(self.console, "italic")) + lines.append(get_code_format("italic")) if "underlined" in e.keys(): - lines.append(get_code_format(self.console, "underlined")) + lines.append(get_code_format("underlined")) if "strikethrough" in e.keys(): - lines.append(get_code_format(self.console, "strikethrough")) + lines.append(get_code_format("strikethrough")) if "obfuscated" in e.keys(): - lines.append(get_code_format(self.console, "obfuscated")) + lines.append(get_code_format("obfuscated")) if "color" in e.keys(): - lines.append(get_code_format(self.console, e["color"])) + lines.append(get_code_format(e["color"])) # Then append the text if "text" in e.keys(): if e["text"] == "\n": @@ -95,7 +95,7 @@ class Player: return self.name -def get_code_format(console, format_name): +def get_code_format(format_name): root_dir = os.path.abspath(os.path.curdir) format_file = os.path.join(root_dir, "app", "config", "motd_format.json") try: @@ -106,14 +106,14 @@ def get_code_format(console, format_name): return data.get(format_name) else: logger.error(f"Format MOTD Error: format name {format_name} does not exist") - console.error( + Console.error( f"Format MOTD Error: format name {format_name} does not exist" ) return "" except Exception as e: logger.critical(f"Config File Error: Unable to read {format_file} due to {e}") - console.critical(f"Config File Error: Unable to read {format_file} due to {e}") + Console.critical(f"Config File Error: Unable to read {format_file} due to {e}") return "" diff --git a/app/classes/minecraft/stats.py b/app/classes/minecraft/stats.py index 128dae81..fa1504a3 100644 --- a/app/classes/minecraft/stats.py +++ b/app/classes/minecraft/stats.py @@ -133,7 +133,7 @@ class Stats: internal_ip = server["server_ip"] server_port = server["server_port"] - logger.debug("Pinging {internal_ip} on port {server_port}") + logger.debug(f"Pinging {internal_ip} on port {server_port}") if helper_servers.get_server_type_by_id(server_id) != "minecraft-bedrock": int_mc_ping = ping(internal_ip, int(server_port)) diff --git a/app/classes/shared/command.py b/app/classes/shared/command.py index 3a574ea5..961c6d84 100644 --- a/app/classes/shared/command.py +++ b/app/classes/shared/command.py @@ -3,6 +3,7 @@ import cmd import time import threading import logging +from app.classes.shared.console import Console from app.classes.shared.import3 import import3 @@ -13,7 +14,6 @@ class MainPrompt(cmd.Cmd): def __init__(self, helper, tasks_manager, migration_manager): super().__init__() self.helper = helper - self.console = self.helper.console self.tasks_manager = tasks_manager self.migration_manager = migration_manager # overrides the default Prompt @@ -34,20 +34,20 @@ class MainPrompt(cmd.Cmd): elif line == "down": self.migration_manager.down() elif line == "done": - self.console.info(self.migration_manager.done) + Console.info(self.migration_manager.done) elif line == "todo": - self.console.info(self.migration_manager.todo) + Console.info(self.migration_manager.todo) elif line == "diff": - self.console.info(self.migration_manager.diff) + Console.info(self.migration_manager.diff) elif line == "info": - self.console.info(f"Done: {self.migration_manager.done}") - self.console.info(f"FS: {self.migration_manager.todo}") - self.console.info(f"Todo: {self.migration_manager.diff}") + Console.info(f"Done: {self.migration_manager.done}") + Console.info(f"FS: {self.migration_manager.todo}") + Console.info(f"Todo: {self.migration_manager.diff}") elif line.startswith("add "): migration_name = line[len("add ") :] self.migration_manager.create(migration_name, False) else: - self.console.info("Unknown migration command") + Console.info("Unknown migration command") @staticmethod def do_threads(_line): @@ -65,21 +65,21 @@ class MainPrompt(cmd.Cmd): def universal_exit(self): logger.info("Stopping all server daemons / threads") - self.console.info( + Console.info( "Stopping all server daemons / threads - This may take a few seconds" ) self.helper.websocket_helper.disconnect_all() - self.console.info("Waiting for main thread to stop") + Console.info("Waiting for main thread to stop") while True: if self.tasks_manager.get_main_thread_run_status(): sys.exit(0) time.sleep(1) def help_exit(self): - self.console.help("Stops the server if running, Exits the program") + Console.help("Stops the server if running, Exits the program") def help_migrations(self): - self.console.help("Only for advanced users. Use with caution") + Console.help("Only for advanced users. Use with caution") def help_import3(self): - self.console.help("Import users and servers from Crafty 3") + Console.help("Import users and servers from Crafty 3") diff --git a/app/classes/shared/console.py b/app/classes/shared/console.py index f2c21967..d885298e 100644 --- a/app/classes/shared/console.py +++ b/app/classes/shared/console.py @@ -28,44 +28,56 @@ class Console: else: print(message) - def magenta(self, message): - self.do_print(message, "magenta") + @staticmethod + def magenta(message): + Console.do_print(message, "magenta") - def cyan(self, message): - self.do_print(message, "cyan") + @staticmethod + def cyan(message): + Console.do_print(message, "cyan") - def yellow(self, message): - self.do_print(message, "yellow") + @staticmethod + def yellow(message): + Console.do_print(message, "yellow") - def red(self, message): - self.do_print(message, "red") + @staticmethod + def red(message): + Console.do_print(message, "red") - def green(self, message): - self.do_print(message, "green") + @staticmethod + def green(message): + Console.do_print(message, "green") - def white(self, message): - self.do_print(message, "white") + @staticmethod + def white(message): + Console.do_print(message, "white") - def debug(self, message): + @staticmethod + def debug(message): dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p") - self.magenta(f"[+] Crafty: {dt} - DEBUG:\t{message}") + Console.magenta(f"[+] Crafty: {dt} - DEBUG:\t{message}") - def info(self, message): + @staticmethod + def info(message): dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p") - self.white(f"[+] Crafty: {dt} - INFO:\t{message}") + Console.white(f"[+] Crafty: {dt} - INFO:\t{message}") - def warning(self, message): + @staticmethod + def warning(message): dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p") - self.cyan(f"[+] Crafty: {dt} - WARNING:\t{message}") + Console.cyan(f"[+] Crafty: {dt} - WARNING:\t{message}") - def error(self, message): + @staticmethod + def error(message): dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p") - self.yellow(f"[+] Crafty: {dt} - ERROR:\t{message}") + Console.yellow(f"[+] Crafty: {dt} - ERROR:\t{message}") - def critical(self, message): + @staticmethod + def critical(message): dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p") - self.red(f"[+] Crafty: {dt} - CRITICAL:\t{message}") + Console.red(f"[+] Crafty: {dt} - CRITICAL:\t{message}") - def help(self, message): + @staticmethod + def help(message): dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p") - self.green(f"[+] Crafty: {dt} - HELP:\t{message}") + Console.green(f"[+] Crafty: {dt} - HELP:\t{message}") diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index e3085c71..80dcec59 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -19,6 +19,7 @@ from socket import gethostname from contextlib import suppress import psutil +from app.classes.shared.console import Console from app.classes.shared.installer import installer from app.classes.shared.file_helpers import FileHelpers from app.classes.shared.translation import Translation @@ -41,8 +42,7 @@ except ModuleNotFoundError as err: class Helpers: allowed_quotes = ['"', "'", "`"] - def __init__(self, console): - self.console = console + def __init__(self): self.root_dir = os.path.abspath(os.path.curdir) self.config_dir = os.path.join(self.root_dir, "app", "config") self.webroot = os.path.join(self.root_dir, "app", "frontend") @@ -200,14 +200,14 @@ class Helpers: else: logger.error(f"Config File Error: setting {key} does not exist") - self.console.error(f"Config File Error: setting {key} does not exist") + Console.error(f"Config File Error: setting {key} does not exist") return default_return except Exception as e: logger.critical( f"Config File Error: Unable to read {self.settings_file} due to {e}" ) - self.console.critical( + Console.critical( f"Config File Error: Unable to read {self.settings_file} due to {e}" ) @@ -224,7 +224,7 @@ class Helpers: else: logger.error(f"Config File Error: setting {key} does not exist") - self.console.error(f"Config File Error: setting {key} does not exist") + Console.error(f"Config File Error: setting {key} does not exist") return default_return with open(self.settings_file, "w", encoding="utf-8") as f: @@ -234,7 +234,7 @@ class Helpers: logger.critical( f"Config File Error: Unable to read {self.settings_file} due to {e}" ) - self.console.critical( + Console.critical( f"Config File Error: Unable to read {self.settings_file} due to {e}" ) @@ -260,7 +260,7 @@ class Helpers: version_data = json.load(f) except Exception as e: - self.console.critical(f"Unable to get version data! \n{e}") + Console.critical(f"Unable to get version data! \n{e}") return version_data @@ -470,13 +470,13 @@ class Helpers: with suppress(FileExistsError): os.makedirs(os.path.join(self.root_dir, "logs")) except Exception as e: - self.console.error(f"Failed to make logs directory with error: {e} ") + Console.error(f"Failed to make logs directory with error: {e} ") # ensure the log file is there try: open(log_file, "a", encoding="utf-8").close() except Exception as e: - self.console.critical(f"Unable to open log file! {e}") + Console.critical(f"Unable to open log file! {e}") sys.exit(1) # del any old session.lock file as this is a new session @@ -576,7 +576,7 @@ class Helpers: pid = data.get("pid") started = data.get("started") if psutil.pid_exists(pid): - self.console.critical( + Console.critical( f"Another Crafty Controller agent seems to be running..." f"\npid: {pid} \nstarted on: {started}" ) @@ -591,7 +591,7 @@ class Helpers: except Exception as e: logger.error(f"Failed to locate existing session.lock with error: {e} ") - self.console.error( + Console.error( f"Failed to locate existing session.lock with error: {e} " ) @@ -693,12 +693,12 @@ class Helpers: logger.info("Cert and Key files already exists, not creating them.") return True - self.console.info("Generating a self signed SSL") + Console.info("Generating a self signed SSL") logger.info("Generating a self signed SSL") # create a key pair logger.info("Generating a key pair. This might take a moment.") - self.console.info("Generating a key pair. This might take a moment.") + Console.info("Generating a key pair. This might take a moment.") k = crypto.PKey() k.generate_key(crypto.TYPE_RSA, 4096) diff --git a/app/classes/shared/import3.py b/app/classes/shared/import3.py index b3854d12..6d36371d 100644 --- a/app/classes/shared/import3.py +++ b/app/classes/shared/import3.py @@ -3,6 +3,7 @@ import os import logging from app.classes.controllers.users_controller import helper_users +from app.classes.shared.console import Console logger = logging.getLogger(__name__) @@ -10,7 +11,6 @@ logger = logging.getLogger(__name__) class import3: def __init__(self, helper, controller): self.helper = helper - self.console = self.helper.console self.controller = controller def start_import(self): @@ -21,13 +21,11 @@ class import3: ) ) if not os.path.exists(folder): - self.console.info( + Console.info( "Crafty cannot find the path you entered. " "Does Crafty's user have permission to access it?" ) - self.console.info( - "Please run the import3 command again and enter a valid path." - ) + Console.info("Please run the import3 command again and enter a valid path.") else: with open(os.path.join(folder, "users.json"), encoding="utf-8") as f: user_json = json.loads(f.read()) @@ -41,10 +39,10 @@ class import3: if isinstance(json_data, list): for user in json_data: helper_users.add_rawpass_user(user["username"], user["password"]) - self.console.info(f"Imported user {user['username']} from Crafty 3") + Console.info(f"Imported user {user['username']} from Crafty 3") logger.info(f"Imported user {user['username']} from Crafty 3") else: - self.console.info( + Console.info( "There is only one user detected. " "Cannot create duplicate Admin account." ) @@ -65,7 +63,7 @@ class import3: max_mem=(int(server["memory_max"]) / 1000), port=server["server_port"], ) - self.console.info( + Console.info( f"Imported server {server['server_name']}[{server['id']}] " f"from Crafty 3 to new server id {new_server_id}" ) @@ -82,7 +80,7 @@ class import3: max_mem=(int(json_data["memory_max"]) / 1000), port=json_data["server_port"], ) - self.console.info( + Console.info( f"Imported server {json_data['server_name']}[{json_data['id']}] " f"from Crafty 3 to new server id {new_server_id}" ) diff --git a/app/classes/shared/main_controller.py b/app/classes/shared/main_controller.py index 3dde3e3c..3bb16e1c 100644 --- a/app/classes/shared/main_controller.py +++ b/app/classes/shared/main_controller.py @@ -23,6 +23,7 @@ from app.classes.models.users import helper_users from app.classes.models.management import helpers_management from app.classes.models.servers import helper_servers from app.classes.shared.authentication import Authentication +from app.classes.shared.console import Console from app.classes.shared.helpers import Helpers from app.classes.shared.server import Server from app.classes.shared.file_helpers import FileHelpers @@ -36,7 +37,6 @@ logger = logging.getLogger(__name__) class Controller: def __init__(self, database, helper): self.helper = helper - self.console = self.helper.console self.server_jars = ServerJars(helper) self.users_helper = helper_users(database, self.helper) self.servers_helper = helper_servers(database) @@ -94,7 +94,7 @@ class Controller: f"Skipping this server" ) - self.console.warning( + Console.warning( f"Unable to find server {s['server_name']} at path {s['path']}. " f"Skipping this server" ) @@ -107,9 +107,7 @@ class Controller: # if the properties file isn't there, let's warn if not Helpers.check_file_exists(settings_file): logger.error(f"Unable to find {settings_file}. Skipping this server.") - self.console.error( - f"Unable to find {settings_file}. Skipping this server." - ) + Console.error(f"Unable to find {settings_file}. Skipping this server.") continue settings = ServerProps(settings_file) @@ -132,7 +130,7 @@ class Controller: self.refresh_server_settings(s["server_id"]) - self.console.info( + Console.info( f"Loaded Server: ID {s['server_id']}" + f" | Name: {s['server_name']}" + f" | Autostart: {s['auto_start']}" @@ -314,14 +312,14 @@ class Controller: def stop_all_servers(self): servers = self.list_running_servers() logger.info(f"Found {len(servers)} running server(s)") - self.console.info(f"Found {len(servers)} running server(s)") + Console.info(f"Found {len(servers)} running server(s)") logger.info("Stopping All Servers") - self.console.info("Stopping All Servers") + Console.info("Stopping All Servers") for s in servers: logger.info(f"Stopping Server ID {s['id']} - {s['name']}") - self.console.info(f"Stopping Server ID {s['id']} - {s['name']}") + Console.info(f"Stopping Server ID {s['id']} - {s['name']}") self.stop_server(s["id"]) @@ -329,7 +327,7 @@ class Controller: time.sleep(2) logger.info("All Servers Stopped") - self.console.info("All Servers Stopped") + Console.info("All Servers Stopped") def stop_server(self, server_id): # issue the stop command @@ -807,9 +805,7 @@ class Controller: server_name = server_data["server_name"] logger.info(f"Deleting Server: ID {server_id} | Name: {server_name} ") - self.console.info( - f"Deleting Server: ID {server_id} | Name: {server_name} " - ) + Console.info(f"Deleting Server: ID {server_id} | Name: {server_name} ") srv_obj = s["server_obj"] running = srv_obj.check_running() diff --git a/app/classes/shared/migration.py b/app/classes/shared/migration.py index 0edc29e2..6d1bfba8 100644 --- a/app/classes/shared/migration.py +++ b/app/classes/shared/migration.py @@ -16,6 +16,7 @@ from playhouse.migrate import ( make_index_name, ) +from app.classes.shared.console import Console from app.classes.shared.helpers import Helpers logger = logging.getLogger(__name__) @@ -398,13 +399,13 @@ class MigrationManager(object): Runs all unapplied migrations. """ logger.info("Starting migrations") - self.helper.console.info("Starting migrations") + Console.info("Starting migrations") done = [] diff = self.diff if not diff: logger.info("There is nothing to migrate") - self.helper.console.info("There is nothing to migrate") + Console.info("There is nothing to migrate") return done migrator = self.migrator diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index a40b3523..3900f822 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -20,6 +20,7 @@ from app.classes.models.servers import Server_Stats, helper_servers from app.classes.models.management import helpers_management from app.classes.models.users import helper_users from app.classes.models.server_permissions import Permissions_Servers +from app.classes.shared.console import Console from app.classes.shared.helpers import Helpers from app.classes.shared.file_helpers import FileHelpers @@ -93,7 +94,6 @@ class Server: def __init__(self, helper, management_helper, stats): self.helper = helper self.management_helper = management_helper - self.console = self.helper.console # holders for our process self.process = None self.line = False @@ -149,9 +149,7 @@ class Server: delay = int(self.settings["auto_start_delay"]) logger.info(f"Scheduling server {self.name} to start in {delay} seconds") - self.console.info( - f"Scheduling server {self.name} to start in {delay} seconds" - ) + Console.info(f"Scheduling server {self.name} to start in {delay} seconds") self.server_scheduler.add_job( self.run_scheduled_server, @@ -161,7 +159,7 @@ class Server: ) def run_scheduled_server(self): - self.console.info(f"Starting server ID: {self.server_id} - {self.name}") + Console.info(f"Starting server ID: {self.server_id} - {self.name}") logger.info(f"Starting server ID: {self.server_id} - {self.name}") # Sets waiting start to false since we're attempting to start the server. helper_servers.set_waiting_start(self.server_id, False) @@ -182,7 +180,7 @@ class Server: # Register an shedule for polling server stats when running logger.info(f"Polling server statistics {self.name} every {5} seconds") - self.console.info(f"Polling server statistics {self.name} every {5} seconds") + Console.info(f"Polling server statistics {self.name} every {5} seconds") try: self.server_scheduler.add_job( self.realtime_stats, @@ -213,19 +211,17 @@ class Server: logger.critical( f"Server executable path: {full_path} does not seem to exist" ) - self.console.critical( + Console.critical( f"Server executable path: {full_path} does not seem to exist" ) if not Helpers.check_path_exists(self.server_path): logger.critical(f"Server path: {self.server_path} does not seem to exits") - self.console.critical( - f"Server path: {self.server_path} does not seem to exits" - ) + Console.critical(f"Server path: {self.server_path} does not seem to exits") if not Helpers.check_writeable(self.server_path): logger.critical(f"Unable to write/access {self.server_path}") - self.console.critical(f"Unable to write/access {self.server_path}") + Console.critical(f"Unable to write/access {self.server_path}") def start_server(self, user_id): if not user_id: @@ -253,16 +249,14 @@ class Server: # fail safe in case we try to start something already running if self.check_running(): logger.error("Server is already running - Cancelling Startup") - self.console.error("Server is already running - Cancelling Startup") + Console.error("Server is already running - Cancelling Startup") return False if self.check_update(): logger.error("Server is updating. Terminating startup.") return False logger.info(f"Launching Server {self.name} with command {self.server_command}") - self.console.info( - f"Launching Server {self.name} with command {self.server_command}" - ) + Console.info(f"Launching Server {self.name} with command {self.server_command}") # Checks for eula. Creates one if none detected. # If EULA is detected and not set to true we offer to set it true. @@ -424,7 +418,7 @@ class Server: if self.process.poll() is None: logger.info(f"Server {self.name} running with PID {self.process.pid}") - self.console.info(f"Server {self.name} running with PID {self.process.pid}") + Console.info(f"Server {self.name} running with PID {self.process.pid}") self.is_crashed = False helper_servers.server_crash_reset(self.server_id) self.record_server_stats() @@ -471,7 +465,7 @@ class Server: f"Server PID {self.process.pid} died right after starting " f"- is this a server config issue?" ) - self.console.critical( + Console.critical( f"Server PID {self.process.pid} died right after starting " f"- is this a server config issue?" ) @@ -481,7 +475,7 @@ class Server: f"Server {self.name} has crash detection enabled " f"- starting watcher task" ) - self.console.info( + Console.info( f"Server {self.name} has crash detection enabled " f"- starting watcher task" ) @@ -524,7 +518,7 @@ class Server: f"Server {self.name} has crash detection enabled " f"- starting watcher task" ) - self.console.info( + Console.info( f"Server {self.name} has crash detection enabled " "- starting watcher task" ) @@ -557,7 +551,7 @@ class Server: running = self.check_running() if not running: logger.info(f"Can't stop server {self.name} if it's not running") - self.console.info(f"Can't stop server {self.name} if it's not running") + Console.info(f"Can't stop server {self.name} if it's not running") return x = 0 @@ -573,7 +567,7 @@ class Server: f"seconds until force close)" ) logger.info(logstr) - self.console.info(logstr) + Console.info(logstr) running = self.check_running() time.sleep(2) @@ -582,13 +576,13 @@ class Server: logger.info( f"Server {server_name} is still running - Forcing the process down" ) - self.console.info( + Console.info( f"Server {server_name} is still running - Forcing the process down" ) self.kill() logger.info(f"Stopped Server {server_name} with PID {server_pid}") - self.console.info(f"Stopped Server {server_name} with PID {server_pid}") + Console.info(f"Stopped Server {server_name} with PID {server_pid}") # massive resetting of variables self.cleanup_server_object() @@ -633,7 +627,7 @@ class Server: if not self.check_running() and command.lower() != "start": logger.warning(f'Server not running, unable to send command "{command}"') return False - self.console.info(f"COMMAND TIME: {command}") + Console.info(f"COMMAND TIME: {command}") logger.debug(f"Sending command {command} to server") # send it @@ -657,7 +651,7 @@ class Server: f"The server {name} has crashed and will be restarted. " f"Restarting server" ) - self.console.critical( + Console.critical( f"The server {name} has crashed and will be restarted. " f"Restarting server" ) @@ -668,7 +662,7 @@ class Server: f"The server {name} has crashed, " f"crash detection is disabled and it will not be restarted" ) - self.console.critical( + Console.critical( f"The server {name} has crashed, " f"crash detection is disabled and it will not be restarted" ) @@ -737,7 +731,7 @@ class Server: f"Server {self.name} has been restarted {self.restart_count}" f" times. It has crashed, not restarting." ) - self.console.critical( + Console.critical( f"Server {self.name} has been restarted {self.restart_count}" f" times. It has crashed, not restarting." ) @@ -751,7 +745,7 @@ class Server: def remove_watcher_thread(self): logger.info("Removing old crash detection watcher thread") - self.console.info("Removing old crash detection watcher thread") + Console.info("Removing old crash detection watcher thread") self.server_scheduler.remove_job("c_" + str(self.server_id)) def agree_eula(self, user_id): @@ -1184,7 +1178,7 @@ class Server: "/status", "update_server_status", servers_ping ) except: - self.console.critical("Can't broadcast server status to websocket") + Console.critical("Can't broadcast server status to websocket") def get_servers_stats(self): @@ -1211,7 +1205,7 @@ class Server: server_port = server["server_port"] server_name = server.get("server_name", f"ID#{server_id}") - logger.debug("Pinging server '{server}' on {internal_ip}:{server_port}") + logger.debug(f"Pinging server '{server}' on {internal_ip}:{server_port}") if helper_servers.get_server_type_by_id(server_id) == "minecraft-bedrock": int_mc_ping = ping_bedrock(internal_ip, int(server_port)) else: @@ -1285,7 +1279,7 @@ class Server: internal_ip = server["server_ip"] server_port = server["server_port"] - logger.debug("Pinging {internal_ip} on port {server_port}") + logger.debug(f"Pinging {internal_ip} on port {server_port}") if helper_servers.get_server_type_by_id(self.server_id) != "minecraft-bedrock": int_mc_ping = ping(internal_ip, int(server_port)) diff --git a/app/classes/shared/tasks.py b/app/classes/shared/tasks.py index ecd77f36..cb004691 100644 --- a/app/classes/shared/tasks.py +++ b/app/classes/shared/tasks.py @@ -11,6 +11,7 @@ from apscheduler.triggers.cron import CronTrigger from app.classes.models.management import helpers_management from app.classes.models.users import helper_users +from app.classes.shared.console import Console from app.classes.web.tornado_handler import Webserver logger = logging.getLogger("apscheduler") @@ -119,7 +120,7 @@ class TasksManager: logger.info("Caught error during shutdown", exc_info=True) logger.info("***** Crafty Shutting Down *****\n\n") - self.helper.console.info("***** Crafty Shutting Down *****\n\n") + Console.info("***** Crafty Shutting Down *****\n\n") self.main_thread_exiting = True def start_webserver(self): @@ -127,7 +128,7 @@ class TasksManager: def reload_webserver(self): self.tornado.stop_web_server() - self.helper.console.info("Waiting 3 seconds") + Console.info("Waiting 3 seconds") time.sleep(3) self.webserver_thread = threading.Thread( target=self.tornado.run_tornado, daemon=True, name="tornado_thread" @@ -139,16 +140,16 @@ class TasksManager: def start_scheduler(self): logger.info("Launching Scheduler Thread...") - self.helper.console.info("Launching Scheduler Thread...") + Console.info("Launching Scheduler Thread...") self.schedule_thread.start() logger.info("Launching command thread...") - self.helper.console.info("Launching command thread...") + Console.info("Launching command thread...") self.command_thread.start() logger.info("Launching log watcher...") - self.helper.console.info("Launching log watcher...") + Console.info("Launching log watcher...") self.log_watcher_thread.start() logger.info("Launching realtime thread...") - self.helper.console.info("Launching realtime thread...") + Console.info("Launching realtime thread...") self.realtime_thread.start() def scheduler_thread(self): @@ -177,10 +178,8 @@ class TasksManager: ], ) except Exception as e: - self.helper.console.error( - f"Failed to schedule task with error: {e}." - ) - self.helper.console.warning("Removing failed task from DB.") + Console.error(f"Failed to schedule task with error: {e}.") + Console.warning("Removing failed task from DB.") logger.error(f"Failed to schedule task with error: {e}.") logger.warning("Removing failed task from DB.") # remove items from DB if task fails to add to apscheduler @@ -274,10 +273,8 @@ class TasksManager: ], ) except Exception as e: - self.helper.console.error( - f"Failed to schedule task with error: {e}." - ) - self.helper.console.warning("Removing failed task from DB.") + Console.error(f"Failed to schedule task with error: {e}.") + Console.warning("Removing failed task from DB.") logger.error(f"Failed to schedule task with error: {e}.") logger.warning("Removing failed task from DB.") # remove items from DB if task fails to add to apscheduler @@ -387,10 +384,8 @@ class TasksManager: ], ) except Exception as e: - self.helper.console.error( - f"Failed to schedule task with error: {e}." - ) - self.helper.console.info("Removing failed task from DB.") + Console.error(f"Failed to schedule task with error: {e}.") + Console.info("Removing failed task from DB.") self.controller.management_helper.delete_scheduled_task(sch_id) else: if job_data["interval_type"] == "hours": @@ -499,7 +494,7 @@ class TasksManager: logger.info( f"Stats collection frequency set to {stats_update_frequency} seconds" ) - self.helper.console.info( + Console.info( f"Stats collection frequency set to {stats_update_frequency} seconds" ) diff --git a/app/classes/shared/translation.py b/app/classes/shared/translation.py index 17914eb8..5c79c911 100644 --- a/app/classes/shared/translation.py +++ b/app/classes/shared/translation.py @@ -3,6 +3,8 @@ import logging import os import typing as t +from app.classes.shared.console import Console + logger = logging.getLogger(__name__) @@ -59,7 +61,7 @@ class Translation: f"Translation File Error: page {page} " f"does not exist for lang {language}" ) - self.helper.console.error( + Console.error( f"Translation File Error: page {page} " f"does not exist for lang {language}" ) @@ -73,7 +75,7 @@ class Translation: f"Translation File Error: word {word} does not exist on page " f"{page} for lang {language}" ) - self.helper.console.error( + Console.error( f"Translation File Error: word {word} does not exist on page " f"{page} for lang {language}" ) @@ -83,7 +85,7 @@ class Translation: logger.critical( f"Translation File Error: Unable to read {language_file} due to {e}" ) - self.helper.console.critical( + Console.critical( f"Translation File Error: Unable to read {language_file} due to {e}" ) return None diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index 88d5f435..1420b78a 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -8,6 +8,7 @@ import tornado.web import tornado.escape from app.classes.models.server_permissions import Enum_Permissions_Server +from app.classes.shared.console import Console from app.classes.shared.helpers import Helpers from app.classes.shared.server import ServerOutBuf from app.classes.web.base_handler import BaseHandler @@ -283,9 +284,7 @@ class AjaxHandler(BaseHandler): if server_id is None: logger.warning("Server ID not found in send_command ajax call") - self.helper.console.warning( - "Server ID not found in send_command ajax call" - ) + Console.warning("Server ID not found in send_command ajax call") srv_obj = self.controller.get_server_obj(server_id) @@ -484,7 +483,7 @@ class AjaxHandler(BaseHandler): ) server_id = self.get_argument("id", None) - self.helper.console.warning(f"Delete {file_path} for server {server_id}") + Console.warning(f"Delete {file_path} for server {server_id}") if not self.check_server_id(server_id, "del_backup"): return @@ -502,9 +501,7 @@ class AjaxHandler(BaseHandler): ) ) or not Helpers.check_file_exists(os.path.abspath(file_path)): logger.warning(f"Invalid path in del_backup ajax call ({file_path})") - self.helper.console.warning( - f"Invalid path in del_backup ajax call ({file_path})" - ) + Console.warning(f"Invalid path in del_backup ajax call ({file_path})") return # Delete the file @@ -567,7 +564,7 @@ class AjaxHandler(BaseHandler): logger.warning( f"Server ID not defined in {page_name} ajax call ({server_id})" ) - self.helper.console.warning( + Console.warning( f"Server ID not defined in {page_name} ajax call ({server_id})" ) return @@ -579,7 +576,7 @@ class AjaxHandler(BaseHandler): logger.warning( f"Server ID not found in {page_name} ajax call ({server_id})" ) - self.helper.console.warning( + Console.warning( f"Server ID not found in {page_name} ajax call ({server_id})" ) return diff --git a/app/classes/web/file_handler.py b/app/classes/web/file_handler.py index 5118acf1..63c7d57a 100644 --- a/app/classes/web/file_handler.py +++ b/app/classes/web/file_handler.py @@ -5,6 +5,7 @@ import tornado.web import tornado.escape from app.classes.models.server_permissions import Enum_Permissions_Server +from app.classes.shared.console import Console from app.classes.shared.helpers import Helpers from app.classes.shared.file_helpers import FileHelpers from app.classes.web.base_handler import BaseHandler @@ -66,7 +67,7 @@ class FileHandler(BaseHandler): logger.warning( f"Invalid path in get_file file file ajax call ({file_path})" ) - self.helper.self.helper.console.warning( + Console.warning( f"Invalid path in get_file file file ajax call ({file_path})" ) return @@ -175,7 +176,7 @@ class FileHandler(BaseHandler): logger.warning( f"Invalid path in create_file file ajax call ({file_path})" ) - self.helper.self.helper.console.warning( + Console.warning( f"Invalid path in create_file file ajax call ({file_path})" ) return @@ -209,7 +210,7 @@ class FileHandler(BaseHandler): logger.warning( f"Invalid path in create_dir file ajax call ({dir_path})" ) - self.helper.self.helper.console.warning( + Console.warning( f"Invalid path in create_dir file ajax call ({dir_path})" ) return @@ -257,9 +258,7 @@ class FileHandler(BaseHandler): self.get_body_argument("file_path", default=None, strip=True) ) - self.helper.self.helper.console.warning( - f"Delete {file_path} for server {server_id}" - ) + Console.warning(f"Delete {file_path} for server {server_id}") if not self.check_server_id(server_id, "del_file"): return @@ -277,7 +276,7 @@ class FileHandler(BaseHandler): ) ) or not Helpers.check_file_exists(os.path.abspath(file_path)): logger.warning(f"Invalid path in del_file file ajax call ({file_path})") - self.helper.console.warning( + Console.warning( f"Invalid path in del_file file ajax call ({file_path})" ) return @@ -294,7 +293,7 @@ class FileHandler(BaseHandler): self.get_body_argument("dir_path", default=None, strip=True) ) - self.helper.console.warning(f"Delete {dir_path} for server {server_id}") + Console.warning(f"Delete {dir_path} for server {server_id}") if not self.check_server_id(server_id, "del_dir"): return @@ -306,9 +305,7 @@ class FileHandler(BaseHandler): Helpers.get_os_understandable_path(server_info["path"]), dir_path ) or not Helpers.check_path_exists(os.path.abspath(dir_path)): logger.warning(f"Invalid path in del_file file ajax call ({dir_path})") - self.helper.console.warning( - f"Invalid path in del_file file ajax call ({dir_path})" - ) + Console.warning(f"Invalid path in del_file file ajax call ({dir_path})") return # Delete the directory @@ -366,7 +363,7 @@ class FileHandler(BaseHandler): logger.warning( f"Invalid path in save_file file ajax call ({file_path})" ) - self.helper.console.warning( + Console.warning( f"Invalid path in save_file file ajax call ({file_path})" ) return @@ -394,9 +391,7 @@ class FileHandler(BaseHandler): if item_path is None or new_item_name is None: logger.warning("Invalid path(s) in rename_file file ajax call") - self.helper.console.warning( - "Invalid path(s) in rename_file file ajax call" - ) + Console.warning("Invalid path(s) in rename_file file ajax call") return if not Helpers.in_path( @@ -408,7 +403,7 @@ class FileHandler(BaseHandler): logger.warning( f"Invalid old name path in rename_file file ajax call ({server_id})" ) - self.helper.console.warning( + Console.warning( f"Invalid old name path in rename_file file ajax call ({server_id})" ) return @@ -424,7 +419,7 @@ class FileHandler(BaseHandler): logger.warning( f"Invalid new name path in rename_file file ajax call ({server_id})" ) - self.helper.console.warning( + Console.warning( f"Invalid new name path in rename_file file ajax call ({server_id})" ) return @@ -472,9 +467,7 @@ class FileHandler(BaseHandler): if item_path is None or new_item_name is None: logger.warning("Invalid path(s) in rename_file file ajax call") - self.helper.console.warning( - "Invalid path(s) in rename_file file ajax call" - ) + Console.warning("Invalid path(s) in rename_file file ajax call") return if not Helpers.in_path( @@ -486,7 +479,7 @@ class FileHandler(BaseHandler): logger.warning( f"Invalid old name path in rename_file file ajax call ({server_id})" ) - self.helper.console.warning( + Console.warning( f"Invalid old name path in rename_file file ajax call ({server_id})" ) return @@ -502,7 +495,7 @@ class FileHandler(BaseHandler): logger.warning( f"Invalid new name path in rename_file file ajax call ({server_id})" ) - self.helper.console.warning( + Console.warning( f"Invalid new name path in rename_file file ajax call ({server_id})" ) return @@ -515,7 +508,7 @@ class FileHandler(BaseHandler): logger.warning( f"Server ID not defined in {page_name} file ajax call ({server_id})" ) - self.helper.console.warning( + Console.warning( f"Server ID not defined in {page_name} file ajax call ({server_id})" ) return @@ -527,7 +520,7 @@ class FileHandler(BaseHandler): logger.warning( f"Server ID not found in {page_name} file ajax call ({server_id})" ) - self.helper.console.warning( + Console.warning( f"Server ID not found in {page_name} file ajax call ({server_id})" ) return diff --git a/app/classes/web/tornado_handler.py b/app/classes/web/tornado_handler.py index 1b3f6775..b0b1a3b0 100644 --- a/app/classes/web/tornado_handler.py +++ b/app/classes/web/tornado_handler.py @@ -11,6 +11,7 @@ import tornado.escape import tornado.locale import tornado.httpserver +from app.classes.shared.console import Console from app.classes.shared.helpers import Helpers from app.classes.web.file_handler import FileHandler from app.classes.web.public_handler import PublicHandler @@ -211,21 +212,21 @@ class Webserver: f"https://{Helpers.get_local_ip()}:{https_port} " f"is up and ready for connections." ) - self.helper.console.info( + Console.info( f"https://{Helpers.get_local_ip()}:{https_port} " f"is up and ready for connections." ) - self.helper.console.info("Server Init Complete: Listening For Connections:") + Console.info("Server Init Complete: Listening For Connections:") self.ioloop = tornado.ioloop.IOLoop.current() self.ioloop.start() def stop_web_server(self): logger.info("Shutting Down Web Server") - self.helper.console.info("Shutting Down Web Server") + Console.info("Shutting Down Web Server") self.ioloop.stop() self.HTTP_Server.stop() self.HTTPS_Server.stop() logger.info("Web Server Stopped") - self.helper.console.info("Web Server Stopped") + Console.info("Web Server Stopped") diff --git a/app/classes/web/upload_handler.py b/app/classes/web/upload_handler.py index 990fc0fc..4877d5cc 100644 --- a/app/classes/web/upload_handler.py +++ b/app/classes/web/upload_handler.py @@ -6,6 +6,7 @@ import tornado.options import tornado.httpserver from app.classes.models.server_permissions import Enum_Permissions_Server +from app.classes.shared.console import Console from app.classes.shared.helpers import Helpers from app.classes.shared.main_controller import Controller from app.classes.web.base_handler import BaseHandler @@ -82,12 +83,12 @@ class UploadHandler(BaseHandler): if user_id is None: logger.warning("User ID not found in upload handler call") - self.helper.console.warning("User ID not found in upload handler call") + Console.warning("User ID not found in upload handler call") self.do_upload = False if server_id is None: logger.warning("Server ID not found in upload handler call") - self.helper.console.warning("Server ID not found in upload handler call") + Console.warning("Server ID not found in upload handler call") self.do_upload = False if Enum_Permissions_Server.Files not in exec_user_server_permissions: @@ -95,7 +96,7 @@ class UploadHandler(BaseHandler): f"User {user_id} tried to upload a file to " f"{server_id} without permissions!" ) - self.helper.console.warning( + Console.warning( f"User {user_id} tried to upload a file to " f"{server_id} without permissions!" ) @@ -123,7 +124,7 @@ class UploadHandler(BaseHandler): f"User {user_id} tried to upload a file to {server_id} " f"but the path is not inside of the server!" ) - self.helper.console.warning( + Console.warning( f"User {user_id} tried to upload a file to {server_id} " f"but the path is not inside of the server!" ) diff --git a/app/classes/web/websocket_helper.py b/app/classes/web/websocket_helper.py index 0486f859..68044b5f 100644 --- a/app/classes/web/websocket_helper.py +++ b/app/classes/web/websocket_helper.py @@ -1,6 +1,8 @@ import json import logging +from app.classes.shared.console import Console + logger = logging.getLogger(__name__) @@ -100,7 +102,7 @@ class WebSocketHelper: ) def disconnect_all(self): - self.helper.console.info("Disconnecting WebSocket clients") + Console.info("Disconnecting WebSocket clients") for client in self.clients: client.close() - self.helper.console.info("Disconnected WebSocket clients") + Console.info("Disconnected WebSocket clients") diff --git a/main.py b/main.py index 260d7937..ccadb3b6 100644 --- a/main.py +++ b/main.py @@ -11,14 +11,14 @@ from app.classes.shared.console import Console from app.classes.shared.helpers import Helpers console = Console() -helper = Helpers(console) +helper = Helpers() if helper.checkRoot(): - console.critical( + Console.critical( "Root detected. Root/Admin access denied. " "Run Crafty again with non-elevated permissions." ) time.sleep(5) - console.critical("Crafty shutting down. Root/Admin access denied.") + Console.critical("Crafty shutting down. Root/Admin access denied.") sys.exit(0) # pylint: disable=wrong-import-position try: @@ -46,7 +46,7 @@ def do_intro(): {'/' * 75} """ - console.magenta(intro) + Console.magenta(intro) def setup_logging(debug=True): @@ -64,7 +64,7 @@ def setup_logging(debug=True): else: logging.basicConfig(level=logging.DEBUG) logging.warning(f"Unable to read logging config from {logging_config_file}") - console.critical(f"Unable to read logging config from {logging_config_file}") + Console.critical(f"Unable to read logging config from {logging_config_file}") # Our Main Starter @@ -94,7 +94,7 @@ if __name__ == "__main__": # setting up the logger object logger = logging.getLogger(__name__) - console.cyan(f"Logging set to: {logger.level}") + Console.cyan(f"Logging set to: {logger.level}") peewee_logger = logging.getLogger("peewee") peewee_logger.setLevel(logging.INFO) @@ -119,8 +119,8 @@ if __name__ == "__main__": fresh_install = installer.is_fresh_install() if fresh_install: - console.debug("Fresh install detected") - console.warning( + Console.debug("Fresh install detected") + Console.warning( f"We have detected a fresh install. Please be sure to forward " f"Crafty's port, {helper.get_setting('https_port')}, " f"through your router/firewall if you would like to be able " @@ -128,7 +128,7 @@ if __name__ == "__main__": ) installer.default_settings() else: - console.debug("Existing install detected") + Console.debug("Existing install detected") # now the tables are created, we can load the tasks_manger and server controller controller = Controller(database, helper) @@ -140,7 +140,7 @@ if __name__ == "__main__": # init servers logger.info("Initializing all servers defined") - console.info("Initializing all servers defined") + Console.info("Initializing all servers defined") controller.init_all_servers() servers = controller.list_defined_servers() @@ -156,10 +156,10 @@ if __name__ == "__main__": tasks_manager.serverjar_cache_refresher() logger.info("Checking Internet. This may take a minute.") - console.info("Checking Internet. This may take a minute.") + Console.info("Checking Internet. This may take a minute.") if not helper.check_internet(): - console.warning( + Console.warning( "We have detected the machine running Crafty has no " "connection to the internet. Client connections to " "the server may be limited." @@ -180,7 +180,7 @@ if __name__ == "__main__": logger.info( f"Recieved {signal.Signals(sig[0]).name} [{sig[0]}], stopping Crafty..." ) - console.info( + Console.info( f"Recieved {signal.Signals(sig[0]).name} [{sig[0]}], stopping Crafty..." ) tasks_manager._main_graceful_exit() @@ -194,7 +194,7 @@ if __name__ == "__main__": except KeyboardInterrupt: print() # for newline logger.info("Recieved SIGINT, stopping Crafty...") - console.info("Recieved SIGINT, stopping Crafty...") + Console.info("Recieved SIGINT, stopping Crafty...") tasks_manager._main_graceful_exit() Crafty.universal_exit() else: @@ -206,7 +206,7 @@ if __name__ == "__main__": time.sleep(1) except KeyboardInterrupt: logger.info("Recieved SIGINT, stopping Crafty...") - console.info("Recieved SIGINT, stopping Crafty...") + Console.info("Recieved SIGINT, stopping Crafty...") break tasks_manager._main_graceful_exit() Crafty.universal_exit() From 12b0f8326d73025e1f331b7afb9ed7b442c9c517 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 12 Apr 2022 17:17:12 -0400 Subject: [PATCH 06/19] Fix bug where no backup dir would exist on clone --- app/classes/web/server_handler.py | 3 ++- app/frontend/templates/panel/dashboard.html | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/classes/web/server_handler.py b/app/classes/web/server_handler.py index 42f9cacd..1482200b 100644 --- a/app/classes/web/server_handler.py +++ b/app/classes/web/server_handler.py @@ -219,6 +219,7 @@ class ServerHandler(BaseHandler): new_server_log_file = str( Helpers.get_os_understandable_path(server_data.get("log_path")) ).replace(server_uuid, new_server_uuid) + backup_path = os.path.join(self.helper.backup_path, new_server_uuid) server_port = server_data.get("server_port") server_type = server_data.get("type") @@ -226,7 +227,7 @@ class ServerHandler(BaseHandler): new_server_name, new_server_uuid, new_server_path, - "", + backup_path, new_server_command, new_executable, new_server_log_file, diff --git a/app/frontend/templates/panel/dashboard.html b/app/frontend/templates/panel/dashboard.html index 9f213905..0d091aef 100644 --- a/app/frontend/templates/panel/dashboard.html +++ b/app/frontend/templates/panel/dashboard.html @@ -588,11 +588,15 @@ $(".clone_button").click(function () { server_id = $(this).attr("data-id"); send_command(server_id, 'clone_server'); - bootbox.alert({ + bootbox.dialog({ backdrop: true, title: '{% raw translate("dashboard", "sendingCommand", data["lang"]) %}', - message: '
      {% raw translate("dashboard", "bePatientClone", data["lang"]) %}
    ' + message: '
      {% raw translate("dashboard", "bePatientClone", data["lang"]) %}
    ', + closeButton: false, }); + setTimeout(function () { + location.reload(); + }, 5000) }); }); From ec6421b62cef84842b39e1bbb404bae467c355df Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 12 Apr 2022 17:37:20 -0400 Subject: [PATCH 07/19] Disable Backups when no path --- app/classes/shared/server.py | 2 + .../templates/panel/server_backup.html | 614 ++++++++++-------- 2 files changed, 333 insertions(+), 283 deletions(-) diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index 3900f822..0971e4e8 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -762,6 +762,8 @@ class Server: return False def backup_server(self): + if self.settings["backup_path"] is "": + return backup_thread = threading.Thread( target=self.a_backup_server, daemon=True, name=f"backup_{self.name}" ) diff --git a/app/frontend/templates/panel/server_backup.html b/app/frontend/templates/panel/server_backup.html index a30fb803..c7654ed3 100644 --- a/app/frontend/templates/panel/server_backup.html +++ b/app/frontend/templates/panel/server_backup.html @@ -9,14 +9,15 @@
    - +
    @@ -24,155 +25,181 @@
    - {% include "parts/details_stats.html %} + {% include "parts/details_stats.html %}
    - {% include "parts/server_controls_list.html %} + {% include "parts/server_controls_list.html %} -
    -
    -
    -
    -
    - {% raw xsrf_form_html() %} - - +
    +
    +
    +
    + + {% raw xsrf_form_html() %} + + - {% if data['backing_up'] %} -
    -
    {{ data['backup_stats']['percent'] }}%
    -
    -

    Backing up {{data['backup_stats']['total_files']}} Files

    - {% end %} - -
    - {% if not data['backing_up'] %} -
    - -
    - {% end %} -
    - {% if data['super_user'] %} - - - {% end %} -
    - -
    - - -
    -
    - - {% if data['backup_config']['compress'] %} - {{ translate('serverBackups', 'compress', data['lang']) }} - {% else %} - {{ translate('serverBackups', 'compress', data['lang']) }} - {% end %} -
    -
    - -
    - -
    - - - - - - + {% if data['backing_up'] %} +
    +
    {{ + data['backup_stats']['percent'] }}%
    - -
    -
    - - -

    {{ translate('serverBackups', 'currentBackups', data['lang']) }}

    - - - - - - - - - {% for backup in data['backup_list'] %} - - - - - - {% end %} - - -
    {{ translate('serverBackups', 'options', data['lang']) }}{{ translate('serverBackups', 'path', data['lang']) }}{{ translate('serverBackups', 'size', data['lang']) }}
    - - - {{ translate('serverBackups', 'download', data['lang']) }} - -
    -
    - - -
    {{ backup['path'] }}{{ backup['size'] }}
    - -
    -
    -
    -
    -
    -
    -
    -

    {{ translate('serverBackups', 'excludedBackups', data['lang']) }}

    -
    -
    -
      - {% for item in data['exclusions'] %} -
    • {{item}}
    • -
      +

      Backing up {{data['backup_stats']['total_files']}} Files

      {% end %} -
    + +
    + {% if not data['backing_up'] %} +
    + +
    + {% end %} +
    + {% if data['super_user'] %} + + + {% end %} +
    + +
    + + +
    +
    + + {% if data['backup_config']['compress'] %} + {{ translate('serverBackups', 'compress', data['lang']) }} + {% else %} + {{ + translate('serverBackups', 'compress', data['lang']) }} + {% end %} +
    +
    + +
    + +
    + + + + + +
    +
    +
    + + +

    {{ translate('serverBackups', 'currentBackups', data['lang']) }}

    + + + + + + + + + {% for backup in data['backup_list'] %} + + + + + + {% end %} + + +
    {{ translate('serverBackups', 'options', data['lang']) }}{{ translate('serverBackups', 'path', data['lang']) }}{{ translate('serverBackups', 'size', data['lang']) }}
    + + + {{ translate('serverBackups', 'download', data['lang']) }} + +
    +
    + + +
    {{ backup['path'] }}{{ backup['size'] }}
    + +
    +
    +
    +
    +
    +
    +
    +

    {{ translate('serverBackups', 'excludedBackups', + data['lang']) }}

    +
    +
    +
      + {% for item in data['exclusions'] %} +
    • {{item}}
    • +
      + {% end %} +
    +
    +
    @@ -183,41 +210,44 @@
    @@ -226,7 +256,7 @@ {% block js %}