mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Backup Restore/Root Disable
This commit is contained in:
parent
798dac02a5
commit
a19ba7dbb6
@ -51,6 +51,17 @@ class Server_Perms_Controller:
|
|||||||
def add_role_server(server_id, role_id, rs_permissions="00000000"):
|
def add_role_server(server_id, role_id, rs_permissions="00000000"):
|
||||||
return server_permissions.add_role_server(server_id, role_id, rs_permissions)
|
return server_permissions.add_role_server(server_id, role_id, rs_permissions)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_server_roles(server_id):
|
||||||
|
return server_permissions.get_server_roles(server_id)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def backup_role_swap(old_server_id, new_server_id):
|
||||||
|
role_list = server_permissions.get_server_roles(old_server_id)
|
||||||
|
for role in role_list:
|
||||||
|
server_permissions.add_role_server(new_server_id, role.role_id, server_permissions.get_permissions_mask(int(role.role_id), int(old_server_id)))
|
||||||
|
#server_permissions.add_role_server(new_server_id, role.role_id, '00001000')
|
||||||
|
|
||||||
#************************************************************************************************
|
#************************************************************************************************
|
||||||
# Servers Permissions Methods
|
# Servers Permissions Methods
|
||||||
#************************************************************************************************
|
#************************************************************************************************
|
||||||
|
@ -227,6 +227,10 @@ class helpers_management:
|
|||||||
def update_scheduled_task(schedule_id, updates):
|
def update_scheduled_task(schedule_id, updates):
|
||||||
Schedules.update(updates).where(Schedules.schedule_id == schedule_id).execute()
|
Schedules.update(updates).where(Schedules.schedule_id == schedule_id).execute()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete_scheduled_task_by_server(server_id):
|
||||||
|
Schedules.delete().where(Schedules.server_id == int(server_id)).execute()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_scheduled_task(schedule_id):
|
def get_scheduled_task(schedule_id):
|
||||||
return model_to_dict(Schedules.get(Schedules.schedule_id == schedule_id)).execute()
|
return model_to_dict(Schedules.get(Schedules.schedule_id == schedule_id)).execute()
|
||||||
|
@ -118,10 +118,18 @@ class Permissions_Servers:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def get_permissions_mask(role_id, server_id):
|
def get_permissions_mask(role_id, server_id):
|
||||||
permissions_mask = ''
|
permissions_mask = ''
|
||||||
role_server = Role_Servers.select().where(Role_Servers.role_id == role_id).where(Role_Servers.server_id == server_id).execute()
|
role_server = Role_Servers.select().where(Role_Servers.role_id == role_id).where(Role_Servers.server_id == server_id).get()
|
||||||
permissions_mask = role_server.permissions
|
permissions_mask = role_server.permissions
|
||||||
return permissions_mask
|
return permissions_mask
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_server_roles(server_id):
|
||||||
|
role_list = []
|
||||||
|
roles = Role_Servers.select().where(Role_Servers.server_id == server_id).execute()
|
||||||
|
for role in roles:
|
||||||
|
role_list.append(role.role_id)
|
||||||
|
return role_list
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_role_permissions_list(role_id):
|
def get_role_permissions_list(role_id):
|
||||||
permissions_mask = '00000000'
|
permissions_mask = '00000000'
|
||||||
|
@ -338,6 +338,12 @@ class Helpers:
|
|||||||
logger.critical("Unable to write to {} - Error: {}".format(path, e))
|
logger.critical("Unable to write to {} - Error: {}".format(path, e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def checkRoot(self):
|
||||||
|
if os.geteuid() == 0:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
def unzipFile(self, zip_path):
|
def unzipFile(self, zip_path):
|
||||||
new_dir_list = zip_path.split('/')
|
new_dir_list = zip_path.split('/')
|
||||||
new_dir = ''
|
new_dir = ''
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
import os
|
import os
|
||||||
|
import pathlib
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
from peewee import DoesNotExist
|
||||||
|
import schedule
|
||||||
import yaml
|
import yaml
|
||||||
import asyncio
|
import asyncio
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import zipfile
|
import zipfile
|
||||||
from distutils import dir_util
|
from distutils import dir_util
|
||||||
|
from app.classes.models.management import helpers_management
|
||||||
|
|
||||||
from app.classes.shared.helpers import helper
|
from app.classes.shared.helpers import helper
|
||||||
from app.classes.shared.console import console
|
from app.classes.shared.console import console
|
||||||
@ -285,11 +289,32 @@ class Controller:
|
|||||||
helper.ensure_dir_exists(new_server_dir)
|
helper.ensure_dir_exists(new_server_dir)
|
||||||
helper.ensure_dir_exists(backup_path)
|
helper.ensure_dir_exists(backup_path)
|
||||||
tempDir = tempfile.mkdtemp()
|
tempDir = tempfile.mkdtemp()
|
||||||
|
has_properties = False
|
||||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||||
|
#extracts archive to temp directory
|
||||||
zip_ref.extractall(tempDir)
|
zip_ref.extractall(tempDir)
|
||||||
|
if len(zip_ref.filelist) > 1:
|
||||||
|
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('ERROR IN ZIP IMPORT: {}'.format(ex))
|
||||||
|
if not has_properties:
|
||||||
|
logger.info("No server.properties found on zip file import. Creating one with port selection of {}".format(str(port)))
|
||||||
|
with open(os.path.join(new_server_dir, "server.properties"), "w") as f:
|
||||||
|
f.write("server-port={}".format(port))
|
||||||
|
f.close()
|
||||||
|
zip_ref.close()
|
||||||
|
else:
|
||||||
|
|
||||||
|
#iterates list of files
|
||||||
for i in range(len(zip_ref.filelist)):
|
for i in range(len(zip_ref.filelist)):
|
||||||
if len(zip_ref.filelist) > 1 or not zip_ref.filelist[i].filename.endswith('/'):
|
#checks if the list of files inside of a dir is greater than 1 or if it's not a directory.
|
||||||
test = zip_ref.filelist[i].filename
|
if len(zip_ref.filelist) > 1 or not zip_ref.filelist[i].is_dir():
|
||||||
|
#sets local variable to be that filename and we break out of the loop since we found our root dir.
|
||||||
|
test = zip_ref.filelist[i-1].filename
|
||||||
break
|
break
|
||||||
path_list = test.split('/')
|
path_list = test.split('/')
|
||||||
root_path = path_list[0]
|
root_path = path_list[0]
|
||||||
@ -299,7 +324,7 @@ class Controller:
|
|||||||
|
|
||||||
full_root_path = os.path.join(tempDir, root_path)
|
full_root_path = os.path.join(tempDir, root_path)
|
||||||
|
|
||||||
has_properties = False
|
|
||||||
for item in os.listdir(full_root_path):
|
for item in os.listdir(full_root_path):
|
||||||
if str(item) == 'server.properties':
|
if str(item) == 'server.properties':
|
||||||
has_properties = True
|
has_properties = True
|
||||||
@ -328,10 +353,20 @@ class Controller:
|
|||||||
server_log_file, server_stop, port)
|
server_log_file, server_stop, port)
|
||||||
return new_id
|
return new_id
|
||||||
|
|
||||||
|
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']
|
||||||
|
Server_Perms_Controller.backup_role_swap(old_server_id, new_server_id)
|
||||||
|
backup_path = helper.validate_traversal(helper.backup_path, old_bu_path)
|
||||||
|
backup_path_components = list(backup_path.parts)
|
||||||
|
backup_path_components[-1] = new_uuid
|
||||||
|
new_bu_path = pathlib.PurePath(os.path.join(*backup_path_components))
|
||||||
|
backup_path.rename(new_bu_path)
|
||||||
|
|
||||||
def register_server(self, name: str, server_uuid: str, server_dir: str, backup_path: str, server_command: str, server_file: str, server_log_file: str, server_stop: str, server_port: int):
|
def register_server(self, name: str, server_uuid: str, server_dir: str, backup_path: str, server_command: str, server_file: str, server_log_file: str, server_stop: str, server_port: int):
|
||||||
# put data in the db
|
# 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)
|
new_id = self.servers.create_server(name, server_uuid, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, server_port)
|
||||||
|
if not helper.check_file_exists(os.path.join(server_dir, "crafty_managed.txt")):
|
||||||
try:
|
try:
|
||||||
# place a file in the dir saying it's owned by crafty
|
# place a file in the dir saying it's owned by crafty
|
||||||
with open(os.path.join(server_dir, "crafty_managed.txt"), 'w') as f:
|
with open(os.path.join(server_dir, "crafty_managed.txt"), 'w') as f:
|
||||||
@ -356,6 +391,7 @@ class Controller:
|
|||||||
if int(s['server_id']) == int(server_id):
|
if int(s['server_id']) == int(server_id):
|
||||||
server_data = self.get_server_data(server_id)
|
server_data = self.get_server_data(server_id)
|
||||||
server_name = server_data['server_name']
|
server_name = server_data['server_name']
|
||||||
|
backup_dir = self.servers.get_server_data_by_id(server_id)['backup_path']
|
||||||
|
|
||||||
logger.info("Deleting Server: ID {} | Name: {} ".format(server_id, server_name))
|
logger.info("Deleting Server: ID {} | Name: {} ".format(server_id, server_name))
|
||||||
console.info("Deleting Server: ID {} | Name: {} ".format(server_id, server_name))
|
console.info("Deleting Server: ID {} | Name: {} ".format(server_id, server_name))
|
||||||
@ -366,7 +402,19 @@ class Controller:
|
|||||||
if running:
|
if running:
|
||||||
self.stop_server(server_id)
|
self.stop_server(server_id)
|
||||||
if files:
|
if files:
|
||||||
|
try:
|
||||||
shutil.rmtree(helper.get_os_understandable_path(self.servers.get_server_data_by_id(server_id)['path']))
|
shutil.rmtree(helper.get_os_understandable_path(self.servers.get_server_data_by_id(server_id)['path']))
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Unable to delete server files for server with ID: {} with error logged: {}".format(server_id, e))
|
||||||
|
if helper.check_path_exists(self.servers.get_server_data_by_id(server_id)['backup_path']):
|
||||||
|
shutil.rmtree(helper.get_os_understandable_path(self.servers.get_server_data_by_id(server_id)['backup_path']))
|
||||||
|
|
||||||
|
|
||||||
|
#Cleanup scheduled tasks
|
||||||
|
try:
|
||||||
|
helpers_management.delete_scheduled_task_by_server(server_id)
|
||||||
|
except DoesNotExist:
|
||||||
|
logger.info("No scheduled jobs exist. Continuing.")
|
||||||
# remove the server from the DB
|
# remove the server from the DB
|
||||||
self.servers.remove_server(server_id)
|
self.servers.remove_server(server_id)
|
||||||
|
|
||||||
@ -374,3 +422,4 @@ class Controller:
|
|||||||
self.servers_list.pop(counter)
|
self.servers_list.pop(counter)
|
||||||
|
|
||||||
counter += 1
|
counter += 1
|
||||||
|
return
|
||||||
|
@ -243,6 +243,15 @@ class Server:
|
|||||||
try:
|
try:
|
||||||
self.process = subprocess.Popen(self.server_command, cwd=self.server_path, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
self.process = subprocess.Popen(self.server_command, cwd=self.server_path, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
|
#Checks for java on initial fail
|
||||||
|
if os.system("java -version") == 32512:
|
||||||
|
msg = "Server {} failed to start with error code: {}".format(self.name, "Java not found. Please install Java then try again.")
|
||||||
|
if user_id:
|
||||||
|
websocket_helper.broadcast_user(user_id, 'send_start_error',{
|
||||||
|
'error': translation.translate('error', 'noJava', user_lang).format(self.name)
|
||||||
|
})
|
||||||
|
return False
|
||||||
|
else:
|
||||||
msg = "Server {} failed to start with error code: {}".format(self.name, ex)
|
msg = "Server {} failed to start with error code: {}".format(self.name, ex)
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
if user_id:
|
if user_id:
|
||||||
@ -512,14 +521,14 @@ class Server:
|
|||||||
return
|
return
|
||||||
|
|
||||||
def list_backups(self):
|
def list_backups(self):
|
||||||
conf = management_helper.get_backup_config(self.server_id)
|
|
||||||
if self.settings['backup_path']:
|
if self.settings['backup_path']:
|
||||||
if helper.check_path_exists(helper.get_os_understandable_path(self.settings['backup_path'])):
|
if helper.check_path_exists(helper.get_os_understandable_path(self.settings['backup_path'])):
|
||||||
files = helper.get_human_readable_files_sizes(helper.list_dir_by_date(helper.get_os_understandable_path(self.settings['backup_path'])))
|
files = helper.get_human_readable_files_sizes(helper.list_dir_by_date(helper.get_os_understandable_path(self.settings['backup_path'])))
|
||||||
return [{"path": os.path.relpath(f['path'], start=helper.get_os_understandable_path(conf['backup_path'])), "size": f["size"]} for f in files]
|
return [{"path": os.path.relpath(f['path'], start=helper.get_os_understandable_path(self.settings['backup_path'])), "size": f["size"]} for f in files]
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
else:
|
else:
|
||||||
|
logger.info("Error putting backup file list for server with ID: {}".format(self.server_id))
|
||||||
return[]
|
return[]
|
||||||
|
|
||||||
def jar_update(self):
|
def jar_update(self):
|
||||||
|
@ -212,6 +212,21 @@ class AjaxHandler(BaseHandler):
|
|||||||
svr = self.controller.get_server_obj(server_id)
|
svr = self.controller.get_server_obj(server_id)
|
||||||
svr.agree_eula(user_data['user_id'])
|
svr.agree_eula(user_data['user_id'])
|
||||||
|
|
||||||
|
elif page == "restore_backup":
|
||||||
|
server_id = bleach.clean(self.get_argument('id', None))
|
||||||
|
zip_name = bleach.clean(self.get_argument('zip_file', None))
|
||||||
|
svr_obj = self.controller.servers.get_server_obj(server_id)
|
||||||
|
server_data = self.controller.servers.get_server_data_by_id(server_id)
|
||||||
|
backup_path = svr_obj.backup_path
|
||||||
|
if helper.validate_traversal(backup_path, zip_name):
|
||||||
|
new_server = self.controller.import_zip_server(svr_obj.server_name, os.path.join(backup_path, zip_name), server_data['executable'], '1', '2', server_data['server_port'])
|
||||||
|
new_server_id = new_server
|
||||||
|
new_server = self.controller.get_server_data(new_server)
|
||||||
|
self.controller.rename_backup_dir(server_id, new_server_id, new_server['server_uuid'])
|
||||||
|
self.controller.remove_server(server_id, True)
|
||||||
|
self.redirect('/panel/dashboard')
|
||||||
|
|
||||||
|
|
||||||
@tornado.web.authenticated
|
@tornado.web.authenticated
|
||||||
def delete(self, page):
|
def delete(self, page):
|
||||||
if page == "del_file":
|
if page == "del_file":
|
||||||
|
@ -121,13 +121,22 @@ class PanelHandler(BaseHandler):
|
|||||||
|
|
||||||
elif page == 'dashboard':
|
elif page == 'dashboard':
|
||||||
if exec_user['superuser'] == 1:
|
if exec_user['superuser'] == 1:
|
||||||
|
try:
|
||||||
page_data['servers'] = self.controller.servers.get_all_servers_stats()
|
page_data['servers'] = self.controller.servers.get_all_servers_stats()
|
||||||
|
except IndexError:
|
||||||
|
self.controller.stats.record_stats()
|
||||||
|
page_data['servers'] = self.controller.servers.get_all_servers_stats()
|
||||||
|
|
||||||
for data in page_data['servers']:
|
for data in page_data['servers']:
|
||||||
try:
|
try:
|
||||||
data['stats']['waiting_start'] = self.controller.servers.get_waiting_start(int(data['stats']['server_id']['server_id']))
|
data['stats']['waiting_start'] = self.controller.servers.get_waiting_start(int(data['stats']['server_id']['server_id']))
|
||||||
except:
|
except:
|
||||||
data['stats']['waiting_start'] = False
|
data['stats']['waiting_start'] = False
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
|
user_auth = self.controller.servers.get_authorized_servers_stats(exec_user_id)
|
||||||
|
except IndexError:
|
||||||
|
self.controller.stats.record_stats()
|
||||||
user_auth = self.controller.servers.get_authorized_servers_stats(exec_user_id)
|
user_auth = self.controller.servers.get_authorized_servers_stats(exec_user_id)
|
||||||
logger.debug("ASFR: {}".format(user_auth))
|
logger.debug("ASFR: {}".format(user_auth))
|
||||||
page_data['servers'] = user_auth
|
page_data['servers'] = user_auth
|
||||||
@ -208,9 +217,12 @@ class PanelHandler(BaseHandler):
|
|||||||
if subpage == "backup":
|
if subpage == "backup":
|
||||||
server_info = self.controller.servers.get_server_data_by_id(server_id)
|
server_info = self.controller.servers.get_server_data_by_id(server_id)
|
||||||
page_data['backup_config'] = self.controller.management.get_backup_config(server_id)
|
page_data['backup_config'] = self.controller.management.get_backup_config(server_id)
|
||||||
|
self.controller.refresh_server_settings(server_id)
|
||||||
|
try:
|
||||||
page_data['backup_list'] = server.list_backups()
|
page_data['backup_list'] = server.list_backups()
|
||||||
|
except:
|
||||||
|
page_data['backup_list'] = []
|
||||||
page_data['backup_path'] = helper.wtol_path(server_info["backup_path"])
|
page_data['backup_path'] = helper.wtol_path(server_info["backup_path"])
|
||||||
print(page_data['backup_path'])
|
|
||||||
|
|
||||||
def get_banned_players_html():
|
def get_banned_players_html():
|
||||||
banned_players = self.controller.servers.get_banned_players(server_id)
|
banned_players = self.controller.servers.get_banned_players(server_id)
|
||||||
@ -416,8 +428,6 @@ class PanelHandler(BaseHandler):
|
|||||||
return
|
return
|
||||||
elif Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions:
|
elif Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions:
|
||||||
if str(user_id) != str(exec_user_id):
|
if str(user_id) != str(exec_user_id):
|
||||||
print("USER ID ", user_id)
|
|
||||||
print("EXEC ID ", exec_user_id)
|
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not a user editor")
|
self.redirect("/panel/error?error=Unauthorized access: not a user editor")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -45,8 +45,10 @@
|
|||||||
<a href="/panel/backup_now?id={{ data['server_stats']['server_id']['server_id'] }}" class="btn btn-primary" onclick="backup_started()">{{ translate('serverBackups', 'backupNow', data['lang']) }}</a>
|
<a href="/panel/backup_now?id={{ data['server_stats']['server_id']['server_id'] }}" class="btn btn-primary" onclick="backup_started()">{{ translate('serverBackups', 'backupNow', data['lang']) }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
{% if data['super_user'] %}
|
||||||
<label for="server_name">{{ translate('serverBackups', 'storageLocation', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverBackups', 'storageLocationDesc', data['lang']) }}</small> </label>
|
<label for="server_name">{{ translate('serverBackups', 'storageLocation', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverBackups', 'storageLocationDesc', data['lang']) }}</small> </label>
|
||||||
<input type="text" class="form-control" name="backup_path" id="backup_path" value="{{ data['server_stats']['server_id']['backup_path'] }}" placeholder="{{ translate('serverBackups', 'storageLocation', data['lang']) }}" >
|
<input type="text" class="form-control" name="backup_path" id="backup_path" value="{{ data['server_stats']['server_id']['backup_path'] }}" placeholder="{{ translate('serverBackups', 'storageLocation', data['lang']) }}" >
|
||||||
|
{% end %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -100,6 +102,10 @@
|
|||||||
<i class="fas fa-trash" aria-hidden="true"></i>
|
<i class="fas fa-trash" aria-hidden="true"></i>
|
||||||
{{ translate('serverBackups', 'delete', data['lang']) }}
|
{{ translate('serverBackups', 'delete', data['lang']) }}
|
||||||
</button>
|
</button>
|
||||||
|
<button data-file="{{ backup['path'] }}" class="btn btn-warning restore_button">
|
||||||
|
<i class="fas fa-undo-alt" aria-hidden="true"></i>
|
||||||
|
{{ translate('serverBackups', 'restore', data['lang']) }}
|
||||||
|
</button>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ backup['path'] }}</td>
|
<td>{{ backup['path'] }}</td>
|
||||||
<td>{{ backup['size'] }}</td>
|
<td>{{ backup['size'] }}</td>
|
||||||
@ -162,6 +168,31 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function restore_backup(filename, id){
|
||||||
|
var token = getCookie("_xsrf")
|
||||||
|
|
||||||
|
console.log('Sending Command to restore backup: ' + filename)
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
headers: {'X-XSRFToken': token},
|
||||||
|
url: '/ajax/restore_backup?server_id='+id,
|
||||||
|
data: {
|
||||||
|
zip_file: filename,
|
||||||
|
id: id
|
||||||
|
},
|
||||||
|
success: function(data) {
|
||||||
|
var dialog = bootbox.dialog({
|
||||||
|
message: '<i class="fa fa-spin fa-spinner"></i> {{ translate('serverBackups', 'restoring', data['lang']) }}',
|
||||||
|
closeButton: false
|
||||||
|
});
|
||||||
|
setTimeout(function(){
|
||||||
|
location.href=('/panel/dashboard');
|
||||||
|
}, 15000);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$( document ).ready(function() {
|
$( document ).ready(function() {
|
||||||
console.log( "ready!" );
|
console.log( "ready!" );
|
||||||
$("#backup_config_box").hide();
|
$("#backup_config_box").hide();
|
||||||
@ -211,6 +242,30 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$( ".restore_button" ).click(function() {
|
||||||
|
var file_to_restore = $(this).data("file");
|
||||||
|
|
||||||
|
|
||||||
|
bootbox.confirm({
|
||||||
|
title: "{{ translate('serverBackups', 'restore', data['lang']) }} "+file_to_restore,
|
||||||
|
message: "{{ translate('serverBackups', 'confirmRestore', data['lang']) }}",
|
||||||
|
buttons: {
|
||||||
|
cancel: {
|
||||||
|
label: '<i class="fas fa-times"></i> {{ translate("serverBackups", "cancel", data['lang']) }}'
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
label: '<i class="fas fa-check"></i> {{ translate("serverBackups", "restore", data['lang']) }}'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callback: function (result) {
|
||||||
|
console.log(result);
|
||||||
|
if (result == true) {
|
||||||
|
restore_backup(file_to_restore, {{ data['server_stats']['server_id']['server_id'] }} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -236,34 +236,16 @@ let server_id = '{{ data['server_stats']['server_id']['server_id'] }}';
|
|||||||
function deleteServer (){
|
function deleteServer (){
|
||||||
path = "{{data['server_stats']['server_id']['path']}}";
|
path = "{{data['server_stats']['server_id']['path']}}";
|
||||||
name = "{{data['server_stats']['server_id']['server_name']}}";
|
name = "{{data['server_stats']['server_id']['server_name']}}";
|
||||||
bootbox.confirm({
|
bootbox.dialog({
|
||||||
size: "",
|
size: "",
|
||||||
title: "{% raw translate('serverConfig', 'deleteFilesQuestion', data['lang']) %}",
|
title: "{% raw translate('serverConfig', 'deleteFilesQuestion', data['lang']) %}",
|
||||||
closeButton: false,
|
closeButton: false,
|
||||||
message: "{% raw translate('serverConfig', 'deleteFilesQuestionMessage', data['lang']) %}",
|
message: "{% raw translate('serverConfig', 'deleteFilesQuestionMessage', data['lang']) %}",
|
||||||
buttons: {
|
buttons: {
|
||||||
confirm: {
|
files: {
|
||||||
label: "{{ translate('serverConfig', 'yesDeleteFiles', data['lang']) }}",
|
label: "{{ translate('serverConfig', 'yesDeleteFiles', data['lang']) }}",
|
||||||
className: 'btn-danger',
|
className: 'btn-danger',
|
||||||
},
|
callback: function(){
|
||||||
cancel: {
|
|
||||||
label: "{{ translate('serverConfig', 'noDeleteFiles', data['lang']) }}",
|
|
||||||
className: 'btn-link',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
callback: function(result) {
|
|
||||||
if (!result){
|
|
||||||
deleteServerE()
|
|
||||||
setTimeout(function(){ window.location = '/panel/dashboard'; }, 5000);
|
|
||||||
bootbox.dialog({
|
|
||||||
backdrop: true,
|
|
||||||
title: '{% raw translate("serverConfig", "sendingDelete", data['lang']) %}',
|
|
||||||
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> {% raw translate("serverConfig", "bePatientDelete", data['lang']) %} </div>',
|
|
||||||
closeButton: false
|
|
||||||
})
|
|
||||||
|
|
||||||
return;}
|
|
||||||
else{
|
|
||||||
deleteServerFilesE();
|
deleteServerFilesE();
|
||||||
setTimeout(function(){ window.location = '/panel/dashboard'; }, 5000);
|
setTimeout(function(){ window.location = '/panel/dashboard'; }, 5000);
|
||||||
bootbox.dialog({
|
bootbox.dialog({
|
||||||
@ -272,7 +254,34 @@ let server_id = '{{ data['server_stats']['server_id']['server_id'] }}';
|
|||||||
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> {% raw translate("serverConfig", "bePatientDeleteFiles", data['lang']) %} </div>',
|
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> {% raw translate("serverConfig", "bePatientDeleteFiles", data['lang']) %} </div>',
|
||||||
closeButton: false
|
closeButton: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
noFiles: {
|
||||||
|
label: "{{ translate('serverConfig', 'noDeleteFiles', data['lang']) }}",
|
||||||
|
className: 'btn-outline-danger',
|
||||||
|
callback: function(){
|
||||||
|
deleteServerE()
|
||||||
|
setTimeout(function(){ window.location = '/panel/dashboard'; }, 5000);
|
||||||
|
bootbox.dialog({
|
||||||
|
backdrop: true,
|
||||||
|
title: '{% raw translate("serverConfig", "sendingDelete", data['lang']) %}',
|
||||||
|
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> {% raw translate("serverConfig", "bePatientDelete", data['lang']) %} </div>',
|
||||||
|
closeButton: false
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cancel: {
|
||||||
|
label: "{{ translate('serverConfig', 'cancel', data['lang']) }}",
|
||||||
|
className: 'btn-secondary',
|
||||||
|
callback: function(){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callback: function(result) {
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
"internet": "We have detected the machine running Crafty has no connection to the internet. Client connections to the server may be limited.",
|
"internet": "We have detected the machine running Crafty has no connection to the internet. Client connections to the server may be limited.",
|
||||||
"eulaTitle": "Agree To EULA",
|
"eulaTitle": "Agree To EULA",
|
||||||
"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 Mojang EULA is linked under this message.",
|
||||||
"eulaAgree": "Do you agree?"
|
"eulaAgree": "Do you agree?",
|
||||||
|
"noJava": "Server {} failed to start with error code: We have detected Java is not installed. Please install java then start the server."
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"contact": "Contact Crafty Control Support via Discord",
|
"contact": "Contact Crafty Control Support via Discord",
|
||||||
@ -178,7 +179,10 @@
|
|||||||
"destroyBackup": "Destroy backup \" + file_to_del + \"?",
|
"destroyBackup": "Destroy backup \" + file_to_del + \"?",
|
||||||
"confirmDelete": "Do you want to delete this backup? This cannot be undone.",
|
"confirmDelete": "Do you want to delete this backup? This cannot be undone.",
|
||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
"options": "Options"
|
"options": "Options",
|
||||||
|
"restoring": "Restoring Backup. This may take a while. Please be patient.",
|
||||||
|
"restore": "Restore",
|
||||||
|
"confirmRestore": "Are you sure you want to restore from this backup. All current server files will changed to backup state and will be unrecoverable."
|
||||||
},
|
},
|
||||||
"serverFiles": {
|
"serverFiles": {
|
||||||
"noscript": "The file manager does not work without JavaScript",
|
"noscript": "The file manager does not work without JavaScript",
|
||||||
@ -247,7 +251,7 @@
|
|||||||
"yesDelete": "Yes, delete",
|
"yesDelete": "Yes, delete",
|
||||||
"noDelete": "No, go back",
|
"noDelete": "No, go back",
|
||||||
"deleteFilesQuestion": "Delete server files from machine?",
|
"deleteFilesQuestion": "Delete server files from machine?",
|
||||||
"deleteFilesQuestionMessage": "Would you like Crafty to delete all server files from the host machine?",
|
"deleteFilesQuestionMessage": "Would you like Crafty to delete all server files from the host machine? <br><br><strong>This includes server backups.</strong>",
|
||||||
"yesDeleteFiles": "Yes, delete files",
|
"yesDeleteFiles": "Yes, delete files",
|
||||||
"noDeleteFiles": "No, just remove from panel",
|
"noDeleteFiles": "No, just remove from panel",
|
||||||
"sendingDelete": "Deleting Server",
|
"sendingDelete": "Deleting Server",
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
"internet": "Olemme havainneet, että Crafty -koneella ei ole Internet -yhteyttä. Asiakasyhteydet palvelimelle voivat olla rajalliset.",
|
"internet": "Olemme havainneet, että Crafty -koneella ei ole Internet -yhteyttä. Asiakasyhteydet palvelimelle voivat olla rajalliset.",
|
||||||
"eulaTitle": "Hyväksy EULA",
|
"eulaTitle": "Hyväksy EULA",
|
||||||
"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 Mojang EULA:sta on linkitetty tämän viestin alla.",
|
||||||
"eulaAgree": "Oletko samaa mieltä?"
|
"eulaAgree": "Oletko samaa mieltä?",
|
||||||
|
"noJava": "Server {} failed to start with error code: We have detected Java is not installed. Please install java then start the server."
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"contact": "Ota yhteyttä Crafty Control -tukeen Discordin kautta",
|
"contact": "Ota yhteyttä Crafty Control -tukeen Discordin kautta",
|
||||||
@ -179,7 +180,10 @@
|
|||||||
"destroyBackup": "Tuhotaanko varmuuskopio \" + file_to_del + \"?",
|
"destroyBackup": "Tuhotaanko varmuuskopio \" + file_to_del + \"?",
|
||||||
"confirmDelete": "Haluatko poistaa tämän varmuuskopion? Tätä ei voi peruuttaa.",
|
"confirmDelete": "Haluatko poistaa tämän varmuuskopion? Tätä ei voi peruuttaa.",
|
||||||
"confirm": "Vahvista",
|
"confirm": "Vahvista",
|
||||||
"options": "Vaihtoehtoja"
|
"options": "Vaihtoehtoja",
|
||||||
|
"restoring": "Varmuuskopion palauttaminen. Tämä voi kestää hetken. Olkaa kärsivällisiä.",
|
||||||
|
"restore": "Palauttaa",
|
||||||
|
"confirmRestore": "Haluatko varmasti palauttaa tämän varmuuskopion. Kaikki nykyiset palvelintiedostot muutetaan varmuuskopiotilaan, eikä niitä voida palauttaa."
|
||||||
},
|
},
|
||||||
"serverFiles": {
|
"serverFiles": {
|
||||||
"noscript": "Tiedostojenhallinta ei toimi ilman JavaScriptiä",
|
"noscript": "Tiedostojenhallinta ei toimi ilman JavaScriptiä",
|
||||||
@ -237,7 +241,23 @@
|
|||||||
"save": "Tallenna",
|
"save": "Tallenna",
|
||||||
"cancel": "Peruuta",
|
"cancel": "Peruuta",
|
||||||
"deleteServer": "Poista palvelin",
|
"deleteServer": "Poista palvelin",
|
||||||
"stopBeforeDeleting": "Pysäytä palvelin ennen sen poistamista"
|
"stopBeforeDeleting": "Pysäytä palvelin ennen sen poistamista",
|
||||||
|
"exeUpdateURLDesc": "Direct Download URL for updates.",
|
||||||
|
"exeUpdateURL": "Palvelimen suoritettavan päivityksen URL-osoite",
|
||||||
|
"update": "Päivitä suoritettava",
|
||||||
|
"bePatientUpdate": "Ole kärsivällinen, kun päivitämme palvelinta. Latausajat voivat vaihdella Internet-nopeutesi mukaan.<br /> Tämä näyttö päivittyy hetkessä",
|
||||||
|
"sendingRequest": "Pyyntöäsi lähetetään...",
|
||||||
|
"deleteServerQuestion": "Poistetaanko palvelin?",
|
||||||
|
"deleteServerQuestionMessage": "Haluatko varmasti poistaa tämän palvelimen? Tämän jälkeen ei ole paluuta...",
|
||||||
|
"yesDelete": "Kyllä, poista",
|
||||||
|
"noDelete": "Ei, mene takaisin",
|
||||||
|
"deleteFilesQuestion": "Poistetaanko palvelintiedostot koneelta?",
|
||||||
|
"deleteFilesQuestionMessage": "Haluatko Craftyn poistavan kaikki palvelintiedostot isäntäkoneelta? <br><br><strong> Tämä sisältää palvelimen varmuuskopiot. <strong>",
|
||||||
|
"yesDeleteFiles": "Kyllä, poista tiedostoja",
|
||||||
|
"noDeleteFiles": "Ei, poista vain paneelista",
|
||||||
|
"sendingDelete": "Poistetaan palvelinta",
|
||||||
|
"bePatientDelete": "Ole kärsivällinen, kun poistamme palvelimesi Crafty-paneelista. Tämä näyttö sulkeutuu hetken kuluttua.",
|
||||||
|
"bePatientDeleteFiles" : "Ole kärsivällinen, kun poistamme palvelimesi Crafty-paneelista ja poistamme kaikki tiedostot. Tämä näyttö sulkeutuu hetken kuluttua."
|
||||||
},
|
},
|
||||||
"serverConfigHelp": {
|
"serverConfigHelp": {
|
||||||
"title": "Palvelimen asetukset",
|
"title": "Palvelimen asetukset",
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
"internet": "Nous avons détecté que la machine exécutant Crafty n'a pas de connexion à Internet. Les connexions client au serveur peuvent être limitées.",
|
"internet": "Nous avons détecté que la machine exécutant Crafty n'a pas de connexion à Internet. Les connexions client au serveur peuvent être limitées.",
|
||||||
"eulaTitle": "Accepter le EULA",
|
"eulaTitle": "Accepter le EULA",
|
||||||
"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 Mojang est liée sous ce message.",
|
||||||
"eulaAgree": "Êtes-vous d'accord?"
|
"eulaAgree": "Êtes-vous d'accord?",
|
||||||
|
"noJava": "Server {} failed to start with error code: We have detected Java is not installed. Please install java then start the server."
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"contact": "Contacter le Support de Crafty Control via Discord",
|
"contact": "Contacter le Support de Crafty Control via Discord",
|
||||||
@ -178,7 +179,10 @@
|
|||||||
"destroyBackup": "Supprimer la sauvegarde \" + file_to_del + \" ?",
|
"destroyBackup": "Supprimer la sauvegarde \" + file_to_del + \" ?",
|
||||||
"confirmDelete": "Es-tu sûr de vouloir supprimer cette sauvegarde ? Tu ne pourras pas revenir en arrière.",
|
"confirmDelete": "Es-tu sûr de vouloir supprimer cette sauvegarde ? Tu ne pourras pas revenir en arrière.",
|
||||||
"confirm": "Confirmer",
|
"confirm": "Confirmer",
|
||||||
"options": "Options"
|
"options": "Options",
|
||||||
|
"restoring": "Restauration de la sauvegarde. Cela peut prendre un peu de temps. S'il vous plaît soyez patient.",
|
||||||
|
"restore": "Restaurer",
|
||||||
|
"restoreConfirm": "Êtes-vous sûr de vouloir restaurer à partir de cette sauvegarde. Tous les fichiers du serveur actuel passeront à l'état de sauvegarde et seront irrécupérables."
|
||||||
},
|
},
|
||||||
"serverFiles": {
|
"serverFiles": {
|
||||||
"noscript": "Le gestionnaire de fichiers ne fonctionne pas sans JavaScript",
|
"noscript": "Le gestionnaire de fichiers ne fonctionne pas sans JavaScript",
|
||||||
@ -247,7 +251,7 @@
|
|||||||
"yesDelete": "Oui, Supprimer",
|
"yesDelete": "Oui, Supprimer",
|
||||||
"noDelete": "Non, revenir en arrière",
|
"noDelete": "Non, revenir en arrière",
|
||||||
"deleteFilesQuestion": "Supprimer les fichiers de la machine ?",
|
"deleteFilesQuestion": "Supprimer les fichiers de la machine ?",
|
||||||
"deleteFilesQuestionMessage": "Veux-tu que Crafty supprime tous les fichiers du serveur de la machine hôte ?",
|
"deleteFilesQuestionMessage": "Veux-tu que Crafty supprime tous les fichiers du serveur de la machine hôte? <br><br><strong>Cela inclut les sauvegardes du serveur.</strong>",
|
||||||
"yesDeleteFiles": "Oui, Supprimer les fichier",
|
"yesDeleteFiles": "Oui, Supprimer les fichier",
|
||||||
"noDeleteFiles": "Non, Supprimer uniquement du tabelau de bord",
|
"noDeleteFiles": "Non, Supprimer uniquement du tabelau de bord",
|
||||||
"sendingDelete": "Suppression du Serveur",
|
"sendingDelete": "Suppression du Serveur",
|
||||||
|
346
app/translations/zh_CN.json
Normal file
346
app/translations/zh_CN.json
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
{
|
||||||
|
"login": {
|
||||||
|
"forgotPassword": "忘记密码",
|
||||||
|
"login": "登录",
|
||||||
|
"password": "密码",
|
||||||
|
"username": "用户名"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"hereIsTheError": "错误如下",
|
||||||
|
"contact": "通过 Discord 联系 Crafty Control 支持",
|
||||||
|
"terribleFailure": "多糟糕的错误!",
|
||||||
|
"embarassing": "哦,天哪,这太尴尬了。",
|
||||||
|
"error": "错误!",
|
||||||
|
"start-error": "服务器 {} 启动失败,错误代码为:{}",
|
||||||
|
"closedPort": "我们检测到端口 {} 在主机上可能没有打开,或者被防火墙阻断了。远程客户端到服务器的连接可能受限。",
|
||||||
|
"internet": "我们检测到运行 Crafty 的设备没有网络连接。客户端到服务器的连接可能受限。",
|
||||||
|
"eulaTitle": "同意最终用户许可协议(EULA)",
|
||||||
|
"eulaMsg": "你必须同意最终用户许可协议(EULA)。一份 Mojang EULA 副本的链接在此消息下方。",
|
||||||
|
"eulaAgree": "你同意吗?"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"contact": "通过 Discord 联系 Crafty Control 支持",
|
||||||
|
"unableToFind": "我们无法找到您想要查看的页面。请再试一次,或者返回上一页并刷新。",
|
||||||
|
"notFound": "页面未找到"
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"version": "版本",
|
||||||
|
"copyright": "版权",
|
||||||
|
"allRightsReserved": "保留所有权利"
|
||||||
|
},
|
||||||
|
"sidebar": {
|
||||||
|
"dashboard": "仪表板",
|
||||||
|
"servers": "服务器",
|
||||||
|
"documentation": "文档",
|
||||||
|
"credits": "鸣谢",
|
||||||
|
"contribute": "贡献",
|
||||||
|
"newServer": "创建新服务器",
|
||||||
|
"navigation": "导航栏"
|
||||||
|
},
|
||||||
|
"serverWizard": {
|
||||||
|
"newServer": "创建新服务器",
|
||||||
|
"importServer": "导入现有服务器",
|
||||||
|
"importZip": "从 Zip 文件导入",
|
||||||
|
"serverName": "服务器名称",
|
||||||
|
"serverPath": "服务器路径",
|
||||||
|
"serverType": "服务器类型",
|
||||||
|
"selectType": "选择一种类型",
|
||||||
|
"serverVersion": "服务器版本",
|
||||||
|
"selectVersion": "选择一个版本",
|
||||||
|
"absoluteServerPath": "您的服务器的绝对路径",
|
||||||
|
"serverJar": "服务器 Jar 核心",
|
||||||
|
"minMem": "最小内存",
|
||||||
|
"maxMem": "最大内存",
|
||||||
|
"serverPort": "服务器端口",
|
||||||
|
"defaultPort": "默认值为 25565",
|
||||||
|
"sizeInGB": "大小(以 GB 为单位)",
|
||||||
|
"zipPath": "服务器路径",
|
||||||
|
"absoluteZipPath": "您的服务器的绝对路径",
|
||||||
|
"resetForm": "重置表单",
|
||||||
|
"importServerButton": "导入服务器!",
|
||||||
|
"buildServer": "建立服务器!",
|
||||||
|
"quickSettings": "快捷设置",
|
||||||
|
"quickSettingsDescription": "别担心,你可以稍后再更改这些设置",
|
||||||
|
"myNewServer": "我的新服务器",
|
||||||
|
"bePatient": "请耐心等待,我们正在 ' + (importing ? '导入' : '下载') + ' 服务器",
|
||||||
|
"importing": "导入服务器中……",
|
||||||
|
"downloading": "下载服务器中……",
|
||||||
|
"addRole": "将服务器添加到现有角色",
|
||||||
|
"autoCreate": "如果没有选择任何角色,Crafty 将会为您创建一个!",
|
||||||
|
"selectRole": "选择角色"
|
||||||
|
},
|
||||||
|
"dashboard": {
|
||||||
|
"dashboard": "仪表板",
|
||||||
|
"memUsage": "内存使用量",
|
||||||
|
"cpuUsage": "CPU 使用量",
|
||||||
|
"host": "主机",
|
||||||
|
"players": "玩家",
|
||||||
|
"backups": "备份",
|
||||||
|
"newServer": "创建新服务器",
|
||||||
|
"allServers": "所有服务器",
|
||||||
|
"server": "服务器",
|
||||||
|
"actions": "操作",
|
||||||
|
"world": "世界",
|
||||||
|
"motd": "今日消息(MOTD)",
|
||||||
|
"version": "版本",
|
||||||
|
"status": "状态",
|
||||||
|
"online": "在线",
|
||||||
|
"offline": "离线",
|
||||||
|
"lastBackup": "上次:",
|
||||||
|
"nextBackup": "下次:",
|
||||||
|
"servers": "服务器",
|
||||||
|
"cannotSeeOnMobile": "在移动设备上什么都看不到?",
|
||||||
|
"cannotSee": "什么都看不到?",
|
||||||
|
"cannotSeeOnMobile2": "尝试横向滚动表格。",
|
||||||
|
"max": "最大",
|
||||||
|
"avg": "平均",
|
||||||
|
"bePatientStart": "请耐心等待,我们正在启动服务器。<br /> 稍后此页面会刷新",
|
||||||
|
"bePatientStop": "请耐心等待,我们正在停止服务器。<br /> 稍后此页面会刷新",
|
||||||
|
"bePatientRestart": "请耐心等待,我们正在重启服务器。<br /> 稍后此页面会刷新",
|
||||||
|
"bePatientClone": "请耐心等待,我们正在克隆服务器。<br /> 稍后此页面会刷新",
|
||||||
|
"sendingCommand": "正在发送您的指令",
|
||||||
|
"cpuCurFreq": "当前 CPU 时钟",
|
||||||
|
"cpuMaxFreq": "最大 CPU 时钟",
|
||||||
|
"cpuCores": "CPU 核心",
|
||||||
|
"start": "启动",
|
||||||
|
"stop": "停止",
|
||||||
|
"clone": "克隆",
|
||||||
|
"kill": "杀死进程",
|
||||||
|
"restart": "重启",
|
||||||
|
"killing": "正在杀死进程……",
|
||||||
|
"starting": "延迟启动",
|
||||||
|
"delay-explained": "服务进程已经在刚才启动,并且正在延迟 Minecraft 服务器实例的启动",
|
||||||
|
"no-servers": "当前没有服务器。要开始,请点击",
|
||||||
|
"welcome": "欢迎来到 Crafty Controller"
|
||||||
|
},
|
||||||
|
"accessDenied": {
|
||||||
|
"accessDenied": "拒绝访问",
|
||||||
|
"noAccess": "您没有权限访问此资源",
|
||||||
|
"contactAdmin": "联系您的服务器管理员来获得访问此资源的权限,或者如果您认为您应该有权限访问此资源,请联系支持。",
|
||||||
|
"contact": "通过 Discord 联系 Crafty Control 支持"
|
||||||
|
},
|
||||||
|
"serverStats": {
|
||||||
|
"online": "运行中",
|
||||||
|
"offline": "已停止",
|
||||||
|
"serverStatus": "服务器状态",
|
||||||
|
"serverStarted": "服务器已启动",
|
||||||
|
"serverUptime": "服务器正常运行时间",
|
||||||
|
"players": "玩家",
|
||||||
|
"memUsage": "内存使用量",
|
||||||
|
"cpuUsage": "CPU 使用量",
|
||||||
|
"version": "版本",
|
||||||
|
"description": "简介",
|
||||||
|
"errorCalculatingUptime": "计算正常运行时间时发生错误",
|
||||||
|
"serverTime": "UTC 时间",
|
||||||
|
"unableToConnect": "无法连接"
|
||||||
|
},
|
||||||
|
"serverDetails": {
|
||||||
|
"serverDetails": "服务器详情",
|
||||||
|
"terminal": "终端",
|
||||||
|
"logs": "日志",
|
||||||
|
"schedule": "计划",
|
||||||
|
"backup": "备份",
|
||||||
|
"files": "文件",
|
||||||
|
"config": "配置",
|
||||||
|
"playerControls": "玩家管理"
|
||||||
|
},
|
||||||
|
"serverTerm": {
|
||||||
|
"stopScroll": "停止自动滚动",
|
||||||
|
"commandInput": "输入您的指令",
|
||||||
|
"sendCommand": "发送指令",
|
||||||
|
"start": "启动",
|
||||||
|
"restart": "重启",
|
||||||
|
"stop": "停止",
|
||||||
|
"updating": "更新中……",
|
||||||
|
"starting": "延迟启动",
|
||||||
|
"delay-explained": "服务进程已经在刚才启动,并且正在延迟 Minecraft 服务器实例的启动"
|
||||||
|
},
|
||||||
|
"serverPlayerManagement": {
|
||||||
|
"players": "玩家",
|
||||||
|
"bannedPlayers": "已封禁的玩家",
|
||||||
|
"loadingBannedPlayers": "正在加载已封禁的玩家"
|
||||||
|
},
|
||||||
|
"serverBackups": {
|
||||||
|
"backupNow": "现在备份!",
|
||||||
|
"backupAtMidnight": "午夜自动备份?",
|
||||||
|
"storageLocation": "存储位置",
|
||||||
|
"storageLocationDesc": "您想要在哪里存储备份?",
|
||||||
|
"maxBackups": "最大备份数量",
|
||||||
|
"maxBackupsDesc": "Crafty 不会存储多于 N 个备份,并且会删除最旧的备份(输入 0 以保留所有备份)",
|
||||||
|
"save": "保存",
|
||||||
|
"cancel": "取消",
|
||||||
|
"currentBackups": "现有备份",
|
||||||
|
"download": "下载",
|
||||||
|
"path": "路径",
|
||||||
|
"size": "大小",
|
||||||
|
"delete": "删除",
|
||||||
|
"backupTask": "一个备份任务已开始。",
|
||||||
|
"destroyBackup": "删除备份 \" + file_to_del + \"?",
|
||||||
|
"confirmDelete": "您想要删除这个备份吗?此操作不能撤销。",
|
||||||
|
"confirm": "确认",
|
||||||
|
"options": "选项"
|
||||||
|
},
|
||||||
|
"serverFiles": {
|
||||||
|
"noscript": "文件管理器无法在没有 JavaScript 的情况下使用",
|
||||||
|
"error": "获取文件时发生错误",
|
||||||
|
"files": "文件",
|
||||||
|
"default": "默认",
|
||||||
|
"save": "保存",
|
||||||
|
"editingFile": "正在编辑文件",
|
||||||
|
"delete": "删除",
|
||||||
|
"createFile": "创建文件",
|
||||||
|
"createDir": "创建目录",
|
||||||
|
"rename": "重命名",
|
||||||
|
"createFileQuestion": "您希望新文件叫什么名字?",
|
||||||
|
"createDirQuestion": "您希望新目录叫什么名字?",
|
||||||
|
"renameItemQuestion": "新名称应当是什么?",
|
||||||
|
"deleteItemQuestion": "您确定要删除 \" + name + \" 吗?",
|
||||||
|
"deleteItemQuestionMessage": "您正在删除 \\\"\" + path + \"\\\"!<br/><br/>此操作不可逆转,文件将永远遗失!",
|
||||||
|
"yesDelete": "是,我知道结果",
|
||||||
|
"noDelete": "否",
|
||||||
|
"unsupportedLanguage": "警告:这不是一个受支持的文件类型",
|
||||||
|
"keybindings": "按键绑定",
|
||||||
|
"fileReadError": "文件读取错误",
|
||||||
|
"upload": "上传",
|
||||||
|
"unzip": "解压",
|
||||||
|
"clickUpload": "点击这里来选择您的文件",
|
||||||
|
"uploadTitle": "上传文件到:",
|
||||||
|
"waitUpload": "请等待,我们正在上传您的文件……这需要一点时间。",
|
||||||
|
"stayHere": "请不要离开此页面!",
|
||||||
|
"close": "关闭",
|
||||||
|
"download": "下载"
|
||||||
|
},
|
||||||
|
"serverConfig": {
|
||||||
|
"serverName": "服务器名称",
|
||||||
|
"serverNameDesc": "您希望把这个服务器叫做什么",
|
||||||
|
"serverPath": "服务器运行目录",
|
||||||
|
"serverPathDesc": "完整绝对路径(不包含可执行文件)",
|
||||||
|
"serverLogLocation": "服务器日志路径",
|
||||||
|
"serverLogLocationDesc": "日志文件的完整绝对路径",
|
||||||
|
"serverExecutable": "服务器可执行文件",
|
||||||
|
"serverExecutableDesc": "服务器的可执行文件",
|
||||||
|
"serverExecutionCommand": "服务器运行命令",
|
||||||
|
"serverExecutionCommandDesc": "在隐藏的终端内要如何启动服务器",
|
||||||
|
"serverStopCommand": "服务器停止指令",
|
||||||
|
"serverStopCommandDesc": "要发送给程序以关闭它的指令",
|
||||||
|
"serverAutostartDelay": "服务器自动启动延迟",
|
||||||
|
"serverAutostartDelayDesc": "自动启动前的延迟(如果已在下方启用)",
|
||||||
|
"serverIP": "服务器 IP",
|
||||||
|
"serverIPDesc": "Crafty 要连接以获取状态的 IP(如果遇到问题,尝试使用真实 IP 而非 127.0.0.1)",
|
||||||
|
"serverPort": "服务器端口",
|
||||||
|
"serverPortDesc": "Crafty 要连接以获取状态的端口",
|
||||||
|
"removeOldLogsAfter": "此时间后删除旧日志",
|
||||||
|
"removeOldLogsAfterDesc": "日志文件要在多少天后视为旧文件被删除(0 为关闭)",
|
||||||
|
"serverAutoStart": "服务器自动启动",
|
||||||
|
"serverCrashDetection": "服务器崩溃检测",
|
||||||
|
"save": "保存",
|
||||||
|
"cancel": "取消",
|
||||||
|
"deleteServer": "删除服务器",
|
||||||
|
"stopBeforeDeleting": "请在删除之前停止服务器",
|
||||||
|
"exeUpdateURLDesc": "用于下载更新的直接链接。",
|
||||||
|
"exeUpdateURL": "服务器可执行文件更新地址",
|
||||||
|
"update": "更新可执行文件",
|
||||||
|
"bePatientUpdate": "请耐心等待,我们正在更新服务器。下载时长可能因您的网络速度而异。<br /> 稍后此页面会刷新",
|
||||||
|
"sendingRequest": "正在发送您的请求……",
|
||||||
|
"deleteServerQuestion": "删除服务器?",
|
||||||
|
"deleteServerQuestionMessage": "您确定要删除此服务器吗?在此之后将无法撤销……",
|
||||||
|
"yesDelete": "是,删除",
|
||||||
|
"noDelete": "否,返回",
|
||||||
|
"deleteFilesQuestion": "从设备上删除服务器文件?",
|
||||||
|
"deleteFilesQuestionMessage": "您想要 Crafty 从主机上删除所有的服务器文件吗?",
|
||||||
|
"yesDeleteFiles": "是,删除文件",
|
||||||
|
"noDeleteFiles": "否,只从面板中移除",
|
||||||
|
"sendingDelete": "正在删除服务器",
|
||||||
|
"bePatientDelete": "请耐心等待,我们正在从 Crafty 面板中移除服务器。稍后此页面会关闭。",
|
||||||
|
"bePatientDeleteFiles" : "请耐心等待,我们正在从 Crafty 面板中移除服务器并删除所有文件。稍后此页面会关闭。"
|
||||||
|
},
|
||||||
|
"serverConfigHelp": {
|
||||||
|
"title": "服务器配置区",
|
||||||
|
"desc": "您可以在这里更改您的服务器配置",
|
||||||
|
"perms": [
|
||||||
|
"我们<code>不推荐</code>更改由 Crafty 管理的服务器的路径。",
|
||||||
|
"更改路径<code>可能会</code>破坏一些东西,尤其是在 Linux 这类文件权限锁定得更加严格的操作系统上。",
|
||||||
|
"<br /><br/>",
|
||||||
|
"如果您认为您必须更改服务器存放的位置,你可能需要给予 \"crafty\" 用户对服务器路径的读取/写入权限。",
|
||||||
|
"<br />",
|
||||||
|
"<br />",
|
||||||
|
"在 Linux 上,最好通过执行如下命令来完成:<br />",
|
||||||
|
"<code>",
|
||||||
|
" sudo chown crafty:crafty /您的/服务器/路径 -R<br />",
|
||||||
|
" sudo chmod 2775 /您的/服务器/路径 -R<br />",
|
||||||
|
"</code>"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"panelConfig": {
|
||||||
|
"save": "保存",
|
||||||
|
"cancel": "取消",
|
||||||
|
"delete": "删除"
|
||||||
|
},
|
||||||
|
"datatables": {
|
||||||
|
"i18n": {
|
||||||
|
"decimal": "",
|
||||||
|
"emptyTable": "数据表中没有可用的数据",
|
||||||
|
"info": "正在显示从 _START_ 到 _END_ 的共 _TOTAL_ 个项目",
|
||||||
|
"infoEmpty": "正在显示从 0 到 0 的共 0 个项目",
|
||||||
|
"infoFiltered": "(从 _MAX_ 个项目中筛选出)",
|
||||||
|
"infoPostFix": "",
|
||||||
|
"thousands": ",",
|
||||||
|
"lengthMenu": "显示 _MENU_ 个项目",
|
||||||
|
"loadingRecords": "正在加载……",
|
||||||
|
"processing": "正在处理……",
|
||||||
|
"search": "搜索:",
|
||||||
|
"zeroRecords": "没有找到匹配的记录",
|
||||||
|
"paginate": {
|
||||||
|
"first": "首页",
|
||||||
|
"last": "末页",
|
||||||
|
"next": "下一页",
|
||||||
|
"previous": "上一页"
|
||||||
|
},
|
||||||
|
"aria": {
|
||||||
|
"sortAscending": ":激活对队列的升序排列",
|
||||||
|
"sortDescending": ":激活对队列的降序排列"
|
||||||
|
},
|
||||||
|
"buttons": {
|
||||||
|
"collection": "合集 <span class='ui-button-icon-primary ui-icon ui-icon-triangle-1-s'\/>",
|
||||||
|
"colvis": "列可见性",
|
||||||
|
"colvisRestore": "恢复可见性",
|
||||||
|
"copy": "复制",
|
||||||
|
"copyKeys": "按 ctrl 或 u2318 + C 以复制表中的数据到您的系统剪贴板。<br><br>点击这条消息或者按 escape(ESC)来取消。",
|
||||||
|
"copySuccess": {
|
||||||
|
"1": "复制了 1 行到剪贴板",
|
||||||
|
"_": "复制了 %d 行到剪贴板"
|
||||||
|
},
|
||||||
|
"copyTitle": "复制到剪贴板",
|
||||||
|
"csv": "CSV",
|
||||||
|
"excel": "Excel",
|
||||||
|
"pageLength": {
|
||||||
|
"-1": "显示所有行",
|
||||||
|
"1": "显示 1 行",
|
||||||
|
"_": "显示 %d 行"
|
||||||
|
},
|
||||||
|
"pdf": "PDF",
|
||||||
|
"print": "打印"
|
||||||
|
},
|
||||||
|
"select": {
|
||||||
|
"rows": {
|
||||||
|
"0": "点击某一行以选择",
|
||||||
|
"1": "%d 行已选中",
|
||||||
|
"_": "%d 行已选中"
|
||||||
|
},
|
||||||
|
"cells": {
|
||||||
|
"0": "点击某个单元格以选择",
|
||||||
|
"1": "%d 个单元格已选中",
|
||||||
|
"_": "%d 个单元格已选中"
|
||||||
|
},
|
||||||
|
"columns": {
|
||||||
|
"0": "点击某一列以选择",
|
||||||
|
"1": "%d 列已选中",
|
||||||
|
"_": "%d 列已选中"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"base": {
|
||||||
|
"doesNotWorkWithoutJavascript": "<strong>警告:</strong>Crafty 无法在没有 JavaScript 的情况下使用!"
|
||||||
|
}
|
||||||
|
}
|
11
main.py
11
main.py
@ -1,3 +1,4 @@
|
|||||||
|
from cmd import Cmd
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
@ -78,13 +79,21 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if helper.check_file_exists('/.dockerenv'):
|
||||||
|
console.cyan("Docker environment detected!")
|
||||||
|
else:
|
||||||
|
if helper.checkRoot():
|
||||||
|
console.critical("Root detected. Root/Admin access denied. Run Crafty again with non-elevated permissions.")
|
||||||
|
time.sleep(5)
|
||||||
|
console.critical("Crafty shutting down. Root/Admin access denied.")
|
||||||
|
sys.exit(0)
|
||||||
helper.ensure_logging_setup()
|
helper.ensure_logging_setup()
|
||||||
|
|
||||||
setup_logging(debug=args.verbose)
|
setup_logging(debug=args.verbose)
|
||||||
|
|
||||||
# setting up the logger object
|
# setting up the logger object
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
print("Logging set to: {} ".format(logger.level))
|
console.cyan("Logging set to: {} ".format(logger.level))
|
||||||
|
|
||||||
# print our pretty start message
|
# print our pretty start message
|
||||||
do_intro()
|
do_intro()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
cryptography~=3.4
|
||||||
argon2-cffi~=20.1
|
argon2-cffi~=20.1
|
||||||
bleach~=3.1
|
bleach~=3.1
|
||||||
colorama~=0.4
|
colorama~=0.4
|
||||||
cryptography~=3.4
|
|
||||||
peewee~=3.13
|
peewee~=3.13
|
||||||
pexpect~=4.8
|
pexpect~=4.8
|
||||||
psutil~=5.7
|
psutil~=5.7
|
||||||
@ -11,3 +11,4 @@ requests~=2.26
|
|||||||
schedule~=1.1.0
|
schedule~=1.1.0
|
||||||
termcolor~=1.1
|
termcolor~=1.1
|
||||||
tornado~=6.0
|
tornado~=6.0
|
||||||
|
cached_property==1.5.2
|
Loading…
Reference in New Issue
Block a user