diff --git a/app/classes/controllers/management_controller.py b/app/classes/controllers/management_controller.py index 33eceb1b..c8900475 100644 --- a/app/classes/controllers/management_controller.py +++ b/app/classes/controllers/management_controller.py @@ -91,6 +91,10 @@ class Management_Controller: def get_scheduled_task(schedule_id): return management_helper.get_scheduled_task(schedule_id) + @staticmethod + def get_scheduled_task_model(schedule_id): + return management_helper.get_scheduled_task_model(schedule_id) + @staticmethod def get_schedules_by_server(server_id): return management_helper.get_schedules_by_server(server_id) @@ -111,5 +115,5 @@ class Management_Controller: return management_helper.get_backup_config(server_id) @staticmethod - def set_backup_config(server_id: int, backup_path: str = None, max_backups: int = None, auto_enabled: bool = True): - return management_helper.set_backup_config(server_id, backup_path, max_backups, auto_enabled) + def set_backup_config(server_id: int, backup_path: str = None, max_backups: int = None): + return management_helper.set_backup_config(server_id, backup_path, max_backups) diff --git a/app/classes/models/management.py b/app/classes/models/management.py index d3d938d2..6c6c520c 100644 --- a/app/classes/models/management.py +++ b/app/classes/models/management.py @@ -112,6 +112,8 @@ class Schedules(Model): start_time = CharField(null=True) command = CharField(null=True) comment = CharField() + one_time = BooleanField(default=False) + cron_string = CharField(default="") class Meta: table_name = 'schedules' @@ -205,7 +207,7 @@ class helpers_management: # Schedules Methods #************************************************************************************************ @staticmethod - def create_scheduled_task(server_id, action, interval, interval_type, start_time, command, comment=None, enabled=True): + def create_scheduled_task(server_id, action, interval, interval_type, start_time, command, comment=None, enabled=True, one_time=False, cron_string='* * * * *'): sch_id = Schedules.insert({ Schedules.server_id: server_id, Schedules.action: action, @@ -214,7 +216,10 @@ class helpers_management: Schedules.interval_type: interval_type, Schedules.start_time: start_time, Schedules.command: command, - Schedules.comment: comment + Schedules.comment: comment, + Schedules.one_time: one_time, + Schedules.cron_string: cron_string + }).execute() return sch_id @@ -235,6 +240,10 @@ class helpers_management: def get_scheduled_task(schedule_id): return model_to_dict(Schedules.get(Schedules.schedule_id == schedule_id)).execute() + @staticmethod + def get_scheduled_task_model(schedule_id): + return Schedules.select().where(Schedules.schedule_id == schedule_id).get() + @staticmethod def get_schedules_by_server(server_id): return Schedules.select().where(Schedules.server_id == server_id).execute() @@ -272,7 +281,7 @@ class helpers_management: return conf @staticmethod - def set_backup_config(server_id: int, backup_path: str = None, max_backups: int = None, auto_enabled: bool = True): + def set_backup_config(server_id: int, backup_path: str = None, max_backups: int = None): logger.debug("Updating server {} backup config with {}".format(server_id, locals())) try: row = Backups.select().where(Backups.server_id == server_id).join(Schedules).join(Servers)[0] @@ -297,7 +306,6 @@ class helpers_management: new_row = True if max_backups is not None: conf['max_backups'] = max_backups - schd['enabled'] = bool(auto_enabled) if not new_row: with database.atomic(): if backup_path is not None: @@ -305,15 +313,12 @@ class helpers_management: else: u1 = 0 u2 = Backups.update(conf).where(Backups.server_id == server_id).execute() - u3 = Schedules.update(schd).where(Schedules.schedule_id == row.schedule_id).execute() logger.debug("Updating existing backup record. {}+{}+{} rows affected".format(u1, u2, u3)) else: with database.atomic(): conf["server_id"] = server_id if backup_path is not None: u = Servers.update(backup_path=backup_path).where(Servers.server_id == server_id) - s = Schedules.create(**schd) - conf['schedule_id'] = s.schedule_id b = Backups.create(**conf) logger.debug("Creating new backup record.") diff --git a/app/classes/shared/tasks.py b/app/classes/shared/tasks.py index 46391226..28bea355 100644 --- a/app/classes/shared/tasks.py +++ b/app/classes/shared/tasks.py @@ -1,3 +1,4 @@ +from datetime import timedelta import os import sys import json @@ -6,6 +7,11 @@ import logging import threading import asyncio import shutil +from tzlocal import get_localzone +import tzlocal + +from pytz import HOUR, timezone +from app.classes.controllers.users_controller import Users_Controller from app.classes.shared.helpers import helper from app.classes.shared.console import console @@ -15,6 +21,8 @@ from app.classes.web.websocket_helper import websocket_helper from app.classes.minecraft.serverjars import server_jar_obj from app.classes.models.servers import servers_helper from app.classes.models.management import management_helper +from apscheduler.schedulers.background import BackgroundScheduler +from apscheduler.events import EVENT_JOB_ERROR, EVENT_JOB_EXECUTED, EVENT_ALL, EVENT_JOB_REMOVED logger = logging.getLogger(__name__) @@ -46,6 +54,10 @@ class TasksManager: self.controller = controller self.tornado = Webserver(controller, self) + self.scheduler = BackgroundScheduler(timezone=str(tzlocal.get_localzone())) + + self.users_controller = Users_Controller() + self.webserver_thread = threading.Thread(target=self.tornado.run_tornado, daemon=True, name='tornado_thread') self.main_thread_exiting = False @@ -104,6 +116,8 @@ class TasksManager: elif command == "update_executable": svr.jar_update() + else: + svr.send_command(command) management_helper.mark_command_complete(c.get('command_id', None)) time.sleep(1) @@ -147,11 +161,87 @@ class TasksManager: console.info("Launching realtime thread...") self.realtime_thread.start() - @staticmethod - def scheduler_thread(): - while True: - schedule.run_pending() - time.sleep(1) + def scheduler_thread(self): + schedules = management_helper.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') + #load schedules from DB + for schedule in schedules: + if schedule.cron_string != "": + cron = schedule.cron_string.split(' ') + self.scheduler.add_job(management_helper.add_command, 'cron', minute = cron[0], hour = cron[1], day = cron[2], month = cron[3], day_of_week = cron[4], id=str(schedule.schedule_id), args=[schedule.server_id, self.users_controller.get_id_by_name('system'), '127.0.0.1', schedule.command]) + else: + if schedule.interval_type == 'hours': + self.scheduler.add_job(management_helper.add_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]) + elif schedule.interval_type == 'minutes': + self.scheduler.add_job(management_helper.add_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]) + elif schedule.interval_type == 'days': + time = schedule.start_time.split(':') + self.scheduler.add_job(management_helper.add_command, 'cron', day = '*/'+str(schedule.interval), hour=time[0], minute=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]) + + self.scheduler.start() + + + def schedule_job(self, job_data): + sch_id = management_helper.create_scheduled_task(job_data['server_id'], job_data['action'], job_data['interval'], job_data['interval_type'], job_data['time'], job_data['command'], "None", job_data['enabled'], job_data['one_time'], job_data['cron_string']) + if job_data['enabled']: + if job_data['cron_string'] != "": + cron = job_data['cron_string'].split(' ') + try: + self.scheduler.add_job(management_helper.add_command, 'cron', minute = cron[0], hour = cron[1], day = cron[2], month = cron[3], day_of_week = cron[4], id=str(sch_id), args=[job_data['server_id'], self.users_controller.get_id_by_name('system'), '127.0.0.1', job_data['command']]) + except Exception as e: + console.error("Failed to schedule task with error: {}.".format(e)) + console.info("Removing failed task from DB.") + management_helper.delete_scheduled_task(sch_id) + else: + if job_data['interval_type'] == 'hours': + self.scheduler.add_job(management_helper.add_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']]) + elif job_data['interval_type'] == 'minutes': + self.scheduler.add_job(management_helper.add_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']]) + elif job_data['interval_type'] == 'days': + time = job_data['start_time'].split(':') + self.scheduler.add_job(management_helper.add_command, 'cron', day = '*/'+str(job_data['interval']), hour = time[0], minute = 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']], ) + + def remove_job(self, sch_id): + management_helper.delete_scheduled_task(sch_id) + self.scheduler.remove_job(str(sch_id)) + + def update_job(self, sch_id, job_data): + management_helper.update_scheduled_task(sch_id, job_data) + if job_data['enabled']: + self.scheduler.remove_job(str(sch_id)) + if job_data['cron_string'] != "": + cron = job_data['cron_string'].split(' ') + try: + self.scheduler.add_job(management_helper.add_command, 'cron', minute = cron[0], hour = cron[1], day = cron[2], month = cron[3], day_of_week = cron[4], args=[job_data['server_id'], self.users_controller.get_id_by_name('system'), '127.0.0.1', job_data['command']]) + except Exception as e: + console.error("Failed to schedule task with error: {}.".format(e)) + console.info("Removing failed task from DB.") + management_helper.delete_scheduled_task(sch_id) + else: + if job_data['interval_type'] == 'hours': + self.scheduler.add_job(management_helper.add_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']]) + elif job_data['interval_type'] == 'minutes': + self.scheduler.add_job(management_helper.add_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']]) + elif job_data['interval_type'] == 'days': + time = job_data['start_time'].split(':') + self.scheduler.add_job(management_helper.add_command, 'cron', day = '*/'+str(job_data['interval']), hour = time[0], minute = 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']], ) + else: + try: + self.scheduler.get_job(str(sch_id)) + self.scheduler.remove_job(str(sch_id)) + except: + logger.info("APScheduler found no scheduled job on schedule update for schedule with id: {}. Assuming it was already disabled.".format(sch_id)) + + def schedule_watcher(self, event): + if not event.exception: + task = management_helper.get_scheduled_task_model(int(event.job_id)) + if task.one_time: + self.remove_job(task.schedule_id) + logger.info("one time task detected. Deleting...") + else: + print("error") + logger.error("Task failed with error: {}".format(event.exception)) def start_stats_recording(self): stats_update_frequency = helper.get_setting('stats_update_frequency') diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index 1456d7e4..d8f472aa 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -341,6 +341,13 @@ class AjaxHandler(BaseHandler): # Delete the file os.remove(file_path) + if page == "del_task": + if not permissions['Schedule'] in user_perms: + self.redirect("/panel/error?error=Unauthorized access to Tasks") + else: + sch_id = self.get_argument('schedule_id', '-404') + self.tasks_manager.remove_job(sch_id) + if page == "del_backup": if not permissions['Backup'] in user_perms: if not exec_user['superuser']: diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index 428e21f8..79211b1e 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -8,6 +8,7 @@ import time import datetime import os +from tornado import locale from tornado import iostream from tornado.ioloop import IOLoop from app.classes.shared.console import console @@ -459,6 +460,98 @@ class PanelHandler(BaseHandler): page_data['languages'].append(file.split('.')[0]) template = "panel/panel_edit_user.html" + + elif page == "add_schedule": + server_id = self.get_argument('id', None) + page_data['get_players'] = lambda: self.controller.stats.get_server_players(server_id) + page_data['active_link'] = 'tasks' + page_data['permissions'] = { + 'Commands': Enum_Permissions_Server.Commands, + 'Terminal': Enum_Permissions_Server.Terminal, + 'Logs': Enum_Permissions_Server.Logs, + 'Schedule': Enum_Permissions_Server.Schedule, + 'Backup': Enum_Permissions_Server.Backup, + 'Files': Enum_Permissions_Server.Files, + 'Config': Enum_Permissions_Server.Config, + 'Players': Enum_Permissions_Server.Players, + } + page_data['user_permissions'] = self.controller.server_perms.get_server_permissions_foruser(exec_user_id, server_id) + exec_user_server_permissions = self.controller.server_perms.get_user_permissions_list(exec_user_id, server_id) + page_data['server_data'] = self.controller.servers.get_server_data_by_id(server_id) + page_data['server_stats'] = self.controller.servers.get_server_stats_by_id(server_id) + page_data['new_schedule'] = True + page_data['schedule'] = {} + page_data['schedule']['server_id'] = server_id + page_data['schedule']['schedule_id'] = '' + page_data['schedule']['action'] = "" + page_data['schedule']['enabled'] = True + page_data['schedule']['command'] = '' + page_data['schedule']['one_time'] = False + page_data['schedule']['cron_string'] = "" + page_data['schedule']['time'] = "" + page_data['schedule']['interval'] = "" + #we don't need to check difficulty here. We'll just default to basic for new schedules + page_data['schedule']['difficulty'] = "basic" + page_data['schedule']['interval_type'] = 'days' + + if not Enum_Permissions_Server.Schedule in exec_user_server_permissions: + if not exec_user['superuser']: + self.redirect("/panel/error?error=Unauthorized access To Scheduled Tasks") + return + + template = "panel/server_schedule_edit.html" + + elif page == "edit_schedule": + server_id = self.get_argument('id', None) + sch_id = self.get_argument('sch_id', None) + schedule = self.controller.management.get_scheduled_task_model(sch_id) + page_data['get_players'] = lambda: self.controller.stats.get_server_players(server_id) + page_data['active_link'] = 'tasks' + page_data['permissions'] = { + 'Commands': Enum_Permissions_Server.Commands, + 'Terminal': Enum_Permissions_Server.Terminal, + 'Logs': Enum_Permissions_Server.Logs, + 'Schedule': Enum_Permissions_Server.Schedule, + 'Backup': Enum_Permissions_Server.Backup, + 'Files': Enum_Permissions_Server.Files, + 'Config': Enum_Permissions_Server.Config, + 'Players': Enum_Permissions_Server.Players, + } + page_data['user_permissions'] = self.controller.server_perms.get_server_permissions_foruser(exec_user_id, server_id) + exec_user_server_permissions = self.controller.server_perms.get_user_permissions_list(exec_user_id, server_id) + page_data['server_data'] = self.controller.servers.get_server_data_by_id(server_id) + page_data['server_stats'] = self.controller.servers.get_server_stats_by_id(server_id) + page_data['new_schedule'] = False + page_data['schedule'] = {} + page_data['schedule']['server_id'] = server_id + page_data['schedule']['schedule_id'] = schedule.schedule_id + page_data['schedule']['action'] = schedule.action + #we check here to see if the command is any of the default ones. We do not want a user changing to a custom command and seeing our command there. + if schedule.action != 'start' or schedule.action != 'stop' or schedule.action != 'restart' or schedule.action != 'backup': + page_data['schedule']['command'] = schedule.command + else: + page_data['schedule']['command'] = '' + page_data['schedule']['enabled'] = schedule.enabled + page_data['schedule']['one_time'] = schedule.one_time + page_data['schedule']['cron_string'] = schedule.cron_string + page_data['schedule']['time'] = schedule.start_time + page_data['schedule']['interval'] = schedule.interval + page_data['schedule']['interval_type'] = schedule.interval_type + if schedule.cron_string == '': + difficulty = 'basic' + else: + difficulty = 'advanced' + page_data['schedule']['difficulty'] = difficulty + + if sch_id == None or server_id == None: + self.redirect("/panel/error?error=Invalid server ID or Schedule ID") + + if not Enum_Permissions_Server.Schedule in exec_user_server_permissions: + if not exec_user['superuser']: + self.redirect("/panel/error?error=Unauthorized access To Scheduled Tasks") + return + + template = "panel/server_schedule_edit.html" elif page == "edit_user": user_id = self.get_argument('id', None) @@ -801,10 +894,6 @@ class PanelHandler(BaseHandler): else: backup_path = server_obj.backup_path max_backups = bleach.clean(self.get_argument('max_backups', None)) - try: - enabled = int(float(bleach.clean(self.get_argument('auto_enabled'), '0'))) - except Exception as e: - enabled = '0' if not permissions['Backup'] in user_perms: if not exec_user['superuser']: @@ -819,18 +908,10 @@ class PanelHandler(BaseHandler): self.redirect("/panel/error?error=Invalid Server ID") return - if enabled == '0': - #TODO Use Controller method - server_obj = self.controller.servers.get_server_obj(server_id) - server_obj.backup_path = backup_path - self.controller.servers.update_server(server_obj) - self.controller.management.set_backup_config(server_id, max_backups=max_backups, auto_enabled=False) - else: - #TODO Use Controller method - server_obj = self.controller.servers.get_server_obj(server_id) - server_obj.backup_path = backup_path - self.controller.servers.update_server(server_obj) - self.controller.management.set_backup_config(server_id, max_backups=max_backups, auto_enabled=True) + server_obj = self.controller.servers.get_server_obj(server_id) + server_obj.backup_path = backup_path + self.controller.servers.update_server(server_obj) + self.controller.management.set_backup_config(server_id, max_backups=max_backups) self.controller.management.add_to_audit_log(exec_user['user_id'], "Edited server {}: updated backups".format(server_id), @@ -839,6 +920,239 @@ class PanelHandler(BaseHandler): self.tasks_manager.reload_schedule_from_db() self.redirect("/panel/server_detail?id={}&subpage=backup".format(server_id)) + + if page == "add_schedule": + server_id = bleach.clean(self.get_argument('id', None)) + difficulty = bleach.clean(self.get_argument('difficulty', None)) + server_obj = self.controller.servers.get_server_obj(server_id) + enabled = bleach.clean(self.get_argument('enabled', '0')) + if difficulty == 'basic': + action = bleach.clean(self.get_argument('action', None)) + interval = bleach.clean(self.get_argument('interval', None)) + interval_type = bleach.clean(self.get_argument('interval_type', None)) + #only check for time if it's number of days + if interval_type == "days": + time = bleach.clean(self.get_argument('time', None)) + if action == "command": + command = bleach.clean(self.get_argument('command', None)) + elif action == "start": + command = "start_server" + elif action == "stop": + command = "stop_server" + elif action == "restart": + command = "restart_server" + elif action == "backup": + command = "backup_server" + else: + interval_type = '' + cron_string = bleach.clean(self.get_argument('cron', '')) + cron_split = cron_string.split(' ') + if len(cron_split) != 5: + self.redirect("/panel/error?error=INVALID FORMAT: Invalid Cron Format. Cron must have a space between each character and only have a max of 5 characters * * * * *") + return + action = bleach.clean(self.get_argument('action', None)) + if action == "command": + command = bleach.clean(self.get_argument('command', None)) + elif action == "start": + command = "start_server" + elif action == "stop": + command = "stop_server" + elif action == "restart": + command = "restart_server" + elif action == "backup": + command = "backup_server" + if bleach.clean(self.get_argument('enabled', '1'))=='1': + enabled = True + else: + enabled = False + if bleach.clean(self.get_argument('one_time', '0')) == '1': + one_time = True + else: + one_time = False + + if not exec_user['superuser'] and not permissions['Backup'] in user_perms: + self.redirect("/panel/error?error=Unauthorized access: User not authorized") + return + elif server_id is None: + self.redirect("/panel/error?error=Invalid Server ID") + return + else: + # does this server id exist? + if not self.controller.servers.server_id_exists(server_id): + self.redirect("/panel/error?error=Invalid Server ID") + return + minute = datetime.datetime.now().minute + hour = datetime.datetime.now().hour + if minute < 10: + minute = '0' + str(minute) + if hour < 10: + hour = '0'+str(hour) + current_time = str(hour)+':'+str(minute) + + if interval_type == "days": + job_data = { + "server_id": server_id, + "action": action, + "interval_type": interval_type, + "interval": interval, + "command": command, + "start_time": time, + "enabled": enabled, + "one_time": one_time, + "cron_string": '' + } + elif difficulty == "advanced": + job_data = { + "server_id": server_id, + "action": action, + "interval_type": '', + "interval": '', + "command": '', + "start_time": current_time, + "command": command, + "cron_string": cron_string, + "enabled": enabled, + "one_time": one_time + } + else: + job_data = { + "server_id": server_id, + "action": action, + "interval_type": interval_type, + "interval": interval, + "command": command, + "enabled": enabled, + "start_time": current_time, + "one_time": one_time, + "cron_string": '' + } + + self.tasks_manager.schedule_job(job_data) + + self.controller.management.add_to_audit_log(exec_user['user_id'], + "Edited server {}: added scheduled job".format(server_id), + server_id, + self.get_remote_ip()) + self.tasks_manager.reload_schedule_from_db() + self.redirect("/panel/server_detail?id={}&subpage=tasks".format(server_id)) + + + if page == "edit_schedule": + server_id = bleach.clean(self.get_argument('id', None)) + difficulty = bleach.clean(self.get_argument('difficulty', None)) + server_obj = self.controller.servers.get_server_obj(server_id) + enabled = bleach.clean(self.get_argument('enabled', '0')) + if difficulty == 'basic': + action = bleach.clean(self.get_argument('action', None)) + interval = bleach.clean(self.get_argument('interval', None)) + interval_type = bleach.clean(self.get_argument('interval_type', None)) + #only check for time if it's number of days + if interval_type == "days": + time = bleach.clean(self.get_argument('time', None)) + if action == "command": + command = bleach.clean(self.get_argument('command', None)) + elif action == "start": + command = "start_server" + elif action == "stop": + command = "stop_server" + elif action == "restart": + command = "restart_server" + elif action == "backup": + command = "backup_server" + else: + interval_type = '' + cron_string = bleach.clean(self.get_argument('cron', '')) + sch_id = self.get_argument('sch_id', None) + if len(cron_string.split(' ')) != 5: + self.redirect("/panel/error?error=INVALID FORMAT: Invalid Cron Format. Cron must have a space between each character and only have a max of 5 characters * * * * *") + return + action = bleach.clean(self.get_argument('action', None)) + if action == "command": + command = bleach.clean(self.get_argument('command', None)) + elif action == "start": + command = "start_server" + elif action == "stop": + command = "stop_server" + elif action == "restart": + command = "restart_server" + elif action == "backup": + command = "backup_server" + if bleach.clean(self.get_argument('enabled', '1'))=='1': + enabled = True + else: + enabled = False + if bleach.clean(self.get_argument('one_time', '0')) == '1': + one_time = True + else: + one_time = False + + if not exec_user['superuser'] and not permissions['Backup'] in user_perms: + self.redirect("/panel/error?error=Unauthorized access: User not authorized") + return + elif server_id is None: + self.redirect("/panel/error?error=Invalid Server ID") + return + else: + # does this server id exist? + if not self.controller.servers.server_id_exists(server_id): + self.redirect("/panel/error?error=Invalid Server ID") + return + minute = datetime.datetime.now().minute + hour = datetime.datetime.now().hour + if minute < 10: + minute = '0' + str(minute) + if hour < 10: + hour = '0'+str(hour) + current_time = str(hour)+':'+str(minute) + + if interval_type == "days": + job_data = { + "server_id": server_id, + "action": action, + "interval_type": interval_type, + "interval": interval, + "command": command, + "start_time": time, + "enabled": enabled, + "one_time": one_time, + "cron_string": '' + } + elif difficulty == "advanced": + job_data = { + "server_id": server_id, + "action": action, + "interval_type": '', + "interval": '', + "command": '', + "start_time": current_time, + "command": command, + "cron_string": cron_string, + "enabled": enabled, + "one_time": one_time + } + else: + job_data = { + "server_id": server_id, + "action": action, + "interval_type": interval_type, + "interval": interval, + "command": command, + "enabled": enabled, + "start_time": current_time, + "one_time": one_time, + "cron_string": '' + } + sch_id = self.get_argument('sch_id', None) + self.tasks_manager.update_job(sch_id, job_data) + + self.controller.management.add_to_audit_log(exec_user['user_id'], + "Edited server {}: updated schedule".format(server_id), + server_id, + self.get_remote_ip()) + self.tasks_manager.reload_schedule_from_db() + self.redirect("/panel/server_detail?id={}&subpage=tasks".format(server_id)) + + elif page == "edit_user": if bleach.clean(self.get_argument('username', None)) == 'system': self.redirect("/panel/error?error=Unauthorized access: system user is not editable") @@ -1144,8 +1458,8 @@ class PanelHandler(BaseHandler): else: self.set_status(404) - page_data = [] - page_data['lang'] = tornado.locale.get("en_EN") + page_data = {} + page_data['lang'] = locale.get("en_EN") self.render( "public/404.html", translate=self.translator.translate, diff --git a/app/frontend/templates/panel/parts/server_controls_list.html b/app/frontend/templates/panel/parts/server_controls_list.html index b3502e96..6cbad0d2 100644 --- a/app/frontend/templates/panel/parts/server_controls_list.html +++ b/app/frontend/templates/panel/parts/server_controls_list.html @@ -13,7 +13,7 @@ {% end %} {% if data['permissions']['Schedule'] in data['user_permissions'] %} {% end %} diff --git a/app/frontend/templates/panel/server_backup.html b/app/frontend/templates/panel/server_backup.html index f44f892a..df25644e 100644 --- a/app/frontend/templates/panel/server_backup.html +++ b/app/frontend/templates/panel/server_backup.html @@ -56,16 +56,6 @@ -
- -
- diff --git a/app/frontend/templates/panel/server_schedule_edit.html b/app/frontend/templates/panel/server_schedule_edit.html new file mode 100644 index 00000000..ebf3689a --- /dev/null +++ b/app/frontend/templates/panel/server_schedule_edit.html @@ -0,0 +1,251 @@ +{% extends ../base.html %} + +{% block meta %} + +{% end %} + +{% block title %}Crafty Controller - {{ translate('serverDetails', 'serverDetails', data['lang']) }}{% end %} + +{% block content %} + +
+ + +
+
+ +
+ +
+ + + {% include "parts/details_stats.html %} + +
+ +
+
+
+ {% include "parts/server_controls_list.html %} + +
+
+ {% if data['new_schedule'] == True %} +
+ {% else %} + + {% end %} + {% raw xsrf_form_html() %} + + + +
+
+ +
+
+
+ +
+
+
+ + +
+
+ +
+
+
+ + +
+
+
+ + + +
+ + +
+
+ + +
+ + +
+
+ +
+
+
+
+ + + +
+ + +{% end %} + +{% block js %} + + +{% end %} \ No newline at end of file diff --git a/app/frontend/templates/panel/server_tasks.html b/app/frontend/templates/panel/server_tasks.html index a345b135..f5aa57e6 100644 --- a/app/frontend/templates/panel/server_tasks.html +++ b/app/frontend/templates/panel/server_tasks.html @@ -35,98 +35,39 @@ {% include "parts/server_controls_list.html %}
-
-
- {% raw xsrf_form_html() %} - - - -
-
- -
-
-
-
- -
- -
- - -
-
- -
- -
- - -
- -
- - -
- - -
-
- - -
- - - -
-
- -
+ +

Scheduled Tasks

+ + + + {% for schedule in data['schedules'] %} + + {% end %} - + {% end %} +
ActionCommand Interval Start Time Enabled Edit

{{schedule.action}}

+

{{schedule.command}}

+
+ {% if schedule.interval != '' %}

Every

{{schedule.interval}} {{schedule.interval_type}}

+ {% else %} +

Cron String:

+

{{schedule.cron_string}}

+ {% end %}

{{schedule.start_time}}

@@ -143,11 +84,18 @@
- - + +
+
+
@@ -184,19 +132,77 @@ function yesnoCheck(that) { if (that.value == "command") { document.getElementById("ifYes").style.display = "block"; + document.getElementById("command").required = true; } else { document.getElementById("ifYes").style.display = "none"; + document.getElementById("command").required = false; } } function basicAdvanced(that) { if (that.value == "advanced") { document.getElementById("ifAdvanced").style.display = "block"; document.getElementById("ifBasic").style.display = "none"; + document.getElementById("interval").required = false; + document.getElementById("time").required = false; } else { document.getElementById("ifAdvanced").style.display = "none"; document.getElementById("ifBasic").style.display = "block"; + document.getElementById("interval").required = true; + document.getElementById("time").required = true; } } +function ifDays(that) { + if (that.value == "days") { + document.getElementById("ifDays").style.display = "block"; + document.getElementById("time").required = true; + } else { + document.getElementById("ifDays").style.display = "none"; + document.getElementById("time").required = false; + } +} + +$( ".del_button" ).click(function() { + var sch_id = $(this).data('sch'); + var server_id = {{ data['server_stats']['server_id']['server_id'] }}; + + console.log(sch_id) + + bootbox.confirm({ + title: "Test", + message: "{{ translate('serverBackups', 'confirmDelete', data['lang']) }}", + buttons: { + cancel: { + label: ' {{ translate("serverBackups", "cancel", data['lang']) }}' + }, + confirm: { + label: ' {{ translate("serverBackups", "confirm", data['lang']) }}' + } + }, + callback: function (result) { + console.log(result); + if (result == true) { + del_task(sch_id, server_id); + } + } + }); +}); + +function del_task(sch_id, id){ + var token = getCookie("_xsrf") + + $.ajax({ + type: "DELETE", + headers: {'X-XSRFToken': token}, + url: '/ajax/del_task?server_id='+id+'&schedule_id='+sch_id, + data: { + schedule_id: sch_id, + id: id + }, + success: function(data) { + location.reload(); + }, + }); +} diff --git a/app/migrations/20210915205501_cron_task.py b/app/migrations/20210915205501_cron_task.py new file mode 100644 index 00000000..62767240 --- /dev/null +++ b/app/migrations/20210915205501_cron_task.py @@ -0,0 +1,16 @@ +# Generated by database migrator +import peewee + +def migrate(migrator, database, **kwargs): + migrator.add_columns('schedules', cron_string=peewee.CharField(default="")) + """ + Write your migrations here. + """ + + + +def rollback(migrator, database, **kwargs): + migrator.drop_columns('schedules', ['cron_string']) + """ + Write your rollback migrations here. + """ diff --git a/app/migrations/20210915205501_one_time_task.py b/app/migrations/20210915205501_one_time_task.py new file mode 100644 index 00000000..3ed0041a --- /dev/null +++ b/app/migrations/20210915205501_one_time_task.py @@ -0,0 +1,16 @@ +# Generated by database migrator +import peewee + +def migrate(migrator, database, **kwargs): + migrator.add_columns('schedules', one_time=peewee.BooleanField(default=False)) + """ + Write your migrations here. + """ + + + +def rollback(migrator, database, **kwargs): + migrator.drop_columns('schedules', ['one_time']) + """ + Write your rollback migrations here. + """