From 0b3d20ffbeeb356e2500aadb79ab2e029acc4910 Mon Sep 17 00:00:00 2001 From: luukas Date: Fri, 26 Mar 2021 15:57:50 +0200 Subject: [PATCH] One monster truck commit for add translation API, add fi_FI and en_EN translations, add C and .properties file support, check if file is binary before sending and clean up ajax handler --- app/classes/shared/translation.py | 57 ++++ app/classes/web/ajax_handler.py | 185 ++++------- app/classes/web/base_handler.py | 3 +- app/classes/web/default_handler.py | 10 +- app/classes/web/panel_handler.py | 6 +- app/classes/web/public_handler.py | 6 +- app/classes/web/server_handler.py | 6 +- app/classes/web/tornado.py | 3 +- app/classes/web/websocket_handler.py | 3 +- app/frontend/templates/base.html | 20 +- app/frontend/templates/footer.html | 4 +- app/frontend/templates/main_menu.html | 23 +- app/frontend/templates/panel/dashboard.html | 78 ++--- app/frontend/templates/panel/denied.html | 9 +- .../templates/panel/parts/details_stats.html | 28 +- .../panel/server_admin_controls.html | 24 +- .../templates/panel/server_backup.html | 64 ++-- .../templates/panel/server_config.html | 86 +++-- .../templates/panel/server_files.html | 97 +++--- app/frontend/templates/panel/server_logs.html | 18 +- app/frontend/templates/panel/server_term.html | 30 +- app/frontend/templates/public/404.html | 6 +- app/frontend/templates/public/error.html | 11 +- app/frontend/templates/public/login.html | 12 +- app/frontend/templates/server/wizard.html | 169 +++++----- app/translations/en_EN.json | 287 ++++++++++++++++ app/translations/fi_FI.json | 311 ++++++++++++++++++ 27 files changed, 1088 insertions(+), 468 deletions(-) create mode 100644 app/classes/shared/translation.py create mode 100644 app/translations/en_EN.json create mode 100644 app/translations/fi_FI.json diff --git a/app/classes/shared/translation.py b/app/classes/shared/translation.py new file mode 100644 index 00000000..76d44aaa --- /dev/null +++ b/app/classes/shared/translation.py @@ -0,0 +1,57 @@ +from app.classes.shared.helpers import helper +from app.classes.shared.console import console + +import os +import json + +import logging + +logger = logging.getLogger(__name__) + +class Translation(): + def __init__(self): + self.translations_path = os.path.join(helper.root_dir, 'app', 'translations') + def translate(self, page, word): + translated_word = None + lang = helper.get_setting('language') + fallback_lang = 'en_EN' + + translated_word = \ + self.translate_inner(page, word, lang) or \ + self.translate_inner(page, word, fallback_lang) + + if translated_word: + if isinstance(translated_word, dict): return json.dumps(translated_word) + elif iter(translated_word) and not isinstance(translated_word, str): return '\n'.join(translated_word) + return translated_word + return 'Error while getting translation' + def translate_inner(self, page, word, lang): + lang_file = os.path.join( + self.translations_path, + lang + '.json' + ) + try: + with open(lang_file, 'r') as f: + data = json.load(f) + + try: + translated_page = data[page] + except KeyError: + logger.error('Translation File Error: page {} does not exist for lang {}'.format(page, lang)) + console.error('Translation File Error: page {} does not exist for lang {}'.format(page, lang)) + return None + + try: + translated_word = translated_page[word] + return translated_word + except KeyError: + logger.error('Translation File Error: word {} does not exist on page {} for lang {}'.format(word, page, lang)) + console.error('Translation File Error: word {} does not exist on page {} for lang {}'.format(word, page, lang)) + return None + + except Exception as e: + logger.critical('Translation File Error: Unable to read {} due to {}'.format(lang_file, e)) + console.critical('Translation File Error: Unable to read {} due to {}'.format(lang_file, e)) + return None + +translation = Translation() \ No newline at end of file diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index 59712bac..0796527e 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -20,7 +20,8 @@ class AjaxHandler(BaseHandler): def render_page(self, template, page_data): self.render( template, - data=page_data + data=page_data, + translate=self.translator.translate, ) @tornado.web.authenticated @@ -84,47 +85,36 @@ class AjaxHandler(BaseHandler): file_path = self.get_argument('file_path', None) server_id = self.get_argument('id', None) - if server_id is None: - logger.warning("Server ID not found in get_file ajax call") - console.warning("Server ID not found in get_file ajax call") - return False - else: - server_id = bleach.clean(server_id) - - # does this server id exist? - if not db_helper.server_id_exists(server_id): - logger.warning("Server ID not found in get_file ajax call ({})".format(server_id)) - console.warning("Server ID not found in get_file ajax call ({})".format(server_id)) - return False + if not self.check_server_id(server_id, 'get_file'): return False + else: server_id = bleach.clean(server_id) if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], file_path)\ - or not helper.check_file_exists(os.path.abspath(file_path)): + or not helper.check_file_exists(os.path.abspath(file_path)): logger.warning("Invalid path in get_file ajax call ({})".format(file_path)) console.warning("Invalid path in get_file ajax call ({})".format(file_path)) return False + + + error = None + + try: + with open(file_path) as file: + file_contents = file.read() + except UnicodeDecodeError: + file_contents = '' + error = 'UnicodeDecodeError' - file = open(file_path) - file_contents = file.read() - file.close() - - self.write(file_contents) + self.write({ + 'content': file_contents, + 'error': error + }) self.finish() elif page == "get_tree": server_id = self.get_argument('id', None) - if server_id is None: - logger.warning("Server ID not found in get_file ajax call") - console.warning("Server ID not found in get_file ajax call") - return False - else: - server_id = bleach.clean(server_id) - - # does this server id exist? - if not db_helper.server_id_exists(server_id): - logger.warning("Server ID not found in get_file ajax call ({})".format(server_id)) - console.warning("Server ID not found in get_file ajax call ({})".format(server_id)) - return False + if not self.check_server_id(server_id, 'get_tree'): return False + else: server_id = bleach.clean(server_id) self.write(db_helper.get_server_data_by_id(server_id)['path'] + '\n' + helper.generate_tree(db_helper.get_server_data_by_id(server_id)['path'])) @@ -161,21 +151,11 @@ class AjaxHandler(BaseHandler): server_id = self.get_argument('id', None) print(server_id) - if server_id is None: - logger.warning("Server ID not found in create_file ajax call") - console.warning("Server ID not found in create_file ajax call") - return False - else: - server_id = bleach.clean(server_id) - - # does this server id exist? - if not db_helper.server_id_exists(server_id): - logger.warning("Server ID not found in create_file ajax call ({})".format(server_id)) - console.warning("Server ID not found in create_file ajax call ({})".format(server_id)) - return False + if not self.check_server_id(server_id, 'create_file'): return False + else: server_id = bleach.clean(server_id) if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], file_path) \ - or helper.check_file_exists(os.path.abspath(file_path)): + or helper.check_file_exists(os.path.abspath(file_path)): logger.warning("Invalid path in create_file ajax call ({})".format(file_path)) console.warning("Invalid path in create_file ajax call ({})".format(file_path)) return False @@ -191,21 +171,11 @@ class AjaxHandler(BaseHandler): server_id = self.get_argument('id', None) print(server_id) - if server_id is None: - logger.warning("Server ID not found in create_dir ajax call") - console.warning("Server ID not found in create_dir ajax call") - return False - else: - server_id = bleach.clean(server_id) - - # does this server id exist? - if not db_helper.server_id_exists(server_id): - logger.warning("Server ID not found in create_dir ajax call ({})".format(server_id)) - console.warning("Server ID not found in create_dir ajax call ({})".format(server_id)) - return False + if not self.check_server_id(server_id, 'create_dir'): return False + else: server_id = bleach.clean(server_id) if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], dir_path) \ - or helper.check_path_exists(os.path.abspath(dir_path)): + or helper.check_path_exists(os.path.abspath(dir_path)): 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 False @@ -219,23 +189,15 @@ class AjaxHandler(BaseHandler): file_path = self.get_body_argument('file_path', default=None, strip=True) server_id = self.get_argument('id', None) - if server_id is None: - logger.warning("Server ID not found in del_file ajax call") - console.warning("Server ID not found in del_file ajax call") - return False - else: - server_id = bleach.clean(server_id) + console.warning("delete {} for server {}".format(file_path, server_id)) - # does this server id exist? - if not db_helper.server_id_exists(server_id): - logger.warning("Server ID not found in del_file ajax call ({})".format(server_id)) - console.warning("Server ID not found in del_file ajax call ({})".format(server_id)) - return False + if not self.check_server_id(server_id, 'del_file'): return False + else: server_id = bleach.clean(server_id) server_info = db_helper.get_server_data_by_id(server_id) - if not helper.in_path(server_info['path'], file_path) \ - or not helper.in_path(server_info['backup_path'], file_path) \ - or not helper.check_file_exists(os.path.abspath(file_path)): + if not (helper.in_path(server_info['path'], file_path) \ + or helper.in_path(server_info['backup_path'], file_path)) \ + or not helper.check_file_exists(os.path.abspath(file_path)): logger.warning("Invalid path in del_file ajax call ({})".format(file_path)) console.warning("Invalid path in del_file ajax call ({})".format(file_path)) return False @@ -248,29 +210,20 @@ class AjaxHandler(BaseHandler): server_id = self.get_argument('id', None) print(server_id) - if server_id is None: - logger.warning("Server ID not found in del_file ajax call") - console.warning("Server ID not found in del_file ajax call") - return False - else: - server_id = bleach.clean(server_id) + console.warning("delete {} for server {}".format(file_path, server_id)) - # does this server id exist? - if not db_helper.server_id_exists(server_id): - logger.warning("Server ID not found in del_file ajax call ({})".format(server_id)) - console.warning("Server ID not found in del_file ajax call ({})".format(server_id)) - return False + if not self.check_server_id(server_id, 'del_dir'): return False + else: server_id = bleach.clean(server_id) server_info = db_helper.get_server_data_by_id(server_id) if not helper.in_path(server_info['path'], dir_path) \ - or not helper.in_path(server_info['backup_path'], dir_path) \ - or not helper.check_path_exists(os.path.abspath(dir_path)): + or not helper.check_path_exists(os.path.abspath(dir_path)): logger.warning("Invalid path in del_file ajax call ({})".format(dir_path)) console.warning("Invalid path in del_file ajax call ({})".format(dir_path)) return False - # Delete the file - # os.rmdir(dir_path) + # Delete the directory + # os.rmdir(dir_path) # Would only remove empty directories shutil.rmtree(dir_path) # Removes also when there are contents @tornado.web.authenticated @@ -283,21 +236,11 @@ class AjaxHandler(BaseHandler): print(file_path) print(server_id) - if server_id is None: - logger.warning("Server ID not found in save_file ajax call") - console.warning("Server ID not found in save_file ajax call") - return False - else: - server_id = bleach.clean(server_id) - - # does this server id exist? - if not db_helper.server_id_exists(server_id): - logger.warning("Server ID not found in save_file ajax call ({})".format(server_id)) - console.warning("Server ID not found in save_file ajax call ({})".format(server_id)) - return False + if not self.check_server_id(server_id, 'save_file'): return False + else: server_id = bleach.clean(server_id) if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], file_path)\ - or not helper.check_file_exists(os.path.abspath(file_path)): + or not helper.check_file_exists(os.path.abspath(file_path)): logger.warning("Invalid path in save_file ajax call ({})".format(file_path)) console.warning("Invalid path in save_file ajax call ({})".format(file_path)) return False @@ -312,37 +255,41 @@ class AjaxHandler(BaseHandler): server_id = self.get_argument('id', None) print(server_id) - if server_id is None: - logger.warning("Server ID not found in rename_item ajax call ({})".format(server_id)) - console.warning("Server ID not found in rename_item ajax call ({})".format(server_id)) - return False - else: - server_id = bleach.clean(server_id) - - # does this server id exist? - if not db_helper.server_id_exists(server_id): - logger.warning("Server ID not found in rename_item ajax call ({})".format(server_id)) - console.warning("Server ID not found in rename_item ajax call ({})".format(server_id)) - return False + if not self.check_server_id(server_id, 'rename_item'): return False + else: server_id = bleach.clean(server_id) if item_path is None or new_item_name is None: - logger.warning("Invalid path in rename_item ajax call") - console.warning("Invalid path in rename_item ajax call") + logger.warning("Invalid path(s) in rename_item ajax call") + console.warning("Invalid path(s) in rename_item ajax call") return False if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], item_path) \ - or not helper.check_path_exists(os.path.abspath(item_path)): - logger.warning("Invalid path in rename_item ajax call ({})".format(server_id)) - console.warning("Invalid path in rename_item ajax call ({})".format(server_id)) + or not helper.check_path_exists(os.path.abspath(item_path)): + logger.warning("Invalid old name path in rename_item ajax call ({})".format(server_id)) + console.warning("Invalid old name path in rename_item ajax call ({})".format(server_id)) return False new_item_path = os.path.join(os.path.split(item_path)[0], new_item_name) if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], new_item_path) \ - or helper.check_path_exists(os.path.abspath(new_item_path)): - logger.warning("Invalid path 2 in rename_item ajax call ({})".format(server_id)) - console.warning("Invalid path 2 in rename_item ajax call ({})".format(server_id)) + or helper.check_path_exists(os.path.abspath(new_item_path)): + logger.warning("Invalid new name path in rename_item ajax call ({})".format(server_id)) + console.warning("Invalid new name path in rename_item ajax call ({})".format(server_id)) return False # RENAME os.rename(item_path, new_item_path) + def check_server_id(self, server_id, page_name): + if server_id is None: + logger.warning("Server ID not defined in {} ajax call ({})".format(page_name, server_id)) + console.warning("Server ID not defined in {} ajax call ({})".format(page_name, server_id)) + return False + else: + server_id = bleach.clean(server_id) + + # does this server id exist? + if not db_helper.server_id_exists(server_id): + logger.warning("Server ID not found in {} ajax call ({})".format(page_name, server_id)) + console.warning("Server ID not found in {} ajax call ({})".format(page_name, server_id)) + return False + return True diff --git a/app/classes/web/base_handler.py b/app/classes/web/base_handler.py index 5c715b66..e578cd17 100644 --- a/app/classes/web/base_handler.py +++ b/app/classes/web/base_handler.py @@ -12,9 +12,10 @@ logger = logging.getLogger(__name__) class BaseHandler(tornado.web.RequestHandler): - def initialize(self, controller=None, tasks_manager=None): + def initialize(self, controller=None, tasks_manager=None, translator=None): self.controller = controller self.tasks_manager = tasks_manager + self.translator = translator def get_remote_ip(self): remote_ip = self.request.headers.get("X-Real-IP") or \ diff --git a/app/classes/web/default_handler.py b/app/classes/web/default_handler.py index 45515c47..ebb53694 100644 --- a/app/classes/web/default_handler.py +++ b/app/classes/web/default_handler.py @@ -11,7 +11,13 @@ class DefaultHandler(BaseHandler): def prepare(self, page=None): if page is not None: self.set_status(404) - self.render("public/404.html") + self.render( + "public/404.html", + translate=self.translator.translate, + ) else: - self.redirect("/public/login") + self.redirect( + "/public/login", + translate=self.translator.translate, + ) diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index 0a004fe7..082eb163 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -399,6 +399,7 @@ class PanelHandler(BaseHandler): data=page_data, time=time, utc_offset=(time.timezone * -1 / 60 / 60), + translate=self.translator.translate, ) @tornado.web.authenticated @@ -705,4 +706,7 @@ class PanelHandler(BaseHandler): else: self.set_status(404) - self.render("public/404.html") + self.render( + "public/404.html", + translate=self.translator.translate, + ) diff --git a/app/classes/web/public_handler.py b/app/classes/web/public_handler.py index 7f968677..7988138d 100644 --- a/app/classes/web/public_handler.py +++ b/app/classes/web/public_handler.py @@ -63,7 +63,11 @@ class PublicHandler(BaseHandler): else: self.redirect('/public/login') - self.render(template, data=page_data) + self.render( + template, + data=page_data, + translate=self.translator.translate, + ) def post(self, page=None): diff --git a/app/classes/web/server_handler.py b/app/classes/web/server_handler.py index f34ba033..9f882f93 100644 --- a/app/classes/web/server_handler.py +++ b/app/classes/web/server_handler.py @@ -69,7 +69,8 @@ class ServerHandler(BaseHandler): self.render( template, - data=page_data + data=page_data, + translate=self.translator.translate, ) @tornado.web.authenticated @@ -197,5 +198,6 @@ class ServerHandler(BaseHandler): self.render( template, - data=page_data + data=page_data, + translate=self.translator.translate, ) \ No newline at end of file diff --git a/app/classes/web/tornado.py b/app/classes/web/tornado.py index 096dd746..ceb2a12f 100644 --- a/app/classes/web/tornado.py +++ b/app/classes/web/tornado.py @@ -25,6 +25,7 @@ try: from app.classes.web.ajax_handler import AjaxHandler from app.classes.web.api_handler import ServersStats, NodeStats from app.classes.web.websocket_handler import SocketHandler + from app.classes.shared.translation import translation except ModuleNotFoundError as e: logger.critical("Import Error: Unable to load {} module".format(e, e.name)) @@ -120,7 +121,7 @@ class Webserver: tornado.locale.set_default_locale(lang) - handler_args = {"controller": self.controller, "tasks_manager": self.tasks_manager} + handler_args = {"controller": self.controller, "tasks_manager": self.tasks_manager, "translator": translation} handlers = [ (r'/', DefaultHandler, handler_args), (r'/public/(.*)', PublicHandler, handler_args), diff --git a/app/classes/web/websocket_handler.py b/app/classes/web/websocket_handler.py index a33707f6..150a955b 100644 --- a/app/classes/web/websocket_handler.py +++ b/app/classes/web/websocket_handler.py @@ -8,9 +8,10 @@ from app.classes.web.websocket_helper import websocket_helper class SocketHandler(tornado.websocket.WebSocketHandler): - def initialize(self, controller=None, tasks_manager=None): + def initialize(self, controller=None, tasks_manager=None, translator=None): self.controller = controller self.tasks_manager = tasks_manager + self.translator = translator def get_remote_ip(self): remote_ip = self.request.headers.get("X-Real-IP") or \ diff --git a/app/frontend/templates/base.html b/app/frontend/templates/base.html index 8b6e3ab4..2a780c64 100644 --- a/app/frontend/templates/base.html +++ b/app/frontend/templates/base.html @@ -59,9 +59,9 @@
-
-
Warning: Crafty doesn't work properly when JavaScript isn't enabled!
-
+
{% block content %} @@ -138,7 +138,9 @@