diff --git a/CHANGELOG.md b/CHANGELOG.md index 47afae18..cd7daf70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,17 @@ # Changelog ## --- [4.0.20] - 2022/TBD ### New features -TBD +- Add option to run command before backup. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/536)) ### Bug fixes - Fix local java server imports. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/529)) +- Fix Schedule Restore | Add Backup Config Preservation. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/533)) +- Rework `/public` Route. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/538)) ### Tweaks - Hide stats DB directory from files tree. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/530)) +- Added further login screen customisation settings. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/531)) +- Set backup filename to use same time as schedule. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/534)) +- Move Schedules to from DB to Queue Datatype. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/535)) +- Move raknet icon failure to a debug log. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/537)) ### Lang TBD

diff --git a/app/classes/controllers/management_controller.py b/app/classes/controllers/management_controller.py index 47860fe1..dc0f5422 100644 --- a/app/classes/controllers/management_controller.py +++ b/app/classes/controllers/management_controller.py @@ -1,4 +1,5 @@ import logging +import queue from app.classes.models.management import HelpersManagement from app.classes.models.servers import HelperServers @@ -9,6 +10,26 @@ logger = logging.getLogger(__name__) class ManagementController: def __init__(self, management_helper): self.management_helper = management_helper + self.command_queue = queue.Queue() + + # ********************************************************************************** + # Config Methods + # ********************************************************************************** + @staticmethod + def set_login_image(path): + HelpersManagement.set_login_image(path) + + @staticmethod + def get_login_image(): + return HelpersManagement.get_login_image() + + @staticmethod + def set_login_opacity(opacity): + return HelpersManagement.set_login_opacity(opacity) + + @staticmethod + def get_login_opacity(): + return HelpersManagement.get_login_opacity() # ********************************************************************************** # Host_Stats Methods @@ -28,9 +49,6 @@ class ManagementController: # ********************************************************************************** # Commands Methods # ********************************************************************************** - @staticmethod - def get_unactioned_commands(): - return HelpersManagement.get_unactioned_commands() def send_command(self, user_id, server_id, remote_ip, command): server_name = HelperServers.get_server_friendly_name(server_id) @@ -42,11 +60,12 @@ class ManagementController: server_id, remote_ip, ) - HelpersManagement.add_command(server_id, user_id, remote_ip, command) + self.queue_command( + {"server_id": server_id, "user_id": user_id, "command": command} + ) - @staticmethod - def mark_command_complete(command_id=None): - return HelpersManagement.mark_command_complete(command_id) + def queue_command(self, command_data): + self.command_queue.put(command_data) # ********************************************************************************** # Audit_Log Methods @@ -78,6 +97,10 @@ class ManagementController: command, name, enabled=True, + one_time=False, + cron_string="* * * * *", + parent=None, + delay=0, ): return HelpersManagement.create_scheduled_task( server_id, @@ -88,20 +111,16 @@ class ManagementController: command, name, enabled, + one_time, + cron_string, + parent, + delay, ) @staticmethod def delete_scheduled_task(schedule_id): return HelpersManagement.delete_scheduled_task(schedule_id) - @staticmethod - def set_login_image(path): - HelpersManagement.set_login_image(path) - - @staticmethod - def get_login_image(): - return HelpersManagement.get_login_image() - @staticmethod def update_scheduled_task(schedule_id, updates): return HelpersManagement.update_scheduled_task(schedule_id, updates) @@ -145,9 +164,18 @@ class ManagementController: excluded_dirs: list = None, compress: bool = False, shutdown: bool = False, + before: str = "", + after: str = "", ): return self.management_helper.set_backup_config( - server_id, backup_path, max_backups, excluded_dirs, compress, shutdown + server_id, + backup_path, + max_backups, + excluded_dirs, + compress, + shutdown, + before, + after, ) @staticmethod diff --git a/app/classes/minecraft/stats.py b/app/classes/minecraft/stats.py index e3611509..07dd9c0d 100644 --- a/app/classes/minecraft/stats.py +++ b/app/classes/minecraft/stats.py @@ -300,7 +300,7 @@ class Stats: server_icon = base64.encodebytes(ping_obj["icon"]) except Exception as e: server_icon = False - logger.info( + logger.debug( "Unable to read the server icon due to the following error:", exc_info=e ) ping_data = { diff --git a/app/classes/models/management.py b/app/classes/models/management.py index 55c86bb7..bb183eef 100644 --- a/app/classes/models/management.py +++ b/app/classes/models/management.py @@ -13,7 +13,7 @@ from peewee import ( from playhouse.shortcuts import model_to_dict from app.classes.models.base_model import BaseModel -from app.classes.models.users import Users, HelperUsers +from app.classes.models.users import HelperUsers from app.classes.models.servers import Servers from app.classes.models.server_permissions import PermissionsServers from app.classes.shared.main_models import DatabaseShortcuts @@ -44,6 +44,7 @@ class AuditLog(BaseModel): class CraftySettings(BaseModel): secret_api_key = CharField(default="") login_photo = CharField(default="login_1.jpg") + login_opacity = IntegerField(default=100) class Meta: table_name = "crafty_settings" @@ -68,22 +69,6 @@ class HostStats(BaseModel): table_name = "host_stats" -# ********************************************************************************** -# Commands Class -# ********************************************************************************** -class Commands(BaseModel): - command_id = AutoField() - created = DateTimeField(default=datetime.datetime.now) - server_id = ForeignKeyField(Servers, backref="server", index=True) - user = ForeignKeyField(Users, backref="user", index=True) - source_ip = CharField(default="127.0.0.1") - command = CharField(default="") - executed = BooleanField(default=False) - - class Meta: - table_name = "commands" - - # ********************************************************************************** # Webhooks Class # ********************************************************************************** @@ -131,6 +116,8 @@ class Backups(BaseModel): server_id = ForeignKeyField(Servers, backref="backups_server") compress = BooleanField(default=False) shutdown = BooleanField(default=False) + before = CharField(default="") + after = CharField(default="") class Meta: table_name = "backups" @@ -150,33 +137,6 @@ class HelpersManagement: query = HostStats.select().order_by(HostStats.id.desc()).get() return model_to_dict(query) - # ********************************************************************************** - # Commands Methods - # ********************************************************************************** - @staticmethod - def add_command(server_id, user_id, remote_ip, command): - Commands.insert( - { - Commands.server_id: server_id, - Commands.user: user_id, - Commands.source_ip: remote_ip, - Commands.command: command, - } - ).execute() - - @staticmethod - def get_unactioned_commands(): - query = Commands.select().where(Commands.executed == 0) - return query - - @staticmethod - def mark_command_complete(command_id=None): - if command_id is not None: - logger.debug(f"Marking Command {command_id} completed") - Commands.update({Commands.executed: True}).where( - Commands.command_id == command_id - ).execute() - # ********************************************************************************** # Audit_Log Methods # ********************************************************************************** @@ -255,6 +215,9 @@ class HelpersManagement: ) return settings[0].secret_api_key + # ********************************************************************************** + # Config Methods + # ********************************************************************************** @staticmethod def get_login_image(): settings = CraftySettings.select(CraftySettings.login_photo).where( @@ -268,6 +231,19 @@ class HelpersManagement: CraftySettings.id == 1 ).execute() + @staticmethod + def get_login_opacity(): + settings = CraftySettings.select(CraftySettings.login_opacity).where( + CraftySettings.id == 1 + ) + return settings[0].login_opacity + + @staticmethod + def set_login_opacity(opacity): + CraftySettings.update({CraftySettings.login_opacity: opacity}).where( + CraftySettings.id == 1 + ).execute() + # ********************************************************************************** # Schedules Methods # ********************************************************************************** @@ -369,6 +345,8 @@ class HelpersManagement: "server_id": row.server_id_id, "compress": row.compress, "shutdown": row.shutdown, + "before": row.before, + "after": row.after, } except IndexError: conf = { @@ -378,6 +356,8 @@ class HelpersManagement: "server_id": server_id, "compress": False, "shutdown": False, + "before": "", + "after": "", } return conf @@ -393,6 +373,8 @@ class HelpersManagement: excluded_dirs: list = None, compress: bool = False, shutdown: bool = False, + before: str = "", + after: str = "", ): logger.debug(f"Updating server {server_id} backup config with {locals()}") if Backups.select().where(Backups.server_id == server_id).exists(): @@ -405,6 +387,8 @@ class HelpersManagement: "server_id": server_id, "compress": False, "shutdown": False, + "before": "", + "after": "", } new_row = True if max_backups is not None: @@ -414,6 +398,8 @@ class HelpersManagement: conf["excluded_dirs"] = dirs_to_exclude conf["compress"] = compress conf["shutdown"] = shutdown + conf["before"] = before + conf["after"] = after if not new_row: with self.database.atomic(): if backup_path is not None: @@ -473,9 +459,3 @@ class HelpersManagement: f"Not removing {dir_to_del} from excluded directories - " f"not in the excluded directory list for server ID {server_id}" ) - - @staticmethod - def clear_unexecuted_commands(): - Commands.update({Commands.executed: True}).where( - Commands.executed == False # pylint: disable=singleton-comparison - ).execute() diff --git a/app/classes/shared/main_controller.py b/app/classes/shared/main_controller.py index 3a229d20..b4dfb323 100644 --- a/app/classes/shared/main_controller.py +++ b/app/classes/shared/main_controller.py @@ -965,10 +965,6 @@ class Controller: # remove the server from the DB self.servers.remove_server(server_id) - @staticmethod - def clear_unexecuted_commands(): - HelpersManagement.clear_unexecuted_commands() - @staticmethod def clear_support_status(): HelperUsers.clear_support_status() diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index 745d840d..1b277a76 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -131,13 +131,13 @@ class ServerInstance: self.stats_helper = HelperServerStats(self.server_id) self.last_backup_failed = False try: - tz = get_localzone() + self.tz = get_localzone() except ZoneInfoNotFoundError: logger.error( "Could not capture time zone from system. Falling back to Europe/London" ) - tz = "Europe/London" - self.server_scheduler = BackgroundScheduler(timezone=str(tz)) + self.tz = "Europe/London" + self.server_scheduler = BackgroundScheduler(timezone=str(self.tz)) self.server_scheduler.start() self.backup_thread = threading.Thread( target=self.a_backup_server, daemon=True, name=f"backup_{self.name}" @@ -175,7 +175,6 @@ class ServerInstance: self.name = server_name self.settings = server_data_obj - self.stats_helper.init_database(server_id) self.record_server_stats() # build our server run command @@ -1024,7 +1023,17 @@ class ServerInstance: ) time.sleep(3) conf = HelpersManagement.get_backup_config(self.server_id) + if conf["before"]: + if self.check_running(): + logger.debug( + "Found running server and send command option. Sending command" + ) + self.send_command(conf["before"]) + if conf["shutdown"]: + if conf["before"]: + # pause to let people read message. + time.sleep(5) logger.info( "Found shutdown preference. Delaying" + "backup start. Shutting down server." @@ -1037,7 +1046,7 @@ class ServerInstance: try: backup_filename = ( f"{self.settings['backup_path']}/" - f"{datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}" + f"{datetime.datetime.now().astimezone(self.tz).strftime('%Y-%m-%d_%H-%M-%S')}" # pylint: disable=line-too-long ) logger.info( f"Creating backup of server '{self.settings['server_name']}'" @@ -1105,6 +1114,14 @@ class ServerInstance: self.run_threaded_server(HelperUsers.get_user_id_by_name("system")) time.sleep(3) self.last_backup_failed = False + if conf["after"]: + if self.check_running(): + logger.debug( + "Found running server and send command option. Sending command" + ) + self.send_command(conf["after"]) + # pause to let people read message. + time.sleep(5) except: logger.exception( f"Failed to create backup of server {self.name} (ID {self.server_id})" diff --git a/app/classes/shared/tasks.py b/app/classes/shared/tasks.py index 17940181..e96acd14 100644 --- a/app/classes/shared/tasks.py +++ b/app/classes/shared/tasks.py @@ -91,22 +91,21 @@ class TasksManager: def command_watcher(self): while True: # select any commands waiting to be processed - commands = HelpersManagement.get_unactioned_commands() - for cmd in commands: + if not self.controller.management.command_queue.empty(): + cmd = self.controller.management.command_queue.get() try: svr = self.controller.servers.get_server_instance_by_id( - cmd.server_id.server_id + cmd["server_id"] ) except: logger.error( "Server value requested does not exist! " "Purging item from waiting commands." ) - HelpersManagement.mark_command_complete(cmd.command_id) continue - user_id = cmd.user_id - command = cmd.command + user_id = cmd["user_id"] + command = cmd["command"] if command == "start_server": svr.run_threaded_server(user_id) @@ -136,8 +135,6 @@ class TasksManager: else: svr.send_command(command) - HelpersManagement.mark_command_complete(cmd.command_id) - time.sleep(1) def _main_graceful_exit(self): @@ -212,16 +209,19 @@ class TasksManager: if schedule.cron_string != "": try: new_job = self.scheduler.add_job( - HelpersManagement.add_command, + self.controller.management.queue_command, CronTrigger.from_crontab( schedule.cron_string, timezone=str(self.tz) ), id=str(schedule.schedule_id), args=[ - schedule.server_id, - self.users_controller.get_id_by_name("system"), - "127.0.0.1", - schedule.command, + { + "server_id": schedule.server_id.server_id, + "user_id": self.users_controller.get_id_by_name( + "system" + ), + "command": schedule.command, + } ], ) except Exception as e: @@ -237,45 +237,54 @@ class TasksManager: else: if schedule.interval_type == "hours": new_job = self.scheduler.add_job( - HelpersManagement.add_command, + self.controller.management.queue_command, "cron", minute=0, hour="*/" + str(schedule.interval), id=str(schedule.schedule_id), args=[ - schedule.server_id, - self.users_controller.get_id_by_name("system"), - "127.0.0.1", - schedule.command, + { + "server_id": schedule.server_id.server_id, + "user_id": self.users_controller.get_id_by_name( + "system" + ), + "command": schedule.command, + } ], ) elif schedule.interval_type == "minutes": new_job = self.scheduler.add_job( - HelpersManagement.add_command, + self.controller.management.queue_command, "cron", minute="*/" + str(schedule.interval), id=str(schedule.schedule_id), args=[ - schedule.server_id, - self.users_controller.get_id_by_name("system"), - "127.0.0.1", - schedule.command, + { + "server_id": schedule.server_id.server_id, + "user_id": self.users_controller.get_id_by_name( + "system" + ), + "command": schedule.command, + } ], ) elif schedule.interval_type == "days": curr_time = schedule.start_time.split(":") new_job = self.scheduler.add_job( - HelpersManagement.add_command, + self.controller.management.queue_command, "cron", day="*/" + str(schedule.interval), hour=curr_time[0], minute=curr_time[1], id=str(schedule.schedule_id), args=[ - schedule.server_id, - self.users_controller.get_id_by_name("system"), - "127.0.0.1", - schedule.command, + { + "server_id": schedule.server_id.server_id, + "user_id": self.users_controller.get_id_by_name( + "system" + ), + "command": schedule.command, + } ], ) if new_job != "error": @@ -322,16 +331,19 @@ class TasksManager: if job_data["cron_string"] != "": try: new_job = self.scheduler.add_job( - HelpersManagement.add_command, + self.controller.management.queue_command, CronTrigger.from_crontab( job_data["cron_string"], timezone=str(self.tz) ), id=str(sch_id), args=[ - job_data["server_id"], - self.users_controller.get_id_by_name("system"), - "127.0.0.1", - job_data["command"], + { + "server_id": job_data["server_id"], + "user_id": self.users_controller.get_id_by_name( + "system" + ), + "command": job_data["command"], + } ], ) except Exception as e: @@ -345,45 +357,54 @@ class TasksManager: else: if job_data["interval_type"] == "hours": new_job = self.scheduler.add_job( - HelpersManagement.add_command, + self.controller.management.queue_command, "cron", minute=0, hour="*/" + str(job_data["interval"]), id=str(sch_id), args=[ - job_data["server_id"], - self.users_controller.get_id_by_name("system"), - "127.0.0.1", - job_data["command"], + { + "server_id": job_data["server_id"], + "user_id": self.users_controller.get_id_by_name( + "system" + ), + "command": job_data["command"], + } ], ) elif job_data["interval_type"] == "minutes": new_job = self.scheduler.add_job( - HelpersManagement.add_command, + self.controller.management.queue_command, "cron", minute="*/" + str(job_data["interval"]), id=str(sch_id), args=[ - job_data["server_id"], - self.users_controller.get_id_by_name("system"), - "127.0.0.1", - job_data["command"], + { + "server_id": job_data["server_id"], + "user_id": self.users_controller.get_id_by_name( + "system" + ), + "command": job_data["command"], + } ], ) elif job_data["interval_type"] == "days": curr_time = job_data["start_time"].split(":") new_job = self.scheduler.add_job( - HelpersManagement.add_command, + self.controller.management.queue_command, "cron", day="*/" + str(job_data["interval"]), hour=curr_time[0], minute=curr_time[1], id=str(sch_id), args=[ - job_data["server_id"], - self.users_controller.get_id_by_name("system"), - "127.0.0.1", - job_data["command"], + { + "server_id": job_data["server_id"], + "user_id": self.users_controller.get_id_by_name( + "system" + ), + "command": job_data["command"], + } ], ) logger.info("Added job. Current enabled schedules: ") @@ -460,16 +481,19 @@ class TasksManager: if job_data["cron_string"] != "": try: new_job = self.scheduler.add_job( - HelpersManagement.add_command, + self.controller.management.queue_command, CronTrigger.from_crontab( job_data["cron_string"], timezone=str(self.tz) ), id=str(sch_id), args=[ - job_data["server_id"], - self.users_controller.get_id_by_name("system"), - "127.0.0.1", - job_data["command"], + { + "server_id": job_data["server_id"], + "user_id": self.users_controller.get_id_by_name( + "system" + ), + "command": job_data["command"], + } ], ) except Exception as e: @@ -480,45 +504,54 @@ class TasksManager: else: if job_data["interval_type"] == "hours": new_job = self.scheduler.add_job( - HelpersManagement.add_command, + self.controller.management.queue_command, "cron", minute=0, hour="*/" + str(job_data["interval"]), id=str(sch_id), args=[ - job_data["server_id"], - self.users_controller.get_id_by_name("system"), - "127.0.0.1", - job_data["command"], + { + "server_id": job_data["server_id"], + "user_id": self.users_controller.get_id_by_name( + "system" + ), + "command": job_data["command"], + } ], ) elif job_data["interval_type"] == "minutes": new_job = self.scheduler.add_job( - HelpersManagement.add_command, + self.controller.management.queue_command, "cron", minute="*/" + str(job_data["interval"]), id=str(sch_id), args=[ - job_data["server_id"], - self.users_controller.get_id_by_name("system"), - "127.0.0.1", - job_data["command"], + { + "server_id": job_data["server_id"], + "user_id": self.users_controller.get_id_by_name( + "system" + ), + "command": job_data["command"], + } ], ) elif job_data["interval_type"] == "days": curr_time = job_data["start_time"].split(":") new_job = self.scheduler.add_job( - HelpersManagement.add_command, + self.controller.management.queue_command, "cron", day="*/" + str(job_data["interval"]), hour=curr_time[0], minute=curr_time[1], id=str(sch_id), args=[ - job_data["server_id"], - self.users_controller.get_id_by_name("system"), - "127.0.0.1", - job_data["command"], + { + "server_id": job_data["server_id"], + "user_id": self.users_controller.get_id_by_name( + "system" + ), + "command": job_data["command"], + } ], ) if new_job != "error": @@ -579,15 +612,18 @@ class TasksManager: seconds=schedule.delay ) self.scheduler.add_job( - HelpersManagement.add_command, + self.controller.management.queue_command, "date", run_date=delaytime, id=str(schedule.schedule_id), args=[ - schedule.server_id, - self.users_controller.get_id_by_name("system"), - "127.0.0.1", - schedule.command, + { + "server_id": schedule.server_id.server_id, + "user_id": self.users_controller.get_id_by_name( + "system" + ), + "command": schedule.command, + } ], ) else: diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index cdd67146..97de6b13 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -348,14 +348,11 @@ class AjaxHandler(BaseHandler): server.backup_server() - elif page == "clear_comms": - if exec_user["superuser"]: - self.controller.clear_unexecuted_commands() - return - elif page == "select_photo": if exec_user["superuser"]: - photo = self.get_argument("photo", None) + photo = urllib.parse.unquote(self.get_argument("photo", "")) + opacity = self.get_argument("opacity", 100) + self.controller.management.set_login_opacity(int(opacity)) if photo == "login_1.jpg": self.controller.management.set_login_image("login_1.jpg") self.controller.cached_login = f"{photo}" @@ -366,7 +363,7 @@ class AjaxHandler(BaseHandler): elif page == "delete_photo": if exec_user["superuser"]: - photo = self.get_argument("photo", None) + photo = urllib.parse.unquote(self.get_argument("photo", None)) if photo and photo != "login_1.jpg": os.remove( os.path.join( @@ -440,15 +437,8 @@ class AjaxHandler(BaseHandler): for schedule in self.controller.management.get_schedules_by_server( server_id ): - self.controller.management.create_scheduled_task( - new_server_id, - schedule.action, - schedule.interval, - schedule.interval_type, - schedule.start_time, - schedule.command, - schedule.name, - schedule.enabled, + self.tasks_manager.update_job( + schedule.schedule_id, {"server_id": new_server_id} ) # preserve execution command new_server_obj = self.controller.servers.get_server_obj( @@ -456,6 +446,29 @@ class AjaxHandler(BaseHandler): ) new_server_obj.execution_command = server_data["execution_command"] self.controller.servers.update_server(new_server_obj) + + # preserve backup config + backup_config = self.controller.management.get_backup_config( + server_id + ) + excluded_dirs = [] + server_obj = self.controller.servers.get_server_obj(server_id) + loop_backup_path = self.helper.wtol_path(server_obj.path) + for item in self.controller.management.get_excluded_backup_dirs( + server_id + ): + item_path = self.helper.wtol_path(item) + bu_path = os.path.relpath(item_path, loop_backup_path) + bu_path = os.path.join(new_server_obj.path, bu_path) + excluded_dirs.append(bu_path) + self.controller.management.set_backup_config( + new_server_id, + new_server_obj.backup_path, + backup_config["max_backups"], + excluded_dirs, + backup_config["compress"], + backup_config["shutdown"], + ) # remove old server's tasks try: self.tasks_manager.remove_all_server_tasks(server_id) @@ -484,15 +497,8 @@ class AjaxHandler(BaseHandler): for schedule in self.controller.management.get_schedules_by_server( server_id ): - self.controller.management.create_scheduled_task( - new_server_id, - schedule.action, - schedule.interval, - schedule.interval_type, - schedule.start_time, - schedule.command, - schedule.name, - schedule.enabled, + self.tasks_manager.update_job( + schedule.schedule_id, {"server_id": new_server_id} ) # preserve execution command new_server_obj = self.controller.servers.get_server_obj( @@ -500,6 +506,29 @@ class AjaxHandler(BaseHandler): ) new_server_obj.execution_command = server_data["execution_command"] self.controller.servers.update_server(new_server_obj) + + # preserve backup config + backup_config = self.controller.management.get_backup_config( + server_id + ) + excluded_dirs = [] + server_obj = self.controller.servers.get_server_obj(server_id) + loop_backup_path = self.helper.wtol_path(server_obj.path) + for item in self.controller.management.get_excluded_backup_dirs( + server_id + ): + item_path = self.helper.wtol_path(item) + bu_path = os.path.relpath(item_path, loop_backup_path) + bu_path = os.path.join(new_server_obj.path, bu_path) + excluded_dirs.append(bu_path) + self.controller.management.set_backup_config( + new_server_id, + new_server_obj.backup_path, + backup_config["max_backups"], + excluded_dirs, + backup_config["compress"], + backup_config["shutdown"], + ) try: self.tasks_manager.remove_all_server_tasks(server_id) except: diff --git a/app/classes/web/default_handler.py b/app/classes/web/default_handler.py index c0bbc9ad..22533815 100644 --- a/app/classes/web/default_handler.py +++ b/app/classes/web/default_handler.py @@ -17,6 +17,5 @@ class DefaultHandler(BaseHandler): ) else: self.redirect( - "/public/login", - # translate=self.translator.translate, + "/login", ) diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index 582517db..60194678 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -291,6 +291,7 @@ class PanelHandler(BaseHandler): # todo: make this actually pull and compare version data "update_available": self.helper.update_available, "background": self.controller.cached_login, + "login_opacity": self.controller.management.get_login_opacity(), "serverTZ": tz, "version_data": self.helper.get_version_string(), "failed_servers": self.controller.servers.failed_servers, @@ -883,6 +884,9 @@ class PanelHandler(BaseHandler): if item not in page_data["backgrounds"]: page_data["backgrounds"].append(item) page_data["background"] = self.controller.cached_login + page_data[ + "login_opacity" + ] = self.controller.management.get_login_opacity() else: page_data["managed_users"] = self.controller.users.get_managed_users( exec_user["user_id"] @@ -1678,6 +1682,8 @@ class PanelHandler(BaseHandler): compress = self.get_argument("compress", False) shutdown = self.get_argument("shutdown", False) check_changed = self.get_argument("changed") + before = self.get_argument("backup_before", "") + after = self.get_argument("backup_after", "") if str(check_changed) == str(1): checked = self.get_body_arguments("root_path") else: @@ -1701,6 +1707,8 @@ class PanelHandler(BaseHandler): excluded_dirs=checked, compress=bool(compress), shutdown=bool(shutdown), + before=before, + after=after, ) self.controller.management.add_to_audit_log( diff --git a/app/classes/web/public_handler.py b/app/classes/web/public_handler.py index 7f3f0c26..d5bff692 100644 --- a/app/classes/web/public_handler.py +++ b/app/classes/web/public_handler.py @@ -40,6 +40,7 @@ class PublicHandler(BaseHandler): "lang_page": self.helper.get_lang_page(self.helper.get_setting("language")), "query": "", "background": self.controller.cached_login, + "login_opacity": self.controller.management.get_login_opacity(), } if self.request.query: @@ -61,15 +62,15 @@ class PublicHandler(BaseHandler): self.clear_cookie("token") # self.clear_cookie("user") # self.clear_cookie("user_data") - self.redirect("/public/login") + self.redirect("/login") return # if we have no page, let's go to login else: if self.request.query: - self.redirect("/public/login?" + self.request.query) + self.redirect("/login?" + self.request.query) else: - self.redirect("/public/login") + self.redirect("/login") return self.render( @@ -96,9 +97,9 @@ class PublicHandler(BaseHandler): if page == "login": - next_page = "/public/login" + next_page = "/login" if self.request.query: - next_page = "/public/login?" + self.request.query + next_page = "/login?" + self.request.query entered_username = bleach.clean(self.get_argument("username")) entered_password = bleach.clean(self.get_argument("password")) @@ -113,11 +114,9 @@ class PublicHandler(BaseHandler): # 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}" - ) + self.redirect(f"/login?error_msg={error_msg}&{self.request.query}") else: - self.redirect(f"/public/login?error_msg={error_msg}") + self.redirect(f"/login?error_msg={error_msg}") return # if we don't have a user @@ -127,11 +126,9 @@ class PublicHandler(BaseHandler): # 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}" - ) + self.redirect(f"/login?error_msg={error_msg}&{self.request.query}") else: - self.redirect(f"/public/login?error_msg={error_msg}") + self.redirect(f"/login?error_msg={error_msg}") return # if they are disabled @@ -144,11 +141,9 @@ class PublicHandler(BaseHandler): # 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}" - ) + self.redirect(f"/login?error_msg={error_msg}&{self.request.query}") else: - self.redirect(f"/public/login?error_msg={error_msg}") + self.redirect(f"/login?error_msg={error_msg}") return login_result = self.helper.verify_pass(entered_password, user_data.password) @@ -187,13 +182,11 @@ class PublicHandler(BaseHandler): user_data.user_id, "Tried to log in", 0, self.get_remote_ip() ) if self.request.query: - self.redirect( - f"/public/login?error_msg={error_msg}&{self.request.query}" - ) + self.redirect(f"/login?error_msg={error_msg}&{self.request.query}") else: - self.redirect(f"/public/login?error_msg={error_msg}") + self.redirect(f"/login?error_msg={error_msg}") else: if self.request.query: - self.redirect("/public/login?" + self.request.query) + self.redirect("/login?" + self.request.query) else: - self.redirect("/public/login") + self.redirect("/login") diff --git a/app/classes/web/tornado_handler.py b/app/classes/web/tornado_handler.py index 9394fa42..4feae695 100644 --- a/app/classes/web/tornado_handler.py +++ b/app/classes/web/tornado_handler.py @@ -147,7 +147,6 @@ class Webserver: } handlers = [ (r"/", DefaultHandler, handler_args), - (r"/public/(.*)", PublicHandler, handler_args), (r"/panel/(.*)", PanelHandler, handler_args), (r"/server/(.*)", ServerHandler, handler_args), (r"/ajax/(.*)", AjaxHandler, handler_args), @@ -168,6 +167,9 @@ class Webserver: (r"/api/v1/users/delete_user", DeleteUser, handler_args), # API Routes V2 *api_handlers(handler_args), + # Using this one at the end + # to catch all the other requests to Public Handler + (r"/(.*)", PublicHandler, handler_args), ] app = tornado.web.Application( @@ -179,21 +181,14 @@ class Webserver: xsrf_cookies=True, autoreload=False, log_function=self.log_function, - login_url="/public/login", + login_url="/login", default_handler_class=PublicHandler, static_handler_class=CustomStaticHandler, serve_traceback=debug_errors, ) http_handers = [ (r"/", HTTPHandler, handler_args), - (r"/public/(.*)", HTTPHandlerPage, handler_args), - (r"/panel/(.*)", HTTPHandlerPage, handler_args), - (r"/server/(.*)", HTTPHandlerPage, handler_args), - (r"/ajax/(.*)", HTTPHandlerPage, handler_args), - (r"/api/stats/servers", HTTPHandlerPage, handler_args), - (r"/api/stats/node", HTTPHandlerPage, handler_args), - (r"/ws", HTTPHandlerPage, handler_args), - (r"/upload", HTTPHandlerPage, handler_args), + (r"/(.+)", HTTPHandlerPage, handler_args), ] http_app = tornado.web.Application( http_handers, @@ -205,7 +200,7 @@ class Webserver: autoreload=False, log_function=self.log_function, default_handler_class=HTTPHandler, - login_url="/public/login", + login_url="/login", serve_traceback=debug_errors, ) diff --git a/app/frontend/templates/notify.html b/app/frontend/templates/notify.html index 78f62409..9d41d17d 100644 --- a/app/frontend/templates/notify.html +++ b/app/frontend/templates/notify.html @@ -1,57 +1,59 @@ + {% if data['user_data']['preparing'] %} + {{ translate('notify', 'supportLogs', data['lang']) }}

+ +
+
0%
+
+
+ {% else %} + {{ translate('notify', 'supportLogs', data['lang']) }} + {% end %} + {% if data['superuser'] %} + {{ translate('notify', 'activityLog', data['lang']) }} + {% end %} + {{ translate('notify', 'logout', data['lang']) }} + + + - \ No newline at end of file + \ No newline at end of file diff --git a/app/frontend/templates/panel/denied.html b/app/frontend/templates/panel/denied.html index f924e553..717c0def 100644 --- a/app/frontend/templates/panel/denied.html +++ b/app/frontend/templates/panel/denied.html @@ -1,69 +1,82 @@ - - - - - Crafty Controller - - - - - - - - - - - - - - - - -
-
-
-
-
-
-
+ + + + + Crafty Controller + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ +
+


-
- -
-
+
-
- +
- - - - - - - - - - - - + +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/frontend/templates/panel/panel_config.html b/app/frontend/templates/panel/panel_config.html index a4ee9f66..4bf13833 100644 --- a/app/frontend/templates/panel/panel_config.html +++ b/app/frontend/templates/panel/panel_config.html @@ -221,73 +221,184 @@

{{ translate('panelConfig', 'adminControls', data['lang']) }}

-
- - -
-
+
+
+

{{ translate('panelConfig', 'customLoginPage', data['lang']) }}

+
- -

{{ translate('panelConfig', 'loginImage', data['lang']) }}

-
-

- -

- {% raw xsrf_form_html() %} - - -
-
- -
-
-
- - - - -
+
+
+

{{ translate('panelConfig', 'loginImage', data['lang']) }}

+
+ + {% raw xsrf_form_html() %} + +
+
+
+ +
+ +
+
+
+
+
+
{{ translate('panelConfig', 'preview', data['lang']) }}:
+
+
+ +
+ +
+
+ +
+ + +
+ +
+
+
+ Responsive image +
+ +
+
+
+ + +
+
-
- -

-
-
-
-
-
-

{{ translate('panelConfig', 'loginBackground', data['lang']) }}




-
- -
-
-
{{ translate('panelConfig', 'preview', data['lang']) }}:
- -
-
-
- - -
+
@@ -367,24 +478,13 @@ }); }); - $('.clear-comm').click(function () { - var token = getCookie("_xsrf") - $.ajax({ - type: "POST", - headers: { 'X-XSRFToken': token }, - url: '/ajax/clear_comm', - success: function (data) { - }, - }); - }) - $('.delete-photo').click(function () { var token = getCookie("_xsrf") let photo = $('#photo').find(":selected").val(); $.ajax({ type: "POST", headers: { 'X-XSRFToken': token }, - url: '/ajax/delete_photo?photo=' + photo, + url: '/ajax/delete_photo?photo=' + encodeURIComponent(photo), success: function (data) { location.reload(); }, @@ -394,20 +494,50 @@ $('.select-photo').click(function () { var token = getCookie("_xsrf") let photo = $('#photo').find(":selected").val(); + let opacity = $('#modal_opacity').val(); + let enc_photo = encodeURIComponent(photo); + $.ajax({ type: "POST", headers: { 'X-XSRFToken': token }, - url: '/ajax/select_photo?photo=' + photo, + url: '/ajax/select_photo?photo=' + enc_photo + '&opacity=' + opacity, success: function (data) { window.location.reload(); }, }); }) + $(document).ready(function () { + let opacity = parseInt($("#modal_opacity").val()); + document.getElementById('login-form-background').style.background = 'rgb(34, 36, 55, ' + (opacity / 100) + ')'; + }); + + function previewOpacity() { + let opacity = parseInt($("#modal_opacity").val()) + console.debug("Selected Opacity = " + opacity + "%"); + document.getElementById('opacityValue').innerHTML = (opacity) + "%"; + document.getElementById('login-form-background').style.background = 'rgb(34, 36, 55, ' + (opacity / 100) + ')'; + } + + function updateBackgroundSelect() { + $("#photo").val($("#try_photo").val()).change(); + } + + function updateBackgroundPreview() { + var img = document.getElementById('bg-preview'); + if ($("#photo").val() == "login_1.jpg") { + var src_path = "../../static/assets/images/auth/".concat($("#photo").val()); + } + else { + var src_path = "../../static/assets/images/auth/custom/".concat($("#photo").val()); + } + img.src = src_path; + } + var file; function sendFile() { file = $("#file")[0].files[0] - document.getElementById("upload_input").innerHTML = '
 
' + document.getElementById("upload_input").innerHTML = '
 
'; let xmlHttpRequest = new XMLHttpRequest(); let token = getCookie("_xsrf") let fileName = file.name diff --git a/app/frontend/templates/panel/server_backup.html b/app/frontend/templates/panel/server_backup.html index a50b55b5..4af0ba1a 100644 --- a/app/frontend/templates/panel/server_backup.html +++ b/app/frontend/templates/panel/server_backup.html @@ -107,6 +107,40 @@ translate('serverBackups', 'shutdown', data['lang']) }} {% end %}
+
+ + {% if data['backup_config']['before'] %} + Run + Command Before Backup +
+ + {% else %} + Run Command + Before Backup +
+ + {% end %} +
+
+ + {% if data['backup_config']['after'] %} + Run + Command After Backup +
+ + {% else %} + Run Command + Before Backup +
+ + {% end %} +
@@ -344,6 +378,22 @@ }); } + $("#before-check").on("click", function () { + if ($("#before-check:checked").val()) { + $("#backup_before").css("display", "inline-block"); + } else { + $("#backup_before").css("display", "none"); + $("#backup_before").val(""); + } + }); + $("#after-check").on("click", function () { + if ($("#after-check:checked").val()) { + $("#backup_after").css("display", "inline-block"); + } else { + $("#backup_after").css("display", "none"); + $("#backup_after").val(""); + } + }); $(document).ready(function () { try { diff --git a/app/frontend/templates/public/404.html b/app/frontend/templates/public/404.html index 480fe5cf..c598dd19 100644 --- a/app/frontend/templates/public/404.html +++ b/app/frontend/templates/public/404.html @@ -23,7 +23,7 @@ @@ -36,8 +37,9 @@
-