Merge branch 'dev' into tweak/support-logs-zip-comment

This commit is contained in:
Zedifus 2022-08-27 19:00:38 +01:00
commit 51d123e9eb
43 changed files with 1100 additions and 258 deletions

View File

@ -1,11 +1,16 @@
# Changelog
## --- [4.0.11] - 2022/TBD
### New features
TBD
- Add server import status indicators ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/433))
- Users can now be assigned as manager of other users/roles ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/434))
- Add variable shutdown timeouts ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/435))
- Add server metrics graph ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/436))
### Bug fixes
TBD
- Fix creation quota not refilling after server delete ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/434))
- Add missing bedrock dependency (libcurl.so.4) ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/437))
### Tweaks
TBD
- Make imports threaded ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/433))
- Add 'Created By' Field to servers ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/434))
### Lang
TBD
<br><br>

View File

@ -15,6 +15,7 @@ RUN apt-get update \
&& apt-get -y --no-install-recommends install \
sudo \
gcc \
libcurl4 \
python3 \
python3-dev \
python3-pip \

View File

@ -60,26 +60,6 @@ class CraftyPermsController:
permissions_list = PermissionsCrafty.get_permissions(permissions_mask)
return permissions_list
@staticmethod
def add_server_creation(user_id):
"""Increase the "Server Creation" counter for this user
Args:
user_id (int): The modifiable user's ID
Returns:
int: The new count of servers created by this user
"""
return PermissionsCrafty.add_server_creation(user_id)
@staticmethod
def add_user_creation(user_id):
return PermissionsCrafty.add_user_creation(user_id)
@staticmethod
def add_role_creation(user_id):
return PermissionsCrafty.add_role_creation(user_id)
@staticmethod
def get_api_key_permissions_list(key: ApiKeys):
return PermissionsCrafty.get_api_key_permissions_list(key)

View File

@ -64,8 +64,8 @@ class RolesController:
HelperRoles.update_role(role_id, up_data)
@staticmethod
def add_role(role_name):
return HelperRoles.add_role(role_name)
def add_role(role_name, manager):
return HelperRoles.add_role(role_name, manager)
class RoleServerJsonType(t.TypedDict):
server_id: t.Union[str, int]
@ -92,6 +92,7 @@ class RolesController:
def add_role_advanced(
name: str,
servers: t.Iterable[RoleServerJsonType],
manager: int,
) -> int:
"""Add a role with a name and a list of servers
@ -102,7 +103,7 @@ class RolesController:
Returns:
int: The new role's ID
"""
role_id: t.Final[int] = HelperRoles.add_role(name)
role_id: t.Final[int] = HelperRoles.add_role(name, manager)
for server in servers:
PermissionsServers.get_or_create(
role_id, server["server_id"], server["permissions"]
@ -114,6 +115,7 @@ class RolesController:
role_id: t.Union[str, int],
role_name: t.Optional[str],
servers: t.Optional[t.Iterable[RoleServerJsonType]],
manager: int,
) -> None:
"""Update a role with a name and a list of servers
@ -152,6 +154,7 @@ class RolesController:
up_data = {
"role_name": role_name,
"last_update": Helpers.get_time_as_string(),
"manager": manager,
}
# TODO: do the last_update on the db side
HelperRoles.update_role(role_id, up_data)

View File

@ -4,6 +4,7 @@ import time
import json
import pathlib
import typing as t
import datetime
from app.classes.controllers.roles_controller import RolesController
from app.classes.shared.file_helpers import FileHelpers
@ -51,6 +52,7 @@ class ServersController(metaclass=Singleton):
server_log_file: str,
server_stop: str,
server_type: str,
created_by: int,
server_port: int = 25565,
server_host: str = "127.0.0.1",
) -> int:
@ -85,6 +87,7 @@ class ServersController(metaclass=Singleton):
server_log_file,
server_stop,
server_type,
created_by,
server_port,
server_host,
)
@ -102,25 +105,32 @@ class ServersController(metaclass=Singleton):
server_instance.update_server_instance()
return ret
def get_history_stats(self, server_id):
max_age = self.helper.get_setting("history_max_age")
now = datetime.datetime.now()
minimum_to_exist = now - datetime.timedelta(days=max_age)
srv = ServersController().get_server_instance_by_id(server_id)
return srv.stats_helper.get_history_stats(server_id, minimum_to_exist)
@staticmethod
def update_unloaded_server(server_obj):
ret = HelperServers.update_server(server_obj)
return ret
@staticmethod
def set_download(server_id):
def set_import(server_id):
srv = ServersController().get_server_instance_by_id(server_id)
return srv.stats_helper.set_download()
return srv.stats_helper.set_import()
@staticmethod
def finish_download(server_id):
def finish_import(server_id):
srv = ServersController().get_server_instance_by_id(server_id)
return srv.stats_helper.finish_download()
return srv.stats_helper.finish_import()
@staticmethod
def get_download_status(server_id):
def get_import_status(server_id):
server = ServersController().get_server_instance_by_id(server_id)
return server.stats_helper.get_download_status()
return server.stats_helper.get_import_status()
def remove_server(self, server_id):
roles_list = PermissionsServers.get_roles_from_server(server_id)

View File

@ -1,7 +1,9 @@
import logging
import typing as t
from app.classes.models.servers import HelperServers
from app.classes.models.users import HelperUsers
from app.classes.models.roles import HelperRoles
from app.classes.models.crafty_permissions import (
PermissionsCrafty,
EnumPermissionsCrafty,
@ -132,6 +134,18 @@ class UsersController:
def set_support_path(user_id, support_path):
HelperUsers.set_support_path(user_id, support_path)
@staticmethod
def get_managed_users(exec_user_id):
return HelperUsers.get_managed_users(exec_user_id)
@staticmethod
def get_managed_roles(exec_user_id):
return HelperUsers.get_managed_roles(exec_user_id)
@staticmethod
def get_created_servers(exec_user_id):
return HelperServers.get_total_owned_servers(exec_user_id)
def update_user(self, user_id: str, user_data=None, user_crafty_data=None):
if user_crafty_data is None:
user_crafty_data = {}
@ -206,6 +220,7 @@ class UsersController:
def add_user(
self,
username,
manager,
password,
email="default@example.com",
enabled: bool = True,
@ -213,6 +228,7 @@ class UsersController:
):
return self.users_helper.add_user(
username,
manager,
password=password,
email=email,
enabled=enabled,
@ -236,6 +252,10 @@ class UsersController:
)
def remove_user(self, user_id):
for user in self.get_managed_users(user_id):
self.update_user(user.user_id, {"manager": None})
for role in HelperUsers.get_managed_roles(user_id):
HelperRoles.update_role(role.role_id, {"manager": None})
return self.users_helper.remove_user(user_id)
@staticmethod

View File

@ -175,7 +175,7 @@ class ServerJars:
# we submit a db update for it's stats.
while True:
try:
ServersController.set_download(server_id)
ServersController.set_import(server_id)
for user in server_users:
self.helper.websocket_helper.broadcast_user(
user, "send_start_reload", {}
@ -190,7 +190,7 @@ class ServerJars:
try:
with open(path, "wb") as output:
shutil.copyfileobj(r.raw, output)
ServersController.finish_download(server_id)
ServersController.finish_import(server_id)
for user in server_users:
self.helper.websocket_helper.broadcast_user(
@ -203,7 +203,7 @@ class ServerJars:
return True
except Exception as e:
logger.error(f"Unable to save jar to {path} due to error:{e}")
ServersController.finish_download(server_id)
ServersController.finish_import(server_id)
server_users = PermissionsServers.get_server_user_list(server_id)
for user in server_users:
self.helper.websocket_helper.broadcast_user(

View File

@ -9,6 +9,7 @@ from peewee import (
)
from app.classes.models.base_model import BaseModel
from app.classes.models.servers import HelperServers
from app.classes.models.users import Users, ApiKeys, HelperUsers
from app.classes.shared.permission_helper import PermissionHelper
@ -23,9 +24,6 @@ class UserCrafty(BaseModel):
limit_server_creation = IntegerField(default=-1)
limit_user_creation = IntegerField(default=0)
limit_role_creation = IntegerField(default=0)
created_server = IntegerField(default=0)
created_user = IntegerField(default=0)
created_role = IntegerField(default=0)
class Meta:
table_name = "user_crafty"
@ -107,9 +105,6 @@ class PermissionsCrafty:
UserCrafty.limit_server_creation: 0,
UserCrafty.limit_user_creation: 0,
UserCrafty.limit_role_creation: 0,
UserCrafty.created_server: 0,
UserCrafty.created_user: 0,
UserCrafty.created_role: 0,
}
).execute()
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
@ -159,11 +154,16 @@ class PermissionsCrafty:
@staticmethod
def get_created_quantity_list(user_id):
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
quantity_list = {
EnumPermissionsCrafty.SERVER_CREATION.name: user_crafty.created_server,
EnumPermissionsCrafty.USER_CONFIG.name: user_crafty.created_user,
EnumPermissionsCrafty.ROLES_CONFIG.name: user_crafty.created_role,
EnumPermissionsCrafty.SERVER_CREATION.name: HelperServers.get_total_owned_servers( # pylint: disable=line-too-long
user_id
),
EnumPermissionsCrafty.USER_CONFIG.name: HelperUsers.get_managed_users(
user_id
).count(),
EnumPermissionsCrafty.ROLES_CONFIG.name: HelperUsers.get_managed_roles(
user_id
).count(),
}
return quantity_list
@ -183,31 +183,6 @@ class PermissionsCrafty:
or limit_list[permission.name] == -1
)
@staticmethod
def add_server_creation(user_id: int):
"""Increase the "Server Creation" counter for this user
Args:
user_id (int): The modifiable user's ID
"""
UserCrafty.update(created_server=UserCrafty.created_server + 1).where(
UserCrafty.user_id == user_id
).execute()
@staticmethod
def add_user_creation(user_id):
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
user_crafty.created_user += 1
UserCrafty.save(user_crafty)
return user_crafty.created_user
@staticmethod
def add_role_creation(user_id):
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
user_crafty.created_role += 1
UserCrafty.save(user_crafty)
return user_crafty.created_role
@staticmethod
def get_api_key_permissions_list(key: ApiKeys):
user = HelperUsers.get_user(key.user_id)

View File

@ -6,6 +6,7 @@ from peewee import (
DoesNotExist,
AutoField,
DateTimeField,
IntegerField,
)
from playhouse.shortcuts import model_to_dict
@ -22,6 +23,7 @@ class Roles(BaseModel):
created = DateTimeField(default=datetime.datetime.now)
last_update = DateTimeField(default=datetime.datetime.now)
role_name = CharField(default="", unique=True, index=True)
manager = IntegerField(null=True)
class Meta:
table_name = "roles"
@ -71,11 +73,12 @@ class HelperRoles:
)
@staticmethod
def add_role(role_name):
def add_role(role_name, manager):
role_id = Roles.insert(
{
Roles.role_name: role_name.lower(),
Roles.created: Helpers.get_time_as_string(),
Roles.manager: manager,
}
).execute()
return role_id

View File

@ -53,7 +53,7 @@ class ServerStats(Model):
waiting_start = BooleanField(default=False)
first_run = BooleanField(default=True)
crashed = BooleanField(default=False)
downloading = BooleanField(default=False)
importing = BooleanField(default=False)
class Meta:
table_name = "server_stats"
@ -137,6 +137,14 @@ class HelperServerStats:
)
return server_data
def get_history_stats(self, server_id, max_age):
return (
ServerStats.select()
.where(ServerStats.created > max_age)
.where(ServerStats.server_id == server_id)
.execute(self.database)
)
def insert_server_stats(self, server_stats):
server_id = server_stats.get("id", 0)
@ -207,26 +215,26 @@ class HelperServerStats:
ServerStats.server_id == self.server_id
).execute(self.database)
def set_download(self):
def set_import(self):
# self.select_database(self.server_id)
ServerStats.update(downloading=True).where(
ServerStats.update(importing=True).where(
ServerStats.server_id == self.server_id
).execute(self.database)
def finish_download(self):
def finish_import(self):
# self.select_database(self.server_id)
ServerStats.update(downloading=False).where(
ServerStats.update(importing=False).where(
ServerStats.server_id == self.server_id
).execute(self.database)
def get_download_status(self):
def get_import_status(self):
# self.select_database(self.server_id)
download_status = (
import_status = (
ServerStats.select()
.where(ServerStats.server_id == self.server_id)
.get(self.database)
)
return download_status.downloading
return import_status.importing
def server_crash_reset(self):
if self.server_id is None:
@ -249,7 +257,6 @@ class HelperServerStats:
def set_update(self, value):
if self.server_id is None:
return
# self.select_database(self.server_id)
try:
# Checks if server even exists

View File

@ -38,6 +38,8 @@ class Servers(BaseModel):
logs_delete_after = IntegerField(default=0)
type = CharField(default="minecraft-java")
show_status = BooleanField(default=1)
created_by = IntegerField(default=-100)
shutdown_timeout = IntegerField(default=60)
class Meta:
table_name = "servers"
@ -64,6 +66,7 @@ class HelperServers:
server_log_file: str,
server_stop: str,
server_type: str,
created_by: int,
server_port: int = 25565,
server_host: str = "127.0.0.1",
) -> int:
@ -105,6 +108,7 @@ class HelperServers:
Servers.stop_command: server_stop,
Servers.backup_path: backup_path,
Servers.type: server_type,
Servers.created_by: created_by,
}
).execute()
@ -112,6 +116,10 @@ class HelperServers:
def get_server_obj(server_id):
return Servers.get_by_id(server_id)
@staticmethod
def get_total_owned_servers(user_id):
return Servers.select().where(Servers.created_by == user_id).count()
@staticmethod
def get_server_type_by_id(server_id):
server_type = Servers.select().where(Servers.server_id == server_id).get()

View File

@ -6,6 +6,7 @@ from peewee import (
ForeignKeyField,
CharField,
AutoField,
IntegerField,
DateTimeField,
BooleanField,
CompositeKey,
@ -40,6 +41,7 @@ class Users(BaseModel):
server_order = CharField(default="")
preparing = BooleanField(default=False)
hints = BooleanField(default=True)
manager = IntegerField(default=None, null=True)
class Meta:
table_name = "users"
@ -138,6 +140,16 @@ class HelperUsers:
user_query = Users.select().where(Users.user_id == user_id)
return user_query
@staticmethod
def get_managed_users(exec_user_id):
user_query = Users.select().where(Users.manager == exec_user_id)
return user_query
@staticmethod
def get_managed_roles(exec_user_id):
roles_query = Roles.select().where(Roles.manager == exec_user_id)
return roles_query
@staticmethod
def get_user(user_id):
if user_id == 0:
@ -192,6 +204,7 @@ class HelperUsers:
def add_user(
self,
username: str,
manager: str,
password: str = None,
email: t.Optional[str] = None,
enabled: bool = True,
@ -209,6 +222,7 @@ class HelperUsers:
Users.enabled: enabled,
Users.superuser: superuser,
Users.created: Helpers.get_time_as_string(),
Users.manager: manager,
}
).execute()
return user_id
@ -229,6 +243,7 @@ class HelperUsers:
Users.enabled: enabled,
Users.superuser: superuser,
Users.created: Helpers.get_time_as_string(),
Users.manager: None,
}
).execute()
return user_id

View File

@ -27,10 +27,15 @@ class FileHelpers:
FileHelpers.del_dirs(sub)
else:
# Delete file if it is a file:
try:
sub.unlink()
except:
logger.error(f"Unable to delete file {sub}")
try:
# This removes the top-level folder:
path.rmdir()
except:
logger.error("Unable to remove top level")
return True
@staticmethod

View File

@ -0,0 +1,216 @@
import os
import time
import shutil
import logging
import threading
from app.classes.controllers.server_perms_controller import PermissionsServers
from app.classes.controllers.servers_controller import ServersController
from app.classes.shared.helpers import Helpers
from app.classes.shared.file_helpers import FileHelpers
logger = logging.getLogger(__name__)
class ImportHelpers:
allowed_quotes = ['"', "'", "`"]
def __init__(self, helper, file_helper):
self.file_helper: FileHelpers = file_helper
self.helper: Helpers = helper
def import_jar_server(self, server_path, new_server_dir, port, new_id):
import_thread = threading.Thread(
target=self.import_threaded_jar_server,
daemon=True,
args=(server_path, new_server_dir, port, new_id),
name=f"{new_id}_import",
)
import_thread.start()
def import_threaded_jar_server(self, server_path, new_server_dir, port, new_id):
for item in os.listdir(server_path):
if not item == "db_stats":
try:
if os.path.isdir(os.path.join(server_path, item)):
FileHelpers.copy_dir(
os.path.join(server_path, item),
os.path.join(new_server_dir, item),
)
else:
FileHelpers.copy_file(
os.path.join(server_path, item),
os.path.join(new_server_dir, item),
)
except shutil.Error as ex:
logger.error(f"Server import failed with error: {ex}")
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. "
f"Creating one with port selection of {str(port)}"
)
with open(
os.path.join(new_server_dir, "server.properties"), "w", encoding="utf-8"
) as file:
file.write(f"server-port={port}")
file.close()
time.sleep(5)
ServersController.finish_import(new_id)
server_users = PermissionsServers.get_server_user_list(new_id)
for user in server_users:
self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {})
def import_java_zip_server(self, temp_dir, new_server_dir, port, new_id):
import_thread = threading.Thread(
target=self.import_threaded_java_zip_server,
daemon=True,
args=(temp_dir, new_server_dir, port, new_id),
name=f"{new_id}_java_zip_import",
)
import_thread.start()
def import_threaded_java_zip_server(self, temp_dir, new_server_dir, port, new_id):
has_properties = False
# extracts archive to temp directory
for item in os.listdir(temp_dir):
if str(item) == "server.properties":
has_properties = True
try:
if not os.path.isdir(os.path.join(temp_dir, item)):
FileHelpers.move_file(
os.path.join(temp_dir, item), os.path.join(new_server_dir, item)
)
else:
if item != "db_stats":
FileHelpers.move_dir(
os.path.join(temp_dir, 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. "
f"Creating one with port selection of {str(port)}"
)
with open(
os.path.join(new_server_dir, "server.properties"), "w", encoding="utf-8"
) as file:
file.write(f"server-port={port}")
file.close()
server_users = PermissionsServers.get_server_user_list(new_id)
ServersController.finish_import(new_id)
for user in server_users:
self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {})
# deletes temp dir
FileHelpers.del_dirs(temp_dir)
def import_bedrock_server(
self, server_path, new_server_dir, port, full_jar_path, new_id
):
import_thread = threading.Thread(
target=self.import_threaded_bedrock_server,
daemon=True,
args=(server_path, new_server_dir, port, full_jar_path, new_id),
name=f"{new_id}_bedrock_import",
)
import_thread.start()
def import_threaded_bedrock_server(
self, server_path, new_server_dir, port, full_jar_path, new_id
):
for item in os.listdir(server_path):
if not item == "db_stats":
try:
if os.path.isdir(os.path.join(server_path, item)):
FileHelpers.copy_dir(
os.path.join(server_path, item),
os.path.join(new_server_dir, item),
)
else:
FileHelpers.copy_file(
os.path.join(server_path, item),
os.path.join(new_server_dir, item),
)
except shutil.Error as ex:
logger.error(f"Server import failed with error: {ex}")
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. "
f"Creating one with port selection of {str(port)}"
)
with open(
os.path.join(new_server_dir, "server.properties"), "w", encoding="utf-8"
) as file:
file.write(f"server-port={port}")
file.close()
if os.name != "nt":
if Helpers.check_file_exists(full_jar_path):
os.chmod(full_jar_path, 0o2760)
ServersController.finish_import(new_id)
server_users = PermissionsServers.get_server_user_list(new_id)
for user in server_users:
self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {})
def import_bedrock_zip_server(
self, temp_dir, new_server_dir, full_jar_path, port, new_id
):
import_thread = threading.Thread(
target=self.import_threaded_bedrock_zip_server,
daemon=True,
args=(temp_dir, new_server_dir, full_jar_path, port, new_id),
name=f"{new_id}_bedrock_import",
)
import_thread.start()
def import_threaded_bedrock_zip_server(
self, temp_dir, new_server_dir, full_jar_path, port, new_id
):
has_properties = False
# extracts archive to temp directory
for item in os.listdir(temp_dir):
if str(item) == "server.properties":
has_properties = True
try:
if not os.path.isdir(os.path.join(temp_dir, item)):
FileHelpers.move_file(
os.path.join(temp_dir, item), os.path.join(new_server_dir, item)
)
else:
if item != "db_stats":
FileHelpers.move_dir(
os.path.join(temp_dir, 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. "
f"Creating one with port selection of {str(port)}"
)
with open(
os.path.join(new_server_dir, "server.properties"), "w", encoding="utf-8"
) as file:
file.write(f"server-port={port}")
file.close()
ServersController.finish_import(new_id)
server_users = PermissionsServers.get_server_user_list(new_id)
for user in server_users:
self.helper.websocket_helper.broadcast_user(user, "send_start_reload", {})
if os.name != "nt":
if Helpers.check_file_exists(full_jar_path):
os.chmod(full_jar_path, 0o2760)
# deletes temp dir
FileHelpers.del_dirs(temp_dir)

View File

@ -29,15 +29,17 @@ from app.classes.shared.authentication import Authentication
from app.classes.shared.console import Console
from app.classes.shared.helpers import Helpers
from app.classes.shared.file_helpers import FileHelpers
from app.classes.shared.import_helper import ImportHelpers
from app.classes.minecraft.serverjars import ServerJars
logger = logging.getLogger(__name__)
class Controller:
def __init__(self, database, helper, file_helper):
def __init__(self, database, helper, file_helper, import_helper):
self.helper: Helpers = helper
self.file_helper: FileHelpers = file_helper
self.import_helper: ImportHelpers = import_helper
self.server_jars: ServerJars = ServerJars(helper)
self.users_helper: HelperUsers = HelperUsers(database, self.helper)
self.roles_helper: HelperRoles = HelperRoles(database)
@ -247,7 +249,7 @@ class Controller:
except:
return {"percent": 0, "total_files": 0}
def create_api_server(self, data: dict):
def create_api_server(self, data: dict, user_id):
server_fs_uuid = Helpers.create_uuid()
new_server_path = os.path.join(self.helper.servers_dir, server_fs_uuid)
backup_path = os.path.join(self.helper.backup_path, server_fs_uuid)
@ -310,7 +312,9 @@ class Controller:
# TODO: Copy files from the zip file to the new server directory
server_file = create_data["jarfile"]
raise Exception("Not yet implemented")
_create_server_properties_if_needed(create_data["server_properties_port"])
_create_server_properties_if_needed(
create_data["server_properties_port"],
)
min_mem = create_data["mem_min"]
max_mem = create_data["mem_max"]
@ -406,6 +410,7 @@ class Controller:
server_log_file=log_location,
server_stop=stop_command,
server_port=monitoring_port,
created_by=user_id,
server_host=monitoring_host,
server_type=monitoring_type,
)
@ -432,6 +437,7 @@ class Controller:
min_mem: int,
max_mem: int,
port: int,
user_id: int,
):
server_id = Helpers.create_uuid()
server_dir = os.path.join(self.helper.servers_dir, server_id)
@ -492,6 +498,7 @@ class Controller:
server_log_file,
server_stop,
port,
user_id,
server_type="minecraft-java",
)
@ -527,6 +534,7 @@ class Controller:
min_mem: int,
max_mem: int,
port: int,
user_id: int,
):
server_id = Helpers.create_uuid()
new_server_dir = os.path.join(self.helper.servers_dir, server_id)
@ -540,25 +548,6 @@ class Controller:
Helpers.ensure_dir_exists(new_server_dir)
Helpers.ensure_dir_exists(backup_path)
server_path = Helpers.get_os_understandable_path(server_path)
try:
FileHelpers.copy_dir(server_path, new_server_dir, True)
except shutil.Error as ex:
logger.error(f"Server import failed with error: {ex}")
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. "
f"Creating one with port selection of {str(port)}"
)
with open(
os.path.join(new_server_dir, "server.properties"), "w", encoding="utf-8"
) as file:
file.write(f"server-port={port}")
file.close()
full_jar_path = os.path.join(new_server_dir, server_jar)
@ -587,8 +576,11 @@ class Controller:
server_log_file,
server_stop,
port,
user_id,
server_type="minecraft-java",
)
ServersController.set_import(new_id)
self.import_helper.import_jar_server(server_path, new_server_dir, port, new_id)
return new_id
def import_zip_server(
@ -599,6 +591,7 @@ class Controller:
min_mem: int,
max_mem: int,
port: int,
user_id: int,
):
server_id = Helpers.create_uuid()
new_server_dir = os.path.join(self.helper.servers_dir, server_id)
@ -612,32 +605,6 @@ class Controller:
temp_dir = Helpers.get_os_understandable_path(zip_path)
Helpers.ensure_dir_exists(new_server_dir)
Helpers.ensure_dir_exists(backup_path)
has_properties = False
# extracts archive to temp directory
for item in os.listdir(temp_dir):
if str(item) == "server.properties":
has_properties = True
try:
if not os.path.isdir(os.path.join(temp_dir, item)):
FileHelpers.move_file(
os.path.join(temp_dir, item), os.path.join(new_server_dir, item)
)
else:
FileHelpers.move_dir(
os.path.join(temp_dir, 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. "
f"Creating one with port selection of {str(port)}"
)
with open(
os.path.join(new_server_dir, "server.properties"), "w", encoding="utf-8"
) as file:
file.write(f"server-port={port}")
file.close()
full_jar_path = os.path.join(new_server_dir, server_jar)
@ -667,8 +634,13 @@ class Controller:
server_log_file,
server_stop,
port,
user_id,
server_type="minecraft-java",
)
ServersController.set_import(new_id)
self.import_helper.import_java_zip_server(
temp_dir, new_server_dir, port, new_id
)
return new_id
# **********************************************************************************
@ -676,7 +648,12 @@ class Controller:
# **********************************************************************************
def import_bedrock_server(
self, server_name: str, server_path: str, server_exe: str, port: int
self,
server_name: str,
server_path: str,
server_exe: str,
port: int,
user_id: int,
):
server_id = Helpers.create_uuid()
new_server_dir = os.path.join(self.helper.servers_dir, server_id)
@ -690,25 +667,6 @@ class Controller:
Helpers.ensure_dir_exists(new_server_dir)
Helpers.ensure_dir_exists(backup_path)
server_path = Helpers.get_os_understandable_path(server_path)
try:
FileHelpers.copy_dir(server_path, new_server_dir, True)
except shutil.Error as ex:
logger.error(f"Server import failed with error: {ex}")
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. "
f"Creating one with port selection of {str(port)}"
)
with open(
os.path.join(new_server_dir, "server.properties"), "w", encoding="utf-8"
) as file:
file.write(f"server-port={port}")
file.close()
full_jar_path = os.path.join(new_server_dir, server_exe)
@ -730,15 +688,22 @@ class Controller:
server_log_file,
server_stop,
port,
user_id,
server_type="minecraft-bedrock",
)
if os.name != "nt":
if Helpers.check_file_exists(full_jar_path):
os.chmod(full_jar_path, 0o2760)
ServersController.set_import(new_id)
self.import_helper.import_bedrock_server(
server_path, new_server_dir, port, full_jar_path, new_id
)
return new_id
def import_bedrock_zip_server(
self, server_name: str, zip_path: str, server_exe: str, port: int
self,
server_name: str,
zip_path: str,
server_exe: str,
port: int,
user_id: int,
):
server_id = Helpers.create_uuid()
new_server_dir = os.path.join(self.helper.servers_dir, server_id)
@ -752,32 +717,6 @@ class Controller:
temp_dir = Helpers.get_os_understandable_path(zip_path)
Helpers.ensure_dir_exists(new_server_dir)
Helpers.ensure_dir_exists(backup_path)
has_properties = False
# extracts archive to temp directory
for item in os.listdir(temp_dir):
if str(item) == "server.properties":
has_properties = True
try:
if not os.path.isdir(os.path.join(temp_dir, item)):
FileHelpers.move_file(
os.path.join(temp_dir, item), os.path.join(new_server_dir, item)
)
else:
FileHelpers.move_dir(
os.path.join(temp_dir, 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. "
f"Creating one with port selection of {str(port)}"
)
with open(
os.path.join(new_server_dir, "server.properties"), "w", encoding="utf-8"
) as file:
file.write(f"server-port={port}")
file.close()
full_jar_path = os.path.join(new_server_dir, server_exe)
@ -799,8 +738,12 @@ class Controller:
server_log_file,
server_stop,
port,
user_id,
server_type="minecraft-bedrock",
)
self.import_helper.import_bedrock_zip_server(
temp_dir, new_server_dir, full_jar_path, port, new_id
)
if os.name != "nt":
if Helpers.check_file_exists(full_jar_path):
os.chmod(full_jar_path, 0o2760)
@ -841,6 +784,7 @@ class Controller:
server_log_file: str,
server_stop: str,
server_port: int,
created_by: int,
server_type: str,
server_host: str = "127.0.0.1",
):
@ -855,6 +799,7 @@ class Controller:
server_log_file,
server_stop,
server_type,
created_by,
server_port,
server_host,
)

View File

@ -26,6 +26,7 @@ class DatabaseBuilder:
password=password,
email="default@example.com",
superuser=True,
manager=None,
)
def is_fresh_install(self):

View File

@ -293,7 +293,7 @@ class ServerInstance:
else:
user_lang = HelperUsers.get_user_lang_by_id(user_id)
if self.stats_helper.get_download_status():
if self.stats_helper.get_import_status():
if user_id:
self.helper.websocket_helper.broadcast_user(
user_id,
@ -612,12 +612,16 @@ class ServerInstance:
# caching the name and pid number
server_name = self.name
server_pid = self.process.pid
self.shutdown_timeout = self.settings["shutdown_timeout"]
while running:
i += 1
ttk = int(self.shutdown_timeout - (i * 2))
if i <= self.shutdown_timeout / 2:
logstr = (
f"Server {server_name} is still running "
f"- waiting 2s to see if it stops ({int(60-(i*2))} "
"- waiting 2s to see if it stops"
f"({ttk} "
f"seconds until force close)"
)
logger.info(logstr)
@ -626,7 +630,7 @@ class ServerInstance:
time.sleep(2)
# if we haven't closed in 60 seconds, let's just slam down on the PID
if i >= 30:
if i >= round(self.shutdown_timeout / 2, 0):
logger.info(
f"Server {server_name} is still running - Forcing the process down"
)
@ -1223,6 +1227,7 @@ class ServerInstance:
"version": raw_ping_result.get("version"),
"icon": raw_ping_result.get("icon"),
"crashed": self.is_crashed,
"created": datetime.datetime.now().strftime("%Y/%m/%d, %H:%M:%S"),
},
)
total_players += int(raw_ping_result.get("online"))

View File

@ -394,6 +394,7 @@ class AjaxHandler(BaseHandler):
"1",
"2",
server_data["server_port"],
server_data["created_by"],
)
new_server_id = new_server
new_server = self.controller.servers.get_server_data(new_server)
@ -416,6 +417,7 @@ class AjaxHandler(BaseHandler):
temp_dir,
server_data["executable"],
server_data["server_port"],
server_data["created_by"],
)
new_server_id = new_server
new_server = self.controller.servers.get_server_data(new_server)

View File

@ -340,10 +340,11 @@ class CreateUser(ApiHandler):
new_username = self.get_argument("username").lower()
new_pass = self.get_argument("password")
manager = int(user_obj["user_id"])
if new_username:
self.controller.users.add_user(
new_username, new_pass, "default@example.com", True, False
new_username, manager, new_pass, "default@example.com", True, False
)
self.return_response(

View File

@ -453,8 +453,8 @@ class PanelHandler(BaseHandler):
for server in un_used_servers[:]:
if flag == 0:
server["stats"][
"downloading"
] = self.controller.servers.get_download_status(
"importing"
] = self.controller.servers.get_import_status(
str(server["stats"]["server_id"]["server_id"])
)
server["stats"]["crashed"] = self.controller.servers.is_crashed(
@ -524,6 +524,7 @@ class PanelHandler(BaseHandler):
"files",
"admin_controls",
"schedules",
"metrics",
]
if not self.failed_server:
server = self.controller.servers.get_server_instance_by_id(server_id)
@ -571,11 +572,11 @@ class PanelHandler(BaseHandler):
"started": "False",
}
if not self.failed_server:
page_data["downloading"] = self.controller.servers.get_download_status(
page_data["importing"] = self.controller.servers.get_import_status(
server_id
)
else:
page_data["downloading"] = False
page_data["importing"] = False
page_data["server_id"] = server_id
try:
page_data["waiting_start"] = self.controller.servers.get_waiting_start(
@ -754,6 +755,11 @@ class PanelHandler(BaseHandler):
page_data["backup_list"] = []
page_data["backup_path"] = Helpers.wtol_path(server_info["backup_path"])
if subpage == "metrics":
page_data["history_stats"] = self.controller.servers.get_history_stats(
server_id
)
def get_banned_players_html():
banned_players = self.controller.servers.get_banned_players(server_id)
if banned_players is None:
@ -860,6 +866,18 @@ class PanelHandler(BaseHandler):
page_data["users"] = self.controller.users.get_all_users()
page_data["roles"] = self.controller.roles.get_all_roles()
page_data["auth-servers"][user.user_id] = super_auth_servers
page_data["managed_users"] = []
else:
page_data["managed_users"] = self.controller.users.get_managed_users(
exec_user["user_id"]
)
page_data["assigned_roles"] = []
for item in page_data["roles"]:
page_data["assigned_roles"].append(item.role_id)
page_data["managed_roles"] = self.controller.users.get_managed_roles(
exec_user["user_id"]
)
template = "panel/panel_config.html"
@ -885,7 +903,7 @@ class PanelHandler(BaseHandler):
)
return
page_data["roles_all"] = self.controller.roles.get_all_roles()
page_data["roles"] = self.controller.roles.get_all_roles()
page_data["servers"] = []
page_data["servers_all"] = self.controller.servers.get_all_defined_servers()
page_data["role-servers"] = []
@ -904,8 +922,16 @@ class PanelHandler(BaseHandler):
)
if superuser:
page_data["super-disabled"] = ""
page_data["users"] = self.controller.users.get_all_users()
else:
page_data["super-disabled"] = "disabled"
page_data["exec_user"] = exec_user["user_id"]
page_data["manager"] = {
"user_id": -100,
"username": "None",
}
for file in sorted(
os.listdir(os.path.join(self.helper.root_dir, "app", "translations"))
):
@ -1074,9 +1100,21 @@ class PanelHandler(BaseHandler):
page_data["user"] = self.controller.users.get_user_by_id(user_id)
page_data["servers"] = set()
page_data["role-servers"] = page_role_servers
page_data["roles_all"] = self.controller.roles.get_all_roles()
page_data["roles"] = self.controller.roles.get_all_roles()
page_data["exec_user"] = exec_user["user_id"]
page_data["servers_all"] = self.controller.servers.get_all_defined_servers()
page_data["superuser"] = superuser
if page_data["user"]["manager"] is not None:
page_data["manager"] = self.controller.users.get_user_by_id(
page_data["user"]["manager"]
)
else:
page_data["manager"] = {
"user_id": -100,
"username": "None",
}
if exec_user["superuser"]:
page_data["users"] = self.controller.users.get_all_users()
page_data[
"permissions_all"
] = self.controller.crafty_perms.list_defined_crafty_permissions()
@ -1115,6 +1153,17 @@ class PanelHandler(BaseHandler):
"/panel/error?error=Unauthorized access: not a user editor"
)
return
if (
(
self.controller.users.get_user_by_id(user_id)["manager"]
!= exec_user["user_id"]
)
and not exec_user["superuser"]
and str(exec_user["user_id"]) != str(user_id)
):
self.redirect(
"/panel/error?error=Unauthorized access: you cannot edit this user"
)
page_data["servers"] = []
page_data["role-servers"] = []
@ -1212,6 +1261,11 @@ class PanelHandler(BaseHandler):
defined_servers = self.controller.servers.get_authorized_servers(
exec_user["user_id"]
)
page_data["role_manager"] = {
"user_id": -100,
"username": "None",
}
page_servers = []
for server in defined_servers:
if server not in page_servers:
@ -1229,6 +1283,7 @@ class PanelHandler(BaseHandler):
user_roles = self.get_user_roles()
page_data["new_role"] = False
role_id = self.get_argument("id", None)
role = self.controller.roles.get_role(role_id)
page_data["role"] = self.controller.roles.get_role_with_servers(role_id)
if exec_user["superuser"]:
defined_servers = self.controller.servers.list_defined_servers()
@ -1252,7 +1307,21 @@ class PanelHandler(BaseHandler):
page_data["user-roles"] = user_roles
page_data["users"] = self.controller.users.get_all_users()
if EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions:
if page_data["role"]["manager"] is not None:
page_data["role_manager"] = self.controller.users.get_user_by_id(
page_data["role"]["manager"]
)
else:
page_data["role_manager"] = {
"user_id": -100,
"username": "None",
}
if (
EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions
or exec_user["user_id"] != role["manager"]
and not exec_user["superuser"]
):
self.redirect(
"/panel/error?error=Unauthorized access: not a role editor"
)
@ -1266,8 +1335,15 @@ class PanelHandler(BaseHandler):
elif page == "remove_role":
role_id = bleach.clean(self.get_argument("id", None))
if not superuser:
self.redirect("/panel/error?error=Unauthorized access: not superuser")
if (
not superuser
and self.controller.roles.get_role(role_id)["manager"]
!= exec_user["user_id"]
):
self.redirect(
"/panel/error?error=Unauthorized access: not superuser not"
" role manager"
)
return
if role_id is None:
self.redirect("/panel/error?error=Invalid Role ID")
@ -1418,6 +1494,7 @@ class PanelHandler(BaseHandler):
return
server_name = self.get_argument("server_name", None)
server_obj = self.controller.servers.get_server_obj(server_id)
shutdown_timeout = self.get_argument("shutdown_timeout", 60)
if superuser:
server_path = self.get_argument("server_path", None)
if Helpers.is_os_windows():
@ -1498,6 +1575,7 @@ class PanelHandler(BaseHandler):
)
server_obj.server_name = server_name
server_obj.shutdown_timeout = shutdown_timeout
if superuser:
if Helpers.validate_traversal(
self.helper.get_servers_root_dir(), server_path
@ -1930,6 +2008,7 @@ class PanelHandler(BaseHandler):
"system user is not editable"
)
user_id = bleach.clean(self.get_argument("id", None))
user = self.controller.users.get_user_by_id(user_id)
username = bleach.clean(self.get_argument("username", None).lower())
if (
username != self.controller.users.get_user_by_id(user_id)["username"]
@ -1962,7 +2041,19 @@ class PanelHandler(BaseHandler):
else:
superuser = 0
if not exec_user["superuser"]:
if exec_user["superuser"]:
manager = self.get_argument("manager")
if manager == "":
manager = None
else:
manager = int(manager)
else:
manager = user["manager"]
if (
not exec_user["superuser"]
and int(exec_user["user_id"]) != user["manager"]
):
if username is None or username == "":
self.redirect("/panel/error?error=Invalid username")
return
@ -2013,6 +2104,7 @@ class PanelHandler(BaseHandler):
user_data = {
"username": username,
"manager": manager,
"password": password0,
"email": email,
"enabled": enabled,
@ -2158,6 +2250,15 @@ class PanelHandler(BaseHandler):
if username is None or username == "":
self.redirect("/panel/error?error=Invalid username")
return
if exec_user["superuser"]:
manager = self.get_argument("manager")
if manager == "":
manager = None
else:
manager = int(manager)
else:
manager = int(exec_user["user_id"])
# does this user id exist?
if self.controller.users.get_id_by_name(username) is not None:
self.redirect("/panel/error?error=User exists")
@ -2172,6 +2273,7 @@ class PanelHandler(BaseHandler):
user_id = self.controller.users.add_user(
username,
manager=manager,
password=password0,
email=email,
enabled=enabled,
@ -2198,14 +2300,19 @@ class PanelHandler(BaseHandler):
server_id=0,
source_ip=self.get_remote_ip(),
)
self.controller.crafty_perms.add_user_creation(exec_user["user_id"])
self.redirect("/panel/panel_config")
elif page == "edit_role":
role_id = bleach.clean(self.get_argument("id", None))
role_name = bleach.clean(self.get_argument("role_name", None))
if EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions:
role = self.controller.roles.get_role(role_id)
if (
EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions
and exec_user["user_id"] != role["manager"]
and not exec_user["superuser"]
):
self.redirect(
"/panel/error?error=Unauthorized access: not a role editor"
)
@ -2221,9 +2328,18 @@ class PanelHandler(BaseHandler):
self.redirect("/panel/error?error=Invalid Role ID")
return
if exec_user["superuser"]:
manager = self.get_argument("manager", None)
if manager == "":
manager = None
else:
manager = role["manager"]
servers = self.get_role_servers()
self.controller.roles.update_role_advanced(role_id, role_name, servers)
self.controller.roles.update_role_advanced(
role_id, role_name, servers, manager
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
@ -2235,6 +2351,12 @@ class PanelHandler(BaseHandler):
elif page == "add_role":
role_name = bleach.clean(self.get_argument("role_name", None))
if exec_user["superuser"]:
manager = self.get_argument("manager", None)
if manager == "":
manager = None
else:
manager = exec_user["user_id"]
if EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions:
self.redirect(
@ -2259,7 +2381,9 @@ class PanelHandler(BaseHandler):
servers = self.get_role_servers()
role_id = self.controller.roles.add_role_advanced(role_name, servers)
role_id = self.controller.roles.add_role_advanced(
role_name, servers, manager
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
@ -2267,7 +2391,6 @@ class PanelHandler(BaseHandler):
server_id=0,
source_ip=self.get_remote_ip(),
)
self.controller.crafty_perms.add_role_creation(exec_user["user_id"])
self.redirect("/panel/panel_config")
else:

View File

@ -116,7 +116,9 @@ class ApiRolesIndexHandler(BaseApiHandler):
400, {"status": "error", "error": "ROLE_NAME_ALREADY_EXISTS"}
)
role_id = self.controller.roles.add_role_advanced(role_name, servers)
role_id = self.controller.roles.add_role_advanced(
role_name, servers, user["user_id"]
)
self.controller.management.add_to_audit_log(
user["user_id"],

View File

@ -665,10 +665,9 @@ class ApiServersIndexHandler(BaseApiHandler):
},
)
new_server_id, new_server_uuid = self.controller.create_api_server(data)
# Increase the server creation counter
self.controller.crafty_perms.add_server_creation(user["user_id"])
new_server_id, new_server_uuid = self.controller.create_api_server(
data, user["user_id"]
)
self.controller.servers.stats.record_stats()

View File

@ -84,6 +84,7 @@ class ApiServersServerActionHandler(BaseApiHandler):
new_server_log_file,
server_data.get("stop_command"),
server_data.get("type"),
user_id,
server_data.get("server_port"),
)

View File

@ -96,6 +96,7 @@ class ApiUsersIndexHandler(BaseApiHandler):
username = data["username"]
username = str(username).lower()
manager = int(user["user_id"])
password = data["password"]
email = data.get("email", "default@example.com")
enabled = data.get("enabled", True)
@ -149,6 +150,7 @@ class ApiUsersIndexHandler(BaseApiHandler):
# TODO: do this in the most efficient way
user_id = self.controller.users.add_user(
username,
manager,
password,
email,
enabled,

View File

@ -1,6 +1,7 @@
import json
import logging
import os
import time
import tornado.web
import tornado.escape
import bleach
@ -224,6 +225,23 @@ class ServerHandler(BaseHandler):
if server_id is not None:
if command == "clone_server":
if (
not superuser
and not self.controller.crafty_perms.can_create_server(
exec_user["user_id"]
)
):
time.sleep(3)
self.helper.websocket_helper.broadcast_user(
exec_user["user_id"],
"send_start_error",
{
"error": "<i class='fas fa-exclamation-triangle'"
" style='font-size:48px;color:red'>"
"</i> Not a server creator or server limit reached."
},
)
return
def is_name_used(name):
for server in self.controller.servers.get_all_defined_servers():
@ -231,6 +249,7 @@ class ServerHandler(BaseHandler):
return True
return
template = "/panel/dashboard"
server_data = self.controller.servers.get_server_data_by_id(
server_id
)
@ -265,6 +284,7 @@ class ServerHandler(BaseHandler):
backup_path = os.path.join(self.helper.backup_path, new_server_uuid)
server_port = server_data.get("server_port")
server_type = server_data.get("type")
created_by = exec_user["user_id"]
new_server_id = self.controller.servers.create_server(
new_server_name,
@ -276,6 +296,7 @@ class ServerHandler(BaseHandler):
new_server_log_file,
stop_command,
server_type,
created_by,
server_port,
)
if not exec_user["superuser"]:
@ -283,7 +304,8 @@ class ServerHandler(BaseHandler):
new_server_id
).get("server_uuid")
role_id = self.controller.roles.add_role(
f"Creator of Server with uuid={new_server_uuid}"
f"Creator of Server with uuid={new_server_uuid}",
exec_user["user_id"],
)
self.controller.server_perms.add_role_server(
new_server_id, role_id, "11111111"
@ -291,9 +313,6 @@ class ServerHandler(BaseHandler):
self.controller.users.add_role_to_user(
exec_user["user_id"], role_id
)
self.controller.crafty_perms.add_server_creation(
exec_user["user_id"]
)
self.controller.servers.init_all_servers()
@ -353,6 +372,7 @@ class ServerHandler(BaseHandler):
min_mem,
max_mem,
port,
exec_user["user_id"],
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
@ -369,7 +389,13 @@ class ServerHandler(BaseHandler):
return
new_server_id = self.controller.import_zip_server(
server_name, zip_path, import_server_jar, min_mem, max_mem, port
server_name,
zip_path,
import_server_jar,
min_mem,
max_mem,
port,
exec_user["user_id"],
)
if new_server_id == "false":
self.redirect(
@ -385,8 +411,6 @@ class ServerHandler(BaseHandler):
new_server_id,
self.get_remote_ip(),
)
# deletes temp dir
FileHelpers.del_dirs(zip_path)
else:
if len(server_parts) != 3:
self.redirect("/panel/error?error=Invalid server data")
@ -402,6 +426,7 @@ class ServerHandler(BaseHandler):
min_mem,
max_mem,
port,
exec_user["user_id"],
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
@ -420,7 +445,8 @@ class ServerHandler(BaseHandler):
new_server_id
).get("server_uuid")
role_id = self.controller.roles.add_role(
f"Creator of Server with uuid={new_server_uuid}"
f"Creator of Server with uuid={new_server_uuid}",
exec_user["user_id"],
)
self.controller.server_perms.add_role_server(
new_server_id, role_id, "11111111"
@ -428,9 +454,6 @@ class ServerHandler(BaseHandler):
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:
@ -483,7 +506,11 @@ class ServerHandler(BaseHandler):
return
new_server_id = self.controller.import_bedrock_server(
server_name, import_server_path, import_server_exe, port
server_name,
import_server_path,
import_server_exe,
port,
exec_user["user_id"],
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
@ -500,7 +527,11 @@ class ServerHandler(BaseHandler):
return
new_server_id = self.controller.import_bedrock_zip_server(
server_name, zip_path, import_server_exe, port
server_name,
zip_path,
import_server_exe,
port,
exec_user["user_id"],
)
if new_server_id == "false":
self.redirect(
@ -516,8 +547,6 @@ class ServerHandler(BaseHandler):
new_server_id,
self.get_remote_ip(),
)
# deletes temp dir
FileHelpers.del_dirs(zip_path)
else:
if len(server_parts) != 2:
self.redirect("/panel/error?error=Invalid server data")
@ -526,7 +555,13 @@ class ServerHandler(BaseHandler):
# TODO: add server type check here and call the correct server
# add functions if not a jar
new_server_id = self.controller.create_jar_server(
server_type, server_version, server_name, min_mem, max_mem, port
server_type,
server_version,
server_name,
min_mem,
max_mem,
port,
exec_user["user_id"],
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
@ -545,7 +580,8 @@ class ServerHandler(BaseHandler):
new_server_id
).get("server_uuid")
role_id = self.controller.roles.add_role(
f"Creator of Server with uuid={new_server_uuid}"
f"Creator of Server with uuid={new_server_uuid}",
exec_user["user_id"],
)
self.controller.server_perms.add_role_server(
new_server_id, role_id, "11111111"
@ -553,9 +589,6 @@ class ServerHandler(BaseHandler):
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:

View File

@ -40,6 +40,16 @@
<!-- Bootstrap Toggle -->
<link href="https://gitcdn.github.io/bootstrap-toggle/2.2.2/css/bootstrap-toggle.min.css" rel="stylesheet">
<script defer src="https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"
integrity="sha512-ElRFoEQdI5Ht6kZvyzXhYG9NqjtkmlkfYk0wr6wHxU9JEHakS7UJZNeml5ALk+8IKlU6jDgMabC3vkumRokgJA=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"
integrity="sha512-UXumZrZNiOwnTcZSHLOfcTs0aos2MzBWHXOHOuB0J/R44QB0dwY5JgfbvljXcklVf65Gc4El6RjZ+lnwd2az2g=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/1.2.1/chartjs-plugin-zoom.min.js"
integrity="sha512-klQv6lz2YR+MecyFYMFRuU2eAl8IPRo6zHnsc9n142TJuJHS8CG0ix4Oq9na9ceeg1u5EkBfZsFcV3U7J51iew=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- End Bootstrap Toggle -->
</head>

View File

@ -193,9 +193,9 @@
<a data-id="{{server['server_data']['server_id']}}" class="" title="{{
translate('dashboard', 'delay-explained' , data['lang'])}}">{{ translate('dashboard', 'starting',
data['lang']) }}</i></a>
{% elif server['stats']['downloading']%}
{% elif server['stats']['importing']%}
<a data-id="{{server['server_data']['server_id']}}" class=""><i class="fa fa-spinner fa-spin"></i>
{{ translate('serverTerm', 'downloading',
{{ translate('serverTerm', 'importing',
data['lang']) }}</a>
{% else %}
<a data-id="{{server['server_data']['server_id']}}" class="play_button" data-toggle="tooltip"
@ -399,12 +399,12 @@
data['lang']) }}</i></a>
</div>
</div>
{% elif server['stats']['downloading']%}
{% elif server['stats']['importing']%}
<div class="row">
<div class="col-12 px-0">
<a data-id="{{server['server_data']['server_id']}}" class="btn btn-link"><i
class="fa fa-spinner fa-spin"></i>
{{ translate('serverTerm', 'downloading', data['lang']) }}</a>
{{ translate('serverTerm', 'importing', data['lang']) }}</a>
</div>
</div>
{% else %}
@ -893,9 +893,6 @@
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> &nbsp; {% raw translate("dashboard", "bePatientClone", data["lang"]) %} </div>',
closeButton: false,
});
setTimeout(function () {
location.reload();
}, 5000)
}
</script>
<script src="/static/assets/vendors/js/jquery-ui.js"></script>

View File

@ -87,6 +87,38 @@
<td><a href="/panel/edit_user?id={{user.user_id}}"><i class="fas fa-pencil-alt"></i></a></td>
</tr>
{% end %}
{% for user in data['managed_users'] %}
<tr>
<td><i class="fas fa-user"></i> {{ user.username }}</td>
<td>
{% if user.enabled %}
<span class="text-success">
<i class="fas fa-check-square"></i> Yes
</span>
{% else %}
<span class="text-danger">
<i class="far fa-times-square"></i> No
</span>
{% end %}
</td>
<td id="server_list_{{user.user_id}}">
<ul id="{{user.user_id}}">
{% for item in data['auth-servers'][user.user_id] %}
<li>{{item}}</li>
{% end %}
</ul>
</td>
<td id="role_list_{{user.user_id}}">
<ul>
{% for item in data['user-roles'][user.user_id] %}
<li data-toggle="tooltip" title="{{ item }}">{{item}}</li>
{% end %}
</ul>
</td>
<td><a href="/panel/edit_user?id={{user.user_id}}"><i class="fas fa-pencil-alt"></i></a></td>
</tr>
{% end %}
</tbody>
</table>
</div>
@ -146,6 +178,34 @@
</tr>
{% end %}
{% if not data['superuser'] %}
{% for role in data['managed_roles'] %}
{% if role.role_id not in data['assigned_roles'] %}
<tr>
<td>{{ role.role_name }}</td>
<td id="role_list_{{role.role_id}}">
<ul id="{{role.role_id}}">
{% for item in data['role-servers'][role.role_id] %}
<li>{{item}}</li>
{% end %}
</ul>
</td>
<td>
<ul>
{% for user in data['users'] %}
{% for ruser in data['user-roles'][user.user_id] %}
{% if ruser == role.role_name %}
<li>{{ user.username }}</li>
{% end %}
{% end %}
{% end %}
</ul>
</td>
<td><a href="/panel/edit_role?id={{role.role_id}}"><i class="fas fa-pencil-alt"></i></a></td>
</tr>
{% end %}
{% end %}
{% end %}
</tbody>
</table>
</div>

View File

@ -49,7 +49,7 @@
</ul>
<div class="">
<div class="">
<form class="forms-sample" method="post" action="{{ '/panel/add_role' if data['new_role'] else '/panel/edit_role' }}">
<form id="role_form" class="forms-sample" method="post" action="{{ '/panel/add_role' if data['new_role'] else '/panel/edit_role' }}">
{% raw xsrf_form_html() %}
<input type="hidden" name="id" value="{{ data['role']['role_id'] }}">
<input type="hidden" name="subpage" value="config">
@ -63,6 +63,29 @@
<label for="role_name">{{ translate('rolesConfig', 'roleName', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('rolesConfig', 'roleDesc', data['lang']) }}</small> </label>
<input type="text" class="form-control" name="role_name" id="role_name" value="{{ data['role']['role_name'] }}" placeholder="Role Name" >
</div>
<br />
{% if data['superuser'] %}
<div class="form-group">
<label class="form-label" for="manager">{{ translate('rolesConfig', 'selectManager',
data['lang']) }}
</label>
<select class="form-select form-control form-control-lg select-css" id="manager" name="manager"
form="role_form">
{% if data["role_manager"]["username"] != "None" %}
<option value='{{data["role_manager"]["user_id"]}}'>{{ data["role_manager"]["username"]
}}</option>
{% end %}
<option value="">None</option>
{% for user in data['users'] %}
{% if user.user_id != data['role_manager']['user_id']
%}
<option value="{{user.user_id}}">{{user.username}}</option>
{% end %}
{% end %}
</select>
</div>
{% end %}
</div>
</div>
@ -252,6 +275,8 @@
<br />
{{ translate('rolesConfig', 'configUpdate', data['lang']) }} {{ str(data['role']['last_update']) }}
<br />
{{ translate('userConfig', 'manager', data['lang']) }}: {{ data['role_manager']['username'] }}
<br />
</p>
</blockquote>
<div class="text-center">

View File

@ -121,6 +121,27 @@ data['lang']) }}{% end %}
{% end %}
</select>
</div>
{% if data['superuser'] %}
<div class="form-group">
<label class="form-label" for="manager">{{ translate('userConfig', 'selectManager',
data['lang']) }}
</label>
<select class="form-select form-control form-control-lg select-css" id="manager" name="manager"
form="user_form">
{% if data["manager"]["username"] != "None" %}
<option value='{{data["manager"]["user_id"]}}'>{{ data["manager"]["username"]
}}</option>
{% end %}
<option value="">None</option>
{% for user in data['users'] %}
{% if user.username != data['user']['username'] and user.user_id != data['manager']['user_id']
%}
<option value="{{user.user_id}}">{{user.username}}</option>
{% end %}
{% end %}
</select>
</div>
{% end %}
</div>
</div>
@ -141,21 +162,29 @@ data['lang']) }}{% end %}
</tr>
</thead>
<tbody>
{% for role in data['roles_all'] %}
{% for role in data['roles'] %}
<tr>
{% if data['superuser'] or role.role_id in data['user']['roles'] or role.manager == data['exec_user'] %}
<td>{{ role.role_name }}</td>
<td>
{% if role.role_id in data['user']['roles'] %}
{% if role.manager == data['exec_user'] or data['superuser'] %}
<input type="checkbox" class="form-check-input"
id="role_{{ role.role_id }}_membership" name="role_{{ role.role_id }}_membership"
checked="" value="1">
{% else %}
<input type="checkbox" class="form-check-input"
id="role_{{ role.role_id }}_membership" name="role_{{ role.role_id }}_membership"
checked="" value="1" disabled>
{% end %}
{% elif data['superuser'] or role.manager == data['exec_user'] %}
<input type="checkbox" class="form-check-input"
id="role_{{ role.role_id }}_membership" name="role_{{ role.role_id }}_membership"
value="1">
{% end %}
</td>
{% end %}
</tr>
{% end %}
</tbody>
@ -268,6 +297,8 @@ data['lang']) }}{% end %}
<br />
{{ translate('userConfig', 'lastIP', data['lang']) }} {{ data['user']['last_ip'] }}
<br />
{{ translate('userConfig', 'manager', data['lang'])}}: {{data['manager']['username'] }}
<br />
</p>
</blockquote>
</div>
@ -284,7 +315,7 @@ data['lang']) }}{% end %}
{% else %}
<button class="btn btn-sm btn-danger delete-user"><i class="fas fa-trash"></i> {{
translate('userConfig', 'deleteUserB', data['lang']) }}</a>
{% end %}
{% end %}</button>
</div>
</div>

View File

@ -30,6 +30,7 @@
{% if data['permissions']['Players'] in data['user_permissions'] and data['server_data']['type'] != 'minecraft-bedrock' %}
<a class="dropdown-item {% if data['active_link'] == 'admin_controls' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=admin_controls" role="tab" aria-selected="true"><i class="fas fa-users"></i> {{ translate('serverDetails', 'playerControls', data['lang']) }}</a>
{% end %}
<a class="dropdown-item {% if data['active_link'] == 'metrics' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=metrics" role="tab" aria-selected="true"><i class='fas fa-chart-area'></i>{{ translate('serverDetails', 'metrics', data['lang']) }}</a>
</div>
</div>
</div>

View File

@ -49,4 +49,8 @@
<i class="fas fa-users"></i>{{ translate('serverDetails', 'playerControls', data['lang']) }}</a>
</li>
{% end %}
<li class="nav-item term-nav-item">
<a class="nav-link {% if data['active_link'] == 'metrics' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=metrics" role="tab" aria-selected="true">
<i class='fas fa-chart-area'></i>{{ translate('serverDetails', 'metrics', data['lang']) }}</a>
</li>
</ul>

View File

@ -165,6 +165,18 @@
</div>
{% end %}
<div class="form-group">
<label for="shutdown_timeout">{{ translate('serverConfig', 'shutdownTimeout', data['lang']) }}
<small class="text-muted ml-1"> - {{ translate('serverConfig', 'timeoutExplain1', data['lang'])
}}&nbsp;
{{ data['server_stats']['server_id']['stop_command'] }}&nbsp;{{ translate('serverConfig',
'timeoutExplain2', data['lang']) }}
</small> </label>
<input type="number" class="form-control" name="shutdown_timeout" id="shutdown_timeout"
value="{{ data['server_stats']['server_id']['shutdown_timeout'] }}" step="2" max="300" min="60"
required>
</div>
<div class="form-group">
<label for="logs_delete_after">{{ translate('serverConfig', 'removeOldLogsAfter', data['lang']) }}
<small class="text-muted ml-1"> - {{ translate('serverConfig', 'removeOldLogsAfterDesc',

View File

@ -0,0 +1,225 @@
{% extends ../base.html %}
{% block meta %}
{% end %}
{% block title %}Crafty Controller - {{ translate('serverDetails', 'serverDetails', data['lang']) }}{% end %}
{% block content %}
<div class="content-wrapper">
<!-- Page Title Header Starts-->
<div class="row page-title-header">
<div class="col-12">
<div class="page-header">
<h4 class="page-title">
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
</h4>
</div>
</div>
</div>
<!-- Page Title Header Ends-->
{% include "parts/details_stats.html %}
<div class="row">
<div class="col-sm-12 grid-margin">
<div class="card">
<div class="card-body pt-0">
<span class="d-none d-sm-block">
{% include "parts/server_controls_list.html %}
</span>
<span class="d-block d-sm-none">
{% include "parts/m_server_controls_list.html %}
</span>
<button style="float: right; visibility: hidden;" class="btn btn-outline-success reset-button"
id="reset-button"><i class="fas fa-undo"></i>&nbsp;{{ translate('serverMetrics', 'resetZoom', data['lang'])
}}</button>
{% if data['user_data']['hints'] %}
<span data-html="true" class="hints text-center" title="<i class='fa fa-info-circle'></i> " ,
data-content="{{
translate('serverMetrics', 'zoomHint1' , data['lang'])}} <br> <br> {{ translate('serverMetrics', 'zoomHint2', data['lang'])}}" , data-placement="top"></span>
{% end %}
<div class="chart-wrapper">
<canvas id="lineChart"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
.chart-wrapper {
height: 65vh;
}
.popover-body {
color: white !important;
;
}
</style>
<script type="text/javascript">
var zoomed = false;
//line
var ctxL = document.getElementById("lineChart").getContext('2d');
const players = []
const dates = []
const ram = []
const cpu = []
{% for item in data['history_stats'] %}
{% if 'minecraft-java' in data['server_stats']['server_type'] %}
players.push("{{ item.online }}");
{% end %}
dates.push("{{ item.created.strftime('%Y/%m/%d, %H:%M:%S') }}");
ram.push("{{ item.mem_percent }}")
cpu.push("{{ item.cpu }}")
{% end %}
var hist_chart = new Chart(ctxL, {
type: 'line',
data: {
labels: dates,
datasets: [{
label: "Players",
data: players,
borderColor: [
'rgba(136, 98, 224, .5)',
],
borderWidth: 2,
lineTension: 0,
},
{
label: "MEM",
data: ram,
borderColor: [
'rgba(33, 150, 243, .5)',
],
borderWidth: 2,
lineTension: 0,
},
{
label: "CPU",
data: cpu,
borderColor: [
'rgba(255, 175, 0, .5)',
],
borderWidth: 2,
lineTension: 0,
},
]
},
options: {
maintainAspectRatio: false,
plugins: {
zoom: {
zoom: {
onZoom({ hist_chart }) {
console.log("zooming");
document.getElementById("reset-button").style.visibility = "visible";
zoomed = true;
},
wheel: {
enabled: true,
modifierKey: 'shift',
},
drag: {
enabled: true,
modifierKey: "shift"
},
pinch: {
enabled: true
},
mode: 'x',
},
pan: {
enabled: true,
mode: "x",
threshhold: 1,
}
},
},
fill: false,
lineTension: 5,
responsive: true,
scales: {
y: {
min: 0,
},
x: {
position: 'right',
min: dates.length - 200,
}
}
}
});
$(window).ready(function () {
$('body').click(function () {
$('.hints').popover("hide");
});
});
$(document).ready(function () {
if ($(window).width() > 1000) {
$('[data-toggle="popover"]').popover();
$('.hints').popover("show");
}
webSocket.on('update_server_details', function (data) {
dates.push(data.created);
players.push(data.online);
cpu.push(data.cpu)
ram.push(data.mem_percent)
data = {
labels: dates,
datasets: [{
label: "Players",
data: players,
borderColor: [
'rgba(136, 98, 224, .5)',
],
borderWidth: 2,
lineTension: 0,
},
{
label: "MEM",
data: ram,
borderColor: [
'rgba(33, 150, 243, .5)',
],
borderWidth: 2,
lineTension: 0,
},
{
label: "CPU",
data: cpu,
borderColor: [
'rgba(255, 175, 0, .5)',
],
borderWidth: 2,
lineTension: 0,
},
]
}
if (!zoomed) {
hist_chart.options.scales.x.min = dates.length - 200;
}
hist_chart.update(data)
});
$(".reset-button").click(function () {
console.log("resetting zoom");
zoomed = false;
hist_chart.resetZoom();
document.getElementById("reset-button").style.visibility = "hidden";
});
});
</script>
{% end %}

View File

@ -65,9 +65,9 @@
<button onclick="" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1 disabled">{% raw translate('serverTerm', 'restart', data['lang']) %}</button>
<button onclick="" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1 disabled">{{ translate('serverTerm', 'stop', data['lang']) }}</button>
</div>
{% elif data['downloading'] %}
{% elif data['importing'] %}
<div id="control_buttons" class="mt-4 flex-wrap d-flex justify-content-between justify-content-md-center align-items-center px-5 px-md-0" style="visibility: visible">
<button onclick="" id="start-btn" style="max-width: 12rem; white-space: nowrap;" class="btn btn-secondary m-1 flex-grow-1 disabled"><i class="fa fa-spinner fa-spin"></i> {{ translate('serverTerm', 'downloading',
<button onclick="" id="start-btn" style="max-width: 12rem; white-space: nowrap;" class="btn btn-secondary m-1 flex-grow-1 disabled"><i class="fa fa-spinner fa-spin"></i> {{ translate('serverTerm', 'importing',
data['lang']) }}</button>
<button onclick="" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1 disabled">{% raw translate('serverTerm', 'restart', data['lang']) %}</button>
<button onclick="" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1 disabled">{{ translate('serverTerm', 'stop', data['lang']) }}</button>

View File

@ -0,0 +1,16 @@
# Generated by database migrator
import peewee
def migrate(migrator, database, **kwargs):
migrator.add_columns("roles", manager=peewee.IntegerField(null=True))
"""
Write your migrations here.
"""
def rollback(migrator, database, **kwargs):
migrator.drop_columns("roles", ["manager"])
"""
Write your rollback migrations here.
"""

View File

@ -0,0 +1,16 @@
# Generated by database migrator
import peewee
def migrate(migrator, database, **kwargs):
migrator.add_columns("users", manager=peewee.IntegerField(null=True))
"""
Write your migrations here.
"""
def rollback(migrator, database, **kwargs):
migrator.drop_columns("users", ["manager"])
"""
Write your rollback migrations here.
"""

View File

@ -0,0 +1,16 @@
# Generated by database migrator
import peewee
def migrate(migrator, database, **kwargs):
migrator.add_columns("servers", created_by=peewee.IntegerField(default=-100))
"""
Write your migrations here.
"""
def rollback(migrator, database, **kwargs):
migrator.drop_columns("servers", ["created_by"])
"""
Write your rollback migrations here.
"""

View File

@ -0,0 +1,20 @@
# Generated by database migrator
import peewee
def migrate(migrator, database, **kwargs):
migrator.drop_columns("user_crafty", ["created_server"])
migrator.drop_columns("user_crafty", ["created_user"])
migrator.drop_columns("user_crafty", ["created_role"])
"""
Write your migrations here.
"""
def rollback(migrator, database, **kwargs):
migrator.add_columns("user_crafty", created_server=peewee.IntegerField(default=0))
migrator.add_columns("user_crafty", created_user=peewee.IntegerField(default=0))
migrator.add_columns("user_crafty", created_role=peewee.IntegerField(default=0))
"""
Write your rollback migrations here.
"""

View File

@ -0,0 +1,16 @@
# Generated by database migrator
import peewee
def migrate(migrator, database, **kwargs):
migrator.add_columns("servers", shutdown_timeout=peewee.IntegerField(default=60))
"""
Write your migrations here.
"""
def rollback(migrator, database, **kwargs):
migrator.drop_columns("servers", ["shutdown_timeout"])
"""
Write your rollback migrations here.
"""

View File

@ -0,0 +1,17 @@
# Generated by database migrator
import peewee
def migrate(migrator, database, **kwargs):
migrator.rename_column("server_stats", "downloading", "importing")
"""
Write your migrations here.
"""
def rollback(migrator, database, **kwargs):
migrator.rename_column("server_stats", "importing", "downloading")
"""
Write your rollback migrations here.
"""

View File

@ -245,7 +245,8 @@
"roleUsers": "Role Users: ",
"serverAccess": "Access?",
"serverName": "Server Name",
"serversDesc": "servers this role is allowed to access"
"serversDesc": "servers this role is allowed to access",
"selectManager": "Select a manager for this Role"
},
"serverBackups": {
"backupAtMidnight": "Auto-backup at midnight?",
@ -324,7 +325,10 @@
"stopBeforeDeleting": "Please stop the server before deleting it",
"update": "Update Executable",
"yesDelete": "Yes, delete",
"yesDeleteFiles": "Yes, delete files"
"yesDeleteFiles": "Yes, delete files",
"shutdownTimeout": "Shutdown Timeout",
"timeoutExplain1": "How long Crafty will wait for your server to shutdown after executing the",
"timeoutExplain2": "command before it forces the process down."
},
"serverConfigHelp": {
"desc": "Here is where you can change the configuration of your server",
@ -351,7 +355,8 @@
"playerControls": "Player Management",
"schedule": "Schedule",
"serverDetails": "Server Details",
"terminal": "Terminal"
"terminal": "Terminal",
"metrics": "Metrics"
},
"serverFiles": {
"clickUpload": "Click here to select your files",
@ -463,7 +468,7 @@
"serverTerm": {
"commandInput": "Enter your command",
"delay-explained": "The service/agent has recently started and is delaying the start of the minecraft server instance",
"downloading": "Downloading...",
"importing": "Importing...",
"restart": "Restart",
"sendCommand": "Send command",
"start": "Start",
@ -472,6 +477,11 @@
"stopScroll": "Stop Auto Scrolling",
"updating": "Updating..."
},
"serverMetrics": {
"resetZoom": "Reset Zoom",
"zoomHint1": "To zoom on the graph hold your shift key then use your scroll wheel.",
"zoomHint2": "Alternatively hold the shift key then click and drag the area you'd like to zoom in on."
},
"serverWizard": {
"absoluteServerPath": "Absolute path to your server",
"absoluteZipPath": "Absolute path to your server",
@ -556,6 +566,8 @@
"userRoles": "User Roles",
"userRolesDesc": "Roles this user is a member of.",
"userSettings": "User Settings",
"uses": "Number of uses allowed (-1==No Limit)"
"uses": "Number of uses allowed (-1==No Limit)",
"manager": "Manager",
"selectManager": "Select Manager for User"
}
}

View File

@ -14,6 +14,7 @@ from app.classes.shared.import3 import Import3
from app.classes.shared.console import Console
from app.classes.shared.helpers import Helpers
from app.classes.models.users import HelperUsers
from app.classes.shared.import_helper import ImportHelpers
console = Console()
helper = Helpers()
@ -135,8 +136,9 @@ if __name__ == "__main__":
else:
Console.debug("Existing install detected")
file_helper = FileHelpers(helper)
import_helper = ImportHelpers(helper, file_helper)
# now the tables are created, we can load the tasks_manager and server controller
controller = Controller(database, helper, file_helper)
controller = Controller(database, helper, file_helper, import_helper)
import3 = Import3(helper, controller)
tasks_manager = TasksManager(helper, controller)
tasks_manager.start_webserver()