From c89609ae61b74210c300fd6a35896dbca1d1be7b Mon Sep 17 00:00:00 2001 From: Andrew <mcdeweykp@gmail.com> Date: Thu, 10 Feb 2022 15:27:40 -0500 Subject: [PATCH] Inital bedrock support --- app/classes/controllers/servers_controller.py | 2 + app/classes/minecraft/mc_ping.py | 8 +- app/classes/shared/main_controller.py | 100 +++- app/classes/web/server_handler.py | 9 + .../templates/server/bedrock_wizard.html | 551 ++++++++++++++++++ app/frontend/templates/server/wizard.html | 11 + 6 files changed, 675 insertions(+), 6 deletions(-) create mode 100644 app/frontend/templates/server/bedrock_wizard.html diff --git a/app/classes/controllers/servers_controller.py b/app/classes/controllers/servers_controller.py index 0e0599c5..bc5475f3 100644 --- a/app/classes/controllers/servers_controller.py +++ b/app/classes/controllers/servers_controller.py @@ -28,6 +28,7 @@ class Servers_Controller: server_file: str, server_log_file: str, server_stop: str, + server_type: str, server_port=25565): return servers_helper.create_server( name, @@ -38,6 +39,7 @@ class Servers_Controller: server_file, server_log_file, server_stop, + server_type, server_port) @staticmethod diff --git a/app/classes/minecraft/mc_ping.py b/app/classes/minecraft/mc_ping.py index 52d3cdec..3f1d34db 100644 --- a/app/classes/minecraft/mc_ping.py +++ b/app/classes/minecraft/mc_ping.py @@ -133,7 +133,13 @@ def ping(ip, port): sock.connect((ip, port)) except socket.error: - return False + #We'll try gathering this data on a UDP port next + try: + sock =socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.connect((ip, port)) + #If the udp port fails as well we're toast. :sadcat: + except socket.error: + return False try: host = ip.encode('utf-8') diff --git a/app/classes/shared/main_controller.py b/app/classes/shared/main_controller.py index c03ffb1a..cd7904e5 100644 --- a/app/classes/shared/main_controller.py +++ b/app/classes/shared/main_controller.py @@ -7,6 +7,7 @@ import tempfile from distutils import dir_util from typing import Union from peewee import DoesNotExist +import platform from app.classes.controllers.crafty_perms_controller import Crafty_Perms_Controller from app.classes.controllers.management_controller import Management_Controller @@ -158,6 +159,7 @@ class Controller: logger.warning(f"Failed to copy file with error: {e}") #Copy crafty logs to archive dir full_log_name = os.path.join(crafty_path, 'logs') + print(self.project_root) shutil.copytree(os.path.join(self.project_root, 'logs'), full_log_name) shutil.make_archive(tempZipStorage, "zip", tempDir) @@ -295,7 +297,7 @@ class Controller: # download the jar server_jar_obj.download_jar(server, version, full_jar_path) - new_id = self.register_server(name, server_id, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, port) + new_id = self.register_server(name, server_id, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, port, type='minecraft-java') return new_id @staticmethod @@ -351,7 +353,7 @@ class Controller: server_stop = "stop" new_id = self.register_server(server_name, server_id, new_server_dir, backup_path, server_command, server_jar, - server_log_file, server_stop, port) + server_log_file, server_stop, port, server_type='minecraft-java') return new_id def import_zip_server(self, server_name: str, zip_path: str, server_jar: str, min_mem: int, max_mem: int, port: int): @@ -394,9 +396,96 @@ class Controller: server_stop = "stop" new_id = self.register_server(server_name, server_id, new_server_dir, backup_path, server_command, server_jar, - server_log_file, server_stop, port) + server_log_file, server_stop, port, type='minecraft-java') return new_id +#---------------------------------------------------BEDROCK IMPORTS--------------------------------------------------- + + def import_bedrock_server(self, server_name: str, server_path: str, server_exe: str, port: int): + server_id = helper.create_uuid() + new_server_dir = os.path.join(helper.servers_dir, server_id) + backup_path = os.path.join(helper.backup_path, server_id) + if helper.is_os_windows(): + new_server_dir = helper.wtol_path(new_server_dir) + backup_path = helper.wtol_path(backup_path) + new_server_dir.replace(' ', '^ ') + backup_path.replace(' ', '^ ') + + helper.ensure_dir_exists(new_server_dir) + helper.ensure_dir_exists(backup_path) + server_path = helper.get_os_understandable_path(server_path) + dir_util.copy_tree(server_path, new_server_dir) + + has_properties = False + for item in os.listdir(new_server_dir): + if str(item) == 'server.properties': + has_properties = True + if not has_properties: + logger.info(f"No server.properties found on zip file import. Creating one with port selection of {str(port)}") + with open(os.path.join(new_server_dir, "server.properties"), "w", encoding='utf-8') as f: + f.write(f"server-port={port}") + f.close() + + full_jar_path = os.path.join(new_server_dir, server_exe) + + #due to adding strings this must not be an fstring + if helper.is_os_windows(): + server_command = f'"{full_jar_path}"' + else: + server_command = f'LD_LIBRARY_PATH=. .{full_jar_path}' + logger.debug('command: ' + server_command) + server_log_file = "N/A" + server_stop = "stop" + + new_id = self.register_server(server_name, server_id, new_server_dir, backup_path, server_command, server_exe, + server_log_file, server_stop, port, server_type='minecraft-bedrock') + return new_id + + def import_bedrock_zip_server(self, server_name: str, zip_path: str, server_exe: str, port: int): + server_id = helper.create_uuid() + new_server_dir = os.path.join(helper.servers_dir, server_id) + backup_path = os.path.join(helper.backup_path, server_id) + if helper.is_os_windows(): + new_server_dir = helper.wtol_path(new_server_dir) + backup_path = helper.wtol_path(backup_path) + new_server_dir.replace(' ', '^ ') + backup_path.replace(' ', '^ ') + + tempDir = helper.get_os_understandable_path(zip_path) + helper.ensure_dir_exists(new_server_dir) + helper.ensure_dir_exists(backup_path) + has_properties = False + #extracts archive to temp directory + for item in os.listdir(tempDir): + if str(item) == 'server.properties': + has_properties = True + try: + shutil.move(os.path.join(tempDir, item), os.path.join(new_server_dir, item)) + except Exception as ex: + logger.error(f'ERROR IN ZIP IMPORT: {ex}') + if not has_properties: + logger.info(f"No server.properties found on zip file import. Creating one with port selection of {str(port)}") + with open(os.path.join(new_server_dir, "server.properties"), "w", encoding='utf-8') as f: + f.write(f"server-port={port}") + f.close() + + full_jar_path = os.path.join(new_server_dir, server_exe) + + #due to strings being added we need to leave this as not an fstring + if helper.is_os_windows(): + server_command = f'"{full_jar_path}"' + else: + server_command = f'LD_LIBRARY_PATH=. .{full_jar_path}' + logger.debug('command: ' + server_command) + server_log_file = "N/A" + server_stop = "stop" + + new_id = self.register_server(server_name, server_id, new_server_dir, backup_path, server_command, server_exe, + server_log_file, server_stop, port, server_type='minecraft-bedrock') + return new_id + +#---------------------------------------------------END BEDROCK IMPORTS--------------------------------------------------- + def rename_backup_dir(self, old_server_id, new_server_id, new_uuid): server_data = self.servers.get_server_data_by_id(old_server_id) old_bu_path = server_data['backup_path'] @@ -421,11 +510,12 @@ class Controller: server_file: str, server_log_file: str, server_stop: str, - server_port: int): + server_port: int, + server_type: str): # put data in the db new_id = self.servers.create_server( - name, server_uuid, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, server_port) + name, server_uuid, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, server_type, server_port) if not helper.check_file_exists(os.path.join(server_dir, "crafty_managed.txt")): try: diff --git a/app/classes/web/server_handler.py b/app/classes/web/server_handler.py index a734dd1f..618c03e4 100644 --- a/app/classes/web/server_handler.py +++ b/app/classes/web/server_handler.py @@ -113,6 +113,13 @@ class ServerHandler(BaseHandler): page_data['js_server_types'] = json.dumps(server_jar_obj.get_serverjar_data()) template = "server/wizard.html" + if page == "bedrock_step1": + if not superuser and not self.controller.crafty_perms.can_create_server(exec_user["user_id"]): + self.redirect("/panel/error?error=Unauthorized access: not a server creator or server limit reached") + return + + template = "server/bedrock_wizard.html" + self.render( template, data=page_data, @@ -170,6 +177,7 @@ class ServerHandler(BaseHandler): new_executable = server_data.get('executable') new_server_log_file = str(helper.get_os_understandable_path(server_data.get('log_path'))).replace(server_uuid, new_server_uuid) server_port = server_data.get('server_port') + server_type = server_data.get('server_type') self.controller.servers.create_server(new_server_name, new_server_uuid, @@ -179,6 +187,7 @@ class ServerHandler(BaseHandler): new_executable, new_server_log_file, stop_command, + server_type, server_port) self.controller.init_all_servers() diff --git a/app/frontend/templates/server/bedrock_wizard.html b/app/frontend/templates/server/bedrock_wizard.html new file mode 100644 index 00000000..6ea12c6d --- /dev/null +++ b/app/frontend/templates/server/bedrock_wizard.html @@ -0,0 +1,551 @@ +{% extends ../base.html %} + +{% block title %}Crafty Controller - {{ translate('serverWizard', 'newServer', data['lang']) }}{% end %} + +{% block content %} + +<div class="content-wrapper"> + <ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist"> + <li class="nav-item term-nav-item"> + <a class="nav-link" href="/server/step1" role="tab" aria-selected="false"> + <i class="fas fa-file-signature"></i>Minecraft-Java</a> + </li> + <li class="nav-item term-nav-item"> + <a class="nav-link active" href="/server/bedrock_step1" role="tab" aria-selected="false"> + <i class="fas fa-file-signature"></i>Minecraft-Bedrock</a> + </li> +</ul> +<br> +<div class="d-none" id="overlay" onclick="hide(event)"></div> + <div class="row"> + <div class="col-sm-6 grid-margin stretch-card"> + <div class="card"> + <div class="card-body"> + + <h4>{{ translate('serverWizard', 'importServer', data['lang']) }}</h4> + <br /> + <p class="card-description"> + + <form method="post" class="server-wizard" onSubmit="wait_msg(true)"> + {% raw xsrf_form_html() %} + <input type="hidden" value="import_jar" name="create_type"> + <div class="row"> + + <div class="col-sm-12"> + <div class="form-group"> + <label for="server_name">{{ translate('serverWizard', 'serverName', data['lang']) }}</label> + <input type="text" class="form-control" id="server_name" name="server_name" value="" placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required> + </div> + </div> + + <div class="col-sm-12"> + <div class="form-group"> + <label for="server">{{ translate('serverWizard', 'serverPath', data['lang']) }} <small>{{ translate('serverWizard', 'absoluteServerPath', data['lang']) }}</small></label> + <input type="text" class="form-control" id="server_path" name="server_path" placeholder="/var/opt/server" required> + </div> + </div> + + <div class="col-sm-12"> + <div class="form-group"> + <label for="server_jar">{{ translate('serverWizard', 'serverJar', data['lang']) }}</label> + <input type="text" class="form-control" id="server_jar" name="server_jar" value="" placeholder="paper.jar" required> + </div> + </div> + + + + </div> + <br /> + <h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription', data['lang']) }}</small></h4> + <hr> + <div class="row"> + + <div class="col-sm-3"> + <div class="form-group"> + <label for="min_memory2">{{ translate('serverWizard', 'minMem', data['lang']) }} <small> - {{ translate('serverWizard', 'sizeInGB', data['lang']) }}</small></label> + <input type="number" class="form-control" id="min_memory2" name="min_memory" value="1" step="0.5" min="0.5" required> + </div> + </div> + + <div class="col-sm-3 offset-1"> + <div class="form-group"> + <label for="max_memory2">{{ translate('serverWizard', 'maxMem', data['lang']) }} <small> - {{ translate('serverWizard', 'sizeInGB', data['lang']) }}</small></label> + <input type="number" class="form-control" id="max_memory2" name="max_memory" value="2" step="0.5" min="0.5" required> + </div> + </div> + + <div class="col-sm-3 offset-1"> + <div class="form-group"> + <label for="port2">{{ translate('serverWizard', 'serverPort', data['lang']) }} <small> - {{ translate('serverWizard', 'defaultPort', data['lang']) }}</small></label> + <input type="number" class="form-control" id="port2" name="port" value="25565" step="1" min="1" required> + </div> + </div> + <div class="col-sm-12"> + <div class="form-group"> + <div id="accordion-2"> + <div class="card"> + <div class="card-header p-2" id="Role-2"> + <p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-2" aria-expanded="true" aria-controls="collapseRole-2"> + <i class="fas fa-chevron-down"></i> {{ translate('serverWizard', 'addRole', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'autoCreate', data['lang']) }}</small> + </p> + </div> + <div id="collapseRole-2" class="collapse" aria-labelledby="Role-2" data-parent=""> + <div class="card-body scroll"> + <div class="form-group"> + {% for r in data['roles'] %} + <span class="d-block menu-option"><label><input name="{{ r['role_id'] }}" type="checkbox"> + {{ r['role_name'].capitalize() }}</label></span> + {% end %} + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + <button type="submit" class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton', data['lang']) }}</button> + <button type="reset" class="btn btn-danger mr-2">{{ translate('serverWizard', 'resetForm', data['lang']) }}</button> + + </form> + </p> + </div> + </div> + </div> + </div> + <div class="col-sm-13 grid-margin stretch-card"> + <div class="card"> + <div class="card-body"> + + <h4>{{ translate('serverWizard', 'importZip', data['lang']) }}</h4> + <br /> + <p class="card-description"> + + <form name="zip" method="post" class="server-wizard" onSubmit="wait_msg(true)"> + {% raw xsrf_form_html() %} + <input type="hidden" value="import_zip" name="create_type"> + + <div class="row"> + <div class="col-sm-9"> + <div class="col-sm-12"> + <div class="form-group"> + <label for="server_name">{{ translate('serverWizard', 'serverName', data['lang']) }}</label> + <input type="text" class="form-control" id="server_name" name="server_name" value="" placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required> + </div> + </div> + + <div class="col-sm-12"> + <div class="form-group"> + <label for="server">{{ translate('serverWizard', 'zipPath', data['lang']) }} <small>{{ translate('serverWizard', 'absoluteZipPath', data['lang']) }}</small></label> + <input type="text" class="form-control" id="server_path" name="server_path" placeholder="/var/opt/server.zip" required> + </div> + </div> + + <div class="col-sm-12"> + <div class="form-group"> + <label for="server">{{ translate('serverWizard', 'selectRoot', data['lang']) }} <small>{{ translate('serverWizard', 'explainRoot', data['lang']) }}</small></label> + <br> + <button class="btn btn-primary mr-2" id="root_files_button" type="button">{{ translate('serverWizard', 'clickRoot', data['lang']) }}</button> + </div> + </div> + + + <div class="col-sm-12"> + <div class="form-group"> + <label for="server_jar">{{ translate('serverWizard', 'serverJar', data['lang']) }}</label> + <input type="text" class="form-control" id="server_jar" name="server_jar" value="" placeholder="paper.jar" required> + </div> + </div> + </div> + + + + <div class="col-sm-3"> + <h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription', data['lang']) }}</small></h4> + <hr> + <div class="row"> + + <div class="col-sm-12"> + <div class="form-group"> + <label for="min_memory3">{{ translate('serverWizard', 'minMem', data['lang']) }} <small> - {{ translate('serverWizard', 'sizeInGB', data['lang']) }}</small></label> + <input type="number" class="form-control" id="min_memory3" name="min_memory" value="1" step="0.5" min="0.5" required> + </div> + </div> + + <div class="col-sm-12"> + <div class="form-group"> + <label for="max_memory3">{{ translate('serverWizard', 'maxMem', data['lang']) }} <small> - {{ translate('serverWizard', 'sizeInGB', data['lang']) }}</small></label> + <input type="number" class="form-control" id="max_memory3" name="max_memory" value="2" step="0.5" min="0.5" required> + </div> + </div> + + <div class="col-sm-12"> + <div class="form-group"> + <label for="port3">{{ translate('serverWizard', 'serverPort', data['lang']) }} <small> - {{ translate('serverWizard', 'defaultPort', data['lang']) }}</small></label> + <input type="number" class="form-control" id="port3" name="port" value="25565" step="1" min="1" required> + </div> + </div> + + <div class="col-sm-12"> + <div class="form-group"> + <div id="accordion-3"> + <div class="card"> + <div class="card-header p-2" id="Role-3"> + <p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-3" aria-expanded="true" aria-controls="collapseRole-3"> + <i class="fas fa-chevron-down"></i> {{ translate('serverWizard', 'addRole', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'autoCreate', data['lang']) }}</small> + </p> + </div> + <div id="collapseRole-3" class="collapse" aria-labelledby="Role-3" data-parent=""> + <div class="card-body scroll"> + <div class="form-group"> + {% for r in data['roles'] %} + <span class="d-block menu-option"><label><input name="{{ r['role_id'] }}" type="checkbox"> + {{ r['role_name'].capitalize() }}</label></span> + {% end %} + </div> + </div> + </div> + </div> + </div> + </div> + </div> + <div class="col-sm-12" style="visibility: hidden;"> + <div class="form-group"> + <input type="text" class="form-control" id="zip_root_path" name="zip_root_path"> + </div> + </div> + <div class="modal fade" id="dir_select" tabindex="-1" role="dialog" aria-labelledby="dir_select" aria-hidden="true"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h5 class="modal-title" id="exampleModalLongTitle">{{ translate('serverWizard', 'selectZipDir', data['lang']) }}</h5> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"> + <span aria-hidden="true">×</span> + </button> + </div> + <div class="modal-body"> + <div class="tree-ctx-item" id="main-tree-div" data-path="" style="overflow: scroll; max-height:75%;"> + <input type="radio" id="main-tree-input" name="root_path" value="" checked> + <span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path=""> + <i class="far fa-folder"></i> + <i class="far fa-folder-open"></i> + {{ translate('serverFiles', 'files', data['lang']) }} + </span> + </input> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-secondary" data-dismiss="modal">{{ translate('serverWizard', 'close', data['lang']) }}</button> + <button type="button" id="modal-okay" data-dismiss="modal" class="btn btn-primary">{{ translate('serverWizard', 'save', data['lang']) }}</button> + </div> + </div> + </div> + </div> + </div> + <button id="zip_submit" type="submit" title="You must select server root dir first" disabled class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton', data['lang']) }}</button> + <button type="reset" class="btn btn-danger mr-2">{{ translate('serverWizard', 'resetForm', data['lang']) }}</button> + </div> + </div> + </form> + </p> + </div> + </div> + </div> +</div> +<style> +.scroll { + max-height: 12em; + overflow-y: auto; +} +.menu-btn { + font-size: 0.9em; + padding: 2px 10px; +} +.menu { + padding-top: 10px; + z-index: 200; + margin-top: 4px; + position: absolute; + background-color: #2a2c44; +} +.menu-option { + padding: 6px 20px 6px; + color: white; +} +#overlay { + position: absolute; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + z-index: 100; +} +</style> +<style> + /* Remove default bullets */ + .tree-view, + .tree-nested { + list-style-type: none; + margin: 0; + padding: 0; + margin-left: 10px; + } + + /* Style the items */ + .tree-item, + .files-tree-title { + cursor: pointer; + user-select: none; /* Prevent text selection */ + } + + /* Create the caret/arrow with a unicode, and style it */ + .tree-caret .fa-folder { + display: inline-block; + } + .tree-caret .fa-folder-open { + display: none; + } + + /* Rotate the caret/arrow icon when clicked on (using JavaScript) */ + .tree-caret-down .fa-folder { + display: none; + } + .tree-caret-down .fa-folder-open { + display: inline-block; + } + + /* Hide the nested list */ + .tree-nested { + display: none; + } +</style> + +{% end %} + +{% block js%} +<script> + document.getElementById("root_files_button").addEventListener("click", function(){ + if(document.forms["zip"]["server_path"].value != ""){ + if(document.getElementById('root_files_button').classList.contains('clicked')){ + document.getElementById('main-tree-div').innerHTML = '<input type="radio" id="main-tree-input" name="root_path" value="" checked><span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path=""><i class="far fa-folder"></i><i class="far fa-folder-open"></i>{{ translate('serverFiles', 'files', data['lang']) }}</span></input>' + }else{ + document.getElementById('root_files_button').classList.add('clicked') + } + path = document.forms["zip"]["server_path"].value; + console.log(document.forms["zip"]["server_path"].value) + var token = getCookie("_xsrf"); + var dialog = bootbox.dialog({ + message: '<p class="text-center mb-0"><i class="fa fa-spin fa-cog"></i> Please wait while we gather your files...</p>', + closeButton: false + }); + setTimeout(function(){ + dialog.modal('hide'); +}, 2000); + $.ajax({ + type: "POST", + headers: {'X-XSRFToken': token}, + url: '/ajax/unzip_server?id=-1&path='+path, + }); + }else{ + bootbox.alert("You must input a path before selecting this button"); + } + }); +</script> + +<script> +function dropDown(event) { + event.target.parentElement.children[1].classList.remove("d-none"); + document.getElementById("overlay").classList.remove("d-none"); +} +function hide(event) { + var items = document.getElementsByClassName('menu'); + for (let i = 0; i < items.length; i++) { + items[i].classList.add("d-none"); + } + document.getElementById("overlay").classList.add("d-none"); +} + $( document ).ready(function() { + console.log('ready'); + var forms = $('form.server-wizard'); + forms.each(function(i, formEl) { + var form = $(formEl); + var min = form.find('[name=min_memory]'); + var max = form.find('[name=max_memory]'); + console.log(form, min, max) + min.change(function(){ + check_sizes(max, min, 'min'); + }); + max.change(function(){ + check_sizes(max, min, 'max'); + }); + }); + }); + + function wait_msg(importing){ + bootbox.alert({ + title: importing ? '{% raw translate("serverWizard", "importing", data['lang']) %}' : '{% raw translate("serverWizard", "downloading", data['lang']) %}', + message: '<i class="fas fa-cloud-download"></i> {% raw translate("serverWizard", "bePatient", data['lang']) %}', + }); + } + + function show_file_tree(){ + $("#dir_select").modal(); + } + + function check_sizes(a, b, changed){ + max_mem = parseFloat(a.val()); + min_mem = parseFloat(b.val()); + if (max_mem < min_mem && changed === 'min'){ + a.val(min_mem) + } + if (max_mem < min_mem && changed === 'max'){ + b.val(max_mem) + } + } + + function getTreeView(path) { + document.getElementById('zip_submit').disabled = false; + path = path + + $.ajax({ + type: "GET", + url: '/ajax/get_zip_tree?id=-1&path='+path, + dataType: 'text', + success: function(data){ + console.log("got response:"); + console.log(data); + + dataArr = data.split('\n'); + serverDir = dataArr.shift(); // Remove & return first element (server directory) + text = dataArr.join('\n'); + + try{ + document.getElementById('main-tree-div').innerHTML += text; + document.getElementById('main-tree').parentElement.classList.add("clicked"); + }catch{ + document.getElementById('files-tree').innerHTML = text; + } + + + document.getElementsByClassName('files-tree-title')[0].setAttribute('data-path', serverDir); + document.getElementsByClassName('files-tree-title')[0].setAttribute('data-name', 'Files'); + + }, + }); + } + + function getToggleMain(event) { + path = event.target.parentElement.getAttribute('data-path'); + document.getElementById("files-tree").classList.toggle("d-block"); + document.getElementById(path+"span").classList.toggle("tree-caret-down"); + document.getElementById(path+"span").classList.toggle("tree-caret"); + } + + + function getDirView(event) { + path = event.target.parentElement.getAttribute('data-path'); + + if (document.getElementById(path).classList.contains('clicked')){ + + var toggler = document.getElementById(path+"span"); + + if (toggler.classList.contains('files-tree-title')){ + document.getElementById(path+"ul").classList.toggle("d-block"); + document.getElementById(path+"span").classList.toggle("tree-caret-down"); + } + return; + }else{ + $.ajax({ + type: "GET", + url: '/ajax/get_zip_dir?id=-1&path='+path, + dataType: 'text', + success: function(data){ + console.log("got response:"); + + dataArr = data.split('\n'); + serverDir = dataArr.shift(); // Remove & return first element (server directory) + text = dataArr.join('\n'); + + try{ + document.getElementById(path+"span").classList.add('tree-caret-down'); + document.getElementById(path).innerHTML += text; + document.getElementById(path).classList.add("clicked"); + }catch{ + console.log("Bad") + } + + var toggler = document.getElementById(path); + + if (toggler.classList.contains('files-tree-title')){ + document.getElementById(path+"span").addEventListener("click", function caretListener() { + document.getElementById(path+"ul").classList.toggle("d-block"); + document.getElementById(path+"span").classList.toggle("tree-caret-down"); + }); + } + }, + }); + } + } + if (webSocket) { + webSocket.on('send_temp_path', function (data) { + document.getElementById('main-tree-input').setAttribute('value', data.path) + getTreeView(data.path); + show_file_tree(); + }); + } + +</script> +<script type="text/javascript"> + //<![CDATA[ + // array of possible countries in the same order as they appear in the country selection list + + function decodeHtmlCharCodes(str) { + return str.replace(""", "\""); + } + + function convertHtmlJsonToJavacriptArray(str) { + var result = [] + str = decodeHtmlCharCodes(str) + for(var i in str) + result.push([i, str [i]]); + return result + } + + var text = '{% raw data["js_server_types"] %}'; + var serverTypesLists = JSON.parse(text); + //convertHtmlJsonToJavacriptArray('{{ data["js_server_types"] }}') + /* CountryChange() is called from the onchange event of a select element. + * param selectObj - the select object which fired the on change event. + */ + function serverTypeChange(selectObj) { + // get the index of the selected option + var idx = selectObj.selectedIndex; + // get the value of the selected option + var which = selectObj.options[idx].value; + // use the selected option value to retrieve the list of items from the serverTypesLists array + cList = serverTypesLists[which]; + // get the country select element via its known id + var cSelect = document.getElementById("server"); + // remove the current options from the country select + var len=cSelect.options.length; + while (cSelect.options.length > 0) { + cSelect.remove(0); + } + var newOption; + // create new options ordered by descending + for (var i=(cList.length)-1; i>=0; i--) { + newOption = document.createElement("option"); + newOption.value = which+"|"+cList[i]; // assumes option string and value are the same + newOption.text=cList[i]; + // add the new option + try { + cSelect.add(newOption); // this will fail in DOM browsers but is needed for IE + } + catch (e) { + cSelect.appendChild(newOption); + } + } + } + //]]> + </script> +{% end %} \ No newline at end of file diff --git a/app/frontend/templates/server/wizard.html b/app/frontend/templates/server/wizard.html index 7f82fd29..8e2f1b2a 100644 --- a/app/frontend/templates/server/wizard.html +++ b/app/frontend/templates/server/wizard.html @@ -5,6 +5,17 @@ {% block content %} <div class="content-wrapper"> + <div class="content-wrapper"> + <ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist"> + <li class="nav-item term-nav-item"> + <a class="nav-link active" href="/server/step1" role="tab" aria-selected="false"> + <i class="fas fa-file-signature"></i>Minecraft-Java</a> + </li> + <li class="nav-item term-nav-item"> + <a class="nav-link" href="/server/bedrock_step1" role="tab" aria-selected="false"> + <i class="fas fa-file-signature"></i>Minecraft-Bedrock</a> + </li> + </ul> <div class="d-none" id="overlay" onclick="hide(event)"></div> <div class="row"> <div class="col-sm-6 grid-margin stretch-card">