mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'zip-import' into 'dev'
Zip imports - super users - and more See merge request crafty-controller/crafty-commander!128
This commit is contained in:
commit
149cf4fd49
@ -18,6 +18,7 @@ from requests import get
|
|||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
import ctypes
|
import ctypes
|
||||||
import telnetlib
|
import telnetlib
|
||||||
|
from app.classes.web.websocket_helper import websocket_helper
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from socket import gethostname
|
from socket import gethostname
|
||||||
@ -730,6 +731,68 @@ class Helpers:
|
|||||||
output += '</ul>\n'
|
output += '</ul>\n'
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_zip_tree(folder, output=""):
|
||||||
|
file_list = os.listdir(folder)
|
||||||
|
file_list = sorted(file_list, key=str.casefold)
|
||||||
|
output += \
|
||||||
|
"""<ul class="tree-nested d-block" id="{}ul">"""\
|
||||||
|
.format(folder)
|
||||||
|
for raw_filename in file_list:
|
||||||
|
filename = html.escape(raw_filename)
|
||||||
|
rel = os.path.join(folder, raw_filename)
|
||||||
|
if os.path.isdir(rel):
|
||||||
|
output += \
|
||||||
|
"""<li class="tree-item" data-path="{}">
|
||||||
|
\n<div id="{}" data-path="{}" data-name="{}" class="tree-caret tree-ctx-item tree-folder">
|
||||||
|
<input type="radio" name="root_path" value="{}">
|
||||||
|
<span id="{}span" class="files-tree-title" data-path="{}" data-name="{}" onclick="getDirView(event)">
|
||||||
|
<i class="far fa-folder"></i>
|
||||||
|
<i class="far fa-folder-open"></i>
|
||||||
|
{}
|
||||||
|
</span>
|
||||||
|
</input></div><li>
|
||||||
|
\n"""\
|
||||||
|
.format(os.path.join(folder, filename), os.path.join(folder, filename), os.path.join(folder, filename), filename, os.path.join(folder, filename), os.path.join(folder, filename), os.path.join(folder, filename), filename, filename)
|
||||||
|
return output
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_zip_dir(folder, output=""):
|
||||||
|
file_list = os.listdir(folder)
|
||||||
|
file_list = sorted(file_list, key=str.casefold)
|
||||||
|
output += \
|
||||||
|
"""<ul class="tree-nested d-block" id="{}ul">"""\
|
||||||
|
.format(folder)
|
||||||
|
for raw_filename in file_list:
|
||||||
|
filename = html.escape(raw_filename)
|
||||||
|
rel = os.path.join(folder, raw_filename)
|
||||||
|
if os.path.isdir(rel):
|
||||||
|
output += \
|
||||||
|
"""<li class="tree-item" data-path="{}">
|
||||||
|
\n<div id="{}" data-path="{}" data-name="{}" class="tree-caret tree-ctx-item tree-folder">
|
||||||
|
<input type="radio" name="root_path" value="{}">
|
||||||
|
<span id="{}span" class="files-tree-title" data-path="{}" data-name="{}" onclick="getDirView(event)">
|
||||||
|
<i class="far fa-folder"></i>
|
||||||
|
<i class="far fa-folder-open"></i>
|
||||||
|
{}
|
||||||
|
</span>
|
||||||
|
</input></div><li>"""\
|
||||||
|
.format(os.path.join(folder, filename), os.path.join(folder, filename), os.path.join(folder, filename), filename, os.path.join(folder, filename), os.path.join(folder, filename), os.path.join(folder, filename), filename, filename)
|
||||||
|
return output
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def unzipServer(zip_path, user_id):
|
||||||
|
if helper.check_file_perms(zip_path):
|
||||||
|
tempDir = tempfile.mkdtemp()
|
||||||
|
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||||
|
#extracts archive to temp directory
|
||||||
|
zip_ref.extractall(tempDir)
|
||||||
|
if user_id:
|
||||||
|
websocket_helper.broadcast_user(user_id, 'send_temp_path',{
|
||||||
|
'path': tempDir
|
||||||
|
})
|
||||||
|
return
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def in_path(parent_path, child_path):
|
def in_path(parent_path, child_path):
|
||||||
# Smooth out relative path names, note: if you are concerned about symbolic links, you should use os.path.realpath too
|
# Smooth out relative path names, note: if you are concerned about symbolic links, you should use os.path.realpath too
|
||||||
|
@ -295,66 +295,23 @@ class Controller:
|
|||||||
server_id = helper.create_uuid()
|
server_id = helper.create_uuid()
|
||||||
new_server_dir = os.path.join(helper.servers_dir, server_id)
|
new_server_dir = os.path.join(helper.servers_dir, server_id)
|
||||||
backup_path = os.path.join(helper.backup_path, server_id)
|
backup_path = os.path.join(helper.backup_path, server_id)
|
||||||
zip_path = helper.get_os_understandable_path(zip_path)
|
tempDir = helper.get_os_understandable_path(zip_path)
|
||||||
|
helper.ensure_dir_exists(new_server_dir)
|
||||||
if helper.check_file_perms(zip_path):
|
helper.ensure_dir_exists(backup_path)
|
||||||
helper.ensure_dir_exists(new_server_dir)
|
has_properties = False
|
||||||
helper.ensure_dir_exists(backup_path)
|
#extracts archive to temp directory
|
||||||
tempDir = tempfile.mkdtemp()
|
for item in os.listdir(tempDir):
|
||||||
has_properties = False
|
if str(item) == 'server.properties':
|
||||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
has_properties = True
|
||||||
#extracts archive to temp directory
|
try:
|
||||||
zip_ref.extractall(tempDir)
|
shutil.move(os.path.join(tempDir, item), os.path.join(new_server_dir, item))
|
||||||
if len(zip_ref.filelist) > 1:
|
except Exception as ex:
|
||||||
for item in os.listdir(tempDir):
|
logger.error('ERROR IN ZIP IMPORT: {}'.format(ex))
|
||||||
if str(item) == 'server.properties':
|
if not has_properties:
|
||||||
has_properties = True
|
logger.info("No server.properties found on zip file import. Creating one with port selection of {}".format(str(port)))
|
||||||
try:
|
with open(os.path.join(new_server_dir, "server.properties"), "w") as f:
|
||||||
shutil.move(os.path.join(tempDir, item), os.path.join(new_server_dir, item))
|
f.write("server-port={}".format(port))
|
||||||
except Exception as ex:
|
f.close()
|
||||||
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)):
|
|
||||||
#checks if the list of files inside of a dir is greater than 1 or if it's not a directory.
|
|
||||||
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
|
|
||||||
path_list = test.split('/')
|
|
||||||
root_path = path_list[0]
|
|
||||||
if len(path_list) > 1:
|
|
||||||
for i in range(len(path_list)-1):
|
|
||||||
try:
|
|
||||||
root_path = os.path.join(root_path, path_list[i+1])
|
|
||||||
except:
|
|
||||||
root_path = root_path
|
|
||||||
|
|
||||||
full_root_path = os.path.join(tempDir, root_path)
|
|
||||||
|
|
||||||
|
|
||||||
for item in os.listdir(full_root_path):
|
|
||||||
if str(item) == 'server.properties':
|
|
||||||
has_properties = True
|
|
||||||
try:
|
|
||||||
shutil.move(os.path.join(full_root_path, 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:
|
|
||||||
return "false"
|
|
||||||
|
|
||||||
full_jar_path = os.path.join(new_server_dir, server_jar)
|
full_jar_path = os.path.join(new_server_dir, server_jar)
|
||||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||||
|
@ -134,6 +134,22 @@ class AjaxHandler(BaseHandler):
|
|||||||
helper.generate_tree(path))
|
helper.generate_tree(path))
|
||||||
self.finish()
|
self.finish()
|
||||||
|
|
||||||
|
elif page == "get_zip_tree":
|
||||||
|
server_id = self.get_argument('id', None)
|
||||||
|
path = self.get_argument('path', None)
|
||||||
|
|
||||||
|
self.write(helper.get_os_understandable_path(path) + '\n' +
|
||||||
|
helper.generate_zip_tree(path))
|
||||||
|
self.finish()
|
||||||
|
|
||||||
|
elif page == "get_zip_dir":
|
||||||
|
server_id = self.get_argument('id', None)
|
||||||
|
path = self.get_argument('path', None)
|
||||||
|
|
||||||
|
self.write(helper.get_os_understandable_path(path) + '\n' +
|
||||||
|
helper.generate_zip_dir(path))
|
||||||
|
self.finish()
|
||||||
|
|
||||||
elif page == "get_dir":
|
elif page == "get_dir":
|
||||||
server_id = self.get_argument('id', None)
|
server_id = self.get_argument('id', None)
|
||||||
path = self.get_argument('path', None)
|
path = self.get_argument('path', None)
|
||||||
@ -276,6 +292,11 @@ class AjaxHandler(BaseHandler):
|
|||||||
self.controller.remove_server(server_id, True)
|
self.controller.remove_server(server_id, True)
|
||||||
self.redirect('/panel/dashboard')
|
self.redirect('/panel/dashboard')
|
||||||
|
|
||||||
|
elif page == "unzip_server":
|
||||||
|
path = self.get_argument('path', None)
|
||||||
|
helper.unzipServer(path, exec_user_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
@tornado.web.authenticated
|
@tornado.web.authenticated
|
||||||
def delete(self, page):
|
def delete(self, page):
|
||||||
|
@ -16,8 +16,8 @@ from app.classes.shared.main_models import Users, installer
|
|||||||
from app.classes.web.base_handler import BaseHandler
|
from app.classes.web.base_handler import BaseHandler
|
||||||
|
|
||||||
from app.classes.models.servers import Servers
|
from app.classes.models.servers import Servers
|
||||||
from app.classes.models.server_permissions import Enum_Permissions_Server
|
from app.classes.models.server_permissions import Enum_Permissions_Server, Permissions_Servers
|
||||||
from app.classes.models.crafty_permissions import Enum_Permissions_Crafty
|
from app.classes.models.crafty_permissions import Enum_Permissions_Crafty, Permissions_Crafty
|
||||||
from app.classes.models.management import management_helper
|
from app.classes.models.management import management_helper
|
||||||
|
|
||||||
from app.classes.shared.helpers import helper
|
from app.classes.shared.helpers import helper
|
||||||
@ -402,19 +402,22 @@ class PanelHandler(BaseHandler):
|
|||||||
page_data['role-servers'] = auth_role_servers
|
page_data['role-servers'] = auth_role_servers
|
||||||
page_data['user-roles'] = user_roles
|
page_data['user-roles'] = user_roles
|
||||||
|
|
||||||
if exec_user['superuser'] == 1:
|
page_data['users'] = self.controller.users.user_query(exec_user['user_id'])
|
||||||
super_auth_servers = []
|
page_data['roles'] = self.controller.users.user_role_query(exec_user['user_id'])
|
||||||
super_auth_servers.append("Access To All Servers")
|
|
||||||
page_data['users'] = self.controller.users.get_all_users()
|
|
||||||
page_data['roles'] = self.controller.roles.get_all_roles()
|
|
||||||
page_data['auth-servers'][exec_user['user_id']] = super_auth_servers
|
|
||||||
else:
|
|
||||||
page_data['users'] = self.controller.users.user_query(exec_user['user_id'])
|
|
||||||
page_data['roles'] = self.controller.users.user_role_query(exec_user['user_id'])
|
|
||||||
|
|
||||||
for user in page_data['users']:
|
for user in page_data['users']:
|
||||||
if user.user_id != exec_user['user_id']:
|
if user.user_id != exec_user['user_id']:
|
||||||
user.api_token = "********"
|
user.api_token = "********"
|
||||||
|
if exec_user['superuser']:
|
||||||
|
for user in self.controller.users.get_all_users():
|
||||||
|
if user.superuser == 1:
|
||||||
|
super_auth_servers = []
|
||||||
|
super_auth_servers.append("Super User Access To All Servers")
|
||||||
|
page_data['users'] = self.controller.users.get_all_users()
|
||||||
|
page_data['roles'] = self.controller.roles.get_all_roles()
|
||||||
|
page_data['auth-servers'][user.user_id] = super_auth_servers
|
||||||
|
|
||||||
template = "panel/panel_config.html"
|
template = "panel/panel_config.html"
|
||||||
|
|
||||||
elif page == "add_user":
|
elif page == "add_user":
|
||||||
@ -445,6 +448,10 @@ class PanelHandler(BaseHandler):
|
|||||||
page_data['quantity_server'] = self.controller.crafty_perms.list_all_crafty_permissions_quantity_limits()
|
page_data['quantity_server'] = self.controller.crafty_perms.list_all_crafty_permissions_quantity_limits()
|
||||||
page_data['languages'] = []
|
page_data['languages'] = []
|
||||||
page_data['languages'].append(self.controller.users.get_user_lang_by_id(exec_user_id))
|
page_data['languages'].append(self.controller.users.get_user_lang_by_id(exec_user_id))
|
||||||
|
if exec_user['superuser']:
|
||||||
|
page_data['super-disabled'] = ''
|
||||||
|
else:
|
||||||
|
page_data['super-disabled'] = 'disabled'
|
||||||
for file in os.listdir(os.path.join(helper.root_dir, 'app', 'translations')):
|
for file in os.listdir(os.path.join(helper.root_dir, 'app', 'translations')):
|
||||||
if file.endswith('.json'):
|
if file.endswith('.json'):
|
||||||
if file != str(page_data['languages'][0] + '.json'):
|
if file != str(page_data['languages'][0] + '.json'):
|
||||||
@ -470,6 +477,12 @@ class PanelHandler(BaseHandler):
|
|||||||
page_data['quantity_server'] = self.controller.crafty_perms.list_crafty_permissions_quantity_limits(user_id)
|
page_data['quantity_server'] = self.controller.crafty_perms.list_crafty_permissions_quantity_limits(user_id)
|
||||||
page_data['languages'] = []
|
page_data['languages'] = []
|
||||||
page_data['languages'].append(self.controller.users.get_user_lang_by_id(user_id))
|
page_data['languages'].append(self.controller.users.get_user_lang_by_id(user_id))
|
||||||
|
#checks if super user. If not we disable the button.
|
||||||
|
if exec_user['superuser'] and str(exec_user['user_id']) != str(user_id):
|
||||||
|
page_data['super-disabled'] = ''
|
||||||
|
else:
|
||||||
|
page_data['super-disabled'] = 'disabled'
|
||||||
|
|
||||||
for file in sorted(os.listdir(os.path.join(helper.root_dir, 'app', 'translations'))):
|
for file in sorted(os.listdir(os.path.join(helper.root_dir, 'app', 'translations'))):
|
||||||
if file.endswith('.json'):
|
if file.endswith('.json'):
|
||||||
if file != str(page_data['languages'][0] + '.json'):
|
if file != str(page_data['languages'][0] + '.json'):
|
||||||
@ -498,9 +511,13 @@ class PanelHandler(BaseHandler):
|
|||||||
elif page == "remove_user":
|
elif page == "remove_user":
|
||||||
user_id = bleach.clean(self.get_argument('id', None))
|
user_id = bleach.clean(self.get_argument('id', None))
|
||||||
|
|
||||||
if not exec_user['superuser']:
|
if not exec_user['superuser'] and Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions:
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
elif str(exec_user_id) == str(user_id):
|
||||||
|
self.redirect("/panel/error?error=Unauthorized access: you cannot delete yourself")
|
||||||
|
return
|
||||||
elif user_id is None:
|
elif user_id is None:
|
||||||
self.redirect("/panel/error?error=Invalid User ID")
|
self.redirect("/panel/error?error=Invalid User ID")
|
||||||
return
|
return
|
||||||
@ -832,6 +849,18 @@ class PanelHandler(BaseHandler):
|
|||||||
enabled = int(float(self.get_argument('enabled', '0')))
|
enabled = int(float(self.get_argument('enabled', '0')))
|
||||||
regen_api = int(float(self.get_argument('regen_api', '0')))
|
regen_api = int(float(self.get_argument('regen_api', '0')))
|
||||||
lang = bleach.clean(self.get_argument('language'), 'en_EN')
|
lang = bleach.clean(self.get_argument('language'), 'en_EN')
|
||||||
|
if exec_user['superuser']:
|
||||||
|
#Checks if user is trying to change super user status of self. We don't want that. Automatically make them stay super user since we know they are.
|
||||||
|
if str(exec_user['user_id']) != str(user_id):
|
||||||
|
superuser = bleach.clean(self.get_argument('superuser', '0'))
|
||||||
|
else:
|
||||||
|
superuser = '1'
|
||||||
|
else:
|
||||||
|
superuser = '0'
|
||||||
|
if superuser == '1':
|
||||||
|
superuser = True
|
||||||
|
else:
|
||||||
|
superuser = False
|
||||||
|
|
||||||
if Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions:
|
if 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):
|
||||||
@ -910,6 +939,7 @@ class PanelHandler(BaseHandler):
|
|||||||
"regen_api": regen_api,
|
"regen_api": regen_api,
|
||||||
"roles": roles,
|
"roles": roles,
|
||||||
"lang": lang,
|
"lang": lang,
|
||||||
|
"superuser": superuser,
|
||||||
}
|
}
|
||||||
user_crafty_data = {
|
user_crafty_data = {
|
||||||
"permissions_mask": permissions_mask,
|
"permissions_mask": permissions_mask,
|
||||||
@ -934,6 +964,14 @@ class PanelHandler(BaseHandler):
|
|||||||
email = bleach.clean(self.get_argument('email', "default@example.com"))
|
email = bleach.clean(self.get_argument('email', "default@example.com"))
|
||||||
enabled = int(float(self.get_argument('enabled', '0'))),
|
enabled = int(float(self.get_argument('enabled', '0'))),
|
||||||
lang = bleach.clean(self.get_argument('lang', 'en_EN'))
|
lang = bleach.clean(self.get_argument('lang', 'en_EN'))
|
||||||
|
if exec_user['superuser']:
|
||||||
|
superuser = bleach.clean(self.get_argument('superuser', '0'))
|
||||||
|
else:
|
||||||
|
superuser = '0'
|
||||||
|
if superuser == '1':
|
||||||
|
superuser = True
|
||||||
|
else:
|
||||||
|
superuser = False
|
||||||
|
|
||||||
if Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions:
|
if Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions:
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not a user editor")
|
self.redirect("/panel/error?error=Unauthorized access: not a user editor")
|
||||||
@ -982,7 +1020,7 @@ class PanelHandler(BaseHandler):
|
|||||||
else:
|
else:
|
||||||
server_quantity[permission.name] = 0
|
server_quantity[permission.name] = 0
|
||||||
|
|
||||||
user_id = self.controller.users.add_user(username, password=password0, email=email, enabled=enabled)
|
user_id = self.controller.users.add_user(username, password=password0, email=email, enabled=enabled, superuser=superuser)
|
||||||
user_data = {
|
user_data = {
|
||||||
"roles": roles,
|
"roles": roles,
|
||||||
'lang': lang
|
'lang': lang
|
||||||
|
@ -191,12 +191,13 @@ class ServerHandler(BaseHandler):
|
|||||||
self.get_remote_ip())
|
self.get_remote_ip())
|
||||||
elif import_type == 'import_zip':
|
elif import_type == 'import_zip':
|
||||||
# here import_server_path means the zip path
|
# here import_server_path means the zip path
|
||||||
good_path = self.controller.verify_zip_server(import_server_path)
|
zip_path = bleach.clean(self.get_argument('root_path'))
|
||||||
|
good_path = helper.check_path_exists(zip_path)
|
||||||
if not good_path:
|
if not good_path:
|
||||||
self.redirect("/panel/error?error=Zip file not found!")
|
self.redirect("/panel/error?error=Temp path not found!")
|
||||||
return
|
return
|
||||||
|
|
||||||
new_server_id = self.controller.import_zip_server(server_name, import_server_path,import_server_jar, min_mem, max_mem, port)
|
new_server_id = self.controller.import_zip_server(server_name, zip_path, import_server_jar, min_mem, max_mem, port)
|
||||||
if new_server_id == "false":
|
if new_server_id == "false":
|
||||||
self.redirect("/panel/error?error=Zip file not accessible! You can fix this permissions issue with sudo chown -R crafty:crafty {} And sudo chmod 2775 -R {}".format(import_server_path, import_server_path))
|
self.redirect("/panel/error?error=Zip file not accessible! You can fix this permissions issue with sudo chown -R crafty:crafty {} And sudo chmod 2775 -R {}".format(import_server_path, import_server_path))
|
||||||
return
|
return
|
||||||
@ -204,6 +205,8 @@ class ServerHandler(BaseHandler):
|
|||||||
"imported a zip server named \"{}\"".format(server_name), # Example: Admin imported a server named "old creative"
|
"imported a zip server named \"{}\"".format(server_name), # Example: Admin imported a server named "old creative"
|
||||||
new_server_id,
|
new_server_id,
|
||||||
self.get_remote_ip())
|
self.get_remote_ip())
|
||||||
|
#deletes temp dir
|
||||||
|
shutil.rmtree(zip_path)
|
||||||
else:
|
else:
|
||||||
if len(server_parts) != 2:
|
if len(server_parts) != 2:
|
||||||
self.redirect("/panel/error?error=Invalid server data")
|
self.redirect("/panel/error?error=Invalid server data")
|
||||||
|
@ -187,9 +187,9 @@
|
|||||||
|
|
||||||
<label for="superuser" class="form-check-label ml-4 mb-4">
|
<label for="superuser" class="form-check-label ml-4 mb-4">
|
||||||
{% if data['user']['superuser'] %}
|
{% if data['user']['superuser'] %}
|
||||||
<input type="checkbox" class="form-check-input" id="superuser" name="superuser" checked="" value="1" disabled >Super User
|
<input type="checkbox" onclick="superConfirm()" class="form-check-input" id="superuser" name="superuser" checked="" value="1" {{ data['super-disabled'] }} >Super User
|
||||||
{% else %}
|
{% else %}
|
||||||
<input type="checkbox" class="form-check-input" id="superuser" name="superuser" value="1" disabled >Super User
|
<input type="checkbox" onclick="superConfirm()" class="form-check-input" id="superuser" name="superuser" {{ data['super-disabled'] }} value="1" >Super User
|
||||||
{% end %}
|
{% end %}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
@ -229,7 +229,7 @@
|
|||||||
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i> Delete User</a><br />
|
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i> Delete User</a><br />
|
||||||
<small>You cannot delete a superuser</small>
|
<small>You cannot delete a superuser</small>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="/panel/remove_user?id={{ data['user']['user_id'] }}" class="btn btn-sm btn-danger"><i class="fas fa-trash"></i> Delete User</a>
|
<button class="btn btn-sm btn-danger delete-user"><i class="fas fa-trash"></i> Delete User</a>
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -250,6 +250,58 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<script>
|
<script>
|
||||||
|
$( ".delete-user" ).click(function() {
|
||||||
|
var file_to_del = $(this).data("file");
|
||||||
|
|
||||||
|
console.log("User to delete is {{ data['user']['username'] }}");
|
||||||
|
|
||||||
|
bootbox.confirm({
|
||||||
|
title: "{% raw translate('usersConfig', 'deleteUser', data['lang']) %}"+"{{ data['user']['username'] }}",
|
||||||
|
message: "{{ translate('usersConfig', 'confirmDelete', data['lang']) }}",
|
||||||
|
buttons: {
|
||||||
|
cancel: {
|
||||||
|
label: '<i class="fas fa-times"></i> {{ translate("serverBackups", "cancel", data['lang']) }}'
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
className: 'btn-outline-danger',
|
||||||
|
label: '<i class="fas fa-check"></i> {{ translate("serverBackups", "confirm", data['lang']) }}'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callback: function (result) {
|
||||||
|
console.log(result);
|
||||||
|
if (result == true) {
|
||||||
|
location.href="/panel/remove_user?id={{ data['user']['user_id'] }}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function superConfirm() {
|
||||||
|
if (document.getElementById('superuser').checked){
|
||||||
|
bootbox.confirm({
|
||||||
|
title: "{{ translate('panelConfig', 'superConfirmTitle', data['lang']) }}",
|
||||||
|
message: "{{ translate('panelConfig', 'superConfirm', data['lang']) }}",
|
||||||
|
buttons: {
|
||||||
|
cancel: {
|
||||||
|
label: '<i class="fa fa-times"></i> {{ translate('panelConfig', 'cancel', data['lang']) }}'
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
className: 'btn-outline-warning',
|
||||||
|
label: '<i class="fa fa-check"></i> {{ translate('serverBackups', 'confirm', data['lang']) }}'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callback: function (result) {
|
||||||
|
if (result == true){
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
document.getElementById('superuser').checked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
|
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
|
||||||
|
@ -209,7 +209,7 @@
|
|||||||
<br />
|
<br />
|
||||||
<p class="card-description">
|
<p class="card-description">
|
||||||
|
|
||||||
<form method="post" class="server-wizard" onSubmit="wait_msg(true)">
|
<form name="zip" method="post" class="server-wizard" onSubmit="wait_msg(true)">
|
||||||
{% raw xsrf_form_html() %}
|
{% raw xsrf_form_html() %}
|
||||||
<input type="hidden" value="import_zip" name="create_type">
|
<input type="hidden" value="import_zip" name="create_type">
|
||||||
|
|
||||||
@ -229,6 +229,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</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="col-sm-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="server_jar">{{ translate('serverWizard', 'serverJar', data['lang']) }}</label>
|
<label for="server_jar">{{ translate('serverWizard', 'serverJar', data['lang']) }}</label>
|
||||||
@ -288,9 +297,40 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-12" style="visibility: hidden;">
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" class="form-control" id="zip_root_path" name="zip_root_path">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal fade" id="dir_select" tabindex="-1" role="dialog" aria-labelledby="dir_select" aria-hidden="true">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="exampleModalLongTitle">{{ translate('serverWizard', 'selectZipDir', data['lang']) }}</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="tree-ctx-item" id="main-tree-div" data-path="" style="overflow: scroll; max-height:75%;">
|
||||||
|
<input type="radio" id="main-tree-input" name="root_path" value="" checked>
|
||||||
|
<span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path="">
|
||||||
|
<i class="far fa-folder"></i>
|
||||||
|
<i class="far fa-folder-open"></i>
|
||||||
|
{{ translate('serverFiles', 'files', data['lang']) }}
|
||||||
|
</span>
|
||||||
|
</input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ translate('serverWizard', 'close', data['lang']) }}</button>
|
||||||
|
<button type="button" id="modal-okay" data-dismiss="modal" class="btn btn-primary">{{ translate('serverWizard', 'save', data['lang']) }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton', data['lang']) }}</button>
|
<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>
|
<button type="reset" class="btn btn-danger mr-2">{{ translate('serverWizard', 'resetForm', data['lang']) }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -329,10 +369,76 @@
|
|||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<style>
|
||||||
|
/* Remove default bullets */
|
||||||
|
.tree-view,
|
||||||
|
.tree-nested {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the items */
|
||||||
|
.tree-item,
|
||||||
|
.files-tree-title {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none; /* Prevent text selection */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the caret/arrow with a unicode, and style it */
|
||||||
|
.tree-caret .fa-folder {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.tree-caret .fa-folder-open {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
|
||||||
|
.tree-caret-down .fa-folder {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.tree-caret-down .fa-folder-open {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide the nested list */
|
||||||
|
.tree-nested {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
{% block js%}
|
{% block js%}
|
||||||
|
<script>
|
||||||
|
document.getElementById("root_files_button").addEventListener("click", function(){
|
||||||
|
if(document.forms["zip"]["server_path"].value != ""){
|
||||||
|
if(document.getElementById('root_files_button').classList.contains('clicked')){
|
||||||
|
document.getElementById('main-tree-div').innerHTML = '<input type="radio" id="main-tree-input" name="root_path" value="" checked><span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path=""><i class="far fa-folder"></i><i class="far fa-folder-open"></i>{{ translate('serverFiles', 'files', data['lang']) }}</span></input>'
|
||||||
|
}else{
|
||||||
|
document.getElementById('root_files_button').classList.add('clicked')
|
||||||
|
}
|
||||||
|
path = document.forms["zip"]["server_path"].value;
|
||||||
|
console.log(document.forms["zip"]["server_path"].value)
|
||||||
|
var token = getCookie("_xsrf");
|
||||||
|
var dialog = bootbox.dialog({
|
||||||
|
message: '<p class="text-center mb-0"><i class="fa fa-spin fa-cog"></i> Please wait while we gather your files...</p>',
|
||||||
|
closeButton: false
|
||||||
|
});
|
||||||
|
setTimeout(function(){
|
||||||
|
dialog.modal('hide');
|
||||||
|
}, 2000);
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
headers: {'X-XSRFToken': token},
|
||||||
|
url: '/ajax/unzip_server?id=-1&path='+path,
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
bootbox.alert("You must input a path before selecting this button");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function dropDown(event) {
|
function dropDown(event) {
|
||||||
@ -366,10 +472,14 @@ function hide(event) {
|
|||||||
function wait_msg(importing){
|
function wait_msg(importing){
|
||||||
bootbox.alert({
|
bootbox.alert({
|
||||||
title: importing ? '{% raw translate("serverWizard", "importing", data['lang']) %}' : '{% raw translate("serverWizard", "downloading", data['lang']) %}',
|
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']) %}'
|
message: '<i class="fas fa-cloud-download"></i> {% raw translate("serverWizard", "bePatient", data['lang']) %}',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function show_file_tree(){
|
||||||
|
$("#dir_select").modal();
|
||||||
|
}
|
||||||
|
|
||||||
function check_sizes(a, b, changed){
|
function check_sizes(a, b, changed){
|
||||||
max_mem = parseFloat(a.val());
|
max_mem = parseFloat(a.val());
|
||||||
min_mem = parseFloat(b.val());
|
min_mem = parseFloat(b.val());
|
||||||
@ -381,6 +491,97 @@ function hide(event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTreeView(path) {
|
||||||
|
document.getElementById('zip_submit').disabled = false;
|
||||||
|
path = path
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: '/ajax/get_zip_tree?id=-1&path='+path,
|
||||||
|
dataType: 'text',
|
||||||
|
success: function(data){
|
||||||
|
console.log("got response:");
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
dataArr = data.split('\n');
|
||||||
|
serverDir = dataArr.shift(); // Remove & return first element (server directory)
|
||||||
|
text = dataArr.join('\n');
|
||||||
|
|
||||||
|
try{
|
||||||
|
document.getElementById('main-tree-div').innerHTML += text;
|
||||||
|
document.getElementById('main-tree').parentElement.classList.add("clicked");
|
||||||
|
}catch{
|
||||||
|
document.getElementById('files-tree').innerHTML = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementsByClassName('files-tree-title')[0].setAttribute('data-path', serverDir);
|
||||||
|
document.getElementsByClassName('files-tree-title')[0].setAttribute('data-name', 'Files');
|
||||||
|
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getToggleMain(event) {
|
||||||
|
path = event.target.parentElement.getAttribute('data-path');
|
||||||
|
document.getElementById("files-tree").classList.toggle("d-block");
|
||||||
|
document.getElementById(path+"span").classList.toggle("tree-caret-down");
|
||||||
|
document.getElementById(path+"span").classList.toggle("tree-caret");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getDirView(event) {
|
||||||
|
path = event.target.parentElement.getAttribute('data-path');
|
||||||
|
|
||||||
|
if (document.getElementById(path).classList.contains('clicked')){
|
||||||
|
|
||||||
|
var toggler = document.getElementById(path+"span");
|
||||||
|
|
||||||
|
if (toggler.classList.contains('files-tree-title')){
|
||||||
|
document.getElementById(path+"ul").classList.toggle("d-block");
|
||||||
|
document.getElementById(path+"span").classList.toggle("tree-caret-down");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: '/ajax/get_zip_dir?id=-1&path='+path,
|
||||||
|
dataType: 'text',
|
||||||
|
success: function(data){
|
||||||
|
console.log("got response:");
|
||||||
|
|
||||||
|
dataArr = data.split('\n');
|
||||||
|
serverDir = dataArr.shift(); // Remove & return first element (server directory)
|
||||||
|
text = dataArr.join('\n');
|
||||||
|
|
||||||
|
try{
|
||||||
|
document.getElementById(path+"span").classList.add('tree-caret-down');
|
||||||
|
document.getElementById(path).innerHTML += text;
|
||||||
|
document.getElementById(path).classList.add("clicked");
|
||||||
|
}catch{
|
||||||
|
console.log("Bad")
|
||||||
|
}
|
||||||
|
|
||||||
|
var toggler = document.getElementById(path);
|
||||||
|
|
||||||
|
if (toggler.classList.contains('files-tree-title')){
|
||||||
|
document.getElementById(path+"span").addEventListener("click", function caretListener() {
|
||||||
|
document.getElementById(path+"ul").classList.toggle("d-block");
|
||||||
|
document.getElementById(path+"span").classList.toggle("tree-caret-down");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (webSocket) {
|
||||||
|
webSocket.on('send_temp_path', function (data) {
|
||||||
|
document.getElementById('main-tree-input').setAttribute('value', data.path)
|
||||||
|
getTreeView(data.path);
|
||||||
|
show_file_tree();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
//<![CDATA[
|
//<![CDATA[
|
||||||
|
@ -68,7 +68,17 @@
|
|||||||
"downloading": "Downloading Server...",
|
"downloading": "Downloading Server...",
|
||||||
"addRole": "Add Server to Existing Role(s)",
|
"addRole": "Add Server to Existing Role(s)",
|
||||||
"autoCreate": "If none are selected Crafty will make one!",
|
"autoCreate": "If none are selected Crafty will make one!",
|
||||||
"selectRole": "Select Role(s)"
|
"selectRole": "Select Role(s)",
|
||||||
|
"selectZipDir": "Select the directory in the archive you want us to unzip files from",
|
||||||
|
"close": "Close",
|
||||||
|
"save": "Save",
|
||||||
|
"selectRoot": "Select Archive Root Dir",
|
||||||
|
"clickRoot": "Click here to select Root Dir",
|
||||||
|
"explainRoot": "Please click the button below to select your server's root dir inside of the archive"
|
||||||
|
},
|
||||||
|
"usersConfig":{
|
||||||
|
"deleteUser": "Delete user: ",
|
||||||
|
"confirmDelete": "Are you sure you want to delete this user? This action is irreversible."
|
||||||
},
|
},
|
||||||
"dashboard": {
|
"dashboard": {
|
||||||
"dashboard": "Dashboard",
|
"dashboard": "Dashboard",
|
||||||
@ -279,7 +289,10 @@
|
|||||||
"panelConfig": {
|
"panelConfig": {
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"delete": "Delete"
|
"delete": "Delete",
|
||||||
|
"superConfirmTitle": "Enable Super User? Are you sure?",
|
||||||
|
"superConfirm": "Proceed only if you want this user to have access to EVERYTHING (all user accounts, servers, panel configs, etc). They can even remove your super user access."
|
||||||
|
|
||||||
},
|
},
|
||||||
"datatables": {
|
"datatables": {
|
||||||
"i18n": {
|
"i18n": {
|
||||||
|
Loading…
Reference in New Issue
Block a user