mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Improved File Loading, Fixed Port checking
This commit is contained in:
parent
abb7b8af08
commit
7dd24b6b15
@ -94,8 +94,8 @@ class Users_Controller:
|
||||
users_helper.update_user(user_id, up_data)
|
||||
|
||||
@staticmethod
|
||||
def add_user(username, password=None, api_token=None, enabled=True, superuser=False):
|
||||
return users_helper.add_user(username, password=password, api_token=api_token, enabled=enabled, superuser=superuser)
|
||||
def add_user(username, password=None, email="default@example.com", api_token=None, enabled=True, superuser=False):
|
||||
return users_helper.add_user(username, password=password, email=email, api_token=api_token, enabled=enabled, superuser=superuser)
|
||||
|
||||
@staticmethod
|
||||
def remove_user(user_id):
|
||||
|
@ -38,6 +38,7 @@ class Users(Model):
|
||||
last_ip = CharField(default="")
|
||||
username = CharField(default="", unique=True, index=True)
|
||||
password = CharField(default="")
|
||||
email = CharField(default="default@example.com")
|
||||
enabled = BooleanField(default=True)
|
||||
superuser = BooleanField(default=False)
|
||||
api_token = CharField(default="", unique=True, index=True) # we may need to revisit this
|
||||
@ -112,6 +113,7 @@ class helper_users:
|
||||
'last_ip': "127.27.23.89",
|
||||
'username': "SYSTEM",
|
||||
'password': None,
|
||||
'email': "default@example.com",
|
||||
'enabled': True,
|
||||
'superuser': True,
|
||||
'api_token': None,
|
||||
@ -136,7 +138,7 @@ class helper_users:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def add_user(username, password=None, api_token=None, enabled=True, superuser=False):
|
||||
def add_user(username, password=None, email=None, api_token=None, enabled=True, superuser=False):
|
||||
if password is not None:
|
||||
pw_enc = helper.encode_pass(password)
|
||||
else:
|
||||
@ -149,6 +151,7 @@ class helper_users:
|
||||
user_id = Users.insert({
|
||||
Users.username: username.lower(),
|
||||
Users.password: pw_enc,
|
||||
Users.email: email,
|
||||
Users.api_token: api_token,
|
||||
Users.enabled: enabled,
|
||||
Users.superuser: superuser,
|
||||
|
@ -97,13 +97,33 @@ class Helpers:
|
||||
|
||||
@staticmethod
|
||||
def check_port(server_port):
|
||||
try:
|
||||
ip = get('https://api.ipify.org').content.decode('utf8')
|
||||
except:
|
||||
ip = 'google.com'
|
||||
a_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
ip = get('https://api.ipify.org').content.decode('utf8')
|
||||
a_socket.settimeout(20.0)
|
||||
|
||||
location = (ip, server_port)
|
||||
result_of_check = a_socket.connect_ex(location)
|
||||
|
||||
a_socket.close()
|
||||
|
||||
if result_of_check == 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def check_server_conn(server_port):
|
||||
a_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
a_socket.settimeout(10.0)
|
||||
ip = '127.0.0.1'
|
||||
|
||||
location = (ip, server_port)
|
||||
result_of_check = a_socket.connect_ex(location)
|
||||
a_socket.close()
|
||||
|
||||
if result_of_check == 0:
|
||||
return True
|
||||
else:
|
||||
@ -654,29 +674,58 @@ class Helpers:
|
||||
@staticmethod
|
||||
def generate_tree(folder, output=""):
|
||||
file_list = os.listdir(folder)
|
||||
file_list.sort()
|
||||
file_list = sorted(file_list, key=str.casefold)
|
||||
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 data-path="{}" data-name="{}" class="tree-caret tree-ctx-item tree-folder">
|
||||
\n<div id="{}" data-path="{}" data-name="{}" class="tree-caret tree-ctx-item tree-folder">
|
||||
<span id="{}span" class="files-tree-title" data-path="{}" onclick="getDirView(event)">
|
||||
<i class="far fa-folder"></i>
|
||||
<i class="far fa-folder-open"></i>
|
||||
{}
|
||||
</div>
|
||||
\n<ul class="tree-nested">"""\
|
||||
.format(os.path.join(folder, filename), os.path.join(folder, filename), filename, filename)
|
||||
</span>
|
||||
</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), filename)
|
||||
else:
|
||||
output += """<li
|
||||
class="tree-item tree-ctx-item tree-file"
|
||||
data-path="{}"
|
||||
data-name="{}"
|
||||
onclick="clickOnFile(event)"><span style="margin-right: 6px;"><i class="far fa-file"></i></span>{}</li>""".format(os.path.join(folder, filename), filename, filename)
|
||||
return output
|
||||
|
||||
output += helper.generate_tree(rel)
|
||||
output += '</ul>\n</li>'
|
||||
@staticmethod
|
||||
def generate_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">
|
||||
<span id="{}span" class="files-tree-title" data-path="{}" onclick="getDirView(event)">
|
||||
<i class="far fa-folder"></i>
|
||||
<i class="far fa-folder-open"></i>
|
||||
{}
|
||||
</span>
|
||||
</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), filename)
|
||||
else:
|
||||
output += """<li
|
||||
class="tree-item tree-ctx-item tree-file"
|
||||
data-path="{}"
|
||||
data-name="{}"
|
||||
onclick="clickOnFile(event)"><span style="margin-right: 6px;"><i class="far fa-file"></i></span>{}</li>""".format(os.path.join(folder, filename), filename, filename)
|
||||
output += '</ul>\n'
|
||||
return output
|
||||
|
||||
@staticmethod
|
||||
|
@ -130,7 +130,7 @@ class Controller:
|
||||
|
||||
@staticmethod
|
||||
def add_system_user():
|
||||
helper_users.add_user("system", helper.random_string_generator(64), helper_users.new_api_token(), False, False)
|
||||
helper_users.add_user("system", helper.random_string_generator(64), "default@example.com", helper_users.new_api_token(), False, False)
|
||||
|
||||
def get_server_settings(self, server_id):
|
||||
for s in self.servers_list:
|
||||
|
@ -48,7 +48,7 @@ class db_builder:
|
||||
# Users.enabled: True,
|
||||
# Users.superuser: True
|
||||
#}).execute()
|
||||
user_id = users_helper.add_user(username=username, password=password, superuser=True)
|
||||
user_id = users_helper.add_user(username=username, password=password, email="default@example.com", superuser=True)
|
||||
#users_helper.update_user(user_id, user_crafty_data={"permissions_mask":"111", "server_quantity":[-1,-1,-1]} )
|
||||
|
||||
#console.info("API token is {}".format(api_token))
|
||||
|
@ -274,6 +274,8 @@ class Server:
|
||||
self.stats.record_stats()
|
||||
websocket_helper.broadcast_user(user_id, 'send_start_reload', {
|
||||
})
|
||||
check_port_thread = threading.Thread(target=self.check_internet_thread, daemon=True, args=(user_id, user_lang, ), name=f"backup_{self.name}")
|
||||
check_port_thread.start()
|
||||
else:
|
||||
logger.warning("Server PID {} died right after starting - is this a server config issue?".format(self.process.pid))
|
||||
console.warning("Server PID {} died right after starting - is this a server config issue?".format(self.process.pid))
|
||||
@ -284,27 +286,26 @@ class Server:
|
||||
|
||||
self.crash_watcher_schedule = schedule.every(30).seconds.do(self.detect_crash).tag(self.name)
|
||||
|
||||
check_port_thread = threading.Thread(target=self.check_internet_thread, daemon=True, args=(user_id, user_lang, ), name=f"backup_{self.name}")
|
||||
check_port_thread.start()
|
||||
|
||||
def check_internet_thread(self, user_id, user_lang):
|
||||
if user_id:
|
||||
if helper.check_internet():
|
||||
loc_server_port = servers_helper.get_server_stats_by_id(self.server_id)['server_port']
|
||||
port_status = False
|
||||
|
||||
for i in range(3):
|
||||
if helper.check_port(loc_server_port):
|
||||
port_status = True
|
||||
return
|
||||
checked = False
|
||||
while not checked:
|
||||
if helper.check_server_conn(loc_server_port):
|
||||
checked = True
|
||||
result_of_check = helper.check_port(loc_server_port)
|
||||
|
||||
if result_of_check == True:
|
||||
return
|
||||
else:
|
||||
websocket_helper.broadcast_user(user_id, 'send_start_error', {
|
||||
'error': translation.translate('error', 'closedPort', user_lang).format(loc_server_port)
|
||||
})
|
||||
else:
|
||||
time.sleep(5)
|
||||
|
||||
|
||||
if port_status == False:
|
||||
websocket_helper.broadcast_user(user_id, 'send_start_error', {
|
||||
'error': translation.translate('error', 'closedPort', user_lang).format(loc_server_port)
|
||||
})
|
||||
else:
|
||||
websocket_helper.broadcast_user(user_id, 'send_start_error', {
|
||||
'error': translation.translate('error', 'internet', user_lang)
|
||||
|
@ -124,12 +124,26 @@ class AjaxHandler(BaseHandler):
|
||||
|
||||
elif page == "get_tree":
|
||||
server_id = self.get_argument('id', None)
|
||||
path = self.get_argument('path', None)
|
||||
|
||||
if not self.check_server_id(server_id, 'get_tree'): return
|
||||
else: server_id = bleach.clean(server_id)
|
||||
|
||||
self.write(helper.get_os_understandable_path(self.controller.servers.get_server_data_by_id(server_id)['path']) + '\n' +
|
||||
helper.generate_tree(helper.get_os_understandable_path(self.controller.servers.get_server_data_by_id(server_id)['path'])))
|
||||
if helper.validate_traversal(self.controller.servers.get_server_data_by_id(server_id)['path'], path):
|
||||
self.write(helper.get_os_understandable_path(path) + '\n' +
|
||||
helper.generate_tree(path))
|
||||
self.finish()
|
||||
|
||||
elif page == "get_dir":
|
||||
server_id = self.get_argument('id', None)
|
||||
path = self.get_argument('path', None)
|
||||
|
||||
if not self.check_server_id(server_id, 'get_tree'): return
|
||||
else: server_id = bleach.clean(server_id)
|
||||
|
||||
if helper.validate_traversal(self.controller.servers.get_server_data_by_id(server_id)['path'], path):
|
||||
self.write(helper.get_os_understandable_path(path) + '\n' +
|
||||
helper.generate_dir(path))
|
||||
self.finish()
|
||||
|
||||
@tornado.web.authenticated
|
||||
@ -328,7 +342,8 @@ class AjaxHandler(BaseHandler):
|
||||
return
|
||||
|
||||
# Delete the file
|
||||
os.remove(file_path)
|
||||
if helper.validate_traversal(helper.get_os_understandable_path(server_info['path']), file_path):
|
||||
os.remove(file_path)
|
||||
|
||||
elif page == "del_dir":
|
||||
if not permissions['Files'] in user_perms:
|
||||
@ -352,7 +367,8 @@ class AjaxHandler(BaseHandler):
|
||||
|
||||
# Delete the directory
|
||||
# os.rmdir(dir_path) # Would only remove empty directories
|
||||
shutil.rmtree(dir_path) # Removes also when there are contents
|
||||
if helper.validate_traversal(helper.get_os_understandable_path(server_info['path']), dir_path):
|
||||
shutil.rmtree(dir_path) # Removes also when there are contents
|
||||
|
||||
elif page == "delete_server":
|
||||
if not permissions['Config'] in user_perms:
|
||||
|
@ -422,6 +422,7 @@ class PanelHandler(BaseHandler):
|
||||
page_data['user'] = {}
|
||||
page_data['user']['username'] = ""
|
||||
page_data['user']['user_id'] = -1
|
||||
page_data['user']['email'] = ""
|
||||
page_data['user']['enabled'] = True
|
||||
page_data['user']['superuser'] = False
|
||||
page_data['user']['api_token'] = "N/A"
|
||||
@ -489,6 +490,9 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
if exec_user['user_id'] != page_data['user']['user_id']:
|
||||
page_data['user']['api_token'] = "********"
|
||||
|
||||
if exec_user['email'] == 'default@example.com':
|
||||
page_data['user']['email'] = ""
|
||||
template = "panel/panel_edit_user.html"
|
||||
|
||||
elif page == "remove_user":
|
||||
@ -824,6 +828,7 @@ class PanelHandler(BaseHandler):
|
||||
username = bleach.clean(self.get_argument('username', None))
|
||||
password0 = bleach.clean(self.get_argument('password0', None))
|
||||
password1 = bleach.clean(self.get_argument('password1', None))
|
||||
email = bleach.clean(self.get_argument('email', "default@example.com"))
|
||||
enabled = int(float(self.get_argument('enabled', '0')))
|
||||
regen_api = int(float(self.get_argument('regen_api', '0')))
|
||||
lang = bleach.clean(self.get_argument('language'), 'en_EN')
|
||||
@ -894,9 +899,13 @@ class PanelHandler(BaseHandler):
|
||||
else:
|
||||
server_quantity[permission.name] = 0
|
||||
|
||||
# if email is None or "":
|
||||
# email = "default@example.com"
|
||||
|
||||
user_data = {
|
||||
"username": username,
|
||||
"password": password0,
|
||||
"email": email,
|
||||
"enabled": enabled,
|
||||
"regen_api": regen_api,
|
||||
"roles": roles,
|
||||
@ -922,6 +931,7 @@ class PanelHandler(BaseHandler):
|
||||
username = bleach.clean(self.get_argument('username', None))
|
||||
password0 = bleach.clean(self.get_argument('password0', None))
|
||||
password1 = bleach.clean(self.get_argument('password1', None))
|
||||
email = bleach.clean(self.get_argument('email', "default@example.com"))
|
||||
enabled = int(float(self.get_argument('enabled', '0'))),
|
||||
lang = bleach.clean(self.get_argument('lang', 'en_EN'))
|
||||
|
||||
@ -972,7 +982,7 @@ class PanelHandler(BaseHandler):
|
||||
else:
|
||||
server_quantity[permission.name] = 0
|
||||
|
||||
user_id = self.controller.users.add_user(username, password=password0, enabled=enabled)
|
||||
user_id = self.controller.users.add_user(username, password=password0, email=email, enabled=enabled)
|
||||
user_data = {
|
||||
"roles": roles,
|
||||
'lang': lang
|
||||
|
@ -1,10 +1,13 @@
|
||||
from re import X
|
||||
import sys
|
||||
import json
|
||||
import libgravatar
|
||||
import logging
|
||||
import requests
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.helpers import Helpers, helper
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.main_models import fn
|
||||
@ -121,9 +124,27 @@ class PublicHandler(BaseHandler):
|
||||
# log this login
|
||||
self.controller.management.add_to_audit_log(user_data.user_id, "Logged in", 0, self.get_remote_ip())
|
||||
|
||||
if helper.get_setting("allow_nsfw_profile_pictures"):
|
||||
rating = "x"
|
||||
else:
|
||||
rating = "g"
|
||||
|
||||
|
||||
#Get grvatar hash for profile pictures
|
||||
if user_data.email != 'default@example.com' or "":
|
||||
g = libgravatar.Gravatar(libgravatar.sanitize_email(user_data.email))
|
||||
url = g.get_image(size=80, default="404", force_default=False, rating=rating, filetype_extension=False, use_ssl=True) # + "?d=404"
|
||||
if requests.head(url).status_code != 404:
|
||||
profile_url = url
|
||||
else:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
else:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
cookie_data = {
|
||||
"username": user_data.username,
|
||||
"user_id": user_data.user_id,
|
||||
"email": user_data.email,
|
||||
"profile_url": profile_url,
|
||||
"account_type": user_data.superuser,
|
||||
}
|
||||
|
||||
|
@ -12,5 +12,6 @@
|
||||
"show_contribute_link": true,
|
||||
"virtual_terminal_lines": 70,
|
||||
"max_log_lines": 700,
|
||||
"keywords": ["help", "chunk"]
|
||||
"keywords": ["help", "chunk"],
|
||||
"allow_nsfw_profile_pictures": false
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
<link rel="shortcut icon" href="/static/assets/images/favicon.png" />
|
||||
<link rel="stylesheet" href="/static/assets/css/crafty.css">
|
||||
|
||||
</head>
|
||||
|
||||
<body class="dark-theme">
|
||||
|
@ -2,7 +2,11 @@
|
||||
<footer class="footer">
|
||||
<div class="container-fluid ">
|
||||
|
||||
<<<<<<< app/frontend/templates/footer.html
|
||||
<span class="text-muted d-block text-center text-sm-left d-sm-inline-block">{{ translate('footer', 'copyright', data['lang']) }} © 2021 - 2022 <a href="https://craftycontrol.com/" target="_blank">Crafty Controller</a>. {{ translate('footer', 'allRightsReserved', data['lang']) }}.</span>
|
||||
=======
|
||||
<span class="text-muted d-block text-center text-sm-left d-sm-inline-block">{{ translate('footer', 'copyright', data['lang']) }} © 2021 - 2022 <a href="http://www.craftycontrol.com/" target="_blank">Crafty Controller</a>. {{ translate('footer', 'allRightsReserved', data['lang']) }}.</span>
|
||||
>>>>>>> app/frontend/templates/footer.html
|
||||
<span class="float-none float-sm-right d-block mt-1 mt-sm-0 text-center">{{ translate('footer', 'version', data['lang']) }}: {{ data['version_data'] }}
|
||||
</span>
|
||||
</div>
|
||||
|
@ -18,15 +18,16 @@
|
||||
|
||||
<li class="nav-item dropdown user-dropdown">
|
||||
<a class="nav-link dropdown-toggle" id="UserDropdown" href="#" data-toggle="dropdown" aria-expanded="false">
|
||||
<img class="img-xs rounded-circle" src="/static/assets/images/faces-clipart/pic-1.png" alt="Profile image"> </a>
|
||||
<img class="img-xs rounded-circle profile-picture" src="{{ data['user_data']['profile_url'] }}" alt="Profile image"> </a>
|
||||
<div class="dropdown-menu dropdown-menu-right navbar-dropdown" aria-labelledby="UserDropdown">
|
||||
<div class="dropdown-header text-center">
|
||||
<img class="img-md rounded-circle" src="/static/assets/images/faces-clipart/pic-1.png" alt="Profile image">
|
||||
<img class="img-md rounded-circle profile-picture" src="{{ data['user_data']['profile_url'] }}" alt="Profile image">
|
||||
<p class="mb-1 mt-3 font-weight-semibold">{{ data['user_data']['username'] }}</p>
|
||||
<p class="font-weight-light text-muted mb-0">Roles: </p>
|
||||
{% for r in data['user_role'] %}
|
||||
<p class="font-weight-light text-muted mb-0">{{ r }}</p>
|
||||
{% end %}
|
||||
<p class="font-weight-light text-muted mb-0">Email: {{ data['user_data']['email'] }}</p>
|
||||
</div>
|
||||
{% if "Super User" in data['user_role'] %}
|
||||
<a class="dropdown-item" href="/panel/activity_logs"><i class="dropdown-item-icon mdi mdi-calendar-check-outline text-primary"></i> Activity</a>
|
||||
|
@ -80,6 +80,10 @@
|
||||
<label class="form-label" for="password1">Repeat Password <small class="text-muted ml-1"> - leave blank to don't change</small> </label>
|
||||
<input type="password" class="form-control" name="password1" id="password1" value="" placeholder="Repeat Password" >
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="email">Gravatar Email <small class="text-muted ml-1"> - for the profile picture. this is not required. crafty will never make use of user emails. User emails are strictly for Gravatar</small> </label>
|
||||
<input type="email" class="form-control" name="email" id="email" value="{{ data['user']['email'] }}" placeholder="Gravatar Email" >
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="language">User Language:</label>
|
||||
<select class="form-select form-control form-control-lg select-css" id="language" name="language" form="user_form">
|
||||
|
@ -25,7 +25,7 @@
|
||||
</div>
|
||||
<!-- Page Title Header Ends-->
|
||||
|
||||
{% include "parts/details_stats.html %}
|
||||
{% include "parts/details_stats.html" %}
|
||||
|
||||
<div class="row">
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
</div>
|
||||
<!-- Page Title Header Ends-->
|
||||
|
||||
{% include "parts/details_stats.html %}
|
||||
{% include "parts/details_stats.html" %}
|
||||
|
||||
<div class="row">
|
||||
|
||||
@ -134,13 +134,15 @@
|
||||
</style>
|
||||
<ul class="tree-view">
|
||||
<li>
|
||||
<div class="tree-caret tree-ctx-item files-tree-title">
|
||||
<i class="far fa-folder"></i>
|
||||
<i class="far fa-folder-open"></i>
|
||||
{{ translate('serverFiles', 'files', data['lang']) }}
|
||||
<div class="tree-ctx-item" data-path="{{ data['server_stats']['server_id']['path'] }}">
|
||||
<span id="{{ data['server_stats']['server_id']['path'] }}span" class="files-tree-title tree-caret-down" data-path="{{ data['server_stats']['server_id']['path'] }}" onclick="getToggleMain(event)">
|
||||
<i class="far fa-folder"></i>
|
||||
<i class="far fa-folder-open"></i>
|
||||
{{ translate('serverFiles', 'files', data['lang']) }}
|
||||
</span>
|
||||
</div>
|
||||
<ul class="tree-nested d-block" id="files-tree">
|
||||
<li>{{ translate('serverFiles', 'error', data['lang']) }}</li>
|
||||
<li><i class="fa fa-spin fa-spinner"></i>{{ translate('serverFiles', 'loadingRecords', data['lang']) }}</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
@ -648,10 +650,13 @@
|
||||
}, false);
|
||||
});
|
||||
}
|
||||
function getTreeView() {
|
||||
function getTreeView(event) {
|
||||
|
||||
path = '{{ data['server_stats']['server_id']['path'] }}'
|
||||
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: '/ajax/get_tree?id={{ data['server_stats']['server_id']['server_id'] }}',
|
||||
url: '/ajax/get_tree?id={{ data['server_stats']['server_id']['server_id'] }}&path='+path,
|
||||
dataType: 'text',
|
||||
success: function(data){
|
||||
console.log("got response:");
|
||||
@ -661,26 +666,75 @@
|
||||
serverDir = dataArr.shift(); // Remove & return first element (server directory)
|
||||
text = dataArr.join('\n');
|
||||
|
||||
document.getElementById('files-tree').innerHTML = text;
|
||||
try{
|
||||
document.getElementById(path).innerHTML += text;
|
||||
event.target.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');
|
||||
|
||||
setTimeout(function () {setTreeViewContext()}, 1000);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
var toggler = document.getElementsByClassName("tree-caret");
|
||||
var i;
|
||||
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");
|
||||
}
|
||||
|
||||
for (i = 0; i < toggler.length; i++) {
|
||||
if (toggler[i].classList.contains('files-tree-title')) continue;
|
||||
toggler[i].addEventListener("click", function caretListener() {
|
||||
this.parentElement.querySelector(".tree-nested").classList.toggle("d-block");
|
||||
this.classList.toggle("tree-caret-down");
|
||||
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_dir?id={{ data['server_stats']['server_id']['server_id'] }}&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")
|
||||
}
|
||||
|
||||
setTimeout(function () {setTreeViewContext()}, 1000);
|
||||
|
||||
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");
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function setTreeViewContext() {
|
||||
var treeItems = document.getElementsByClassName('tree-ctx-item');
|
||||
@ -875,11 +929,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementsByClassName('files-tree-title')[0].addEventListener("click", function caretListener() {
|
||||
this.parentElement.querySelector(".tree-nested").classList.toggle("d-block");
|
||||
this.classList.toggle("tree-caret-down");
|
||||
});
|
||||
|
||||
getTreeView();
|
||||
setTreeViewContext();
|
||||
|
||||
@ -898,7 +947,7 @@
|
||||
target.classList.add('btn-primary');
|
||||
}
|
||||
|
||||
window.onload = getTreeView();
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -43,36 +43,51 @@
|
||||
|
||||
<div class="form-group">
|
||||
<label for="server_name">Action<small class="text-muted ml-1"></small> </label><br>
|
||||
<select id="action" name="action" onchange="yesnoCheck(this);" class="form-control form-control-lg select-css">
|
||||
<option value="start">Start Server</option>
|
||||
<option value="restart">Restart Server</option>
|
||||
<option value="shutdown">Shutdown Server</option>
|
||||
<option value="command">Custon Command</option>
|
||||
<select id="action" name="action" onchange="basicAdvanced(this);" class="form-control form-control-lg select-css">
|
||||
<option value="basic">Basic</option>
|
||||
<option value="advanced">Advanced</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="server_path">Interval <small class="text-muted ml-1"> - How often you want this task to execute</small> </label>
|
||||
<input type="number" class="form-control" name="server_path" id="server_path" value="{{ data['server_stats']['server_id']['path'] }}" placeholder="Interval" required>
|
||||
<br>
|
||||
<br>
|
||||
<select id="interval_type" name="interval_type" class="form-control form-control-lg select-css">
|
||||
<option value="days">Days</option>
|
||||
<option value="hours">Hours</option>
|
||||
<option value="minutes">Minutes</option>
|
||||
<option value="weeks">Weeks</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="time">Time <small class="text-muted ml-1"> - What time do you want your task to execute?</small> </label>
|
||||
<input type="time" class="form-control" name="time" id="time" value="{{ data['server_stats']['server_id']['log_path'] }}" placeholder="Time" required>
|
||||
</div>
|
||||
<div id="ifYes" style="display: none;">
|
||||
<div id="ifBasic">
|
||||
<div class="form-group">
|
||||
<label for="command">Command <small class="text-muted ml-1"> - What command do you want us to execute? Do not include the '/'</small> </label>
|
||||
<input type="input" class="form-control" name="command" id="command" value="" placeholder="Command" required>
|
||||
<label for="server_name">Action<small class="text-muted ml-1"></small> </label><br>
|
||||
<select id="action" name="action" onchange="yesnoCheck(this);" class="form-control form-control-lg select-css">
|
||||
<option value="start">Start Server</option>
|
||||
<option value="restart">Restart Server</option>
|
||||
<option value="shutdown">Shutdown Server</option>
|
||||
<option value="command">Custon Command</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="server_path">Interval <small class="text-muted ml-1"> - How often you want this task to execute</small> </label>
|
||||
<input type="number" class="form-control" name="server_path" id="server_path" value="{{ data['server_stats']['server_id']['path'] }}" placeholder="Interval" required>
|
||||
<br>
|
||||
<br>
|
||||
<select id="interval_type" name="interval_type" class="form-control form-control-lg select-css">
|
||||
<option value="days">Days</option>
|
||||
<option value="hours">Hours</option>
|
||||
<option value="minutes">Minutes</option>
|
||||
<option value="weeks">Weeks</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="time">Time <small class="text-muted ml-1"> - What time do you want your task to execute?</small> </label>
|
||||
<input type="time" class="form-control" name="time" id="time" value="{{ data['server_stats']['server_id']['log_path'] }}" placeholder="Time" required>
|
||||
</div>
|
||||
<div id="ifYes" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label for="command">Command <small class="text-muted ml-1"> - What command do you want us to execute? Do not include the '/'</small> </label>
|
||||
<input type="input" class="form-control" name="command" id="command" value="" placeholder="Command" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ifAdvanced" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label for="cron">Cron <small class="text-muted ml-1"> - Input your cron string</small> </label>
|
||||
<input type="input" class="form-control" name="cron" id="cron" value="* * * * backup_server" placeholder="Cron" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-check-flat">
|
||||
@ -173,6 +188,15 @@
|
||||
document.getElementById("ifYes").style.display = "none";
|
||||
}
|
||||
}
|
||||
function basicAdvanced(that) {
|
||||
if (that.value == "advanced") {
|
||||
document.getElementById("ifAdvanced").style.display = "block";
|
||||
document.getElementById("ifBasic").style.display = "none";
|
||||
} else {
|
||||
document.getElementById("ifAdvanced").style.display = "none";
|
||||
document.getElementById("ifBasic").style.display = "block";
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
16
app/migrations/20210915205501_user_email.py
Normal file
16
app/migrations/20210915205501_user_email.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Generated by database migrator
|
||||
import peewee
|
||||
|
||||
def migrate(migrator, database, **kwargs):
|
||||
migrator.add_columns('users', email=peewee.CharField(default="default@example.com"))
|
||||
"""
|
||||
Write your migrations here.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
def rollback(migrator, database, **kwargs):
|
||||
migrator.drop_columns('users', ['email'])
|
||||
"""
|
||||
Write your rollback migrations here.
|
||||
"""
|
@ -212,7 +212,8 @@
|
||||
"waitUpload": "Please wait while we upload your files... This may take a while.",
|
||||
"stayHere": "DO NOT LEAVE THIS PAGE!",
|
||||
"close": "Close",
|
||||
"download": "Download"
|
||||
"download": "Download",
|
||||
"loadingRecords": "Loading Files..."
|
||||
},
|
||||
"serverConfig": {
|
||||
"serverName": "Server Name",
|
||||
|
22
main.py
22
main.py
@ -6,6 +6,7 @@ import time
|
||||
import argparse
|
||||
import logging.config
|
||||
import signal
|
||||
import threading
|
||||
from app.classes.controllers.management_controller import Management_Controller
|
||||
|
||||
""" Our custom classes / pip packages """
|
||||
@ -36,6 +37,22 @@ def do_intro():
|
||||
|
||||
console.magenta(intro)
|
||||
|
||||
def check_port_thread():
|
||||
port = helper.get_setting('https_port')
|
||||
checked = False
|
||||
while not checked:
|
||||
if helper.check_server_conn(port):
|
||||
checked = True
|
||||
result_of_check = helper.check_port(port)
|
||||
if result_of_check == True:
|
||||
return
|
||||
else:
|
||||
console.warning("We have detected Crafty's port, {} may not be open on the host network or a firewall is blocking it. Remote client connections to Crafty may be limited.".format(helper.get_setting('https_port')))
|
||||
console.help("If you are not forwarding ports from your public IP or your router does not support hairpin NAT you can safely disregard the previous message.")
|
||||
else:
|
||||
time.sleep(5)
|
||||
return
|
||||
|
||||
|
||||
def setup_logging(debug=True):
|
||||
logging_config_file = os.path.join(os.path.curdir,
|
||||
@ -143,9 +160,8 @@ if __name__ == '__main__':
|
||||
|
||||
if not helper.check_internet():
|
||||
console.warning("We have detected the machine running Crafty has no connection to the internet. Client connections to the server may be limited.")
|
||||
elif not helper.check_port(helper.get_setting('https_port')):
|
||||
console.warning("We have detected Crafty's port, {} may not be open on the host network or a firewall is blocking it. Remote client connections to Crafty may be limited.".format(helper.get_setting('https_port')))
|
||||
console.help("If you are not forwarding ports from your public IP or your router does not support hairpin NAT you can safely disregard the previous message.")
|
||||
check_port_thread = threading.Thread(target=check_port_thread, daemon=True, name="crafty_port_check")
|
||||
check_port_thread.start()
|
||||
|
||||
if not controller.check_system_user():
|
||||
controller.add_system_user()
|
||||
|
@ -3,6 +3,7 @@ argon2-cffi~=20.1
|
||||
bleach~=3.1
|
||||
colorama~=0.4
|
||||
cryptography~=3.4
|
||||
libgravatar~=1.0.0
|
||||
peewee~=3.13
|
||||
pexpect~=4.8
|
||||
psutil~=5.7
|
||||
|
Loading…
Reference in New Issue
Block a user