Merge branch 'dev' into refactor/rework-css

This commit is contained in:
Silversthorn 2024-03-09 22:06:24 +01:00
commit 252b37ad53
32 changed files with 399 additions and 120 deletions

View File

@ -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
<br><br>
## --- [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))

View File

@ -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?

View File

@ -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}")

View File

@ -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):

View File

@ -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):

View File

@ -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):

View File

@ -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

View File

@ -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(

View File

@ -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:
"""

View File

@ -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

View File

@ -140,7 +140,7 @@ class TasksManager:
)
elif command == "backup_server":
svr.backup_server()
svr.a_backup_server()
elif command == "update_executable":
svr.jar_update()

View File

@ -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"],

View File

@ -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,
),

View File

@ -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,
},
},
)

View File

@ -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

View File

@ -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(

View File

@ -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

View File

@ -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,
),

View File

@ -1,5 +1,5 @@
{
"major": 4,
"minor": 2,
"sub": 4
"minor": 3,
"sub": 1
}

View File

@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<small>UUID: {{ data['server_stats']['server_id']['server_id'] }}</small>
</h4>
</div>
</div>

View File

@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<small>UUID: {{ data['server_stats']['server_id']['server_id'] }}</small>
</h4>
</div>
</div>
@ -454,7 +454,7 @@
});
}
});
try {
if ($('#backup_path').val() == '') {
console.log('true')

View File

@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<small>UUID: {{ data['server_stats']['server_id']['server_id'] }}</small>
</h4>
</div>
</div>

View File

@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<small>UUID: {{ data['server_stats']['server_id']['server_id'] }}</small>
</h4>
</div>
</div>

View File

@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<small>UUID: {{ data['server_stats']['server_id']['server_id'] }}</small>
</h4>
</div>
</div>

View File

@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<small>UUID: {{ data['server_stats']['server_id']['server_id'] }}</small>
</h4>
</div>
</div>

View File

@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<small>UUID: {{ data['server_stats']['server_id']['server_id'] }}</small>
</h4>
</div>
</div>
@ -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
});
}
}
});
});

View File

@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<small>UUID: {{ data['server_stats']['server_id']['server_id'] }}</small>
</h4>
</div>
</div>

View File

@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<small>UUID: {{ data['server_stats']['server_id']['server_id'] }}</small>
</h4>
</div>
</div>

View File

@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<small>UUID: {{ data['server_stats']['server_id']['server_id'] }}</small>
</h4>
</div>
</div>
@ -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);
}

View File

@ -17,7 +17,7 @@
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<small>UUID: {{ data['server_stats']['server_id']['server_id'] }}</small>
</h4>
</div>
</div>

View File

@ -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),
)

View File

@ -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/**