Merge branch 'dev' into bugfix/backup-download

This commit is contained in:
Zedifus
2025-11-22 17:01:59 +00:00
8 changed files with 67 additions and 19 deletions

View File

@@ -6,8 +6,12 @@ TBD
- Change hour and minute intervals in APScheudler to fix incorrect triggers ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/910))
- Use asyncio locks to limit upload handler race condition ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/907))
- Fix static fonts not working on some browsers ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/906))
- Fix import directory cleanup was not pointing to the proper directory ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/918))
- Fix survey not appearing on first login ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/917))
- Fix failue deleting server's DB files on server delete ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/916))
- Fix server.properties overwritten in bedrock update ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/915))
### Tweaks
TBD
- Provide better feedback on restore failures ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/914))
### Lang
TBD
<br><br>

View File

@@ -177,7 +177,9 @@ class ServersController(metaclass=Singleton):
server_id,
)
self.file_helper.del_dirs(
self.helper.root_dir, "app", "config", "db", "servers", str(server_id)
pathlib.Path(
self.helper.root_dir, "app", "config", "db", "servers", str(server_id)
)
)
@staticmethod

View File

@@ -126,6 +126,7 @@ class FileHelpers:
@staticmethod
def del_dirs(path):
path = pathlib.Path(path)
clean = True
for sub in path.iterdir():
if sub.is_dir():
# Delete folder if it is a folder
@@ -135,26 +136,29 @@ class FileHelpers:
try:
sub.unlink()
except Exception as e:
clean = False
logger.error(f"Unable to delete file {sub}: {e}")
try:
# This removes the top-level folder:
path.rmdir()
except Exception as e:
except Exception:
logger.error("Unable to remove top level")
return e
return True
return False
return clean
@staticmethod
def del_file(path):
path = pathlib.Path(path)
clean = True
try:
logger.debug(f"Deleting file: {path}")
# Remove the file
os.remove(path)
return True
except (FileNotFoundError, PermissionError) as e:
return clean
except (FileNotFoundError, PermissionError):
logger.error(f"Path specified is not a file or does not exist. {path}")
return e
clean = False
return clean
def check_mime_types(self, file_path):
m_type, _value = self.mime_types.guess_type(file_path)

View File

@@ -45,6 +45,7 @@ class BackupManager:
self, backup_config, backup_location, backup_file, svr_obj, in_place
):
server_path = svr_obj.settings["path"]
error = False
if Helpers.validate_traversal(backup_location, backup_file):
if svr_obj.check_running():
svr_obj.stop_server()
@@ -58,10 +59,40 @@ class BackupManager:
os.path.isdir(os.path.join(server_path, item))
and item != "db_stats"
):
self.file_helper.del_dirs(os.path.join(server_path, item))
result = self.file_helper.del_dirs(
os.path.join(server_path, item)
)
if not result:
error = True
else:
self.file_helper.del_file(os.path.join(server_path, item))
result = self.file_helper.del_file(
os.path.join(server_path, item)
)
if not result:
error = True
self.file_helper.restore_archive(backup_location, server_path)
server_users = PermissionsServers.get_server_user_list(svr_obj.server_id)
time.sleep(3)
if error:
for user in server_users:
WebSocketManager().broadcast_user(
user,
"send_start_error",
self.helper.translation.translate(
"notify", "restoreFailed", HelperUsers.get_user_lang_by_id(user)
),
)
else:
for user in server_users:
WebSocketManager().broadcast_user(
user,
"notification",
self.helper.translation.translate(
"notify",
"restoreSuccess",
HelperUsers.get_user_lang_by_id(user),
),
)
def backup_starter(self, backup_config, server):
"""Notify users of backup starting, and start the backup.

View File

@@ -244,7 +244,7 @@ class ImportHelpers:
unzip_path = self.helper.wtol_path(file_path)
# unzips archive that was downloaded.
self.file_helper.unzip_file(unzip_path)
self.file_helper.unzip_file(unzip_path, True)
# adjusts permissions for execution if os is not windows
if not self.helper.is_os_windows():

View File

@@ -5,6 +5,7 @@ import threading
import asyncio
import datetime
import json
from pathlib import Path
from zoneinfo import ZoneInfoNotFoundError
from tzlocal import get_localzone
from apscheduler.events import EVENT_JOB_EXECUTED
@@ -815,15 +816,16 @@ class TasksManager:
os.remove(os.path.join(file))
except FileNotFoundError:
logger.debug("Could not clear out file from temp directory")
for file in os.listdir(
os.path.join(self.controller.project_root, "import", "upload")
):
if self.helper.is_file_older_than_x_days(
os.path.join(self.controller.project_root, "import", "upload", file)
):
import_path = Path(self.controller.project_root, "import", "upload")
for file in os.listdir(import_path):
file_path = Path(import_path, file).resolve(strict=True)
if not self.helper.validate_traversal(import_path, file_path):
logger.error(
"Traversal detected while deleting import file %s", file_path
)
if self.helper.is_file_older_than_x_days(file_path):
try:
os.remove(os.path.join(file))
os.remove(file_path)
except FileNotFoundError:
logger.debug("Could not clear out file from import directory")

View File

@@ -283,6 +283,8 @@
"finishedPreparing": "We've finished preparing your support logs. Please click download to download",
"logout": "Logout",
"preparingLogs": " Please wait while we prepare your logs... We`ll send a notification when they`re ready. This may take a while for large deployments.",
"restoreFailed": "Backup restore failed. Could not delete files from server directory.",
"restoreSuccess": "Server files restored successfully.",
"schedule_desc": "We detected some or all of your scheduled tasks were not successfully transferred during the upgrade. Please confirm your schedules in the schedules tab.",
"schedule_title": "Schedules Migration Warning",
"supportLogs": "Support Logs"

View File

@@ -21,6 +21,7 @@ from app.classes.logging.log_formatter import JsonFormatter
console = Console()
helper = Helpers()
first_login = False
# Get the path our application is running on.
if getattr(sys, "frozen", False):
APPLICATION_PATH = os.path.dirname(sys.executable)
@@ -388,6 +389,7 @@ if __name__ == "__main__":
f"through your router/firewall if you would like to be able "
f"to access Crafty remotely."
)
first_login = True
PASSWORD = helper.create_pass()
installer.default_settings(PASSWORD)
with open(
@@ -426,6 +428,7 @@ if __name__ == "__main__":
import_helper = ImportHelpers(helper, file_helper)
controller = Controller(database, helper, file_helper, import_helper)
controller.set_project_root(APPLICATION_PATH)
controller.first_login = first_login
tasks_manager = TasksManager(helper, controller, file_helper)
import3 = Import3(helper, controller)
helper.migration_notifications = get_migration_notifications()