mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'dev' into 'lukas-jwts'
# Conflicts: # app/classes/web/panel_handler.py # app/frontend/templates/notify.html # app/translations/en_EN.json # requirements.txt
This commit is contained in:
commit
09bd01a634
@ -120,6 +120,9 @@ win-dev-build:
|
|||||||
--hidden-import apscheduler
|
--hidden-import apscheduler
|
||||||
--collect-all tzlocal
|
--collect-all tzlocal
|
||||||
--collect-all tzdata
|
--collect-all tzdata
|
||||||
|
--collect-all pytz
|
||||||
|
--collect-all six
|
||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "crafty-${CI_RUNNER_TAGS}-${CI_COMMIT_BRANCH}_${CI_COMMIT_SHORT_SHA}"
|
name: "crafty-${CI_RUNNER_TAGS}-${CI_COMMIT_BRANCH}_${CI_COMMIT_SHORT_SHA}"
|
||||||
paths:
|
paths:
|
||||||
@ -158,6 +161,9 @@ win-prod-build:
|
|||||||
--hidden-import apscheduler
|
--hidden-import apscheduler
|
||||||
--collect-all tzlocal
|
--collect-all tzlocal
|
||||||
--collect-all tzdata
|
--collect-all tzdata
|
||||||
|
--collect-all pytz
|
||||||
|
--collect-all six
|
||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "crafty-${CI_RUNNER_TAGS}-${CI_COMMIT_BRANCH}_${CI_COMMIT_SHORT_SHA}"
|
name: "crafty-${CI_RUNNER_TAGS}-${CI_COMMIT_BRANCH}_${CI_COMMIT_SHORT_SHA}"
|
||||||
paths:
|
paths:
|
||||||
|
@ -137,7 +137,6 @@ class Controller:
|
|||||||
|
|
||||||
|
|
||||||
def package_support_logs(self, exec_user):
|
def package_support_logs(self, exec_user):
|
||||||
time.sleep(5)
|
|
||||||
websocket_helper.broadcast_user(exec_user['user_id'], 'notification', 'Preparing your support logs')
|
websocket_helper.broadcast_user(exec_user['user_id'], 'notification', 'Preparing your support logs')
|
||||||
tempDir = tempfile.mkdtemp()
|
tempDir = tempfile.mkdtemp()
|
||||||
tempZipStorage = tempfile.mkdtemp()
|
tempZipStorage = tempfile.mkdtemp()
|
||||||
@ -254,6 +253,11 @@ class Controller:
|
|||||||
server_id = helper.create_uuid()
|
server_id = helper.create_uuid()
|
||||||
server_dir = os.path.join(helper.servers_dir, server_id)
|
server_dir = os.path.join(helper.servers_dir, server_id)
|
||||||
backup_path = os.path.join(helper.backup_path, server_id)
|
backup_path = os.path.join(helper.backup_path, server_id)
|
||||||
|
if helper.is_os_windows():
|
||||||
|
server_dir = helper.wtol_path(server_dir)
|
||||||
|
backup_path = helper.wtol_path(backup_path)
|
||||||
|
server_dir.replace(' ', '^ ')
|
||||||
|
backup_path.replace(' ', '^ ')
|
||||||
|
|
||||||
server_file = "{server}-{version}.jar".format(server=server, version=version)
|
server_file = "{server}-{version}.jar".format(server=server, version=version)
|
||||||
full_jar_path = os.path.join(server_dir, server_file)
|
full_jar_path = os.path.join(server_dir, server_file)
|
||||||
@ -279,7 +283,7 @@ class Controller:
|
|||||||
|
|
||||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||||
helper.float_to_string(max_mem),
|
helper.float_to_string(max_mem),
|
||||||
full_jar_path)
|
+'"'+full_jar_path+'"')
|
||||||
server_log_file = "{}/logs/latest.log".format(server_dir)
|
server_log_file = "{}/logs/latest.log".format(server_dir)
|
||||||
server_stop = "stop"
|
server_stop = "stop"
|
||||||
|
|
||||||
@ -310,6 +314,11 @@ class Controller:
|
|||||||
server_id = helper.create_uuid()
|
server_id = helper.create_uuid()
|
||||||
new_server_dir = os.path.join(helper.servers_dir, server_id)
|
new_server_dir = os.path.join(helper.servers_dir, server_id)
|
||||||
backup_path = os.path.join(helper.backup_path, server_id)
|
backup_path = os.path.join(helper.backup_path, server_id)
|
||||||
|
if helper.is_os_windows():
|
||||||
|
server_dir = helper.wtol_path(new_server_dir)
|
||||||
|
backup_path = helper.wtol_path(backup_path)
|
||||||
|
new_server_dir.replace(' ', '^ ')
|
||||||
|
backup_path.replace(' ', '^ ')
|
||||||
|
|
||||||
helper.ensure_dir_exists(new_server_dir)
|
helper.ensure_dir_exists(new_server_dir)
|
||||||
helper.ensure_dir_exists(backup_path)
|
helper.ensure_dir_exists(backup_path)
|
||||||
@ -327,9 +336,10 @@ class Controller:
|
|||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
full_jar_path = os.path.join(new_server_dir, server_jar)
|
full_jar_path = os.path.join(new_server_dir, server_jar)
|
||||||
|
|
||||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||||
helper.float_to_string(max_mem),
|
helper.float_to_string(max_mem),
|
||||||
full_jar_path)
|
+'"'+full_jar_path+'"')
|
||||||
server_log_file = "{}/logs/latest.log".format(new_server_dir)
|
server_log_file = "{}/logs/latest.log".format(new_server_dir)
|
||||||
server_stop = "stop"
|
server_stop = "stop"
|
||||||
|
|
||||||
@ -341,6 +351,12 @@ class Controller:
|
|||||||
server_id = helper.create_uuid()
|
server_id = helper.create_uuid()
|
||||||
new_server_dir = os.path.join(helper.servers_dir, server_id)
|
new_server_dir = os.path.join(helper.servers_dir, server_id)
|
||||||
backup_path = os.path.join(helper.backup_path, server_id)
|
backup_path = os.path.join(helper.backup_path, server_id)
|
||||||
|
if helper.is_os_windows():
|
||||||
|
new_server_dir = helper.wtol_path(new_server_dir)
|
||||||
|
backup_path = helper.wtol_path(backup_path)
|
||||||
|
new_server_dir.replace(' ', '^ ')
|
||||||
|
backup_path.replace(' ', '^ ')
|
||||||
|
|
||||||
tempDir = helper.get_os_understandable_path(zip_path)
|
tempDir = helper.get_os_understandable_path(zip_path)
|
||||||
helper.ensure_dir_exists(new_server_dir)
|
helper.ensure_dir_exists(new_server_dir)
|
||||||
helper.ensure_dir_exists(backup_path)
|
helper.ensure_dir_exists(backup_path)
|
||||||
@ -360,9 +376,10 @@ class Controller:
|
|||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
full_jar_path = os.path.join(new_server_dir, server_jar)
|
full_jar_path = os.path.join(new_server_dir, server_jar)
|
||||||
|
|
||||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||||
helper.float_to_string(max_mem),
|
helper.float_to_string(max_mem),
|
||||||
full_jar_path)
|
+'"'+full_jar_path+'"')
|
||||||
logger.debug('command: ' + server_command)
|
logger.debug('command: ' + server_command)
|
||||||
server_log_file = "{}/logs/latest.log".format(new_server_dir)
|
server_log_file = "{}/logs/latest.log".format(new_server_dir)
|
||||||
server_stop = "stop"
|
server_stop = "stop"
|
||||||
@ -376,6 +393,9 @@ class Controller:
|
|||||||
old_bu_path = server_data['backup_path']
|
old_bu_path = server_data['backup_path']
|
||||||
Server_Perms_Controller.backup_role_swap(old_server_id, new_server_id)
|
Server_Perms_Controller.backup_role_swap(old_server_id, new_server_id)
|
||||||
backup_path = helper.validate_traversal(helper.backup_path, old_bu_path)
|
backup_path = helper.validate_traversal(helper.backup_path, old_bu_path)
|
||||||
|
if helper.is_os_windows():
|
||||||
|
backup_path = helper.wtol_path(backup_path)
|
||||||
|
backup_path.replace(' ', '^ ')
|
||||||
backup_path_components = list(backup_path.parts)
|
backup_path_components = list(backup_path.parts)
|
||||||
backup_path_components[-1] = new_uuid
|
backup_path_components[-1] = new_uuid
|
||||||
new_bu_path = pathlib.PurePath(os.path.join(*backup_path_components))
|
new_bu_path = pathlib.PurePath(os.path.join(*backup_path_components))
|
||||||
@ -386,6 +406,7 @@ class Controller:
|
|||||||
|
|
||||||
def register_server(self, name: str, server_uuid: str, server_dir: str, backup_path: str, server_command: str, server_file: str, server_log_file: str, server_stop: str, server_port: int):
|
def register_server(self, name: str, server_uuid: str, server_dir: str, backup_path: str, server_command: str, server_file: str, server_log_file: str, server_stop: str, server_port: int):
|
||||||
# put data in the db
|
# put data in the db
|
||||||
|
|
||||||
new_id = self.servers.create_server(name, server_uuid, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, server_port)
|
new_id = self.servers.create_server(name, server_uuid, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, server_port)
|
||||||
if not helper.check_file_exists(os.path.join(server_dir, "crafty_managed.txt")):
|
if not helper.check_file_exists(os.path.join(server_dir, "crafty_managed.txt")):
|
||||||
try:
|
try:
|
||||||
|
@ -119,6 +119,8 @@ class Server:
|
|||||||
self.restart_count = 0
|
self.restart_count = 0
|
||||||
self.crash_watcher_schedule = None
|
self.crash_watcher_schedule = None
|
||||||
self.stats = stats
|
self.stats = stats
|
||||||
|
tz = get_localzone()
|
||||||
|
self.server_scheduler = BackgroundScheduler(timezone=str(tz))
|
||||||
self.backup_thread = threading.Thread(target=self.a_backup_server, daemon=True, name=f"backup_{self.name}")
|
self.backup_thread = threading.Thread(target=self.a_backup_server, daemon=True, name=f"backup_{self.name}")
|
||||||
self.is_backingup = False
|
self.is_backingup = False
|
||||||
|
|
||||||
@ -144,8 +146,6 @@ class Server:
|
|||||||
logger.info("Scheduling server {} to start in {} seconds".format(self.name, delay))
|
logger.info("Scheduling server {} to start in {} seconds".format(self.name, delay))
|
||||||
console.info("Scheduling server {} to start in {} seconds".format(self.name, delay))
|
console.info("Scheduling server {} to start in {} seconds".format(self.name, delay))
|
||||||
|
|
||||||
tz = get_localzone()
|
|
||||||
self.server_scheduler = BackgroundScheduler(timezone=str(tz))
|
|
||||||
self.server_scheduler.add_job(self.run_scheduled_server, 'interval', seconds=delay, id=str(self.server_id))
|
self.server_scheduler.add_job(self.run_scheduled_server, 'interval', seconds=delay, id=str(self.server_id))
|
||||||
self.server_scheduler.start()
|
self.server_scheduler.start()
|
||||||
|
|
||||||
@ -300,7 +300,7 @@ class Server:
|
|||||||
logger.info("Server {} has crash detection enabled - starting watcher task".format(self.name))
|
logger.info("Server {} has crash detection enabled - starting watcher task".format(self.name))
|
||||||
console.info("Server {} has crash detection enabled - starting watcher task".format(self.name))
|
console.info("Server {} has crash detection enabled - starting watcher task".format(self.name))
|
||||||
|
|
||||||
self.crash_watcher_schedule = schedule.every(30).seconds.do(self.detect_crash).tag(self.name)
|
self.crash_watcher_schedule = self.server_scheduler.add_job(self.detect_crash, 'interval', seconds=30, id="crash_watcher")
|
||||||
|
|
||||||
def check_internet_thread(self, user_id, user_lang):
|
def check_internet_thread(self, user_id, user_lang):
|
||||||
if user_id:
|
if user_id:
|
||||||
|
@ -197,13 +197,19 @@ class TasksManager:
|
|||||||
for item in jobs:
|
for item in jobs:
|
||||||
logger.info("JOB: {}".format(item))
|
logger.info("JOB: {}".format(item))
|
||||||
|
|
||||||
|
def remove_all_server_tasks(self, server_id):
|
||||||
|
schedules = management_helper.get_schedules_by_server(server_id)
|
||||||
|
for schedule in schedules:
|
||||||
|
self.remove_job(schedule.schedule_id)
|
||||||
|
|
||||||
def remove_job(self, sch_id):
|
def remove_job(self, sch_id):
|
||||||
job = management_helper.get_scheduled_task_model(sch_id)
|
job = management_helper.get_scheduled_task_model(sch_id)
|
||||||
management_helper.delete_scheduled_task(sch_id)
|
management_helper.delete_scheduled_task(sch_id)
|
||||||
if job.enabled:
|
if job.enabled:
|
||||||
self.scheduler.remove_job(str(sch_id))
|
self.scheduler.remove_job(str(sch_id))
|
||||||
|
logger.info("Job with ID {} was deleted.".format(sch_id))
|
||||||
else:
|
else:
|
||||||
logger.info("Job with ID {} was deleted from DB, but was not enabled. Not going to try removing something that doesn't exist from active schedules.")
|
logger.info("Job with ID {} was deleted from DB, but was not enabled. Not going to try removing something that doesn't exist from active schedules.".format(sch_id))
|
||||||
|
|
||||||
def update_job(self, sch_id, job_data):
|
def update_job(self, sch_id, job_data):
|
||||||
management_helper.update_scheduled_task(sch_id, job_data)
|
management_helper.update_scheduled_task(sch_id, job_data)
|
||||||
|
@ -415,6 +415,16 @@ class AjaxHandler(BaseHandler):
|
|||||||
server_id = self.get_argument('id', None)
|
server_id = self.get_argument('id', None)
|
||||||
logger.info(
|
logger.info(
|
||||||
"Removing server from panel for server: {}".format(self.controller.servers.get_server_friendly_name(server_id)))
|
"Removing server from panel for server: {}".format(self.controller.servers.get_server_friendly_name(server_id)))
|
||||||
|
|
||||||
|
server_data = self.controller.get_server_data(server_id)
|
||||||
|
server_name = server_data['server_name']
|
||||||
|
|
||||||
|
self.controller.management.add_to_audit_log(exec_user_id,
|
||||||
|
"Deleted server {} named {}".format(server_id, server_name),
|
||||||
|
server_id,
|
||||||
|
self.get_remote_ip())
|
||||||
|
|
||||||
|
self.tasks_manager.remove_all_server_tasks(server_id)
|
||||||
self.controller.remove_server(server_id, False)
|
self.controller.remove_server(server_id, False)
|
||||||
|
|
||||||
elif page == "delete_server_files":
|
elif page == "delete_server_files":
|
||||||
@ -425,6 +435,16 @@ class AjaxHandler(BaseHandler):
|
|||||||
server_id = self.get_argument('id', None)
|
server_id = self.get_argument('id', None)
|
||||||
logger.info(
|
logger.info(
|
||||||
"Removing server and all associated files for server: {}".format(self.controller.servers.get_server_friendly_name(server_id)))
|
"Removing server and all associated files for server: {}".format(self.controller.servers.get_server_friendly_name(server_id)))
|
||||||
|
|
||||||
|
server_data = self.controller.get_server_data(server_id)
|
||||||
|
server_name = server_data['server_name']
|
||||||
|
|
||||||
|
self.controller.management.add_to_audit_log(exec_user_id,
|
||||||
|
"Deleted server {} named {}".format(server_id, server_name),
|
||||||
|
server_id,
|
||||||
|
self.get_remote_ip())
|
||||||
|
|
||||||
|
self.tasks_manager.remove_all_server_tasks(server_id)
|
||||||
self.controller.remove_server(server_id, True)
|
self.controller.remove_server(server_id, True)
|
||||||
|
|
||||||
@tornado.web.authenticated
|
@tornado.web.authenticated
|
||||||
|
@ -264,28 +264,6 @@ class PanelHandler(BaseHandler):
|
|||||||
elif page == 'contribute':
|
elif page == 'contribute':
|
||||||
template = "panel/contribute.html"
|
template = "panel/contribute.html"
|
||||||
|
|
||||||
elif page == "remove_server":
|
|
||||||
server_id = self.get_argument('id', None)
|
|
||||||
|
|
||||||
if not superuser:
|
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
|
||||||
return
|
|
||||||
elif server_id is None:
|
|
||||||
self.redirect("/panel/error?error=Invalid Server ID")
|
|
||||||
return
|
|
||||||
|
|
||||||
server_data = self.controller.get_server_data(server_id)
|
|
||||||
server_name = server_data['server_name']
|
|
||||||
|
|
||||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
|
||||||
"Deleted server {} named {}".format(server_id, server_name),
|
|
||||||
server_id,
|
|
||||||
self.get_remote_ip())
|
|
||||||
|
|
||||||
self.controller.remove_server(server_id)
|
|
||||||
self.redirect("/panel/dashboard")
|
|
||||||
return
|
|
||||||
|
|
||||||
elif page == 'dashboard':
|
elif page == 'dashboard':
|
||||||
if superuser: # TODO: Figure out a better solution
|
if superuser: # TODO: Figure out a better solution
|
||||||
try:
|
try:
|
||||||
@ -313,7 +291,10 @@ class PanelHandler(BaseHandler):
|
|||||||
logger.error("Failed to get server waiting to start: {} ".format(e))
|
logger.error("Failed to get server waiting to start: {} ".format(e))
|
||||||
data['stats']['waiting_start'] = False
|
data['stats']['waiting_start'] = False
|
||||||
|
|
||||||
page_data['num_players'] = 0
|
try:
|
||||||
|
self.fetch_server_data(page_data)
|
||||||
|
except:
|
||||||
|
page_data['num_players'] = 0
|
||||||
|
|
||||||
IOLoop.current().add_callback(self.fetch_server_data, page_data)
|
IOLoop.current().add_callback(self.fetch_server_data, page_data)
|
||||||
|
|
||||||
@ -1093,7 +1074,7 @@ class PanelHandler(BaseHandler):
|
|||||||
"interval": '',
|
"interval": '',
|
||||||
"command": '',
|
"command": '',
|
||||||
#We'll base every interval off of a midnight start time.
|
#We'll base every interval off of a midnight start time.
|
||||||
"start_time": '00:00',
|
"start_time": '',
|
||||||
"command": command,
|
"command": command,
|
||||||
"cron_string": cron_string,
|
"cron_string": cron_string,
|
||||||
"enabled": enabled,
|
"enabled": enabled,
|
||||||
@ -1213,7 +1194,7 @@ class PanelHandler(BaseHandler):
|
|||||||
"interval": '',
|
"interval": '',
|
||||||
"command": '',
|
"command": '',
|
||||||
#We'll base every interval off of a midnight start time.
|
#We'll base every interval off of a midnight start time.
|
||||||
"start_time": '00:00',
|
"start_time": '',
|
||||||
"command": command,
|
"command": command,
|
||||||
"cron_string": cron_string,
|
"cron_string": cron_string,
|
||||||
"enabled": enabled,
|
"enabled": enabled,
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
<!-- Plugin css for this page -->
|
<!-- Plugin css for this page -->
|
||||||
<link rel="stylesheet" href="/static/assets/vendors/jvectormap/jquery-jvectormap.css">
|
<link rel="stylesheet" href="/static/assets/vendors/jvectormap/jquery-jvectormap.css">
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
|
||||||
<!-- End Plugin css for this page -->
|
<!-- End Plugin css for this page -->
|
||||||
|
|
||||||
<!-- Layout styles -->
|
<!-- Layout styles -->
|
||||||
@ -139,7 +140,6 @@
|
|||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.0/bootbox.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.0/bootbox.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
$.extend($.fn.dataTable.defaults, {
|
$.extend($.fn.dataTable.defaults, {
|
||||||
language: {% raw translate('datatables', 'i18n', data['lang']) %}
|
language: {% raw translate('datatables', 'i18n', data['lang']) %}
|
||||||
})
|
})
|
||||||
@ -247,8 +247,8 @@ if (webSocket) {
|
|||||||
if(x){
|
if(x){
|
||||||
x.remove()}
|
x.remove()}
|
||||||
bootbox.alert({
|
bootbox.alert({
|
||||||
title: 'Download Support Logs?',
|
title: "{{ translate('notify', 'downloadLogs', data['lang']) }}",
|
||||||
message: "We've finished preparing your support logs. Please click download to download",
|
message: "{{ translate('notify', 'finishedPreparing', data['lang']) }}",
|
||||||
buttons: {
|
buttons: {
|
||||||
ok: {
|
ok: {
|
||||||
label: 'Download',
|
label: 'Download',
|
||||||
@ -388,6 +388,19 @@ if (webSocket) {
|
|||||||
}
|
}
|
||||||
webSocket.on('notification', notify);
|
webSocket.on('notification', notify);
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
$('#support_logs').click(function(){
|
||||||
|
var dialog = bootbox.dialog({
|
||||||
|
message: '<p class="text-center mb-0"><i class="fa fa-spin fa-cog"></i>{{ translate('notify', 'preparingLogs', data['lang']) }}</p>',
|
||||||
|
closeButton: false
|
||||||
|
});
|
||||||
|
setTimeout(function(){
|
||||||
|
location.href="/panel/support_logs";
|
||||||
|
}, 6000);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
|
@ -32,11 +32,11 @@
|
|||||||
{% end %}
|
{% end %}
|
||||||
<p class="font-weight-light text-muted mb-0">Email: {{ data['user_data']['email'] }}</p>
|
<p class="font-weight-light text-muted mb-0">Email: {{ data['user_data']['email'] }}</p>
|
||||||
</div>
|
</div>
|
||||||
<a class="dropdown-item" href="/panel/support_logs"><i class="dropdown-item-icon mdi mdi-download-outline text-primary"></i> Support Logs</i></a>
|
<a class="dropdown-item" id="support_logs" ><i class="dropdown-item-icon mdi mdi-download-outline text-primary"></i>{{ translate('notify', 'supportLogs', data['lang']) }}</i></a>
|
||||||
{% if data['superuser'] %}
|
{% if data['superuser'] %}
|
||||||
<a class="dropdown-item" href="/panel/activity_logs"><i class="dropdown-item-icon mdi mdi-calendar-check-outline text-primary"></i> Activity</a>
|
<a class="dropdown-item" href="/panel/activity_logs"><i class="dropdown-item-icon mdi mdi-calendar-check-outline text-primary"></i>{{ translate('notify', 'activityLog', data['lang']) }}</a>
|
||||||
{% end %}
|
{% end %}
|
||||||
<a class="dropdown-item" href="/public/logout"><i class="dropdown-item-icon mdi mdi-power text-primary"></i>Sign Out</a>
|
<a class="dropdown-item" href="/public/logout"><i class="dropdown-item-icon mdi mdi-power text-primary"></i>{{ translate('notify', 'logout', data['lang']) }}</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
@ -180,6 +180,14 @@
|
|||||||
"cannotSee": "Not seeing everything?",
|
"cannotSee": "Not seeing everything?",
|
||||||
"cannotSeeOnMobile": "Try clicking on a scheduled task for full details."
|
"cannotSeeOnMobile": "Try clicking on a scheduled task for full details."
|
||||||
},
|
},
|
||||||
|
"notify":{
|
||||||
|
"supportLogs": "Support Logs",
|
||||||
|
"activityLog": "Activity Logs",
|
||||||
|
"logout": "Logout",
|
||||||
|
"preparingLogs": " Please wait while we prepare your logs... We`ll send a notification when they`re ready. This may take a while for large deployments.",
|
||||||
|
"downloadLogs": "Download Support Logs?",
|
||||||
|
"finishedPreparing": "We've finished preparing your support logs. Please click download to download"
|
||||||
|
},
|
||||||
"serverBackups": {
|
"serverBackups": {
|
||||||
"backupNow": "Backup Now!",
|
"backupNow": "Backup Now!",
|
||||||
"backupAtMidnight": "Auto-backup at midnight?",
|
"backupAtMidnight": "Auto-backup at midnight?",
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
cryptography~=3.4
|
cryptography==3.4
|
||||||
argon2-cffi~=20.1
|
argon2-cffi==20.1
|
||||||
bleach~=3.1
|
bleach==3.1
|
||||||
colorama~=0.4
|
colorama==0.4
|
||||||
cryptography~=3.4
|
cryptography==3.4
|
||||||
libgravatar~=1.0.0
|
libgravatar==1.0.0
|
||||||
peewee~=3.13
|
peewee==3.13
|
||||||
pexpect~=4.8
|
pexpect==4.8
|
||||||
psutil~=5.7
|
psutil==5.7
|
||||||
pyOpenSSL~=19.1.0
|
pyOpenSSL==19.1.0
|
||||||
PyYAML==5.3.1
|
PyYAML==5.3.1
|
||||||
requests~=2.26
|
requests==2.26
|
||||||
termcolor~=1.1
|
termcolor==1.1
|
||||||
tornado~=6.0
|
tornado==6.0
|
||||||
cached_property==1.5.2
|
cached_property==1.5.2
|
||||||
apscheduler~=3.8.1
|
apscheduler==3.8.1
|
||||||
cron-validator~=1.0.3
|
cron-validator==1.0.3
|
||||||
tzlocal~=4.1
|
tzlocal==4.0
|
||||||
pyjwt~=2.3
|
pyjwt==2.3
|
||||||
|
Loading…
Reference in New Issue
Block a user