mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'dev' into feature/steamcmd
This commit is contained in:
commit
d5475b0121
26
CHANGELOG.md
26
CHANGELOG.md
@ -1,5 +1,25 @@
|
||||
# Changelog
|
||||
## --- [4.0.17] - 2022/11/30
|
||||
## --- [4.0.19] - 2022/TBD
|
||||
### New features
|
||||
TBD
|
||||
### Bug fixes
|
||||
- Fix port tooltip not showing on dash while server online. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/503))
|
||||
- Fix '+' char in path causing any file operation to fail. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/502))
|
||||
- Fix colours on public pages. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/504))
|
||||
- Fix bug where public background was not sent to public pages...like the error page resulting in an error...ironic...I know. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/505))
|
||||
- Be sure a user cannot server import crafty dir. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/506))
|
||||
- Remove Pathlib from sub path check ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/507))
|
||||
- Fix root dir selection in Upload Zip Import ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/508))
|
||||
- Fix stats error on mac M1 chips ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/512))
|
||||
- Fix window path escape on java override ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/513))
|
||||
### Tweaks
|
||||
- Make server directories non-configurable ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/511))
|
||||
- Add popover to server port to detail it's purpose ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/514))
|
||||
### Lang
|
||||
TBD
|
||||
<br><br>
|
||||
|
||||
## --- [4.0.17/4.0.18] - 2022/11/30
|
||||
### New features
|
||||
- Automate forge install process through Crafty server creation for Forge server version 1.16 and greater. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/495))
|
||||
- Tooltip for server port on dashboard. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/496))
|
||||
@ -7,8 +27,10 @@
|
||||
### Bug fixes
|
||||
- Fix no port on bedrock server creation. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/493))
|
||||
### Tweaks
|
||||
- Docker🐋 | Update image base to Ubuntu 22.04 Jammy ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/497))<br>
|
||||
- Docker🐋 | Update image base to Ubuntu 22.04 Jammy. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/497))<br>
|
||||
*(OpenJDK16 Removed, no jammy backport)*
|
||||
### Hotfix (4.0.18)
|
||||
- Apply custom login backgrounds on all public pages. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/499))
|
||||
<br><br>
|
||||
|
||||
## --- [4.0.16] - 2022/10/23
|
||||
|
@ -1,5 +1,5 @@
|
||||
[![Crafty Logo](app/frontend/static/assets/images/logo_long.svg)](https://craftycontrol.com)
|
||||
# Crafty Controller 4.0.17
|
||||
# Crafty Controller 4.0.19
|
||||
> Python based Control Panel for your Minecraft Server
|
||||
|
||||
## What is Crafty Controller?
|
||||
|
@ -86,7 +86,7 @@ class Stats:
|
||||
def get_node_stats(self) -> NodeStatsReturnDict:
|
||||
try:
|
||||
cpu_freq = psutil.cpu_freq()
|
||||
except NotImplementedError:
|
||||
except (NotImplementedError, FileNotFoundError):
|
||||
cpu_freq = None
|
||||
if cpu_freq is None:
|
||||
cpu_freq = psutil._common.scpufreq(current=-1, min=-1, max=-1)
|
||||
|
@ -377,6 +377,17 @@ class Helpers:
|
||||
|
||||
return default_return
|
||||
|
||||
@staticmethod
|
||||
def is_subdir(server_path, root_dir):
|
||||
server_path = os.path.realpath(server_path)
|
||||
root_dir = os.path.realpath(root_dir)
|
||||
|
||||
relative = os.path.relpath(server_path, root_dir)
|
||||
|
||||
if relative.startswith(os.pardir):
|
||||
return False
|
||||
return True
|
||||
|
||||
def set_setting(self, key, new_value):
|
||||
try:
|
||||
with open(self.settings_file, "r", encoding="utf-8") as f:
|
||||
|
@ -4,6 +4,7 @@ import pathlib
|
||||
import re
|
||||
import logging
|
||||
import time
|
||||
import urllib.parse
|
||||
import bleach
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
@ -507,12 +508,12 @@ class AjaxHandler(BaseHandler):
|
||||
self.redirect("/panel/dashboard")
|
||||
|
||||
elif page == "unzip_server":
|
||||
path = self.get_argument("path", None)
|
||||
path = urllib.parse.unquote(self.get_argument("path", ""))
|
||||
if not path:
|
||||
path = os.path.join(
|
||||
self.controller.project_root,
|
||||
"imports",
|
||||
self.get_argument("file", ""),
|
||||
urllib.parse.unquote(self.get_argument("file", "")),
|
||||
)
|
||||
if Helpers.check_file_exists(path):
|
||||
self.helper.unzip_server(path, exec_user["user_id"])
|
||||
|
@ -7,6 +7,7 @@ import json
|
||||
import logging
|
||||
import threading
|
||||
import shlex
|
||||
import urllib.parse
|
||||
import bleach
|
||||
import requests
|
||||
import tornado.web
|
||||
@ -289,6 +290,7 @@ class PanelHandler(BaseHandler):
|
||||
page_data: t.Dict[str, t.Any] = {
|
||||
# todo: make this actually pull and compare version data
|
||||
"update_available": self.helper.update_available,
|
||||
"background": self.controller.cached_login,
|
||||
"serverTZ": tz,
|
||||
"version_data": self.helper.get_version_string(),
|
||||
"failed_servers": self.controller.servers.failed_servers,
|
||||
@ -806,9 +808,15 @@ class PanelHandler(BaseHandler):
|
||||
user_roles_list = self.controller.users.get_user_roles_names(
|
||||
user.user_id
|
||||
)
|
||||
user_servers = self.controller.servers.get_authorized_servers(
|
||||
user.user_id
|
||||
)
|
||||
try:
|
||||
user_servers = self.controller.servers.get_authorized_servers(
|
||||
user.user_id
|
||||
)
|
||||
except:
|
||||
return self.redirect(
|
||||
"/panel/error?error=Cannot load panel config"
|
||||
" while servers are unloaded"
|
||||
)
|
||||
servers = []
|
||||
for server in user_servers:
|
||||
if server.name not in servers:
|
||||
@ -1386,9 +1394,10 @@ class PanelHandler(BaseHandler):
|
||||
template = "panel/activity_logs.html"
|
||||
|
||||
elif page == "download_file":
|
||||
file = Helpers.get_os_understandable_path(self.get_argument("path", ""))
|
||||
name = self.get_argument("name", "")
|
||||
|
||||
file = Helpers.get_os_understandable_path(
|
||||
urllib.parse.unquote(self.get_argument("path", ""))
|
||||
)
|
||||
name = urllib.parse.unquote(self.get_argument("name", ""))
|
||||
server_id = self.check_server_id()
|
||||
if server_id is None:
|
||||
return
|
||||
@ -1551,7 +1560,10 @@ class PanelHandler(BaseHandler):
|
||||
return
|
||||
if java_selection:
|
||||
try:
|
||||
execution_list = shlex.split(execution_command)
|
||||
if self.helper.is_os_windows():
|
||||
execution_list = shlex.split(execution_command, posix=False)
|
||||
else:
|
||||
execution_list = shlex.split(execution_command, posix=True)
|
||||
except ValueError:
|
||||
self.redirect(
|
||||
"/panel/error?error=Invalid execution command. Java path"
|
||||
@ -1603,7 +1615,6 @@ class PanelHandler(BaseHandler):
|
||||
if Helpers.validate_traversal(
|
||||
self.helper.get_servers_root_dir(), server_path
|
||||
):
|
||||
server_obj.path = server_path
|
||||
server_obj.log_path = log_path
|
||||
if Helpers.validate_traversal(
|
||||
self.helper.get_servers_root_dir(), executable
|
||||
@ -1615,7 +1626,6 @@ class PanelHandler(BaseHandler):
|
||||
server_obj.executable_update_url = executable_update_url
|
||||
server_obj.show_status = show_status
|
||||
else:
|
||||
server_obj.path = server_obj.path
|
||||
server_obj.log_path = server_obj.log_path
|
||||
server_obj.executable = server_obj.executable
|
||||
server_obj.execution_command = execution_command
|
||||
|
@ -39,6 +39,7 @@ class PublicHandler(BaseHandler):
|
||||
"lang": self.helper.get_setting("language"),
|
||||
"lang_page": self.helper.get_lang_page(self.helper.get_setting("language")),
|
||||
"query": "",
|
||||
"background": self.controller.cached_login,
|
||||
}
|
||||
|
||||
if self.request.query:
|
||||
@ -48,7 +49,6 @@ class PublicHandler(BaseHandler):
|
||||
template = "public/404.html"
|
||||
|
||||
if page == "login":
|
||||
page_data["background"] = self.controller.cached_login
|
||||
template = "public/login.html"
|
||||
|
||||
elif page == 404:
|
||||
|
@ -90,7 +90,8 @@ class ApiServersServerIndexHandler(BaseApiHandler):
|
||||
server_obj = self.controller.servers.get_server_obj(server_id)
|
||||
for key in data:
|
||||
# If we don't validate the input there could be security issues
|
||||
setattr(server_obj, key, data[key])
|
||||
if key != "path":
|
||||
setattr(server_obj, key, data[key])
|
||||
self.controller.servers.update_server(server_obj)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
|
@ -331,6 +331,15 @@ class ServerHandler(BaseHandler):
|
||||
return
|
||||
|
||||
if import_type == "import_jar":
|
||||
if not self.helper.is_subdir(
|
||||
import_server_path, self.controller.project_root
|
||||
):
|
||||
self.redirect(
|
||||
"/panel/error?error=Loop Error: The selected path will cause"
|
||||
" an infinite copy loop. Make sure Crafty's directory is not"
|
||||
" in your server path."
|
||||
)
|
||||
return
|
||||
good_path = self.controller.verify_jar_server(
|
||||
import_server_path, import_server_jar
|
||||
)
|
||||
@ -480,6 +489,15 @@ class ServerHandler(BaseHandler):
|
||||
return
|
||||
|
||||
if import_type == "import_jar":
|
||||
if self.helper.is_subdir(
|
||||
import_server_path, self.controller.project_root
|
||||
):
|
||||
self.redirect(
|
||||
"/panel/error?error=Loop Error: The selected path will cause"
|
||||
" an infinite copy loop. Make sure Crafty's directory is not"
|
||||
" in your server path."
|
||||
)
|
||||
return
|
||||
good_path = self.controller.verify_jar_server(
|
||||
import_server_path, import_server_exe
|
||||
)
|
||||
|
@ -7,7 +7,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class StatusHandler(BaseHandler):
|
||||
def get(self):
|
||||
page_data = {}
|
||||
page_data = {"background": self.controller.cached_login}
|
||||
page_data["lang"] = self.helper.get_setting("language")
|
||||
page_data["lang_page"] = self.helper.get_lang_page(
|
||||
self.helper.get_setting("language")
|
||||
|
@ -1,6 +1,7 @@
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
import urllib.parse
|
||||
import tornado.web
|
||||
import tornado.options
|
||||
import tornado.httpserver
|
||||
@ -108,7 +109,9 @@ class UploadHandler(BaseHandler):
|
||||
logger.debug("Could not delete file on user server upload")
|
||||
|
||||
self.helper.ensure_dir_exists(path)
|
||||
filename = self.request.headers.get("X-FileName", None)
|
||||
filename = urllib.parse.unquote(
|
||||
self.request.headers.get("X-FileName", None)
|
||||
)
|
||||
if not str(filename).endswith(".zip"):
|
||||
self.helper.websocket_helper.broadcast("close_upload_box", "error")
|
||||
self.finish("error")
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"major": 4,
|
||||
"minor": 0,
|
||||
"sub": 17
|
||||
"sub": 19
|
||||
}
|
||||
|
@ -22155,7 +22155,7 @@ ul li {
|
||||
}
|
||||
|
||||
.popover .popover-body {
|
||||
color: #000;
|
||||
color: var(--base-text);
|
||||
background: var(--card-banner-bg);
|
||||
}
|
||||
|
||||
|
@ -278,9 +278,10 @@
|
||||
{% end %}
|
||||
|
||||
</td>
|
||||
<td draggable="false" id="server_running_status_{{server['server_data']['server_id']}}">
|
||||
<td draggable="false">
|
||||
<span class="port" data-toggle="tooltip" title="{{
|
||||
server['server_data']['server_port'] }}">
|
||||
<div id="server_running_status_{{server['server_data']['server_id']}}">
|
||||
{% if server['stats']['running'] %}
|
||||
<span class="text-success"><i class="fas fa-signal"></i> {{ translate('dashboard', 'online',
|
||||
data['lang']) }}</span>
|
||||
@ -299,6 +300,7 @@
|
||||
data-players="{{ server['stats']['online']}}" data-max="{{ server['stats']['max'] }}"></span>
|
||||
</tr>
|
||||
{% end %}
|
||||
</div>
|
||||
</span>
|
||||
{% for server in data['failed_servers'] %}
|
||||
<tr id="{{server['server_id']}}" draggable="false">
|
||||
|
@ -62,9 +62,10 @@
|
||||
<label for="server_path">{{ translate('serverConfig', 'serverPath', data['lang']) }} <small
|
||||
class="text-muted ml-1"> - {{ translate('serverConfig', 'serverPathDesc', data['lang']) }}</small>
|
||||
</label>
|
||||
<input type="text" class="form-control" name="server_path" id="server_path"
|
||||
value="{{ data['server_stats']['server_id']['path'] }}"
|
||||
placeholder="{{ translate('serverConfig', 'serverPath', data['lang']) }}" required>
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<span style="color: gray; font-size: 12px;">{{ data['server_stats']['server_id']['path'] }}</span>
|
||||
🔒
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% if data['server_stats']['server_type'] != "minecraft-bedrock" %}
|
||||
@ -157,7 +158,6 @@
|
||||
<input type="text" class="form-control" name="server_ip" id="server_ip"
|
||||
value="{{ data['server_stats']['server_id']['server_ip'] }}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="server_port">{{ translate('serverConfig', 'serverPort', data['lang']) }} <small
|
||||
class="text-muted ml-1"> - {{ translate('serverConfig', 'serverPortDesc', data['lang']) }}
|
||||
@ -165,6 +165,11 @@
|
||||
<input type="number" class="form-control" name="server_port" id="server_port"
|
||||
value="{{ data['server_stats']['server_id']['server_port'] }}" step="1" max="65566" min="1"
|
||||
required>
|
||||
<span data-html="true" class="port-hint text-center"
|
||||
title="<i class='fal fa-exclamation-triangle'></i> " ,
|
||||
data-content="{{
|
||||
translate('serverConfig', 'statsHint1' , data['lang'])}} <br> <br> <strong>{{ translate('serverConfig', 'statsHint2', data['lang'])}}</strong>" ,
|
||||
data-placement="right"></span>
|
||||
</div>
|
||||
{% end %}
|
||||
|
||||
@ -522,6 +527,20 @@
|
||||
});
|
||||
}
|
||||
|
||||
$("#server_port").focus(function () {
|
||||
|
||||
$('[data-toggle="popover"]').popover();
|
||||
if ($(window).width() < 1000) {
|
||||
$('.port-hint').attr("data-placement", "top")
|
||||
} else {
|
||||
$('.port-hint').attr("data-placement", "right")
|
||||
}
|
||||
$('.port-hint').popover("show");
|
||||
});
|
||||
$("#server_port").focusout(function () {
|
||||
$('.port-hint').popover("hide");
|
||||
});
|
||||
|
||||
$(document).ready(function () {
|
||||
webSocket.on('remove_spinner', function () {
|
||||
document.getElementById("update-spinner").style.visibility = "hidden";
|
||||
|
@ -1027,7 +1027,9 @@
|
||||
function downloadFileE(event) {
|
||||
path = event.target.parentElement.getAttribute('data-path');
|
||||
name = event.target.parentElement.getAttribute('data-name');
|
||||
window.location.href = `/panel/download_file?id=${serverId}&path=${path}&name=${name}`;
|
||||
encoded_path = encodeURIComponent(path)
|
||||
encoded_name = encodeURIComponent(name)
|
||||
window.location.href = `/panel/download_file?id=${serverId}&path=${encoded_path}&name=${encoded_name}`;
|
||||
}
|
||||
|
||||
function renameItemE(event) {
|
||||
|
@ -1,70 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Crafty Controller</title>
|
||||
<!-- plugins:css -->
|
||||
<link rel="stylesheet" href="/static/assets/vendors/mdi/css/materialdesignicons.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/flag-icon-css/css/flag-icon.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
|
||||
<!-- endinject -->
|
||||
<!-- Plugin css for this page -->
|
||||
<!-- End Plugin css for this page -->
|
||||
<!-- Layout styles -->
|
||||
<link rel="stylesheet" href="/static/assets/css/dark/style.css">
|
||||
<!-- End Layout styles -->
|
||||
<link rel="shortcut icon" type="image/svg+xml" href="/static/assets/images/logo_small.svg">
|
||||
<link rel="alternate icon" href="/static/assets/images/favicon.png" />
|
||||
</head>
|
||||
<body class="dark-theme">
|
||||
<div class="container-scroller">
|
||||
<div class="container-fluid page-body-wrapper full-page-wrapper">
|
||||
<div class="content-wrapper d-flex align-items-center auth auth-bg-1 theme-one">
|
||||
<div class="row w-100">
|
||||
<div class="col-lg-4 mx-auto">
|
||||
|
||||
<div class="auto-form-wrapper">
|
||||
<div class="text-center">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Crafty Controller</title>
|
||||
<!-- plugins:css -->
|
||||
<link rel="stylesheet" href="/static/assets/vendors/mdi/css/materialdesignicons.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/flag-icon-css/css/flag-icon.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
|
||||
<!-- endinject -->
|
||||
<!-- Plugin css for this page -->
|
||||
<!-- End Plugin css for this page -->
|
||||
<!-- Layout styles -->
|
||||
<link rel="stylesheet" href="/static/assets/css/dark/style.css">
|
||||
<!-- End Layout styles -->
|
||||
<link rel="shortcut icon" type="image/svg+xml" href="/static/assets/images/logo_small.svg">
|
||||
<link rel="alternate icon" href="/static/assets/images/favicon.png" />
|
||||
</head>
|
||||
<style>
|
||||
.auth.auth-bg-1 {
|
||||
background: url("../../static/assets/images/auth/{{data['background']}}"),
|
||||
url("../../static/assets/images/auth/login-1.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="dark-theme">
|
||||
<div class="container-scroller">
|
||||
<div class="container-fluid page-body-wrapper full-page-wrapper">
|
||||
<div class="content-wrapper d-flex align-items-center auth auth-bg-1 theme-one">
|
||||
<div class="row w-100">
|
||||
<div class="col-lg-4 mx-auto">
|
||||
|
||||
<div class="auto-form-wrapper">
|
||||
<div class="text-center">
|
||||
<img src="/static/assets/images/logo_long.svg"><br /><br />
|
||||
<div class="col-sm-12 grid-margin stretch-card">
|
||||
<div class="card card-statistics social-card facebook-card card-colored">
|
||||
<div class="card-body">
|
||||
<h4 class="platform-name mb-3 mt-4 font-weight-semibold user-name">404</h4>
|
||||
<h5 class="headline font-weight-medium">{{ translate('404', 'notFound', data['lang']) }}</h5>
|
||||
<p class="mb-2 comment font-weight-light">
|
||||
{{ translate('404', 'unableToFind', data['lang']) }}
|
||||
<br /><br />
|
||||
<a class="d-inline font-weight-medium" href="https://discord.gg/9VJPhCE"> {{ translate('404', 'contact', data['lang']) }}</a>
|
||||
</p>
|
||||
<div class="col-sm-12 grid-margin stretch-card">
|
||||
<div class="card card-statistics social-card facebook-card card-colored">
|
||||
<div class="card-body">
|
||||
<h4 class="platform-name mb-3 mt-4 font-weight-semibold user-name">404</h4>
|
||||
<h5 class="headline font-weight-medium">{{ translate('404', 'notFound', data['lang']) }}</h5>
|
||||
<p class="mb-2 comment font-weight-light">
|
||||
{{ translate('404', 'unableToFind', data['lang']) }}
|
||||
<br /><br />
|
||||
<a class="d-inline font-weight-medium" href="https://discord.gg/9VJPhCE"> {{ translate('404',
|
||||
'contact', data['lang']) }}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- content-wrapper ends -->
|
||||
</div>
|
||||
<!-- page-body-wrapper ends -->
|
||||
<!-- content-wrapper ends -->
|
||||
</div>
|
||||
<!-- container-scroller -->
|
||||
<!-- plugins:js -->
|
||||
<script src="/static/assets/vendors/js/vendor.bundle.base.js"></script>
|
||||
<!-- endinject -->
|
||||
<!-- inject:js -->
|
||||
<script src="/static/assets/js/shared/off-canvas.js"></script>
|
||||
<script src="/static/assets/js/shared/hoverable-collapse.js"></script>
|
||||
<script src="/static/assets/js/shared/misc.js"></script>
|
||||
<script src="/static/assets/js/shared/settings.js"></script>
|
||||
<script src="/static/assets/js/shared/todolist.js"></script>
|
||||
<!-- endinject -->
|
||||
</body>
|
||||
<!-- page-body-wrapper ends -->
|
||||
</div>
|
||||
<!-- container-scroller -->
|
||||
<!-- plugins:js -->
|
||||
<script src="/static/assets/vendors/js/vendor.bundle.base.js"></script>
|
||||
<!-- endinject -->
|
||||
<!-- inject:js -->
|
||||
<script src="/static/assets/js/shared/off-canvas.js"></script>
|
||||
<script src="/static/assets/js/shared/hoverable-collapse.js"></script>
|
||||
<script src="/static/assets/js/shared/misc.js"></script>
|
||||
<script src="/static/assets/js/shared/settings.js"></script>
|
||||
<script src="/static/assets/js/shared/todolist.js"></script>
|
||||
<!-- endinject -->
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,73 +1,86 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Crafty Controller</title>
|
||||
<!-- plugins:css -->
|
||||
<link rel="stylesheet" href="/static/assets/vendors/mdi/css/materialdesignicons.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/flag-icon-css/css/flag-icon.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
|
||||
<!-- endinject -->
|
||||
<!-- Plugin css for this page -->
|
||||
<!-- End Plugin css for this page -->
|
||||
<!-- Layout styles -->
|
||||
<link rel="stylesheet" href="/static/assets/css/dark/style.css">
|
||||
<!-- End Layout styles -->
|
||||
<link rel="shortcut icon" type="image/svg+xml" href="/static/assets/images/logo_small.svg">
|
||||
<link rel="alternate icon" href="/static/assets/images/favicon.png" />
|
||||
</head>
|
||||
<body class="dark-theme">
|
||||
<div class="container-scroller">
|
||||
<div class="container-fluid page-body-wrapper full-page-wrapper">
|
||||
<div class="content-wrapper d-flex align-items-center auth auth-bg-1 theme-one">
|
||||
<div class="row w-100">
|
||||
<div class="col-lg-4 mx-auto">
|
||||
|
||||
<div class="auto-form-wrapper">
|
||||
<div class="text-center">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Crafty Controller</title>
|
||||
<!-- plugins:css -->
|
||||
<link rel="stylesheet" href="/static/assets/vendors/mdi/css/materialdesignicons.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/flag-icon-css/css/flag-icon.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
|
||||
<!-- endinject -->
|
||||
<!-- Plugin css for this page -->
|
||||
<!-- End Plugin css for this page -->
|
||||
<!-- Layout styles -->
|
||||
<link rel="stylesheet" href="/static/assets/css/dark/style.css">
|
||||
<!-- End Layout styles -->
|
||||
<link rel="shortcut icon" type="image/svg+xml" href="/static/assets/images/logo_small.svg">
|
||||
<link rel="alternate icon" href="/static/assets/images/favicon.png" />
|
||||
</head>
|
||||
<style>
|
||||
.auth.auth-bg-1 {
|
||||
background: url("../../static/assets/images/auth/{{data['background']}}"),
|
||||
url("../../static/assets/images/auth/login-1.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="dark-theme">
|
||||
<div class="container-scroller">
|
||||
<div class="container-fluid page-body-wrapper full-page-wrapper">
|
||||
<div class="content-wrapper d-flex align-items-center auth auth-bg-1 theme-one">
|
||||
<div class="row w-100">
|
||||
<div class="col-lg-4 mx-auto">
|
||||
|
||||
<div class="auto-form-wrapper">
|
||||
<div class="text-center">
|
||||
<img src="/static/assets/images/logo_long.svg"><br /><br />
|
||||
<div class="col-sm-12 grid-margin stretch-card">
|
||||
<div class="card card-statistics social-card google-card card-colored">
|
||||
<div class="card-body">
|
||||
<h4 class="platform-name mb-3 mt-4 font-weight-semibold user-name">{{ translate('error', 'error', data['lang']) }}</h4>
|
||||
<h5 class="headline font-weight-medium">{{ translate('error', 'terribleFailure', data['lang']) }}</h5>
|
||||
<p class="mb-2 comment font-weight-light">
|
||||
{{ translate('error', 'embarassing', data['lang']) }}<br />
|
||||
<br />
|
||||
<b>{{ translate('error', 'hereIsTheError', data['lang']) }}: {{data['error']}}</b><br /><br />
|
||||
That's all the help I can give you - Godspeed
|
||||
<br /><br />
|
||||
<a class="d-inline font-weight-medium" href="https://discord.gg/9VJPhCE"> {{ translate('error', 'contact', data['lang']) }}</a>
|
||||
</p>
|
||||
<div class="col-sm-12 grid-margin stretch-card">
|
||||
<div class="card card-statistics social-card google-card card-colored">
|
||||
<div class="card-body">
|
||||
<h4 class="platform-name mb-3 mt-4 font-weight-semibold user-name">{{ translate('error', 'error',
|
||||
data['lang']) }}</h4>
|
||||
<h5 class="headline font-weight-medium">{{ translate('error', 'terribleFailure', data['lang']) }}
|
||||
</h5>
|
||||
<p class="mb-2 comment font-weight-light">
|
||||
{{ translate('error', 'embarassing', data['lang']) }}<br />
|
||||
<br />
|
||||
<b>{{ translate('error', 'hereIsTheError', data['lang']) }}: {{data['error']}}</b><br /><br />
|
||||
That's all the help I can give you - Godspeed
|
||||
<br /><br />
|
||||
<a class="d-inline font-weight-medium" href="https://discord.gg/9VJPhCE"> {{ translate('error',
|
||||
'contact', data['lang']) }}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- content-wrapper ends -->
|
||||
</div>
|
||||
<!-- page-body-wrapper ends -->
|
||||
<!-- content-wrapper ends -->
|
||||
</div>
|
||||
<!-- container-scroller -->
|
||||
<!-- plugins:js -->
|
||||
<script src="/static/assets/vendors/js/vendor.bundle.base.js"></script>
|
||||
<!-- endinject -->
|
||||
<!-- inject:js -->
|
||||
<script src="/static/assets/js/shared/off-canvas.js"></script>
|
||||
<script src="/static/assets/js/shared/hoverable-collapse.js"></script>
|
||||
<script src="/static/assets/js/shared/misc.js"></script>
|
||||
<script src="/static/assets/js/shared/settings.js"></script>
|
||||
<script src="/static/assets/js/shared/todolist.js"></script>
|
||||
<!-- endinject -->
|
||||
</body>
|
||||
<!-- page-body-wrapper ends -->
|
||||
</div>
|
||||
<!-- container-scroller -->
|
||||
<!-- plugins:js -->
|
||||
<script src="/static/assets/vendors/js/vendor.bundle.base.js"></script>
|
||||
<!-- endinject -->
|
||||
<!-- inject:js -->
|
||||
<script src="/static/assets/js/shared/off-canvas.js"></script>
|
||||
<script src="/static/assets/js/shared/hoverable-collapse.js"></script>
|
||||
<script src="/static/assets/js/shared/misc.js"></script>
|
||||
<script src="/static/assets/js/shared/settings.js"></script>
|
||||
<script src="/static/assets/js/shared/todolist.js"></script>
|
||||
<!-- endinject -->
|
||||
</body>
|
||||
|
||||
</html>
|
@ -21,6 +21,13 @@
|
||||
<link rel="shortcut icon" type="image/svg+xml" href="/static/assets/images/logo_small.svg">
|
||||
<link rel="alternate icon" href="/static/assets/images/favicon.png" />
|
||||
</head>
|
||||
<style>
|
||||
.auth.auth-bg-1 {
|
||||
background: url("../../static/assets/images/auth/{{data['background']}}"),
|
||||
url("../../static/assets/images/auth/login-1.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="dark-theme">
|
||||
<div class="container-scroller">
|
||||
@ -60,11 +67,6 @@
|
||||
.login-input:focus {
|
||||
box-shadow: 0 12px 16px 0 hsla(0, 0%, 0%, 0.4);
|
||||
}
|
||||
|
||||
.auth.auth-bg-1 {
|
||||
background: url("../../static/assets/images/auth/{{data['background']}}");
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
{% if data['query'] %}
|
||||
<form action="/public/login?{{ data['query'] }}" method="post">
|
||||
|
@ -7,6 +7,13 @@
|
||||
|
||||
{% block content %}
|
||||
<!-- View for Large screen -->
|
||||
<style>
|
||||
.auth.auth-bg-1 {
|
||||
background: url("../../static/assets/images/auth/{{data['background']}}"),
|
||||
url("../../static/assets/images/auth/login-1.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
<div class="row justify-content-center">
|
||||
<div class="content-wrapper col-md login-modal d-none d-sm-block" style="background-color: var(--dropdown-bg);">
|
||||
<img src="/static/assets/images/logo_long.png" style='width: 25%; margin-left: 38%;'>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ data['lang_page'] }}">
|
||||
<html lang="{{ data['lang_page'] }}" class="default">
|
||||
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
@ -24,7 +24,7 @@
|
||||
<link rel="alternate icon" href="/static/assets/images/favicon.png" />
|
||||
</head>
|
||||
|
||||
<body class="dark-theme">
|
||||
<body>
|
||||
<div class="container-scroller">
|
||||
<div class="container-fluid page-body-wrapper full-page-wrapper">
|
||||
<div class="content-wrapper d-flex align-items-sm-center auth auth-bg-1 theme-one">
|
||||
|
@ -424,8 +424,8 @@
|
||||
<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 fade" id="dir_upload_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">
|
||||
@ -436,7 +436,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="tree-ctx-item" id="main-tree-div" data-path=""
|
||||
<div class="tree-ctx-item" id="main-tree-div-upload" data-path=""
|
||||
style="overflow: scroll; max-height:75%;">
|
||||
<input type="radio" id="main-tree-input-upload" name="root_path" value="" checked>
|
||||
<span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path="">
|
||||
@ -558,14 +558,14 @@
|
||||
|
||||
{% block js%}
|
||||
<script>
|
||||
|
||||
var upload;
|
||||
var file;
|
||||
function sendFile() {
|
||||
file = $("#file")[0].files[0]
|
||||
document.getElementById("upload_input").innerHTML = '<div class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>'
|
||||
let xmlHttpRequest = new XMLHttpRequest();
|
||||
let token = getCookie("_xsrf")
|
||||
let fileName = file.name
|
||||
let fileName = encodeURIComponent(file.name)
|
||||
let target = '/upload'
|
||||
let mimeType = file.type
|
||||
let size = file.size
|
||||
@ -597,8 +597,9 @@
|
||||
|
||||
document.getElementById("root_upload_button").addEventListener("click", function () {
|
||||
if (file) {
|
||||
upload = true;
|
||||
if (document.getElementById('root_upload_button').classList.contains('clicked')) {
|
||||
document.getElementById('main-tree-div').innerHTML = '<input type="radio" id="main-tree-input-upload" 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>'
|
||||
document.getElementById('main-tree-div-upload').innerHTML = '<input type="radio" id="main-tree-input-upload" name="root_path" value="" checked><span id="main-tree-upload" 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_upload_button').classList.add('clicked')
|
||||
}
|
||||
@ -610,7 +611,7 @@
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/unzip_server?id=-1&file=' + file.name,
|
||||
url: '/ajax/unzip_server?id=-1&file=' + encodeURIComponent(file.name),
|
||||
});
|
||||
} else {
|
||||
bootbox.alert("You must input a path before selecting this button");
|
||||
@ -663,7 +664,7 @@
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/unzip_server?id=-1&path=' + path,
|
||||
url: '/ajax/unzip_server?id=-1&path=' + encodeURIComponent(path),
|
||||
});
|
||||
} else {
|
||||
bootbox.alert("You must input a path before selecting this button");
|
||||
@ -692,7 +693,11 @@
|
||||
}
|
||||
|
||||
function show_file_tree() {
|
||||
$("#dir_select").modal();
|
||||
if (upload) {
|
||||
$("#dir_upload_select").modal();
|
||||
} else {
|
||||
$("#dir_select").modal();
|
||||
}
|
||||
}
|
||||
|
||||
function getTreeView(path) {
|
||||
@ -716,12 +721,20 @@
|
||||
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;
|
||||
if (styles.visibility === "hidden") {
|
||||
try {
|
||||
document.getElementById('main-tree-div').innerHTML += text;
|
||||
document.getElementById('main-tree').parentElement.classList.add("clicked");
|
||||
} catch {
|
||||
document.getElementById('files-tree').innerHTML = text;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
document.getElementById('main-tree-div-upload').innerHTML += text;
|
||||
document.getElementById('main-tree-upload').parentElement.classList.add("clicked");
|
||||
} catch {
|
||||
document.getElementById('files-tree').innerHTML = text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -552,8 +552,8 @@
|
||||
<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 fade" id="dir_upload_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">
|
||||
@ -564,10 +564,11 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="tree-ctx-item" id="main-tree-div" data-path=""
|
||||
<div class="tree-ctx-item" id="main-tree-div-upload" data-path=""
|
||||
style="overflow: scroll; max-height:75%;">
|
||||
<input type="radio" id="main-tree-input-upload" name="root_path" value="" checked>
|
||||
<span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path="">
|
||||
<span id="main-tree-upload" 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']) }}
|
||||
@ -788,7 +789,7 @@
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/unzip_server?id=-1&path=' + path,
|
||||
url: '/ajax/unzip_server?id=-1&path=' + encodeURIComponent(path),
|
||||
});
|
||||
} else {
|
||||
bootbox.alert("You must input a path before selecting this button");
|
||||
@ -799,6 +800,7 @@
|
||||
|
||||
{% block js %}
|
||||
<script>
|
||||
var upload = false;
|
||||
var file;
|
||||
function sendFile() {
|
||||
file = $("#file")[0].files[0]
|
||||
@ -853,7 +855,7 @@
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/unzip_server?id=-1&path=' + path,
|
||||
url: '/ajax/unzip_server?id=-1&path=' + encodeURIComponent(path),
|
||||
});
|
||||
} else {
|
||||
bootbox.alert("You must input a path before selecting this button");
|
||||
@ -862,8 +864,9 @@
|
||||
|
||||
document.getElementById("root_upload_button").addEventListener("click", function () {
|
||||
if (file) {
|
||||
upload = true;
|
||||
if (document.getElementById('root_upload_button').classList.contains('clicked')) {
|
||||
document.getElementById('main-tree-div').innerHTML = '<input type="radio" id="main-tree-input-upload" 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>'
|
||||
document.getElementById('main-tree-div-upload').innerHTML = '<input type="radio" id="main-tree-input-upload" name="root_path" value="" checked><span id="main-tree-upload" 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_upload_button').classList.add('clicked')
|
||||
}
|
||||
@ -875,7 +878,7 @@
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/unzip_server?id=-1&file=' + file.name,
|
||||
url: '/ajax/unzip_server?id=-1&file=' + encodeURIComponent(file.name),
|
||||
});
|
||||
} else {
|
||||
bootbox.alert("You must input a path before selecting this button");
|
||||
@ -926,7 +929,11 @@
|
||||
}
|
||||
|
||||
function show_file_tree() {
|
||||
$("#dir_select").modal();
|
||||
if (upload) {
|
||||
$("#dir_upload_select").modal();
|
||||
} else {
|
||||
$("#dir_select").modal();
|
||||
}
|
||||
}
|
||||
|
||||
function check_sizes(a, b, changed) {
|
||||
@ -961,15 +968,22 @@
|
||||
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;
|
||||
if (styles.visibility === "hidden") {
|
||||
try {
|
||||
document.getElementById('main-tree-div').innerHTML += text;
|
||||
document.getElementById('main-tree').parentElement.classList.add("clicked");
|
||||
} catch {
|
||||
document.getElementById('files-tree').innerHTML = text;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
document.getElementById('main-tree-div-upload').innerHTML += text;
|
||||
document.getElementById('main-tree-upload').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');
|
||||
|
||||
|
@ -340,7 +340,9 @@
|
||||
"yesDeleteFiles": "Yes, delete files",
|
||||
"shutdownTimeout": "Shutdown Timeout",
|
||||
"timeoutExplain1": "How long Crafty will wait for your server to shutdown after executing the",
|
||||
"timeoutExplain2": "command before it forces the process down."
|
||||
"timeoutExplain2": "command before it forces the process down.",
|
||||
"statsHint1": "The port your server is running on should go here. This is just how Crafty opens a connection to your server for stats.",
|
||||
"statsHint2": "This does not change the port of your server. You must still change the port in your server config file."
|
||||
},
|
||||
"serverConfigHelp": {
|
||||
"desc": "Here is where you can change the configuration of your server",
|
||||
|
Loading…
Reference in New Issue
Block a user