Merge branch 'dev' into enhancement/ignored-exits

This commit is contained in:
Zedifus 2023-02-11 18:33:48 +00:00
commit fa6f17e347
15 changed files with 221 additions and 164 deletions

View File

@ -1,13 +1,15 @@
# Changelog
## --- [4.0.21] - 2023/TBD
### New features
TBD
- Add better feedback for uploads with a progress bar ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/546))
### Bug fixes
TBD
- Fix exception related to page data on server start ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/544))
### Tweaks
TBD
- Cleanup authentication helpers ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/545))
- Optimize file upload progress WS ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/546))
- Truncate sidebar servers to a max of 10 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/552))
### Lang
TBD
- Add additional translations to backups page strings ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/543))
<br><br>
## --- [4.0.20] - 2023/01/29

View File

@ -13,7 +13,6 @@ logger = logging.getLogger(__name__)
class Authentication:
def __init__(self, helper):
self.helper = helper
self.secret = "my secret"
try:
self.secret = ManagementController.get_crafty_api_key()
if self.secret == "":

View File

@ -1013,7 +1013,7 @@ class Helpers:
for item in file_list:
if os.path.isdir(os.path.join(folder, item)):
dir_list.append(item)
elif str(item) != "crafty.sqlite":
elif str(item) != self.ignored_names:
unsorted_files.append(item)
file_list = sorted(dir_list, key=str.casefold) + sorted(
unsorted_files, key=str.casefold
@ -1054,7 +1054,7 @@ class Helpers:
for item in file_list:
if os.path.isdir(os.path.join(folder, item)):
dir_list.append(item)
elif str(item) != "crafty.sqlite":
elif str(item) != self.ignored_names:
unsorted_files.append(item)
file_list = sorted(dir_list, key=str.casefold) + sorted(
unsorted_files, key=str.casefold

View File

@ -183,6 +183,7 @@ class ServerHandler(BaseHandler):
"version_data": "version_data_here", # TODO
"user_data": exec_user,
"show_contribute": self.helper.get_setting("show_contribute_link", True),
"background": self.controller.cached_login,
"lang": self.controller.users.get_user_lang_by_id(exec_user["user_id"]),
"lang_page": Helpers.get_lang_page(
self.controller.users.get_user_lang_by_id(exec_user["user_id"])

View File

@ -7,12 +7,12 @@ logger = logging.getLogger(__name__)
class StatusHandler(BaseHandler):
def get(self):
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")
)
page_data["servers"] = self.controller.servers.get_all_servers_stats()
page_data = {
"background": self.controller.cached_login,
"lang": self.helper.get_setting("language"),
"lang_page": self.helper.get_lang_page(self.helper.get_setting("language")),
"servers": self.controller.servers.get_all_servers_stats(),
}
running = 0
for srv in page_data["servers"]:
if srv["stats"]["running"]:

View File

@ -52,18 +52,19 @@ class UploadHandler(BaseHandler):
f"User with ID {user_id} attempted to upload a file that"
f" exceeded the max body size."
)
self.helper.websocket_helper.broadcast_user(
user_id,
"send_start_error",
return self.finish_json(
413,
{
"error": self.helper.translation.translate(
"status": "error",
"error": "TOO LARGE",
"info": self.helper.translation.translate(
"error",
"fileTooLarge",
self.controller.users.get_user_lang_by_id(user_id),
),
},
)
return
self.do_upload = True
if superuser:
@ -141,48 +142,50 @@ class UploadHandler(BaseHandler):
f"User with ID {user_id} attempted to upload a file that"
f" exceeded the max body size."
)
self.helper.websocket_helper.broadcast_user(
user_id,
"send_start_error",
return self.finish_json(
413,
{
"error": self.helper.translation.translate(
"status": "error",
"error": "TOO LARGE",
"info": self.helper.translation.translate(
"error",
"fileTooLarge",
self.controller.users.get_user_lang_by_id(user_id),
),
},
)
return
self.do_upload = True
if not superuser:
self.helper.websocket_helper.broadcast_user(
user_id,
"send_start_error",
return self.finish_json(
401,
{
"error": self.helper.translation.translate(
"status": "error",
"error": "UNAUTHORIZED ACCESS",
"info": self.helper.translation.translate(
"error",
"superError",
self.controller.users.get_user_lang_by_id(user_id),
),
},
)
return
if not self.request.headers.get("X-Content-Type", None).startswith(
"image/"
):
self.helper.websocket_helper.broadcast_user(
user_id,
"send_start_error",
return self.finish_json(
415,
{
"error": self.helper.translation.translate(
"status": "error",
"error": "TYPE ERROR",
"info": self.helper.translation.translate(
"error",
"fileError",
self.controller.users.get_user_lang_by_id(user_id),
),
},
)
return
if user_id is None:
logger.warning("User ID not found in upload handler call")
Console.warning("User ID not found in upload handler call")
@ -219,18 +222,19 @@ class UploadHandler(BaseHandler):
f"User with ID {user_id} attempted to upload a file that"
f" exceeded the max body size."
)
self.helper.websocket_helper.broadcast_user(
user_id,
"send_start_error",
return self.finish_json(
413,
{
"error": self.helper.translation.translate(
"status": "error",
"error": "TOO LARGE",
"info": self.helper.translation.translate(
"error",
"fileTooLarge",
self.controller.users.get_user_lang_by_id(user_id),
),
},
)
return
self.do_upload = True
if superuser:

View File

@ -81,7 +81,7 @@
<i class="menu-arrow"></i>
</a>
<div class="collapse" id="page-layouts">
<ul class="nav flex-column sub-menu">
<ul class="nav flex-column sub-menu" id="sidebar-servers">
{% if data['crafty_permissions']['Server_Creation'] in data['user_crafty_permissions'] %}
<li class="nav-item">
<a class="nav-link" href="/server/step1"><i class="fas fa-plus-circle"></i> &nbsp; {{ translate('sidebar',
@ -138,4 +138,9 @@
</ul>
</nav>
<script>
$(document).ready(function () {
$('#sidebar-servers li:gt(10)').remove();
})
</script>
<!-- partial -->

View File

@ -6,7 +6,8 @@
{% block title %}Crafty Controller - {{ translate('panelConfig', 'pageTitle', data['lang']) }}{% end %}
{% block content %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.10/css/bootstrap-select.min.css">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.10/css/bootstrap-select.min.css">
<div class="content-wrapper">
@ -71,7 +72,8 @@
<button type="button" class="btn btn-outline-default custom-picker" onclick="$('option', $('#lang_select')).each(function(element) {
$(this).removeAttr('selected').prop('selected', false); $('.selectpicker').selectpicker('refresh')
});">Enable all Languages</button>
<select id="lang_select" class="form-control selectpicker show-tick" data-icon-base="fas" data-tick-icon="fa-check" multiple data-style="custom-picker">
<select id="lang_select" class="form-control selectpicker show-tick" data-icon-base="fas"
data-tick-icon="fa-check" multiple data-style="custom-picker">
{% for lang in data['all_languages'] %}
{% if lang in item[1] %}
<option selected>{{lang}}</option>
@ -80,10 +82,13 @@
{% end %}
{% end %}
</select>
<textarea id="disabled_lang" name="{{item[0]}}" class="form-control list hidden" rows="{{ len(data['all_languages']) }}" value="{{','.join(item[1])}}" hidden>{{','.join(item[1])}}</textarea>
<textarea id="disabled_lang" name="{{item[0]}}" class="form-control list hidden"
rows="{{ len(data['all_languages']) }}" value="{{','.join(item[1])}}"
hidden>{{','.join(item[1])}}</textarea>
</div>
{% elif isinstance(item[1], list) %}
<textarea value="{{','.join(item[1])}}" type="text" name="{{item[0]}}" class="form-control list">{{','.join(item[1])}}</textarea>
<textarea value="{{','.join(item[1])}}" type="text" name="{{item[0]}}"
class="form-control list">{{','.join(item[1])}}</textarea>
{% elif isinstance(item[1], bool) %}
<div style="margin-left: 30px;">
{% if item[1] == True %}
@ -99,9 +104,11 @@
{% end %}
</div>
{% elif isinstance(item[1], int) %}
<input type="number" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}" step="1" min="0" required>
<input type="number" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}"
step="1" min="0" required>
{% else %}
<input type="text" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}" step="2" min="0" required>
<input type="text" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}"
step="2" min="0" required>
{% end %}
</div>
{% end %}
@ -276,44 +283,6 @@
},
});
})
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%">&nbsp;<i class="fa-solid fa-spinner"></i></div></div>'
let xmlHttpRequest = new XMLHttpRequest();
let token = getCookie("_xsrf")
let fileName = file.name
let target = '/upload'
let mimeType = file.type
let size = file.size
let type = 'background'
xmlHttpRequest.open('POST', target, true);
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
xmlHttpRequest.setRequestHeader('X-Content-Length', size);
xmlHttpRequest.setRequestHeader('X-Content-Disposition', 'attachment; filename="' + fileName + '"');
xmlHttpRequest.setRequestHeader('X-Content-Upload-Type', type);
xmlHttpRequest.setRequestHeader('X-FileName', fileName);
xmlHttpRequest.addEventListener('load', (event) => {
if (event.target.responseText == 'success') {
console.log('Upload for file', file.name, 'was successful!')
document.getElementById("upload_input").innerHTML = '<div class="card-header header-sm d-flex justify-content-between align-items-center"><span id="file-uploaded" style="color: gray;">' + fileName + '</span> 🔒</div>';
setTimeout(function () {
window.location.reload();
}, 2000);
}
else {
alert('Upload failed with response: ' + event.target.responseText);
doUpload = false;
}
}, false);
xmlHttpRequest.addEventListener('error', (e) => {
console.error('Error while uploading file', file.name + '.', 'Event:', e)
}, false);
xmlHttpRequest.send(file);
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.10/js/bootstrap-select.min.js">
</script>

View File

@ -352,7 +352,7 @@
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%">&nbsp;<i class="fa-solid fa-spinner"></i></div></div>';
document.getElementById("upload_input").innerHTML = '<div class="progress"><div id="upload-progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%">&nbsp;<i class="fa-solid fa-spinner"></i></div></div>';
let xmlHttpRequest = new XMLHttpRequest();
let token = getCookie("_xsrf")
let fileName = file.name
@ -361,6 +361,15 @@
let size = file.size
let type = 'background'
xmlHttpRequest.upload.addEventListener('progress', function (e) {
if (e.loaded <= size) {
var percent = Math.round(e.loaded / size * 100);
$(`#upload-progress-bar`).css('width', percent + '%');
$(`#upload-progress-bar`).html(percent + '%');
}
});
xmlHttpRequest.open('POST', target, true);
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
@ -377,7 +386,15 @@
}, 2000);
}
else {
alert('Upload failed with response: ' + event.target.responseText);
let response_text = JSON.parse(event.target.responseText);
var x = document.querySelector('.bootbox');
console.log(JSON.parse(event.target.responseText).info)
bootbox.alert({
message: JSON.parse(event.target.responseText).info,
callback: function () {
window.location.reload();
}
});
doUpload = false;
}
}, false);

View File

@ -110,15 +110,15 @@
<div class="form-group">
<label for="command-check" class="form-check-label ml-4 mb-4"></label>
{% if data['backup_config']['before'] %}
<input type="checkbox" class="form-check-input" id="before-check" name="before-check" checked>Run
Command Before Backup
<input type="checkbox" class="form-check-input" id="before-check" name="before-check" checked>{{
translate('serverBackups', 'before', data['lang']) }}
<br>
<input type="text" class="form-control" name="backup_before" id="backup_before"
value="{{ data['backup_config']['before'] }}" placeholder="We enter the / for you"
style="display: inline-block;">
{% else %}
<input type="checkbox" class="form-check-input" id="before-check" name="before-check">Run Command
Before Backup
<input type="checkbox" class="form-check-input" id="before-check" name="before-check">{{
translate('serverBackups', 'before', data['lang']) }}
<br>
<input type="text" class="form-control" name="backup_before" id="backup_before" value=""
placeholder="We enter the / for you." style="display: none;">
@ -127,15 +127,15 @@
<div class="form-group">
<label for="command-check" class="form-check-label ml-4 mb-4"></label>
{% if data['backup_config']['after'] %}
<input type="checkbox" class="form-check-input" id="after-check" name="after-check" checked>Run
Command After Backup
<input type="checkbox" class="form-check-input" id="after-check" name="after-check" checked>{{
translate('serverBackups', 'after', data['lang']) }}
<br>
<input type="text" class="form-control" name="backup_after" id="backup_after"
value="{{ data['backup_config']['after'] }}" placeholder="We enter the / for you"
style="display: inline-block;">
{% else %}
<input type="checkbox" class="form-check-input" id="after-check" name="after-check">Run Command
Before Backup
<input type="checkbox" class="form-check-input" id="after-check" name="after-check">{{
translate('serverBackups', 'after', data['lang']) }}
<br>
<input type="text" class="form-control" name="backup_after" id="backup_after" value=""
placeholder="We enter the / for you." style="display: none;">

View File

@ -705,6 +705,15 @@
let mimeType = file.type
let size = file.size
xmlHttpRequest.upload.addEventListener('progress', function (e) {
if (e.loaded <= size) {
var percent = Math.round(e.loaded / size * 100);
$(`#upload-progress-bar-${i + 1}`).css('width', percent + '%');
$(`#upload-progress-bar-${i + 1}`).html(percent + '%');
}
});
xmlHttpRequest.open('POST', target, true);
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
@ -751,7 +760,22 @@
$(`#upload-progress-bar-${i + 1}`).html('<i style="color: black;" class="fas fa-box-check"></i>')
}
else {
alert('Upload failed with response: ' + event.target.responseText);
let response_text = JSON.parse(event.target.responseText);
var x = document.querySelector('.bootbox');
if (x) {
x.remove()
}
var x = document.querySelector('.modal-content');
if (x) {
x.remove()
}
console.log(JSON.parse(event.target.responseText).info)
bootbox.alert({
message: JSON.parse(event.target.responseText).info,
callback: function () {
window.location.reload();
}
});
doUpload = false;
}
}, false);
@ -788,7 +812,7 @@
var height = files.files.length * 50;
var waitMessage = '<p class="text-center mb-0">' +
'<i class="fa fa-spin fa-cog"></i>' +
'<i class="fa fa-spin fa-cog"></i>&nbsp;' +
"{{ translate('serverFiles', 'waitUpload', data['lang']) }}" + '<br>' +
'<strong>' + "{{ translate('serverFiles', 'stayHere', data['lang']) }}" + '</strong>' +
'</p>' +
@ -826,7 +850,7 @@
await sendFile(files.files[i], path, serverId, nFiles - i - 1, i, (progress) => {
$(`#upload-progress-bar-${i + 1}`).attr('aria-valuenow', progress)
$(`#upload-progress-bar-${i + 1}`).css('width', progress + '%')
$(`#upload-progress-bar-${i + 1}`).css('width', progress + '%');
});
}
hideUploadBox();

View File

@ -562,7 +562,7 @@
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%">&nbsp;<i class="fa-solid fa-spinner"></i></div></div>'
document.getElementById("upload_input").innerHTML = '<div class="progress"><div id="upload-progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%">&nbsp;<i class="fa-solid fa-spinner"></i></div></div>'
let xmlHttpRequest = new XMLHttpRequest();
let token = getCookie("_xsrf")
let fileName = encodeURIComponent(file.name)
@ -571,6 +571,15 @@
let size = file.size
let type = 'server_import'
xmlHttpRequest.upload.addEventListener('progress', function (e) {
if (e.loaded <= size) {
var percent = Math.round(e.loaded / size * 100);
$(`#upload-progress-bar`).css('width', percent + '%');
$(`#upload-progress-bar`).html(percent + '%');
}
});
xmlHttpRequest.open('POST', target, true);
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
@ -585,7 +594,15 @@
document.getElementById("lower_half").style.visibility = "visible";
}
else {
alert('Upload failed with response: ' + event.target.responseText);
let response_text = JSON.parse(event.target.responseText);
var x = document.querySelector('.bootbox');
console.log(JSON.parse(event.target.responseText).info)
bootbox.alert({
message: JSON.parse(event.target.responseText).info,
callback: function () {
window.location.reload();
}
});
doUpload = false;
}
}, false);

View File

@ -804,7 +804,7 @@
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%">&nbsp;<i class="fa-solid fa-spinner"></i></div></div>'
document.getElementById("upload_input").innerHTML = '<div class="progress"><div id="upload-progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%">&nbsp;<i class="fa-solid fa-spinner"></i></div></div>'
let xmlHttpRequest = new XMLHttpRequest();
let token = getCookie("_xsrf")
let fileName = file.name
@ -813,6 +813,15 @@
let size = file.size
let type = 'server_import'
xmlHttpRequest.upload.addEventListener('progress', function (e) {
if (e.loaded <= size) {
var percent = Math.round(e.loaded / size * 100);
$(`#upload-progress-bar`).css('width', percent + '%');
$(`#upload-progress-bar`).html(percent + '%');
}
});
xmlHttpRequest.open('POST', target, true);
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
@ -827,7 +836,15 @@
document.getElementById("lower_half").style.visibility = "visible";
}
else {
alert('Upload failed with response: ' + event.target.responseText);
let response_text = JSON.parse(event.target.responseText);
var x = document.querySelector('.bootbox');
console.log(JSON.parse(event.target.responseText).info)
bootbox.alert({
message: JSON.parse(event.target.responseText).info,
callback: function () {
window.location.reload();
}
});
doUpload = false;
}
}, false);

View File

@ -297,7 +297,9 @@
"shutdown": "Shutdown server for duration of backup",
"size": "Size",
"storageLocation": "Storage Location",
"storageLocationDesc": "Where do you want to store backups?"
"storageLocationDesc": "Where do you want to store backups?",
"before": "Run command before backup",
"after": "Run command after backup"
},
"serverConfig": {
"bePatientDelete": "Please be patient while we remove your server from the Crafty panel. This screen will close in a few moments.",