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..90a357f1 100644 --- a/app/classes/controllers/roles_controller.py +++ b/app/classes/controllers/roles_controller.py @@ -1,25 +1,28 @@ 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, roles_helper): + self.users_helper = users_helper + self.roles_helper = roles_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 +40,42 @@ 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 self.roles_helper.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..a2e422aa 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,102 @@ 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..c15eabcf 100644 --- a/app/classes/minecraft/mc_ping.py +++ b/app/classes/minecraft/mc_ping.py @@ -9,7 +9,7 @@ import uuid import random from app.classes.minecraft.bedrock_ping import BedrockPing -from app.classes.shared.console import console +from app.classes.shared.console import Console logger = logging.getLogger(__name__) @@ -106,14 +106,14 @@ def get_code_format(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/serverjars.py b/app/classes/minecraft/serverjars.py index 01ad1fb1..c6b39607 100644 --- a/app/classes/minecraft/serverjars.py +++ b/app/classes/minecraft/serverjars.py @@ -4,23 +4,17 @@ import time import shutil import logging from datetime import datetime +import requests 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 +44,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 +102,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 +159,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 +170,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 +178,13 @@ 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 +194,25 @@ 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..fa1504a3 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,9 @@ 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 +87,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 +97,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 +113,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}") @@ -130,8 +133,8 @@ class Stats: internal_ip = server["server_ip"] 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": + 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)) ping_data = {} @@ -232,7 +235,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..28e5796e --- /dev/null +++ b/app/classes/models/base_model.py @@ -0,0 +1,8 @@ +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..a35d4f50 100644 --- a/app/classes/models/crafty_permissions.py +++ b/app/classes/models/crafty_permissions.py @@ -1,35 +1,22 @@ 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 +from app.classes.shared.permission_helper import PermissionHelper + +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 +28,6 @@ class User_Crafty(Model): class Meta: table_name = "user_crafty" - database = database # ********************************************************************************** @@ -68,7 +54,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 +81,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 +96,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 +126,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 +166,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 +176,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 +192,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 = PermissionHelper.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..7ba524b1 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,21 @@ 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 +204,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,45 +226,48 @@ 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)) .where(Role_Servers.server_id == server_id) .execute() ) - user_permissions_mask = role_server[0].permissions + try: + user_permissions_mask = role_server[0].permissions + except: + if user["superuser"]: + user_permissions_mask = "11111111" + else: + user_permissions_mask = "00000000" key_permissions_mask = key.server_permissions - permissions_mask = permission_helper.combine_masks( + 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..961c6d84 100644 --- a/app/classes/shared/command.py +++ b/app/classes/shared/command.py @@ -3,23 +3,21 @@ import cmd import time import threading import logging +from app.classes.shared.console import Console -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.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) + Console.info(self.migration_manager.done) elif line == "todo": - console.info(self.migration_manager.todo) + Console.info(self.migration_manager.todo) elif line == "diff": - console.info(self.migration_manager.diff) + 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}") + 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: - console.info("Unknown migration command") + 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( + 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() + 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): + 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): + 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): + 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..d885298e 100644 --- a/app/classes/shared/console.py +++ b/app/classes/shared/console.py @@ -28,47 +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 = Console() + Console.green(f"[+] Crafty: {dt} - HELP:\t{message}") diff --git a/app/classes/shared/file_helpers.py b/app/classes/shared/file_helpers.py index bc21da51..b6f4d223 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): @@ -110,6 +113,3 @@ class FileHelpers: ) return True - - -file_helper = FileHelpers() diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index 58f3f1fe..80dcec59 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -19,10 +19,11 @@ from socket import gethostname from contextlib import suppress import psutil -from app.classes.shared.console import console +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__) @@ -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") + 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( + 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") + 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( + 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}") + 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} ") + 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}") + 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( + 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( + 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,15 @@ 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 +649,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 +680,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 +689,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") + 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.") + Console.info("Generating a key pair. This might take a moment.") k = crypto.PKey() k.generate_key(crypto.TYPE_RSA, 4096) @@ -756,11 +774,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 +903,27 @@ 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 +955,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 +992,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..6d36371d 100644 --- a/app/classes/shared/import3.py +++ b/app/classes/shared/import3.py @@ -2,16 +2,16 @@ 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 +from app.classes.shared.console import Console logger = logging.getLogger(__name__) class import3: - def __init__(self): - self.controller = Controller() + def __init__(self, helper, controller): + self.helper = helper + self.controller = controller def start_import(self): folder = os.path.normpath( @@ -21,11 +21,11 @@ class import3: ) ) if not os.path.exists(folder): - console.info( + 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.") + 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 +34,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"]) + Console.info(f"Imported user {user['username']} from Crafty 3") logger.info(f"Imported user {user['username']} from Crafty 3") else: - console.info( + Console.info( "There is only one user detected. " "Cannot create duplicate Admin account." ) @@ -52,8 +51,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 +63,7 @@ class import3: max_mem=(int(server["memory_max"]) / 1000), port=server["server_port"], ) - 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"], ) - 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}" ) @@ -90,6 +88,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..2fccef9c 100644 --- a/app/classes/shared/main_controller.py +++ b/app/classes/shared/main_controller.py @@ -6,6 +6,11 @@ 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 @@ -15,40 +20,40 @@ from app.classes.controllers.server_perms_controller import Server_Perms_Control 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.roles import helper_roles 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.console import Console +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.server_jars = ServerJars(helper) + self.users_helper = helper_users(database, self.helper) + self.roles_helper = helper_roles(database) + 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.roles_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 +88,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( + 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.") + Console.error(f"Unable to find {settings_file}. Skipping this server.") continue settings = ServerProps(settings_file) @@ -112,7 +117,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 +132,7 @@ class Controller: self.refresh_server_settings(s["server_id"]) - console.info( + Console.info( f"Loaded Server: ID {s['server_id']}" + f" | Name: {s['server_name']}" + f" | Autostart: {s['auto_start']}" @@ -154,7 +159,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 +200,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 +213,19 @@ 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 +236,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 +261,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 +293,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 +314,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)") + Console.info(f"Found {len(servers)} running server(s)") logger.info("Stopping All Servers") - console.info("Stopping All Servers") + 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']}") + Console.info(f"Stopping Server ID {s['id']} - {s['name']}") self.stop_server(s["id"]) @@ -322,7 +329,7 @@ class Controller: time.sleep(2) logger.info("All Servers Stopped") - console.info("All Servers Stopped") + Console.info("All Servers Stopped") def stop_server(self, server_id): # issue the stop command @@ -338,12 +345,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 +358,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 +378,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 +407,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 +437,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(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}") @@ -464,16 +471,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 +509,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 +528,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 +550,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 +587,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 +621,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 +642,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 +668,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 +690,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 +711,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 +724,23 @@ 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 ) - backup_path = helper.wtol_path(str(backup_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 = 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 +772,9 @@ 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 +807,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} ") + Console.info(f"Deleting Server: ID {server_id} | Name: {server_name} ") srv_obj = s["server_obj"] running = srv_obj.check_running() @@ -804,8 +816,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 +826,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 8079f7d9..52509534 100644 --- a/app/classes/shared/main_models.py +++ b/app/classes/shared/main_models.py @@ -1,54 +1,36 @@ 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, fn - 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 - # This is commented out after presenting issues when - # moving from SQLiteDatabase to SqliteQueueDatabase - # //TODO Enable tuning - # 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: @@ -56,7 +38,6 @@ class db_builder: class db_shortcuts: - # ********************************************************************************** # Generic Databse Methods # ********************************************************************************** @@ -77,10 +58,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..6d1bfba8 100644 --- a/app/classes/shared/migration.py +++ b/app/classes/shared/migration.py @@ -7,22 +7,17 @@ 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.console import Console +from app.classes.shared.helpers import Helpers logger = logging.getLogger(__name__) @@ -303,13 +298,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 +330,17 @@ 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 +367,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 +399,13 @@ class MigrationManager(object): Runs all unapplied migrations. """ logger.info("Starting migrations") - console.info("Starting migrations") + 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") + Console.info("There is nothing to migrate") return done migrator = self.migrator @@ -421,10 +421,12 @@ 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..772ab969 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -8,28 +8,22 @@ import logging.config import subprocess import html import tempfile +import psutil +from psutil import NoSuchProcess + +# 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.console import Console +from app.classes.shared.helpers import Helpers +from app.classes.shared.file_helpers import FileHelpers logger = logging.getLogger(__name__) @@ -37,11 +31,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 +74,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 +92,9 @@ 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 # holders for our process self.process = None self.line = False @@ -121,14 +118,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 +150,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") + Console.info(f"Scheduling server {self.name} to start in {delay} seconds") self.server_scheduler.add_job( self.run_scheduled_server, @@ -163,10 +160,10 @@ class Server: ) def run_scheduled_server(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. - 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 +181,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") + Console.info(f"Polling server statistics {self.name} every {5} seconds") try: self.server_scheduler.add_job( self.realtime_stats, @@ -203,43 +200,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( + 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") + 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}") + 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 +250,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") + 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}") + 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 +285,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 +296,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 +310,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 +319,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 +331,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 +355,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 +379,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 +394,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 +413,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}") + 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 +434,39 @@ 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( + Console.critical( f"Server PID {self.process.pid} died right after starting " f"- is this a server config issue?" ) @@ -475,7 +476,7 @@ class Server: f"Server {self.name} has crash detection enabled " f"- starting watcher task" ) - console.info( + Console.info( f"Server {self.name} has crash detection enabled " f"- starting watcher task" ) @@ -486,11 +487,15 @@ 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 +519,7 @@ class Server: f"Server {self.name} has crash detection enabled " f"- starting watcher task" ) - console.info( + Console.info( f"Server {self.name} has crash detection enabled " "- starting watcher task" ) @@ -547,7 +552,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") + Console.info(f"Can't stop server {self.name} if it's not running") return x = 0 @@ -563,7 +568,7 @@ class Server: f"seconds until force close)" ) logger.info(logstr) - console.info(logstr) + Console.info(logstr) running = self.check_running() time.sleep(2) @@ -572,17 +577,17 @@ class Server: logger.info( f"Server {server_name} is still running - Forcing the process down" ) - 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}") - 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() - 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 +595,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 +628,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}") + Console.info(f"COMMAND TIME: {command}") logger.debug(f"Sending command {command} to server") # send it @@ -647,7 +652,7 @@ class Server: f"The server {name} has crashed and will be restarted. " f"Restarting server" ) - console.warning( + Console.critical( f"The server {name} has crashed and will be restarted. " f"Restarting server" ) @@ -658,7 +663,7 @@ class Server: f"The server {name} has crashed, " f"crash detection is disabled and it will not be restarted" ) - console.critical( + Console.critical( f"The server {name} has crashed, " f"crash detection is disabled and it will not be restarted" ) @@ -666,8 +671,11 @@ class Server: def kill(self): logger.info(f"Terminating server {self.server_id} and all child processes") - process = psutil.Process(self.process.pid) - + try: + process = psutil.Process(self.process.pid) + except NoSuchProcess: + logger.info(f"Cannot kill {self.process.pid} as we cannot find that pid.") + return # for every sub process... for proc in process.children(recursive=True): # kill all the child processes @@ -710,7 +718,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 +735,21 @@ class Server: f"Server {self.name} has been restarted {self.restart_count}" f" times. It has crashed, not restarting." ) - console.critical( + 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") + Console.info("Removing old crash detection watcher thread") self.server_scheduler.remove_job("c_" + str(self.server_id)) def agree_eula(self, user_id): @@ -758,6 +766,9 @@ class Server: return False def backup_server(self): + if self.settings["backup_path"] == "": + logger.critical("Backup path is None. Canceling Backup!") + return backup_thread = threading.Thread( target=self.a_backup_server, daemon=True, name=f"backup_{self.name}" ) @@ -765,7 +776,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 +798,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 +838,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 +862,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 +881,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 +914,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 +925,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 +943,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 +972,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 +980,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 +998,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 +1014,11 @@ 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 +1041,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 +1080,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 +1102,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 +1147,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 +1176,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") + Console.critical("Can't broadcast server status to websocket") def get_servers_stats(self): @@ -1181,7 +1194,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}") @@ -1199,8 +1212,8 @@ 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}") - if servers_helper.get_server_type_by_id(server_id) == "minecraft-bedrock": + 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: int_mc_ping = ping(internal_ip, int(server_port)) @@ -1212,7 +1225,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 +1274,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}") @@ -1273,8 +1286,8 @@ class Server: internal_ip = server["server_ip"] 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": + 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)) ping_data = {} @@ -1288,7 +1301,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 +1323,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 +1347,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 +1358,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 +1474,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..60272f14 100644 --- a/app/classes/shared/tasks.py +++ b/app/classes/shared/tasks.py @@ -4,24 +4,15 @@ 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.shared.console import Console 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 +32,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 +70,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 +78,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 +87,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 +108,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") + Console.info("***** Crafty Shutting Down *****\n\n") self.main_thread_exiting = True def start_webserver(self): @@ -136,7 +128,7 @@ class TasksManager: def reload_webserver(self): self.tornado.stop_web_server() - 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" @@ -148,20 +140,20 @@ class TasksManager: def start_scheduler(self): logger.info("Launching Scheduler Thread...") - console.info("Launching Scheduler Thread...") + Console.info("Launching Scheduler Thread...") self.schedule_thread.start() logger.info("Launching command thread...") - console.info("Launching command thread...") + Console.info("Launching command thread...") self.command_thread.start() logger.info("Launching log watcher...") - console.info("Launching log watcher...") + Console.info("Launching log watcher...") self.log_watcher_thread.start() logger.info("Launching realtime thread...") - console.info("Launching realtime thread...") + 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 +165,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 +178,18 @@ class TasksManager: ], ) except Exception as e: - console.error(f"Failed to schedule task with error: {e}.") - 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 - 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 +203,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 +217,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 +237,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 +254,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 +273,16 @@ class TasksManager: ], ) except Exception as e: - console.error(f"Failed to schedule task with error: {e}.") - 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 - 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 +296,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 +310,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 +329,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 +352,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 +371,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 +384,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) + 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": self.scheduler.add_job( - management_helper.add_command, + helpers_management.add_command, "cron", minute=0, hour="*/" + str(job_data["interval"]), @@ -410,7 +404,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 +418,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 +444,12 @@ 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 = self.controller.management.get_scheduled_task_model( + int(event.job_id) + ) + self.controller.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 +461,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 +472,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 +492,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( + Console.info( f"Stats collection frequency set to {stats_update_frequency} seconds" ) @@ -516,36 +512,39 @@ 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..5c79c911 100644 --- a/app/classes/shared/translation.py +++ b/app/classes/shared/translation.py @@ -3,15 +3,17 @@ import logging import os import typing as t -from app.classes.shared.console import console -from app.classes.shared.helpers import helper +from app.classes.shared.console import Console 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 +61,7 @@ class Translation: f"Translation File Error: page {page} " f"does not exist for lang {language}" ) - 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}" ) - console.error( + Console.error( f"Translation File Error: word {word} does not exist on page " f"{page} for lang {language}" ) @@ -83,10 +85,7 @@ class Translation: logger.critical( f"Translation File Error: Unable to read {language_file} due to {e}" ) - console.critical( + 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..49eeec9e 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -3,23 +3,16 @@ 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.console import Console +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 +60,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 +72,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 +80,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 +88,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 +98,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 +168,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 +233,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 +245,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 +284,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") + Console.warning("Server ID not found in send_command ajax call") srv_obj = self.controller.get_server_obj(server_id) @@ -390,8 +383,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 +403,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 +421,27 @@ 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): + self.helper.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 +478,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}") + Console.warning(f"Delete {file_path} for server {server_id}") if not self.check_server_id(server_id, "del_backup"): return @@ -495,21 +492,22 @@ 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})") + 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 +564,7 @@ class AjaxHandler(BaseHandler): logger.warning( f"Server ID not defined in {page_name} ajax call ({server_id})" ) - console.warning( + Console.warning( f"Server ID not defined in {page_name} ajax call ({server_id})" ) return @@ -578,7 +576,7 @@ class AjaxHandler(BaseHandler): logger.warning( f"Server ID not found in {page_name} ajax call ({server_id})" ) - console.warning( + Console.warning( f"Server ID not found in {page_name} ajax call ({server_id})" ) return diff --git a/app/classes/web/api_handler.py b/app/classes/web/api_handler.py index 8a9abedc..b0736da5 100644 --- a/app/classes/web/api_handler.py +++ b/app/classes/web/api_handler.py @@ -135,16 +135,28 @@ class SendCommand(ApiHandler): def post(self): user = self.authenticate_user() + user_obj = self.controller.users.get_user_by_api_token(self.api_token) + if user is None: self.access_denied("unknown") + return server_id = self.get_argument("id") + if ( + not user_obj["user_id"] + in self.controller.server_perms.get_server_user_list(server_id) + and not user_obj["superuser"] + ): + self.access_denied("unknown") + return + if not self.permissions[ "Commands" ] in self.controller.server_perms.get_api_key_permissions_list( self.controller.users.get_api_key_by_token(self.api_token), server_id ): self.access_denied(user) + return command = self.get_argument("command", default=None, strip=True) server_id = self.get_argument("id") @@ -163,16 +175,28 @@ class ServerBackup(ApiHandler): def post(self): user = self.authenticate_user() + user_obj = self.controller.users.get_user_by_api_token(self.api_token) + if user is None: self.access_denied("unknown") + return server_id = self.get_argument("id") + if ( + not user_obj["user_id"] + in self.controller.server_perms.get_server_user_list(server_id) + and not user_obj["superuser"] + ): + self.access_denied("unknown") + return + if not self.permissions[ "Backup" ] in self.controller.server_perms.get_api_key_permissions_list( self.controller.users.get_api_key_by_token(self.api_token), server_id ): self.access_denied(user) + return server = self.controller.get_server_obj(server_id) @@ -190,15 +214,23 @@ class StartServer(ApiHandler): if user is None: self.access_denied("unknown") - + return server_id = self.get_argument("id") - if not self.permissions[ + if ( + not user_obj["user_id"] + in self.controller.server_perms.get_server_user_list(server_id) + and not user_obj["superuser"] + ): + self.access_denied("unknown") + return + elif not self.permissions[ "Commands" ] in self.controller.server_perms.get_api_key_permissions_list( self.controller.users.get_api_key_by_token(self.api_token), server_id ): - self.access_denied(user) + self.access_denied("unknown") + return server = self.controller.get_server_obj(server_id) @@ -216,16 +248,27 @@ class StopServer(ApiHandler): user = self.authenticate_user() remote_ip = self.get_remote_ip() + user_obj = self.controller.users.get_user_by_api_token(self.api_token) + if user is None: self.access_denied("unknown") + return server_id = self.get_argument("id") + if ( + not user_obj["user_id"] + in self.controller.server_perms.get_server_user_list(server_id) + and not user_obj["superuser"] + ): + self.access_denied("unknown") + if not self.permissions[ "Commands" ] in self.controller.server_perms.get_api_key_permissions_list( self.controller.users.get_api_key_by_token(self.api_token), server_id ): self.access_denied(user) + return server = self.controller.get_server_obj(server_id) @@ -243,10 +286,17 @@ class RestartServer(ApiHandler): def post(self): user = self.authenticate_user() remote_ip = self.get_remote_ip() - server_id = self.get_argument("id") + user_obj = self.controller.users.get_user_by_api_token(self.api_token) if user is None: self.access_denied("unknown") + return + server_id = self.get_argument("id") + + if not user_obj["user_id"] in self.controller.server_perms.get_server_user_list( + server_id + ): + self.access_denied("unknown") if not self.permissions[ "Commands" @@ -264,9 +314,21 @@ class RestartServer(ApiHandler): class CreateUser(ApiHandler): def post(self): user = self.authenticate_user() + user_obj = self.controller.users.get_user_by_api_token(self.api_token) + + user_perms = self.controller.crafty_perms.get_crafty_permissions_list( + user_obj["user_id"] + ) + if ( + not self.permissions["User_Config"] in user_perms + and not user_obj["superuser"] + ): + self.access_denied("unknown") + return if user is None: self.access_denied("unknown") + return if not self.permissions[ "User_Config" @@ -274,6 +336,7 @@ class CreateUser(ApiHandler): self.controller.users.get_api_key_by_token(self.api_token) ): self.access_denied(user) + return new_username = self.get_argument("username") new_pass = self.get_argument("password") @@ -305,8 +368,22 @@ class DeleteUser(ApiHandler): def post(self): user = self.authenticate_user() + user_obj = self.controller.users.get_user_by_api_token(self.api_token) + + user_perms = self.controller.crafty_perms.get_crafty_permissions_list( + user_obj["user_id"] + ) + + if ( + not self.permissions["User_Config"] in user_perms + and not user_obj["superuser"] + ): + self.access_denied("unknown") + return + if user is None: self.access_denied("unknown") + return if not self.permissions[ "User_Config" @@ -314,6 +391,7 @@ class DeleteUser(ApiHandler): self.controller.users.get_api_key_by_token(self.api_token) ): self.access_denied(user) + return user_id = self.get_argument("user_id", None, True) user_to_del = self.controller.users.get_user_by_id(user_id) @@ -336,15 +414,19 @@ class ListServers(ApiHandler): if user is None: self.access_denied("unknown") + return if self.api_token is None: self.access_denied("unknown") + return if user_obj["superuser"]: servers = self.controller.servers.get_all_defined_servers() servers = [str(i) for i in servers] else: - servers = self.controller.servers.get_all_defined_servers() + servers = self.controller.servers.get_authorized_servers( + user_obj["user_id"] + ) servers = [str(i) for i in servers] self.return_response( diff --git a/app/classes/web/base_handler.py b/app/classes/web/base_handler.py index d8fe6c95..499cbb87 100644 --- a/app/classes/web/base_handler.py +++ b/app/classes/web/base_handler.py @@ -1,17 +1,9 @@ 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__) @@ -23,8 +15,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 +35,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..63c7d57a 100644 --- a/app/classes/web/file_handler.py +++ b/app/classes/web/file_handler.py @@ -1,20 +1,15 @@ 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.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 -try: - import bleach - import tornado.web - import tornado.escape - -except ModuleNotFoundError as e: - helper.auto_installer_fix(e) - logger = logging.getLogger(__name__) @@ -54,7 +49,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 +58,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( + Console.warning( f"Invalid path in get_file file file ajax call ({file_path})" ) return @@ -101,13 +96,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 +118,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 +156,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 +167,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( + Console.warning( f"Invalid path in create_file file ajax call ({file_path})" ) return @@ -195,7 +190,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 +201,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( + Console.warning( f"Invalid path in create_dir file ajax call ({dir_path})" ) return @@ -227,8 +222,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 +254,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}") + Console.warning(f"Delete {file_path} for server {server_id}") if not self.check_server_id(server_id, "del_file"): return @@ -272,33 +267,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( + 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}") + Console.warning(f"Delete {dir_path} for server {server_id}") if not self.check_server_id(server_id, "del_dir"): return @@ -306,20 +301,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})") + 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 +345,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 +354,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( + Console.warning( f"Invalid path in save_file file ajax call ({file_path})" ) return @@ -382,7 +377,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 +391,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") + 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( + 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( + Console.warning( f"Invalid new name path in rename_file file ajax call ({server_id})" ) return @@ -458,7 +453,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 +467,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") + 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( + 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( + Console.warning( f"Invalid new name path in rename_file file ajax call ({server_id})" ) return @@ -513,7 +508,7 @@ class FileHandler(BaseHandler): logger.warning( f"Server ID not defined in {page_name} file ajax call ({server_id})" ) - console.warning( + Console.warning( f"Server ID not defined in {page_name} file ajax call ({server_id})" ) return @@ -525,7 +520,7 @@ class FileHandler(BaseHandler): logger.warning( f"Server ID not found in {page_name} file ajax call ({server_id})" ) - console.warning( + 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/http_handler_page.py b/app/classes/web/http_handler_page.py index 96f8a611..30a8aaa1 100644 --- a/app/classes/web/http_handler_page.py +++ b/app/classes/web/http_handler_page.py @@ -1,7 +1,5 @@ import logging import requests - -from app.classes.shared.helpers import helper from app.classes.web.base_handler import BaseHandler logger = logging.getLogger(__name__) @@ -16,13 +14,15 @@ class HTTPHandlerPage(BaseHandler): url_list = url.split("/") if url_list[0] != "": primary_url = url_list[0] + ":" + str(port) + "/" - backup_url = url_list[0] + ":" + str(helper.get_setting("https_port")) + "/" + backup_url = ( + url_list[0] + ":" + str(self.helper.get_setting("https_port")) + "/" + ) for i in range(len(url_list) - 1): primary_url += url_list[i + 1] backup_url += url_list[i + 1] else: primary_url = url + str(port) - backup_url = url + str(helper.get_setting("https_port")) + backup_url = url + str(self.helper.get_setting("https_port")) try: resp = requests.get(primary_url) diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index 6a15b6f8..8e877652 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,9 @@ 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 +581,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 +631,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 +641,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 +684,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 +795,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 +806,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 +863,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 +975,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 +1146,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 +1155,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 +1271,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 +1308,14 @@ 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 +1360,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)) @@ -1477,7 +1475,7 @@ class PanelHandler(BaseHandler): one_time = False if not superuser and not permissions[ - "Backup" + "Schedule" ] in self.controller.server_perms.get_user_id_permissions_list( exec_user["user_id"], server_id ): @@ -1635,7 +1633,7 @@ class PanelHandler(BaseHandler): one_time = False if not superuser and not permissions[ - "Backup" + "Schedule" ] in self.controller.server_perms.get_user_id_permissions_list( exec_user["user_id"], server_id ): @@ -1741,7 +1739,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 +1893,9 @@ 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 +1914,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 +2056,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 +2073,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 a91482ef..5269ba2e 100644 --- a/app/classes/web/public_handler.py +++ b/app/classes/web/public_handler.py @@ -1,24 +1,17 @@ import logging +import bleach -from app.classes.models.users import 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.shared.helpers import Helpers +from app.classes.models.users import helper_users 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: @@ -26,7 +19,9 @@ 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") @@ -39,10 +34,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: @@ -88,10 +83,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: @@ -107,9 +102,21 @@ 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() - ) + try: + user_id = helper_users.get_user_id_by_name(entered_username.lower()) + user_data = helper_users.get_user_model(user_id) + except: + error_msg = "Incorrect username or password. Please try again." + # self.clear_cookie("user") + # self.clear_cookie("user_data") + self.clear_cookie("token") + if self.request.query: + self.redirect( + f"/public/login?error_msg={error_msg}&{self.request.query}" + ) + else: + self.redirect(f"/public/login?error_msg={error_msg}") + return # if we don't have a user if not user_data: @@ -142,7 +149,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: @@ -152,14 +159,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 = Helpers.get_time_as_string() + user_data.save() # log this login self.controller.management.add_to_audit_log( diff --git a/app/classes/web/server_handler.py b/app/classes/web/server_handler.py index 293f2838..1482200b 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,17 @@ 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,8 +217,9 @@ 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) + 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") @@ -230,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, @@ -299,7 +296,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 +319,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 +414,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 +437,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..71b29f62 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,10 @@ 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..b0b1a3b0 100644 --- a/app/classes/web/tornado_handler.py +++ b/app/classes/web/tornado_handler.py @@ -3,10 +3,16 @@ 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.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 from app.classes.web.panel_handler import PanelHandler @@ -31,26 +37,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 +99,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 +118,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 +135,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 +165,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 +190,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 +209,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} " + 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:") + 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") + 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") + Console.info("Web Server Stopped") diff --git a/app/classes/web/upload_handler.py b/app/classes/web/upload_handler.py index 02273a08..4877d5cc 100644 --- a/app/classes/web/upload_handler.py +++ b/app/classes/web/upload_handler.py @@ -1,22 +1,15 @@ 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.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 +19,13 @@ 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 +38,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 +48,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 +83,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") + 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") + 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 +96,7 @@ class UploadHandler(BaseHandler): f"User {user_id} tried to upload a file to " f"{server_id} without permissions!" ) - console.warning( + Console.warning( f"User {user_id} tried to upload a file to " f"{server_id} without permissions!" ) @@ -108,8 +106,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 +115,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 +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!" ) - 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!" ) @@ -148,13 +146,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..64648fd8 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,10 @@ 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 +35,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 +47,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 +58,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 +70,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 +85,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..68044b5f 100644 --- a/app/classes/web/websocket_helper.py +++ b/app/classes/web/websocket_helper.py @@ -1,13 +1,14 @@ import json import logging -from app.classes.shared.console import console +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 +102,7 @@ class WebSocketHelper: ) def disconnect_all(self): - console.info("Disconnecting WebSocket clients") + Console.info("Disconnecting WebSocket clients") for client in self.clients: client.close() - console.info("Disconnected WebSocket clients") - - -websocket_helper = WebSocketHelper() + Console.info("Disconnected WebSocket clients") 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) }); }); 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 %}