mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'backups-and-stuff' into dev
This commit is contained in:
commit
506c9bb3c3
1
.gitignore
vendored
1
.gitignore
vendored
@ -18,6 +18,7 @@ venv.bak/
|
|||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
servers/
|
servers/
|
||||||
|
backups/
|
||||||
session.lock
|
session.lock
|
||||||
.header
|
.header
|
||||||
default.json
|
default.json
|
||||||
|
@ -9,7 +9,6 @@ from datetime import datetime
|
|||||||
from app.classes.shared.helpers import helper
|
from app.classes.shared.helpers import helper
|
||||||
from app.classes.shared.console import console
|
from app.classes.shared.console import console
|
||||||
from app.classes.shared.models import Servers
|
from app.classes.shared.models import Servers
|
||||||
# from app.classes.shared.controller import controller
|
|
||||||
from app.classes.minecraft.server_props import ServerProps
|
from app.classes.minecraft.server_props import ServerProps
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -8,7 +8,6 @@ import datetime
|
|||||||
|
|
||||||
from app.classes.shared.helpers import helper
|
from app.classes.shared.helpers import helper
|
||||||
from app.classes.minecraft.mc_ping import ping
|
from app.classes.minecraft.mc_ping import ping
|
||||||
from app.classes.shared.controller import controller
|
|
||||||
from app.classes.shared.models import db_helper
|
from app.classes.shared.models import db_helper
|
||||||
from app.classes.shared.models import Host_Stats, Server_Stats
|
from app.classes.shared.models import Host_Stats, Server_Stats
|
||||||
|
|
||||||
@ -17,6 +16,9 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class Stats:
|
class Stats:
|
||||||
|
|
||||||
|
def __init__(self, controller):
|
||||||
|
self.controller = controller
|
||||||
|
|
||||||
def get_node_stats(self):
|
def get_node_stats(self):
|
||||||
boot_time = datetime.datetime.fromtimestamp(psutil.boot_time())
|
boot_time = datetime.datetime.fromtimestamp(psutil.boot_time())
|
||||||
data = {}
|
data = {}
|
||||||
@ -184,7 +186,7 @@ class Stats:
|
|||||||
server_stats_list = []
|
server_stats_list = []
|
||||||
server_stats = {}
|
server_stats = {}
|
||||||
|
|
||||||
servers = controller.servers_list
|
servers = self.controller.servers_list
|
||||||
|
|
||||||
logger.info("Getting Stats for all servers...")
|
logger.info("Getting Stats for all servers...")
|
||||||
|
|
||||||
@ -211,7 +213,7 @@ class Stats:
|
|||||||
internal_ip = server_data.get('server-ip', "127.0.0.1")
|
internal_ip = server_data.get('server-ip', "127.0.0.1")
|
||||||
server_port = server_settings.get('server-port', "25565")
|
server_port = server_settings.get('server-port', "25565")
|
||||||
|
|
||||||
logger.debug("Pinging {} on port {}".format(internal_ip, server_port))
|
logger.debug("Pinging server '{}' on {}:{}".format(s.get('server_name', "ID#{}".format(server_id)), internal_ip, server_port))
|
||||||
int_mc_ping = ping(internal_ip, int(server_port))
|
int_mc_ping = ping(internal_ip, int(server_port))
|
||||||
|
|
||||||
int_data = False
|
int_data = False
|
||||||
@ -289,5 +291,3 @@ class Stats:
|
|||||||
|
|
||||||
Host_Stats.delete().where(Host_Stats.time < last_week).execute()
|
Host_Stats.delete().where(Host_Stats.time < last_week).execute()
|
||||||
Server_Stats.delete().where(Server_Stats.created < last_week).execute()
|
Server_Stats.delete().where(Server_Stats.created < last_week).execute()
|
||||||
|
|
||||||
stats = Stats()
|
|
||||||
|
@ -20,7 +20,11 @@ except ModuleNotFoundError as e:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
class MainPrompt(cmd.Cmd):
|
class MainPrompt(cmd.Cmd, object):
|
||||||
|
|
||||||
|
def __init__(self, tasks_manager):
|
||||||
|
super().__init__()
|
||||||
|
self.tasks_manager = tasks_manager
|
||||||
|
|
||||||
# overrides the default Prompt
|
# overrides the default Prompt
|
||||||
prompt = "Crafty Controller v{} > ".format(helper.get_version_string())
|
prompt = "Crafty Controller v{} > ".format(helper.get_version_string())
|
||||||
|
@ -15,6 +15,7 @@ from app.classes.shared.models import db_helper, Servers, User_Servers
|
|||||||
from app.classes.shared.server import Server
|
from app.classes.shared.server import Server
|
||||||
from app.classes.minecraft.server_props import ServerProps
|
from app.classes.minecraft.server_props import ServerProps
|
||||||
from app.classes.minecraft.serverjars import server_jar_obj
|
from app.classes.minecraft.serverjars import server_jar_obj
|
||||||
|
from app.classes.minecraft.stats import Stats
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ class Controller:
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.servers_list = []
|
self.servers_list = []
|
||||||
|
self.stats = Stats(self)
|
||||||
|
|
||||||
def check_server_loaded(self, server_id_to_check: int):
|
def check_server_loaded(self, server_id_to_check: int):
|
||||||
|
|
||||||
@ -72,7 +74,7 @@ class Controller:
|
|||||||
temp_server_dict = {
|
temp_server_dict = {
|
||||||
'server_id': s.get('server_id'),
|
'server_id': s.get('server_id'),
|
||||||
'server_data_obj': s,
|
'server_data_obj': s,
|
||||||
'server_obj': Server(),
|
'server_obj': Server(self.stats),
|
||||||
'server_settings': settings.props
|
'server_settings': settings.props
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +96,6 @@ class Controller:
|
|||||||
server_obj.reload_server_settings()
|
server_obj.reload_server_settings()
|
||||||
|
|
||||||
def get_server_obj(self, server_id):
|
def get_server_obj(self, server_id):
|
||||||
|
|
||||||
for s in self.servers_list:
|
for s in self.servers_list:
|
||||||
if int(s['server_id']) == int(server_id):
|
if int(s['server_id']) == int(server_id):
|
||||||
return s['server_obj']
|
return s['server_obj']
|
||||||
@ -196,12 +197,14 @@ class Controller:
|
|||||||
def create_jar_server(self, server: str, version: str, name: str, min_mem: int, max_mem: int, port: int):
|
def create_jar_server(self, server: str, version: str, name: str, min_mem: int, max_mem: int, port: int):
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
# make the dir - perhaps a UUID?
|
# make the dir - perhaps a UUID?
|
||||||
helper.ensure_dir_exists(server_dir)
|
helper.ensure_dir_exists(server_dir)
|
||||||
|
helper.ensure_dir_exists(backup_path)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# do a eula.txt
|
# do a eula.txt
|
||||||
@ -227,7 +230,7 @@ class Controller:
|
|||||||
# download the jar
|
# download the jar
|
||||||
server_jar_obj.download_jar(server, version, full_jar_path)
|
server_jar_obj.download_jar(server, version, full_jar_path)
|
||||||
|
|
||||||
new_id = self.register_server(name, server_id, server_dir, server_command, server_file, server_log_file, server_stop)
|
new_id = self.register_server(name, server_id, server_dir, backup_path, server_command, server_file, server_log_file, server_stop)
|
||||||
return new_id
|
return new_id
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -248,8 +251,10 @@ class Controller:
|
|||||||
def import_jar_server(self, server_name: str, server_path: str, server_jar: str, min_mem: int, max_mem: int, port: int):
|
def import_jar_server(self, server_name: str, server_path: str, server_jar: str, min_mem: int, max_mem: int, port: int):
|
||||||
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)
|
||||||
|
|
||||||
helper.ensure_dir_exists(new_server_dir)
|
helper.ensure_dir_exists(new_server_dir)
|
||||||
|
helper.ensure_dir_exists(backup_path)
|
||||||
dir_util.copy_tree(server_path, new_server_dir)
|
dir_util.copy_tree(server_path, new_server_dir)
|
||||||
|
|
||||||
full_jar_path = os.path.join(new_server_dir, server_jar)
|
full_jar_path = os.path.join(new_server_dir, server_jar)
|
||||||
@ -259,15 +264,18 @@ class Controller:
|
|||||||
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"
|
||||||
|
|
||||||
new_id = self.register_server(server_name, server_id, new_server_dir, server_command, server_jar,
|
new_id = self.register_server(server_name, server_id, new_server_dir, backup_path, server_command, server_jar,
|
||||||
server_log_file, server_stop, port)
|
server_log_file, server_stop, port)
|
||||||
return new_id
|
return new_id
|
||||||
|
|
||||||
def import_zip_server(self, server_name: str, zip_path: str, server_jar: str, min_mem: int, max_mem: int, port: int):
|
def import_zip_server(self, server_name: str, zip_path: str, server_jar: str, min_mem: int, max_mem: int, port: int):
|
||||||
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)
|
||||||
|
|
||||||
if helper.check_file_perms(zip_path):
|
if helper.check_file_perms(zip_path):
|
||||||
helper.ensure_dir_exists(new_server_dir)
|
helper.ensure_dir_exists(new_server_dir)
|
||||||
|
helper.ensure_dir_exists(backup_path)
|
||||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||||
zip_ref.extractall(new_server_dir)
|
zip_ref.extractall(new_server_dir)
|
||||||
else:
|
else:
|
||||||
@ -281,11 +289,11 @@ class Controller:
|
|||||||
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"
|
||||||
|
|
||||||
new_id = self.register_server(server_name, server_id, new_server_dir, server_command, server_jar,
|
new_id = self.register_server(server_name, server_id, new_server_dir, backup_path, server_command, server_jar,
|
||||||
server_log_file, server_stop, port)
|
server_log_file, server_stop, port)
|
||||||
return new_id
|
return new_id
|
||||||
|
|
||||||
def register_server(self, name: str, server_id: str, server_dir: str, server_command: str, server_file: str, server_log_file: str, server_stop: str, server_port=25565):
|
def register_server(self, name: str, server_id: str, server_dir: str, backup_path: str, server_command: str, server_file: str, server_log_file: str, server_stop: str, server_port=25565):
|
||||||
# put data in the db
|
# put data in the db
|
||||||
new_id = Servers.insert({
|
new_id = Servers.insert({
|
||||||
Servers.server_name: name,
|
Servers.server_name: name,
|
||||||
@ -298,7 +306,8 @@ class Controller:
|
|||||||
Servers.crash_detection: False,
|
Servers.crash_detection: False,
|
||||||
Servers.log_path: server_log_file,
|
Servers.log_path: server_log_file,
|
||||||
Servers.server_port: server_port,
|
Servers.server_port: server_port,
|
||||||
Servers.stop_command: server_stop
|
Servers.stop_command: server_stop,
|
||||||
|
Servers.backup_path: backup_path
|
||||||
}).execute()
|
}).execute()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -343,5 +352,3 @@ class Controller:
|
|||||||
self.servers_list.pop(counter)
|
self.servers_list.pop(counter)
|
||||||
|
|
||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
controller = Controller()
|
|
||||||
|
8
app/classes/shared/exceptions.py
Normal file
8
app/classes/shared/exceptions.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
class CraftyException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class DatabaseException(CraftyException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class SchemaError(DatabaseException):
|
||||||
|
pass
|
@ -10,6 +10,8 @@ import socket
|
|||||||
import random
|
import random
|
||||||
import logging
|
import logging
|
||||||
import html
|
import html
|
||||||
|
import zipfile
|
||||||
|
import pathlib
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from socket import gethostname
|
from socket import gethostname
|
||||||
@ -36,6 +38,7 @@ class Helpers:
|
|||||||
self.config_dir = os.path.join(self.root_dir, 'app', 'config')
|
self.config_dir = os.path.join(self.root_dir, 'app', 'config')
|
||||||
self.webroot = os.path.join(self.root_dir, 'app', 'frontend')
|
self.webroot = os.path.join(self.root_dir, 'app', 'frontend')
|
||||||
self.servers_dir = os.path.join(self.root_dir, 'servers')
|
self.servers_dir = os.path.join(self.root_dir, 'servers')
|
||||||
|
self.backup_path = os.path.join(self.root_dir, 'backups')
|
||||||
|
|
||||||
self.session_file = os.path.join(self.root_dir, 'app', 'config', 'session.lock')
|
self.session_file = os.path.join(self.root_dir, 'app', 'config', 'session.lock')
|
||||||
self.settings_file = os.path.join(self.root_dir, 'app', 'config', 'config.json')
|
self.settings_file = os.path.join(self.root_dir, 'app', 'config', 'config.json')
|
||||||
@ -43,6 +46,7 @@ class Helpers:
|
|||||||
self.ensure_dir_exists(os.path.join(self.root_dir, 'app', 'config', 'db'))
|
self.ensure_dir_exists(os.path.join(self.root_dir, 'app', 'config', 'db'))
|
||||||
self.db_path = os.path.join(self.root_dir, 'app', 'config', 'db', 'crafty.sqlite')
|
self.db_path = os.path.join(self.root_dir, 'app', 'config', 'db', 'crafty.sqlite')
|
||||||
self.serverjar_cache = os.path.join(self.config_dir, 'serverjars.json')
|
self.serverjar_cache = os.path.join(self.config_dir, 'serverjars.json')
|
||||||
|
self.credits_cache = os.path.join(self.config_dir, 'credits.json')
|
||||||
self.passhasher = PasswordHasher()
|
self.passhasher = PasswordHasher()
|
||||||
self.exiting = False
|
self.exiting = False
|
||||||
|
|
||||||
@ -305,6 +309,8 @@ class Helpers:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_path_exists(path: str):
|
def check_path_exists(path: str):
|
||||||
|
if not path:
|
||||||
|
return False
|
||||||
logger.debug('Looking for path: {}'.format(path))
|
logger.debug('Looking for path: {}'.format(path))
|
||||||
|
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
@ -371,6 +377,19 @@ class Helpers:
|
|||||||
total += entry.stat(follow_symlinks=False).st_size
|
total += entry.stat(follow_symlinks=False).st_size
|
||||||
return total
|
return total
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def list_dir_by_date(path: str, reverse=False):
|
||||||
|
return [str(p) for p in sorted(pathlib.Path(path).iterdir(), key=os.path.getmtime, reverse=reverse)]
|
||||||
|
|
||||||
|
def get_human_readable_files_sizes(self, paths: list):
|
||||||
|
sizes = []
|
||||||
|
for p in paths:
|
||||||
|
sizes.append({
|
||||||
|
"path": p,
|
||||||
|
"size": self.human_readable_file_size(os.stat(p).st_size)
|
||||||
|
})
|
||||||
|
return sizes
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def base64_encode_string(string: str):
|
def base64_encode_string(string: str):
|
||||||
s_bytes = str(string).encode('utf-8')
|
s_bytes = str(string).encode('utf-8')
|
||||||
@ -520,7 +539,7 @@ class Helpers:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def get_banned_players(server_id, db_helper):
|
def get_banned_players(server_id, db_helper):
|
||||||
stats = db_helper.get_server_stats_by_id(server_id)
|
stats = db_helper.get_server_stats_by_id(server_id)
|
||||||
server_path = stats[0]['server_id']['path']
|
server_path = stats['server_id']['path']
|
||||||
path = os.path.join(server_path, 'banned-players.json')
|
path = os.path.join(server_path, 'banned-players.json')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -533,5 +552,13 @@ class Helpers:
|
|||||||
|
|
||||||
return json.loads(content)
|
return json.loads(content)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def zip_directory(file, path, compression=zipfile.ZIP_LZMA):
|
||||||
|
with zipfile.ZipFile(file, 'w', compression) as zf:
|
||||||
|
for root, dirs, files in os.walk(path):
|
||||||
|
for file in files:
|
||||||
|
zf.write(os.path.join(root, file),
|
||||||
|
os.path.relpath(os.path.join(root, file),
|
||||||
|
os.path.join(path, '..')))
|
||||||
|
|
||||||
helper = Helpers()
|
helper = Helpers()
|
||||||
|
@ -9,6 +9,8 @@ from app.classes.minecraft.server_props import ServerProps
|
|||||||
from app.classes.web.websocket_helper import websocket_helper
|
from app.classes.web.websocket_helper import websocket_helper
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
peewee_logger = logging.getLogger('peewee')
|
||||||
|
peewee_logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from peewee import *
|
from peewee import *
|
||||||
@ -20,15 +22,30 @@ except ModuleNotFoundError as e:
|
|||||||
console.critical("Import Error: Unable to load {} module".format(e, e.name))
|
console.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
schema_version = (0, 1, 0) # major, minor, patch semver
|
||||||
|
|
||||||
database = SqliteDatabase(helper.db_path, pragmas={
|
database = SqliteDatabase(helper.db_path, pragmas={
|
||||||
'journal_mode': 'wal',
|
'journal_mode': 'wal',
|
||||||
'cache_size': -1024 * 10})
|
'cache_size': -1024 * 10})
|
||||||
|
|
||||||
|
|
||||||
class BaseModel(Model):
|
class BaseModel(Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
database = database
|
database = database
|
||||||
|
|
||||||
|
class SchemaVersion(BaseModel):
|
||||||
|
# DO NOT EVER CHANGE THE SCHEMA OF THIS TABLE
|
||||||
|
# (unless we have a REALLY good reason to)
|
||||||
|
# There will only ever be one row, and it allows the database loader to detect
|
||||||
|
# what it needs to do on major version upgrades so you don't have to wipe the DB
|
||||||
|
# every time you upgrade
|
||||||
|
schema_major = IntegerField()
|
||||||
|
schema_minor = IntegerField()
|
||||||
|
schema_patch = IntegerField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
table_name = 'schema_version'
|
||||||
|
primary_key = CompositeKey('schema_major', 'schema_minor', 'schema_patch')
|
||||||
|
|
||||||
|
|
||||||
class Users(BaseModel):
|
class Users(BaseModel):
|
||||||
user_id = AutoField()
|
user_id = AutoField()
|
||||||
@ -97,6 +114,7 @@ class Servers(BaseModel):
|
|||||||
server_uuid = CharField(default="", index=True)
|
server_uuid = CharField(default="", index=True)
|
||||||
server_name = CharField(default="Server", index=True)
|
server_name = CharField(default="Server", index=True)
|
||||||
path = CharField(default="")
|
path = CharField(default="")
|
||||||
|
backup_path = CharField(default="")
|
||||||
executable = CharField(default="")
|
executable = CharField(default="")
|
||||||
log_path = CharField(default="")
|
log_path = CharField(default="")
|
||||||
execution_command = CharField(default="")
|
execution_command = CharField(default="")
|
||||||
@ -111,16 +129,6 @@ class Servers(BaseModel):
|
|||||||
class Meta:
|
class Meta:
|
||||||
table_name = "servers"
|
table_name = "servers"
|
||||||
|
|
||||||
|
|
||||||
class User_Servers(BaseModel):
|
|
||||||
user_id = ForeignKeyField(Users, backref='user_server')
|
|
||||||
server_id = ForeignKeyField(Servers, backref='user_server')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
table_name = 'user_servers'
|
|
||||||
primary_key = CompositeKey('user_id', 'server_id')
|
|
||||||
|
|
||||||
|
|
||||||
class Role_Servers(BaseModel):
|
class Role_Servers(BaseModel):
|
||||||
role_id = ForeignKeyField(Roles, backref='role_server')
|
role_id = ForeignKeyField(Roles, backref='role_server')
|
||||||
server_id = ForeignKeyField(Servers, backref='role_server')
|
server_id = ForeignKeyField(Servers, backref='role_server')
|
||||||
@ -178,12 +186,25 @@ class Webhooks(BaseModel):
|
|||||||
class Meta:
|
class Meta:
|
||||||
table_name = "webhooks"
|
table_name = "webhooks"
|
||||||
|
|
||||||
|
class Schedules(BaseModel):
|
||||||
|
schedule_id = IntegerField(unique=True, primary_key=True)
|
||||||
|
server_id = ForeignKeyField(Servers, backref='schedule_server')
|
||||||
|
enabled = BooleanField()
|
||||||
|
action = CharField()
|
||||||
|
interval = IntegerField()
|
||||||
|
interval_type = CharField()
|
||||||
|
start_time = CharField(null=True)
|
||||||
|
command = CharField(null=True)
|
||||||
|
comment = CharField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
table_name = 'schedules'
|
||||||
|
|
||||||
class Backups(BaseModel):
|
class Backups(BaseModel):
|
||||||
directories = CharField()
|
directories = CharField(null=True)
|
||||||
storage_location = CharField()
|
|
||||||
max_backups = IntegerField()
|
max_backups = IntegerField()
|
||||||
server_id = IntegerField(index=True)
|
server_id = ForeignKeyField(Servers, backref='backups_server')
|
||||||
|
schedule_id = ForeignKeyField(Schedules, backref='backups_schedule')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
table_name = 'backups'
|
table_name = 'backups'
|
||||||
@ -202,17 +223,23 @@ class db_builder:
|
|||||||
Host_Stats,
|
Host_Stats,
|
||||||
Webhooks,
|
Webhooks,
|
||||||
Servers,
|
Servers,
|
||||||
User_Servers,
|
|
||||||
Role_Servers,
|
Role_Servers,
|
||||||
Server_Stats,
|
Server_Stats,
|
||||||
Commands,
|
Commands,
|
||||||
Audit_Log
|
Audit_Log,
|
||||||
|
SchemaVersion,
|
||||||
|
Schedules
|
||||||
])
|
])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def default_settings():
|
def default_settings():
|
||||||
logger.info("Fresh Install Detected - Creating Default Settings")
|
logger.info("Fresh Install Detected - Creating Default Settings")
|
||||||
console.info("Fresh Install Detected - Creating Default Settings")
|
console.info("Fresh Install Detected - Creating Default Settings")
|
||||||
|
SchemaVersion.insert({
|
||||||
|
SchemaVersion.schema_major: schema_version[0],
|
||||||
|
SchemaVersion.schema_minor: schema_version[1],
|
||||||
|
SchemaVersion.schema_patch: schema_version[2]
|
||||||
|
}).execute()
|
||||||
default_data = helper.find_default_password()
|
default_data = helper.find_default_password()
|
||||||
|
|
||||||
username = default_data.get("username", 'admin')
|
username = default_data.get("username", 'admin')
|
||||||
@ -239,9 +266,39 @@ class db_builder:
|
|||||||
return True
|
return True
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_schema_version():
|
||||||
|
svs = SchemaVersion.select().execute()
|
||||||
|
if len(svs) != 1:
|
||||||
|
raise exceptions.SchemaError("Multiple or no schema versions detected - potentially a failed upgrade?")
|
||||||
|
sv = svs[0]
|
||||||
|
svt = (sv.schema_major, sv.schema_minor, sv.schema_patch)
|
||||||
|
logger.debug("Schema: found {}, expected {}".format(svt, schema_version))
|
||||||
|
console.debug("Schema: found {}, expected {}".format(svt, schema_version))
|
||||||
|
if sv.schema_major > schema_version[0]:
|
||||||
|
raise exceptions.SchemaError("Major version mismatch - possible code reversion")
|
||||||
|
elif sv.schema_major < schema_version[0]:
|
||||||
|
db_shortcuts.upgrade_schema()
|
||||||
|
|
||||||
|
if sv.schema_minor > schema_version[1]:
|
||||||
|
logger.warning("Schema minor mismatch detected: found {}, expected {}. Proceed with caution".format(svt, schema_version))
|
||||||
|
console.warning("Schema minor mismatch detected: found {}, expected {}. Proceed with caution".format(svt, schema_version))
|
||||||
|
elif sv.schema_minor < schema_version[1]:
|
||||||
|
db_shortcuts.upgrade_schema()
|
||||||
|
|
||||||
|
if sv.schema_patch > schema_version[2]:
|
||||||
|
logger.info("Schema patch mismatch detected: found {}, expected {}. Proceed with caution".format(svt, schema_version))
|
||||||
|
console.info("Schema patch mismatch detected: found {}, expected {}. Proceed with caution".format(svt, schema_version))
|
||||||
|
elif sv.schema_patch < schema_version[2]:
|
||||||
|
db_shortcuts.upgrade_schema()
|
||||||
|
logger.info("Schema validation successful! {}".format(schema_version))
|
||||||
|
|
||||||
class db_shortcuts:
|
class db_shortcuts:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def upgrade_schema():
|
||||||
|
raise NotImplemented("I don't know who you are or how you reached this code, but this should NOT have happened. Please report it to the developer with due haste.")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def return_rows(query):
|
def return_rows(query):
|
||||||
rows = []
|
rows = []
|
||||||
@ -258,13 +315,12 @@ class db_shortcuts:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_server_data_by_id(server_id):
|
def get_server_data_by_id(server_id):
|
||||||
|
query = Servers.select().where(Servers.server_id == server_id).limit(1)
|
||||||
try:
|
try:
|
||||||
query = Servers.get_by_id(server_id)
|
return db_helper.return_rows(query)[0]
|
||||||
except DoesNotExist:
|
except IndexError:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
return model_to_dict(query)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all_defined_servers():
|
def get_all_defined_servers():
|
||||||
query = Servers.select()
|
query = Servers.select()
|
||||||
@ -307,7 +363,7 @@ class db_shortcuts:
|
|||||||
|
|
||||||
for s in servers:
|
for s in servers:
|
||||||
latest = Server_Stats.select().where(Server_Stats.server_id == s.get('server_id')).order_by(Server_Stats.created.desc()).limit(1)
|
latest = Server_Stats.select().where(Server_Stats.server_id == s.get('server_id')).order_by(Server_Stats.created.desc()).limit(1)
|
||||||
server_data.append({'server_data': s, "stats": db_helper.return_rows(latest)})
|
server_data.append({'server_data': s, "stats": db_helper.return_rows(latest)[0]})
|
||||||
return server_data
|
return server_data
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -352,7 +408,7 @@ class db_shortcuts:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def get_server_stats_by_id(server_id):
|
def get_server_stats_by_id(server_id):
|
||||||
stats = Server_Stats.select().where(Server_Stats.server_id == server_id).order_by(Server_Stats.created.desc()).limit(1)
|
stats = Server_Stats.select().where(Server_Stats.server_id == server_id).order_by(Server_Stats.created.desc()).limit(1)
|
||||||
return db_helper.return_rows(stats)
|
return db_helper.return_rows(stats)[0]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def server_id_exists(server_id):
|
def server_id_exists(server_id):
|
||||||
@ -417,6 +473,8 @@ class db_shortcuts:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_userid_by_name(username):
|
def get_userid_by_name(username):
|
||||||
|
if username == "SYSTEM":
|
||||||
|
return 0
|
||||||
try:
|
try:
|
||||||
return (Users.get(Users.username == username)).user_id
|
return (Users.get(Users.username == username)).user_id
|
||||||
except DoesNotExist:
|
except DoesNotExist:
|
||||||
@ -424,6 +482,21 @@ class db_shortcuts:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_user(user_id):
|
def get_user(user_id):
|
||||||
|
if user_id == 0:
|
||||||
|
return {
|
||||||
|
user_id: 0,
|
||||||
|
created: None,
|
||||||
|
last_login: None,
|
||||||
|
last_update: None,
|
||||||
|
last_ip: "127.27.23.89",
|
||||||
|
username: "SYSTEM",
|
||||||
|
password: None,
|
||||||
|
enabled: True,
|
||||||
|
superuser: False,
|
||||||
|
api_token: None,
|
||||||
|
roles: [],
|
||||||
|
servers: []
|
||||||
|
}
|
||||||
user = model_to_dict(Users.get(Users.user_id == user_id))
|
user = model_to_dict(Users.get(Users.user_id == user_id))
|
||||||
|
|
||||||
if user:
|
if user:
|
||||||
@ -432,13 +505,13 @@ class db_shortcuts:
|
|||||||
roles = set()
|
roles = set()
|
||||||
for r in roles_query:
|
for r in roles_query:
|
||||||
roles.add(r.role_id.role_id)
|
roles.add(r.role_id.role_id)
|
||||||
servers_query = User_Servers.select().join(Servers, JOIN.INNER).where(User_Servers.user_id == user_id)
|
#servers_query = User_Servers.select().join(Servers, JOIN.INNER).where(User_Servers.user_id == user_id)
|
||||||
# TODO: this query needs to be narrower
|
## TODO: this query needs to be narrower
|
||||||
servers = set()
|
servers = set()
|
||||||
for s in servers_query:
|
#for s in servers_query:
|
||||||
servers.add(s.server_id.server_id)
|
# servers.add(s.server_id.server_id)
|
||||||
user['roles'] = roles
|
user['roles'] = roles
|
||||||
user['servers'] = servers
|
#user['servers'] = servers
|
||||||
logger.debug("user: ({}) {}".format(user_id, user))
|
logger.debug("user: ({}) {}".format(user_id, user))
|
||||||
return user
|
return user
|
||||||
else:
|
else:
|
||||||
@ -478,10 +551,10 @@ class db_shortcuts:
|
|||||||
# TODO: This is horribly inefficient and we should be using bulk queries but im going for functionality at this point
|
# TODO: This is horribly inefficient and we should be using bulk queries but im going for functionality at this point
|
||||||
User_Roles.delete().where(User_Roles.user_id == user_id).where(User_Roles.role_id.in_(removed_roles)).execute()
|
User_Roles.delete().where(User_Roles.user_id == user_id).where(User_Roles.role_id.in_(removed_roles)).execute()
|
||||||
|
|
||||||
for server in added_servers:
|
#for server in added_servers:
|
||||||
User_Servers.get_or_create(user_id=user_id, server_id=server)
|
# User_Servers.get_or_create(user_id=user_id, server_id=server)
|
||||||
# TODO: This is horribly inefficient and we should be using bulk queries but im going for functionality at this point
|
# # TODO: This is horribly inefficient and we should be using bulk queries but im going for functionality at this point
|
||||||
User_Servers.delete().where(User_Servers.user_id == user_id).where(User_Servers.server_id.in_(removed_servers)).execute()
|
#User_Servers.delete().where(User_Servers.user_id == user_id).where(User_Servers.server_id.in_(removed_servers)).execute()
|
||||||
if up_data:
|
if up_data:
|
||||||
Users.update(up_data).where(Users.user_id == user_id).execute()
|
Users.update(up_data).where(Users.user_id == user_id).execute()
|
||||||
|
|
||||||
@ -658,8 +731,111 @@ class db_shortcuts:
|
|||||||
Audit_Log.source_ip: source_ip
|
Audit_Log.source_ip: source_ip
|
||||||
}).execute()
|
}).execute()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_scheduled_task(server_id, action, interval, interval_type, start_time, command, comment=None, enabled=True):
|
||||||
|
sch_id = Schedules.insert({
|
||||||
|
Schedules.server_id: server_id,
|
||||||
|
Schedules.action: action,
|
||||||
|
Schedules.enabled: enabled,
|
||||||
|
Schedules.interval: interval,
|
||||||
|
Schedules.interval_type: interval_type,
|
||||||
|
Schedules.start_time: start_time,
|
||||||
|
Schedules.command: command,
|
||||||
|
Schedules.comment: comment
|
||||||
|
}).execute()
|
||||||
|
return sch_id
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete_scheduled_task(schedule_id):
|
||||||
|
sch = Schedules.get(Schedules.schedule_id == schedule_id)
|
||||||
|
return Schedules.delete_instance(sch)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def update_scheduled_task(schedule_id, updates):
|
||||||
|
Schedules.update(updates).where(Schedules.schedule_id == schedule_id).execute()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_scheduled_task(schedule_id):
|
||||||
|
return model_to_dict(Schedules.get(Schedules.schedule_id == schedule_id)).execute()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_schedules_by_server(server_id):
|
||||||
|
return Schedules.select().where(Schedules.server_id == server_id).execute()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_schedules_all():
|
||||||
|
return Schedules.select().execute()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_schedules_enabled():
|
||||||
|
return Schedules.select().where(Schedules.enabled == True).execute()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_backup_config(server_id):
|
||||||
|
try:
|
||||||
|
row = Backups.select().where(Backups.server_id == server_id).join(Schedules).join(Servers)[0]
|
||||||
|
conf = {
|
||||||
|
"backup_path": row.server_id.backup_path,
|
||||||
|
"directories": row.directories,
|
||||||
|
"max_backups": row.max_backups,
|
||||||
|
"auto_enabled": row.schedule_id.enabled,
|
||||||
|
"server_id": row.server_id.server_id
|
||||||
|
}
|
||||||
|
except IndexError:
|
||||||
|
conf = {
|
||||||
|
"backup_path": None,
|
||||||
|
"directories": None,
|
||||||
|
"max_backups": 0,
|
||||||
|
"auto_enabled": True,
|
||||||
|
"server_id": server_id
|
||||||
|
}
|
||||||
|
return conf
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set_backup_config(server_id: int, backup_path: str = None, max_backups: int = None, auto_enabled: bool = True):
|
||||||
|
logger.debug("Updating server {} backup config with {}".format(server_id, locals()))
|
||||||
|
try:
|
||||||
|
row = Backups.select().where(Backups.server_id == server_id).join(Schedules).join(Servers)[0]
|
||||||
|
new_row = False
|
||||||
|
conf = {}
|
||||||
|
schd = {}
|
||||||
|
except IndexError:
|
||||||
|
conf = {
|
||||||
|
"directories": None,
|
||||||
|
"max_backups": 0,
|
||||||
|
"server_id": server_id
|
||||||
|
}
|
||||||
|
schd = {
|
||||||
|
"enabled": True,
|
||||||
|
"action": "backup_server",
|
||||||
|
"interval_type": "days",
|
||||||
|
"interval": 1,
|
||||||
|
"start_time": "00:00",
|
||||||
|
"server_id": server_id,
|
||||||
|
"comment": "Default backup job"
|
||||||
|
}
|
||||||
|
new_row = True
|
||||||
|
if max_backups is not None:
|
||||||
|
conf['max_backups'] = max_backups
|
||||||
|
schd['enabled'] = bool(auto_enabled)
|
||||||
|
if not new_row:
|
||||||
|
with database.atomic():
|
||||||
|
if backup_path is not None:
|
||||||
|
u1 = Servers.update(backup_path=backup_path).where(Servers.server_id == server_id).execute()
|
||||||
|
else:
|
||||||
|
u1 = 0
|
||||||
|
u2 = Backups.update(conf).where(Backups.server_id == server_id).execute()
|
||||||
|
u3 = Schedules.update(schd).where(Schedules.schedule_id == row.schedule_id).execute()
|
||||||
|
logger.debug("Updating existing backup record. {}+{}+{} rows affected".format(u1, u2, u3))
|
||||||
|
else:
|
||||||
|
with database.atomic():
|
||||||
|
conf["server_id"] = server_id
|
||||||
|
if backup_path is not None:
|
||||||
|
u = Servers.update(backup_path=backup_path).where(Servers.server_id == server_id)
|
||||||
|
s = Schedules.create(**schd)
|
||||||
|
conf['schedule_id'] = s.schedule_id
|
||||||
|
b = Backups.create(**conf)
|
||||||
|
logger.debug("Creating new backup record.")
|
||||||
|
|
||||||
installer = db_builder()
|
installer = db_builder()
|
||||||
db_helper = db_shortcuts()
|
db_helper = db_shortcuts()
|
@ -9,6 +9,7 @@ import datetime
|
|||||||
import threading
|
import threading
|
||||||
import schedule
|
import schedule
|
||||||
import logging.config
|
import logging.config
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
|
||||||
from app.classes.shared.helpers import helper
|
from app.classes.shared.helpers import helper
|
||||||
@ -29,7 +30,7 @@ except ModuleNotFoundError as e:
|
|||||||
|
|
||||||
class Server:
|
class Server:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, stats):
|
||||||
# holders for our process
|
# holders for our process
|
||||||
self.process = None
|
self.process = None
|
||||||
self.line = False
|
self.line = False
|
||||||
@ -45,6 +46,7 @@ class Server:
|
|||||||
self.is_crashed = False
|
self.is_crashed = False
|
||||||
self.restart_count = 0
|
self.restart_count = 0
|
||||||
self.crash_watcher_schedule = None
|
self.crash_watcher_schedule = None
|
||||||
|
self.stats = stats
|
||||||
|
|
||||||
def reload_server_settings(self):
|
def reload_server_settings(self):
|
||||||
server_data = db_helper.get_server_data_by_id(self.server_id)
|
server_data = db_helper.get_server_data_by_id(self.server_id)
|
||||||
@ -108,7 +110,6 @@ class Server:
|
|||||||
helper.do_exit()
|
helper.do_exit()
|
||||||
|
|
||||||
def start_server(self):
|
def start_server(self):
|
||||||
from app.classes.minecraft.stats import stats
|
|
||||||
|
|
||||||
# fail safe in case we try to start something already running
|
# fail safe in case we try to start something already running
|
||||||
if self.check_running():
|
if self.check_running():
|
||||||
@ -155,7 +156,6 @@ class Server:
|
|||||||
self.server_thread.join()
|
self.server_thread.join()
|
||||||
|
|
||||||
def stop_server(self):
|
def stop_server(self):
|
||||||
from app.classes.minecraft.stats import stats
|
|
||||||
if self.settings['stop_command']:
|
if self.settings['stop_command']:
|
||||||
self.send_command(self.settings['stop_command'])
|
self.send_command(self.settings['stop_command'])
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ class Server:
|
|||||||
# massive resetting of variables
|
# massive resetting of variables
|
||||||
self.cleanup_server_object()
|
self.cleanup_server_object()
|
||||||
|
|
||||||
stats.record_stats()
|
self.stats.record_stats()
|
||||||
|
|
||||||
def restart_threaded_server(self):
|
def restart_threaded_server(self):
|
||||||
|
|
||||||
@ -318,3 +318,26 @@ class Server:
|
|||||||
logger.info("Removing old crash detection watcher thread")
|
logger.info("Removing old crash detection watcher thread")
|
||||||
console.info("Removing old crash detection watcher thread")
|
console.info("Removing old crash detection watcher thread")
|
||||||
schedule.clear(self.name)
|
schedule.clear(self.name)
|
||||||
|
|
||||||
|
def backup_server(self):
|
||||||
|
logger.info("Starting server {} (ID {}) backup".format(self.name, self.server_id))
|
||||||
|
conf = db_helper.get_backup_config(self.server_id)
|
||||||
|
try:
|
||||||
|
backup_filename = "{}/{}.zip".format(conf['backup_path'], datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S'))
|
||||||
|
logger.info("Creating backup of server '{}' (ID#{}) at '{}'".format(self.settings['server_name'], self.server_id, backup_filename))
|
||||||
|
helper.zip_directory(backup_filename, self.server_path)
|
||||||
|
backup_list = self.list_backups()
|
||||||
|
if len(self.list_backups()) > conf["max_backups"]:
|
||||||
|
oldfile = backup_list[0]
|
||||||
|
logger.info("Removing old backup '{}'".format(oldfile))
|
||||||
|
os.remove(oldfile)
|
||||||
|
except:
|
||||||
|
logger.exception("Failed to create backup of server {} (ID {})".format(self.name, self.server_id))
|
||||||
|
|
||||||
|
def list_backups(self):
|
||||||
|
conf = db_helper.get_backup_config(self.server_id)
|
||||||
|
if helper.check_path_exists(self.settings['backup_path']):
|
||||||
|
files = helper.get_human_readable_files_sizes(helper.list_dir_by_date(self.settings['backup_path']))
|
||||||
|
return [{"path": os.path.relpath(f['path'], start=conf['backup_path']), "size": f["size"]} for f in files]
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
@ -8,11 +8,9 @@ import asyncio
|
|||||||
|
|
||||||
from app.classes.shared.helpers import helper
|
from app.classes.shared.helpers import helper
|
||||||
from app.classes.shared.console import console
|
from app.classes.shared.console import console
|
||||||
from app.classes.web.tornado import webserver
|
from app.classes.web.tornado import Webserver
|
||||||
from app.classes.web.websocket_helper import websocket_helper
|
from app.classes.web.websocket_helper import websocket_helper
|
||||||
|
|
||||||
from app.classes.minecraft.stats import stats
|
|
||||||
from app.classes.shared.controller import controller
|
|
||||||
from app.classes.minecraft.serverjars import server_jar_obj
|
from app.classes.minecraft.serverjars import server_jar_obj
|
||||||
from app.classes.shared.models import db_helper
|
from app.classes.shared.models import db_helper
|
||||||
|
|
||||||
@ -26,11 +24,26 @@ except ModuleNotFoundError as e:
|
|||||||
console.critical("Import Error: Unable to load {} module".format(e, e.name))
|
console.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
scheduler_intervals = { 'seconds',
|
||||||
|
'minutes',
|
||||||
|
'hours',
|
||||||
|
'days',
|
||||||
|
'weeks',
|
||||||
|
'monday',
|
||||||
|
'tuesday',
|
||||||
|
'wednesday',
|
||||||
|
'thursday',
|
||||||
|
'friday',
|
||||||
|
'saturday',
|
||||||
|
'sunday'
|
||||||
|
}
|
||||||
|
|
||||||
class TasksManager:
|
class TasksManager:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, controller):
|
||||||
self.tornado = webserver()
|
self.controller = controller
|
||||||
|
self.tornado = Webserver(controller, self)
|
||||||
|
|
||||||
self.webserver_thread = threading.Thread(target=self.tornado.run_tornado, daemon=True, name='tornado_thread')
|
self.webserver_thread = threading.Thread(target=self.tornado.run_tornado, daemon=True, name='tornado_thread')
|
||||||
|
|
||||||
self.main_kill_switch_thread = threading.Thread(target=self.main_kill_switch, daemon=True, name="main_loop")
|
self.main_kill_switch_thread = threading.Thread(target=self.main_kill_switch, daemon=True, name="main_loop")
|
||||||
@ -39,13 +52,13 @@ class TasksManager:
|
|||||||
self.schedule_thread = threading.Thread(target=self.scheduler_thread, daemon=True, name="scheduler")
|
self.schedule_thread = threading.Thread(target=self.scheduler_thread, daemon=True, name="scheduler")
|
||||||
|
|
||||||
self.log_watcher_thread = threading.Thread(target=self.log_watcher, daemon=True, name="log_watcher")
|
self.log_watcher_thread = threading.Thread(target=self.log_watcher, daemon=True, name="log_watcher")
|
||||||
self.log_watcher_thread.start()
|
|
||||||
|
|
||||||
self.command_thread = threading.Thread(target=self.command_watcher, daemon=True, name="command_watcher")
|
self.command_thread = threading.Thread(target=self.command_watcher, daemon=True, name="command_watcher")
|
||||||
self.command_thread.start()
|
|
||||||
|
|
||||||
self.realtime_thread = threading.Thread(target=self.realtime, daemon=True, name="realtime")
|
self.realtime_thread = threading.Thread(target=self.realtime, daemon=True, name="realtime")
|
||||||
self.realtime_thread.start()
|
|
||||||
|
self.reload_schedule_from_db()
|
||||||
|
|
||||||
|
|
||||||
def get_main_thread_run_status(self):
|
def get_main_thread_run_status(self):
|
||||||
return self.main_thread_exiting
|
return self.main_thread_exiting
|
||||||
@ -60,14 +73,29 @@ class TasksManager:
|
|||||||
self._main_graceful_exit()
|
self._main_graceful_exit()
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
@staticmethod
|
def reload_schedule_from_db(self):
|
||||||
def command_watcher():
|
jobs = db_helper.get_schedules_enabled()
|
||||||
|
schedule.clear(tag='backup')
|
||||||
|
schedule.clear(tag='db')
|
||||||
|
for j in jobs:
|
||||||
|
if j.interval_type in scheduler_intervals:
|
||||||
|
logger.info("Loading schedule ID#{i}: '{a}' every {n} {t} at {s}".format(
|
||||||
|
i=j.schedule_id, a=j.action, n=j.interval, t=j.interval_type, s=j.start_time))
|
||||||
|
try:
|
||||||
|
getattr(schedule.every(j.interval), j.interval_type).at(j.start_time).do(
|
||||||
|
db_helper.send_command, 0, j.server_id, "127.27.23.89", j.action)
|
||||||
|
except schedule.ScheduleValueError as e:
|
||||||
|
logger.critical("Scheduler value error occurred: {} on ID#{}".format(e, j.schedule_id))
|
||||||
|
else:
|
||||||
|
logger.critical("Unknown schedule job type '{}' at id {}, skipping".format(j.interval_type, j.schedule_id))
|
||||||
|
|
||||||
|
def command_watcher(self):
|
||||||
while True:
|
while True:
|
||||||
# select any commands waiting to be processed
|
# select any commands waiting to be processed
|
||||||
commands = db_helper.get_unactioned_commands()
|
commands = db_helper.get_unactioned_commands()
|
||||||
for c in commands:
|
for c in commands:
|
||||||
|
|
||||||
svr = controller.get_server_obj(c['server_id']['server_id'])
|
svr = self.controller.get_server_obj(c['server_id']['server_id'])
|
||||||
command = c.get('command', None)
|
command = c.get('command', None)
|
||||||
|
|
||||||
if command == 'start_server':
|
if command == 'start_server':
|
||||||
@ -79,6 +107,9 @@ class TasksManager:
|
|||||||
elif command == "restart_server":
|
elif command == "restart_server":
|
||||||
svr.restart_threaded_server()
|
svr.restart_threaded_server()
|
||||||
|
|
||||||
|
elif command == "backup_server":
|
||||||
|
svr.backup_server()
|
||||||
|
|
||||||
db_helper.mark_command_complete(c.get('command_id', None))
|
db_helper.mark_command_complete(c.get('command_id', None))
|
||||||
|
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
@ -88,7 +119,7 @@ class TasksManager:
|
|||||||
os.remove(helper.session_file)
|
os.remove(helper.session_file)
|
||||||
os.remove(os.path.join(helper.root_dir, 'exit.txt'))
|
os.remove(os.path.join(helper.root_dir, 'exit.txt'))
|
||||||
os.remove(os.path.join(helper.root_dir, '.header'))
|
os.remove(os.path.join(helper.root_dir, '.header'))
|
||||||
controller.stop_all_servers()
|
self.controller.stop_all_servers()
|
||||||
except:
|
except:
|
||||||
logger.info("Caught error during shutdown", exc_info=True)
|
logger.info("Caught error during shutdown", exc_info=True)
|
||||||
|
|
||||||
@ -113,6 +144,15 @@ class TasksManager:
|
|||||||
logger.info("Launching Scheduler Thread...")
|
logger.info("Launching Scheduler Thread...")
|
||||||
console.info("Launching Scheduler Thread...")
|
console.info("Launching Scheduler Thread...")
|
||||||
self.schedule_thread.start()
|
self.schedule_thread.start()
|
||||||
|
logger.info("Launching command thread...")
|
||||||
|
console.info("Launching command thread...")
|
||||||
|
self.command_thread.start()
|
||||||
|
logger.info("Launching log watcher...")
|
||||||
|
console.info("Launching log watcher...")
|
||||||
|
self.log_watcher_thread.start()
|
||||||
|
logger.info("Launching realtime thread...")
|
||||||
|
console.info("Launching realtime thread...")
|
||||||
|
self.realtime_thread.start()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def scheduler_thread():
|
def scheduler_thread():
|
||||||
@ -120,17 +160,16 @@ class TasksManager:
|
|||||||
schedule.run_pending()
|
schedule.run_pending()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
@staticmethod
|
def start_stats_recording(self):
|
||||||
def start_stats_recording():
|
|
||||||
stats_update_frequency = helper.get_setting('stats_update_frequency')
|
stats_update_frequency = helper.get_setting('stats_update_frequency')
|
||||||
logger.info("Stats collection frequency set to {stats} seconds".format(stats=stats_update_frequency))
|
logger.info("Stats collection frequency set to {stats} seconds".format(stats=stats_update_frequency))
|
||||||
console.info("Stats collection frequency set to {stats} seconds".format(stats=stats_update_frequency))
|
console.info("Stats collection frequency set to {stats} seconds".format(stats=stats_update_frequency))
|
||||||
|
|
||||||
# one for now,
|
# one for now,
|
||||||
stats.record_stats()
|
self.controller.stats.record_stats()
|
||||||
|
|
||||||
# one for later
|
# one for later
|
||||||
schedule.every(stats_update_frequency).seconds.do(stats.record_stats)
|
schedule.every(stats_update_frequency).seconds.do(self.controller.stats.record_stats).tag('stats-recording')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def serverjar_cache_refresher():
|
def serverjar_cache_refresher():
|
||||||
@ -138,7 +177,7 @@ class TasksManager:
|
|||||||
server_jar_obj.refresh_cache()
|
server_jar_obj.refresh_cache()
|
||||||
|
|
||||||
logger.info("Scheduling Serverjars.com cache refresh service every 12 hours")
|
logger.info("Scheduling Serverjars.com cache refresh service every 12 hours")
|
||||||
schedule.every(12).hours.do(server_jar_obj.refresh_cache)
|
schedule.every(12).hours.do(server_jar_obj.refresh_cache).tag('serverjars')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def realtime():
|
def realtime():
|
||||||
@ -174,4 +213,5 @@ class TasksManager:
|
|||||||
def log_watcher(self):
|
def log_watcher(self):
|
||||||
console.debug('in log_watcher')
|
console.debug('in log_watcher')
|
||||||
helper.check_for_old_logs(db_helper)
|
helper.check_for_old_logs(db_helper)
|
||||||
schedule.every(6).hours.do(lambda: helper.check_for_old_logs(db_helper))
|
schedule.every(6).hours.do(lambda: helper.check_for_old_logs(db_helper)).tag('log-mgmt')
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ import shutil
|
|||||||
from app.classes.shared.console import console
|
from app.classes.shared.console import console
|
||||||
from app.classes.shared.models import Users, installer
|
from app.classes.shared.models import Users, installer
|
||||||
from app.classes.web.base_handler import BaseHandler
|
from app.classes.web.base_handler import BaseHandler
|
||||||
from app.classes.shared.controller import controller
|
|
||||||
from app.classes.shared.models import db_helper
|
from app.classes.shared.models import db_helper
|
||||||
from app.classes.shared.helpers import helper
|
from app.classes.shared.helpers import helper
|
||||||
|
|
||||||
@ -56,8 +55,8 @@ class AjaxHandler(BaseHandler):
|
|||||||
logger.warning("Server Data not found in server_log ajax call")
|
logger.warning("Server Data not found in server_log ajax call")
|
||||||
self.redirect("/panel/error?error=Server ID Not Found")
|
self.redirect("/panel/error?error=Server ID Not Found")
|
||||||
|
|
||||||
if server_data['log_path']:
|
if not server_data['log_path']:
|
||||||
logger.warning("Server ID not found in server_log ajax call ({})".format(server_id))
|
logger.warning("Log path not found in server_log ajax call ({})".format(server_id))
|
||||||
|
|
||||||
if full_log:
|
if full_log:
|
||||||
log_lines = helper.get_setting('max_log_lines')
|
log_lines = helper.get_setting('max_log_lines')
|
||||||
@ -149,7 +148,7 @@ class AjaxHandler(BaseHandler):
|
|||||||
logger.warning("Server ID not found in send_command ajax call")
|
logger.warning("Server ID not found in send_command ajax call")
|
||||||
console.warning("Server ID not found in send_command ajax call")
|
console.warning("Server ID not found in send_command ajax call")
|
||||||
|
|
||||||
srv_obj = controller.get_server_obj(server_id)
|
srv_obj = self.controller.get_server_obj(server_id)
|
||||||
|
|
||||||
if command:
|
if command:
|
||||||
if srv_obj.check_running():
|
if srv_obj.check_running():
|
||||||
@ -219,7 +218,6 @@ class AjaxHandler(BaseHandler):
|
|||||||
if page == "del_file":
|
if page == "del_file":
|
||||||
file_path = self.get_body_argument('file_path', default=None, strip=True)
|
file_path = self.get_body_argument('file_path', default=None, strip=True)
|
||||||
server_id = self.get_argument('id', None)
|
server_id = self.get_argument('id', None)
|
||||||
print(server_id)
|
|
||||||
|
|
||||||
if server_id is None:
|
if server_id is None:
|
||||||
logger.warning("Server ID not found in del_file ajax call")
|
logger.warning("Server ID not found in del_file ajax call")
|
||||||
@ -234,7 +232,9 @@ class AjaxHandler(BaseHandler):
|
|||||||
console.warning("Server ID not found in del_file ajax call ({})".format(server_id))
|
console.warning("Server ID not found in del_file ajax call ({})".format(server_id))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], file_path) \
|
server_info = db_helper.get_server_data_by_id(server_id)
|
||||||
|
if not helper.in_path(server_info['path'], file_path) \
|
||||||
|
or not helper.in_path(server_info['backup_path'], file_path) \
|
||||||
or not helper.check_file_exists(os.path.abspath(file_path)):
|
or not helper.check_file_exists(os.path.abspath(file_path)):
|
||||||
logger.warning("Invalid path in del_file ajax call ({})".format(file_path))
|
logger.warning("Invalid path in del_file ajax call ({})".format(file_path))
|
||||||
console.warning("Invalid path in del_file ajax call ({})".format(file_path))
|
console.warning("Invalid path in del_file ajax call ({})".format(file_path))
|
||||||
@ -261,7 +261,9 @@ class AjaxHandler(BaseHandler):
|
|||||||
console.warning("Server ID not found in del_file ajax call ({})".format(server_id))
|
console.warning("Server ID not found in del_file ajax call ({})".format(server_id))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], dir_path) \
|
server_info = db_helper.get_server_data_by_id(server_id)
|
||||||
|
if not helper.in_path(server_info['path'], dir_path) \
|
||||||
|
or not helper.in_path(server_info['backup_path'], dir_path) \
|
||||||
or not helper.check_path_exists(os.path.abspath(dir_path)):
|
or not helper.check_path_exists(os.path.abspath(dir_path)):
|
||||||
logger.warning("Invalid path in del_file ajax call ({})".format(dir_path))
|
logger.warning("Invalid path in del_file ajax call ({})".format(dir_path))
|
||||||
console.warning("Invalid path in del_file ajax call ({})".format(dir_path))
|
console.warning("Invalid path in del_file ajax call ({})".format(dir_path))
|
||||||
|
@ -5,13 +5,13 @@ import tornado.web
|
|||||||
import tornado.escape
|
import tornado.escape
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from app.classes.web.base_handler import BaseHandler
|
||||||
from app.classes.shared.models import Users
|
from app.classes.shared.models import Users
|
||||||
from app.classes.minecraft.stats import stats
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class BaseHandler(tornado.web.RequestHandler):
|
class ApiHandler(BaseHandler):
|
||||||
|
|
||||||
def return_response(self, data: dict):
|
def return_response(self, data: dict):
|
||||||
# Define a standardized response
|
# Define a standardized response
|
||||||
@ -25,6 +25,7 @@ class BaseHandler(tornado.web.RequestHandler):
|
|||||||
def authenticate_user(self):
|
def authenticate_user(self):
|
||||||
try:
|
try:
|
||||||
log.debug("Searching for specified token")
|
log.debug("Searching for specified token")
|
||||||
|
# TODO: YEET THIS
|
||||||
user_data = Users.get(api_token=self.get_argument('token'))
|
user_data = Users.get(api_token=self.get_argument('token'))
|
||||||
log.debug("Checking results")
|
log.debug("Checking results")
|
||||||
if user_data:
|
if user_data:
|
||||||
@ -40,19 +41,19 @@ class BaseHandler(tornado.web.RequestHandler):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ServersStats(BaseHandler):
|
class ServersStats(ApiHandler):
|
||||||
def get(self):
|
def get(self):
|
||||||
"""Get details about all servers"""
|
"""Get details about all servers"""
|
||||||
self.authenticate_user()
|
self.authenticate_user()
|
||||||
# Get server stats
|
# Get server stats
|
||||||
self.finish(self.write({"servers": stats.get_servers_stats()}))
|
self.finish(self.write({"servers": self.controller.stats.get_servers_stats()}))
|
||||||
|
|
||||||
|
|
||||||
class NodeStats(BaseHandler):
|
class NodeStats(ApiHandler):
|
||||||
def get(self):
|
def get(self):
|
||||||
"""Get stats for particular node"""
|
"""Get stats for particular node"""
|
||||||
self.authenticate_user()
|
self.authenticate_user()
|
||||||
# Get node stats
|
# Get node stats
|
||||||
node_stats = stats.get_node_stats()
|
node_stats = self.controller.stats.get_node_stats()
|
||||||
node_stats.pop("servers")
|
node_stats.pop("servers")
|
||||||
self.finish(self.write(node_stats))
|
self.finish(self.write(node_stats))
|
||||||
|
@ -1,11 +1,21 @@
|
|||||||
import logging
|
import logging
|
||||||
import tornado.web
|
import tornado.web
|
||||||
|
import bleach
|
||||||
|
from typing import (
|
||||||
|
Union,
|
||||||
|
List,
|
||||||
|
Optional
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class BaseHandler(tornado.web.RequestHandler):
|
class BaseHandler(tornado.web.RequestHandler):
|
||||||
|
|
||||||
|
def initialize(self, controller=None, tasks_manager=None):
|
||||||
|
self.controller = controller
|
||||||
|
self.tasks_manager = tasks_manager
|
||||||
|
|
||||||
def get_remote_ip(self):
|
def get_remote_ip(self):
|
||||||
remote_ip = self.request.headers.get("X-Real-IP") or \
|
remote_ip = self.request.headers.get("X-Real-IP") or \
|
||||||
self.request.headers.get("X-Forwarded-For") or \
|
self.request.headers.get("X-Forwarded-For") or \
|
||||||
@ -14,3 +24,28 @@ class BaseHandler(tornado.web.RequestHandler):
|
|||||||
|
|
||||||
def get_current_user(self):
|
def get_current_user(self):
|
||||||
return self.get_secure_cookie("user", max_age_days=1)
|
return self.get_secure_cookie("user", max_age_days=1)
|
||||||
|
|
||||||
|
def autobleach(self, text):
|
||||||
|
if type(text) is bool:
|
||||||
|
return text
|
||||||
|
else:
|
||||||
|
return text
|
||||||
|
|
||||||
|
def get_argument(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
default: Union[None, str, tornado.web._ArgDefaultMarker] = tornado.web._ARG_DEFAULT,
|
||||||
|
strip: bool = True,
|
||||||
|
) -> Optional[str]:
|
||||||
|
arg = self._get_argument(name, default, self.request.arguments, strip)
|
||||||
|
logger.debug("Bleaching {}: {}".format(name, arg))
|
||||||
|
return bleach.clean(arg)
|
||||||
|
|
||||||
|
def get_arguments(self, name: str, strip: bool = True) -> List[str]:
|
||||||
|
assert isinstance(strip, bool)
|
||||||
|
args = self._get_arguments(name, self.request.arguments, strip)
|
||||||
|
args_ret = []
|
||||||
|
for arg in args:
|
||||||
|
logger.debug("Bleaching {}: {}".format(name, arg))
|
||||||
|
args_ret += bleach.clean(arg)
|
||||||
|
return args_ret
|
||||||
|
@ -5,14 +5,13 @@ import tornado.escape
|
|||||||
import bleach
|
import bleach
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
|
import os
|
||||||
|
|
||||||
from app.classes.shared.console import console
|
from app.classes.shared.console import console
|
||||||
from app.classes.shared.models import Users, installer
|
from app.classes.shared.models import Users, installer
|
||||||
from app.classes.web.base_handler import BaseHandler
|
from app.classes.web.base_handler import BaseHandler
|
||||||
from app.classes.shared.controller import controller
|
|
||||||
from app.classes.shared.models import db_helper, Servers
|
from app.classes.shared.models import db_helper, Servers
|
||||||
from app.classes.shared.helpers import helper
|
from app.classes.shared.helpers import helper
|
||||||
from app.classes.minecraft.stats import stats
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -50,8 +49,8 @@ class PanelHandler(BaseHandler):
|
|||||||
'user_role' : user_role,
|
'user_role' : user_role,
|
||||||
'server_stats': {
|
'server_stats': {
|
||||||
'total': len(defined_servers),
|
'total': len(defined_servers),
|
||||||
'running': len(controller.list_running_servers()),
|
'running': len(self.controller.list_running_servers()),
|
||||||
'stopped': (len(controller.list_defined_servers()) - len(controller.list_running_servers()))
|
'stopped': (len(self.controller.list_defined_servers()) - len(self.controller.list_running_servers()))
|
||||||
},
|
},
|
||||||
'menu_servers': defined_servers,
|
'menu_servers': defined_servers,
|
||||||
'hosts_data': db_helper.get_latest_hosts_stats(),
|
'hosts_data': db_helper.get_latest_hosts_stats(),
|
||||||
@ -64,7 +63,7 @@ class PanelHandler(BaseHandler):
|
|||||||
if page_data['server_stats']['total'] == 0 and page != "error":
|
if page_data['server_stats']['total'] == 0 and page != "error":
|
||||||
self.set_status(301)
|
self.set_status(301)
|
||||||
self.redirect("/server/step1")
|
self.redirect("/server/step1")
|
||||||
return False
|
return
|
||||||
|
|
||||||
if page == 'unauthorized':
|
if page == 'unauthorized':
|
||||||
template = "panel/denied.html"
|
template = "panel/denied.html"
|
||||||
@ -73,6 +72,11 @@ class PanelHandler(BaseHandler):
|
|||||||
template = "public/error.html"
|
template = "public/error.html"
|
||||||
|
|
||||||
elif page == 'credits':
|
elif page == 'credits':
|
||||||
|
with open(helper.credits_cache) as republic_credits_will_do:
|
||||||
|
credits = json.load(republic_credits_will_do)
|
||||||
|
page_data["patreons"] = credits["patreons"]
|
||||||
|
page_data["staff"] = credits["staff"]
|
||||||
|
page_data["translations"] = credits["translations"]
|
||||||
template = "panel/credits.html"
|
template = "panel/credits.html"
|
||||||
|
|
||||||
elif page == 'contribute':
|
elif page == 'contribute':
|
||||||
@ -88,7 +92,7 @@ class PanelHandler(BaseHandler):
|
|||||||
server_id,
|
server_id,
|
||||||
self.get_remote_ip())
|
self.get_remote_ip())
|
||||||
|
|
||||||
controller.remove_server(server_id)
|
self.controller.remove_server(server_id)
|
||||||
self.redirect("/panel/dashboard")
|
self.redirect("/panel/dashboard")
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -114,14 +118,14 @@ class PanelHandler(BaseHandler):
|
|||||||
|
|
||||||
if server_id is None:
|
if server_id is None:
|
||||||
self.redirect("/panel/error?error=Invalid Server ID")
|
self.redirect("/panel/error?error=Invalid Server ID")
|
||||||
return False
|
return
|
||||||
else:
|
else:
|
||||||
server_id = bleach.clean(server_id)
|
server_id = bleach.clean(server_id)
|
||||||
|
|
||||||
# does this server id exist?
|
# does this server id exist?
|
||||||
if not db_helper.server_id_exists(server_id):
|
if not db_helper.server_id_exists(server_id):
|
||||||
self.redirect("/panel/error?error=Invalid Server ID")
|
self.redirect("/panel/error?error=Invalid Server ID")
|
||||||
return False
|
return
|
||||||
|
|
||||||
if user['superuser'] != 1:
|
if user['superuser'] != 1:
|
||||||
#if not db_helper.server_id_authorized(server_id, userId):
|
#if not db_helper.server_id_authorized(server_id, userId):
|
||||||
@ -129,17 +133,21 @@ class PanelHandler(BaseHandler):
|
|||||||
self.redirect("/panel/error?error=Invalid Server ID")
|
self.redirect("/panel/error?error=Invalid Server ID")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
valid_subpages = ['term', 'logs', 'config', 'files', 'admin_controls']
|
valid_subpages = ['term', 'logs', 'backup', 'config', 'files', 'admin_controls']
|
||||||
|
|
||||||
if subpage not in valid_subpages:
|
if subpage not in valid_subpages:
|
||||||
logger.debug('not a valid subpage')
|
logger.debug('not a valid subpage')
|
||||||
subpage = 'term'
|
subpage = 'term'
|
||||||
logger.debug('Subpage: "{}"'.format(subpage))
|
logger.debug('Subpage: "{}"'.format(subpage))
|
||||||
|
|
||||||
|
server = self.controller.get_server_obj(server_id)
|
||||||
# server_data isn't needed since the server_stats also pulls server data
|
# server_data isn't needed since the server_stats also pulls server data
|
||||||
# page_data['server_data'] = db_helper.get_server_data_by_id(server_id)
|
page_data['server_data'] = db_helper.get_server_data_by_id(server_id)
|
||||||
page_data['server_stats'] = db_helper.get_server_stats_by_id(server_id)
|
page_data['server_stats'] = db_helper.get_server_stats_by_id(server_id)
|
||||||
page_data['get_players'] = lambda: stats.get_server_players(server_id)
|
page_data['get_players'] = lambda: self.controller.stats.get_server_players(server_id)
|
||||||
|
if subpage == "backup":
|
||||||
|
page_data['backup_config'] = db_helper.get_backup_config(server_id)
|
||||||
|
page_data['backup_list'] = server.list_backups()
|
||||||
|
|
||||||
def get_banned_players_html():
|
def get_banned_players_html():
|
||||||
banned_players = helper.get_banned_players(server_id, db_helper)
|
banned_players = helper.get_banned_players(server_id, db_helper)
|
||||||
@ -166,6 +174,79 @@ class PanelHandler(BaseHandler):
|
|||||||
# template = "panel/server_details.html"
|
# template = "panel/server_details.html"
|
||||||
template = "panel/server_{subpage}.html".format(subpage=subpage)
|
template = "panel/server_{subpage}.html".format(subpage=subpage)
|
||||||
|
|
||||||
|
elif page == 'download_backup':
|
||||||
|
server_id = self.get_argument('id', None)
|
||||||
|
file = self.get_argument('file', "")
|
||||||
|
|
||||||
|
if server_id is None:
|
||||||
|
self.redirect("/panel/error?error=Invalid Server ID")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
server_id = bleach.clean(server_id)
|
||||||
|
|
||||||
|
# does this server id exist?
|
||||||
|
if not db_helper.server_id_exists(server_id):
|
||||||
|
self.redirect("/panel/error?error=Invalid Server ID")
|
||||||
|
return
|
||||||
|
|
||||||
|
exec_user = db_helper.get_user(user_data['user_id'])
|
||||||
|
|
||||||
|
if not exec_user['superuser']:
|
||||||
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
|
return
|
||||||
|
|
||||||
|
server_info = db_helper.get_server_data_by_id(server_id)
|
||||||
|
backup_file = os.path.abspath(os.path.join(server_info["backup_path"], file))
|
||||||
|
if not helper.in_path(server_info["backup_path"], backup_file) \
|
||||||
|
or not os.path.isfile(backup_file):
|
||||||
|
self.redirect("/panel/error?error=Invalid path detected")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.set_header('Content-Type', 'application/octet-stream')
|
||||||
|
self.set_header('Content-Disposition', 'attachment; filename=' + file)
|
||||||
|
chunk_size = 1024 * 1024 * 4 # 4 MiB
|
||||||
|
|
||||||
|
with open(backup_file, 'rb') as f:
|
||||||
|
while True:
|
||||||
|
chunk = f.read(chunk_size)
|
||||||
|
if not chunk:
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
self.write(chunk) # write the chunk to response
|
||||||
|
self.flush() # send the chunk to client
|
||||||
|
except iostream.StreamClosedError:
|
||||||
|
# this means the client has closed the connection
|
||||||
|
# so break the loop
|
||||||
|
break
|
||||||
|
finally:
|
||||||
|
# deleting the chunk is very important because
|
||||||
|
# if many clients are downloading files at the
|
||||||
|
# same time, the chunks in memory will keep
|
||||||
|
# increasing and will eat up the RAM
|
||||||
|
del chunk
|
||||||
|
self.redirect("/panel/server_detail?id={}&subpage=backup".format(server_id))
|
||||||
|
|
||||||
|
elif page == 'backup_now':
|
||||||
|
server_id = self.get_argument('id', None)
|
||||||
|
|
||||||
|
if server_id is None:
|
||||||
|
self.redirect("/panel/error?error=Invalid Server ID")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# does this server id exist?
|
||||||
|
if not db_helper.server_id_exists(server_id):
|
||||||
|
self.redirect("/panel/error?error=Invalid Server ID")
|
||||||
|
return
|
||||||
|
|
||||||
|
exec_user = db_helper.get_user(user_data['user_id'])
|
||||||
|
|
||||||
|
if not exec_user['superuser']:
|
||||||
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
|
return
|
||||||
|
|
||||||
|
server = self.controller.get_server_obj(server_id).backup_server()
|
||||||
|
self.redirect("/panel/server_detail?id={}&subpage=backup".format(server_id))
|
||||||
|
|
||||||
elif page == 'panel_config':
|
elif page == 'panel_config':
|
||||||
page_data['users'] = db_helper.get_all_users()
|
page_data['users'] = db_helper.get_all_users()
|
||||||
page_data['roles'] = db_helper.get_all_roles()
|
page_data['roles'] = db_helper.get_all_roles()
|
||||||
@ -194,10 +275,10 @@ class PanelHandler(BaseHandler):
|
|||||||
|
|
||||||
if not exec_user['superuser']:
|
if not exec_user['superuser']:
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
return False
|
return
|
||||||
|
|
||||||
page_data['roles_all'] = db_helper.get_all_roles()
|
page_data['roles_all'] = db_helper.get_all_roles()
|
||||||
page_data['servers_all'] = controller.list_defined_servers()
|
page_data['servers_all'] = self.controller.list_defined_servers()
|
||||||
template = "panel/panel_edit_user.html"
|
template = "panel/panel_edit_user.html"
|
||||||
|
|
||||||
elif page == "edit_user":
|
elif page == "edit_user":
|
||||||
@ -205,16 +286,16 @@ class PanelHandler(BaseHandler):
|
|||||||
user_id = self.get_argument('id', None)
|
user_id = self.get_argument('id', None)
|
||||||
page_data['user'] = db_helper.get_user(user_id)
|
page_data['user'] = db_helper.get_user(user_id)
|
||||||
page_data['roles_all'] = db_helper.get_all_roles()
|
page_data['roles_all'] = db_helper.get_all_roles()
|
||||||
page_data['servers_all'] = controller.list_defined_servers()
|
page_data['servers_all'] = self.controller.list_defined_servers()
|
||||||
|
|
||||||
exec_user = db_helper.get_user(user_data['user_id'])
|
exec_user = db_helper.get_user(user_data['user_id'])
|
||||||
|
|
||||||
if not exec_user['superuser']:
|
if not exec_user['superuser']:
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
return False
|
return
|
||||||
elif user_id is None:
|
elif user_id is None:
|
||||||
self.redirect("/panel/error?error=Invalid User ID")
|
self.redirect("/panel/error?error=Invalid User ID")
|
||||||
return False
|
return
|
||||||
|
|
||||||
if exec_user['user_id'] != page_data['user']['user_id']:
|
if exec_user['user_id'] != page_data['user']['user_id']:
|
||||||
page_data['user']['api_token'] = "********"
|
page_data['user']['api_token'] = "********"
|
||||||
@ -228,19 +309,19 @@ class PanelHandler(BaseHandler):
|
|||||||
|
|
||||||
if not exec_user['superuser']:
|
if not exec_user['superuser']:
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
return False
|
return
|
||||||
elif user_id is None:
|
elif user_id is None:
|
||||||
self.redirect("/panel/error?error=Invalid User ID")
|
self.redirect("/panel/error?error=Invalid User ID")
|
||||||
return False
|
return
|
||||||
else:
|
else:
|
||||||
# does this user id exist?
|
# does this user id exist?
|
||||||
target_user = db_helper.get_user(user_id)
|
target_user = db_helper.get_user(user_id)
|
||||||
if not target_user:
|
if not target_user:
|
||||||
self.redirect("/panel/error?error=Invalid User ID")
|
self.redirect("/panel/error?error=Invalid User ID")
|
||||||
return False
|
return
|
||||||
elif target_user['superuser']:
|
elif target_user['superuser']:
|
||||||
self.redirect("/panel/error?error=Cannot remove a superuser")
|
self.redirect("/panel/error?error=Cannot remove a superuser")
|
||||||
return False
|
return
|
||||||
|
|
||||||
db_helper.remove_user(user_id)
|
db_helper.remove_user(user_id)
|
||||||
|
|
||||||
@ -263,25 +344,25 @@ class PanelHandler(BaseHandler):
|
|||||||
|
|
||||||
if not exec_user['superuser']:
|
if not exec_user['superuser']:
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
return False
|
return
|
||||||
|
|
||||||
page_data['servers_all'] = controller.list_defined_servers()
|
page_data['servers_all'] = self.controller.list_defined_servers()
|
||||||
template = "panel/panel_edit_role.html"
|
template = "panel/panel_edit_role.html"
|
||||||
|
|
||||||
elif page == "edit_role":
|
elif page == "edit_role":
|
||||||
page_data['new_role'] = False
|
page_data['new_role'] = False
|
||||||
role_id = self.get_argument('id', None)
|
role_id = self.get_argument('id', None)
|
||||||
page_data['role'] = db_helper.get_role(role_id)
|
page_data['role'] = db_helper.get_role(role_id)
|
||||||
page_data['servers_all'] = controller.list_defined_servers()
|
page_data['servers_all'] = self.controller.list_defined_servers()
|
||||||
|
|
||||||
exec_user = db_helper.get_user(user_data['user_id'])
|
exec_user = db_helper.get_user(user_data['user_id'])
|
||||||
|
|
||||||
if not exec_user['superuser']:
|
if not exec_user['superuser']:
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
return False
|
return
|
||||||
elif role_id is None:
|
elif role_id is None:
|
||||||
self.redirect("/panel/error?error=Invalid Role ID")
|
self.redirect("/panel/error?error=Invalid Role ID")
|
||||||
return False
|
return
|
||||||
|
|
||||||
template = "panel/panel_edit_role.html"
|
template = "panel/panel_edit_role.html"
|
||||||
|
|
||||||
@ -293,16 +374,16 @@ class PanelHandler(BaseHandler):
|
|||||||
|
|
||||||
if not exec_user['superuser']:
|
if not exec_user['superuser']:
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
return False
|
return
|
||||||
elif role_id is None:
|
elif role_id is None:
|
||||||
self.redirect("/panel/error?error=Invalid Role ID")
|
self.redirect("/panel/error?error=Invalid Role ID")
|
||||||
return False
|
return
|
||||||
else:
|
else:
|
||||||
# does this user id exist?
|
# does this user id exist?
|
||||||
target_role = db_helper.get_user(role_id)
|
target_role = db_helper.get_user(role_id)
|
||||||
if not target_role:
|
if not target_role:
|
||||||
self.redirect("/panel/error?error=Invalid Role ID")
|
self.redirect("/panel/error?error=Invalid Role ID")
|
||||||
return False
|
return
|
||||||
|
|
||||||
db_helper.remove_role(role_id)
|
db_helper.remove_role(role_id)
|
||||||
|
|
||||||
@ -348,17 +429,15 @@ class PanelHandler(BaseHandler):
|
|||||||
|
|
||||||
if not exec_user['superuser']:
|
if not exec_user['superuser']:
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
return False
|
return
|
||||||
elif server_id is None:
|
elif server_id is None:
|
||||||
self.redirect("/panel/error?error=Invalid Server ID")
|
self.redirect("/panel/error?error=Invalid Server ID")
|
||||||
return False
|
return
|
||||||
else:
|
else:
|
||||||
server_id = bleach.clean(server_id)
|
|
||||||
|
|
||||||
# does this server id exist?
|
# does this server id exist?
|
||||||
if not db_helper.server_id_exists(server_id):
|
if not db_helper.server_id_exists(server_id):
|
||||||
self.redirect("/panel/error?error=Invalid Server ID")
|
self.redirect("/panel/error?error=Invalid Server ID")
|
||||||
return False
|
return
|
||||||
|
|
||||||
Servers.update({
|
Servers.update({
|
||||||
Servers.server_name: server_name,
|
Servers.server_name: server_name,
|
||||||
@ -375,7 +454,7 @@ class PanelHandler(BaseHandler):
|
|||||||
Servers.logs_delete_after: logs_delete_after,
|
Servers.logs_delete_after: logs_delete_after,
|
||||||
}).where(Servers.server_id == server_id).execute()
|
}).where(Servers.server_id == server_id).execute()
|
||||||
|
|
||||||
controller.refresh_server_settings(server_id)
|
self.controller.refresh_server_settings(server_id)
|
||||||
|
|
||||||
db_helper.add_to_audit_log(user_data['user_id'],
|
db_helper.add_to_audit_log(user_data['user_id'],
|
||||||
"Edited server {} named {}".format(server_id, server_name),
|
"Edited server {} named {}".format(server_id, server_name),
|
||||||
@ -384,6 +463,41 @@ class PanelHandler(BaseHandler):
|
|||||||
|
|
||||||
self.redirect("/panel/server_detail?id={}&subpage=config".format(server_id))
|
self.redirect("/panel/server_detail?id={}&subpage=config".format(server_id))
|
||||||
|
|
||||||
|
if page == "server_backup":
|
||||||
|
logger.debug(self.request.arguments)
|
||||||
|
server_id = self.get_argument('id', None)
|
||||||
|
backup_path = bleach.clean(self.get_argument('backup_path', None))
|
||||||
|
max_backups = bleach.clean(self.get_argument('max_backups', None))
|
||||||
|
enabled = int(float(bleach.clean(self.get_argument('auto_enabled'), '0')))
|
||||||
|
|
||||||
|
user_data = json.loads(self.get_secure_cookie("user_data"))
|
||||||
|
exec_user = db_helper.get_user(user_data['user_id'])
|
||||||
|
|
||||||
|
if not exec_user['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
|
||||||
|
else:
|
||||||
|
# does this server id exist?
|
||||||
|
if not db_helper.server_id_exists(server_id):
|
||||||
|
self.redirect("/panel/error?error=Invalid Server ID")
|
||||||
|
return
|
||||||
|
|
||||||
|
if backup_path is not None:
|
||||||
|
Servers.update({
|
||||||
|
Servers.backup_path: backup_path
|
||||||
|
}).where(Servers.server_id == server_id).execute()
|
||||||
|
db_helper.set_backup_config(server_id, max_backups=max_backups)
|
||||||
|
|
||||||
|
db_helper.add_to_audit_log(user_data['user_id'],
|
||||||
|
"Edited server {}: updated backups".format(server_id),
|
||||||
|
server_id,
|
||||||
|
self.get_remote_ip())
|
||||||
|
self.tasks_manager.reload_schedule_from_db()
|
||||||
|
self.redirect("/panel/server_detail?id={}&subpage=backup".format(server_id))
|
||||||
|
|
||||||
elif page == "edit_user":
|
elif page == "edit_user":
|
||||||
user_id = bleach.clean(self.get_argument('id', None))
|
user_id = bleach.clean(self.get_argument('id', None))
|
||||||
username = bleach.clean(self.get_argument('username', None))
|
username = bleach.clean(self.get_argument('username', None))
|
||||||
@ -397,22 +511,22 @@ class PanelHandler(BaseHandler):
|
|||||||
|
|
||||||
if not exec_user['superuser']:
|
if not exec_user['superuser']:
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
return False
|
return
|
||||||
elif username is None or username == "":
|
elif username is None or username == "":
|
||||||
self.redirect("/panel/error?error=Invalid username")
|
self.redirect("/panel/error?error=Invalid username")
|
||||||
return False
|
return
|
||||||
elif user_id is None:
|
elif user_id is None:
|
||||||
self.redirect("/panel/error?error=Invalid User ID")
|
self.redirect("/panel/error?error=Invalid User ID")
|
||||||
return False
|
return
|
||||||
else:
|
else:
|
||||||
# does this user id exist?
|
# does this user id exist?
|
||||||
if not db_helper.user_id_exists(user_id):
|
if not db_helper.user_id_exists(user_id):
|
||||||
self.redirect("/panel/error?error=Invalid User ID")
|
self.redirect("/panel/error?error=Invalid User ID")
|
||||||
return False
|
return
|
||||||
|
|
||||||
if password0 != password1:
|
if password0 != password1:
|
||||||
self.redirect("/panel/error?error=Passwords must match")
|
self.redirect("/panel/error?error=Passwords must match")
|
||||||
return False
|
return
|
||||||
|
|
||||||
roles = set()
|
roles = set()
|
||||||
for role in db_helper.get_all_roles():
|
for role in db_helper.get_all_roles():
|
||||||
@ -425,7 +539,7 @@ class PanelHandler(BaseHandler):
|
|||||||
roles.add(role.role_id)
|
roles.add(role.role_id)
|
||||||
|
|
||||||
servers = set()
|
servers = set()
|
||||||
for server in controller.list_defined_servers():
|
for server in self.controller.list_defined_servers():
|
||||||
argument = int(float(
|
argument = int(float(
|
||||||
bleach.clean(
|
bleach.clean(
|
||||||
self.get_argument('server_{}_access'.format(server['server_id']), '0')
|
self.get_argument('server_{}_access'.format(server['server_id']), '0')
|
||||||
@ -461,19 +575,19 @@ class PanelHandler(BaseHandler):
|
|||||||
exec_user = db_helper.get_user(user_data['user_id'])
|
exec_user = db_helper.get_user(user_data['user_id'])
|
||||||
if not exec_user['superuser']:
|
if not exec_user['superuser']:
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
return False
|
return
|
||||||
elif username is None or username == "":
|
elif username is None or username == "":
|
||||||
self.redirect("/panel/error?error=Invalid username")
|
self.redirect("/panel/error?error=Invalid username")
|
||||||
return False
|
return
|
||||||
else:
|
else:
|
||||||
# does this user id exist?
|
# does this user id exist?
|
||||||
if db_helper.get_userid_by_name(username) is not None:
|
if db_helper.get_userid_by_name(username) is not None:
|
||||||
self.redirect("/panel/error?error=User exists")
|
self.redirect("/panel/error?error=User exists")
|
||||||
return False
|
return
|
||||||
|
|
||||||
if password0 != password1:
|
if password0 != password1:
|
||||||
self.redirect("/panel/error?error=Passwords must match")
|
self.redirect("/panel/error?error=Passwords must match")
|
||||||
return False
|
return
|
||||||
|
|
||||||
roles = set()
|
roles = set()
|
||||||
for role in db_helper.get_all_roles():
|
for role in db_helper.get_all_roles():
|
||||||
@ -486,7 +600,7 @@ class PanelHandler(BaseHandler):
|
|||||||
roles.add(role['role_id'])
|
roles.add(role['role_id'])
|
||||||
|
|
||||||
servers = set()
|
servers = set()
|
||||||
for server in controller.list_defined_servers():
|
for server in self.controller.list_defined_servers():
|
||||||
argument = int(float(
|
argument = int(float(
|
||||||
bleach.clean(
|
bleach.clean(
|
||||||
self.get_argument('server_{}_access'.format(server['server_id']), '0')
|
self.get_argument('server_{}_access'.format(server['server_id']), '0')
|
||||||
@ -517,21 +631,21 @@ class PanelHandler(BaseHandler):
|
|||||||
|
|
||||||
if not exec_user['superuser']:
|
if not exec_user['superuser']:
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
return False
|
return
|
||||||
elif role_name is None or role_name == "":
|
elif role_name is None or role_name == "":
|
||||||
self.redirect("/panel/error?error=Invalid username")
|
self.redirect("/panel/error?error=Invalid username")
|
||||||
return False
|
return
|
||||||
elif role_id is None:
|
elif role_id is None:
|
||||||
self.redirect("/panel/error?error=Invalid Role ID")
|
self.redirect("/panel/error?error=Invalid Role ID")
|
||||||
return False
|
return
|
||||||
else:
|
else:
|
||||||
# does this user id exist?
|
# does this user id exist?
|
||||||
if not db_helper.role_id_exists(role_id):
|
if not db_helper.role_id_exists(role_id):
|
||||||
self.redirect("/panel/error?error=Invalid Role ID")
|
self.redirect("/panel/error?error=Invalid Role ID")
|
||||||
return False
|
return
|
||||||
|
|
||||||
servers = set()
|
servers = set()
|
||||||
for server in controller.list_defined_servers():
|
for server in self.controller.list_defined_servers():
|
||||||
argument = int(float(
|
argument = int(float(
|
||||||
bleach.clean(
|
bleach.clean(
|
||||||
self.get_argument('server_{}_access'.format(server['server_id']), '0')
|
self.get_argument('server_{}_access'.format(server['server_id']), '0')
|
||||||
@ -560,18 +674,18 @@ class PanelHandler(BaseHandler):
|
|||||||
exec_user = db_helper.get_user(user_data['user_id'])
|
exec_user = db_helper.get_user(user_data['user_id'])
|
||||||
if not exec_user['superuser']:
|
if not exec_user['superuser']:
|
||||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||||
return False
|
return
|
||||||
elif role_name is None or role_name == "":
|
elif role_name is None or role_name == "":
|
||||||
self.redirect("/panel/error?error=Invalid role name")
|
self.redirect("/panel/error?error=Invalid role name")
|
||||||
return False
|
return
|
||||||
else:
|
else:
|
||||||
# does this user id exist?
|
# does this user id exist?
|
||||||
if db_helper.get_roleid_by_name(role_name) is not None:
|
if db_helper.get_roleid_by_name(role_name) is not None:
|
||||||
self.redirect("/panel/error?error=Role exists")
|
self.redirect("/panel/error?error=Role exists")
|
||||||
return False
|
return
|
||||||
|
|
||||||
servers = set()
|
servers = set()
|
||||||
for server in controller.list_defined_servers():
|
for server in self.controller.list_defined_servers():
|
||||||
argument = int(float(
|
argument = int(float(
|
||||||
bleach.clean(
|
bleach.clean(
|
||||||
self.get_argument('server_{}_access'.format(server['server_id']), '0')
|
self.get_argument('server_{}_access'.format(server['server_id']), '0')
|
||||||
@ -592,3 +706,7 @@ class PanelHandler(BaseHandler):
|
|||||||
server_id=0,
|
server_id=0,
|
||||||
source_ip=self.get_remote_ip())
|
source_ip=self.get_remote_ip())
|
||||||
self.redirect("/panel/panel_config")
|
self.redirect("/panel/panel_config")
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.set_status(404)
|
||||||
|
self.render("public/404.html")
|
||||||
|
@ -6,10 +6,8 @@ import shutil
|
|||||||
|
|
||||||
from app.classes.shared.console import console
|
from app.classes.shared.console import console
|
||||||
from app.classes.web.base_handler import BaseHandler
|
from app.classes.web.base_handler import BaseHandler
|
||||||
from app.classes.shared.controller import controller
|
|
||||||
from app.classes.shared.models import db_helper, Servers
|
from app.classes.shared.models import db_helper, Servers
|
||||||
from app.classes.minecraft.serverjars import server_jar_obj
|
from app.classes.minecraft.serverjars import server_jar_obj
|
||||||
from app.classes.minecraft.stats import stats
|
|
||||||
from app.classes.shared.helpers import helper
|
from app.classes.shared.helpers import helper
|
||||||
|
|
||||||
|
|
||||||
@ -48,16 +46,16 @@ class ServerHandler(BaseHandler):
|
|||||||
|
|
||||||
template = "public/404.html"
|
template = "public/404.html"
|
||||||
|
|
||||||
defined_servers = controller.list_defined_servers()
|
defined_servers = self.controller.list_defined_servers()
|
||||||
|
|
||||||
page_data = {
|
page_data = {
|
||||||
'version_data': helper.get_version_string(),
|
'version_data': helper.get_version_string(),
|
||||||
'user_data': user_data,
|
'user_data': user_data,
|
||||||
'user_role' : user_role,
|
'user_role' : user_role,
|
||||||
'server_stats': {
|
'server_stats': {
|
||||||
'total': len(controller.list_defined_servers()),
|
'total': len(self.controller.list_defined_servers()),
|
||||||
'running': len(controller.list_running_servers()),
|
'running': len(self.controller.list_running_servers()),
|
||||||
'stopped': (len(controller.list_defined_servers()) - len(controller.list_running_servers()))
|
'stopped': (len(self.controller.list_defined_servers()) - len(self.controller.list_running_servers()))
|
||||||
},
|
},
|
||||||
'hosts_data': db_helper.get_latest_hosts_stats(),
|
'hosts_data': db_helper.get_latest_hosts_stats(),
|
||||||
'menu_servers': defined_servers,
|
'menu_servers': defined_servers,
|
||||||
@ -144,7 +142,7 @@ class ServerHandler(BaseHandler):
|
|||||||
Servers.stop_command: stop_command
|
Servers.stop_command: stop_command
|
||||||
}).execute()
|
}).execute()
|
||||||
|
|
||||||
controller.init_all_servers()
|
self.controller.init_all_servers()
|
||||||
console.debug('initted all servers')
|
console.debug('initted all servers')
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -164,26 +162,26 @@ class ServerHandler(BaseHandler):
|
|||||||
server_parts = server.split("|")
|
server_parts = server.split("|")
|
||||||
|
|
||||||
if import_type == 'import_jar':
|
if import_type == 'import_jar':
|
||||||
good_path = controller.verify_jar_server(import_server_path, import_server_jar)
|
good_path = self.controller.verify_jar_server(import_server_path, import_server_jar)
|
||||||
|
|
||||||
if not good_path:
|
if not good_path:
|
||||||
self.redirect("/panel/error?error=Server path or Server Jar not found!")
|
self.redirect("/panel/error?error=Server path or Server Jar not found!")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
new_server_id = controller.import_jar_server(server_name, import_server_path,import_server_jar, min_mem, max_mem, port)
|
new_server_id = self.controller.import_jar_server(server_name, import_server_path,import_server_jar, min_mem, max_mem, port)
|
||||||
elif import_type == 'import_zip':
|
elif import_type == 'import_zip':
|
||||||
good_path = controller.verify_zip_server(import_server_path)
|
good_path = self.controller.verify_zip_server(import_server_path)
|
||||||
if not good_path:
|
if not good_path:
|
||||||
self.redirect("/panel/error?error=Zip file not found!")
|
self.redirect("/panel/error?error=Zip file not found!")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
new_server_id = controller.import_zip_server(server_name, import_server_path,import_server_jar, min_mem, max_mem, port)
|
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":
|
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
|
return False
|
||||||
else:
|
else:
|
||||||
# todo: add server type check here and call the correct server add functions if not a jar
|
# todo: add server type check here and call the correct server add functions if not a jar
|
||||||
new_server_id = controller.create_jar_server(server_parts[0], server_parts[1], server_name, min_mem, max_mem, port)
|
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:
|
if new_server_id:
|
||||||
db_helper.add_to_audit_log(user_data['user_id'],
|
db_helper.add_to_audit_log(user_data['user_id'],
|
||||||
@ -194,7 +192,7 @@ class ServerHandler(BaseHandler):
|
|||||||
logger.error("Unable to create server")
|
logger.error("Unable to create server")
|
||||||
console.error("Unable to create server")
|
console.error("Unable to create server")
|
||||||
|
|
||||||
stats.record_stats()
|
self.controller.stats.record_stats()
|
||||||
self.redirect("/panel/dashboard")
|
self.redirect("/panel/dashboard")
|
||||||
|
|
||||||
self.render(
|
self.render(
|
||||||
|
@ -33,12 +33,14 @@ except ModuleNotFoundError as e:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class webserver:
|
class Webserver:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, controller, tasks_manager):
|
||||||
self.ioloop = None
|
self.ioloop = None
|
||||||
self.HTTP_Server = None
|
self.HTTP_Server = None
|
||||||
self.HTTPS_Server = None
|
self.HTTPS_Server = None
|
||||||
|
self.controller = controller
|
||||||
|
self.tasks_manager = tasks_manager
|
||||||
self._asyncio_patch()
|
self._asyncio_patch()
|
||||||
|
|
||||||
|
|
||||||
@ -118,15 +120,16 @@ class webserver:
|
|||||||
|
|
||||||
tornado.locale.set_default_locale(lang)
|
tornado.locale.set_default_locale(lang)
|
||||||
|
|
||||||
|
handler_args = {"controller": self.controller, "tasks_manager": self.tasks_manager}
|
||||||
handlers = [
|
handlers = [
|
||||||
(r'/', DefaultHandler),
|
(r'/', DefaultHandler, handler_args),
|
||||||
(r'/public/(.*)', PublicHandler),
|
(r'/public/(.*)', PublicHandler, handler_args),
|
||||||
(r'/panel/(.*)', PanelHandler),
|
(r'/panel/(.*)', PanelHandler, handler_args),
|
||||||
(r'/server/(.*)', ServerHandler),
|
(r'/server/(.*)', ServerHandler, handler_args),
|
||||||
(r'/ajax/(.*)', AjaxHandler),
|
(r'/ajax/(.*)', AjaxHandler, handler_args),
|
||||||
(r'/api/stats/servers', ServersStats),
|
(r'/api/stats/servers', ServersStats, handler_args),
|
||||||
(r'/api/stats/node', NodeStats),
|
(r'/api/stats/node', NodeStats, handler_args),
|
||||||
(r'/ws', SocketHandler),
|
(r'/ws', SocketHandler, handler_args),
|
||||||
]
|
]
|
||||||
|
|
||||||
app = tornado.web.Application(
|
app = tornado.web.Application(
|
||||||
|
@ -8,6 +8,10 @@ from app.classes.web.websocket_helper import websocket_helper
|
|||||||
|
|
||||||
class SocketHandler(tornado.websocket.WebSocketHandler):
|
class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||||
|
|
||||||
|
def initialize(self, controller=None, tasks_manager=None):
|
||||||
|
self.controller = controller
|
||||||
|
self.tasks_manager = tasks_manager
|
||||||
|
|
||||||
def get_remote_ip(self):
|
def get_remote_ip(self):
|
||||||
remote_ip = self.request.headers.get("X-Real-IP") or \
|
remote_ip = self.request.headers.get("X-Real-IP") or \
|
||||||
self.request.headers.get("X-Forwarded-For") or \
|
self.request.headers.get("X-Forwarded-For") or \
|
||||||
|
137
app/config/credits.json
Normal file
137
app/config/credits.json
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
{
|
||||||
|
"patreons": [
|
||||||
|
{
|
||||||
|
"name": "Richard B",
|
||||||
|
"level": "substainer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "John C",
|
||||||
|
"level": "advocate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nicolas T",
|
||||||
|
"level": "substainer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lightkeeper",
|
||||||
|
"level": "substainer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test user 1",
|
||||||
|
"level": "supporter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test user 2",
|
||||||
|
"level": "other"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"staff": {
|
||||||
|
"development": [
|
||||||
|
{
|
||||||
|
"name": "Phil Tarrant",
|
||||||
|
"title": "Benevolent Dictator for Life",
|
||||||
|
"loc": "Atlanta, GA",
|
||||||
|
"tags": [ "Staff", "Developer", [ "BDFL", "https://en.wikipedia.org/wiki/Benevolent_dictator_for_life" ] ],
|
||||||
|
"blurb": "For best results, apply a thin layer of Phillip to code, cyber security, parenthood for maximum effectiveness. Phillip often spends too much time with his chickens.",
|
||||||
|
"pic": "/static/assets/images/credits/ptarrant_cropped.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pita Bread",
|
||||||
|
"title": null,
|
||||||
|
"loc": "Midwest, USA",
|
||||||
|
"tags": [ "Staff", null, "Community Leader" ],
|
||||||
|
"blurb": "His interests include bread, Linux, and networking. He enjoys pumpkins, organizing, and long-winded emails, but hates wifi.",
|
||||||
|
"pic": "/static/assets/images/credits/pita_cropped.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "macgeek",
|
||||||
|
"title": null,
|
||||||
|
"loc": "Midwest, USA",
|
||||||
|
"tags": [ "Staff", "Developer", "Project Manager" ],
|
||||||
|
"blurb": "Sysadmin for work and sysadmin for fun (avid homelabber). He enjoys a good tech tangent and gaming.",
|
||||||
|
"pic": "/static/assets/images/credits/macgeek_cropped.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "parzivaldewey",
|
||||||
|
"title": null,
|
||||||
|
"loc": "East Coast, USA",
|
||||||
|
"tags": [ "Staff", "Developer", "Support Manager" ],
|
||||||
|
"blurb": "His interests include Linux, gaming, and helping others. When he's able to unplug he enjoys biking, hiking, and playing soccer.",
|
||||||
|
"pic": "/static/assets/images/credits/andrew_cropped.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "MC Gaming",
|
||||||
|
"title": null,
|
||||||
|
"loc": "Central, UK",
|
||||||
|
"tags": [ "Staff", "Developer", null ],
|
||||||
|
"blurb": "His interests include learning, Linux, programming. He loves pentesting apps and gaming.",
|
||||||
|
"pic": "/static/assets/images/credits/mcgaming.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Silversthorn",
|
||||||
|
"title": null,
|
||||||
|
"loc": null,
|
||||||
|
"tags": [ "Staff", "Developer", null ],
|
||||||
|
"blurb": "Often in it's cave, he sometimes goes out to help or do silly jokes. He's an IT clown (not the film), but seriously do the job when it's needed.",
|
||||||
|
"pic": "/static/assets/images/credits/silversthorn.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ThatOneLukas",
|
||||||
|
"title": null,
|
||||||
|
"loc": "Helsinki, FI",
|
||||||
|
"tags": [ "Staff", "Developer", null ],
|
||||||
|
"blurb": "Lukas enjoys bashing his head at the table while his code does not work",
|
||||||
|
"pic": "/static/assets/images/credits/lukas_cropped.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"support": [
|
||||||
|
{
|
||||||
|
"name": "iSilverfyre",
|
||||||
|
"title": null,
|
||||||
|
"loc": null,
|
||||||
|
"tags": [ "Staff", "Wiki", null ],
|
||||||
|
"blurb": "Silver enjoys helping others with their computer needs, writing documentation and loving her cat.",
|
||||||
|
"pic": "/static/assets/images/credits/isilverfyre.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Quentin",
|
||||||
|
"title": null,
|
||||||
|
"loc": null,
|
||||||
|
"tags": [ "Staff", "Developer", null ],
|
||||||
|
"blurb": "Hosts Minecraft servers for his weird friends, works for an IoT company as his dayjob. The 's' in IoT stands for 'secure'.",
|
||||||
|
"pic": "/static/assets/images/credits/qub3d.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"retired": [
|
||||||
|
{
|
||||||
|
"name": "Kev Dagoat",
|
||||||
|
"title": "Head of Development",
|
||||||
|
"loc": "East Coast, AU",
|
||||||
|
"tags": [ "Staff", "Developer", "HOD" ],
|
||||||
|
"blurb": "His interests include Linux, programming, and goats of course. He enjoys building APIs, K8s, and Geeking over video cards.",
|
||||||
|
"pic": "/static/assets/images/credits/kevdagoat.jpeg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Manu",
|
||||||
|
"title": null,
|
||||||
|
"loc": "Eastern, CA",
|
||||||
|
"tags": [ "Staff", "Developer", "Project Manager" ],
|
||||||
|
"blurb": "His interests include learning, Linux, and programming. He enjoys speaking French, doing 6 things at once, and testing software.",
|
||||||
|
"pic": "/static/assets/images/credits/manu_cropped.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "UltraBlack",
|
||||||
|
"title": null,
|
||||||
|
"loc": "Bavaria, DE",
|
||||||
|
"tags": [ "Staff", null, "Idea Manager" ],
|
||||||
|
"blurb": "Hi, my name is Tim, and I'm a huge fan of linux. I'm often gaming and occasionally coding.",
|
||||||
|
"pic": "/static/assets/images/credits/ultrablack_cropped.png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"translations": {
|
||||||
|
"UltraBlack": [ "German" ],
|
||||||
|
"Manu": [ "French" ],
|
||||||
|
"ptarrant": [ "Sarcasm", "Wit" ]
|
||||||
|
}
|
||||||
|
}
|
BIN
app/frontend/static/assets/images/credits/isilverfyre.png
Normal file
BIN
app/frontend/static/assets/images/credits/isilverfyre.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
app/frontend/static/assets/images/credits/qub3d.png
Normal file
BIN
app/frontend/static/assets/images/credits/qub3d.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
BIN
app/frontend/static/assets/images/credits/silversthorn.png
Normal file
BIN
app/frontend/static/assets/images/credits/silversthorn.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
@ -27,9 +27,76 @@
|
|||||||
<div class="col-md-12 grid-margin">
|
<div class="col-md-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||||
|
<h4 class="card-title"><i class="far fa-code"></i> Development Team</h4>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
{% for person in data['staff']['development'] %}
|
||||||
|
<div class="col-md-6 mb-5">
|
||||||
|
<div class="card rounded shadow-none">
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
|
||||||
|
<div class="user-avatar mb-auto">
|
||||||
|
<img src="{{ person['pic'] }}"
|
||||||
|
alt="profile image" class="profile-img img-lg rounded-circle">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="wrapper d-flex align-items-center">
|
||||||
|
<h4 class="mb-0 font-weight-medium">{{ person['name'] }}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper d-flex align-items-center font-weight-medium text-muted">
|
||||||
|
{% if person['loc'] %}
|
||||||
|
<i class="mdi mdi-map-marker-outline mr-2"></i>
|
||||||
|
<p class="mb-0 text-muted">{{ person['loc'] }}</p>
|
||||||
|
{% end %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="wrapper d-flex align-items-start">
|
||||||
|
{% if person['tags'][0] %}
|
||||||
|
<span class="btn btn-sm btn-info mr-2">{{ person['tags'][0] }}</span>
|
||||||
|
{% end %}
|
||||||
|
{% if person['tags'][1] %}
|
||||||
|
<span class="btn btn-sm btn-primary mr-2">{{ person['tags'][1] }}</span>
|
||||||
|
{% end %}
|
||||||
|
{% if person['tags'][2] %}
|
||||||
|
{% if type(person['tags'][2]) is list %}
|
||||||
|
<a href="{{ person['tags'][2][1] }}" class="btn btn-sm btn-inverse-success mr-2">{{ person['tags'][2][0] }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="btn btn-sm btn-inverse-success mr-2">{{ person['tags'][2] }}</span>
|
||||||
|
{% end %}
|
||||||
|
{% end %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper d-flex align-items-start pt-3">
|
||||||
|
{% if person['title'] %}
|
||||||
|
Crafty's {{ person['title'] }}<br /><br />
|
||||||
|
{% end %}
|
||||||
|
{{ person['blurb'] }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
</div> <!-- end of user row -->
|
||||||
|
|
||||||
|
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||||
|
<h4 class="card-title"><i class="fa fa-book"></i> Support and Documentation Team</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
{% for person in data['staff']['support'] %}
|
||||||
<div class="col-md-6 mb-5">
|
<div class="col-md-6 mb-5">
|
||||||
<div class="card rounded shadow-none">
|
<div class="card rounded shadow-none">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -38,74 +105,46 @@
|
|||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
|
|
||||||
<div class="user-avatar mb-auto">
|
<div class="user-avatar mb-auto">
|
||||||
<img src="/static/assets/images/credits/ptarrant_cropped.png"
|
<img src="{{ person['pic'] }}"
|
||||||
alt="profile image" class="profile-img img-lg rounded-circle">
|
alt="profile image" class="profile-img img-lg rounded-circle">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="wrapper d-flex align-items-center">
|
<div class="wrapper d-flex align-items-center">
|
||||||
<h4 class="mb-0 font-weight-medium">Phillip Tarrant</h4>
|
<h4 class="mb-0 font-weight-medium">{{ person['name'] }}</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-center font-weight-medium text-muted">
|
<div class="wrapper d-flex align-items-center font-weight-medium text-muted">
|
||||||
|
{% if person['loc'] %}
|
||||||
<i class="mdi mdi-map-marker-outline mr-2"></i>
|
<i class="mdi mdi-map-marker-outline mr-2"></i>
|
||||||
<p class="mb-0 text-muted">Atlanta, GA</p>
|
<p class="mb-0 text-muted">{{ person['loc'] }}</p>
|
||||||
|
{% end %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="wrapper d-flex align-items-start">
|
<div class="wrapper d-flex align-items-start">
|
||||||
<span class="btn btn-sm btn-info mr-2">Staff</span>
|
{% if person['tags'][0] %}
|
||||||
<span class="btn btn-sm btn-primary mr-2">Developer</span>
|
<span class="btn btn-sm btn-info mr-2">{{ person['tags'][0] }}</span>
|
||||||
<a href="https://en.wikipedia.org/wiki/Benevolent_dictator_for_life" class="btn btn-sm btn-inverse-success mr-2">BDFL</a>
|
{% end %}
|
||||||
|
{% if person['tags'][1] %}
|
||||||
|
<span class="btn btn-sm btn-primary mr-2">{{ person['tags'][1] }}</span>
|
||||||
|
{% end %}
|
||||||
|
{% if person['tags'][2] %}
|
||||||
|
{% if type(person['tags'][2]) is list %}
|
||||||
|
<a href="{{ person['tags'][2][1] }}" class="btn btn-sm btn-inverse-success mr-2">{{ person['tags'][2][0] }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="btn btn-sm btn-inverse-success mr-2">{{ person['tags'][2] }}</span>
|
||||||
|
{% end %}
|
||||||
|
{% end %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-start pt-3">
|
<div class="wrapper d-flex align-items-start pt-3">
|
||||||
Crafty's Benevolent Dictator for Life.<br /><br />
|
{% if person['title'] %}
|
||||||
His interests include Linux, cybersecurity, hacking, and gaming.
|
Crafty's {{ person['title'] }}<br /><br />
|
||||||
He enjoys downtime with the family, and playing with his chickens.
|
{% end %}
|
||||||
</div>
|
{{ person['blurb'] }}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-6 mb-5">
|
|
||||||
<div class="card rounded shadow-none">
|
|
||||||
<div class="card-body">
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
|
|
||||||
<div class="user-avatar mb-auto">
|
|
||||||
<img src="/static/assets/images/credits/pita_cropped.png"
|
|
||||||
alt="profile image" class="profile-img img-lg rounded-circle">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper">
|
|
||||||
<div class="wrapper d-flex align-items-center">
|
|
||||||
<h4 class="mb-0 font-weight-medium">Pita Bread</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-center font-weight-medium text-muted">
|
|
||||||
<i class="mdi mdi-map-marker-outline mr-2"></i>
|
|
||||||
<p class="mb-0 text-muted">Midwest, USA</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-8">
|
|
||||||
<div class="wrapper d-flex align-items-start">
|
|
||||||
<span class="btn btn-sm btn-info mr-2">Staff</span>
|
|
||||||
<span class="btn btn-sm btn-inverse-success mr-2">Community Leader</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-start pt-3">
|
|
||||||
His interests include bread, Linux, and networking.
|
|
||||||
He enjoys pumpkins, organizing, and long-winded emails, but hates wifi.
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -113,99 +152,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% end %}
|
||||||
|
|
||||||
</div> <!-- end user row-->
|
</div> <!-- end user row-->
|
||||||
|
|
||||||
<div class="row">
|
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||||
|
<h4 class="card-title"><i class="far fa-server"></i> Retired Staff</h4>
|
||||||
<div class="col-md-6 mb-5">
|
</div>
|
||||||
<div class="card rounded shadow-none">
|
|
||||||
<div class="card-body">
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
|
|
||||||
<div class="user-avatar mb-auto">
|
|
||||||
<img src="/static/assets/images/credits/kevdagoat.jpeg"
|
|
||||||
alt="profile image" class="profile-img img-lg rounded-circle">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper">
|
|
||||||
<div class="wrapper d-flex align-items-center">
|
|
||||||
<h4 class="mb-0 font-weight-medium">Kev Dagoat</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-center font-weight-medium text-muted">
|
|
||||||
<i class="mdi mdi-map-marker-outline mr-2"></i>
|
|
||||||
<p class="mb-0 text-muted">East Coast, AU</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-8">
|
|
||||||
<div class="wrapper d-flex align-items-start">
|
|
||||||
<span class="btn btn-sm btn-info mr-2">Staff</span>
|
|
||||||
<span class="btn btn-sm btn-primary mr-2">Developer</span>
|
|
||||||
<span class="btn btn-sm btn-inverse-success mr-2">HOD</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-start pt-3">
|
|
||||||
Crafty's Head Of Development<br /><br />
|
|
||||||
His interests include Linux, programming, and goats of course.
|
|
||||||
He enjoys building APIs, K8s, and Geeking over video cards.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="col-md-6 mb-5">
|
|
||||||
<div class="card rounded shadow-none">
|
|
||||||
<div class="card-body">
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
|
|
||||||
<div class="user-avatar mb-auto">
|
|
||||||
<img src="/static/assets/images/credits/mcgaming.png"
|
|
||||||
alt="profile image" class="profile-img img-lg rounded-circle">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper">
|
|
||||||
<div class="wrapper d-flex align-items-center">
|
|
||||||
<h4 class="mb-0 font-weight-medium">MC Gaming</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-center font-weight-medium text-muted">
|
|
||||||
<i class="mdi mdi-map-marker-outline mr-2"></i>
|
|
||||||
<p class="mb-0 text-muted">Central, UK</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-8">
|
|
||||||
<div class="wrapper d-flex align-items-start">
|
|
||||||
<span class="btn btn-sm btn-info mr-2">Staff</span>
|
|
||||||
<span class="btn btn-sm btn-primary mr-2">Developer</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-start pt-3">
|
|
||||||
His interests include learning, Linux, programming.
|
|
||||||
He loves pentesting apps and gaming.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> <!-- end user row-->
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
|
{% for person in data['staff']['retired'] %}
|
||||||
<div class="col-md-6 mb-5">
|
<div class="col-md-6 mb-5">
|
||||||
<div class="card rounded shadow-none">
|
<div class="card rounded shadow-none">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -214,200 +171,46 @@
|
|||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
|
|
||||||
<div class="user-avatar mb-auto">
|
<div class="user-avatar mb-auto">
|
||||||
<img src="/static/assets/images/credits/andrew_cropped.png"
|
<img src="{{ person['pic'] }}"
|
||||||
alt="profile image" class="profile-img img-lg rounded-circle">
|
alt="profile image" class="profile-img img-lg rounded-circle">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="wrapper d-flex align-items-center">
|
<div class="wrapper d-flex align-items-center">
|
||||||
<h4 class="mb-0 font-weight-medium">Andrew Redacted</h4>
|
<h4 class="mb-0 font-weight-medium">{{ person['name'] }}</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-center font-weight-medium text-muted">
|
<div class="wrapper d-flex align-items-center font-weight-medium text-muted">
|
||||||
|
{% if person['loc'] %}
|
||||||
<i class="mdi mdi-map-marker-outline mr-2"></i>
|
<i class="mdi mdi-map-marker-outline mr-2"></i>
|
||||||
<p class="mb-0 text-muted">East Coast, USA</p>
|
<p class="mb-0 text-muted">{{ person['loc'] }}</p>
|
||||||
|
{% end %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="wrapper d-flex align-items-start">
|
<div class="wrapper d-flex align-items-start">
|
||||||
<span class="btn btn-sm btn-info mr-2">Staff</span>
|
{% if person['tags'][0] %}
|
||||||
<span class="btn btn-sm btn-inverse-success mr-2">Support Manager</span>
|
<span class="btn btn-sm btn-info mr-2">{{ person['tags'][0] }}</span>
|
||||||
|
{% end %}
|
||||||
|
{% if person['tags'][1] %}
|
||||||
|
<span class="btn btn-sm btn-primary mr-2">{{ person['tags'][1] }}</span>
|
||||||
|
{% end %}
|
||||||
|
{% if person['tags'][2] %}
|
||||||
|
{% if type(person['tags'][2]) is list %}
|
||||||
|
<a href="{{ person['tags'][2][1] }}" class="btn btn-sm btn-inverse-success mr-2">{{ person['tags'][2][0] }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="btn btn-sm btn-inverse-success mr-2">{{ person['tags'][2] }}</span>
|
||||||
|
{% end %}
|
||||||
|
{% end %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-start pt-3">
|
<div class="wrapper d-flex align-items-start pt-3">
|
||||||
His interests include Linux, gaming, and helping others. When he's able to
|
{% if person['title'] %}
|
||||||
unplug he enjoys biking, hiking, and playing soccer.
|
Crafty's {{ person['title'] }}<br /><br />
|
||||||
</div>
|
{% end %}
|
||||||
</div>
|
{{ person['blurb'] }}
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-6 mb-5">
|
|
||||||
<div class="card rounded shadow-none">
|
|
||||||
<div class="card-body">
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
|
|
||||||
<div class="user-avatar mb-auto">
|
|
||||||
<img src="/static/assets/images/credits/manu_cropped.png"
|
|
||||||
alt="profile image" class="profile-img img-lg rounded-circle">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper">
|
|
||||||
<div class="wrapper d-flex align-items-center">
|
|
||||||
<h4 class="mb-0 font-weight-medium">Manu Redacted</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-center font-weight-medium text-muted">
|
|
||||||
<i class="mdi mdi-map-marker-outline mr-2"></i>
|
|
||||||
<p class="mb-0 text-muted">Eastern, CA</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-8">
|
|
||||||
<div class="wrapper d-flex align-items-start">
|
|
||||||
<span class="btn btn-sm btn-info mr-2">Staff</span>
|
|
||||||
<span class="btn btn-sm btn-primary mr-2">Developer</span>
|
|
||||||
<span class="btn btn-sm btn-inverse-success mr-2">Project Manager</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-start pt-3">
|
|
||||||
His interests include learning, Linux, and programming.
|
|
||||||
He enjoys speaking French, doing 6 things at once, and testing software.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> <!-- end user row-->
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
|
|
||||||
<div class="col-md-6 mb-5">
|
|
||||||
<div class="card rounded shadow-none">
|
|
||||||
<div class="card-body">
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
|
|
||||||
<div class="user-avatar mb-auto">
|
|
||||||
<img src="/static/assets/images/credits/ultrablack_cropped.png"
|
|
||||||
alt="profile image" class="profile-img img-lg rounded-circle">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper">
|
|
||||||
<div class="wrapper d-flex align-items-center">
|
|
||||||
<h4 class="mb-0 font-weight-medium">UltraBlack</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-center font-weight-medium text-muted">
|
|
||||||
<i class="mdi mdi-map-marker-outline mr-2"></i>
|
|
||||||
<p class="mb-0 text-muted">Bavaria, DE</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-8">
|
|
||||||
<div class="wrapper d-flex align-items-start">
|
|
||||||
<span class="btn btn-sm btn-info mr-2">Staff</span>
|
|
||||||
<span class="btn btn-sm btn-inverse-success mr-2">Idea Manager</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-start pt-3">
|
|
||||||
Hi, my name is Tim, and I'm a huge fan of linux.
|
|
||||||
I'm often gaming and occasionally coding.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-6 mb-5">
|
|
||||||
<div class="card rounded shadow-none">
|
|
||||||
<div class="card-body">
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
|
|
||||||
<div class="user-avatar mb-auto">
|
|
||||||
<img src="/static/assets/images/credits/macgeek_cropped.png"
|
|
||||||
alt="profile image" class="profile-img img-lg rounded-circle">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper">
|
|
||||||
<div class="wrapper d-flex align-items-center">
|
|
||||||
<h4 class="mb-0 font-weight-medium">Mac Geek</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-center font-weight-medium text-muted">
|
|
||||||
<i class="mdi mdi-map-marker-outline mr-2"></i>
|
|
||||||
<p class="mb-0 text-muted">Eastern, USA</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-8">
|
|
||||||
<div class="wrapper d-flex align-items-start">
|
|
||||||
<span class="btn btn-sm btn-info mr-2">Staff</span>
|
|
||||||
<span class="btn btn-sm btn-primary mr-2">Developer</span>
|
|
||||||
<span class="btn btn-sm btn-inverse-success mr-2">Support Manager</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-start pt-3">
|
|
||||||
His interests include all things programming, and Pokemon.
|
|
||||||
He enjoys a good tech tangent, gaming, and playing on his phone.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-6 mb-5">
|
|
||||||
<div class="card rounded shadow-none">
|
|
||||||
<div class="card-body">
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
|
|
||||||
<div class="user-avatar mb-auto">
|
|
||||||
<img src="/static/assets/images/credits/lukas_cropped.png"
|
|
||||||
alt="profile image" class="profile-img img-lg rounded-circle">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper">
|
|
||||||
<div class="wrapper d-flex align-items-center">
|
|
||||||
<h4 class="mb-0 font-weight-medium">ThatOneLukas</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-center font-weight-medium text-muted">
|
|
||||||
<i class="mdi mdi-map-marker-outline mr-2"></i>
|
|
||||||
<p class="mb-0 text-muted">Helsinki, FI</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-8">
|
|
||||||
<div class="wrapper d-flex align-items-start">
|
|
||||||
<span class="btn btn-sm btn-info mr-2">Staff</span>
|
|
||||||
<span class="btn btn-sm btn-primary mr-2">Developer</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper d-flex align-items-start pt-3">
|
|
||||||
His interests include programming, gaming, and electronics.
|
|
||||||
He likes gaming, programming, messing around with electronics, and time with his family.
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -415,9 +218,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% end %}
|
||||||
|
|
||||||
</div> <!-- end user row-->
|
</div> <!-- end user row-->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -438,31 +241,22 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
{% for pat in data["patreons"] %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>Richard B</td>
|
<td>{{ pat["name"] }}</td>
|
||||||
<td>
|
<td>
|
||||||
|
{% if pat["level"] == "substainer" %}
|
||||||
<span class="btn btn-sm btn-info mr-2">Substainer</span>
|
<span class="btn btn-sm btn-info mr-2">Substainer</span>
|
||||||
</td>
|
{% elif pat["level"] == "advocate" %}
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>John C</td>
|
|
||||||
<td>
|
|
||||||
<span class="btn btn-sm btn-primary mr-2">Advocate</span>
|
<span class="btn btn-sm btn-primary mr-2">Advocate</span>
|
||||||
|
{% elif pat["level"] == "supporter" %}
|
||||||
|
<span class="btn btn-sm btn-inverse-success mr-2">Supporter</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="btn btn-sm btn-secondary mr-2">Other</span>
|
||||||
|
{% end %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
{% end %}
|
||||||
<td>Nicolas T</td>
|
|
||||||
<td>
|
|
||||||
<span class="btn btn-sm btn-info mr-2">Substainer</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Lightkeeper</td>
|
|
||||||
<td>
|
|
||||||
<span class="btn btn-sm btn-info mr-2">Substainer</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -483,27 +277,16 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
{% for person in data['translations'] %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>Ultrablack</td>
|
<td>{{ person }}</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="btn btn-sm btn-inverse-success mr-2">German</span>
|
{% for language in data['translations'][person] %}
|
||||||
|
<span class="btn btn-sm btn-inverse-success mr-2">{{ language }}</span>
|
||||||
|
{% end %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
{% end %}
|
||||||
<td>Manu</td>
|
|
||||||
<td>
|
|
||||||
<span class="btn btn-sm btn-inverse-success mr-2">French</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>ptarrant</td>
|
|
||||||
<td>
|
|
||||||
<span class="btn btn-sm btn-inverse-success mr-2">Sarcasm</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -125,7 +125,7 @@
|
|||||||
|
|
||||||
<td class="actions_serverlist">
|
<td class="actions_serverlist">
|
||||||
|
|
||||||
{% if server['stats'][0]['running'] %}
|
{% if server['stats']['running'] %}
|
||||||
<a class="stop_button" data-id="{{server['server_data']['server_id']}}"> <i class="fas fa-stop"></i></a>
|
<a class="stop_button" data-id="{{server['server_data']['server_id']}}"> <i class="fas fa-stop"></i></a>
|
||||||
<a class="restart_button" data-id="{{server['server_data']['server_id']}}"> <i class="fas fa-sync"></i></a>
|
<a class="restart_button" data-id="{{server['server_data']['server_id']}}"> <i class="fas fa-sync"></i></a>
|
||||||
{% else %}
|
{% else %}
|
||||||
@ -136,59 +136,59 @@
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<div class="progress mb-1" data-toggle="tooltip" data-placement="top" title="{{server['stats'][0]['cpu']}}">
|
<div class="progress mb-1" data-toggle="tooltip" data-placement="top" title="{{server['stats']['cpu']}}">
|
||||||
<div class="progress-bar
|
<div class="progress-bar
|
||||||
{% if server['stats'][0]['cpu'] <= 33 %}
|
{% if server['stats']['cpu'] <= 33 %}
|
||||||
bg-success
|
bg-success
|
||||||
{% elif 34 <= server['stats'][0]['cpu'] <= 66 %}
|
{% elif 34 <= server['stats']['cpu'] <= 66 %}
|
||||||
bg-warning
|
bg-warning
|
||||||
{% else %}
|
{% else %}
|
||||||
bg-danger
|
bg-danger
|
||||||
{% end %}
|
{% end %}
|
||||||
" role="progressbar" style="width: {{server['stats'][0]['cpu']}}%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
" role="progressbar" style="width: {{server['stats']['cpu']}}%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
</div>
|
</div>
|
||||||
{{server['stats'][0]['cpu']}}%
|
{{server['stats']['cpu']}}%
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<div class="progress mb-1" data-toggle="tooltip" data-placement="top" title="{{server['stats'][0]['mem']}}">
|
<div class="progress mb-1" data-toggle="tooltip" data-placement="top" title="{{server['stats']['mem']}}">
|
||||||
<div class="progress-bar
|
<div class="progress-bar
|
||||||
{% if server['stats'][0]['mem_percent'] <= 33 %}
|
{% if server['stats']['mem_percent'] <= 33 %}
|
||||||
bg-success
|
bg-success
|
||||||
{% elif 34 <= server['stats'][0]['mem_percent'] <= 66 %}
|
{% elif 34 <= server['stats']['mem_percent'] <= 66 %}
|
||||||
bg-warning
|
bg-warning
|
||||||
{% else %}
|
{% else %}
|
||||||
bg-danger
|
bg-danger
|
||||||
{% end %}
|
{% end %}
|
||||||
" role="progressbar" style="width: {{server['stats'][0]['mem_percent']}}%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
" role="progressbar" style="width: {{server['stats']['mem_percent']}}%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
</div>
|
</div>
|
||||||
{{server['stats'][0]['mem_percent']}}% -
|
{{server['stats']['mem_percent']}}% -
|
||||||
|
|
||||||
{% if server['stats'][0]['mem'] == 0 %}
|
{% if server['stats']['mem'] == 0 %}
|
||||||
0 MB
|
0 MB
|
||||||
{% else %}
|
{% else %}
|
||||||
{{server['stats'][0]['mem']}}
|
{{server['stats']['mem']}}
|
||||||
{% end %}
|
{% end %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ server['stats'][0]['world_name'] }} : {{ server['stats'][0]['world_size'] }}
|
{{ server['stats']['world_name'] }} : {{ server['stats']['world_size'] }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% if server['stats'][0]['int_ping_results'] %}
|
{% if server['stats']['int_ping_results'] %}
|
||||||
{{ server['stats'][0]['online'] }} / {{ server['stats'][0]['max'] }} Max<br />
|
{{ server['stats']['online'] }} / {{ server['stats']['max'] }} Max<br />
|
||||||
|
|
||||||
{% if server['stats'][0]['desc'] != 'False' %}
|
{% if server['stats']['desc'] != 'False' %}
|
||||||
{{ server['stats'][0]['desc'] }} <br />
|
{{ server['stats']['desc'] }} <br />
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
{% if server['stats'][0]['version'] != 'False' %}
|
{% if server['stats']['version'] != 'False' %}
|
||||||
{{ server['stats'][0]['version'] }}
|
{{ server['stats']['version'] }}
|
||||||
{% end %}
|
{% end %}
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% if server['stats'][0]['running'] %}
|
{% if server['stats']['running'] %}
|
||||||
<i class="fas fa-thumbs-up"></i> <span class="text-success">Online</span>
|
<i class="fas fa-thumbs-up"></i> <span class="text-success">Online</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<i class="fas fa-thumbs-down"></i> <span class="text-danger">Offline</span>
|
<i class="fas fa-thumbs-down"></i> <span class="text-danger">Offline</span>
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
<div class="card-body pt-3 pb-3">
|
<div class="card-body pt-3 pb-3">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-3 mr-2">
|
<div class="col-sm-3 mr-2">
|
||||||
{% if data['server_stats'][0]['running'] %}
|
{% if data['server_stats']['running'] %}
|
||||||
<b>Server Status:</b> <span class="text-success">Online</span><br />
|
<b>Server Status:</b> <span class="text-success">Online</span><br />
|
||||||
<b>Server Started:</b> <span id="started">{{ data['server_stats'][0]['started'] }} (Server Time)</span><br />
|
<b>Server Started:</b> <span id="started">{{ data['server_stats']['started'] }} (Server Time)</span><br />
|
||||||
<b>Server Uptime:</b> <span id="uptime">Error Calculating</span>
|
<b>Server Uptime:</b> <span id="uptime">Error Calculating</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<b>Server Status:</b> <span class="text-danger">Offline</span><br />
|
<b>Server Status:</b> <span class="text-danger">Offline</span><br />
|
||||||
@ -16,19 +16,19 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-3 mr-2">
|
<div class="col-sm-3 mr-2">
|
||||||
<b>CPU:</b> {{ data['server_stats'][0]['cpu'] }}% <br />
|
<b>CPU:</b> {{ data['server_stats']['cpu'] }}% <br />
|
||||||
<b>Mem:</b> {{ data['server_stats'][0]['mem'] }} <br />
|
<b>Mem:</b> {{ data['server_stats']['mem'] }} <br />
|
||||||
{% if data['server_stats'][0]['int_ping_results'] %}
|
{% if data['server_stats']['int_ping_results'] %}
|
||||||
<b>Players:</b> {{ data['server_stats'][0]['online'] }} / {{ data['server_stats'][0]['max'] }}<br />
|
<b>Players:</b> {{ data['server_stats']['online'] }} / {{ data['server_stats']['max'] }}<br />
|
||||||
{% else %}
|
{% else %}
|
||||||
<b>Players:</b> 0/0<br />
|
<b>Players:</b> 0/0<br />
|
||||||
{% end %}
|
{% end %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-3 mr-2">
|
<div class="col-sm-3 mr-2">
|
||||||
{% if data['server_stats'][0]['version'] != 'False' %}
|
{% if data['server_stats']['version'] != 'False' %}
|
||||||
<b>Server:</b> {{ data['server_stats'][0]['version'] }} <br />
|
<b>Server:</b> {{ data['server_stats']['version'] }} <br />
|
||||||
<b>Desc:</b> {{ data['server_stats'][0]['desc'] }} <br />
|
<b>Desc:</b> {{ data['server_stats']['desc'] }} <br />
|
||||||
{% else %}
|
{% else %}
|
||||||
<b>Server:</b> Unable To Connect <br />
|
<b>Server:</b> Unable To Connect <br />
|
||||||
<b>Desc:</b> Unable To Connect <br />
|
<b>Desc:</b> Unable To Connect <br />
|
||||||
@ -86,9 +86,9 @@
|
|||||||
let startedLocal;
|
let startedLocal;
|
||||||
|
|
||||||
if (started != null) {
|
if (started != null) {
|
||||||
console.log('88', '{{ data['server_stats'][0]['started'] }}');
|
console.log('88', '{{ data['server_stats']['started'] }}');
|
||||||
{% if data['server_stats'][0]['started'] != 'False' %}
|
{% if data['server_stats']['started'] != 'False' %}
|
||||||
startedUTC = '{{ (datetime.datetime.strptime(data['server_stats'][0]['started'], '%Y-%m-%d %H:%M:%S') - datetime.timedelta(seconds=-time.timezone)).strftime('%Y-%m-%d %H:%M:%S') }}';
|
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 %}
|
{% end %}
|
||||||
console.log('utc', startedUTC);
|
console.log('utc', startedUTC);
|
||||||
startedUTC = moment.utc(startedUTC, 'YYYY-MM-DD HH:mm:ss');
|
startedUTC = moment.utc(startedUTC, 'YYYY-MM-DD HH:mm:ss');
|
||||||
@ -105,7 +105,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let nowServerTime = '{{ data['time'] }}';
|
let nowServerTime = '{{ data['time'] }}';
|
||||||
let startedServerTime = '{{ data['server_stats'][0]['started'] }}';
|
let startedServerTime = '{{ data['server_stats']['started'] }}';
|
||||||
|
|
||||||
if (uptime != null && started != null) {
|
if (uptime != null && started != null) {
|
||||||
|
|
||||||
|
@ -15,9 +15,9 @@
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h4 class="page-title">
|
<h4 class="page-title">
|
||||||
Server Details - {{ data['server_stats'][0]['server_id']['server_name'] }}
|
Server Details - {{ data['server_stats']['server_id']['server_name'] }}
|
||||||
<br />
|
<br />
|
||||||
<small>UUID: {{ data['server_stats'][0]['server_id']['server_uuid'] }}</small>
|
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -34,31 +34,31 @@
|
|||||||
<div class="card-body pt-0">
|
<div class="card-body pt-0">
|
||||||
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=term" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=term" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-file-signature"></i>Terminal</a>
|
<i class="fas fa-file-signature"></i>Terminal</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-file-signature"></i>Logs</a>
|
<i class="fas fa-file-signature"></i>Logs</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=tasks" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=tasks" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-clock"></i>Schedule</a>
|
<i class="fas fa-clock"></i>Schedule</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=backup" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=backup" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-save"></i>Backup</a>
|
<i class="fas fa-save"></i>Backup</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=files" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=files" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-folder-tree"></i>Files</a>
|
<i class="fas fa-folder-tree"></i>Files</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=config" role="tab" aria-selected="true">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=config" role="tab" aria-selected="true">
|
||||||
<i class="fas fa-cogs"></i>Config</a>
|
<i class="fas fa-cogs"></i>Config</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=admin_controls" role="tab" aria-selected="true">
|
<a class="nav-link active" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=admin_controls" role="tab" aria-selected="true">
|
||||||
<i class="fas fa-users"></i>Player Controls</a>
|
<i class="fas fa-users"></i>Player Controls</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
247
app/frontend/templates/panel/server_backup.html
Normal file
247
app/frontend/templates/panel/server_backup.html
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
{% extends ../base.html %}
|
||||||
|
|
||||||
|
{% block meta %}
|
||||||
|
<!-- <meta http-equiv="refresh" content="60">-->
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
{% block title %}Crafty Controller - Server Details{% end %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="content-wrapper">
|
||||||
|
|
||||||
|
<!-- Page Title Header Starts-->
|
||||||
|
<div class="row page-title-header">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="page-header">
|
||||||
|
<h4 class="page-title">
|
||||||
|
Server Details - {{ data['server_stats']['server_id']['server_name'] }}
|
||||||
|
<br />
|
||||||
|
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- Page Title Header Ends-->
|
||||||
|
|
||||||
|
{% include "parts/details_stats.html %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-12 grid-margin">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body pt-0">
|
||||||
|
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=term" role="tab" aria-selected="false">
|
||||||
|
<i class="fas fa-file-signature"></i>Terminal</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="false">
|
||||||
|
<i class="fas fa-file-signature"></i>Logs</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=tasks" role="tab" aria-selected="false">
|
||||||
|
<i class="fas fa-clock"></i>Schedule</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=backup" role="tab" aria-selected="true">
|
||||||
|
<i class="fas fa-save"></i>Backup</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=files" role="tab" aria-selected="false">
|
||||||
|
<i class="fas fa-folder-tree"></i>Files</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=config" role="tab" aria-selected="false">
|
||||||
|
<i class="fas fa-cogs"></i>Config</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=admin_controls" role="tab" aria-selected="false">
|
||||||
|
<i class="fas fa-users"></i>Player Controls</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 col-sm-12">
|
||||||
|
<form class="forms-sample" method="post" action="/panel/server_backup">
|
||||||
|
{% raw xsrf_form_html() %}
|
||||||
|
<input type="hidden" name="id" value="{{ data['server_stats']['server_id']['server_id'] }}">
|
||||||
|
<input type="hidden" name="subpage" value="backup">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<a href="/panel/backup_now?id={{ data['server_stats']['server_id']['server_id'] }}" class="btn btn-primary" onclick="backup_started()">Backup Now!</a>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="server_name">Storage Location <small class="text-muted ml-1"> - Where do you want to store backups?</small> </label>
|
||||||
|
<input type="text" class="form-control" name="backup_path" id="backup_path" value="{{ data['server_stats']['server_id']['backup_path'] }}" placeholder="Backup Path" >
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="server_path">Max Backups <small class="text-muted ml-1"> - Crafty will not store more than n backups, deleting the oldest (enter 0 to keep all)</small> </label>
|
||||||
|
<input type="text" class="form-control" name="max_backups" id="max_backups" value="{{ data['backup_config']['max_backups'] }}" placeholder="Max Backups" >
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="superuser" class="form-check-label ml-4 mb-4">
|
||||||
|
{% if data['backup_config']['auto_enabled'] %}
|
||||||
|
<input type="checkbox" class="form-check-input" id="auto_enabled" name="auto_enabled" checked="" value="1" >Auto-backup at 12:00 AM?
|
||||||
|
{% else %}
|
||||||
|
<input type="checkbox" class="form-check-input" id="auto_enabled" name="auto_enabled" value="1" >Auto-backup at 12:00 AM?
|
||||||
|
{% end %}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-success mr-2">Save</button>
|
||||||
|
<button type="reset" class="btn btn-light">Cancel</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6 col-sm-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4 class="card-title">Current Backups</h4>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
|
||||||
|
<table class="table table-responsive dataTable" id="backup_table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="10%">Download</th>
|
||||||
|
<th>Path</th>
|
||||||
|
<th width="20%">Size</th>
|
||||||
|
<th width="10%">Delete</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for backup in data['backup_list'] %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/panel/download_backup?file={{ backup['path'] }}&id={{ data['server_stats']['server_id']['server_id'] }}" class="btn btn-primary">
|
||||||
|
<i class="fas fa-download" aria-hidden="true"></i>
|
||||||
|
Download
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>{{ backup['path'] }}</td>
|
||||||
|
<td>{{ backup['size'] }}</td>
|
||||||
|
<td>
|
||||||
|
<button data-file="{{ backup['path'] }}" class="btn btn-danger del_button">
|
||||||
|
<i class="fas fa-trash" aria-hidden="true"></i>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- content-wrapper ends -->
|
||||||
|
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
|
||||||
|
function getCookie(name) {
|
||||||
|
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
|
||||||
|
return r ? r[1] : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function backup_started(time='5-10') {
|
||||||
|
bootbox.alert({
|
||||||
|
message: "A backup task has been started.",
|
||||||
|
backdrop: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function del_backup(filename, id){
|
||||||
|
var token = getCookie("_xsrf")
|
||||||
|
|
||||||
|
data_to_send = { file_name :filename}
|
||||||
|
|
||||||
|
console.log('Sending Command to delete file: ' + filename)
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
headers: {'X-XSRFToken': token},
|
||||||
|
url: '/ajax/del_file?server_id='+id,
|
||||||
|
data: data_to_send,
|
||||||
|
success: function(data){
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$( document ).ready(function() {
|
||||||
|
console.log( "ready!" );
|
||||||
|
$("#backup_config_box").hide();
|
||||||
|
$("#backup_save_note").hide();
|
||||||
|
|
||||||
|
$("#show_config").click(function () {
|
||||||
|
$("#backup_config_box").toggle();
|
||||||
|
$('#backup_button').hide();
|
||||||
|
$('#backup_save_note').show();
|
||||||
|
$('#backup_data').hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#backup_table').DataTable({
|
||||||
|
"order": [[ 1, "desc" ]],
|
||||||
|
"paging":true,
|
||||||
|
"lengthChange": false,
|
||||||
|
"searching": true,
|
||||||
|
"ordering": true,
|
||||||
|
"info": true,
|
||||||
|
"autoWidth": false,
|
||||||
|
"responsive": true,
|
||||||
|
});
|
||||||
|
|
||||||
|
$( ".del_button" ).click(function() {
|
||||||
|
var file_to_del = $(this).data("file");
|
||||||
|
|
||||||
|
console.log("file to delete is" + file_to_del);
|
||||||
|
|
||||||
|
bootbox.confirm({
|
||||||
|
title: "Destroy backup " + file_to_del + "?",
|
||||||
|
message: "Do you want to delete this file? This cannot be undone.",
|
||||||
|
buttons: {
|
||||||
|
cancel: {
|
||||||
|
label: '<i class="fas fa-times"></i> Cancel'
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
label: '<i class="fas fa-check"></i> Confirm'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callback: function (result) {
|
||||||
|
console.log(result);
|
||||||
|
if (result == true) {
|
||||||
|
del_backup(file_to_del, {{ data['server_stats']['server_id']['server_id'] }} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{% end %}
|
@ -15,9 +15,9 @@
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h4 class="page-title">
|
<h4 class="page-title">
|
||||||
Server Details - {{ data['server_stats'][0]['server_id']['server_name'] }}
|
Server Details - {{ data['server_stats']['server_id']['server_name'] }}
|
||||||
<br />
|
<br />
|
||||||
<small>UUID: {{ data['server_stats'][0]['server_id']['server_uuid'] }}</small>
|
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -34,31 +34,31 @@
|
|||||||
<div class="card-body pt-0">
|
<div class="card-body pt-0">
|
||||||
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=term" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=term" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-file-signature"></i>Terminal</a>
|
<i class="fas fa-file-signature"></i>Terminal</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-file-signature"></i>Logs</a>
|
<i class="fas fa-file-signature"></i>Logs</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=tasks" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=tasks" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-clock"></i>Schedule</a>
|
<i class="fas fa-clock"></i>Schedule</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=backup" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=backup" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-save"></i>Backup</a>
|
<i class="fas fa-save"></i>Backup</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=files" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=files" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-folder-tree"></i>Files</a>
|
<i class="fas fa-folder-tree"></i>Files</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=config" role="tab" aria-selected="true">
|
<a class="nav-link active" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=config" role="tab" aria-selected="true">
|
||||||
<i class="fas fa-cogs"></i>Config</a>
|
<i class="fas fa-cogs"></i>Config</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=admin_controls" role="tab" aria-selected="true">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=admin_controls" role="tab" aria-selected="true">
|
||||||
<i class="fas fa-users"></i>Player Controls</a>
|
<i class="fas fa-users"></i>Player Controls</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@ -68,62 +68,62 @@
|
|||||||
<div class="col-md-6 col-sm-12">
|
<div class="col-md-6 col-sm-12">
|
||||||
<form class="forms-sample" method="post" action="/panel/server_detail">
|
<form class="forms-sample" method="post" action="/panel/server_detail">
|
||||||
{% raw xsrf_form_html() %}
|
{% raw xsrf_form_html() %}
|
||||||
<input type="hidden" name="id" value="{{ data['server_stats'][0]['server_id']['server_id'] }}">
|
<input type="hidden" name="id" value="{{ data['server_stats']['server_id']['server_id'] }}">
|
||||||
<input type="hidden" name="subpage" value="config">
|
<input type="hidden" name="subpage" value="config">
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="server_name">Server Name <small class="text-muted ml-1"> - What you wish to call this server</small> </label>
|
<label for="server_name">Server Name <small class="text-muted ml-1"> - What you wish to call this server</small> </label>
|
||||||
<input type="text" class="form-control" name="server_name" id="server_name" value="{{ data['server_stats'][0]['server_id']['server_name'] }}" placeholder="Server Name" >
|
<input type="text" class="form-control" name="server_name" id="server_name" value="{{ data['server_stats']['server_id']['server_name'] }}" placeholder="Server Name" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="server_path">Server Path <small class="text-muted ml-1"> - Absolute full path (not including executable)</small> </label>
|
<label for="server_path">Server Path <small class="text-muted ml-1"> - Absolute full path (not including executable)</small> </label>
|
||||||
<input type="text" class="form-control" name="server_path" id="server_path" value="{{ data['server_stats'][0]['server_id']['path'] }}" placeholder="Server Path" >
|
<input type="text" class="form-control" name="server_path" id="server_path" value="{{ data['server_stats']['server_id']['path'] }}" placeholder="Server Path" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="log_path">Server Log Location <small class="text-muted ml-1"> - Absolute full path to the log file</small> </label>
|
<label for="log_path">Server Log Location <small class="text-muted ml-1"> - Absolute full path to the log file</small> </label>
|
||||||
<input type="text" class="form-control" name="log_path" id="log_path" value="{{ data['server_stats'][0]['server_id']['log_path'] }}" placeholder="Server Log" >
|
<input type="text" class="form-control" name="log_path" id="log_path" value="{{ data['server_stats']['server_id']['log_path'] }}" placeholder="Server Log" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="executable">Server Executable <small class="text-muted ml-1"> - Just the executable file</small> </label>
|
<label for="executable">Server Executable <small class="text-muted ml-1"> - Just the executable file</small> </label>
|
||||||
<input type="text" class="form-control" name="executable" id="executable" value="{{ data['server_stats'][0]['server_id']['executable'] }}" placeholder="Server Executable" >
|
<input type="text" class="form-control" name="executable" id="executable" value="{{ data['server_stats']['server_id']['executable'] }}" placeholder="Server Executable" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="execution_command">Server Execution Command <small class="text-muted ml-1"> - What will be launched in a hidden terminal</small> </label>
|
<label for="execution_command">Server Execution Command <small class="text-muted ml-1"> - What will be launched in a hidden terminal</small> </label>
|
||||||
<input type="text" class="form-control" name="execution_command" id="execution_command" value="{{ data['server_stats'][0]['server_id']['execution_command'] }}" placeholder="Server Execution Command" >
|
<input type="text" class="form-control" name="execution_command" id="execution_command" value="{{ data['server_stats']['server_id']['execution_command'] }}" placeholder="Server Execution Command" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="stop_command">Server Stop Command <small class="text-muted ml-1"> - Command to send the program to stop it</small> </label>
|
<label for="stop_command">Server Stop Command <small class="text-muted ml-1"> - Command to send the program to stop it</small> </label>
|
||||||
<input type="text" class="form-control" name="stop_command" id="stop_command" value="{{ data['server_stats'][0]['server_id']['stop_command'] }}" placeholder="Server Stop Command" >
|
<input type="text" class="form-control" name="stop_command" id="stop_command" value="{{ data['server_stats']['server_id']['stop_command'] }}" placeholder="Server Stop Command" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="auto_start_delay">Server Autostart Delay <small class="text-muted ml-1"> - Delay before auto starting (if enabled below)</small> </label>
|
<label for="auto_start_delay">Server Autostart Delay <small class="text-muted ml-1"> - Delay before auto starting (if enabled below)</small> </label>
|
||||||
<input type="number" class="form-control" name="auto_start_delay" id="auto_start_delay" value="{{ data['server_stats'][0]['server_id']['auto_start_delay'] }}" step="1" max="999" min="10" >
|
<input type="number" class="form-control" name="auto_start_delay" id="auto_start_delay" value="{{ data['server_stats']['server_id']['auto_start_delay'] }}" step="1" max="999" min="10" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="server_ip">Server IP <small class="text-muted ml-1"> - IP Crafty should connect to for stats (Try a real ip instead of 127.0.0.1 if you have issues)</small> </label>
|
<label for="server_ip">Server IP <small class="text-muted ml-1"> - IP Crafty should connect to for stats (Try a real ip instead of 127.0.0.1 if you have issues)</small> </label>
|
||||||
<input type="text" class="form-control" name="server_ip" id="server_ip" value="{{ data['server_stats'][0]['server_id']['server_ip'] }}">
|
<input type="text" class="form-control" name="server_ip" id="server_ip" value="{{ data['server_stats']['server_id']['server_ip'] }}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="server_port">Server Port <small class="text-muted ml-1"> - Port Crafty should connect to for stats</small> </label>
|
<label for="server_port">Server Port <small class="text-muted ml-1"> - Port Crafty should connect to for stats</small> </label>
|
||||||
<input type="number" class="form-control" name="server_port" id="server_port" value="{{ data['server_stats'][0]['server_id']['server_port'] }}" step="1" max="65566" min="1" >
|
<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" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="logs_delete_after">Remove Old Logs After <small class="text-muted ml-1"> - How many days will a log file has to be old to get deleted (0 is off)</small> </label>
|
<label for="logs_delete_after">Remove Old Logs After <small class="text-muted ml-1"> - How many days will a log file has to be old to get deleted (0 is off)</small> </label>
|
||||||
<input type="number" class="form-control" name="logs_delete_after" id="logs_delete_after" value="{{ data['server_stats'][0]['server_id']['logs_delete_after'] }}" step="1" max="365" min="0" >
|
<input type="number" class="form-control" name="logs_delete_after" id="logs_delete_after" value="{{ data['server_stats']['server_id']['logs_delete_after'] }}" step="1" max="365" min="0" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check-flat">
|
<div class="form-check-flat">
|
||||||
<label for="auto_start" class="form-check-label ml-4 mb-4">
|
<label for="auto_start" class="form-check-label ml-4 mb-4">
|
||||||
{% if data['server_stats'][0]['server_id']['auto_start'] %}
|
{% if data['server_stats']['server_id']['auto_start'] %}
|
||||||
<input type="checkbox" class="form-check-input" id="auto_start" name="auto_start" checked="" value="1">Server Auto Start
|
<input type="checkbox" class="form-check-input" id="auto_start" name="auto_start" checked="" value="1">Server Auto Start
|
||||||
{% else %}
|
{% else %}
|
||||||
<input type="checkbox" class="form-check-input" id="auto_start" name="auto_start" value="1">Server Auto Start
|
<input type="checkbox" class="form-check-input" id="auto_start" name="auto_start" value="1">Server Auto Start
|
||||||
@ -131,7 +131,7 @@
|
|||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="crash_detection" class="form-check-label ml-4 mb-4">
|
<label for="crash_detection" class="form-check-label ml-4 mb-4">
|
||||||
{% if data['server_stats'][0]['server_id']['crash_detection'] %}
|
{% if data['server_stats']['server_id']['crash_detection'] %}
|
||||||
<input type="checkbox" class="form-check-input" id="crash_detection" name="crash_detection" checked="" value="1">Server Crash Detection
|
<input type="checkbox" class="form-check-input" id="crash_detection" name="crash_detection" checked="" value="1">Server Crash Detection
|
||||||
{% else %}
|
{% else %}
|
||||||
<input type="checkbox" class="form-check-input" id="crash_detection" name="crash_detection" value="1" >Server Crash Detection
|
<input type="checkbox" class="form-check-input" id="crash_detection" name="crash_detection" value="1" >Server Crash Detection
|
||||||
@ -170,11 +170,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
{% if data['server_stats'][0]['running'] %}
|
{% if data['server_stats']['running'] %}
|
||||||
<a class="btn btn-sm btn-danger disabled">Delete Server</a><br />
|
<a class="btn btn-sm btn-danger disabled">Delete Server</a><br />
|
||||||
<small>Please stop the server before deleting it</small>
|
<small>Please stop the server before deleting it</small>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="/panel/remove_server?id={{ data['server_stats'][0]['server_id']['server_id'] }}" class="btn btn-sm btn-danger">Delete Server</a>
|
<a href="/panel/remove_server?id={{ data['server_stats']['server_id']['server_id'] }}" class="btn btn-sm btn-danger">Delete Server</a>
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,9 +15,9 @@
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h4 class="page-title">
|
<h4 class="page-title">
|
||||||
Server Details - {{ data['server_stats'][0]['server_id']['server_name'] }}
|
Server Details - {{ data['server_stats']['server_id']['server_name'] }}
|
||||||
<br />
|
<br />
|
||||||
<small>UUID: {{ data['server_stats'][0]['server_id']['server_uuid'] }}</small>
|
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -34,31 +34,31 @@
|
|||||||
<div class="card-body pt-0">
|
<div class="card-body pt-0">
|
||||||
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=term" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=term" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-file-signature"></i>Terminal</a>
|
<i class="fas fa-file-signature"></i>Terminal</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-file-signature"></i>Logs</a>
|
<i class="fas fa-file-signature"></i>Logs</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=tasks" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=tasks" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-clock"></i>Schedule</a>
|
<i class="fas fa-clock"></i>Schedule</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=backup" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=backup" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-save"></i>Backup</a>
|
<i class="fas fa-save"></i>Backup</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=files" role="tab" aria-selected="false">
|
<a class="nav-link active" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=files" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-folder-tree"></i>Files</a>
|
<i class="fas fa-folder-tree"></i>Files</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=config" role="tab" aria-selected="true">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=config" role="tab" aria-selected="true">
|
||||||
<i class="fas fa-cogs"></i>Config</a>
|
<i class="fas fa-cogs"></i>Config</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=admin_controls" role="tab" aria-selected="true">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=admin_controls" role="tab" aria-selected="true">
|
||||||
<i class="fas fa-users"></i>Player Controls</a>
|
<i class="fas fa-users"></i>Player Controls</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@ -329,7 +329,7 @@
|
|||||||
setFileName(event.target.innerText);
|
setFileName(event.target.innerText);
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
url: '/ajax/get_file?id={{ data['server_stats'][0]['server_id']['server_id'] }}&file_path=' + encodeURIComponent(filePath),
|
url: '/ajax/get_file?id={{ data['server_stats']['server_id']['server_id'] }}&file_path=' + encodeURIComponent(filePath),
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
console.log('Got File Contents From Server');
|
console.log('Got File Contents From Server');
|
||||||
@ -393,7 +393,7 @@
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
headers: {'X-XSRFToken': token},
|
headers: {'X-XSRFToken': token},
|
||||||
url: '/ajax/save_file?id={{ data['server_stats'][0]['server_id']['server_id'] }}',
|
url: '/ajax/save_file?id={{ data['server_stats']['server_id']['server_id'] }}',
|
||||||
data: {
|
data: {
|
||||||
file_contents: text,
|
file_contents: text,
|
||||||
file_path: filePath
|
file_path: filePath
|
||||||
@ -410,7 +410,7 @@
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
headers: {'X-XSRFToken': token},
|
headers: {'X-XSRFToken': token},
|
||||||
url: '/ajax/create_file?id={{ data['server_stats'][0]['server_id']['server_id'] }}',
|
url: '/ajax/create_file?id={{ data['server_stats']['server_id']['server_id'] }}',
|
||||||
data: {
|
data: {
|
||||||
file_parent: parent,
|
file_parent: parent,
|
||||||
file_name: name
|
file_name: name
|
||||||
@ -428,7 +428,7 @@
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
headers: {'X-XSRFToken': token},
|
headers: {'X-XSRFToken': token},
|
||||||
url: '/ajax/create_dir?id={{ data['server_stats'][0]['server_id']['server_id'] }}',
|
url: '/ajax/create_dir?id={{ data['server_stats']['server_id']['server_id'] }}',
|
||||||
data: {
|
data: {
|
||||||
dir_parent: parent,
|
dir_parent: parent,
|
||||||
dir_name: name
|
dir_name: name
|
||||||
@ -446,7 +446,7 @@
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
headers: {'X-XSRFToken': token},
|
headers: {'X-XSRFToken': token},
|
||||||
url: '/ajax/rename_item?id={{ data['server_stats'][0]['server_id']['server_id'] }}',
|
url: '/ajax/rename_item?id={{ data['server_stats']['server_id']['server_id'] }}',
|
||||||
data: {
|
data: {
|
||||||
item_path: path,
|
item_path: path,
|
||||||
new_item_name: name
|
new_item_name: name
|
||||||
@ -465,7 +465,7 @@
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
type: "DELETE",
|
type: "DELETE",
|
||||||
headers: {'X-XSRFToken': token},
|
headers: {'X-XSRFToken': token},
|
||||||
url: '/ajax/del_file?id={{ data['server_stats'][0]['server_id']['server_id'] }}',
|
url: '/ajax/del_file?id={{ data['server_stats']['server_id']['server_id'] }}',
|
||||||
data: {
|
data: {
|
||||||
file_path: path
|
file_path: path
|
||||||
},
|
},
|
||||||
@ -482,7 +482,7 @@
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
type: "DELETE",
|
type: "DELETE",
|
||||||
headers: {'X-XSRFToken': token},
|
headers: {'X-XSRFToken': token},
|
||||||
url: '/ajax/del_dir?id={{ data['server_stats'][0]['server_id']['server_id'] }}',
|
url: '/ajax/del_dir?id={{ data['server_stats']['server_id']['server_id'] }}',
|
||||||
data: {
|
data: {
|
||||||
dir_path: path
|
dir_path: path
|
||||||
},
|
},
|
||||||
@ -497,7 +497,7 @@
|
|||||||
function getTreeView() {
|
function getTreeView() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "GET",
|
type: "GET",
|
||||||
url: '/ajax/get_tree?id={{ data['server_stats'][0]['server_id']['server_id'] }}',
|
url: '/ajax/get_tree?id={{ data['server_stats']['server_id']['server_id'] }}',
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
success: function(data){
|
success: function(data){
|
||||||
console.log("got response:");
|
console.log("got response:");
|
||||||
|
@ -15,9 +15,9 @@
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h4 class="page-title">
|
<h4 class="page-title">
|
||||||
Server Details - {{ data['server_stats'][0]['server_id']['server_name'] }}
|
Server Details - {{ data['server_stats']['server_id']['server_name'] }}
|
||||||
<br />
|
<br />
|
||||||
<small>UUID: {{ data['server_stats'][0]['server_id']['server_uuid'] }}</small>
|
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -35,31 +35,31 @@
|
|||||||
|
|
||||||
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=term" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=term" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-terminal"></i>Terminal</a>
|
<i class="fas fa-terminal"></i>Terminal</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="true">
|
<a class="nav-link active" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="true">
|
||||||
<i class="fas fa-file-signature"></i>Logs</a>
|
<i class="fas fa-file-signature"></i>Logs</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=tasks" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=tasks" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-clock"></i>Schedule</a>
|
<i class="fas fa-clock"></i>Schedule</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=backup" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=backup" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-save"></i>Backup</a>
|
<i class="fas fa-save"></i>Backup</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=files" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=files" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-folder-tree"></i>Files</a>
|
<i class="fas fa-folder-tree"></i>Files</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=config" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=config" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-cogs"></i>Config</a>
|
<i class="fas fa-cogs"></i>Config</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=admin_controls" role="tab" aria-selected="true">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=admin_controls" role="tab" aria-selected="true">
|
||||||
<i class="fas fa-users"></i>Player Controls</a>
|
<i class="fas fa-users"></i>Player Controls</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@ -91,7 +91,7 @@
|
|||||||
if( !$("#stop_scroll").is(':checked')){
|
if( !$("#stop_scroll").is(':checked')){
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
url: '/ajax/server_log?id={{ data['server_stats'][0]['server_id']['server_id'] }}&full=1',
|
url: '/ajax/server_log?id={{ data['server_stats']['server_id']['server_id'] }}&full=1',
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
console.log('Got Log From Server')
|
console.log('Got Log From Server')
|
||||||
|
@ -15,9 +15,9 @@
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h4 class="page-title">
|
<h4 class="page-title">
|
||||||
Server Details - {{ data['server_stats'][0]['server_id']['server_name'] }}
|
Server Details - {{ data['server_stats']['server_id']['server_name'] }}
|
||||||
<br />
|
<br />
|
||||||
<small>UUID: {{ data['server_stats'][0]['server_id']['server_uuid'] }}</small>
|
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -35,31 +35,31 @@
|
|||||||
|
|
||||||
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
||||||
<li class="nav-item term-nav-item">
|
<li class="nav-item term-nav-item">
|
||||||
<a class="nav-link active" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=term" role="tab" aria-selected="true">
|
<a class="nav-link active" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=term" role="tab" aria-selected="true">
|
||||||
<i class="fas fa-file-signature"></i>Terminal</a>
|
<i class="fas fa-file-signature"></i>Terminal</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item term-nav-item">
|
<li class="nav-item term-nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-file-signature"></i>Logs</a>
|
<i class="fas fa-file-signature"></i>Logs</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item term-nav-item">
|
<li class="nav-item term-nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=tasks" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=tasks" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-clock"></i>Schedule</a>
|
<i class="fas fa-clock"></i>Schedule</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item term-nav-item">
|
<li class="nav-item term-nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=backup" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=backup" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-save"></i>Backup</a>
|
<i class="fas fa-save"></i>Backup</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item term-nav-item">
|
<li class="nav-item term-nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=files" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=files" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-folder-tree"></i>Files</a>
|
<i class="fas fa-folder-tree"></i>Files</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item term-nav-item">
|
<li class="nav-item term-nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=config" role="tab" aria-selected="false">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=config" role="tab" aria-selected="false">
|
||||||
<i class="fas fa-cogs"></i>Config</a>
|
<i class="fas fa-cogs"></i>Config</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item term-nav-item">
|
<li class="nav-item term-nav-item">
|
||||||
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=admin_controls" role="tab" aria-selected="true">
|
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=admin_controls" role="tab" aria-selected="true">
|
||||||
<i class="fas fa-users"></i>Player Controls</a>
|
<i class="fas fa-users"></i>Player Controls</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item term-nav-item">
|
<li class="nav-item term-nav-item">
|
||||||
@ -128,7 +128,7 @@
|
|||||||
|
|
||||||
// Convert running to lower case (example: 'True' converts to 'true') and
|
// Convert running to lower case (example: 'True' converts to 'true') and
|
||||||
// then to boolean via JSON.parse()
|
// then to boolean via JSON.parse()
|
||||||
let online = JSON.parse('{{ data['server_stats'][0]['running'] }}'.toLowerCase());
|
let online = JSON.parse('{{ data['server_stats']['running'] }}'.toLowerCase());
|
||||||
|
|
||||||
let startBtn = document.querySelector('#start-btn');
|
let startBtn = document.querySelector('#start-btn');
|
||||||
let restartBtn = document.querySelector('#restart-btn');
|
let restartBtn = document.querySelector('#restart-btn');
|
||||||
@ -144,13 +144,13 @@
|
|||||||
stopBtn.setAttribute('disabled', 'disabled');
|
stopBtn.setAttribute('disabled', 'disabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
let server_id = '{{ data['server_stats'][0]['server_id']['server_id'] }}';
|
let server_id = '{{ data['server_stats']['server_id']['server_id'] }}';
|
||||||
|
|
||||||
function get_server_log(){
|
function get_server_log(){
|
||||||
if( !$("#stop_scroll").is(':checked')){
|
if( !$("#stop_scroll").is(':checked')){
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
url: '/ajax/server_log?id={{ data['server_stats'][0]['server_id']['server_id'] }}',
|
url: '/ajax/server_log?id={{ data['server_stats']['server_id']['server_id'] }}',
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
console.log('Got Log From Server')
|
console.log('Got Log From Server')
|
||||||
@ -216,7 +216,7 @@
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
headers: {'X-XSRFToken': token},
|
headers: {'X-XSRFToken': token},
|
||||||
url: '/ajax/send_command?id={{ data['server_stats'][0]['server_id']['server_id'] }}',
|
url: '/ajax/send_command?id={{ data['server_stats']['server_id']['server_id'] }}',
|
||||||
data: data_to_send,
|
data: data_to_send,
|
||||||
success: function(data){
|
success: function(data){
|
||||||
console.log("got response:");
|
console.log("got response:");
|
||||||
|
37
main.py
37
main.py
@ -10,8 +10,9 @@ from app.classes.shared.console import console
|
|||||||
from app.classes.shared.helpers import helper
|
from app.classes.shared.helpers import helper
|
||||||
from app.classes.shared.models import installer
|
from app.classes.shared.models import installer
|
||||||
|
|
||||||
from app.classes.shared.controller import controller
|
|
||||||
from app.classes.shared.tasks import TasksManager
|
from app.classes.shared.tasks import TasksManager
|
||||||
|
from app.classes.shared.controller import Controller
|
||||||
|
|
||||||
from app.classes.shared.cmd import MainPrompt
|
from app.classes.shared.cmd import MainPrompt
|
||||||
|
|
||||||
|
|
||||||
@ -56,7 +57,6 @@ def setup_logging(debug=True):
|
|||||||
|
|
||||||
""" Our Main Starter """
|
""" Our Main Starter """
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
parser = argparse.ArgumentParser("Crafty Controller - A Server Management System")
|
parser = argparse.ArgumentParser("Crafty Controller - A Server Management System")
|
||||||
|
|
||||||
parser.add_argument('-i', '--ignore',
|
parser.add_argument('-i', '--ignore',
|
||||||
@ -94,9 +94,14 @@ if __name__ == '__main__':
|
|||||||
fresh_install = installer.is_fresh_install()
|
fresh_install = installer.is_fresh_install()
|
||||||
|
|
||||||
if fresh_install:
|
if fresh_install:
|
||||||
|
console.debug("Fresh install detected")
|
||||||
installer.create_tables()
|
installer.create_tables()
|
||||||
installer.default_settings()
|
installer.default_settings()
|
||||||
|
else:
|
||||||
|
console.debug("Existing install detected")
|
||||||
|
installer.check_schema_version()
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
# init servers
|
# init servers
|
||||||
logger.info("Initializing all servers defined")
|
logger.info("Initializing all servers defined")
|
||||||
console.info("Initializing all servers defined")
|
console.info("Initializing all servers defined")
|
||||||
@ -107,15 +112,31 @@ if __name__ == '__main__':
|
|||||||
# now the tables are created, we can load the tasks_manger
|
# now the tables are created, we can load the tasks_manger
|
||||||
tasks_manager = TasksManager()
|
tasks_manager = TasksManager()
|
||||||
|
|
||||||
|
=======
|
||||||
|
# now the tables are created, we can load the tasks_manger and server controller
|
||||||
|
controller = Controller()
|
||||||
|
tasks_manager = TasksManager(controller)
|
||||||
|
>>>>>>> backups-and-stuff
|
||||||
tasks_manager.start_webserver()
|
tasks_manager.start_webserver()
|
||||||
tasks_manager.start_scheduler()
|
|
||||||
|
|
||||||
# slowing down reporting just for a 1/2 second so messages look cleaner
|
# slowing down reporting just for a 1/2 second so messages look cleaner
|
||||||
time.sleep(.5)
|
time.sleep(.5)
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
# init servers
|
||||||
|
logger.info("Initializing all servers defined")
|
||||||
|
console.info("Initializing all servers defined")
|
||||||
|
controller.init_all_servers()
|
||||||
|
servers = controller.list_defined_servers()
|
||||||
|
|
||||||
|
>>>>>>> backups-and-stuff
|
||||||
# start stats logging
|
# start stats logging
|
||||||
tasks_manager.start_stats_recording()
|
tasks_manager.start_stats_recording()
|
||||||
|
|
||||||
|
# once the controller is up and stats are logging, we can kick off the scheduler officially
|
||||||
|
tasks_manager.start_scheduler()
|
||||||
|
|
||||||
# refresh our cache and schedule for every 12 hoursour cache refresh for serverjars.com
|
# refresh our cache and schedule for every 12 hoursour cache refresh for serverjars.com
|
||||||
tasks_manager.serverjar_cache_refresher()
|
tasks_manager.serverjar_cache_refresher()
|
||||||
|
|
||||||
@ -123,6 +144,7 @@ if __name__ == '__main__':
|
|||||||
tasks_manager.start_main_kill_switch_watcher()
|
tasks_manager.start_main_kill_switch_watcher()
|
||||||
|
|
||||||
Crafty = MainPrompt(tasks_manager)
|
Crafty = MainPrompt(tasks_manager)
|
||||||
|
<<<<<<< HEAD
|
||||||
if not args.daemon:
|
if not args.daemon:
|
||||||
Crafty.cmdloop()
|
Crafty.cmdloop()
|
||||||
else:
|
else:
|
||||||
@ -143,3 +165,12 @@ if __name__ == '__main__':
|
|||||||
if tasks_manager.get_main_thread_run_status():
|
if tasks_manager.get_main_thread_run_status():
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
=======
|
||||||
|
Crafty.cmdloop()
|
||||||
|
|
||||||
|
# our main loop - eventually a shell
|
||||||
|
# while True:
|
||||||
|
# if tasks_manager.get_main_thread_run_status():
|
||||||
|
# sys.exit(0)
|
||||||
|
# time.sleep(1)
|
||||||
|
>>>>>>> backups-and-stuff
|
||||||
|
Loading…
Reference in New Issue
Block a user