diff --git a/CHANGELOG.md b/CHANGELOG.md
index abd77b2a..996acb40 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,20 @@
# Changelog
-## --- [4.2.4] - 2023/TBD
+## --- [4.3.1] - 2023/TBD
### New features
TBD
+### Bug fixes
+TBD
+### Tweaks
+TBD
+### Lang
+TBD
+
+
+## --- [4.3.0] - 2023/03/09
+### Breaking Changes
+- This release includes database migrations that are not revertable. Once you update to this version you will not be able to rollback to a previous version.
+- In this release, we've implemented a breaking change to enhance server identification within Crafty: instead of relying on numerical integers (1, 2, 3, etc.), Servers are now uniquely identified by their UUIDs. Please adapt your API clients accordingly.
+
### Refactor
- Refactor remote file downloads ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/719))
### Bug fixes
@@ -10,9 +23,10 @@ TBD
- Do not allow users at server limit to clone servers ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/718))
- Fix bug where you cannot get to config with unloaded server ([Commit](https://gitlab.com/crafty-controller/crafty-4/-/commit/9de08973b6bb2ddf91283c5c6b0e189ff34f7e24))
- Fix forge install v1.20, 1.20.1 and 1.20.2 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/710))
-- Fix Sanitisation on Passwords ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/715))
+- Fix Sanitisation on Passwords ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/715) | [Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/725))
- Fix `Upload Imports` on unix systems, that have a space in the root dir name ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/722))
- Fix Bedrock downloads, add `www` to download URL ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/723))
+- Fire backup webhook 'after' backup has finished ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/727))
### Tweaks
- Bump pyOpenSSL & cryptography for CVE-2024-0727, CVE-2023-50782 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/716))
- Bump cryptography for CVE-2024-26130 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/724))
diff --git a/README.md b/README.md
index b1b401d7..bc621c7d 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
[![Crafty Logo](app/frontend/static/assets/images/logo_long.svg)](https://craftycontrol.com)
-# Crafty Controller 4.2.4
+# Crafty Controller 4.3.1
> Python based Control Panel for your Minecraft Server
## What is Crafty Controller?
diff --git a/app/classes/controllers/servers_controller.py b/app/classes/controllers/servers_controller.py
index 86e17802..6a5cce4e 100644
--- a/app/classes/controllers/servers_controller.py
+++ b/app/classes/controllers/servers_controller.py
@@ -80,8 +80,8 @@ class ServersController(metaclass=Singleton):
PeeweeException: If the server already exists
"""
return HelperServers.create_server(
- name,
server_uuid,
+ name,
server_dir,
backup_path,
server_command,
@@ -161,9 +161,9 @@ class ServersController(metaclass=Singleton):
# Servers Methods
# **********************************************************************************
- def get_server_instance_by_id(self, server_id: t.Union[str, int]) -> ServerInstance:
+ def get_server_instance_by_id(self, server_id: t.Union[str, str]) -> ServerInstance:
for server in self.servers_list:
- if int(server["server_id"]) == int(server_id):
+ if server["server_id"] == server_id:
return server["server_obj"]
logger.warning(f"Unable to find server object for server id {server_id}")
diff --git a/app/classes/models/management.py b/app/classes/models/management.py
index e86e3209..ffe207c2 100644
--- a/app/classes/models/management.py
+++ b/app/classes/models/management.py
@@ -31,9 +31,9 @@ class AuditLog(BaseModel):
user_name = CharField(default="")
user_id = IntegerField(default=0, index=True)
source_ip = CharField(default="127.0.0.1")
- server_id = IntegerField(
- default=None, index=True
- ) # When auditing global events, use server ID 0
+ server_id = ForeignKeyField(
+ Servers, backref="audit_server", null=True
+ ) # When auditing global events, use server ID null
log_msg = TextField(default="")
class Meta:
@@ -79,7 +79,7 @@ class HostStats(BaseModel):
# **********************************************************************************
class Webhooks(BaseModel):
id = AutoField()
- server_id = IntegerField(null=True)
+ server_id = ForeignKeyField(Servers, backref="webhook_server", null=True)
name = CharField(default="Custom Webhook", max_length=64)
url = CharField(default="")
webhook_type = CharField(default="Custom")
@@ -337,7 +337,7 @@ class HelpersManagement:
@staticmethod
def delete_scheduled_task_by_server(server_id):
- Schedules.delete().where(Schedules.server_id == int(server_id)).execute()
+ Schedules.delete().where(Schedules.server_id == server_id).execute()
@staticmethod
def get_scheduled_task(schedule_id):
diff --git a/app/classes/models/server_stats.py b/app/classes/models/server_stats.py
index 8473ed12..64258c8c 100644
--- a/app/classes/models/server_stats.py
+++ b/app/classes/models/server_stats.py
@@ -71,7 +71,7 @@ class HelperServerStats:
database = None
def __init__(self, server_id):
- self.server_id = int(server_id)
+ self.server_id = server_id
self.init_database(self.server_id)
def init_database(self, server_id):
diff --git a/app/classes/models/servers.py b/app/classes/models/servers.py
index 00bc5002..13d9096a 100644
--- a/app/classes/models/servers.py
+++ b/app/classes/models/servers.py
@@ -3,7 +3,6 @@ import datetime
import typing as t
from peewee import (
CharField,
- AutoField,
DateTimeField,
BooleanField,
IntegerField,
@@ -13,6 +12,9 @@ from playhouse.shortcuts import model_to_dict
from app.classes.shared.main_models import DatabaseShortcuts
from app.classes.models.base_model import BaseModel
+# from app.classes.models.users import Users
+from app.classes.shared.helpers import Helpers
+
logger = logging.getLogger(__name__)
@@ -20,9 +22,8 @@ logger = logging.getLogger(__name__)
# Servers Model
# **********************************************************************************
class Servers(BaseModel):
- server_id = AutoField()
+ server_id = CharField(primary_key=True, default=Helpers.create_uuid())
created = DateTimeField(default=datetime.datetime.now)
- server_uuid = CharField(default="", index=True)
server_name = CharField(default="Server", index=True)
path = CharField(default="")
backup_path = CharField(default="")
@@ -40,6 +41,7 @@ class Servers(BaseModel):
type = CharField(default="minecraft-java")
show_status = BooleanField(default=1)
created_by = IntegerField(default=-100)
+ # created_by = ForeignKeyField(Users, backref="creator_server", null=True)
shutdown_timeout = IntegerField(default=60)
ignored_exits = CharField(default="0")
count_players = BooleanField(default=True)
@@ -60,8 +62,8 @@ class HelperServers:
# **********************************************************************************
@staticmethod
def create_server(
+ server_id: str,
name: str,
- server_uuid: str,
server_dir: str,
backup_path: str,
server_command: str,
@@ -95,25 +97,24 @@ class HelperServers:
Raises:
PeeweeException: If the server already exists
"""
- return Servers.insert(
- {
- Servers.server_name: name,
- Servers.server_uuid: server_uuid,
- Servers.path: server_dir,
- Servers.executable: server_file,
- Servers.execution_command: server_command,
- Servers.auto_start: False,
- Servers.auto_start_delay: 10,
- Servers.crash_detection: False,
- Servers.log_path: server_log_file,
- Servers.server_port: server_port,
- Servers.server_ip: server_host,
- Servers.stop_command: server_stop,
- Servers.backup_path: backup_path,
- Servers.type: server_type,
- Servers.created_by: created_by,
- }
- ).execute()
+ return Servers.create(
+ server_id=server_id,
+ server_uuid=server_id,
+ server_name=name,
+ path=server_dir,
+ executable=server_file,
+ execution_command=server_command,
+ auto_start=False,
+ auto_start_delay=10,
+ crash_detection=False,
+ log_path=server_log_file,
+ server_port=server_port,
+ server_ip=server_host,
+ stop_command=server_stop,
+ backup_path=backup_path,
+ type=server_type,
+ created_by=created_by,
+ ).server_id
@staticmethod
def get_server_obj(server_id):
diff --git a/app/classes/shared/command.py b/app/classes/shared/command.py
index 95a83047..4b7abbc3 100644
--- a/app/classes/shared/command.py
+++ b/app/classes/shared/command.py
@@ -18,7 +18,12 @@ logger = logging.getLogger(__name__)
class MainPrompt(cmd.Cmd):
def __init__(
- self, helper, tasks_manager, migration_manager, main_controller, import3
+ self,
+ helper,
+ tasks_manager,
+ migration_manager,
+ main_controller,
+ import3,
):
super().__init__()
self.helper: Helpers = helper
diff --git a/app/classes/shared/main_controller.py b/app/classes/shared/main_controller.py
index cfb3a10a..b6e824a5 100644
--- a/app/classes/shared/main_controller.py
+++ b/app/classes/shared/main_controller.py
@@ -239,7 +239,7 @@ class Controller:
try:
os.mkdir(final_path)
except FileExistsError:
- final_path += "_" + server["server_uuid"]
+ final_path += "_" + server["server_id"]
os.mkdir(final_path)
try:
FileHelpers.copy_file(
@@ -632,11 +632,11 @@ class Controller:
# and add the user to it if he's not a superuser
if len(captured_roles) == 0:
if not exec_user["superuser"]:
- new_server_uuid = self.servers.get_server_data_by_id(new_server_id).get(
- "server_uuid"
+ new_server_id = self.servers.get_server_data_by_id(new_server_id).get(
+ "server_id"
)
role_id = self.roles.add_role(
- f"Creator of Server with uuid={new_server_uuid}",
+ f"Creator of Server with id={new_server_id}",
exec_user["user_id"],
)
self.server_perms.add_role_server(new_server_id, role_id, "11111111")
@@ -647,7 +647,7 @@ class Controller:
role_id = role
self.server_perms.add_role_server(new_server_id, role_id, "11111111")
- return new_server_id, server_fs_uuid
+ return new_server_id
@staticmethod
def verify_jar_server(server_path: str, server_jar: str):
@@ -1095,7 +1095,7 @@ class Controller:
for server in servers:
server_path = server.get("path")
new_local_server_path = os.path.join(
- new_server_path, server.get("server_uuid")
+ new_server_path, server.get("server_id")
)
if os.path.isdir(server_path):
WebSocketManager().broadcast_page(
diff --git a/app/classes/shared/migration.py b/app/classes/shared/migration.py
index c31542a2..1adea4c6 100644
--- a/app/classes/shared/migration.py
+++ b/app/classes/shared/migration.py
@@ -200,6 +200,21 @@ class Migrator(object):
)
return model
+ @get_model
+ def alter_column_type(
+ self,
+ model: peewee.Model,
+ column_name: str,
+ field: peewee.Field,
+ ) -> peewee.Model:
+ """
+ Alter field data type in database.
+ """
+ self.operations.append(
+ self.migrator.alter_column_type(model._meta.table_name, column_name, field)
+ )
+ return model
+
@get_model
def rename_table(self, model: peewee.Model, new_name: str) -> peewee.Model:
"""
diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py
index 8d07af23..a31cc891 100644
--- a/app/classes/shared/server.py
+++ b/app/classes/shared/server.py
@@ -208,7 +208,7 @@ class ServerInstance:
self.dir_scheduler.start()
self.start_dir_calc_task()
self.backup_thread = threading.Thread(
- target=self.a_backup_server, daemon=True, name=f"backup_{self.name}"
+ target=self.backup_server, daemon=True, name=f"backup_{self.name}"
)
self.is_backingup = False
# Reset crash and update at initialization
@@ -1110,13 +1110,12 @@ class ServerInstance:
f.write("eula=true")
self.run_threaded_server(user_id)
- @callback
- def backup_server(self):
+ def a_backup_server(self):
if self.settings["backup_path"] == "":
logger.critical("Backup path is None. Canceling Backup!")
return
backup_thread = threading.Thread(
- target=self.a_backup_server, daemon=True, name=f"backup_{self.name}"
+ target=self.backup_server, daemon=True, name=f"backup_{self.name}"
)
logger.info(
f"Starting Backup Thread for server {self.settings['server_name']}."
@@ -1143,7 +1142,8 @@ class ServerInstance:
return False
logger.info(f"Backup Thread started for server {self.settings['server_name']}.")
- def a_backup_server(self):
+ @callback
+ def backup_server(self):
was_server_running = None
logger.info(f"Starting server {self.name} (ID {self.server_id}) backup")
server_users = PermissionsServers.get_server_user_list(self.server_id)
@@ -1373,7 +1373,7 @@ class ServerInstance:
def a_jar_update(self):
server_users = PermissionsServers.get_server_user_list(self.server_id)
was_started = "-1"
- self.backup_server()
+ self.a_backup_server()
# checks if server is running. Calls shutdown if it is running.
if self.check_running():
was_started = True
diff --git a/app/classes/shared/tasks.py b/app/classes/shared/tasks.py
index a5ea32ac..d1b786b9 100644
--- a/app/classes/shared/tasks.py
+++ b/app/classes/shared/tasks.py
@@ -140,7 +140,7 @@ class TasksManager:
)
elif command == "backup_server":
- svr.backup_server()
+ svr.a_backup_server()
elif command == "update_executable":
svr.jar_update()
diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py
index bb9ded4d..8ecaaf7a 100644
--- a/app/classes/web/panel_handler.py
+++ b/app/classes/web/panel_handler.py
@@ -174,7 +174,7 @@ class PanelHandler(BaseHandler):
self.redirect("/panel/error?error=Invalid Server ID")
return None
for server in self.controller.servers.failed_servers:
- if int(server_id) == server["server_id"]:
+ if server_id == server["server_id"]:
self.failed_server = True
return server_id
# Does this server exist?
@@ -557,7 +557,7 @@ class PanelHandler(BaseHandler):
"server_id": {
"server_id": server_id,
"server_name": server_temp_obj["server_name"],
- "server_uuid": server_temp_obj["server_uuid"],
+ "server_uuid": server_temp_obj["server_id"],
"path": server_temp_obj["path"],
"log_path": server_temp_obj["log_path"],
"executable": server_temp_obj["executable"],
diff --git a/app/classes/web/routes/api/api_handlers.py b/app/classes/web/routes/api/api_handlers.py
index 21c78c04..a30350a5 100644
--- a/app/classes/web/routes/api/api_handlers.py
+++ b/app/classes/web/routes/api/api_handlers.py
@@ -208,92 +208,92 @@ def api_handlers(handler_args):
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/?",
+ r"/api/v2/servers/([a-z0-9-]+)/?",
ApiServersServerIndexHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/backups/?",
+ r"/api/v2/servers/([a-z0-9-]+)/backups/?",
ApiServersServerBackupsIndexHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/backups/backup/?",
+ r"/api/v2/servers/([a-z0-9-]+)/backups/backup/?",
ApiServersServerBackupsBackupIndexHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/files/?",
+ r"/api/v2/servers/([a-z0-9-]+)/files/?",
ApiServersServerFilesIndexHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/files/create/?",
+ r"/api/v2/servers/([a-z0-9-]+)/files/create/?",
ApiServersServerFilesCreateHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/files/zip/?",
+ r"/api/v2/servers/([a-z0-9-]+)/files/zip/?",
ApiServersServerFilesZipHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/tasks/?",
+ r"/api/v2/servers/([a-z0-9-]+)/tasks/?",
ApiServersServerTasksIndexHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/tasks/([0-9]+)/?",
+ r"/api/v2/servers/([a-z0-9-]+)/tasks/([0-9]+)/?",
ApiServersServerTasksTaskIndexHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/tasks/([0-9]+)/children/?",
+ r"/api/v2/servers/([a-z0-9-]+)/tasks/([0-9]+)/children/?",
ApiServersServerTasksTaskChildrenHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/stats/?",
+ r"/api/v2/servers/([a-z0-9-]+)/stats/?",
ApiServersServerStatsHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/history/?",
+ r"/api/v2/servers/([a-z0-9-]+)/history/?",
ApiServersServerHistoryHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/webhook/([0-9]+)/?",
+ r"/api/v2/servers/([a-z0-9-]+)/webhook/([0-9]+)/?",
ApiServersServerWebhooksManagementIndexHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/webhook/?",
+ r"/api/v2/servers/([a-z0-9-]+)/webhook/?",
ApiServersServerWebhooksIndexHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/action/([a-z_]+)/?",
+ r"/api/v2/servers/([a-z0-9-]+)/action/([a-z_]+)/?",
ApiServersServerActionHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/logs/?",
+ r"/api/v2/servers/([a-z0-9-]+)/logs/?",
ApiServersServerLogsHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/users/?",
+ r"/api/v2/servers/([a-z0-9-]+)/users/?",
ApiServersServerUsersHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/public/?",
+ r"/api/v2/servers/([a-z0-9-]+)/public/?",
ApiServersServerPublicHandler,
handler_args,
),
(
- r"/api/v2/servers/([0-9]+)/stdin/?",
+ r"/api/v2/servers/([a-z0-9-]+)/stdin/?",
ApiServersServerStdinHandler,
handler_args,
),
diff --git a/app/classes/web/routes/api/servers/index.py b/app/classes/web/routes/api/servers/index.py
index 31dbd4c6..3c14f604 100644
--- a/app/classes/web/routes/api/servers/index.py
+++ b/app/classes/web/routes/api/servers/index.py
@@ -723,9 +723,7 @@ class ApiServersIndexHandler(BaseApiHandler):
405, {"status": "error", "error": "DATA CONSTRAINT FAILED"}
)
return
- new_server_id, new_server_uuid = self.controller.create_api_server(
- data, user["user_id"]
- )
+ new_server_id = self.controller.create_api_server(data, user["user_id"])
self.controller.servers.stats.record_stats()
@@ -734,7 +732,7 @@ class ApiServersIndexHandler(BaseApiHandler):
(
f"created server {data['name']}"
f" (ID: {new_server_id})"
- f" (UUID: {new_server_uuid})"
+ f" (UUID: {new_server_id})"
),
server_id=new_server_id,
source_ip=self.get_remote_ip(),
@@ -746,7 +744,7 @@ class ApiServersIndexHandler(BaseApiHandler):
"status": "ok",
"data": {
"new_server_id": str(new_server_id),
- "new_server_uuid": new_server_uuid,
+ "new_server_uuid": new_server_id,
},
},
)
diff --git a/app/classes/web/routes/api/servers/server/action.py b/app/classes/web/routes/api/servers/server/action.py
index a30ab410..01ce45c4 100644
--- a/app/classes/web/routes/api/servers/server/action.py
+++ b/app/classes/web/routes/api/servers/server/action.py
@@ -3,7 +3,6 @@ import os
from app.classes.models.server_permissions import EnumPermissionsServer
from app.classes.models.servers import Servers
from app.classes.shared.file_helpers import FileHelpers
-from app.classes.shared.helpers import Helpers
from app.classes.web.base_api_handler import BaseApiHandler
@@ -68,10 +67,20 @@ class ApiServersServerActionHandler(BaseApiHandler):
name_counter += 1
new_server_name = server_data.get("server_name") + f" (Copy {name_counter})"
- new_server_uuid = Helpers.create_uuid()
- while os.path.exists(os.path.join(self.helper.servers_dir, new_server_uuid)):
- new_server_uuid = Helpers.create_uuid()
- new_server_path = os.path.join(self.helper.servers_dir, new_server_uuid)
+ new_server_id = self.controller.servers.create_server(
+ new_server_name,
+ None,
+ "",
+ None,
+ server_data.get("executable"),
+ None,
+ server_data.get("stop_command"),
+ server_data.get("type"),
+ user_id,
+ server_data.get("server_port"),
+ )
+
+ new_server_path = os.path.join(self.helper.servers_dir, new_server_id)
self.controller.management.add_to_audit_log(
user_id,
@@ -89,19 +98,12 @@ class ApiServersServerActionHandler(BaseApiHandler):
self.helper.get_os_understandable_path(server_data.get("log_path"))
)
- new_server_id = self.controller.servers.create_server(
- new_server_name,
- new_server_uuid,
- new_server_path,
- "",
- new_server_command,
- server_data.get("executable"),
- new_server_log_file,
- server_data.get("stop_command"),
- server_data.get("type"),
- user_id,
- server_data.get("server_port"),
- )
+ server: Servers = self.controller.servers.get_server_obj(new_server_id)
+ server.path = new_server_path
+ server.log_path = new_server_log_file
+ server.execution_command = new_server_command
+ self.controller.servers.update_server(server)
+
for role in self.controller.server_perms.get_server_roles(server_id):
mask = self.controller.server_perms.get_permissions_mask(
role.role_id, server_id
diff --git a/app/classes/web/routes/api/servers/server/backups/backup/index.py b/app/classes/web/routes/api/servers/server/backups/backup/index.py
index 9a4ecc30..05edd3a9 100644
--- a/app/classes/web/routes/api/servers/server/backups/backup/index.py
+++ b/app/classes/web/routes/api/servers/server/backups/backup/index.py
@@ -145,7 +145,7 @@ class ApiServersServerBackupsBackupIndexHandler(BaseApiHandler):
new_server_id = new_server
new_server = self.controller.servers.get_server_data(new_server)
self.controller.rename_backup_dir(
- server_id, new_server_id, new_server["server_uuid"]
+ server_id, new_server_id, new_server["server_id"]
)
# preserve current schedules
for schedule in self.controller.management.get_schedules_by_server(
diff --git a/app/classes/web/routes/api/servers/server/index.py b/app/classes/web/routes/api/servers/server/index.py
index 06db3158..81035bd0 100644
--- a/app/classes/web/routes/api/servers/server/index.py
+++ b/app/classes/web/routes/api/servers/server/index.py
@@ -176,7 +176,7 @@ class ApiServersServerIndexHandler(BaseApiHandler):
self.tasks_manager.remove_all_server_tasks(server_id)
failed = False
for item in self.controller.servers.failed_servers[:]:
- if item["server_id"] == int(server_id):
+ if item["server_id"] == server_id:
self.controller.servers.failed_servers.remove(item)
failed = True
diff --git a/app/classes/web/routes/metrics/metrics_handlers.py b/app/classes/web/routes/metrics/metrics_handlers.py
index fa43a909..7fb1e31d 100644
--- a/app/classes/web/routes/metrics/metrics_handlers.py
+++ b/app/classes/web/routes/metrics/metrics_handlers.py
@@ -17,7 +17,7 @@ def metrics_handlers(handler_args):
handler_args,
),
(
- r"/metrics/servers/([0-9]+)/?",
+ r"/metrics/servers/([a-z0-9-]+)/?",
ApiOpenMetricsServersHandler,
handler_args,
),
diff --git a/app/config/version.json b/app/config/version.json
index 3c001e77..9a8d1a7f 100644
--- a/app/config/version.json
+++ b/app/config/version.json
@@ -1,5 +1,5 @@
{
"major": 4,
- "minor": 2,
- "sub": 4
+ "minor": 3,
+ "sub": 1
}
diff --git a/app/frontend/templates/panel/server_admin_controls.html b/app/frontend/templates/panel/server_admin_controls.html
index c021f310..b136a650 100644
--- a/app/frontend/templates/panel/server_admin_controls.html
+++ b/app/frontend/templates/panel/server_admin_controls.html
@@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
- UUID: {{ data['server_stats']['server_id']['server_uuid'] }}
+ UUID: {{ data['server_stats']['server_id']['server_id'] }}
diff --git a/app/frontend/templates/panel/server_backup.html b/app/frontend/templates/panel/server_backup.html
index 3606d4af..2a9263ba 100644
--- a/app/frontend/templates/panel/server_backup.html
+++ b/app/frontend/templates/panel/server_backup.html
@@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
- UUID: {{ data['server_stats']['server_id']['server_uuid'] }}
+ UUID: {{ data['server_stats']['server_id']['server_id'] }}
@@ -454,7 +454,7 @@
});
}
});
-
+
try {
if ($('#backup_path').val() == '') {
console.log('true')
diff --git a/app/frontend/templates/panel/server_config.html b/app/frontend/templates/panel/server_config.html
index 392f38a2..46e144c3 100644
--- a/app/frontend/templates/panel/server_config.html
+++ b/app/frontend/templates/panel/server_config.html
@@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
- UUID: {{ data['server_stats']['server_id']['server_uuid'] }}
+ UUID: {{ data['server_stats']['server_id']['server_id'] }}
diff --git a/app/frontend/templates/panel/server_files.html b/app/frontend/templates/panel/server_files.html
index ce188d2a..2d99c6bb 100644
--- a/app/frontend/templates/panel/server_files.html
+++ b/app/frontend/templates/panel/server_files.html
@@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
- UUID: {{ data['server_stats']['server_id']['server_uuid'] }}
+ UUID: {{ data['server_stats']['server_id']['server_id'] }}
diff --git a/app/frontend/templates/panel/server_logs.html b/app/frontend/templates/panel/server_logs.html
index 32f3cb66..3605adba 100644
--- a/app/frontend/templates/panel/server_logs.html
+++ b/app/frontend/templates/panel/server_logs.html
@@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
- UUID: {{ data['server_stats']['server_id']['server_uuid'] }}
+ UUID: {{ data['server_stats']['server_id']['server_id'] }}
diff --git a/app/frontend/templates/panel/server_metrics.html b/app/frontend/templates/panel/server_metrics.html
index 5067e709..be7712e5 100644
--- a/app/frontend/templates/panel/server_metrics.html
+++ b/app/frontend/templates/panel/server_metrics.html
@@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
- UUID: {{ data['server_stats']['server_id']['server_uuid'] }}
+ UUID: {{ data['server_stats']['server_id']['server_id'] }}
diff --git a/app/frontend/templates/panel/server_schedule_edit.html b/app/frontend/templates/panel/server_schedule_edit.html
index fac8242a..7b116f7f 100644
--- a/app/frontend/templates/panel/server_schedule_edit.html
+++ b/app/frontend/templates/panel/server_schedule_edit.html
@@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
- UUID: {{ data['server_stats']['server_id']['server_uuid'] }}
+ UUID: {{ data['server_stats']['server_id']['server_id'] }}
@@ -235,7 +235,7 @@
if (key != "start_time" && key != "cron_string" && key != "interval_type") {
if (typeof value == "boolean") {
return value
- }
+ }
console.log(key)
if (key === "interval" && value === ""){
return 0;
@@ -298,7 +298,7 @@
title: responseData.status,
message: responseData.error
});
- }
+ }
});
$("#schedule_form").on("submit", async function (e) {
@@ -332,7 +332,7 @@
method: 'PATCH',
headers: {
'X-XSRFToken': token,
- "Content-Type": "application/json",
+ "Content-Type": "application/json",
},
body: formDataJsonString,
});
@@ -345,7 +345,7 @@
title: responseData.error,
message: responseData.error_data
});
- }
+ }
});
});
diff --git a/app/frontend/templates/panel/server_schedules.html b/app/frontend/templates/panel/server_schedules.html
index 85bc077d..1fcb30df 100644
--- a/app/frontend/templates/panel/server_schedules.html
+++ b/app/frontend/templates/panel/server_schedules.html
@@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
- UUID: {{ data['server_stats']['server_id']['server_uuid'] }}
+ UUID: {{ data['server_stats']['server_id']['server_id'] }}
diff --git a/app/frontend/templates/panel/server_term.html b/app/frontend/templates/panel/server_term.html
index a127e7aa..7467781a 100644
--- a/app/frontend/templates/panel/server_term.html
+++ b/app/frontend/templates/panel/server_term.html
@@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
- UUID: {{ data['server_stats']['server_id']['server_uuid'] }}
+ UUID: {{ data['server_stats']['server_id']['server_id'] }}
diff --git a/app/frontend/templates/panel/server_webhook_edit.html b/app/frontend/templates/panel/server_webhook_edit.html
index fd556833..80610a49 100644
--- a/app/frontend/templates/panel/server_webhook_edit.html
+++ b/app/frontend/templates/panel/server_webhook_edit.html
@@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
- UUID: {{ data['server_stats']['server_id']['server_uuid'] }}
+ UUID: {{ data['server_stats']['server_id']['server_id'] }}
@@ -161,7 +161,7 @@
if (key != "start_time" && key != "cron_string" && key != "interval_type") {
if (typeof value == "boolean") {
return value
- }
+ }
console.log(key)
if (key === "interval" && value === ""){
return 0;
@@ -221,7 +221,7 @@
title: responseData.status,
message: responseData.error
});
- }
+ }
});
$("#webhook_form").on("submit", async function (e) {
@@ -249,7 +249,7 @@
method: 'PATCH',
headers: {
'X-XSRFToken': token,
- "Content-Type": "application/json",
+ "Content-Type": "application/json",
},
body: formDataJsonString,
});
@@ -262,15 +262,15 @@
title: responseData.status,
message: responseData.error
});
- }
+ }
});
});
-
+
function hexToDiscordInt(hexColor) {
// Remove the hash at the start if it's there
const sanitizedHex = hexColor.startsWith('#') ? hexColor.slice(1) : hexColor;
-
+
// Convert the hex to an integer
return parseInt(sanitizedHex, 16);
}
diff --git a/app/frontend/templates/panel/server_webhooks.html b/app/frontend/templates/panel/server_webhooks.html
index 25a61257..432b0148 100644
--- a/app/frontend/templates/panel/server_webhooks.html
+++ b/app/frontend/templates/panel/server_webhooks.html
@@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
- UUID: {{ data['server_stats']['server_id']['server_uuid'] }}
+ UUID: {{ data['server_stats']['server_id']['server_id'] }}
diff --git a/app/migrations/20240216_rework_servers_uuid.py b/app/migrations/20240216_rework_servers_uuid.py
new file mode 100644
index 00000000..c741a84c
--- /dev/null
+++ b/app/migrations/20240216_rework_servers_uuid.py
@@ -0,0 +1,244 @@
+import datetime
+import uuid
+import peewee
+import logging
+
+from app.classes.shared.console import Console
+from app.classes.shared.migration import Migrator, MigrateHistory
+from app.classes.models.management import (
+ AuditLog,
+ Webhooks,
+ Schedules,
+ Backups,
+)
+from app.classes.models.server_permissions import RoleServers
+
+logger = logging.getLogger(__name__)
+
+
+def migrate(migrator: Migrator, database, **kwargs):
+ """
+ Write your migrations here.
+ """
+ db = database
+
+ # **********************************************************************************
+ # Servers New Model from Old (easier to migrate without dunmping Database)
+ # **********************************************************************************
+ class Servers(peewee.Model):
+ server_id = peewee.CharField(primary_key=True, default=str(uuid.uuid4()))
+ created = peewee.DateTimeField(default=datetime.datetime.now)
+ server_uuid = peewee.CharField(default="", index=True)
+ server_name = peewee.CharField(default="Server", index=True)
+ path = peewee.CharField(default="")
+ backup_path = peewee.CharField(default="")
+ executable = peewee.CharField(default="")
+ log_path = peewee.CharField(default="")
+ execution_command = peewee.CharField(default="")
+ auto_start = peewee.BooleanField(default=0)
+ auto_start_delay = peewee.IntegerField(default=10)
+ crash_detection = peewee.BooleanField(default=0)
+ stop_command = peewee.CharField(default="stop")
+ executable_update_url = peewee.CharField(default="")
+ server_ip = peewee.CharField(default="127.0.0.1")
+ server_port = peewee.IntegerField(default=25565)
+ logs_delete_after = peewee.IntegerField(default=0)
+ type = peewee.CharField(default="minecraft-java")
+ show_status = peewee.BooleanField(default=1)
+ created_by = peewee.IntegerField(default=-100)
+ shutdown_timeout = peewee.IntegerField(default=60)
+ ignored_exits = peewee.CharField(default="0")
+
+ class Meta:
+ table_name = "servers"
+ database = db
+
+ try:
+ logger.info("Migrating Data from Int to UUID (Type Change)")
+ Console.info("Migrating Data from Int to UUID (Type Change)")
+
+ # Changes on Server Table
+ migrator.alter_column_type(
+ Servers,
+ "server_id",
+ peewee.CharField(primary_key=True, default=str(uuid.uuid4())),
+ )
+
+ # Changes on Audit Log Table
+ migrator.alter_column_type(
+ AuditLog,
+ "server_id",
+ peewee.ForeignKeyField(
+ Servers,
+ backref="audit_server",
+ null=True,
+ field=peewee.CharField(primary_key=True, default=str(uuid.uuid4())),
+ ),
+ )
+ # Changes on Webhook Table
+ migrator.alter_column_type(
+ Webhooks,
+ "server_id",
+ peewee.ForeignKeyField(
+ Servers,
+ backref="webhook_server",
+ null=True,
+ field=peewee.CharField(primary_key=True, default=str(uuid.uuid4())),
+ ),
+ )
+
+ migrator.run()
+
+ logger.info("Migrating Data from Int to UUID (Type Change) : SUCCESS")
+ Console.info("Migrating Data from Int to UUID (Type Change) : SUCCESS")
+
+ except Exception as ex:
+ logger.error("Error while migrating Data from Int to UUID (Type Change)")
+ logger.error(ex)
+ Console.error("Error while migrating Data from Int to UUID (Type Change)")
+ Console.error(ex)
+ last_migration = MigrateHistory.get_by_id(MigrateHistory.select().count())
+ last_migration.delete()
+ return
+
+ try:
+ logger.info("Migrating Data from Int to UUID (Foreign Keys)")
+ Console.info("Migrating Data from Int to UUID (Foreign Keys)")
+ # Changes on Audit Log Table
+ for audit_log in AuditLog.select():
+ old_server_id = audit_log.server_id_id
+ if old_server_id == "0" or old_server_id is None:
+ server_uuid = None
+ else:
+ try:
+ server = Servers.get_by_id(old_server_id)
+ server_uuid = server.server_uuid
+ except:
+ server_uuid = old_server_id
+ AuditLog.update(server_id=server_uuid).where(
+ AuditLog.audit_id == audit_log.audit_id
+ ).execute()
+
+ # Changes on Webhooks Log Table
+ for webhook in Webhooks.select():
+ old_server_id = webhook.server_id_id
+ try:
+ server = Servers.get_by_id(old_server_id)
+ server_uuid = server.server_uuid
+ except:
+ server_uuid = old_server_id
+ Webhooks.update(server_id=server_uuid).where(
+ Webhooks.id == webhook.id
+ ).execute()
+
+ # Changes on Schedules Log Table
+ for schedule in Schedules.select():
+ old_server_id = schedule.server_id_id
+ try:
+ server = Servers.get_by_id(old_server_id)
+ server_uuid = server.server_uuid
+ except:
+ server_uuid = old_server_id
+ Schedules.update(server_id=server_uuid).where(
+ Schedules.schedule_id == schedule.schedule_id
+ ).execute()
+
+ # Changes on Backups Log Table
+ for backup in Backups.select():
+ old_server_id = backup.server_id_id
+ try:
+ server = Servers.get_by_id(old_server_id)
+ server_uuid = server.server_uuid
+ except:
+ server_uuid = old_server_id
+ Backups.update(server_id=server_uuid).where(
+ Backups.server_id == old_server_id
+ ).execute()
+
+ # Changes on RoleServers Log Table
+ for role_servers in RoleServers.select():
+ old_server_id = role_servers.server_id_id
+ try:
+ server = Servers.get_by_id(old_server_id)
+ server_uuid = server.server_uuid
+ except:
+ server_uuid = old_server_id
+ RoleServers.update(server_id=server_uuid).where(
+ RoleServers.role_id == role_servers.id
+ and RoleServers.server_id == old_server_id
+ ).execute()
+
+ logger.info("Migrating Data from Int to UUID (Foreign Keys) : SUCCESS")
+ Console.info("Migrating Data from Int to UUID (Foreign Keys) : SUCCESS")
+
+ except Exception as ex:
+ logger.error("Error while migrating Data from Int to UUID (Foreign Keys)")
+ logger.error(ex)
+ Console.error("Error while migrating Data from Int to UUID (Foreign Keys)")
+ Console.error(ex)
+ last_migration = MigrateHistory.get_by_id(MigrateHistory.select().count())
+ last_migration.delete()
+ return
+
+ try:
+ logger.info("Migrating Data from Int to UUID (Primary Keys)")
+ Console.info("Migrating Data from Int to UUID (Primary Keys)")
+ # Migrating servers from the old id type to the new one
+ for server in Servers.select():
+ Servers.update(server_id=server.server_uuid).where(
+ Servers.server_id == server.server_id
+ ).execute()
+
+ logger.info("Migrating Data from Int to UUID (Primary Keys) : SUCCESS")
+ Console.info("Migrating Data from Int to UUID (Primary Keys) : SUCCESS")
+
+ except Exception as ex:
+ logger.error("Error while migrating Data from Int to UUID (Primary Keys)")
+ logger.error(ex)
+ Console.error("Error while migrating Data from Int to UUID (Primary Keys)")
+ Console.error(ex)
+ last_migration = MigrateHistory.get_by_id(MigrateHistory.select().count())
+ last_migration.delete()
+ return
+
+ # Changes on Server Table
+ logger.info("Migrating Data from Int to UUID (Removing UUID Field from Servers)")
+ Console.info("Migrating Data from Int to UUID (Removing UUID Field from Servers)")
+ migrator.drop_columns("servers", ["server_uuid"])
+ migrator.run()
+ logger.info(
+ "Migrating Data from Int to UUID (Removing UUID Field from Servers) : SUCCESS"
+ )
+ Console.info(
+ "Migrating Data from Int to UUID (Removing UUID Field from Servers) : SUCCESS"
+ )
+
+ return
+
+
+def rollback(migrator: Migrator, database, **kwargs):
+ """
+ Write your rollback migrations here.
+ """
+ db = database
+
+ # Changes on Server Table
+ migrator.alter_column_type(
+ "servers",
+ "server_id",
+ peewee.AutoField(),
+ )
+
+ # Changes on Audit Log Table
+ migrator.alter_column_type(
+ AuditLog,
+ "server_id",
+ peewee.IntegerField(default=None, index=True),
+ )
+
+ # Changes on Webhook Table
+ migrator.alter_column_type(
+ Webhooks,
+ "server_id",
+ peewee.IntegerField(null=True),
+ )
diff --git a/sonar-project.properties b/sonar-project.properties
index 635324ef..b6fa060c 100644
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -3,7 +3,7 @@ sonar.organization=crafty-controller
# This is the name and version displayed in the SonarCloud UI.
sonar.projectName=Crafty 4
-sonar.projectVersion=4.2.4
+sonar.projectVersion=4.3.1
sonar.python.version=3.9, 3.10, 3.11
sonar.exclusions=app/migrations/**, app/frontend/static/assets/vendors/**