Add bedrock server creation

This commit is contained in:
amcmanu3 2022-08-31 19:45:19 -04:00
parent b274f0d3b0
commit a07eb58db7
21 changed files with 566 additions and 370 deletions

View File

@ -3,6 +3,7 @@ import time
import shutil
import logging
import threading
import urllib
from app.classes.controllers.server_perms_controller import PermissionsServers
from app.classes.controllers.servers_controller import ServersController
@ -214,3 +215,36 @@ class ImportHelpers:
os.chmod(full_jar_path, 0o2760)
# deletes temp dir
FileHelpers.del_dirs(temp_dir)
def download_bedrock_server(self, path, new_id):
download_thread = threading.Thread(
target=self.download_threaded_bedrock_server,
daemon=True,
args=(path, new_id),
name=f"{new_id}_download",
)
download_thread.start()
def download_threaded_bedrock_server(self, path, new_id):
# downloads zip from remote url
bedrock_url = Helpers.get_latest_bedrock_url()
if bedrock_url.lower().startswith("https"):
urllib.request.urlretrieve(
bedrock_url,
os.path.join(path, "bedrock_server.zip"),
)
unzip_path = os.path.join(path, "bedrock_server.zip")
unzip_path = self.helper.wtol_path(unzip_path)
# unzips archive that was downloaded.
FileHelpers.unzip_file(unzip_path)
# adjusts permissions for execution if os is not windows
if not self.helper.is_os_windows():
os.chmod(os.path.join(path, "bedrock_server"), 0o0744)
# we'll delete the zip we downloaded now
os.remove(os.path.join(path, "bedrock_server.zip"))
ServersController.finish_import(new_id)
server_users = PermissionsServers.get_server_user_list(new_id)
for user in server_users:
self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {})

View File

@ -697,6 +697,49 @@ class Controller:
)
return new_id
def create_bedrock_server(self, server_name, user_id):
server_id = Helpers.create_uuid()
new_server_dir = os.path.join(self.helper.servers_dir, server_id)
backup_path = os.path.join(self.helper.backup_path, server_id)
server_exe = "bedrock_server"
if Helpers.is_os_windows():
# if this is windows we will override the linux bedrock server name.
server_exe = "bedrock_server.exe"
new_server_dir = Helpers.wtol_path(new_server_dir)
backup_path = Helpers.wtol_path(backup_path)
new_server_dir.replace(" ", "^ ")
backup_path.replace(" ", "^ ")
Helpers.ensure_dir_exists(new_server_dir)
Helpers.ensure_dir_exists(backup_path)
full_jar_path = os.path.join(new_server_dir, server_exe)
if Helpers.is_os_windows():
server_command = f'"{full_jar_path}"'
else:
server_command = f"./{server_exe}"
logger.debug("command: " + server_command)
server_log_file = ""
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,
"19132",
user_id,
server_type="minecraft-bedrock",
)
ServersController.set_import(new_id)
self.import_helper.download_bedrock_server(new_server_dir, new_id)
return new_id
def import_bedrock_zip_server(
self,
server_name: str,

View File

@ -338,7 +338,7 @@ class ServerInstance:
"eula =true",
]
if not e_flag:
if not e_flag and self.settings["type"] == "minecraft-java":
if user_id:
self.helper.websocket_helper.broadcast_user(
user_id, "send_eula_bootbox", {"id": self.server_id}

View File

@ -97,6 +97,7 @@ class ServerHandler(BaseHandler):
"version_data": self.helper.get_version_string(),
"user_data": exec_user,
"user_role": exec_user_role,
"online": Helpers.check_internet(),
"roles": list_roles,
"super_user": exec_user["superuser"],
"user_crafty_permissions": exec_user_crafty_permissions,
@ -173,7 +174,6 @@ class ServerHandler(BaseHandler):
)
return
page_data["online"] = Helpers.check_internet()
page_data["server_types"] = self.controller.server_jars.get_serverjar_data()
page_data["js_server_types"] = json.dumps(
self.controller.server_jars.get_serverjar_data()
@ -548,25 +548,14 @@ class ServerHandler(BaseHandler):
self.get_remote_ip(),
)
else:
if len(server_parts) != 2:
self.redirect("/panel/error?error=Invalid server data")
return
server_type, server_version = server_parts
# TODO: add server type check here and call the correct server
# add functions if not a jar
new_server_id = self.controller.create_jar_server(
server_type,
server_version,
new_server_id = self.controller.create_bedrock_server(
server_name,
min_mem,
max_mem,
port,
exec_user["user_id"],
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
f"created a {server_version} {str(server_type).capitalize()} "
f'server named "{server_name}"',
"created a Bedrock " f'server named "{server_name}"',
# Example: Admin created a 1.16.5 Bukkit server named "survival"
new_server_id,
self.get_remote_ip(),

View File

@ -378,7 +378,7 @@
}
bootbox.confirm({
title: "{% raw translate('error', 'eulaTitle', data['lang']) %}",
message: "{% raw translate('error', 'eulaMsg', data['lang']) %} <br><br><a href='https://account.mojang.com/documents/minecraft_eula' target='_blank'>EULA</a><br><br>{% raw translate('error', 'eulaAgree', data['lang']) %}",
message: "{% raw translate('error', 'eulaMsg', data['lang']) %} <br><br><a href='https://www.minecraft.net/en-us/eula' target='_blank'>EULA</a><br><br>{% raw translate('error', 'eulaAgree', data['lang']) %}",
buttons: {
confirm: {
label: 'Yes',

View File

@ -7,445 +7,575 @@
<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">
<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="bedrock_server" required>
</div>
</div>
</ul>
<br>
<div class="d-none" id="overlay" onclick="hide(event)"></div>
<div class="row">
{% if data['online'] %}
<div class="col-sm-6 grid-margin stretch-card">
<div class="card">
<div class="card-body">
<h4>{{ translate('serverWizard', 'newServer', data['lang']) }}</h4>
<br />
<p class="card-description">
<form method="post" name="create_server" class="server-wizard" onSubmit="wait_msg()">
{% raw xsrf_form_html() %}
<div class="row">
<div class="col-sm-12 col-md-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"
placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
</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>
<div class="col-sm-12">
<div class="form-group">
<label for="port2">{{ translate('serverWizard', 'serverPort', data['lang']) }} <small></small></label>
<input type="number" class="form-control" id="port2" name="port" value="19132" step="1" min="1" required>
</div>
<div class="col-sm-12">
<div class="form-group">
<div id="accordion-1">
<div class="card">
<div class="card-header p-2" id="Role-1">
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-1" aria-expanded="true"
aria-controls="collapseRole-1">
<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>
<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">&nbsp;
{{ r['role_name'].capitalize() }}</label></span>
{% end %}
</div>
</div>
</div>
<div id="collapseRole-1" class="collapse" aria-labelledby="Role-1" 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">&nbsp;
{{ r['role_name'].capitalize() }}</label></span>
{% end %}
</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>
<button onclick="eula_confirm()" type="button" class="btn btn-primary mr-2">{{ translate('serverWizard',
'buildServer',
data['lang']) }}</button>
<button type="reset" class="btn btn-danger mr-2">{{ translate('serverWizard', 'resetForm', data['lang'])
}}</button>
</div>
</form>
</p>
</div>
<div class="col-sm-6 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="bedrock_server" required>
</div>
</div>
</div>
</div>
{% end %}
<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="bedrock_server" required>
</div>
</div>
<div class="col-sm-12">
<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>
<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-12">
<div class="form-group">
<label for="port3">{{ translate('serverWizard', 'serverPort', data['lang']) }} <small></small></label>
<input type="number" class="form-control" id="port3" name="port" value="19132" step="1" min="1" required>
</div>
<div class="col-sm-12">
<div class="form-group">
<label for="port2">{{ translate('serverWizard', 'serverPort', data['lang']) }}
<small></small></label>
<input type="number" class="form-control" id="port2" name="port" value="19132" 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 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">&nbsp;
{{ r['role_name'].capitalize() }}</label></span>
{% end %}
</div>
</div>
</div>
</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">&nbsp;
{{ r['role_name'].capitalize() }}</label></span>
{% end %}
</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>
</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 class="col-sm-6 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="bedrock_server" required>
</div>
</div>
</div>
</div>
<div class="col-sm-12">
<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="port3">{{ translate('serverWizard', 'serverPort', data['lang']) }}
<small></small></label>
<input type="number" class="form-control" id="port3" name="port" value="19132" 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>
<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">&times;</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 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">&nbsp;
{{ r['role_name'].capitalize() }}</label></span>
{% end %}
</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 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">&times;</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 {
.scroll {
max-height: 12em;
overflow-y: auto;
}
.menu-btn {
}
.menu-btn {
font-size: 0.9em;
padding: 2px 10px;
}
.menu {
}
.menu {
padding-top: 10px;
z-index: 200;
margin-top: 4px;
position: absolute;
background-color: #2a2c44;
}
.menu-option {
}
.menu-option {
padding: 6px 20px 6px;
color: white;
}
#overlay {
}
#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;
}
.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 */
}
/* 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;
}
/* Create the caret/arrow with a unicode, and style it */
.tree-caret .fa-folder {
display: inline-block;
}
/* 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;
}
.tree-caret .fa-folder-open {
display: none;
}
/* Hide the nested list */
.tree-nested {
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')){
function eula_confirm() {
bootbox.confirm({
title: "{% raw translate('error', 'eulaTitle', data['lang']) %}",
message: "{% raw translate('error', 'eulaMsg', data['lang']) %} <br><br><a href='https://www.minecraft.net/en-us/eula' target='_blank'>EULA</a><br><br>{% raw translate('error', 'eulaAgree', data['lang']) %}",
buttons: {
confirm: {
label: 'Yes',
className: 'btn-info'
},
cancel: {
label: 'No',
className: 'btn-secondary'
}
},
callback: function (result) {
if (result == true) {
document.create_server.submit();
}
else {
return;
}
}
})
}
</script>
<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{
} 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
});
$.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");
}
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
});
$.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) {
function dropDown(event) {
event.target.parentElement.children[1].classList.remove("d-none");
document.getElementById("overlay").classList.remove("d-none");
}
function hide(event) {
}
function hide(event) {
var items = document.getElementsByClassName('menu');
for (let i = 0; i < items.length; i++) {
items[i].classList.add("d-none");
items[i].classList.add("d-none");
}
document.getElementById("overlay").classList.add("d-none");
}
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(){
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 getTreeView(path) {
document.getElementById('zip_submit').disabled = false;
path = path
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);
$.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');
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");
try {
document.getElementById('main-tree-div').innerHTML += text;
document.getElementById('main-tree').parentElement.classList.add("clicked");
} catch {
document.getElementById('files-tree').innerHTML = text;
}
return;
}else{
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,
url: '/ajax/get_zip_dir?id=-1&path=' + path,
dataType: 'text',
success: function(data){
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');
try {
document.getElementById(path + "span").classList.add('tree-caret-down');
document.getElementById(path).innerHTML += text;
document.getElementById(path).classList.add("clicked");
}catch{
} 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 (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) {
setTimeout(function(){
var x = document.querySelector('.bootbox');
if (x) {
x.remove()
}
var x = document.querySelector('.modal-backdrop');
if (x) {
x.remove()
}
document.getElementById('main-tree-input').setAttribute('value', data.path)
getTreeView(data.path);
show_file_tree();
}
if (webSocket) {
webSocket.on('send_temp_path', function (data) {
setTimeout(function () {
var x = document.querySelector('.bootbox');
if (x) {
x.remove()
}
var x = document.querySelector('.modal-backdrop');
if (x) {
x.remove()
}
document.getElementById('main-tree-input').setAttribute('value', data.path)
getTreeView(data.path);
show_file_tree();
}, 5000);
});
}
});
}
</script>
{% end %}
{% end %}

View File

@ -168,7 +168,7 @@
"embarassing": "Oh je, das ist peinlich.",
"error": "Fehler!",
"eulaAgree": "Stimmen Sie zu?",
"eulaMsg": "Sie müssen der EULA zustimmen. Eine Kopie der Mojang EULA ist unter dieser Nachricht verlinkt.",
"eulaMsg": "Sie müssen der EULA zustimmen. Eine Kopie der Minecraft EULA ist unter dieser Nachricht verlinkt.",
"eulaTitle": "Der EULA zustimmen",
"hereIsTheError": "Das ist der Fehler",
"internet": "Wir haben festgestellt, dass der Rechner, auf dem Crafty läuft, keine Verbindung zum Internet hat. Client-Verbindungen zum Server können dadurch eingeschränkt sein.",

View File

@ -168,7 +168,7 @@
"embarassing": "Oh my, well, this is embarrassing.",
"error": "Error!",
"eulaAgree": "Do you agree?",
"eulaMsg": "You must agree to the EULA. A copy of the Mojang EULA is linked under this message.",
"eulaMsg": "You must agree to the EULA. A copy of the Minecraft EULA is linked under this message.",
"eulaTitle": "Agree To EULA",
"fileTooLarge": "Upload failed. File upload too large. Contact system administrator for assistance.",
"hereIsTheError": "Here is the error",

View File

@ -169,7 +169,7 @@
"embarassing": "Oh por, bueno, esto es vergonzoso.",
"error": "Error!",
"eulaAgree": "Estás de acuerdo?",
"eulaMsg": "Debes aceptar el EULA. Una copia del EULA de Mojang esta vinculada debajo de este mensaje.",
"eulaMsg": "Debes aceptar el EULA. Una copia del EULA de Minecraft esta vinculada debajo de este mensaje.",
"eulaTitle": "Aceptar EULA",
"fileTooLarge": "Subida fallida. Carga de archivo demasiado grande. Póngase en contacto con el administrador del sistema para obtener ayuda.",
"hereIsTheError": "Aquí está el error.",
@ -537,4 +537,4 @@
"userSettings": "Configuracion de Usuario.",
"uses": "Número de usos habilitados. (-1 == sin límite)."
}
}
}

View File

@ -192,7 +192,7 @@
"embarassing": "No, tämähän on noloa.",
"error": "Virhe!",
"eulaAgree": "Oletko samaa mieltä?",
"eulaMsg": "Sinun on hyväksyttävä EULA. Kopio Mojang EULA:sta on linkitetty tämän viestin alla.",
"eulaMsg": "Sinun on hyväksyttävä EULA. Kopio Minecraft EULA:sta on linkitetty tämän viestin alla.",
"eulaTitle": "Hyväksy EULA",
"fileTooLarge": "Lataus epäonnistui. Tiedosto on liian suuri. Ota yhteyttä järjestelmänvalvojaan saadaksesi apua.",
"hereIsTheError": "Tässä on virhe",
@ -560,4 +560,4 @@
"userSettings": "Käyttäjäasetukset",
"uses": "Sallittujen käyttäkertojen määtä (-1 == Ei rajaa)"
}
}
}

View File

@ -168,7 +168,7 @@
"embarassing": "Oulà, c'est embarrassant.",
"error": "Erreur !",
"eulaAgree": "Êtes-vous d'accord?",
"eulaMsg": "Vous devez accepter le EULA. Une copie du CLUF de Mojang est liée sous ce message.",
"eulaMsg": "Vous devez accepter le EULA. Une copie du CLUF de Minecraft est liée sous ce message.",
"eulaTitle": "Accepter le EULA",
"fileTooLarge": "Echec du chargement. Le fichier est trop gros. Demande de l'aide à l'administrateur système.",
"hereIsTheError": "Il y a une erreur",
@ -536,4 +536,4 @@
"userSettings": "Paramètres Utilisateur",
"uses": "Nombre d'utilisation Authorisé (-1 == Illimité)"
}
}
}

View File

@ -167,7 +167,7 @@
"embarassing": "Och, dit is beskamsum.",
"error": "Error!",
"eulaAgree": "Binne jo akkoard?",
"eulaMsg": "Jo moatte ynstimme mei de EULA. In kopy fan 'e Mojang EULA is keppele ûnder dit berjocht.",
"eulaMsg": "Jo moatte ynstimme mei de EULA. In kopy fan 'e Minecraft EULA is keppele ûnder dit berjocht.",
"eulaTitle": "Akseptearje mei EULA",
"hereIsTheError": "Hjir is de error",
"internet": "Wy hawwe ûntdutsen dat de masine dy't Crafty draait gjin ferbining hat mei it ynternet. Clientferbiningen mei de server kinne beheind wêze.",
@ -529,4 +529,4 @@
"userSettings": "Brûkersynstellingen",
"uses": "Oantal gebrûk tastien (-1==Gjin limyt)"
}
}
}

View File

@ -167,7 +167,7 @@
"embarassing": "Uhh, ovo je sramotno.",
"error": "Greška!",
"eulaAgree": "Slažete li se?",
"eulaMsg": "Morate prihvatiti EULA-u. Poveznica Mojangove EULA-e se nalazi ispod ove poruke.",
"eulaMsg": "Morate prihvatiti EULA-u. Poveznica Minecraft EULA-e se nalazi ispod ove poruke.",
"eulaTitle": "Prihvatite EULA-u",
"hereIsTheError": "Ovdje je pogreška",
"internet": "Otkrili smo da uređaj koji pokreće Crafty nije povezan s internetom. Povezivanje klijenta s poslužiteljem može biti ograničeno.",
@ -529,4 +529,4 @@
"userSettings": "Korisničke postavke",
"uses": "Broj dopuštenih upotreba (-1==Bez ograničenja)"
}
}
}

View File

@ -168,7 +168,7 @@
"embarassing": "Oh tidak, ini adalah hal yang memalukan",
"error": "Error!",
"eulaAgree": "Apakah anda setuju?",
"eulaMsg": "Anda harus menyetujui EULA. Salinan Mojang EULA ditautkan di bawah pesan ini.",
"eulaMsg": "Anda harus menyetujui EULA. Salinan Minecraft EULA ditautkan di bawah pesan ini.",
"eulaTitle": "Setuju Ke EULA",
"fileTooLarge": "Gagal menggungah. File yang ingin di unggah terlalu besar. Kontak administrator system untuk pengawasan",
"hereIsTheError": "Disini Error nya",
@ -536,4 +536,4 @@
"userSettings": "Pengaturan Pengguna",
"uses": "Jumlah penggunaan yang diizinkan (-1==No Limit)"
}
}
}

View File

@ -167,7 +167,7 @@
"embarassing": "Oh my, well, this is embarrassing.",
"error": "Error!",
"eulaAgree": "Do you agree?",
"eulaMsg": "You must agree to the EULA. A copy of the Mojang EULA is linked under this message.",
"eulaMsg": "You must agree to the EULA. A copy of the Minecraft EULA is linked under this message.",
"eulaTitle": "Agree To EULA",
"hereIsTheError": "Here is the error",
"internet": "We have detected the machine running Crafty has no connection to the internet. Client connections to the server may be limited.",
@ -529,4 +529,4 @@
"userSettings": "Impostazioni Utente",
"uses": "Numero di usi permessi (-1==Nessun limite)"
}
}
}

View File

@ -168,7 +168,7 @@
"embarassing": "Ak nu, tas ir apkaunojoši.",
"error": "Kļūda!",
"eulaAgree": "Vai jūs piekrītat?",
"eulaMsg": "Jums ir jāpiekrīt EULA. Kopija no Mojang EULA ir saitēta zem šī ziņojuma.",
"eulaMsg": "Jums ir jāpiekrīt EULA. Kopija no Minecraft EULA ir saitēta zem šī ziņojuma.",
"eulaTitle": "Piekrist EULA",
"fileTooLarge": "Augšupielāde neizdevās. Faila augšupielāde ir pārāk liela. Sazinies ar sistēmas administratoru priekš palīdzības.",
"hereIsTheError": "Rekur ir kļūda",
@ -536,4 +536,4 @@
"userSettings": "Lietotāju Iestatījumi",
"uses": "Dauzums, cik reizes lietot (-1==Bez Limita)"
}
}
}

View File

@ -168,7 +168,7 @@
"embarassing": "Oh, nou, dit is gênant.",
"error": "Fout!",
"eulaAgree": "Bent u het eens?",
"eulaMsg": "U moet akkoord gaan met de EULA. Een kopie van de Mojang EULA is gelinkt onder dit bericht.",
"eulaMsg": "U moet akkoord gaan met de EULA. Een kopie van de Minecraft EULA is gelinkt onder dit bericht.",
"eulaTitle": "Akkoord gaan met EULA",
"fileTooLarge": "Uploaden mislukt. Bestand uploaden te groot. Neem contact op met de systeembeheerder voor assistentie",
"hereIsTheError": "Hier is de fout",
@ -536,4 +536,4 @@
"userSettings": "Gebruikersinstellingen",
"uses": "Aantal toegestane gebruiken (-1==Geen Limiet)"
}
}
}

View File

@ -167,7 +167,7 @@
"embarassing": "Oh, oeps, dit is gênant.",
"error": "Error!",
"eulaAgree": "Stem je in met de EULA?",
"eulaMsg": "Je moet instemmen met de EULA. Een kopie van de Mojang EULA is onder dit bericht gelinkt.",
"eulaMsg": "Je moet instemmen met de EULA. Een kopie van de Minecraft EULA is onder dit bericht gelinkt.",
"eulaTitle": "Instemmen met de EULA",
"hereIsTheError": "Hier is de error",
"internet": "We hebben gedetecteerd dat de serverhost geen internetverbinding heeft. Client connecties zijn mogelijk gelimiteerd.",
@ -529,4 +529,4 @@
"userSettings": "Gebruikersinstellingen",
"uses": "Aantal keer toegestaan (-1==Geen limiet)"
}
}
}

View File

@ -168,7 +168,7 @@
"embarassing": "Oh, więc, to jest żenujące.",
"error": "Błąd!",
"eulaAgree": "Czy się zgadzasz?",
"eulaMsg": "Musisz się zgodzić na EULA. Kopia EULA Mojangu jest zalinkowana pod tą wiadomością.",
"eulaMsg": "Musisz się zgodzić na EULA. Kopia EULA Minecraft jest zalinkowana pod tą wiadomością.",
"eulaTitle": "Zgódź się na EULA",
"fileTooLarge": "Upload nie udany. Plik jest za duży. Skontaktuj się z administratorem dla pomocy.",
"hereIsTheError": "Tu jest problem",
@ -537,4 +537,4 @@
"userSettings": "Ustawienia użytkownika",
"uses": "Ilość użyć (-1==Bez limitu)"
}
}
}

View File

@ -168,7 +168,7 @@
"embarassing": "Oh. Bem, isso é constrangedor",
"error": "Erro!",
"eulaAgree": "Você concorda?",
"eulaMsg": "Você deve concordar com os Termos de Licença. Uma cópia dos Termos de Licença da Mojang está linkado abaixo desta mensagem.",
"eulaMsg": "Você deve concordar com os Termos de Licença. Uma cópia dos Termos de Licença da Minecraft está linkado abaixo desta mensagem.",
"eulaTitle": "Concordar com os Termos de Licença",
"fileTooLarge": "Upload falhou. Arquivo muito grande. Contato o administrador do sistema para assistência.",
"hereIsTheError": "Aqui está o erro",
@ -537,4 +537,4 @@
"userSettings": "Configurações do Usuário",
"uses": "Número de Usos Permitidos (-1==Sem Limite)"
}
}
}

View File

@ -168,7 +168,7 @@
"embarassing": "哦,天哪,这太尴尬了。",
"error": "错误!",
"eulaAgree": "你同意吗?",
"eulaMsg": "你必须同意最终用户许可协议EULA。一份 Mojang EULA 副本的链接在此消息下方。",
"eulaMsg": "你必须同意最终用户许可协议EULA。一份 Minecraft EULA 副本的链接在此消息下方。",
"eulaTitle": "同意最终用户许可协议EULA",
"fileTooLarge": "上传失败。上传的文件过大。联系系统管理员以获取协助。",
"hereIsTheError": "错误如下",
@ -536,4 +536,4 @@
"userSettings": "用户设置",
"uses": "使用次数限制(-1==无限制)"
}
}
}