From 5c85a575ee9874427b57a4666b30f9d57caa95cd Mon Sep 17 00:00:00 2001 From: Scott R <86810816+xithical@users.noreply.github.com> Date: Fri, 13 Aug 2021 19:45:15 -0500 Subject: [PATCH 01/16] Improving backup efficiency with shutil Removed the old backup code that created a zip on a file-by-file basis and replaced it with make_archive from shutil to just zip the whole directory --- app/classes/shared/helpers.py | 11 +---------- app/classes/shared/server.py | 5 ++++- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index 8ee0de64..0091a647 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -553,13 +553,4 @@ class Helpers: return json.loads(content) - @staticmethod - def zip_directory(file, path, compression=zipfile.ZIP_LZMA): - with zipfile.ZipFile(file, 'w', compression) as zf: - for root, dirs, files in os.walk(path): - for file in files: - zf.write(os.path.join(root, file), - os.path.relpath(os.path.join(root, file), - os.path.join(path, '..'))) - -helper = Helpers() +helper = Helpers() \ No newline at end of file diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index ab6f6372..2fb6a004 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -10,6 +10,8 @@ import threading import schedule import logging.config import zipfile +import shutil +import zlib from app.classes.shared.helpers import helper @@ -324,7 +326,8 @@ class Server: try: backup_filename = "{}/{}.zip".format(conf['backup_path'], datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')) logger.info("Creating backup of server '{}' (ID#{}) at '{}'".format(self.settings['server_name'], self.server_id, backup_filename)) - helper.zip_directory(backup_filename, self.server_path) + # helper.zip_directory(backup_filename, self.server_path) + shutil.make_archive(backup_filename, zip, self.server_path) backup_list = self.list_backups() if len(self.list_backups()) > conf["max_backups"]: oldfile = backup_list[0] From 4757ac05735145543d77c90b5bcbc65de45d8677 Mon Sep 17 00:00:00 2001 From: xithical <86810816+xithical@users.noreply.github.com> Date: Fri, 13 Aug 2021 22:06:22 -0500 Subject: [PATCH 02/16] Repaired backup zipper and old backup removals *Fixed zip arg, should be in quotes *Set while statement to constantly check for and remove old backups *Repaired old backup removal not pulling correct path --- app/classes/shared/server.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index 2fb6a004..e08e9843 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -324,15 +324,15 @@ class Server: logger.info("Starting server {} (ID {}) backup".format(self.name, self.server_id)) conf = db_helper.get_backup_config(self.server_id) try: - backup_filename = "{}/{}.zip".format(conf['backup_path'], datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')) + backup_filename = "{}/{}".format(conf['backup_path'], datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')) logger.info("Creating backup of server '{}' (ID#{}) at '{}'".format(self.settings['server_name'], self.server_id, backup_filename)) - # helper.zip_directory(backup_filename, self.server_path) - shutil.make_archive(backup_filename, zip, self.server_path) - backup_list = self.list_backups() - if len(self.list_backups()) > conf["max_backups"]: + shutil.make_archive(backup_filename, 'zip', self.server_path) + while len(self.list_backups()) > conf["max_backups"]: + backup_list = self.list_backups() oldfile = backup_list[0] - logger.info("Removing old backup '{}'".format(oldfile)) - os.remove(oldfile) + oldfile_path = "{}/{}".format(conf['backup_path'], oldfile['path']) + logger.info("Removing old backup '{}'".format(oldfile['path'])) + os.remove(oldfile_path) except: logger.exception("Failed to create backup of server {} (ID {})".format(self.name, self.server_id)) From 096a38ae5435380e55a21bbcf41f59c50c332dc4 Mon Sep 17 00:00:00 2001 From: Scott R <86810816+xithical@users.noreply.github.com> Date: Fri, 13 Aug 2021 23:28:41 -0500 Subject: [PATCH 03/16] Redoing shutil zip after merging new DB things Merged from Pretzel for DB change things and needed to readd code for shutil for zipping --- app/classes/shared/helpers.py | 8 -------- app/classes/shared/server.py | 12 ++++++------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index 5d124d32..7242fda0 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -555,14 +555,6 @@ class Helpers: return json.loads(content) @staticmethod - def zip_directory(file, path, compression=zipfile.ZIP_LZMA): - with zipfile.ZipFile(file, 'w', compression) as zf: - for root, dirs, files in os.walk(path): - for file in files: - zf.write(os.path.join(root, file), - os.path.relpath(os.path.join(root, file), - os.path.join(path, '..'))) - @staticmethod def copy_files(source, dest): if os.path.isfile(source): shutil.copyfile(source, dest) diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index 2266b256..28292b98 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -11,6 +11,8 @@ import schedule import logging.config import zipfile from threading import Thread +import shutil +import zlib from app.classes.shared.helpers import helper @@ -366,15 +368,13 @@ class Server: try: backup_filename = "{}/{}.zip".format(self.settings['backup_path'], datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')) logger.info("Creating backup of server '{}' (ID#{}) at '{}'".format(self.settings['server_name'], self.server_id, backup_filename)) - helper.zip_directory(backup_filename, self.server_path) + shutil.make_archive(backup_filename, 'zip', self.server_path) while len(self.list_backups()) > conf["max_backups"]: backup_list = self.list_backups() oldfile = backup_list[0] - backup_path = self.settings['backup_path'] - old_file_name = oldfile['path'] - back_old_file = os.path.join(backup_path, old_file_name) - logger.info("Removing old backup '{}'".format(oldfile)) - os.remove(back_old_file) + oldfile_path = "{}/{}".format(conf['backup_path'], oldfile['path']) + logger.info("Removing old backup '{}'".format(oldfile['path'])) + os.remove(oldfile_path) self.is_backingup = False logger.info("Backup of server: {} completed".format(self.name)) return From 5b8764cb45dd9a17dd80f639098f228d19771fd3 Mon Sep 17 00:00:00 2001 From: Scott R <86810816+xithical@users.noreply.github.com> Date: Sat, 14 Aug 2021 00:00:09 -0500 Subject: [PATCH 04/16] Removed extra .zip Unnecessary .zip in backup filename generation in server.py, nuked it --- app/classes/shared/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index 28292b98..e4261b16 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -366,7 +366,7 @@ class Server: self.is_backingup = True conf = db_helper.get_backup_config(self.server_id) try: - backup_filename = "{}/{}.zip".format(self.settings['backup_path'], datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')) + backup_filename = "{}/{}".format(self.settings['backup_path'], datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')) logger.info("Creating backup of server '{}' (ID#{}) at '{}'".format(self.settings['server_name'], self.server_id, backup_filename)) shutil.make_archive(backup_filename, 'zip', self.server_path) while len(self.list_backups()) > conf["max_backups"]: From 689e4abb518579df1e639990f2d2b3f06eb128aa Mon Sep 17 00:00:00 2001 From: Scott R <86810816+xithical@users.noreply.github.com> Date: Sat, 14 Aug 2021 00:07:24 -0500 Subject: [PATCH 05/16] Oops! All backups are gone... but not anymore! While loop automatically removed all old backups greater than the max backups threshold... including if it was set to 0. Set a test for the while loop to make sure max backups is greater than 0 before deletey delete --- app/classes/shared/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index e4261b16..f28546c6 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -369,7 +369,7 @@ class Server: backup_filename = "{}/{}".format(self.settings['backup_path'], datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')) logger.info("Creating backup of server '{}' (ID#{}) at '{}'".format(self.settings['server_name'], self.server_id, backup_filename)) shutil.make_archive(backup_filename, 'zip', self.server_path) - while len(self.list_backups()) > conf["max_backups"]: + while len(self.list_backups()) > conf["max_backups"] and conf["max_backups"] > 0: backup_list = self.list_backups() oldfile = backup_list[0] oldfile_path = "{}/{}".format(conf['backup_path'], oldfile['path']) From 00422f24cdcd4e90339e19eed399d0e44f9bded4 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 18 Aug 2021 18:50:53 -0400 Subject: [PATCH 06/16] Moved delete server to ajax call instead of a task. --- app/classes/shared/tasks.py | 10 ------ app/classes/web/ajax_handler.py | 12 +++++++ .../templates/panel/server_config.html | 33 +++++++++++++++++-- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/app/classes/shared/tasks.py b/app/classes/shared/tasks.py index 572918db..91d8ff0b 100644 --- a/app/classes/shared/tasks.py +++ b/app/classes/shared/tasks.py @@ -113,16 +113,6 @@ class TasksManager: elif command == "update_executable": svr.jar_update() - elif command == "delete_server": - logger.info( - "Removing server from panel for server: {}".format(c['server_id']['server_name'])) - self.controller.remove_server(c['server_id']['server_id'], False) - - elif command == "delete_server_files": - logger.info( - "Removing server and all associated files for server: {}".format(c['server_id']['server_name'])) - self.controller.remove_server(c['server_id']['server_id'], True) - db_helper.mark_command_complete(c.get('command_id', None)) time.sleep(1) diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index bca9397e..c84983ad 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -229,6 +229,18 @@ class AjaxHandler(BaseHandler): # os.rmdir(dir_path) # Would only remove empty directories shutil.rmtree(dir_path) # Removes also when there are contents + elif page == "delete_server": + server_id = self.get_argument('id', None) + logger.info( + "Removing server from panel for server: {}".format(db_helper.get_server_friendly_name(server_id))) + self.controller.remove_server(server_id, False) + + elif page == "delete_server_files": + server_id = self.get_argument('id', None) + logger.info( + "Removing server and all associated files for server: {}".format(db_helper.get_server_friendly_name(server_id))) + self.controller.remove_server(server_id, True) + @tornado.web.authenticated def put(self, page): if page == "save_file": diff --git a/app/frontend/templates/panel/server_config.html b/app/frontend/templates/panel/server_config.html index 501e4d96..a4195bc7 100644 --- a/app/frontend/templates/panel/server_config.html +++ b/app/frontend/templates/panel/server_config.html @@ -203,6 +203,35 @@ }); + function deleteServerE(callback) { + var token = getCookie("_xsrf") + $.ajax({ + type: "DELETE", + headers: {'X-XSRFToken': token}, + url: '/ajax/delete_server?id={{ data['server_stats']['server_id']['server_id'] }}', + data: { + }, + success: function(data){ + console.log("got response:"); + console.log(data); + }, + }); + } + function deleteServerFilesE(path, callback) { + var token = getCookie("_xsrf") + $.ajax({ + type: "DELETE", + headers: {'X-XSRFToken': token}, + url: '/ajax/delete_server_files?id={{ data['server_stats']['server_id']['server_id'] }}', + data: { + }, + success: function(data){ + console.log("got response:"); + console.log(data); + }, + }); + } + let server_id = '{{ data['server_stats']['server_id']['server_id'] }}'; function send_command (server_id, command){ @@ -249,7 +278,7 @@ let server_id = '{{ data['server_stats']['server_id']['server_id'] }}'; }, callback: function(result) { if (!result){ - send_command(server_id, 'delete_server'); + deleteServerE() setTimeout(function(){ window.location = '/panel/dashboard'; }, 5000); bootbox.dialog({ backdrop: true, @@ -260,7 +289,7 @@ let server_id = '{{ data['server_stats']['server_id']['server_id'] }}'; return;} else{ - send_command(server_id, 'delete_server_files'); + deleteServerFilesE(); setTimeout(function(){ window.location = '/panel/dashboard'; }, 5000); bootbox.dialog({ backdrop: true, From 90d59faf5b271ec18ce8f152f890aaa781bc3846 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 19 Aug 2021 16:50:18 -0400 Subject: [PATCH 07/16] This is broken right now. Trying to add unzip function --- .DS_Store | Bin 0 -> 6148 bytes app/classes/shared/helpers.py | 35 +++++++++++ app/classes/shared/server.py | 1 + app/classes/web/ajax_handler.py | 59 +++++++++++++++++- .../templates/panel/server_files.html | 41 ++++++++++++ 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a2f64789cddbefe1f8e91efcfafbb526e0b8bc19 GIT binary patch literal 6148 zcmeHK!AiqG5S_JE6GiMn(Bodb^-!_3co0I>gEt|f2bG%8qJf%(Cbej+*$eimdlB{B)JuCw z!|NW?Xx~dOeD)8bsPpc7{$bGWH%m*~QJ8u`*zT(2pw-5ZlcOMPMg2z93tNfW$JGn! zpk`?~%hor`vR2(3lx0@0SIV-wzA+fs*7EAw*529W^-Xp=xVzVM3cP)kEHb{q13FyY zmD>$FQFx9s6g>+Gw4n=E$|fIbfA-_wt$iiSsHLwDh_3A@sGGTROS!~D&Lq% zWq`jLYkpD*Fm)RS3{YEH3pLz+(k&F&wt`S#Igib}& zse)S!q0@0*a-74MYt-o=xcLx#vfvIysMB$Oslq`x8jUp!7zREwP|(8?z5l!8`~S~L zW@H#J4E!qwL~+O6X<$kGwvH4>Z>>Z 1: + for i in range(len(path_list) - 2): + root_path = os.path.join(root_path, path_list[i + 1]) + + full_root_path = os.path.join(tempDir, root_path) + + for item in os.listdir(full_root_path): + try: + shutil.move(os.path.join(full_root_path, item), os.path.join(new_dir, item)) + except Exception as ex: + logger.error('ERROR IN ZIP IMPORT: {}'.format(ex)) + else: + return "false" + def ensure_logging_setup(self): log_file = os.path.join(os.path.curdir, 'logs', 'commander.log') session_log_file = os.path.join(os.path.curdir, 'logs', 'session.log') diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index e9a9f1c4..6baa8713 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -503,6 +503,7 @@ class Server: while db_helper.get_server_stats_by_id(self.server_id)['updating']: if downloaded and not self.is_backingup: + print("Backup Status: " + str(self.is_backingup)) logger.info("Executable updated successfully. Starting Server") db_helper.set_update(self.server_id, False) diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index c84983ad..d236186e 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -1,5 +1,8 @@ import json import logging +import tempfile +import zipfile + import tornado.web import tornado.escape import bleach @@ -183,10 +186,64 @@ class AjaxHandler(BaseHandler): logger.warning("Invalid path in create_dir ajax call ({})".format(dir_path)) console.warning("Invalid path in create_dir ajax call ({})".format(dir_path)) return - # Create the directory os.mkdir(dir_path) + elif page == "upload_files": + server_id = self.get_argument('id', None) + path = self.get_argument('path', None) + unzip = self.get_argument('unzip', None) + + if helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], path): + try: + files = self.request.files['files'] + for file in files: + if file['filename'].split('.') is not None: + self._upload_file(file['body'], path, file['filename'], unzip) + else: + logger.error("Directory Detected. Skipping") + self.redirect("/panel/server_detail?id={}&subpage=files".format(server_id)) + except Exception as e: + print(e) + self.redirect("/panel/server_detail?id={}&subpage=files".format(server_id)) + else: + logger.error("Invalid directory requested. Canceling upload") + + elif page == 'unzip_file': + print("in unzip file") + path = self.get_argument('path', None) + helper.unzipFile(path) + + def _upload_file(self, file_data, file_path, file_name, unzip): + error = "" + + file_full_path = os.path.join(file_path, file_name) + if os.path.exists(file_full_path): + error = "A file with this name already exists." + + if not helper.check_writeable(file_path): + error = "Unwritable Path" + + if error != "": + logger.error("Unable to save uploaded file due to: {}".format(error)) + return False + + output_file = open(file_full_path, 'wb') + output_file.write(file_data) + logger.info('Saving File: {}'.format(file_full_path)) + uploading = True + while uploading: + try: + new_output = open(file_full_path, 'wb') + new_output.close() + uploading = False + except: + print("file is still uploading") + if unzip == "True": + helper.unzipFile(file_full_path) + print("DONE") + return True + @tornado.web.authenticated def delete(self, page): if page == "del_file": diff --git a/app/frontend/templates/panel/server_files.html b/app/frontend/templates/panel/server_files.html index fe8501f9..10f97718 100644 --- a/app/frontend/templates/panel/server_files.html +++ b/app/frontend/templates/panel/server_files.html @@ -81,6 +81,8 @@ {{ translate('serverFiles', 'rename') }} {{ translate('serverFiles', 'delete') }} {{ translate('serverFiles', 'delete') }} + Upload Files + Unzip @@ -519,6 +521,39 @@ }); } + function unZip(path, callback) { + var token = getCookie("_xsrf") + $.ajax({ + type: "POST", + headers: {'X-XSRFToken': token}, + url: '/ajax/unzip_file?id={{ data['server_stats']['server_id']['server_id'] }}', + data: { + path: path + }, + }); + } + + function uploadFilesE(e){ + path = event.target.parentElement.getAttribute('data-path'); + server_id = {{ data['server_stats']['server_id']['server_id'] }}; + var uploadHtml = '
{% raw xsrf_form_html() %}
Would you like us Unzip directories?

'; + + bootbox.dialog({ + message: uploadHtml, + title: "Upload Files To "+path, + }); + + var fileList = document.getElementById("upload"); + fileList.addEventListener("change", function (e) { + var list = ""; + for (var i = 0; i < this.files.length; i++) { + list += "
"+this.files[i].name+"
"; + } + + $("#fileList").text(list); + }, false); +} + function getTreeView() { $.ajax({ type: "GET", @@ -572,6 +607,7 @@ $('#createFile').toggle(isDir); $('#createDir').toggle(isDir); $('#deleteDir').toggle(isDir); + $('#upload').toggle(isDir); var isFile = event.target.classList.contains('tree-file'); $('#deleteFile').toggle(isFile); @@ -583,6 +619,7 @@ $('#renameItem').hide(); $('#deleteDir').hide(); $('#deleteFile').hide(); + $('#upload').show(); } @@ -636,6 +673,10 @@ }); }) } + function unzipFilesE(event) { + path = event.target.parentElement.getAttribute('data-path'); + unZip(path) + } function deleteFileE(event) { path = event.target.parentElement.getAttribute('data-path'); From e08df4d369ee1fa577adfb861d9efad65c63afdf Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 19 Aug 2021 23:36:25 -0400 Subject: [PATCH 08/16] Completed file uploading. Need to fix listing when right clicking. Unzip is shown at all times. Added unzip function to helpers and is called through ajax for unzipping files to current directory. --- app/classes/shared/controller.py | 5 +- app/classes/shared/helpers.py | 18 +++--- app/classes/web/ajax_handler.py | 31 ++++------ .../templates/panel/server_files.html | 58 ++++++++++++++----- 4 files changed, 71 insertions(+), 41 deletions(-) diff --git a/app/classes/shared/controller.py b/app/classes/shared/controller.py index 26d0411f..a11e6fa5 100644 --- a/app/classes/shared/controller.py +++ b/app/classes/shared/controller.py @@ -286,7 +286,10 @@ class Controller: tempDir = tempfile.mkdtemp() with zipfile.ZipFile(zip_path, 'r') as zip_ref: zip_ref.extractall(tempDir) - test = zip_ref.filelist[1].filename + for i in range(len(zip_ref.filelist)): + if len(zip_ref.filelist) > 1 or not zip_ref.filelist[i].filename.endswith('/'): + test = zip_ref.filelist[i].filename + break path_list = test.split('/') root_path = path_list[0] if len(path_list) > 1: diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index beab8043..19e6504c 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -268,15 +268,16 @@ class Helpers: else: new_dir += '/'+new_dir_list[i] - if helper.check_file_perms(zip_path): + if helper.check_file_perms(zip_path) and os.path.isfile(zip_path): helper.ensure_dir_exists(new_dir) tempDir = tempfile.mkdtemp() - with zipfile.ZipFile(zip_path, 'r') as zip_ref: - zip_ref.extractall(tempDir) - for item in os.listdir(tempDir): - print(item) - test = zip_ref.filelist[1].filename - print(test) + try: + with zipfile.ZipFile(zip_path, 'r') as zip_ref: + zip_ref.extractall(tempDir) + for i in range(len(zip_ref.filelist)): + if len(zip_ref.filelist) > 1 or not zip_ref.filelist[i].filename.endswith('/'): + test = zip_ref.filelist[i].filename + break path_list = test.split('/') root_path = path_list[0] if len(path_list) > 1: @@ -290,8 +291,11 @@ class Helpers: shutil.move(os.path.join(full_root_path, item), os.path.join(new_dir, item)) except Exception as ex: logger.error('ERROR IN ZIP IMPORT: {}'.format(ex)) + except Exception as ex: + print(ex) else: return "false" + return def ensure_logging_setup(self): log_file = os.path.join(os.path.curdir, 'logs', 'commander.log') diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index d236186e..877c4ae3 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -189,32 +189,34 @@ class AjaxHandler(BaseHandler): # Create the directory os.mkdir(dir_path) + elif page == "unzip_file": + server_id = self.get_argument('id', None) + path = self.get_argument('path', None) + helper.unzipFile(path) + self.render_page("/panel/server_detail?id={}&subpage=files".format(server_id)) + return + + elif page == "upload_files": server_id = self.get_argument('id', None) path = self.get_argument('path', None) - unzip = self.get_argument('unzip', None) if helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], path): try: files = self.request.files['files'] for file in files: if file['filename'].split('.') is not None: - self._upload_file(file['body'], path, file['filename'], unzip) + self._upload_file(file['body'], path, file['filename']) else: logger.error("Directory Detected. Skipping") self.redirect("/panel/server_detail?id={}&subpage=files".format(server_id)) except Exception as e: - print(e) self.redirect("/panel/server_detail?id={}&subpage=files".format(server_id)) else: logger.error("Invalid directory requested. Canceling upload") + return - elif page == 'unzip_file': - print("in unzip file") - path = self.get_argument('path', None) - helper.unzipFile(path) - - def _upload_file(self, file_data, file_path, file_name, unzip): + def _upload_file(self, file_data, file_path, file_name): error = "" file_full_path = os.path.join(file_path, file_name) @@ -231,17 +233,6 @@ class AjaxHandler(BaseHandler): output_file = open(file_full_path, 'wb') output_file.write(file_data) logger.info('Saving File: {}'.format(file_full_path)) - uploading = True - while uploading: - try: - new_output = open(file_full_path, 'wb') - new_output.close() - uploading = False - except: - print("file is still uploading") - if unzip == "True": - helper.unzipFile(file_full_path) - print("DONE") return True @tornado.web.authenticated diff --git a/app/frontend/templates/panel/server_files.html b/app/frontend/templates/panel/server_files.html index 10f97718..810207c3 100644 --- a/app/frontend/templates/panel/server_files.html +++ b/app/frontend/templates/panel/server_files.html @@ -531,27 +531,59 @@ path: path }, }); + location.href="/ + } + function uploadFilesE(event){ + path = event.target.parentElement.getAttribute('data-path'); + console.log("PATH: " + path); + $(function () { + server_id = {{ data['server_stats']['server_id']['server_id'] }}; + var uploadHtml = "
" + + '
{% raw xsrf_form_html() %}'+"
" + + "
" + + "
    " + + "
    "; + + bootbox.dialog({ + message: uploadHtml, + title: "File Upload", + buttons: { + success: { + label: "Upload", + className: "btn-default", + callback: function () { + $('#upload_file').submit(); //.trigger('submit'); + } + } + } + }); + + var fileList = document.getElementById("files"); + fileList.addEventListener("change", function (e) { + var list = ""; + for (var i = 0; i < this.files.length; i++) { + list += "
  • " + this.files[i].name + "
  • " + } + + document.getElementById("fileList").innerHTML = list; + }, false); +}); } - function uploadFilesE(e){ + + function uploadFiles(e){ path = event.target.parentElement.getAttribute('data-path'); server_id = {{ data['server_stats']['server_id']['server_id'] }}; - var uploadHtml = '
    {% raw xsrf_form_html() %}
    Would you like us Unzip directories?

    '; - + var uploadHtml = '
    {% raw xsrf_form_html() %}
    '+"" +"
    " +""+'


    '; bootbox.dialog({ message: uploadHtml, title: "Upload Files To "+path, }); - - var fileList = document.getElementById("upload"); - fileList.addEventListener("change", function (e) { - var list = ""; - for (var i = 0; i < this.files.length; i++) { - list += "
    "+this.files[i].name+"
    "; - } - - $("#fileList").text(list); - }, false); } function getTreeView() { From f539f9e0954da66ed33a028e6ec7b09e62aaf3fb Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 19 Aug 2021 23:50:24 -0400 Subject: [PATCH 09/16] I leaned on my keyboard just before the last commit. Fixed the things --- app/classes/web/ajax_handler.py | 2 +- app/frontend/templates/panel/server_files.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index 877c4ae3..cbf7c9e6 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -193,7 +193,7 @@ class AjaxHandler(BaseHandler): server_id = self.get_argument('id', None) path = self.get_argument('path', None) helper.unzipFile(path) - self.render_page("/panel/server_detail?id={}&subpage=files".format(server_id)) + self.redirect("/panel/server_detail?id={}&subpage=files".format(server_id)) return diff --git a/app/frontend/templates/panel/server_files.html b/app/frontend/templates/panel/server_files.html index 810207c3..54eca51b 100644 --- a/app/frontend/templates/panel/server_files.html +++ b/app/frontend/templates/panel/server_files.html @@ -531,7 +531,7 @@ path: path }, }); - location.href="/ + window.location.href = "/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=files" } function uploadFilesE(event){ path = event.target.parentElement.getAttribute('data-path'); From bd51742b947c834569e6cc41d420f20c20dff5dd Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 20 Aug 2021 13:46:01 -0400 Subject: [PATCH 10/16] Added better context menu --- app/frontend/static/assets/css/crafty.css | 58 +++++++++++- .../static/assets/css/shared/style.css | 56 ++++++------ .../templates/panel/server_files.html | 90 +++++++++++-------- 3 files changed, 135 insertions(+), 69 deletions(-) diff --git a/app/frontend/static/assets/css/crafty.css b/app/frontend/static/assets/css/crafty.css index ea94ad5c..c0812602 100644 --- a/app/frontend/static/assets/css/crafty.css +++ b/app/frontend/static/assets/css/crafty.css @@ -79,4 +79,60 @@ body { background-color: var(--dark) !important; /* Firefox */ } .actions_serverlist > a > i { cursor: pointer; -} \ No newline at end of file +} + /* The Overlay (background) */ + .overlay { + /* Height & width depends on how you want to reveal the overlay (see JS below) */ + height: 0; + width: 100vw; + position: fixed; /* Stay in place */ + z-index: 1031; /* Sit on top */ + left: 0; + top: 0; + background-color: rgb(0,0,0); /* Black fallback color */ + background-color: rgba(0,0,0, 0.9); /* Black w/opacity */ + overflow-x: hidden; /* Disable horizontal scroll */ + transition: 0.5s; /* 0.5 second transition effect to slide in or slide down the overlay (height or width, depending on reveal) */ + } + + /* Position the content inside the overlay */ + .overlay-content { + position: relative; + top: 25%; /* 25% from the top */ + width: 100%; /* 100% width */ + text-align: center; /* Centered text/links */ + margin-top: 30px; /* 30px top margin to avoid conflict with the close button on smaller screens */ + } + + /* The navigation links inside the overlay */ + .overlay a { + padding: 8px; + text-decoration: none; + font-size: 36px; + color: #818181; + display: block; /* Display block instead of inline */ + transition: 0.3s; /* Transition effects on hover (color) */ + } + + /* When you mouse over the navigation links, change their color */ + .overlay a:hover, .overlay a:focus { + color: #f1f1f1; + } + + /* Position the close button (top right corner) */ + .overlay .closebtn { + position: absolute; + top: 20px; + right: 45px; + font-size: 60px; + } + + /* When the height of the screen is less than 450 pixels, change the font-size of the links and position the close button again, so they don't overlap */ + @media screen and (max-height: 450px) { + .overlay a {font-size: 20px} + .overlay .closebtn { + font-size: 40px; + top: 15px; + right: 35px; + } + } \ No newline at end of file diff --git a/app/frontend/static/assets/css/shared/style.css b/app/frontend/static/assets/css/shared/style.css index a7093450..35a40ab2 100755 --- a/app/frontend/static/assets/css/shared/style.css +++ b/app/frontend/static/assets/css/shared/style.css @@ -16188,41 +16188,35 @@ body.avgrund-active { border-radius: 2px; } /* Context Menu */ -.context-menu-icon:before { - color: #000; - font: normal normal normal 15px/1 "Material Design Icons"; } + .context-menu { + position: absolute; + text-align: center; + background: lightgray; + border: 1px solid black; + display: none; + } -.context-menu-icon.context-menu-icon-cut:before { - content: '\F190'; } + .context-menu ul { + padding: 0px; + margin: 0px; + min-width: 150px; + list-style: none; + } -.context-menu-icon.context-menu-icon-edit:before { - content: '\F3EF'; } + .context-menu ul li { + padding-bottom: 7px; + padding-top: 7px; + border: 1px solid black; + } -.context-menu-icon.context-menu-icon-copy:before { - content: '\F18F'; } - -.context-menu-icon.context-menu-icon-paste:before { - content: '\F613'; } - -.context-menu-icon.context-menu-icon-delete:before { - content: '\F6CB'; } - -.context-menu-icon.context-menu-icon-quit:before { - content: '\F156'; } - -.context-menu-list { - -webkit-box-shadow: none; - box-shadow: none; - border: 1px solid #dee2e6; } - .context-menu-list .context-menu-item span { - color: #000; - font-size: 0.75rem; - font-family: "roboto", sans-serif; } - .context-menu-list .context-menu-item.context-menu-hover { - background: #000; } - .context-menu-list .context-menu-item.context-menu-hover span { - color: #fff; } + .context-menu ul li a { + text-decoration: none; + color: black; + } + .context-menu ul li:hover { + background: darkgray; + } /* Clockpicker */ .clockpicker-popover { background-color: #dee2e6; } diff --git a/app/frontend/templates/panel/server_files.html b/app/frontend/templates/panel/server_files.html index 54eca51b..959b3004 100644 --- a/app/frontend/templates/panel/server_files.html +++ b/app/frontend/templates/panel/server_files.html @@ -72,7 +72,6 @@