mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'pretzel-fixes' into 'dev'
Bedrock support/chain reaction tasks / server re-ordering See merge request crafty-controller/crafty-commander!166
This commit is contained in:
commit
2265adbf82
20
Dockerfile
20
Dockerfile
@ -1,23 +1,17 @@
|
||||
FROM python:alpine
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV DEBIAN_FRONTEND="noninteractive"
|
||||
|
||||
LABEL maintainer="Dockerfile created by Zedifus <https://gitlab.com/zedifus>"
|
||||
|
||||
# Security Patch for CVE-2021-44228
|
||||
ENV LOG4J_FORMAT_MSG_NO_LOOKUPS=true
|
||||
|
||||
# Install Packages, Build Dependencies & Garbage Collect & Harden
|
||||
# (Alpine Edge repo is needed because jre16 is new)
|
||||
# Install Packages And Dependencies
|
||||
COPY requirements.txt /commander/requirements.txt
|
||||
RUN apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/latest-stable/community \
|
||||
gcc musl-dev libffi-dev make rust cargo openssl-dev llvm11-libs \
|
||||
openjdk8-jre-base openjdk11-jre-headless openjdk16-jre-headless openjdk17-jre-headless mariadb-dev \
|
||||
&& pip3 install --no-cache-dir -r /commander/requirements.txt \
|
||||
&& apk del --no-cache gcc musl-dev libffi-dev make rust cargo openssl-dev llvm11-libs \
|
||||
&& rm -rf /sbin/apk \
|
||||
&& rm -rf /etc/apk \
|
||||
&& rm -rf /lib/apk \
|
||||
&& rm -rf /usr/share/apk \
|
||||
&& rm -rf /var/lib/apk
|
||||
RUN apt update \
|
||||
&& apt install -y gcc python3 python3-pip libmariadb-dev openjdk-8-jre-headless openjdk-11-jre-headless openjdk-16-jre-headless openjdk-17-jre-headless default-jre \
|
||||
&& pip3 install --no-cache-dir -r /commander/requirements.txt
|
||||
|
||||
# Copy Source & copy default config from image
|
||||
COPY ./ /commander
|
||||
|
@ -80,6 +80,10 @@ class Management_Controller:
|
||||
def get_scheduled_task_model(schedule_id):
|
||||
return management_helper.get_scheduled_task_model(schedule_id)
|
||||
|
||||
@staticmethod
|
||||
def get_child_schedules(sch_id):
|
||||
return management_helper.get_child_schedules(sch_id)
|
||||
|
||||
@staticmethod
|
||||
def get_schedules_by_server(server_id):
|
||||
return management_helper.get_schedules_by_server(server_id)
|
||||
|
@ -28,6 +28,7 @@ class Servers_Controller:
|
||||
server_file: str,
|
||||
server_log_file: str,
|
||||
server_stop: str,
|
||||
server_type: str,
|
||||
server_port=25565):
|
||||
return servers_helper.create_server(
|
||||
name,
|
||||
@ -38,6 +39,7 @@ class Servers_Controller:
|
||||
server_file,
|
||||
server_log_file,
|
||||
server_stop,
|
||||
server_type,
|
||||
server_port)
|
||||
|
||||
@staticmethod
|
||||
@ -137,6 +139,10 @@ class Servers_Controller:
|
||||
def server_id_exists(server_id):
|
||||
return servers_helper.server_id_exists(server_id)
|
||||
|
||||
@staticmethod
|
||||
def get_server_type_by_id(server_id):
|
||||
return servers_helper.get_server_type_by_id(server_id)
|
||||
|
||||
@staticmethod
|
||||
def server_id_authorized(server_id_a, user_id):
|
||||
user_roles = users_helper.user_role_query(user_id)
|
||||
|
@ -30,6 +30,14 @@ class Users_Controller:
|
||||
def get_user_by_id(user_id):
|
||||
return users_helper.get_user(user_id)
|
||||
|
||||
@staticmethod
|
||||
def update_server_order(user_id, user_server_order):
|
||||
users_helper.update_server_order(user_id, user_server_order)
|
||||
|
||||
@staticmethod
|
||||
def get_server_order(user_id):
|
||||
return users_helper.get_server_order(user_id)
|
||||
|
||||
@staticmethod
|
||||
def user_query(user_id):
|
||||
return users_helper.user_query(user_id)
|
||||
|
@ -165,3 +165,66 @@ def ping(ip, port):
|
||||
return Server(json.loads(data))
|
||||
finally:
|
||||
sock.close()
|
||||
|
||||
# For the rest of requests see wiki.vg/Protocol
|
||||
def ping_bedrock(ip, port):
|
||||
def read_var_int():
|
||||
i = 0
|
||||
j = 0
|
||||
while True:
|
||||
try:
|
||||
k = sock.recvfrom(1024)
|
||||
except:
|
||||
return False
|
||||
if not k:
|
||||
return 0
|
||||
k = k[0]
|
||||
i |= (k & 0x7f) << (j * 7)
|
||||
j += 1
|
||||
if j > 5:
|
||||
raise ValueError('var_int too big')
|
||||
if not k & 0x80:
|
||||
return i
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.settimeout(2)
|
||||
try:
|
||||
sock.connect((ip, port))
|
||||
|
||||
except:
|
||||
print("in first except")
|
||||
return False
|
||||
|
||||
try:
|
||||
host = ip.encode('utf-8')
|
||||
data = b'' # wiki.vg/Server_List_Ping
|
||||
data += b'\x00' # packet ID
|
||||
data += b'\x04' # protocol variant
|
||||
data += struct.pack('>b', len(host)) + host
|
||||
data += struct.pack('>H', port)
|
||||
data += b'\x01' # next state
|
||||
data = struct.pack('>b', len(data)) + data
|
||||
sock.sendall(data + b'\x01\x00') # handshake + status ping
|
||||
length = read_var_int() # full packet length
|
||||
if length < 10:
|
||||
if length < 0:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
try:
|
||||
sock.recvfrom(1024) # packet type, 0 for pings
|
||||
except:
|
||||
return False
|
||||
length = read_var_int() # string length
|
||||
data = b''
|
||||
while len(data) != length:
|
||||
print("in while")
|
||||
chunk = sock.recv(length - len(data))
|
||||
if not chunk:
|
||||
return False
|
||||
|
||||
data += chunk
|
||||
logger.debug(f"Server reports this data on ping: {data}")
|
||||
return Server(json.loads(data))
|
||||
finally:
|
||||
sock.close()
|
||||
|
@ -9,7 +9,7 @@ from app.classes.models.management import Host_Stats
|
||||
from app.classes.models.servers import Server_Stats, servers_helper
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.minecraft.mc_ping import ping
|
||||
from app.classes.minecraft.mc_ping import ping, ping_bedrock
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -177,7 +177,10 @@ class Stats:
|
||||
server_port = server['server_port']
|
||||
|
||||
logger.debug("Pinging {internal_ip} on port {server_port}")
|
||||
int_mc_ping = ping(internal_ip, int(server_port))
|
||||
if servers_helper.get_server_type_by_id(server_id) == 'minecraft-bedrock':
|
||||
int_mc_ping = ping_bedrock(internal_ip, int(server_port))
|
||||
else:
|
||||
int_mc_ping = ping(internal_ip, int(server_port))
|
||||
|
||||
ping_data = {}
|
||||
|
||||
@ -223,7 +226,10 @@ class Stats:
|
||||
server = s.get('server_name', f"ID#{server_id}")
|
||||
|
||||
logger.debug("Pinging server '{server}' on {internal_ip}:{server_port}")
|
||||
int_mc_ping = ping(internal_ip, int(server_port))
|
||||
if servers_helper.get_server_type_by_id(server_id) == 'minecraft-bedrock':
|
||||
int_mc_ping = ping_bedrock(internal_ip, int(server_port))
|
||||
else:
|
||||
int_mc_ping = ping(internal_ip, int(server_port))
|
||||
|
||||
int_data = False
|
||||
ping_data = {}
|
||||
@ -286,7 +292,10 @@ class Stats:
|
||||
|
||||
|
||||
logger.debug(f"Pinging server '{server.name}' on {internal_ip}:{server_port}")
|
||||
int_mc_ping = ping(internal_ip, int(server_port))
|
||||
if servers_helper.get_server_type_by_id(server_id) == 'minecraft-bedrock':
|
||||
int_mc_ping = ping_bedrock(internal_ip, int(server_port))
|
||||
else:
|
||||
int_mc_ping = ping(internal_ip, int(server_port))
|
||||
|
||||
int_data = False
|
||||
ping_data = {}
|
||||
|
@ -113,6 +113,8 @@ class Schedules(Model):
|
||||
comment = CharField()
|
||||
one_time = BooleanField(default=False)
|
||||
cron_string = CharField(default="")
|
||||
parent = IntegerField(null=True)
|
||||
delay = IntegerField(default=0)
|
||||
|
||||
class Meta:
|
||||
table_name = 'schedules'
|
||||
@ -191,11 +193,14 @@ class helpers_management:
|
||||
Audit_Log.log_msg: audit_msg,
|
||||
Audit_Log.source_ip: source_ip
|
||||
}).execute()
|
||||
#todo make this user configurable
|
||||
#deletes records when they're more than 100
|
||||
ordered = Audit_Log.select().order_by(+Audit_Log.created)
|
||||
for item in ordered:
|
||||
if Audit_Log.select().count() > 300:
|
||||
if not helper.get_setting('max_audit_entries'):
|
||||
max_entries = 300
|
||||
else:
|
||||
max_entries = helper.get_setting('max_audit_entries')
|
||||
if Audit_Log.select().count() > max_entries:
|
||||
Audit_Log.delete().where(Audit_Log.audit_id == item.audit_id).execute()
|
||||
else:
|
||||
return
|
||||
@ -212,7 +217,12 @@ class helpers_management:
|
||||
#deletes records when they're more than 100
|
||||
ordered = Audit_Log.select().order_by(+Audit_Log.created)
|
||||
for item in ordered:
|
||||
if Audit_Log.select().count() > 300:
|
||||
#configurable through app/config/config.json
|
||||
if not helper.get_setting('max_audit_entries'):
|
||||
max_entries = 300
|
||||
else:
|
||||
max_entries = helper.get_setting('max_audit_entries')
|
||||
if Audit_Log.select().count() > max_entries:
|
||||
Audit_Log.delete().where(Audit_Log.audit_id == item.audit_id).execute()
|
||||
else:
|
||||
return
|
||||
@ -230,7 +240,9 @@ class helpers_management:
|
||||
comment=None,
|
||||
enabled=True,
|
||||
one_time=False,
|
||||
cron_string='* * * * *'):
|
||||
cron_string='* * * * *',
|
||||
parent=None,
|
||||
delay=0):
|
||||
sch_id = Schedules.insert({
|
||||
Schedules.server_id: server_id,
|
||||
Schedules.action: action,
|
||||
@ -241,7 +253,9 @@ class helpers_management:
|
||||
Schedules.command: command,
|
||||
Schedules.comment: comment,
|
||||
Schedules.one_time: one_time,
|
||||
Schedules.cron_string: cron_string
|
||||
Schedules.cron_string: cron_string,
|
||||
Schedules.parent: parent,
|
||||
Schedules.delay: delay
|
||||
|
||||
}).execute()
|
||||
return sch_id
|
||||
@ -271,6 +285,14 @@ class helpers_management:
|
||||
def get_schedules_by_server(server_id):
|
||||
return Schedules.select().where(Schedules.server_id == server_id).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_child_schedules_by_server(schedule_id, server_id):
|
||||
return Schedules.select().where(Schedules.server_id == server_id, Schedules.parent == schedule_id).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_child_schedules(schedule_id):
|
||||
return Schedules.select().where(Schedules.parent == schedule_id)
|
||||
|
||||
@staticmethod
|
||||
def get_schedules_all():
|
||||
return Schedules.select().execute()
|
||||
|
@ -173,7 +173,10 @@ class Permissions_Servers:
|
||||
else:
|
||||
roles_list = users_helper.get_user_roles_id(user.user_id)
|
||||
role_server = Role_Servers.select().where(Role_Servers.role_id.in_(roles_list)).where(Role_Servers.server_id == server_id).execute()
|
||||
permissions_mask = role_server[0].permissions
|
||||
try:
|
||||
permissions_mask = role_server[0].permissions
|
||||
except IndexError:
|
||||
permissions_mask = '0' * len(server_permissions.get_permissions_list())
|
||||
return permissions_mask
|
||||
|
||||
@staticmethod
|
||||
|
@ -43,6 +43,7 @@ class Servers(Model):
|
||||
server_ip = CharField(default="127.0.0.1")
|
||||
server_port = IntegerField(default=25565)
|
||||
logs_delete_after = IntegerField(default=0)
|
||||
type = CharField(default="minecraft-java")
|
||||
|
||||
class Meta:
|
||||
table_name = "servers"
|
||||
@ -99,6 +100,7 @@ class helper_servers:
|
||||
server_file: str,
|
||||
server_log_file: str,
|
||||
server_stop: str,
|
||||
server_type: str,
|
||||
server_port=25565):
|
||||
return Servers.insert({
|
||||
Servers.server_name: name,
|
||||
@ -112,7 +114,8 @@ class helper_servers:
|
||||
Servers.log_path: server_log_file,
|
||||
Servers.server_port: server_port,
|
||||
Servers.stop_command: server_stop,
|
||||
Servers.backup_path: backup_path
|
||||
Servers.backup_path: backup_path,
|
||||
Servers.type: server_type
|
||||
}).execute()
|
||||
|
||||
|
||||
@ -120,6 +123,11 @@ class helper_servers:
|
||||
def get_server_obj(server_id):
|
||||
return Servers.get_by_id(server_id)
|
||||
|
||||
@staticmethod
|
||||
def get_server_type_by_id(server_id):
|
||||
server_type = Servers.select().where(Servers.server_id == server_id).get()
|
||||
return server_type.type
|
||||
|
||||
@staticmethod
|
||||
def update_server(server_obj):
|
||||
return server_obj.save()
|
||||
|
@ -42,6 +42,7 @@ class Users(Model):
|
||||
lang = CharField(default="en_EN")
|
||||
support_logs = CharField(default = '')
|
||||
valid_tokens_from = DateTimeField(default=datetime.datetime.now)
|
||||
server_order = CharField(default="")
|
||||
|
||||
class Meta:
|
||||
table_name = "users"
|
||||
@ -173,6 +174,14 @@ class helper_users:
|
||||
if up_data:
|
||||
Users.update(up_data).where(Users.user_id == user_id).execute()
|
||||
|
||||
@staticmethod
|
||||
def update_server_order(user_id, user_server_order):
|
||||
Users.update(server_order = user_server_order).where(Users.user_id == user_id).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_server_order(user_id):
|
||||
return Users.select().where(Users.user_id == user_id)
|
||||
|
||||
@staticmethod
|
||||
def get_super_user_list():
|
||||
final_users = []
|
||||
|
@ -295,7 +295,8 @@ class Controller:
|
||||
# download the jar
|
||||
server_jar_obj.download_jar(server, version, full_jar_path)
|
||||
|
||||
new_id = self.register_server(name, server_id, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, port)
|
||||
new_id = self.register_server(name, server_id, server_dir, backup_path, server_command, server_file, server_log_file, server_stop,
|
||||
port, server_type='minecraft-java')
|
||||
return new_id
|
||||
|
||||
@staticmethod
|
||||
@ -351,7 +352,7 @@ class Controller:
|
||||
server_stop = "stop"
|
||||
|
||||
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, server_type='minecraft-java')
|
||||
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):
|
||||
@ -394,9 +395,102 @@ class Controller:
|
||||
server_stop = "stop"
|
||||
|
||||
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, server_type='minecraft-java')
|
||||
return new_id
|
||||
|
||||
#************************************************************************************************
|
||||
# BEDROCK IMPORTS
|
||||
#************************************************************************************************
|
||||
|
||||
def import_bedrock_server(self, server_name: str, server_path: str, server_exe: str, port: int):
|
||||
server_id = helper.create_uuid()
|
||||
new_server_dir = os.path.join(helper.servers_dir, server_id)
|
||||
backup_path = os.path.join(helper.backup_path, server_id)
|
||||
if helper.is_os_windows():
|
||||
new_server_dir = helper.wtol_path(new_server_dir)
|
||||
backup_path = helper.wtol_path(backup_path)
|
||||
new_server_dir.replace(' ', '^ ')
|
||||
backup_path.replace(' ', '^ ')
|
||||
|
||||
helper.ensure_dir_exists(new_server_dir)
|
||||
helper.ensure_dir_exists(backup_path)
|
||||
server_path = helper.get_os_understandable_path(server_path)
|
||||
dir_util.copy_tree(server_path, new_server_dir)
|
||||
|
||||
has_properties = False
|
||||
for item in os.listdir(new_server_dir):
|
||||
if str(item) == 'server.properties':
|
||||
has_properties = True
|
||||
if not has_properties:
|
||||
logger.info(f"No server.properties found on zip file import. Creating one with port selection of {str(port)}")
|
||||
with open(os.path.join(new_server_dir, "server.properties"), "w", encoding='utf-8') as f:
|
||||
f.write(f"server-port={port}")
|
||||
f.close()
|
||||
|
||||
full_jar_path = os.path.join(new_server_dir, server_exe)
|
||||
|
||||
#due to adding strings this must not be an fstring
|
||||
if helper.is_os_windows():
|
||||
server_command = f'"{full_jar_path}"'
|
||||
else:
|
||||
server_command = f'./{server_exe}'
|
||||
logger.debug('command: ' + server_command)
|
||||
server_log_file = "N/A"
|
||||
server_stop = "stop"
|
||||
|
||||
new_id = self.register_server(server_name, server_id, new_server_dir, backup_path, server_command, server_exe,
|
||||
server_log_file, server_stop, port, server_type='minecraft-bedrock')
|
||||
os.chmod(full_jar_path, 2775)
|
||||
return new_id
|
||||
|
||||
def import_bedrock_zip_server(self, server_name: str, zip_path: str, server_exe: str, port: int):
|
||||
server_id = helper.create_uuid()
|
||||
new_server_dir = os.path.join(helper.servers_dir, server_id)
|
||||
backup_path = os.path.join(helper.backup_path, server_id)
|
||||
if helper.is_os_windows():
|
||||
new_server_dir = helper.wtol_path(new_server_dir)
|
||||
backup_path = helper.wtol_path(backup_path)
|
||||
new_server_dir.replace(' ', '^ ')
|
||||
backup_path.replace(' ', '^ ')
|
||||
|
||||
tempDir = helper.get_os_understandable_path(zip_path)
|
||||
helper.ensure_dir_exists(new_server_dir)
|
||||
helper.ensure_dir_exists(backup_path)
|
||||
has_properties = False
|
||||
#extracts archive to temp directory
|
||||
for item in os.listdir(tempDir):
|
||||
if str(item) == 'server.properties':
|
||||
has_properties = True
|
||||
try:
|
||||
shutil.move(os.path.join(tempDir, item), os.path.join(new_server_dir, item))
|
||||
except Exception as ex:
|
||||
logger.error(f'ERROR IN ZIP IMPORT: {ex}')
|
||||
if not has_properties:
|
||||
logger.info(f"No server.properties found on zip file import. Creating one with port selection of {str(port)}")
|
||||
with open(os.path.join(new_server_dir, "server.properties"), "w", encoding='utf-8') as f:
|
||||
f.write(f"server-port={port}")
|
||||
f.close()
|
||||
|
||||
full_jar_path = os.path.join(new_server_dir, server_exe)
|
||||
|
||||
#due to strings being added we need to leave this as not an fstring
|
||||
if helper.is_os_windows():
|
||||
server_command = f'"{full_jar_path}"'
|
||||
else:
|
||||
server_command = f'./{server_exe}'
|
||||
logger.debug('command: ' + server_command)
|
||||
server_log_file = "N/A"
|
||||
server_stop = "stop"
|
||||
|
||||
new_id = self.register_server(server_name, server_id, new_server_dir, backup_path, server_command, server_exe,
|
||||
server_log_file, server_stop, port, server_type='minecraft-bedrock')
|
||||
os.chmod(full_jar_path, 2775)
|
||||
return new_id
|
||||
|
||||
#************************************************************************************************
|
||||
# BEDROCK IMPORTS END
|
||||
#************************************************************************************************
|
||||
|
||||
def rename_backup_dir(self, old_server_id, new_server_id, new_uuid):
|
||||
server_data = self.servers.get_server_data_by_id(old_server_id)
|
||||
old_bu_path = server_data['backup_path']
|
||||
@ -421,11 +515,12 @@ class Controller:
|
||||
server_file: str,
|
||||
server_log_file: str,
|
||||
server_stop: str,
|
||||
server_port: int):
|
||||
server_port: int,
|
||||
server_type: str):
|
||||
# put data in the db
|
||||
|
||||
new_id = self.servers.create_server(
|
||||
name, server_uuid, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, server_port)
|
||||
name, server_uuid, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, server_type, server_port)
|
||||
|
||||
if not helper.check_file_exists(os.path.join(server_dir, "crafty_managed.txt")):
|
||||
try:
|
||||
|
@ -201,8 +201,8 @@ class Server:
|
||||
logger.info(f"Launching Server {self.name} with command {self.server_command}")
|
||||
console.info(f"Launching Server {self.name} with command {self.server_command}")
|
||||
|
||||
#Checks for eula. Creates one if none detected.
|
||||
#If EULA is detected and not set to one of these true vaiants we offer to set it true.
|
||||
#Checks for eula. Creates one if none detected.
|
||||
#If EULA is detected and not set to one of these true vaiants we offer to set it true.
|
||||
if helper.check_file_exists(os.path.join(self.settings['path'], 'eula.txt')):
|
||||
f = open(os.path.join(self.settings['path'], 'eula.txt'), 'r', encoding='utf-8')
|
||||
line = f.readline().lower()
|
||||
@ -240,24 +240,40 @@ class Server:
|
||||
|
||||
logger.info(f"Starting server in {self.server_path} with command: {self.server_command}")
|
||||
|
||||
try:
|
||||
self.process = subprocess.Popen(
|
||||
self.server_command, cwd=self.server_path, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
except Exception as ex:
|
||||
#Checks for java on initial fail
|
||||
if os.system("java -version") == 32512:
|
||||
if not helper.is_os_windows() and servers_helper.get_server_type_by_id(self.server_id) == "minecraft-bedrock":
|
||||
logger.info(f"Bedrock and Unix detected for server {self.name}. Switching to appropriate execution string")
|
||||
my_env = os.environ
|
||||
my_env["LD_LIBRARY_PATH"] = self.server_path
|
||||
try:
|
||||
self.process = subprocess.Popen(
|
||||
self.server_command, cwd=self.server_path, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=my_env)
|
||||
except Exception as ex:
|
||||
logger.error(f"Server {self.name} failed to start with error code: {ex}")
|
||||
if user_id:
|
||||
websocket_helper.broadcast_user(user_id, 'send_start_error',{
|
||||
'error': translation.translate('error', 'noJava', user_lang).format(self.name)
|
||||
})
|
||||
'error': translation.translate('error', 'start-error', user_lang).format(self.name, ex)
|
||||
})
|
||||
return False
|
||||
|
||||
else:
|
||||
try:
|
||||
self.process = subprocess.Popen(
|
||||
self.server_command, cwd=self.server_path, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
except Exception as ex:
|
||||
#Checks for java on initial fail
|
||||
if os.system("java -version") == 32512:
|
||||
if user_id:
|
||||
websocket_helper.broadcast_user(user_id, 'send_start_error',{
|
||||
'error': translation.translate('error', 'noJava', user_lang).format(self.name)
|
||||
})
|
||||
return False
|
||||
else:
|
||||
logger.error(f"Server {self.name} failed to start with error code: {ex}")
|
||||
if user_id:
|
||||
websocket_helper.broadcast_user(user_id, 'send_start_error',{
|
||||
'error': translation.translate('error', 'start-error', user_lang).format(self.name, ex)
|
||||
})
|
||||
return False
|
||||
else:
|
||||
logger.error(f"Server {self.name} failed to start with error code: {ex}")
|
||||
if user_id:
|
||||
websocket_helper.broadcast_user(user_id, 'send_start_error',{
|
||||
'error': translation.translate('error', 'start-error', user_lang).format(self.name, ex)
|
||||
})
|
||||
return False
|
||||
|
||||
out_buf = ServerOutBuf(self.process, self.server_id)
|
||||
|
||||
@ -359,6 +375,7 @@ class Server:
|
||||
server_name = self.name
|
||||
server_pid = self.process.pid
|
||||
|
||||
|
||||
while running:
|
||||
x = x+1
|
||||
logstr = f"Server {server_name} is still running - waiting 2s to see if it stops ({int(60-(x*2))} seconds until force close)"
|
||||
@ -426,7 +443,6 @@ class Server:
|
||||
|
||||
def crash_detected(self, name):
|
||||
|
||||
print("crash detected")
|
||||
# clear the old scheduled watcher task
|
||||
self.server_scheduler.remove_job(f"c_{self.server_id}")
|
||||
|
||||
@ -477,6 +493,13 @@ class Server:
|
||||
# if all is okay, we just exit out
|
||||
if running:
|
||||
return
|
||||
#check the exit code -- This could be a fix for /stop
|
||||
if self.process.returncode == 0:
|
||||
logger.warning(f'Process {self.process.pid} exited with code {self.process.returncode}. This is considered a clean exit'+
|
||||
' supressing crash handling.')
|
||||
# cancel the watcher task
|
||||
self.server_scheduler.remove_job("c_"+str(self.server_id))
|
||||
return
|
||||
|
||||
servers_helper.sever_crashed(self.server_id)
|
||||
# if we haven't tried to restart more 3 or more times
|
||||
|
@ -4,6 +4,7 @@ import time
|
||||
import logging
|
||||
import threading
|
||||
import asyncio
|
||||
import datetime
|
||||
from tzlocal import get_localzone
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
@ -117,7 +118,6 @@ class TasksManager:
|
||||
def _main_graceful_exit(self):
|
||||
try:
|
||||
os.remove(helper.session_file)
|
||||
os.remove(os.path.join(helper.root_dir, '.header'))
|
||||
self.controller.stop_all_servers()
|
||||
except:
|
||||
logger.info("Caught error during shutdown", exc_info=True)
|
||||
@ -160,59 +160,60 @@ class TasksManager:
|
||||
|
||||
#load schedules from DB
|
||||
for schedule in schedules:
|
||||
if schedule.cron_string != "":
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
CronTrigger.from_crontab(schedule.cron_string,
|
||||
timezone=str(self.tz)),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
except Exception as e:
|
||||
console.error(f"Failed to schedule task with error: {e}.")
|
||||
console.warning("Removing failed task from DB.")
|
||||
logger.error(f"Failed to schedule task with error: {e}.")
|
||||
logger.warning("Removing failed task from DB.")
|
||||
#remove items from DB if task fails to add to apscheduler
|
||||
management_helper.delete_scheduled_task(schedule.schedule_id)
|
||||
else:
|
||||
if schedule.interval_type == 'hours':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = 0,
|
||||
hour = '*/'+str(schedule.interval),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
elif schedule.interval_type == 'minutes':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = '*/'+str(schedule.interval),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
elif schedule.interval_type == 'days':
|
||||
curr_time = schedule.start_time.split(':')
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
day = '*/'+str(schedule.interval),
|
||||
hour=curr_time[0],
|
||||
minute=curr_time[1],
|
||||
id=str(schedule.schedule_id),
|
||||
args=[schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
if schedule.interval != 'reaction':
|
||||
if schedule.cron_string != "":
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
CronTrigger.from_crontab(schedule.cron_string,
|
||||
timezone=str(self.tz)),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
except Exception as e:
|
||||
console.error(f"Failed to schedule task with error: {e}.")
|
||||
console.warning("Removing failed task from DB.")
|
||||
logger.error(f"Failed to schedule task with error: {e}.")
|
||||
logger.warning("Removing failed task from DB.")
|
||||
#remove items from DB if task fails to add to apscheduler
|
||||
management_helper.delete_scheduled_task(schedule.schedule_id)
|
||||
else:
|
||||
if schedule.interval_type == 'hours':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = 0,
|
||||
hour = '*/'+str(schedule.interval),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
elif schedule.interval_type == 'minutes':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = '*/'+str(schedule.interval),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
elif schedule.interval_type == 'days':
|
||||
curr_time = schedule.start_time.split(':')
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
day = '*/'+str(schedule.interval),
|
||||
hour=curr_time[0],
|
||||
minute=curr_time[1],
|
||||
id=str(schedule.schedule_id),
|
||||
args=[schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
self.scheduler.start()
|
||||
jobs = self.scheduler.get_jobs()
|
||||
logger.info("Loaded schedules. Current enabled schedules: ")
|
||||
@ -230,8 +231,14 @@ class TasksManager:
|
||||
"None",
|
||||
job_data['enabled'],
|
||||
job_data['one_time'],
|
||||
job_data['cron_string'])
|
||||
if job_data['enabled']:
|
||||
job_data['cron_string'],
|
||||
job_data['parent'],
|
||||
job_data['delay'])
|
||||
#Checks to make sure some doofus didn't actually make the newly created task a child of itself.
|
||||
if str(job_data['parent']) == str(sch_id):
|
||||
management_helper.update_scheduled_task(sch_id, {'parent':None})
|
||||
#Check to see if it's enabled and is not a chain reaction.
|
||||
if job_data['enabled'] and job_data['interval_type'] != 'reaction':
|
||||
if job_data['cron_string'] != "":
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
@ -293,12 +300,15 @@ class TasksManager:
|
||||
def remove_all_server_tasks(self, server_id):
|
||||
schedules = management_helper.get_schedules_by_server(server_id)
|
||||
for schedule in schedules:
|
||||
self.remove_job(schedule.schedule_id)
|
||||
if schedule.interval != 'reaction':
|
||||
self.remove_job(schedule.schedule_id)
|
||||
|
||||
def remove_job(self, sch_id):
|
||||
job = management_helper.get_scheduled_task_model(sch_id)
|
||||
for schedule in management_helper.get_child_schedules(sch_id):
|
||||
management_helper.update_scheduled_task(schedule.schedule_id, {'parent':None})
|
||||
management_helper.delete_scheduled_task(sch_id)
|
||||
if job.enabled:
|
||||
if job.enabled and job.interval_type != 'reaction':
|
||||
self.scheduler.remove_job(str(sch_id))
|
||||
logger.info(f"Job with ID {sch_id} was deleted.")
|
||||
else:
|
||||
@ -307,62 +317,67 @@ class TasksManager:
|
||||
|
||||
def update_job(self, sch_id, job_data):
|
||||
management_helper.update_scheduled_task(sch_id, job_data)
|
||||
#Checks to make sure some doofus didn't actually make the newly created task a child of itself.
|
||||
if str(job_data['parent']) == str(sch_id):
|
||||
management_helper.update_scheduled_task(sch_id, {'parent':None})
|
||||
try:
|
||||
self.scheduler.remove_job(str(sch_id))
|
||||
if job_data['interval'] != 'reaction':
|
||||
self.scheduler.remove_job(str(sch_id))
|
||||
except:
|
||||
logger.info("No job found in update job. Assuming it was previously disabled. Starting new job.")
|
||||
|
||||
if job_data['enabled']:
|
||||
if job_data['cron_string'] != "":
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
CronTrigger.from_crontab(job_data['cron_string'],
|
||||
timezone=str(self.tz)),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
except Exception as e:
|
||||
console.error(f"Failed to schedule task with error: {e}.")
|
||||
console.info("Removing failed task from DB.")
|
||||
management_helper.delete_scheduled_task(sch_id)
|
||||
else:
|
||||
if job_data['interval_type'] == 'hours':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = 0,
|
||||
hour = '*/'+str(job_data['interval']),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
elif job_data['interval_type'] == 'minutes':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = '*/'+str(job_data['interval']),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
elif job_data['interval_type'] == 'days':
|
||||
curr_time = job_data['start_time'].split(':')
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
day = '*/'+str(job_data['interval']),
|
||||
hour = curr_time[0],
|
||||
minute = curr_time[1],
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
if job_data['interval'] != 'reaction':
|
||||
if job_data['cron_string'] != "":
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
CronTrigger.from_crontab(job_data['cron_string'],
|
||||
timezone=str(self.tz)),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
except Exception as e:
|
||||
console.error(f"Failed to schedule task with error: {e}.")
|
||||
console.info("Removing failed task from DB.")
|
||||
management_helper.delete_scheduled_task(sch_id)
|
||||
else:
|
||||
if job_data['interval_type'] == 'hours':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = 0,
|
||||
hour = '*/'+str(job_data['interval']),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
elif job_data['interval_type'] == 'minutes':
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = '*/'+str(job_data['interval']),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
elif job_data['interval_type'] == 'days':
|
||||
curr_time = job_data['start_time'].split(':')
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
day = '*/'+str(job_data['interval']),
|
||||
hour = curr_time[0],
|
||||
minute = curr_time[1],
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
else:
|
||||
try:
|
||||
self.scheduler.get_job(str(sch_id))
|
||||
@ -376,9 +391,21 @@ class TasksManager:
|
||||
task = management_helper.get_scheduled_task_model(int(event.job_id))
|
||||
management_helper.add_to_audit_log_raw('system', users_helper.get_user_id_by_name('system'), task.server_id,
|
||||
f"Task with id {task.schedule_id} completed successfully", '127.0.0.1')
|
||||
#check if the task is a single run.
|
||||
if task.one_time:
|
||||
self.remove_job(task.schedule_id)
|
||||
logger.info("one time task detected. Deleting...")
|
||||
#check for any child tasks for this. It's kind of backward, but this makes DB management a lot easier. One to one instead of one to many.
|
||||
for schedule in management_helper.get_child_schedules_by_server(task.schedule_id, task.server_id):
|
||||
#event job ID's are strings so we need to look at this as the same data type.
|
||||
if str(schedule.parent) == str(event.job_id):
|
||||
if schedule.enabled:
|
||||
delaytime = datetime.datetime.now() + datetime.timedelta(seconds=schedule.delay)
|
||||
self.scheduler.add_job(management_helper.add_command, 'date', run_date=delaytime, id=str(schedule.schedule_id),
|
||||
args=[schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command])
|
||||
else:
|
||||
logger.info("Event job ID is not numerical. Assuming it's stats - not stored in DB. Moving on.")
|
||||
else:
|
||||
|
@ -258,6 +258,10 @@ class AjaxHandler(BaseHandler):
|
||||
# Create the directory
|
||||
os.mkdir(dir_path)
|
||||
|
||||
elif page == "send_order":
|
||||
self.controller.users.update_server_order(exec_user['user_id'], bleach.clean(self.get_argument('order')))
|
||||
return
|
||||
|
||||
elif page == "unzip_file":
|
||||
if not permissions['Files'] in user_perms:
|
||||
if not superuser:
|
||||
|
@ -307,6 +307,29 @@ class PanelHandler(BaseHandler):
|
||||
list(filter(lambda x: x['stats']['running'], page_data['servers'])))
|
||||
page_data['server_stats']['stopped'] = len(page_data['servers']) - page_data['server_stats']['running']
|
||||
|
||||
#set user server order
|
||||
user_order = self.controller.users.get_user_by_id(exec_user['user_id'])
|
||||
user_order = user_order['server_order'].split(',')
|
||||
page_servers = []
|
||||
server_ids = []
|
||||
|
||||
for server_id in user_order:
|
||||
for server in page_data['servers']:
|
||||
if str(server['server_data']['server_id']) == str(server_id):
|
||||
page_servers.append(server)
|
||||
|
||||
|
||||
for server in page_data['servers']:
|
||||
server_ids.append(str(server['server_data']['server_id']))
|
||||
if server not in page_servers:
|
||||
page_servers.append(server)
|
||||
for server_id in user_order:
|
||||
#remove IDs in list that user no longer has access to
|
||||
if str(server_id) not in server_ids:
|
||||
user_order.remove(server_id)
|
||||
page_data['servers'] = page_servers
|
||||
|
||||
|
||||
for data in page_data['servers']:
|
||||
data['stats']['crashed'] = self.controller.servers.is_crashed(
|
||||
str(data['stats']['server_id']['server_id']))
|
||||
@ -333,7 +356,7 @@ class PanelHandler(BaseHandler):
|
||||
if server_id is None:
|
||||
return
|
||||
|
||||
valid_subpages = ['term', 'logs', 'backup', 'config', 'files', 'admin_controls', 'tasks']
|
||||
valid_subpages = ['term', 'logs', 'backup', 'config', 'files', 'admin_controls', 'schedules']
|
||||
|
||||
if subpage not in valid_subpages:
|
||||
logger.debug('not a valid subpage')
|
||||
@ -363,6 +386,7 @@ class PanelHandler(BaseHandler):
|
||||
}
|
||||
page_data['user_permissions'] = self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id)
|
||||
page_data['server_stats']['crashed'] = self.controller.servers.is_crashed(server_id)
|
||||
page_data['server_stats']['server_type'] = self.controller.servers.get_server_type_by_id(server_id)
|
||||
|
||||
if subpage == 'term':
|
||||
if not page_data['permissions']['Terminal'] in page_data['user_permissions']:
|
||||
@ -377,10 +401,10 @@ class PanelHandler(BaseHandler):
|
||||
return
|
||||
|
||||
|
||||
if subpage == 'tasks':
|
||||
if subpage == 'schedules':
|
||||
if not page_data['permissions']['Schedule'] in page_data['user_permissions']:
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access To Scheduled Tasks")
|
||||
self.redirect("/panel/error?error=Unauthorized access To Schedules")
|
||||
return
|
||||
page_data['schedules'] = management_helper.get_schedules_by_server(server_id)
|
||||
|
||||
@ -559,8 +583,9 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
elif page == "add_schedule":
|
||||
server_id = self.get_argument('id', None)
|
||||
page_data['schedules'] = management_helper.get_schedules_by_server(server_id)
|
||||
page_data['get_players'] = lambda: self.controller.stats.get_server_players(server_id)
|
||||
page_data['active_link'] = 'tasks'
|
||||
page_data['active_link'] = 'schedules'
|
||||
page_data['permissions'] = {
|
||||
'Commands': Enum_Permissions_Server.Commands,
|
||||
'Terminal': Enum_Permissions_Server.Terminal,
|
||||
@ -574,8 +599,10 @@ class PanelHandler(BaseHandler):
|
||||
page_data['user_permissions'] = self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id)
|
||||
page_data['server_data'] = self.controller.servers.get_server_data_by_id(server_id)
|
||||
page_data['server_stats'] = self.controller.servers.get_server_stats_by_id(server_id)
|
||||
page_data['server_stats']['server_type'] = self.controller.servers.get_server_type_by_id(server_id)
|
||||
page_data['new_schedule'] = True
|
||||
page_data['schedule'] = {}
|
||||
page_data['schedule']['children'] = []
|
||||
page_data['schedule']['server_id'] = server_id
|
||||
page_data['schedule']['schedule_id'] = ''
|
||||
page_data['schedule']['action'] = ""
|
||||
@ -591,17 +618,18 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
if not Enum_Permissions_Server.Schedule in page_data['user_permissions']:
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access To Scheduled Tasks")
|
||||
self.redirect("/panel/error?error=Unauthorized access To Schedules")
|
||||
return
|
||||
|
||||
template = "panel/server_schedule_edit.html"
|
||||
|
||||
elif page == "edit_schedule":
|
||||
server_id = self.get_argument('id', None)
|
||||
page_data['schedules'] = management_helper.get_schedules_by_server(server_id)
|
||||
sch_id = self.get_argument('sch_id', None)
|
||||
schedule = self.controller.management.get_scheduled_task_model(sch_id)
|
||||
page_data['get_players'] = lambda: self.controller.stats.get_server_players(server_id)
|
||||
page_data['active_link'] = 'tasks'
|
||||
page_data['active_link'] = 'schedules'
|
||||
page_data['permissions'] = {
|
||||
'Commands': Enum_Permissions_Server.Commands,
|
||||
'Terminal': Enum_Permissions_Server.Terminal,
|
||||
@ -615,11 +643,13 @@ class PanelHandler(BaseHandler):
|
||||
page_data['user_permissions'] = self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id)
|
||||
page_data['server_data'] = self.controller.servers.get_server_data_by_id(server_id)
|
||||
page_data['server_stats'] = self.controller.servers.get_server_stats_by_id(server_id)
|
||||
page_data['server_stats']['server_type'] = self.controller.servers.get_server_type_by_id(server_id)
|
||||
page_data['new_schedule'] = False
|
||||
page_data['schedule'] = {}
|
||||
page_data['schedule']['server_id'] = server_id
|
||||
page_data['schedule']['schedule_id'] = schedule.schedule_id
|
||||
page_data['schedule']['action'] = schedule.action
|
||||
page_data['schedule']['children'] = self.controller.management.get_child_schedules(sch_id)
|
||||
# We check here to see if the command is any of the default ones.
|
||||
# We do not want a user changing to a custom command and seeing our command there.
|
||||
if schedule.action != 'start' or schedule.action != 'stop' or schedule.action != 'restart' or schedule.action != 'backup':
|
||||
@ -632,7 +662,9 @@ class PanelHandler(BaseHandler):
|
||||
page_data['schedule']['time'] = schedule.start_time
|
||||
page_data['schedule']['interval'] = schedule.interval
|
||||
page_data['schedule']['interval_type'] = schedule.interval_type
|
||||
if schedule.cron_string == '':
|
||||
if schedule.interval_type == 'reaction':
|
||||
difficulty = 'reaction'
|
||||
elif schedule.cron_string == '':
|
||||
difficulty = 'basic'
|
||||
else:
|
||||
difficulty = 'advanced'
|
||||
@ -643,7 +675,7 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
if not Enum_Permissions_Server.Schedule in page_data['user_permissions']:
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access To Scheduled Tasks")
|
||||
self.redirect("/panel/error?error=Unauthorized access To Schedules")
|
||||
return
|
||||
|
||||
template = "panel/server_schedule_edit.html"
|
||||
@ -1052,6 +1084,23 @@ class PanelHandler(BaseHandler):
|
||||
command = "restart_server"
|
||||
elif action == "backup":
|
||||
command = "backup_server"
|
||||
|
||||
elif difficulty == 'reaction':
|
||||
interval_type = 'reaction'
|
||||
action = bleach.clean(self.get_argument('action', None))
|
||||
delay = bleach.clean(self.get_argument('delay', None))
|
||||
parent = bleach.clean(self.get_argument('parent', None))
|
||||
if action == "command":
|
||||
command = bleach.clean(self.get_argument('command', None))
|
||||
elif action == "start":
|
||||
command = "start_server"
|
||||
elif action == "stop":
|
||||
command = "stop_server"
|
||||
elif action == "restart":
|
||||
command = "restart_server"
|
||||
elif action == "backup":
|
||||
command = "backup_server"
|
||||
|
||||
else:
|
||||
interval_type = ''
|
||||
cron_string = bleach.clean(self.get_argument('cron', ''))
|
||||
@ -1105,6 +1154,21 @@ class PanelHandler(BaseHandler):
|
||||
"one_time": one_time,
|
||||
"cron_string": ''
|
||||
}
|
||||
elif difficulty == "reaction":
|
||||
job_data = {
|
||||
"server_id": server_id,
|
||||
"action": action,
|
||||
"interval_type": interval_type,
|
||||
"interval": '',
|
||||
#We'll base every interval off of a midnight start time.
|
||||
"start_time": '',
|
||||
"command": command,
|
||||
"cron_string": '',
|
||||
"enabled": enabled,
|
||||
"one_time": one_time,
|
||||
"parent": parent,
|
||||
"delay": delay
|
||||
}
|
||||
elif difficulty == "advanced":
|
||||
job_data = {
|
||||
"server_id": server_id,
|
||||
@ -1116,7 +1180,9 @@ class PanelHandler(BaseHandler):
|
||||
"command": command,
|
||||
"cron_string": cron_string,
|
||||
"enabled": enabled,
|
||||
"one_time": one_time
|
||||
"one_time": one_time,
|
||||
"parent": None,
|
||||
"delay": 0
|
||||
}
|
||||
else:
|
||||
job_data = {
|
||||
@ -1129,7 +1195,9 @@ class PanelHandler(BaseHandler):
|
||||
#We'll base every interval off of a midnight start time.
|
||||
"start_time": '00:00',
|
||||
"one_time": one_time,
|
||||
"cron_string": ''
|
||||
"cron_string": '',
|
||||
'parent': None,
|
||||
'delay': 0
|
||||
}
|
||||
|
||||
self.tasks_manager.schedule_job(job_data)
|
||||
@ -1139,7 +1207,7 @@ class PanelHandler(BaseHandler):
|
||||
server_id,
|
||||
self.get_remote_ip())
|
||||
self.tasks_manager.reload_schedule_from_db()
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=tasks")
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=schedules")
|
||||
|
||||
|
||||
if page == "edit_schedule":
|
||||
@ -1164,6 +1232,22 @@ class PanelHandler(BaseHandler):
|
||||
command = "restart_server"
|
||||
elif action == "backup":
|
||||
command = "backup_server"
|
||||
elif difficulty == 'reaction':
|
||||
interval_type = 'reaction'
|
||||
action = bleach.clean(self.get_argument('action', None))
|
||||
delay = bleach.clean(self.get_argument('delay', None))
|
||||
parent = bleach.clean(self.get_argument('parent', None))
|
||||
if action == "command":
|
||||
command = bleach.clean(self.get_argument('command', None))
|
||||
elif action == "start":
|
||||
command = "start_server"
|
||||
elif action == "stop":
|
||||
command = "stop_server"
|
||||
elif action == "restart":
|
||||
command = "restart_server"
|
||||
elif action == "backup":
|
||||
command = "backup_server"
|
||||
parent = bleach.clean(self.get_argument('parent', None))
|
||||
else:
|
||||
interval_type = ''
|
||||
cron_string = bleach.clean(self.get_argument('cron', ''))
|
||||
@ -1228,9 +1312,26 @@ class PanelHandler(BaseHandler):
|
||||
"start_time": '',
|
||||
"command": command,
|
||||
"cron_string": cron_string,
|
||||
"delay": '',
|
||||
"parent": '',
|
||||
"enabled": enabled,
|
||||
"one_time": one_time
|
||||
}
|
||||
elif difficulty == "reaction":
|
||||
job_data = {
|
||||
"server_id": server_id,
|
||||
"action": action,
|
||||
"interval_type": interval_type,
|
||||
"interval": '',
|
||||
#We'll base every interval off of a midnight start time.
|
||||
"start_time": '',
|
||||
"command": command,
|
||||
"cron_string": '',
|
||||
"enabled": enabled,
|
||||
"one_time": one_time,
|
||||
"parent": parent,
|
||||
"delay": delay
|
||||
}
|
||||
else:
|
||||
job_data = {
|
||||
"server_id": server_id,
|
||||
@ -1241,6 +1342,8 @@ class PanelHandler(BaseHandler):
|
||||
"enabled": enabled,
|
||||
#We'll base every interval off of a midnight start time.
|
||||
"start_time": '00:00',
|
||||
"delay": '',
|
||||
"parent": '',
|
||||
"one_time": one_time,
|
||||
"cron_string": ''
|
||||
}
|
||||
@ -1252,7 +1355,7 @@ class PanelHandler(BaseHandler):
|
||||
server_id,
|
||||
self.get_remote_ip())
|
||||
self.tasks_manager.reload_schedule_from_db()
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=tasks")
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=schedules")
|
||||
|
||||
|
||||
elif page == "edit_user":
|
||||
|
@ -113,6 +113,13 @@ class ServerHandler(BaseHandler):
|
||||
page_data['js_server_types'] = json.dumps(server_jar_obj.get_serverjar_data())
|
||||
template = "server/wizard.html"
|
||||
|
||||
if page == "bedrock_step1":
|
||||
if not superuser and not self.controller.crafty_perms.can_create_server(exec_user["user_id"]):
|
||||
self.redirect("/panel/error?error=Unauthorized access: not a server creator or server limit reached")
|
||||
return
|
||||
|
||||
template = "server/bedrock_wizard.html"
|
||||
|
||||
self.render(
|
||||
template,
|
||||
data=page_data,
|
||||
@ -170,6 +177,7 @@ class ServerHandler(BaseHandler):
|
||||
new_executable = server_data.get('executable')
|
||||
new_server_log_file = str(helper.get_os_understandable_path(server_data.get('log_path'))).replace(server_uuid, new_server_uuid)
|
||||
server_port = server_data.get('server_port')
|
||||
server_type = server_data.get('server_type')
|
||||
|
||||
self.controller.servers.create_server(new_server_name,
|
||||
new_server_uuid,
|
||||
@ -179,6 +187,7 @@ class ServerHandler(BaseHandler):
|
||||
new_executable,
|
||||
new_server_log_file,
|
||||
stop_command,
|
||||
server_type,
|
||||
server_port)
|
||||
|
||||
self.controller.init_all_servers()
|
||||
@ -273,6 +282,89 @@ class ServerHandler(BaseHandler):
|
||||
self.controller.stats.record_stats()
|
||||
self.redirect("/panel/dashboard")
|
||||
|
||||
if page == "bedrock_step1":
|
||||
if not superuser:
|
||||
user_roles = self.controller.roles.get_all_roles()
|
||||
else:
|
||||
user_roles = self.controller.roles.get_all_roles()
|
||||
server = bleach.clean(self.get_argument('server', ''))
|
||||
server_name = bleach.clean(self.get_argument('server_name', ''))
|
||||
port = bleach.clean(self.get_argument('port', ''))
|
||||
import_type = bleach.clean(self.get_argument('create_type', ''))
|
||||
import_server_path = bleach.clean(self.get_argument('server_path', ''))
|
||||
import_server_exe = bleach.clean(self.get_argument('server_jar', ''))
|
||||
server_parts = server.split("|")
|
||||
captured_roles = []
|
||||
for role in user_roles:
|
||||
if bleach.clean(self.get_argument(str(role), '')) == "on":
|
||||
captured_roles.append(role)
|
||||
|
||||
if not server_name:
|
||||
self.redirect("/panel/error?error=Server name cannot be empty!")
|
||||
return
|
||||
|
||||
if import_type == 'import_jar':
|
||||
good_path = self.controller.verify_jar_server(import_server_path, import_server_jar)
|
||||
|
||||
if not good_path:
|
||||
self.redirect("/panel/error?error=Server path or Server Jar not found!")
|
||||
return
|
||||
|
||||
new_server_id = self.controller.import_bedrock_server(server_name, import_server_path,import_server_exe, port)
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
f"imported a jar server named \"{server_name}\"", # Example: Admin imported a server named "old creative"
|
||||
new_server_id,
|
||||
self.get_remote_ip())
|
||||
elif import_type == 'import_zip':
|
||||
# here import_server_path means the zip path
|
||||
zip_path = bleach.clean(self.get_argument('root_path'))
|
||||
good_path = helper.check_path_exists(zip_path)
|
||||
if not good_path:
|
||||
self.redirect("/panel/error?error=Temp path not found!")
|
||||
return
|
||||
|
||||
new_server_id = self.controller.import_bedrock_zip_server(server_name, zip_path, import_server_exe, port)
|
||||
if new_server_id == "false":
|
||||
self.redirect("/panel/error?error=Zip file not accessible! You can fix this permissions issue with" +
|
||||
f"sudo chown -R crafty:crafty {import_server_path} And sudo chmod 2775 -R {import_server_path}")
|
||||
return
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
f"imported a zip server named \"{server_name}\"", # Example: Admin imported a server named "old creative"
|
||||
new_server_id,
|
||||
self.get_remote_ip())
|
||||
#deletes temp dir
|
||||
shutil.rmtree(zip_path)
|
||||
else:
|
||||
if len(server_parts) != 2:
|
||||
self.redirect("/panel/error?error=Invalid server data")
|
||||
return
|
||||
server_type, server_version = server_parts
|
||||
# TODO: add server type check here and call the correct server add functions if not a jar
|
||||
role_ids = self.controller.users.get_user_roles_id(exec_user["user_id"])
|
||||
new_server_id = self.controller.create_jar_server(server_type, server_version, server_name, min_mem, max_mem, port)
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
f"created a {server_version} {str(server_type).capitalize()} server named \"{server_name}\"",
|
||||
# Example: Admin created a 1.16.5 Bukkit server named "survival"
|
||||
new_server_id,
|
||||
self.get_remote_ip())
|
||||
|
||||
# These lines create a new Role for the Server with full permissions and add the user to it if he's not a superuser
|
||||
if len(captured_roles) == 0:
|
||||
if not superuser:
|
||||
new_server_uuid = self.controller.servers.get_server_data_by_id(new_server_id).get("server_uuid")
|
||||
role_id = self.controller.roles.add_role(f"Creator of Server with uuid={new_server_uuid}")
|
||||
self.controller.server_perms.add_role_server(new_server_id, role_id, "11111111")
|
||||
self.controller.users.add_role_to_user(exec_user["user_id"], role_id)
|
||||
self.controller.crafty_perms.add_server_creation(exec_user["user_id"])
|
||||
|
||||
else:
|
||||
for role in captured_roles:
|
||||
role_id = role
|
||||
self.controller.server_perms.add_role_server(new_server_id, role_id, "11111111")
|
||||
|
||||
self.controller.stats.record_stats()
|
||||
self.redirect("/panel/dashboard")
|
||||
|
||||
try:
|
||||
self.render(
|
||||
template,
|
||||
|
@ -13,6 +13,7 @@
|
||||
"show_contribute_link": true,
|
||||
"virtual_terminal_lines": 70,
|
||||
"max_log_lines": 700,
|
||||
"max_audit_entries": 300,
|
||||
"keywords": ["help", "chunk"],
|
||||
"allow_nsfw_profile_pictures": false
|
||||
}
|
||||
|
@ -123,10 +123,10 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for server in data['servers'] %}
|
||||
<tr>
|
||||
<td>
|
||||
<tr id="{{server['server_data']['server_id']}}" draggable="true" ondragstart="start()" ondragover="dragover()" ondragend="dragend()">
|
||||
<td draggable="false">
|
||||
<i class="fas fa-server"></i>
|
||||
<a href="/panel/server_detail?id={{server['server_data']['server_id']}}">
|
||||
<a draggable="false" href="/panel/server_detail?id={{server['server_data']['server_id']}}">
|
||||
{{ server['server_data']['server_name'] }}
|
||||
</a>
|
||||
</td>
|
||||
@ -391,7 +391,7 @@
|
||||
server_desc.innerHTML = server.online + ` / ` + server.max + ` {{ translate('dashboard', 'max', data['lang']) }}<br />`
|
||||
|
||||
server_infos = "";
|
||||
server_infos = server.online + " / " + server.max + "{{ translate('dashboard', 'max', data['lang']) }}<br />"
|
||||
server_infos = server.online + " / " + server.max + " {{ translate('dashboard', 'max', data['lang']) }}<br />"
|
||||
}
|
||||
|
||||
/* Update Motd */
|
||||
@ -554,5 +554,55 @@
|
||||
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
var row;
|
||||
|
||||
function start(){
|
||||
row = event.target;
|
||||
}
|
||||
function dragover(){
|
||||
var e = event;
|
||||
e.preventDefault();
|
||||
|
||||
let children= Array.from(e.target.parentNode.parentNode.children);
|
||||
|
||||
if(children.indexOf(e.target.parentNode)>children.indexOf(row))
|
||||
e.target.parentNode.after(row);
|
||||
else
|
||||
e.target.parentNode.before(row);
|
||||
}
|
||||
|
||||
function dragend(){
|
||||
var id_string = '';
|
||||
const table = document.querySelector("table");
|
||||
for (const row of table.rows) {
|
||||
if (row.getAttribute('id') != null){
|
||||
if (id_string != ''){
|
||||
id_string += ',' + String(row.getAttribute('id'));
|
||||
}else{
|
||||
id_string +=String(row.getAttribute('id'));
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(id_string)
|
||||
sendOrder(id_string)
|
||||
}
|
||||
function sendOrder(id_string) {
|
||||
var token = getCookie("_xsrf")
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: {'X-XSRFToken': token},
|
||||
url: '/ajax/send_order?order='+id_string,
|
||||
data: {
|
||||
order: id_string,
|
||||
},
|
||||
success: function(data){
|
||||
console.log("got response:");
|
||||
console.log(data);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
{% end %}
|
@ -133,7 +133,7 @@
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user-lock"></i> {{ translate('userConfig', 'craftyPerms', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('userConfig', 'craftyPermDesc', data['lang']) }}permissions this user has on Crafty Controller </small></h4>
|
||||
<h4 class="card-title"><i class="fas fa-user-lock"></i> {{ translate('userConfig', 'craftyPerms', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('userConfig', 'craftyPermDesc', data['lang']) }}</small></h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
|
@ -6,7 +6,7 @@
|
||||
<div class="col-sm-4 mr-2">
|
||||
{% if data['server_stats']['running'] %}
|
||||
<b>{{ translate('serverStats', 'serverStatus', data['lang']) }}:</b> <span id="status" class="text-success">{{ translate('serverStats', 'online', data['lang']) }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverStarted', data['lang']) }}:</b> <span id="started">{{ data['server_stats']['started'] }} ({{ translate('serverStats', 'serverTime', data['lang']) }})</span><br />
|
||||
<b>{{ translate('serverStats', 'serverStarted', data['lang']) }}:</b> <span id="started">{{ data['server_stats']['started'] }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverUptime', data['lang']) }}:</b> <span id="uptime">{{ translate('serverStats', 'errorCalculatingUptime', data['lang']) }}</span>
|
||||
{% elif data['server_stats']['crashed'] %}
|
||||
<b>{{ translate('serverStats', 'serverStatus', data['lang']) }}:</b> <span id="status" class="text-danger"> <i class="fas fa-exclamation-triangle"></i> {{ translate('dashboard', 'crashed', data['lang']) }}</span><br />
|
||||
@ -16,7 +16,6 @@
|
||||
<b>{{ translate('serverStats', 'serverStatus', data['lang']) }}:</b> <span id="status" class="text-warning">{{ translate('serverStats', 'offline', data['lang']) }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverStarted', data['lang']) }}:</b> <span id="started" class="text-warning">{{ translate('serverStats', 'offline', data['lang']) }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverUptime', data['lang']) }}:</b> <span id="uptime" class="text-warning">{{ translate('serverStats', 'offline', data['lang']) }}</span>
|
||||
<p>{{ data['server_stats']['crashed'] }}</p>
|
||||
{% end %}
|
||||
<br>
|
||||
<b>{{ translate('serverStats', 'serverTimeZone', data['lang']) }}:</b> <span class="text-info">{{ data['serverTZ'] }}</span>
|
||||
@ -40,6 +39,8 @@
|
||||
<b>{{ translate('serverStats', 'version', data['lang']) }}:</b> <span id="version">{{ translate('serverStats', 'unableToConnect', data['lang']) }}</span> <br />
|
||||
<b>{{ translate('serverStats', 'description', data['lang']) }}:</b> <span id="input_motd" class="input_motd">{{ translate('serverStats', 'unableToConnect', data['lang']) }}</span> <br />
|
||||
{% end %}
|
||||
<b>Server Type: <span class="text-info">{{data['server_stats']['server_type']}}</span></b>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -134,17 +135,15 @@
|
||||
server_input_motd = document.getElementById('input_motd');
|
||||
|
||||
/* TODO Update each element */
|
||||
if (server.running)
|
||||
{
|
||||
if (server.int_ping_results)
|
||||
{
|
||||
server_status.setAttribute("class", "text-success");
|
||||
server_status.innerHTML = `{{ translate('serverStats', 'online', data['lang']) }}`;
|
||||
if (server.running){
|
||||
if (server['stats']['waiting_start']){
|
||||
server_status.setAttribute("class", "text-warning");
|
||||
server_status.innerHTML = `{{ translate('serverStats', 'starting', data['lang']) }}`;
|
||||
}
|
||||
else
|
||||
{
|
||||
server_status.setAttribute("class", "text-warning");
|
||||
server_status.innerHTML = `{{ translate('serverStats', 'starting', data['lang']) }}`;
|
||||
server_status.setAttribute("class", "text-success");
|
||||
server_status.innerHTML = `{{ translate('serverStats', 'online', data['lang']) }}`;
|
||||
}
|
||||
|
||||
startedUTC = server.started;
|
||||
@ -153,7 +152,7 @@
|
||||
startedLocal = startedUTC.utcOffset(browserUTCOffset);
|
||||
startedLocalFormatted = startedLocal.format('YYYY-MM-DD HH:mm:ss');
|
||||
server_started.setAttribute("class", "");
|
||||
server_started.innerHTML = startedLocalFormatted +` ({{ translate('serverStats', 'serverTime', data['lang']) }})`;
|
||||
server_started.innerHTML = startedLocalFormatted;
|
||||
server_uptime.setAttribute("class", "");
|
||||
if (!uptimeLoop) {
|
||||
var calculateUptime = () => {
|
||||
|
@ -5,7 +5,8 @@
|
||||
<i class="fas fa-file-signature"></i>{{ translate('serverDetails', 'terminal', data['lang']) }}</a>
|
||||
</li>
|
||||
{% end %}
|
||||
{% if data['permissions']['Logs'] in data['user_permissions'] %}
|
||||
<!--Bedrock servers don't have logs so we'll only show it if we know it's not a bedrock server.-->
|
||||
{% if data['permissions']['Logs'] in data['user_permissions'] and data['server_data']['type'] != 'minecraft-bedrock'%}
|
||||
<li class="nav-item term-nav-item">
|
||||
<a class="nav-link {% if data['active_link'] == 'logs' %}active{% end %}" 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>{{ translate('serverDetails', 'logs', data['lang']) }}</a>
|
||||
@ -13,7 +14,7 @@
|
||||
{% end %}
|
||||
{% if data['permissions']['Schedule'] in data['user_permissions'] %}
|
||||
<li class="nav-item term-nav-item">
|
||||
<a class="nav-link {% if data['active_link'] == 'tasks' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=tasks" role="tab" aria-selected="false">
|
||||
<a class="nav-link {% if data['active_link'] == 'schedules' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=schedules" role="tab" aria-selected="false">
|
||||
<i class="fas fa-clock"></i>{{ translate('serverDetails', 'schedule', data['lang']) }}</a>
|
||||
</li>
|
||||
{% end %}
|
||||
|
@ -24,7 +24,7 @@
|
||||
</div>
|
||||
<!-- Page Title Header Ends-->
|
||||
|
||||
{% include "parts/details_stats.html %}
|
||||
{% include "parts/details_stats.html" %}
|
||||
|
||||
<div class="row">
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
{% include "parts/server_controls_list.html %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12 col-sm-12">
|
||||
<div class="col-md-8 col-sm-8">
|
||||
{% if data['new_schedule'] == True %}
|
||||
<form class="forms-sample" method="post" action="/panel/new_schedule?id={{ data['server_stats']['server_id']['server_id'] }}">
|
||||
{% else %}
|
||||
@ -45,70 +45,99 @@
|
||||
<input type="hidden" name="subpage" value="config">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="difficulty">Basic / Cron Select<small class="text-muted ml-1"></small> </label><br>
|
||||
<label for="difficulty">Basic / Cron / Chain-Reaction Select<small class="text-muted ml-1"></small> </label><br>
|
||||
<select id="difficulty" name="difficulty" onchange="basicAdvanced(this);" class="form-control form-control-lg select-css" value="{{ data['schedule']['difficulty'] }}">
|
||||
<option id="basic" value="basic">Basic</option>
|
||||
<option id="advanced" value="advanced">Advanced</option>
|
||||
<option id="basic" value="basic">{{ translate('serverScheduleConfig', 'basic' , data['lang']) }}</option>
|
||||
<option id="advanced" value="advanced">{{ translate('serverScheduleConfig', 'cron' , data['lang']) }}</option>
|
||||
<option id="reaction" value="reaction">{{ translate('serverScheduleConfig', 'reaction' , data['lang']) }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="server_name">Action<small class="text-muted ml-1"></small> </label><br>
|
||||
<select id="action" name="action" onchange="yesnoCheck(this);" class="form-control form-control-lg select-css" value="{{ data['schedule']['action'] }}">
|
||||
<option id="start" value="start">Start Server</option>
|
||||
<option id="restart" value="restart">Restart Server</option>
|
||||
<option id="stop" value="stop">Shutdown Server</option>
|
||||
<option id="backup" value="backup">Backup Server</option>
|
||||
<option id="command" value="command">Custon Command</option>
|
||||
<option id="start" value="start">{{ translate('serverScheduleConfig', 'start' , data['lang']) }}</option>
|
||||
<option id="restart" value="restart">{{ translate('serverScheduleConfig', 'restart' , data['lang']) }}</option>
|
||||
<option id="stop" value="stop">{{ translate('serverScheduleConfig', 'stop' , data['lang']) }}</option>
|
||||
<option id="backup" value="backup">{{ translate('serverScheduleConfig', 'backup' , data['lang']) }}</option>
|
||||
<option id="command" value="command">{{ translate('serverScheduleConfig', 'custom' , data['lang']) }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="ifBasic">
|
||||
<div class="form-group">
|
||||
<label for="server_path">Interval <small class="text-muted ml-1"> - How often you want this task to execute</small> </label>
|
||||
<label for="server_path">{{ translate('serverScheduleConfig', 'interval' , data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverScheduleConfig', 'interval-explain' , data['lang']) }}</small> </label>
|
||||
<input type="number" class="form-control" name="interval" id="interval" value="{{ data['schedule']['interval'] }}" placeholder="Interval" required>
|
||||
<br>
|
||||
<br>
|
||||
<select id="interval_type" onchange="ifDays(this);" name="interval_type" class="form-control form-control-lg select-css" value="{{ data['schedule']['interval_type'] }}">
|
||||
<option id = "days" value="days">Days</option>
|
||||
<option id = "hours" value="hours">Hours</option>
|
||||
<option id = "minutes" value="minutes">Minutes</option>
|
||||
<option id = "days" value="days">{{ translate('serverScheduleConfig', 'days' , data['lang']) }}</option>
|
||||
<option id = "hours" value="hours">{{ translate('serverScheduleConfig', 'hours' , data['lang']) }}</option>
|
||||
<option id = "minutes" value="minutes">{{ translate('serverScheduleConfig', 'minutes' , data['lang']) }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="ifDays" style="display: block;">
|
||||
<div class="form-group">
|
||||
<label for="time">Time <small class="text-muted ml-1"> - What time do you want your task to execute?</small> </label>
|
||||
<label for="time">{{ translate('serverScheduleConfig', 'time' , data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverScheduleConfig', 'time-explain' , data['lang']) }}</small> </label>
|
||||
<input type="time" class="form-control" name="time" id="time" value="{{ data['schedule']['time'] }}" placeholder="Time" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ifYes" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label for="command">Command <small class="text-muted ml-1"> - What command do you want us to execute? Do not include the '/'</small> </label>
|
||||
<label for="command">{{ translate('serverScheduleConfig', 'command' , data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverScheduleConfig', 'command-explain' , data['lang']) }}</small> </label>
|
||||
<input type="input" class="form-control" name="command" id="command_input" value="{{ data['schedule']['command'] }}" placeholder="Command" required>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ifAdvanced" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label for="cron">Cron <small class="text-muted ml-1"> - Input your cron string</small> </label>
|
||||
<label for="cron">{{ translate('serverScheduleConfig', 'cron' , data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverScheduleConfig', 'cron-explain' , data['lang']) }}</small> </label>
|
||||
<input type="input" class="form-control" name="cron" id="cron" value="{{ data['schedule']['cron_string'] }}" placeholder="* * * * *">
|
||||
</div>
|
||||
</div>
|
||||
<div id="ifReaction" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label for="delay">{{ translate('serverScheduleConfig', 'offset' , data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverScheduleConfig', 'offset-explain' , data['lang']) }}</small> </label>
|
||||
<input type="number" class="form-control" name="delay" id="delay" value="0">
|
||||
<br>
|
||||
<br>
|
||||
<label for="parent">{{ translate('serverScheduleConfig', 'parent' , data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverScheduleConfig', 'parent-explain' , data['lang']) }}</small> </label>
|
||||
<select id="parent" name="parent" class="form-control form-control-lg select-css" value="{{ data['schedule']['action'] }}">
|
||||
{% for schedule in data['schedules'] %}
|
||||
{% if schedule.schedule_id != data['schedule']['schedule_id'] %}
|
||||
{% if schedule.interval != '' %}
|
||||
<option id="{{schedule.schedule_id}}" value="{{schedule.schedule_id}}">ID: {{schedule.schedule_id}} | {{schedule.command}} | {{schedule.interval}} {{ schedule.interval_type}}</option>
|
||||
{% else %}
|
||||
<option id="{{schedule.schedule_id}}" value="{{schedule.schedule_id}}">ID: {{schedule.schedule_id}} {{schedule.command}} {{schedule.cron_string}}</option>
|
||||
{% end %}
|
||||
{% end %}
|
||||
{% end %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-check-flat">
|
||||
<label for="enabled" class="form-check-label ml-4 mb-4">
|
||||
<input type="checkbox" class="form-check-input" id="enabled" name="enabled" checked="" value="1">Enabled
|
||||
<input type="checkbox" class="form-check-input" id="enabled" name="enabled" checked="" value="1">{{ translate('serverScheduleConfig', 'enabled' , data['lang']) }}
|
||||
</label>
|
||||
|
||||
</div>
|
||||
<div class="form-check-flat">
|
||||
<label for="one_time" class="form-check-label ml-4 mb-4">
|
||||
<input type="checkbox" class="form-check-input" id="one_time" name="one_time" value="1">Delete After Execution
|
||||
<input type="checkbox" class="form-check-input" id="one_time" name="one_time" value="1">{{ translate('serverScheduleConfig', 'one-time' , data['lang']) }}
|
||||
</label>
|
||||
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success mr-2"><i class="fas fa-save"></i> {{ translate('serverConfig', 'save', data['lang']) }}</button>
|
||||
<button type="reset" onclick="location.href=`/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=tasks`" class="btn btn-light"><i class="fas fa-times"></i> {{ translate('serverConfig', 'cancel', data['lang']) }}</button>
|
||||
<button type="reset" onclick="location.href=`/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=schedules`" class="btn btn-light"><i class="fas fa-times"></i> {{ translate('serverConfig', 'cancel', data['lang']) }}</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-sm-4 grid-margin">
|
||||
<h4>{{ translate('serverScheduleConfig', 'children' , data['lang']) }}</h4>
|
||||
<ul>
|
||||
{% for schedule in data['schedule']['children'] %}
|
||||
<li style="overflow: auto;"><a href="/panel/edit_schedule?id={{schedule.server_id}}&sch_id={{schedule.schedule_id}}">{{schedule.schedule_id}} | {{schedule.command}}</a></li>
|
||||
{% end %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -149,12 +178,27 @@
|
||||
function basicAdvanced() {
|
||||
if (document.getElementById('difficulty').value == "advanced") {
|
||||
document.getElementById("ifAdvanced").style.display = "block";
|
||||
document.getElementById("ifReaction").style.display = "none";
|
||||
document.getElementById("ifBasic").style.display = "none";
|
||||
document.getElementById("delay").required = false;
|
||||
document.getElementById("parent").required = false;
|
||||
document.getElementById("interval").required = false;
|
||||
document.getElementById("time").required = false;
|
||||
} else {
|
||||
} else if(document.getElementById('difficulty').value == "reaction"){
|
||||
document.getElementById("ifReaction").style.display = "block";
|
||||
document.getElementById("ifBasic").style.display = "none";
|
||||
document.getElementById("ifAdvanced").style.display = "none";
|
||||
document.getElementById("delay").required = true;
|
||||
document.getElementById("parent").required = true;
|
||||
document.getElementById("interval").required = false;
|
||||
document.getElementById("time").required = false;
|
||||
}
|
||||
else {
|
||||
document.getElementById("ifAdvanced").style.display = "none";
|
||||
document.getElementById("ifReaction").style.display = "none";
|
||||
document.getElementById("ifBasic").style.display = "block";
|
||||
document.getElementById("delay").required = false;
|
||||
document.getElementById("parent").required = false;
|
||||
document.getElementById("interval").required = true;
|
||||
document.getElementById("time").required = true;
|
||||
}
|
||||
|
@ -45,7 +45,8 @@
|
||||
<table class="table table-hover d-none d-lg-block responsive-table" id="schedule_table" width="100%" style="table-layout:fixed;">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th style="width: 25%; min-width: 50px;">Action</th>
|
||||
<th style="width: 2%; min-width: 10px;">ID</th>
|
||||
<th style="width: 23%; min-width: 50px;">Action</th>
|
||||
<th style="width: 40%; min-width: 50px;">Command</th>
|
||||
<th style="width: 10%; min-width: 50px;">Interval</th>
|
||||
<th style="width: 10%; min-width: 50px;">Start Time</th>
|
||||
@ -56,6 +57,9 @@
|
||||
<tbody>
|
||||
{% for schedule in data['schedules'] %}
|
||||
<tr>
|
||||
<td id="{{schedule.schedule_id}}" class="id">
|
||||
<p>{{schedule.schedule_id}}</p>
|
||||
</td>
|
||||
<td id="{{schedule.action}}" class="action">
|
||||
<p>{{schedule.action}}</p>
|
||||
</td>
|
||||
@ -66,6 +70,8 @@
|
||||
{% if schedule.interval != '' %}
|
||||
<p>Every</p>
|
||||
<p>{{schedule.interval}} {{schedule.interval_type}}</p>
|
||||
{% elif schedule.interval_type == 'reaction' %}
|
||||
<p>{{schedule.interval_type}}<br><br>child of ID: {{ schedule.parent }}</p>
|
||||
{% else %}
|
||||
<p>Cron String:</p>
|
||||
<p>{{schedule.cron_string}}</p>
|
||||
@ -141,6 +147,9 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ul style="list-style: none;">
|
||||
<li id="{{schedule.schedule_id}}" class="id" style="border-top: .1em solid gray;">
|
||||
<h4>ID</h4><p>{{schedule.schedule_id}}</p>
|
||||
</li>
|
||||
<li id="{{schedule.action}}" class="action" style="border-top: .1em solid gray;">
|
||||
<h4>Action</h4><p>{{schedule.action}}</p>
|
||||
</li>
|
||||
@ -150,6 +159,8 @@
|
||||
<li id="{{schedule.interval}}" class="action" style="border-top: .1em solid gray;">
|
||||
{% if schedule.interval != '' %}
|
||||
<h4>Interval</h4> <p>Every {{schedule.interval}} {{schedule.interval_type}}</p>
|
||||
{% elif schedule.interval_type == 'reaction' %}
|
||||
<h4>Interval</h4> <p>{{schedule.interval_type}}<br><br>child of ID: {{ schedule.parent }}</p>
|
||||
{% else %}
|
||||
<h4>Interval</h4> <p>Cron String: {{schedule.cron_string}}</p>
|
||||
{% end %}
|
460
app/frontend/templates/server/bedrock_wizard.html
Normal file
460
app/frontend/templates/server/bedrock_wizard.html
Normal file
@ -0,0 +1,460 @@
|
||||
{% extends ../base.html %}
|
||||
|
||||
{% block title %}Crafty Controller - {{ translate('serverWizard', 'newServer', data['lang']) }}{% end %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="content-wrapper">
|
||||
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
||||
<li class="nav-item term-nav-item">
|
||||
<a class="nav-link" href="/server/step1" role="tab" aria-selected="false">
|
||||
<i class="fas fa-file-signature"></i>Minecraft-Java</a>
|
||||
</li>
|
||||
<li class="nav-item term-nav-item">
|
||||
<a class="nav-link active" href="/server/bedrock_step1" role="tab" aria-selected="false">
|
||||
<i class="fas fa-file-signature"></i>Minecraft-Bedrock</a>
|
||||
</li>
|
||||
</ul>
|
||||
<br>
|
||||
<div class="d-none" id="overlay" onclick="hide(event)"></div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
<h4>{{ translate('serverWizard', 'importServer', data['lang']) }}</h4>
|
||||
<br />
|
||||
<p class="card-description">
|
||||
|
||||
<form method="post" class="server-wizard" onSubmit="wait_msg(true)">
|
||||
{% raw xsrf_form_html() %}
|
||||
<input type="hidden" value="import_jar" name="create_type">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_name">{{ translate('serverWizard', 'serverName', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value="" placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server">{{ translate('serverWizard', 'serverPath', data['lang']) }} <small>{{ translate('serverWizard', 'absoluteServerPath', data['lang']) }}</small></label>
|
||||
<input type="text" class="form-control" id="server_path" name="server_path" placeholder="/var/opt/server" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_jar">{{ translate('serverWizard', 'serverJar', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value="" placeholder="bedrock_server" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<br />
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription', data['lang']) }}</small></h4>
|
||||
<hr>
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="port2">{{ translate('serverWizard', 'serverPort', data['lang']) }} <small></small></label>
|
||||
<input type="number" class="form-control" id="port2" name="port" value="19132" step="1" min="1" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<div id="accordion-2">
|
||||
<div class="card">
|
||||
<div class="card-header p-2" id="Role-2">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-2" aria-expanded="true" aria-controls="collapseRole-2">
|
||||
<i class="fas fa-chevron-down"></i> {{ translate('serverWizard', 'addRole', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'autoCreate', data['lang']) }}</small>
|
||||
</p>
|
||||
</div>
|
||||
<div id="collapseRole-2" class="collapse" aria-labelledby="Role-2" data-parent="">
|
||||
<div class="card-body scroll">
|
||||
<div class="form-group">
|
||||
{% for r in data['roles'] %}
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}" type="checkbox">
|
||||
{{ r['role_name'].capitalize() }}</label></span>
|
||||
{% end %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton', data['lang']) }}</button>
|
||||
<button type="reset" class="btn btn-danger mr-2">{{ translate('serverWizard', 'resetForm', data['lang']) }}</button>
|
||||
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
<h4>{{ translate('serverWizard', 'importZip', data['lang']) }}</h4>
|
||||
<br />
|
||||
<p class="card-description">
|
||||
|
||||
<form name="zip" method="post" class="server-wizard" onSubmit="wait_msg(true)">
|
||||
{% raw xsrf_form_html() %}
|
||||
<input type="hidden" value="import_zip" name="create_type">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_name">{{ translate('serverWizard', 'serverName', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value="" placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server">{{ translate('serverWizard', 'zipPath', data['lang']) }} <small>{{ translate('serverWizard', 'absoluteZipPath', data['lang']) }}</small></label>
|
||||
<input type="text" class="form-control" id="server_path" name="server_path" placeholder="/var/opt/server.zip" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server">{{ translate('serverWizard', 'selectRoot', data['lang']) }} <small>{{ translate('serverWizard', 'explainRoot', data['lang']) }}</small></label>
|
||||
<br>
|
||||
<button class="btn btn-primary mr-2" id="root_files_button" type="button">{{ translate('serverWizard', 'clickRoot', data['lang']) }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_jar">{{ translate('serverWizard', 'serverJar', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value="" placeholder="bedrock_server" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="col-sm-12">
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription', data['lang']) }}</small></h4>
|
||||
<hr>
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="port3">{{ translate('serverWizard', 'serverPort', data['lang']) }} <small></small></label>
|
||||
<input type="number" class="form-control" id="port3" name="port" value="19132" step="1" min="1" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<div id="accordion-3">
|
||||
<div class="card">
|
||||
<div class="card-header p-2" id="Role-3">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-3" aria-expanded="true" aria-controls="collapseRole-3">
|
||||
<i class="fas fa-chevron-down"></i> {{ translate('serverWizard', 'addRole', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'autoCreate', data['lang']) }}</small>
|
||||
</p>
|
||||
</div>
|
||||
<div id="collapseRole-3" class="collapse" aria-labelledby="Role-3" data-parent="">
|
||||
<div class="card-body scroll">
|
||||
<div class="form-group">
|
||||
{% for r in data['roles'] %}
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}" type="checkbox">
|
||||
{{ r['role_name'].capitalize() }}</label></span>
|
||||
{% end %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12" style="visibility: hidden;">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" id="zip_root_path" name="zip_root_path">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="dir_select" tabindex="-1" role="dialog" aria-labelledby="dir_select" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLongTitle">{{ translate('serverWizard', 'selectZipDir', data['lang']) }}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="tree-ctx-item" id="main-tree-div" data-path="" style="overflow: scroll; max-height:75%;">
|
||||
<input type="radio" id="main-tree-input" name="root_path" value="" checked>
|
||||
<span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path="">
|
||||
<i class="far fa-folder"></i>
|
||||
<i class="far fa-folder-open"></i>
|
||||
{{ translate('serverFiles', 'files', data['lang']) }}
|
||||
</span>
|
||||
</input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ translate('serverWizard', 'close', data['lang']) }}</button>
|
||||
<button type="button" id="modal-okay" data-dismiss="modal" class="btn btn-primary">{{ translate('serverWizard', 'save', data['lang']) }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button id="zip_submit" type="submit" title="You must select server root dir first" disabled class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton', data['lang']) }}</button>
|
||||
<button type="reset" class="btn btn-danger mr-2">{{ translate('serverWizard', 'resetForm', data['lang']) }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.scroll {
|
||||
max-height: 12em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.menu-btn {
|
||||
font-size: 0.9em;
|
||||
padding: 2px 10px;
|
||||
}
|
||||
.menu {
|
||||
padding-top: 10px;
|
||||
z-index: 200;
|
||||
margin-top: 4px;
|
||||
position: absolute;
|
||||
background-color: #2a2c44;
|
||||
}
|
||||
.menu-option {
|
||||
padding: 6px 20px 6px;
|
||||
color: white;
|
||||
}
|
||||
#overlay {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 100;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
/* Remove default bullets */
|
||||
.tree-view,
|
||||
.tree-nested {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
/* Style the items */
|
||||
.tree-item,
|
||||
.files-tree-title {
|
||||
cursor: pointer;
|
||||
user-select: none; /* Prevent text selection */
|
||||
}
|
||||
|
||||
/* Create the caret/arrow with a unicode, and style it */
|
||||
.tree-caret .fa-folder {
|
||||
display: inline-block;
|
||||
}
|
||||
.tree-caret .fa-folder-open {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
|
||||
.tree-caret-down .fa-folder {
|
||||
display: none;
|
||||
}
|
||||
.tree-caret-down .fa-folder-open {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Hide the nested list */
|
||||
.tree-nested {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% end %}
|
||||
|
||||
{% block js%}
|
||||
<script>
|
||||
document.getElementById("root_files_button").addEventListener("click", function(){
|
||||
if(document.forms["zip"]["server_path"].value != ""){
|
||||
if(document.getElementById('root_files_button').classList.contains('clicked')){
|
||||
document.getElementById('main-tree-div').innerHTML = '<input type="radio" id="main-tree-input" name="root_path" value="" checked><span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path=""><i class="far fa-folder"></i><i class="far fa-folder-open"></i>{{ translate('serverFiles', 'files', data['lang']) }}</span></input>'
|
||||
}else{
|
||||
document.getElementById('root_files_button').classList.add('clicked')
|
||||
}
|
||||
path = document.forms["zip"]["server_path"].value;
|
||||
console.log(document.forms["zip"]["server_path"].value)
|
||||
var token = getCookie("_xsrf");
|
||||
var dialog = bootbox.dialog({
|
||||
message: '<p class="text-center mb-0"><i class="fa fa-spin fa-cog"></i> Please wait while we gather your files...</p>',
|
||||
closeButton: false
|
||||
});
|
||||
setTimeout(function(){
|
||||
dialog.modal('hide');
|
||||
}, 5000);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: {'X-XSRFToken': token},
|
||||
url: '/ajax/unzip_server?id=-1&path='+path,
|
||||
});
|
||||
}else{
|
||||
bootbox.alert("You must input a path before selecting this button");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function dropDown(event) {
|
||||
event.target.parentElement.children[1].classList.remove("d-none");
|
||||
document.getElementById("overlay").classList.remove("d-none");
|
||||
}
|
||||
function hide(event) {
|
||||
var items = document.getElementsByClassName('menu');
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
items[i].classList.add("d-none");
|
||||
}
|
||||
document.getElementById("overlay").classList.add("d-none");
|
||||
}
|
||||
|
||||
function wait_msg(importing){
|
||||
bootbox.alert({
|
||||
title: importing ? '{% raw translate("serverWizard", "importing", data['lang']) %}' : '{% raw translate("serverWizard", "downloading", data['lang']) %}',
|
||||
message: '<i class="fas fa-cloud-download"></i> {% raw translate("serverWizard", "bePatient", data['lang']) %}',
|
||||
});
|
||||
}
|
||||
|
||||
function show_file_tree(){
|
||||
$("#dir_select").modal();
|
||||
}
|
||||
|
||||
function getTreeView(path) {
|
||||
document.getElementById('zip_submit').disabled = false;
|
||||
path = path
|
||||
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: '/ajax/get_zip_tree?id=-1&path='+path,
|
||||
dataType: 'text',
|
||||
success: function(data){
|
||||
console.log("got response:");
|
||||
console.log(data);
|
||||
|
||||
dataArr = data.split('\n');
|
||||
serverDir = dataArr.shift(); // Remove & return first element (server directory)
|
||||
text = dataArr.join('\n');
|
||||
|
||||
try{
|
||||
document.getElementById('main-tree-div').innerHTML += text;
|
||||
document.getElementById('main-tree').parentElement.classList.add("clicked");
|
||||
}catch{
|
||||
document.getElementById('files-tree').innerHTML = text;
|
||||
}
|
||||
|
||||
|
||||
document.getElementsByClassName('files-tree-title')[0].setAttribute('data-path', serverDir);
|
||||
document.getElementsByClassName('files-tree-title')[0].setAttribute('data-name', 'Files');
|
||||
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function getToggleMain(event) {
|
||||
path = event.target.parentElement.getAttribute('data-path');
|
||||
document.getElementById("files-tree").classList.toggle("d-block");
|
||||
document.getElementById(path+"span").classList.toggle("tree-caret-down");
|
||||
document.getElementById(path+"span").classList.toggle("tree-caret");
|
||||
}
|
||||
|
||||
|
||||
function getDirView(event) {
|
||||
path = event.target.parentElement.getAttribute('data-path');
|
||||
|
||||
if (document.getElementById(path).classList.contains('clicked')){
|
||||
|
||||
var toggler = document.getElementById(path+"span");
|
||||
|
||||
if (toggler.classList.contains('files-tree-title')){
|
||||
document.getElementById(path+"ul").classList.toggle("d-block");
|
||||
document.getElementById(path+"span").classList.toggle("tree-caret-down");
|
||||
}
|
||||
return;
|
||||
}else{
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: '/ajax/get_zip_dir?id=-1&path='+path,
|
||||
dataType: 'text',
|
||||
success: function(data){
|
||||
console.log("got response:");
|
||||
|
||||
dataArr = data.split('\n');
|
||||
serverDir = dataArr.shift(); // Remove & return first element (server directory)
|
||||
text = dataArr.join('\n');
|
||||
|
||||
try{
|
||||
document.getElementById(path+"span").classList.add('tree-caret-down');
|
||||
document.getElementById(path).innerHTML += text;
|
||||
document.getElementById(path).classList.add("clicked");
|
||||
}catch{
|
||||
console.log("Bad")
|
||||
}
|
||||
|
||||
var toggler = document.getElementById(path);
|
||||
|
||||
if (toggler.classList.contains('files-tree-title')){
|
||||
document.getElementById(path+"span").addEventListener("click", function caretListener() {
|
||||
document.getElementById(path+"ul").classList.toggle("d-block");
|
||||
document.getElementById(path+"span").classList.toggle("tree-caret-down");
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
if (webSocket) {
|
||||
webSocket.on('send_temp_path', function (data) {
|
||||
document.getElementById('main-tree-input').setAttribute('value', data.path)
|
||||
getTreeView(data.path);
|
||||
show_file_tree();
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
// array of possible countries in the same order as they appear in the country selection list
|
||||
|
||||
function decodeHtmlCharCodes(str) {
|
||||
return str.replace(""", "\"");
|
||||
}
|
||||
|
||||
function convertHtmlJsonToJavacriptArray(str) {
|
||||
var result = []
|
||||
str = decodeHtmlCharCodes(str)
|
||||
for(var i in str)
|
||||
result.push([i, str [i]]);
|
||||
return result
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
{% end %}
|
File diff suppressed because it is too large
Load Diff
16
app/migrations/20210915205501_server_type.py
Normal file
16
app/migrations/20210915205501_server_type.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Generated by database migrator
|
||||
import peewee
|
||||
|
||||
def migrate(migrator, database, **kwargs):
|
||||
migrator.add_columns('servers', type=peewee.CharField(default="minecraft-java"))
|
||||
"""
|
||||
Write your migrations here.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
def rollback(migrator, database, **kwargs):
|
||||
migrator.drop_columns('servers', ['type'])
|
||||
"""
|
||||
Write your rollback migrations here.
|
||||
"""
|
18
app/migrations/20220223_schedule_reaction.py
Normal file
18
app/migrations/20220223_schedule_reaction.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by database migrator
|
||||
import peewee
|
||||
|
||||
def migrate(migrator, database, **kwargs):
|
||||
migrator.add_columns('schedules', parent=peewee.IntegerField(null=True))
|
||||
migrator.add_columns('schedules', delay=peewee.IntegerField(default=0))
|
||||
"""
|
||||
Write your migrations here.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
def rollback(migrator, database, **kwargs):
|
||||
migrator.drop_columns('schedules', ['parent'])
|
||||
migrator.drop_columns('schedules', ['delay'])
|
||||
"""
|
||||
Write your rollback migrations here.
|
||||
"""
|
16
app/migrations/20220226_server_order.py
Normal file
16
app/migrations/20220226_server_order.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Generated by database migrator
|
||||
import peewee
|
||||
|
||||
def migrate(migrator, database, **kwargs):
|
||||
migrator.add_columns('users', server_order=peewee.CharField(default=''))
|
||||
"""
|
||||
Write your migrations here.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
def rollback(migrator, database, **kwargs):
|
||||
migrator.drop_columns('users', ['server_order'])
|
||||
"""
|
||||
Write your rollback migrations here.
|
||||
"""
|
@ -49,7 +49,7 @@
|
||||
"serverVersion": "Server Version",
|
||||
"selectVersion": "Select a Version",
|
||||
"absoluteServerPath": "Absolute path to your server",
|
||||
"serverJar": "Server Jarfile",
|
||||
"serverJar": "Server Executable File",
|
||||
"minMem": "Minimum Memory",
|
||||
"maxMem": "Maximum Memory",
|
||||
"serverPort": "Server Port",
|
||||
@ -178,6 +178,34 @@
|
||||
"cannotSee": "Not seeing everything?",
|
||||
"cannotSeeOnMobile": "Try clicking on a scheduled task for full details."
|
||||
},
|
||||
"serverScheduleConfig":{
|
||||
"basic": "Basic",
|
||||
"cron": "Cron",
|
||||
"reaction": "Reaction",
|
||||
"start": "Start Server",
|
||||
"restart": "Restart Server",
|
||||
"stop": "Shutdown Server",
|
||||
"backup": "Backup Server",
|
||||
"custom": "Custom Command",
|
||||
"interval": "Interval",
|
||||
"interval-explain": "How often do you want this schedule executed?",
|
||||
"days": "Days",
|
||||
"hours": "Hours",
|
||||
"minutes": "Minutes",
|
||||
"time": "Time",
|
||||
"time-explain": "What time do you want your schedule to execute?",
|
||||
"command": "Command",
|
||||
"command-explain": "What command do you want us to execute? Do not include the '/'",
|
||||
"cron-explain": "Enter your cron string",
|
||||
"offset": "Delay Offset",
|
||||
"offset-explain": "How long should we wait to fire this after firing the first task? (Seconds)",
|
||||
"parent": "Select a parent schedule",
|
||||
"parent-explain": "Which schedule should trigger this one?",
|
||||
"enabled": "Enabled",
|
||||
"one-time": "Delete after execution",
|
||||
"children": "Linked Child Tasks: "
|
||||
|
||||
},
|
||||
"notify":{
|
||||
"supportLogs": "Support Logs",
|
||||
"activityLog": "Activity Logs",
|
||||
|
@ -15,3 +15,4 @@ services:
|
||||
- ./docker/logs:/commander/logs
|
||||
- ./docker/servers:/commander/servers
|
||||
- ./docker/config:/commander/app/config
|
||||
- ./import:/commander/import
|
||||
|
@ -15,3 +15,4 @@ services:
|
||||
- ./logs:/commander/logs
|
||||
- ./servers:/commander/servers
|
||||
- ./config:/commander/app/config
|
||||
- ./import:/commander/import
|
||||
|
Loading…
Reference in New Issue
Block a user