mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'lukas-bugfixes' into 'dev'
Bugfixes 🐛❌ and more See merge request crafty-controller/crafty-commander!30
This commit is contained in:
commit
9dfc6ed449
@ -17,8 +17,8 @@ try:
|
||||
import requests
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
console.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
@ -16,7 +16,7 @@ try:
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -29,10 +29,6 @@ class MainPrompt(cmd.Cmd, object):
|
||||
# overrides the default Prompt
|
||||
prompt = "Crafty Controller v{} > ".format(helper.get_version_string())
|
||||
|
||||
def __init__(self, tasks_manager):
|
||||
super().__init__()
|
||||
self.tasks_manager = tasks_manager
|
||||
|
||||
@staticmethod
|
||||
def emptyline():
|
||||
pass
|
||||
@ -49,6 +45,9 @@ class MainPrompt(cmd.Cmd, object):
|
||||
console.critical("Unable to write exit file due to error: {}".format(e))
|
||||
|
||||
def do_exit(self, line):
|
||||
self.universal_exit()
|
||||
|
||||
def universal_exit(self):
|
||||
logger.info("Stopping all server daemons / threads")
|
||||
console.info("Stopping all server daemons / threads - This may take a few seconds")
|
||||
websocket_helper.disconnect_all()
|
||||
|
@ -9,8 +9,8 @@ try:
|
||||
from termcolor import colored
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logging.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
print("Import Error: Unable to load {} module".format(e, e.name))
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
print("Import Error: Unable to load {} module".format(e.name))
|
||||
from app.classes.shared.installer import installer
|
||||
installer.do_install()
|
||||
sys.exit(1)
|
||||
|
@ -28,7 +28,7 @@ try:
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
sys.exit(1)
|
||||
|
||||
class Helpers:
|
||||
|
@ -18,8 +18,8 @@ try:
|
||||
import yaml
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
console.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
sys.exit(1)
|
||||
|
||||
schema_version = (0, 1, 0) # major, minor, patch semver
|
||||
@ -502,6 +502,43 @@ class db_shortcuts:
|
||||
return (Users.get(Users.username == username)).user_id
|
||||
except DoesNotExist:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_user_by_api_token(token: str):
|
||||
query = Users.select().where(Users.api_token == token)
|
||||
|
||||
if query.exists():
|
||||
user = model_to_dict(Users.get(Users.api_token == token))
|
||||
# I know it should apply it without setting it but I'm just making sure
|
||||
user = db_shortcuts.add_user_roles(user)
|
||||
return user
|
||||
else:
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def add_user_roles(user):
|
||||
if type(user) == dict:
|
||||
user_id = user['user_id']
|
||||
else:
|
||||
user_id = user.user_id
|
||||
|
||||
# I just copied this code from get_user, it had those TODOs & comments made by mac - Lukas
|
||||
|
||||
roles_query = User_Roles.select().join(Roles, JOIN.INNER).where(User_Roles.user_id == user_id)
|
||||
# TODO: this query needs to be narrower
|
||||
roles = set()
|
||||
for r in roles_query:
|
||||
roles.add(r.role_id.role_id)
|
||||
#servers_query = User_Servers.select().join(Servers, JOIN.INNER).where(User_Servers.user_id == user_id)
|
||||
## TODO: this query needs to be narrower
|
||||
servers = set()
|
||||
#for s in servers_query:
|
||||
# servers.add(s.server_id.server_id)
|
||||
user['roles'] = roles
|
||||
#user['servers'] = servers
|
||||
#logger.debug("user: ({}) {}".format(user_id, user))
|
||||
return user
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_user(user_id):
|
||||
@ -523,19 +560,8 @@ class db_shortcuts:
|
||||
user = model_to_dict(Users.get(Users.user_id == user_id))
|
||||
|
||||
if user:
|
||||
roles_query = User_Roles.select().join(Roles, JOIN.INNER).where(User_Roles.user_id == user_id)
|
||||
# TODO: this query needs to be narrower
|
||||
roles = set()
|
||||
for r in roles_query:
|
||||
roles.add(r.role_id.role_id)
|
||||
#servers_query = User_Servers.select().join(Servers, JOIN.INNER).where(User_Servers.user_id == user_id)
|
||||
## TODO: this query needs to be narrower
|
||||
servers = set()
|
||||
#for s in servers_query:
|
||||
# servers.add(s.server_id.server_id)
|
||||
user['roles'] = roles
|
||||
#user['servers'] = servers
|
||||
#logger.debug("user: ({}) {}".format(user_id, user))
|
||||
# I know it should apply it without setting it but I'm just making sure
|
||||
user = db_shortcuts.add_user_roles(user)
|
||||
return user
|
||||
else:
|
||||
#logger.debug("user: ({}) {}".format(user_id, {}))
|
||||
|
@ -23,8 +23,8 @@ try:
|
||||
import pexpect
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
console.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -130,8 +130,7 @@ class Server:
|
||||
self.process = pexpect.spawn(self.server_command, cwd=self.server_path, timeout=None, encoding=None)
|
||||
self.is_crashed = False
|
||||
|
||||
ts = time.time()
|
||||
self.start_time = str(datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S'))
|
||||
self.start_time = str(datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'))
|
||||
|
||||
if psutil.pid_exists(self.process.pid):
|
||||
self.PID = self.process.pid
|
||||
|
@ -21,7 +21,7 @@ try:
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
sys.exit(1)
|
||||
|
||||
scheduler_intervals = { 'seconds',
|
||||
|
@ -11,14 +11,21 @@ logger = logging.getLogger(__name__)
|
||||
class Translation():
|
||||
def __init__(self):
|
||||
self.translations_path = os.path.join(helper.root_dir, 'app', 'translations')
|
||||
self.cached_translation = None
|
||||
self.cached_translation_lang = None
|
||||
def translate(self, page, word):
|
||||
translated_word = None
|
||||
lang = helper.get_setting('language')
|
||||
fallback_lang = 'en_EN'
|
||||
|
||||
translated_word = \
|
||||
self.translate_inner(page, word, lang) or \
|
||||
self.translate_inner(page, word, fallback_lang)
|
||||
lang_file_exists = helper.check_file_exists(
|
||||
os.path.join(
|
||||
self.translations_path, lang + '.json'
|
||||
)
|
||||
)
|
||||
|
||||
translated_word = self.translate_inner(page, word, lang) \
|
||||
if lang_file_exists else self.translate_inner(page, word, fallback_lang)
|
||||
|
||||
if translated_word:
|
||||
if isinstance(translated_word, dict): return json.dumps(translated_word)
|
||||
@ -31,8 +38,17 @@ class Translation():
|
||||
lang + '.json'
|
||||
)
|
||||
try:
|
||||
with open(lang_file, 'r') as f:
|
||||
data = json.load(f)
|
||||
if not self.cached_translation:
|
||||
with open(lang_file, 'r') as f:
|
||||
data = json.load(f)
|
||||
self.cached_translation = data
|
||||
elif self.cached_translation_lang != lang:
|
||||
with open(lang_file, 'r') as f:
|
||||
data = json.load(f)
|
||||
self.cached_translation = data
|
||||
self.cached_translation_lang = lang
|
||||
else:
|
||||
data = self.cached_translation
|
||||
|
||||
try:
|
||||
translated_page = data[page]
|
||||
|
@ -6,53 +6,63 @@ import tornado.escape
|
||||
import logging
|
||||
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
from app.classes.shared.models import Users
|
||||
from app.classes.shared.models import db_shortcuts
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ApiHandler(BaseHandler):
|
||||
|
||||
def return_response(self, data: dict):
|
||||
def return_response(self, status: int, data: dict):
|
||||
# Define a standardized response
|
||||
self.set_status(status)
|
||||
self.write(data)
|
||||
|
||||
def access_denied(self, user):
|
||||
log.info("User %s was denied access to API route", user)
|
||||
self.set_status(403)
|
||||
self.finish(self.return_response(403, {'error':'ACCESS_DENIED', 'info':'You were denied access to the requested resource'}))
|
||||
def access_denied(self, user, reason=''):
|
||||
if reason: reason = ' because ' + reason
|
||||
log.info("User %s from IP %s was denied access to the API route " + self.request.path + reason, user, self.get_remote_ip())
|
||||
self.finish(self.return_response(403, {
|
||||
'error':'ACCESS_DENIED',
|
||||
'info':'You were denied access to the requested resource'
|
||||
}))
|
||||
|
||||
def authenticate_user(self):
|
||||
def authenticate_user(self) -> bool:
|
||||
try:
|
||||
log.debug("Searching for specified token")
|
||||
# TODO: YEET THIS
|
||||
user_data = Users.get(api_token=self.get_argument('token'))
|
||||
user_data = db_shortcuts.get_user_by_api_token(self.get_argument('token'))
|
||||
log.debug("Checking results")
|
||||
if user_data:
|
||||
# Login successful! Check perms
|
||||
log.info("User {} has authenticated to API".format(user_data.username))
|
||||
log.info("User {} has authenticated to API".format(user_data['username']))
|
||||
# TODO: Role check
|
||||
|
||||
return True # This is to set the "authenticated"
|
||||
else:
|
||||
logging.debug("Auth unsuccessful")
|
||||
return self.access_denied("unknown")
|
||||
except:
|
||||
log.warning("Traceback occurred when authenticating user to API. Most likely wrong token")
|
||||
return self.access_denied("unknown")
|
||||
pass
|
||||
self.access_denied("unknown", "the user provided an invalid token")
|
||||
return False
|
||||
except Exception as e:
|
||||
log.warning("An error occured while authenticating an API user: %s", e)
|
||||
self.access_denied("unknown"), "an error occured while authenticating the user"
|
||||
return False
|
||||
|
||||
|
||||
class ServersStats(ApiHandler):
|
||||
def get(self):
|
||||
"""Get details about all servers"""
|
||||
self.authenticate_user()
|
||||
authenticated = self.authenticate_user()
|
||||
if not authenticated: return
|
||||
# Get server stats
|
||||
# TODO Check perms
|
||||
self.finish(self.write({"servers": self.controller.stats.get_servers_stats()}))
|
||||
|
||||
|
||||
class NodeStats(ApiHandler):
|
||||
def get(self):
|
||||
"""Get stats for particular node"""
|
||||
self.authenticate_user()
|
||||
authenticated = self.authenticate_user()
|
||||
if not authenticated: return
|
||||
# Get node stats
|
||||
node_stats = self.controller.stats.get_node_stats()
|
||||
node_stats.pop("servers")
|
||||
|
@ -61,7 +61,7 @@ class PanelHandler(BaseHandler):
|
||||
}
|
||||
|
||||
# if no servers defined, let's go to the build server area
|
||||
if page_data['server_stats']['total'] == 0 and page != "error":
|
||||
if page_data['server_stats']['total'] == 0 and page != "error" and page != "credits" and page != "contribute":
|
||||
self.set_status(301)
|
||||
self.redirect("/server/step1")
|
||||
return
|
||||
|
@ -15,8 +15,8 @@ try:
|
||||
import bleach
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
console.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -81,13 +81,13 @@ class PublicHandler(BaseHandler):
|
||||
|
||||
# if we don't have a user
|
||||
if not user_data:
|
||||
next_page = "/public/error?error=Login_Failed"
|
||||
next_page = "/public/error?error=Login Failed"
|
||||
self.redirect(next_page)
|
||||
return False
|
||||
|
||||
# if they are disabled
|
||||
if not user_data.enabled:
|
||||
next_page = "/public/error?error=Login_Failed"
|
||||
next_page = "/public/error?error=Login Failed"
|
||||
self.redirect(next_page)
|
||||
return False
|
||||
|
||||
@ -117,6 +117,10 @@ class PublicHandler(BaseHandler):
|
||||
|
||||
next_page = "/panel/dashboard"
|
||||
self.redirect(next_page)
|
||||
else:
|
||||
# log this failed login attempt
|
||||
db_helper.add_to_audit_log(user_data.user_id, "Tried to log in", 0, self.get_remote_ip())
|
||||
self.redirect('/public/error?error=Login Failed')
|
||||
else:
|
||||
self.redirect("/public/login")
|
||||
|
||||
|
@ -19,8 +19,8 @@ try:
|
||||
import bleach
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
console.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -163,6 +163,10 @@ class ServerHandler(BaseHandler):
|
||||
import_server_jar = bleach.clean(self.get_argument('server_jar', ''))
|
||||
server_parts = server.split("|")
|
||||
|
||||
if not server_name:
|
||||
self.redirect("/panel/error?error=Server name cannot be empty!")
|
||||
return False
|
||||
|
||||
if import_type == 'import_jar':
|
||||
good_path = self.controller.verify_jar_server(import_server_path, import_server_jar)
|
||||
|
||||
@ -171,7 +175,12 @@ class ServerHandler(BaseHandler):
|
||||
return False
|
||||
|
||||
new_server_id = self.controller.import_jar_server(server_name, import_server_path,import_server_jar, min_mem, max_mem, port)
|
||||
db_helper.add_to_audit_log(exec_user_data['user_id'],
|
||||
"imported a jar server named \"{}\"".format(server_name), # Example: Admin imported a server named "old creative"
|
||||
new_server_id,
|
||||
self.get_remote_ip())
|
||||
elif import_type == 'import_zip':
|
||||
# here import_server_path means the zip path
|
||||
good_path = self.controller.verify_zip_server(import_server_path)
|
||||
if not good_path:
|
||||
self.redirect("/panel/error?error=Zip file not found!")
|
||||
@ -179,28 +188,24 @@ class ServerHandler(BaseHandler):
|
||||
|
||||
new_server_id = self.controller.import_zip_server(server_name, import_server_path,import_server_jar, min_mem, max_mem, port)
|
||||
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 False
|
||||
db_helper.add_to_audit_log(exec_user_data['user_id'],
|
||||
"imported a zip server named \"{}\"".format(server_name), # Example: Admin imported a server named "old creative"
|
||||
new_server_id,
|
||||
self.get_remote_ip())
|
||||
else:
|
||||
if len(server_parts) != 2:
|
||||
self.redirect("/panel/error?error=Invalid server data")
|
||||
return False
|
||||
server_type, server_version = server_parts
|
||||
# todo: add server type check here and call the correct server add functions if not a jar
|
||||
new_server_id = self.controller.create_jar_server(server_parts[0], server_parts[1], server_name, min_mem, max_mem, port)
|
||||
|
||||
if new_server_id is not None and exec_user_data is not None and len(server_parts) > 1:
|
||||
new_server_id = self.controller.create_jar_server(server_type, server_version, server_name, min_mem, max_mem, port)
|
||||
db_helper.add_to_audit_log(exec_user_data['user_id'],
|
||||
"created a {} {} server named \"{}\"".format(server_parts[1], str(server_parts[0]).capitalize(), server_name), # Example: Admin created a 1.16.5 Bukkit server named "survival"
|
||||
"created a {} {} server named \"{}\"".format(server_version, str(server_type).capitalize(), server_name), # Example: Admin created a 1.16.5 Bukkit server named "survival"
|
||||
new_server_id,
|
||||
self.get_remote_ip())
|
||||
|
||||
elif new_server_id is not None and exec_user_data is not None:
|
||||
db_helper.add_to_audit_log(exec_user_data['user_id'],
|
||||
"created a {} {} server named \"{}\"".format("Minecraft", str(server_parts[0]).capitalize(), server_name), # Example: Admin created a 1.16.5 Bukkit server named "survival"
|
||||
new_server_id,
|
||||
self.get_remote_ip())
|
||||
|
||||
else:
|
||||
logger.error("Unable to create server")
|
||||
console.error("Unable to create server")
|
||||
|
||||
self.controller.stats.record_stats()
|
||||
self.redirect("/panel/dashboard")
|
||||
|
||||
|
15
app/classes/web/static_handler.py
Normal file
15
app/classes/web/static_handler.py
Normal file
@ -0,0 +1,15 @@
|
||||
import tornado.web
|
||||
from typing import (
|
||||
Optional
|
||||
)
|
||||
|
||||
from app.classes.shared.console import console
|
||||
|
||||
class CustomStaticHandler(tornado.web.StaticFileHandler):
|
||||
def validate_absolute_path(self, root: str, absolute_path: str) -> Optional[str]:
|
||||
try:
|
||||
return super().validate_absolute_path(root, absolute_path)
|
||||
except tornado.web.HTTPError as error:
|
||||
if 'HTTP 404: Not Found' in str(error):
|
||||
self.set_status(404)
|
||||
self.finish({'error':'NOT_FOUND', 'info':'The requested resource was not found on the server'})
|
@ -25,6 +25,7 @@ try:
|
||||
from app.classes.web.ajax_handler import AjaxHandler
|
||||
from app.classes.web.api_handler import ServersStats, NodeStats
|
||||
from app.classes.web.websocket_handler import SocketHandler
|
||||
from app.classes.web.static_handler import CustomStaticHandler
|
||||
from app.classes.shared.translation import translation
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
@ -112,9 +113,6 @@ class Webserver:
|
||||
|
||||
logger.info("Starting Web Server on ports http:{} https:{}".format(http_port, https_port))
|
||||
|
||||
console.info("http://{}:{} is up and ready for connection:".format(helper.get_local_ip(), http_port))
|
||||
console.info("https://{}:{} is up and ready for connection:".format(helper.get_local_ip(), https_port))
|
||||
|
||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||
|
||||
tornado.template.Loader('.')
|
||||
@ -143,7 +141,9 @@ class Webserver:
|
||||
autoreload=False,
|
||||
log_function=self.log_function,
|
||||
login_url="/login",
|
||||
default_handler_class=PublicHandler
|
||||
default_handler_class=PublicHandler,
|
||||
static_handler_class=CustomStaticHandler,
|
||||
serve_traceback=debug_errors,
|
||||
)
|
||||
|
||||
self.HTTP_Server = tornado.httpserver.HTTPServer(app)
|
||||
@ -152,6 +152,11 @@ class Webserver:
|
||||
self.HTTPS_Server = tornado.httpserver.HTTPServer(app, ssl_options=cert_objects)
|
||||
self.HTTPS_Server.listen(https_port)
|
||||
|
||||
logger.info("http://{}:{} is up and ready for connections.".format(helper.get_local_ip(), http_port))
|
||||
logger.info("https://{}:{} is up and ready for connections.".format(helper.get_local_ip(), https_port))
|
||||
console.info("http://{}:{} is up and ready for connections.".format(helper.get_local_ip(), http_port))
|
||||
console.info("https://{}:{} is up and ready for connections.".format(helper.get_local_ip(), https_port))
|
||||
|
||||
console.info("Server Init Complete: Listening For Connections:")
|
||||
|
||||
self.ioloop = tornado.ioloop.IOLoop.instance()
|
||||
|
@ -43,10 +43,12 @@
|
||||
<a class="nav-link active" href="/panel/edit_user?id={{ data['user']['user_id'] }}&subpage=config" role="tab" aria-selected="true">
|
||||
<i class="fas fa-cogs"></i>Config</a>
|
||||
</li>
|
||||
{% if data['new_user'] %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/panel/edit_user?id={{ data['user']['user_id'] }}&subpage=other" role="tab" aria-selected="false">
|
||||
<i class="fas fa-folder-tree"></i>Other</a>
|
||||
</li>
|
||||
{% end %}
|
||||
</ul>
|
||||
|
||||
<div class="row">
|
||||
|
@ -86,11 +86,8 @@
|
||||
let startedLocal;
|
||||
|
||||
if (started != null) {
|
||||
console.log('88', '{{ data['server_stats']['started'] }}');
|
||||
{% if data['server_stats']['started'] != 'False' %}
|
||||
startedUTC = '{{ (datetime.datetime.strptime(data['server_stats']['started'], '%Y-%m-%d %H:%M:%S') - datetime.timedelta(seconds=-time.timezone)).strftime('%Y-%m-%d %H:%M:%S') }}';
|
||||
{% end %}
|
||||
console.log('utc', startedUTC);
|
||||
startedUTC = '{{ data['server_stats']['started'] }}';
|
||||
console.log('started utc:', startedUTC);
|
||||
startedUTC = moment.utc(startedUTC, 'YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
let browserUTCOffset = moment().utcOffset(); // This is in minutes
|
||||
@ -98,32 +95,25 @@
|
||||
startedLocal = startedUTC.utcOffset(browserUTCOffset);
|
||||
startedLocalFormatted = startedLocal.format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
console.log('startedLocal', startedLocal);
|
||||
console.log('startedLocalFormatted', startedLocalFormatted);
|
||||
console.log('started local time:', startedLocalFormatted);
|
||||
|
||||
started.textContent = startedLocalFormatted
|
||||
}
|
||||
|
||||
let nowServerTime = '{{ data['time'] }}';
|
||||
let startedServerTime = '{{ data['server_stats']['started'] }}';
|
||||
|
||||
if (uptime != null && started != null) {
|
||||
|
||||
var msdiff = moment(nowServerTime,"YYYY-MM-DD hh:mm:ss")
|
||||
.diff(moment(startedServerTime,"YYYY-MM-DD hh:mm:ss"));
|
||||
var calculateUptime = () => {
|
||||
var msdiff = moment()
|
||||
.diff(startedLocal);
|
||||
var diff = moment.duration(msdiff);
|
||||
|
||||
uptime.textContent = durationToHumanizedString(diff);
|
||||
}
|
||||
|
||||
if (uptime != null && started != null) {
|
||||
|
||||
console.log('startedLocal', startedLocal)
|
||||
if (startedLocal) {
|
||||
var uptimeLoop = setInterval(() => {
|
||||
var msdiff = moment()
|
||||
.diff(startedLocal);
|
||||
var diff = moment.duration(msdiff);
|
||||
|
||||
uptime.textContent = durationToHumanizedString(diff);
|
||||
}, 1000)
|
||||
calculateUptime()
|
||||
var uptimeLoop = setInterval(calculateUptime, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,6 +194,7 @@
|
||||
}
|
||||
</style>
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<h2 id="fileError"></h2>
|
||||
<div id="editorParent">
|
||||
{{ translate('serverFiles', 'editingFile') }} <span id="editingFile"></span>
|
||||
<div id="editor" onresize="editor.resize()" style="resize: both;width: 100%;">file_contents</div>
|
||||
@ -344,10 +345,13 @@
|
||||
console.log('Got File Contents From Server');
|
||||
json = JSON.parse(data)
|
||||
if (json.error) {
|
||||
$('#editorParent').toggle(false)
|
||||
$('#editorParent').toggle(false) // hide
|
||||
$('#fileError').toggle(true) // show
|
||||
$('#fileError').text("{{ translate('serverFiles', 'fileReadError') }}: " + json.error) // show error
|
||||
editor.blur()
|
||||
} else {
|
||||
$('#editorParent').toggle(true)
|
||||
$('#editorParent').toggle(true) // show
|
||||
$('#fileError').toggle(false) // hide
|
||||
setFileName(event.target.innerText);
|
||||
editor.session.setValue(json.content);
|
||||
}
|
||||
@ -376,7 +380,8 @@
|
||||
}
|
||||
|
||||
setFileName();
|
||||
$('#editorParent').toggle(false)
|
||||
$('#editorParent').toggle(false) // show
|
||||
$('#fileError').toggle(false) // hide
|
||||
editor.blur()
|
||||
|
||||
function setMode (extension) {
|
||||
|
@ -14,7 +14,7 @@
|
||||
<br />
|
||||
<p class="card-description">
|
||||
|
||||
<form method="post">
|
||||
<form method="post" class="server-wizard">
|
||||
{% raw xsrf_form_html() %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
@ -47,22 +47,22 @@
|
||||
|
||||
<div class="col-sm-3">
|
||||
<div class="form-group">
|
||||
<label for="min_memory">{{ translate('serverWizard', 'minMem') }} <small> - {{ translate('serverWizard', 'sizeInGB') }}</small></label>
|
||||
<input type="number" class="form-control" id="min_memory" name="min_memory" value="1" step="0.5" min="0.5">
|
||||
<label for="min_memory1">{{ translate('serverWizard', 'minMem') }} <small> - {{ translate('serverWizard', 'sizeInGB') }}</small></label>
|
||||
<input type="number" class="form-control" id="min_memory1" name="min_memory" value="1" step="0.5" min="0.5">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3 offset-1">
|
||||
<div class="form-group">
|
||||
<label for="max_memory">{{ translate('serverWizard', 'maxMem') }} <small> - {{ translate('serverWizard', 'sizeInGB') }}</small></label>
|
||||
<input type="number" class="form-control" id="max_memory" name="max_memory" value="2" step="0.5" min="0.5">
|
||||
<label for="max_memory1">{{ translate('serverWizard', 'maxMem') }} <small> - {{ translate('serverWizard', 'sizeInGB') }}</small></label>
|
||||
<input type="number" class="form-control" id="max_memory1" name="max_memory" value="2" step="0.5" min="0.5">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3 offset-1">
|
||||
<div class="form-group">
|
||||
<label for="port">{{ translate('serverWizard', 'serverPort') }} <small> - {{ translate('serverWizard', 'defaultPort') }}</small></label>
|
||||
<input type="number" class="form-control" id="port" name="port" value="25565" step="1" min="1">
|
||||
<label for="port1">{{ translate('serverWizard', 'serverPort') }} <small> - {{ translate('serverWizard', 'defaultPort') }}</small></label>
|
||||
<input type="number" class="form-control" id="port1" name="port" value="25565" step="1" min="1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -84,7 +84,7 @@
|
||||
<br />
|
||||
<p class="card-description">
|
||||
|
||||
<form method="post">
|
||||
<form method="post" class="server-wizard">
|
||||
{% raw xsrf_form_html() %}
|
||||
<input type="hidden" value="import_jar" name="create_type">
|
||||
<div class="row">
|
||||
@ -120,22 +120,22 @@
|
||||
|
||||
<div class="col-sm-3">
|
||||
<div class="form-group">
|
||||
<label for="min_memory">{{ translate('serverWizard', 'minMem') }} <small> - {{ translate('serverWizard', 'sizeInGB') }}</small></label>
|
||||
<input type="number" class="form-control" id="min_memory" name="min_memory" value="1" step="0.5" min="0.5">
|
||||
<label for="min_memory2">{{ translate('serverWizard', 'minMem') }} <small> - {{ translate('serverWizard', 'sizeInGB') }}</small></label>
|
||||
<input type="number" class="form-control" id="min_memory2" name="min_memory" value="1" step="0.5" min="0.5">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3 offset-1">
|
||||
<div class="form-group">
|
||||
<label for="max_memory">{{ translate('serverWizard', 'maxMem') }} <small> - {{ translate('serverWizard', 'sizeInGB') }}</small></label>
|
||||
<input type="number" class="form-control" id="max_memory" name="max_memory" value="2" step="0.5" min="0.5">
|
||||
<label for="max_memory2">{{ translate('serverWizard', 'maxMem') }} <small> - {{ translate('serverWizard', 'sizeInGB') }}</small></label>
|
||||
<input type="number" class="form-control" id="max_memory2" name="max_memory" value="2" step="0.5" min="0.5">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3 offset-1">
|
||||
<div class="form-group">
|
||||
<label for="port">{{ translate('serverWizard', 'serverPort') }} <small> - {{ translate('serverWizard', 'defaultPort') }}</small></label>
|
||||
<input type="number" class="form-control" id="port" name="port" value="25565" step="1" min="1">
|
||||
<label for="port2">{{ translate('serverWizard', 'serverPort') }} <small> - {{ translate('serverWizard', 'defaultPort') }}</small></label>
|
||||
<input type="number" class="form-control" id="port2" name="port" value="25565" step="1" min="1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -157,7 +157,7 @@
|
||||
<br />
|
||||
<p class="card-description">
|
||||
|
||||
<form method="post">
|
||||
<form method="post" class="server-wizard">
|
||||
{% raw xsrf_form_html() %}
|
||||
<input type="hidden" value="import_zip" name="create_type">
|
||||
|
||||
@ -194,22 +194,22 @@
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="min_memory">{{ translate('serverWizard', 'minMem') }} <small> - {{ translate('serverWizard', 'sizeInGB') }}</small></label>
|
||||
<input type="number" class="form-control" id="min_memory" name="min_memory" value="1" step="0.5" min="0.5">
|
||||
<label for="min_memory3">{{ translate('serverWizard', 'minMem') }} <small> - {{ translate('serverWizard', 'sizeInGB') }}</small></label>
|
||||
<input type="number" class="form-control" id="min_memory3" name="min_memory" value="1" step="0.5" min="0.5">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="max_memory">{{ translate('serverWizard', 'maxMem') }} <small> - {{ translate('serverWizard', 'sizeInGB') }}</small></label>
|
||||
<input type="number" class="form-control" id="max_memory" name="max_memory" value="2" step="0.5" min="0.5">
|
||||
<label for="max_memory3">{{ translate('serverWizard', 'maxMem') }} <small> - {{ translate('serverWizard', 'sizeInGB') }}</small></label>
|
||||
<input type="number" class="form-control" id="max_memory3" name="max_memory" value="2" step="0.5" min="0.5">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="port">{{ translate('serverWizard', 'serverPort') }} <small> - {{ translate('serverWizard', 'defaultPort') }}</small></label>
|
||||
<input type="number" class="form-control" id="port" name="port" value="25565" step="1" min="1">
|
||||
<label for="port3">{{ translate('serverWizard', 'serverPort') }} <small> - {{ translate('serverWizard', 'defaultPort') }}</small></label>
|
||||
<input type="number" class="form-control" id="port3" name="port" value="25565" step="1" min="1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -231,12 +231,19 @@
|
||||
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
console.log('ready');
|
||||
$("#min_memory").change(function(){
|
||||
check_sizes('min');
|
||||
});
|
||||
$("#max_memory").change(function(){
|
||||
check_sizes('max');
|
||||
console.log('ready');
|
||||
var forms = $('form.server-wizard');
|
||||
forms.each(function(i, formEl) {
|
||||
var form = $(formEl);
|
||||
var min = form.find('[name=min_memory]');
|
||||
var max = form.find('[name=max_memory]');
|
||||
console.log(form, min, max)
|
||||
min.change(function(){
|
||||
check_sizes(max, min, 'min');
|
||||
});
|
||||
max.change(function(){
|
||||
check_sizes(max, min, 'max');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -247,14 +254,14 @@
|
||||
});
|
||||
}
|
||||
|
||||
function check_sizes(changed){
|
||||
max_mem = parseFloat($('#max_memory').val());
|
||||
min_mem = parseFloat($('#min_memory').val());
|
||||
function check_sizes(a, b, changed){
|
||||
max_mem = parseFloat(a.val());
|
||||
min_mem = parseFloat(b.val());
|
||||
if (max_mem < min_mem && changed === 'min'){
|
||||
$('#max_memory').val(min_mem)
|
||||
a.val(min_mem)
|
||||
}
|
||||
if (max_mem < min_mem && changed === 'max'){
|
||||
$('#min_memory').val(max_mem)
|
||||
b.val(max_mem)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@
|
||||
"version": "Version",
|
||||
"description": "Description",
|
||||
"errorCalculatingUptime": "Error Calculating Uptime",
|
||||
"serverTime": "Server Time",
|
||||
"serverTime": "UTC Time",
|
||||
"unableToConnect": "Unable To Connect"
|
||||
},
|
||||
"serverDetails": {
|
||||
@ -170,7 +170,8 @@
|
||||
"yesDelete": "Yes, I understand the consequences",
|
||||
"noDelete": "No",
|
||||
"unsupportedLanguage": "Warning: This is not a supported file type",
|
||||
"keybindings": "Keybindings"
|
||||
"keybindings": "Keybindings",
|
||||
"fileReadError": "File read error"
|
||||
},
|
||||
"serverConfig": {
|
||||
"serverName": "Server Name",
|
||||
|
@ -106,7 +106,7 @@
|
||||
"version": "Versio",
|
||||
"description": "Kuvaus",
|
||||
"errorCalculatingUptime": "Virhe laskettaessa käyttöaikaa",
|
||||
"serverTime": "Palvelimen aikaa",
|
||||
"serverTime": "UTC aikaa",
|
||||
"unableToConnect": "Yhteyden muodostaminen epäonnistui"
|
||||
},
|
||||
"serverDetails": {
|
||||
@ -166,11 +166,12 @@
|
||||
"createDirQuestion": "Minkä nimen haluat uudelle hakemistolle?",
|
||||
"renameItemQuestion": "Mikä uuden nimen pitäisi olla?",
|
||||
"deleteItemQuestion": "Haluatko varmasti poistaa \" + name + \"?",
|
||||
"deleteItemQuestionMessage": "Olet poistamassa \\\"\" + path + \"\\\"!<br/><br/>Tämä toiminta on peruuttamaton ja se menetetään ikuisesti!",
|
||||
"deleteItemQuestionMessage": "Olet poistamassa \\\"\" + path + \"\\\"!<br/><br/>Tämä toiminto on peruuttamaton ja se menetetään ikuisesti!",
|
||||
"yesDelete": "Kyllä, ymmärrän seuraukset",
|
||||
"noDelete": "En",
|
||||
"unsupportedLanguage": "Varoitus: Tätä tiedostotyyppiä ei tueta",
|
||||
"keybindings": "Pikanäppäimet"
|
||||
"keybindings": "Pikanäppäimet",
|
||||
"fileReadError": "Tiedoston lukuvirhe"
|
||||
},
|
||||
"serverConfig": {
|
||||
"serverName": "Palvelimen nimi",
|
||||
|
8
main.py
8
main.py
@ -141,10 +141,4 @@ if __name__ == '__main__':
|
||||
logger.info("Recieved SIGINT, stopping Crafty")
|
||||
break
|
||||
|
||||
logger.info("Stopping all server daemons / threads")
|
||||
console.info("Stopping all server daemons / threads - This may take a few seconds")
|
||||
Crafty._clean_shutdown()
|
||||
while True:
|
||||
if tasks_manager.get_main_thread_run_status():
|
||||
sys.exit(0)
|
||||
time.sleep(1)
|
||||
Crafty.universal_exit()
|
||||
|
Loading…
Reference in New Issue
Block a user