diff --git a/app/classes/models/management.py b/app/classes/models/management.py
index 24505471..495d3e38 100644
--- a/app/classes/models/management.py
+++ b/app/classes/models/management.py
@@ -357,7 +357,7 @@ class HelpersManagement:
data[str(backup.backup_id)] = {
"backup_id": backup.backup_id,
"backup_name": backup.backup_name,
- "backup_path": backup.backup_location,
+ "backup_location": backup.backup_location,
"excluded_dirs": backup.excluded_dirs,
"max_backups": backup.max_backups,
"server_id": backup.server_id_id,
diff --git a/app/classes/shared/file_helpers.py b/app/classes/shared/file_helpers.py
index 3c14447c..a7e27555 100644
--- a/app/classes/shared/file_helpers.py
+++ b/app/classes/shared/file_helpers.py
@@ -235,6 +235,7 @@ class FileHelpers:
path_to_zip,
excluded_dirs,
server_id,
+ backup_id,
comment="",
compressed=None,
):
@@ -306,6 +307,7 @@ class FileHelpers:
results = {
"percent": percent,
"total_files": self.helper.human_readable_file_size(dir_bytes),
+ "backup_id": backup_id,
}
# send status results to page.
WebSocketManager().broadcast_page_params(
diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py
index 0182afc5..e265b0ca 100644
--- a/app/classes/shared/server.py
+++ b/app/classes/shared/server.py
@@ -1197,6 +1197,7 @@ class ServerInstance:
server_dir,
excluded_dirs,
self.server_id,
+ backup_id,
conf["backup_name"],
conf["compress"],
)
@@ -1205,7 +1206,7 @@ class ServerInstance:
len(self.list_backups(backup_location)) > conf["max_backups"]
and conf["max_backups"] > 0
):
- backup_list = self.list_backups()
+ backup_list = self.list_backups(conf["backup_location"])
oldfile = backup_list[0]
oldfile_path = f"{backup_location}/{oldfile['path']}"
logger.info(f"Removing old backup '{oldfile['path']}'")
@@ -1213,7 +1214,12 @@ class ServerInstance:
self.is_backingup = False
logger.info(f"Backup of server: {self.name} completed")
- results = {"percent": 100, "total_files": 0, "current_file": 0}
+ results = {
+ "percent": 100,
+ "total_files": 0,
+ "current_file": 0,
+ "backup_id": backup_id,
+ }
if len(WebSocketManager().clients) > 0:
WebSocketManager().broadcast_page_params(
"/panel/server_detail",
@@ -1251,7 +1257,12 @@ class ServerInstance:
logger.exception(
f"Failed to create backup of server {self.name} (ID {self.server_id})"
)
- results = {"percent": 100, "total_files": 0, "current_file": 0}
+ results = {
+ "percent": 100,
+ "total_files": 0,
+ "current_file": 0,
+ "backup_id": backup_id,
+ }
if len(WebSocketManager().clients) > 0:
WebSocketManager().broadcast_page_params(
"/panel/server_detail",
@@ -1267,17 +1278,6 @@ class ServerInstance:
self.run_threaded_server(HelperUsers.get_user_id_by_name("system"))
self.last_backup_failed = True
- def backup_status(self, source_path, dest_path):
- results = Helpers.calc_percent(source_path, dest_path)
- self.backup_stats = results
- if len(WebSocketManager().clients) > 0:
- WebSocketManager().broadcast_page_params(
- "/panel/server_detail",
- {"id": str(self.server_id)},
- "backup_status",
- results,
- )
-
def last_backup_status(self):
return self.last_backup_failed
diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py
index 962a5abb..4461f0d3 100644
--- a/app/classes/web/panel_handler.py
+++ b/app/classes/web/panel_handler.py
@@ -1286,7 +1286,9 @@ class PanelHandler(BaseHandler):
)
self.controller.servers.refresh_server_settings(server_id)
try:
- page_data["backup_list"] = server.list_backups()
+ page_data["backup_list"] = server.list_backups(
+ page_data["backup_config"]["backup_location"]
+ )
except:
page_data["backup_list"] = []
page_data["backup_path"] = Helpers.wtol_path(
diff --git a/app/classes/web/routes/api/api_handlers.py b/app/classes/web/routes/api/api_handlers.py
index 3bdf27ef..78df3ed5 100644
--- a/app/classes/web/routes/api/api_handlers.py
+++ b/app/classes/web/routes/api/api_handlers.py
@@ -218,7 +218,7 @@ def api_handlers(handler_args):
handler_args,
),
(
- r"/api/v2/servers/([a-z0-9-]+)/backups/backup/?",
+ r"/api/v2/servers/([a-z0-9-]+)/backups/backup/([a-z0-9-]+)/?",
ApiServersServerBackupsBackupIndexHandler,
handler_args,
),
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 cfe8f4b1..fba7bad8 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
@@ -11,7 +11,7 @@ from app.classes.shared.helpers import Helpers
logger = logging.getLogger(__name__)
-backup_schema = {
+BACKUP_SCHEMA = {
"type": "object",
"properties": {
"filename": {"type": "string", "minLength": 5},
@@ -19,11 +19,40 @@ backup_schema = {
"additionalProperties": False,
"minProperties": 1,
}
+BACKUP_PATCH_SCHEMA = {
+ "type": "object",
+ "properties": {
+ "backup_location": {"type": "string", "minLength": 1},
+ "max_backups": {"type": "integer"},
+ "compress": {"type": "boolean"},
+ "shutdown": {"type": "boolean"},
+ "before": {"type": "string"},
+ "after": {"type": "string"},
+ "exclusions": {"type": "array"},
+ },
+ "additionalProperties": False,
+ "minProperties": 1,
+}
+
+BASIC_BACKUP_PATCH_SCHEMA = {
+ "type": "object",
+ "properties": {
+ "max_backups": {"type": "integer"},
+ "compress": {"type": "boolean"},
+ "shutdown": {"type": "boolean"},
+ "before": {"type": "string"},
+ "after": {"type": "string"},
+ "exclusions": {"type": "array"},
+ },
+ "additionalProperties": False,
+ "minProperties": 1,
+}
class ApiServersServerBackupsBackupIndexHandler(BaseApiHandler):
- def get(self, server_id: str):
+ def get(self, server_id: str, backup_id: str):
auth_data = self.authenticate_user()
+ backup_conf = self.controller.management.get_backup_config(backup_id)
if not auth_data:
return
mask = self.controller.server_perms.get_lowest_api_perm_mask(
@@ -32,15 +61,40 @@ class ApiServersServerBackupsBackupIndexHandler(BaseApiHandler):
),
auth_data[5],
)
+ if backup_conf["server_id"]["server_id"] != server_id:
+ return self.finish_json(
+ 400,
+ {
+ "status": "error",
+ "error": "ID_MISMATCH",
+ "error_data": "Server ID backup server ID different",
+ },
+ )
server_permissions = self.controller.server_perms.get_permissions(mask)
if EnumPermissionsServer.BACKUP not in server_permissions:
# if the user doesn't have Schedule permission, return an error
- return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
- self.finish_json(200, self.controller.management.get_backup_config(server_id))
+ return self.finish_json(
+ 400,
+ {
+ "status": "error",
+ "error": "NOT_AUTHORIZED",
+ "error_data": "Authorization Error",
+ },
+ )
+ self.finish_json(200, backup_conf)
- def delete(self, server_id: str):
+ def delete(self, server_id: str, backup_id: str):
auth_data = self.authenticate_user()
- backup_conf = self.controller.management.get_backup_config(server_id)
+ backup_conf = self.controller.management.get_backup_config(backup_id)
+ if backup_conf["server_id"]["server_id"] != server_id:
+ return self.finish_json(
+ 400,
+ {
+ "status": "error",
+ "error": "ID_MISMATCH",
+ "error_data": "Server ID backup server ID different",
+ },
+ )
if not auth_data:
return
mask = self.controller.server_perms.get_lowest_api_perm_mask(
@@ -52,7 +106,14 @@ class ApiServersServerBackupsBackupIndexHandler(BaseApiHandler):
server_permissions = self.controller.server_perms.get_permissions(mask)
if EnumPermissionsServer.BACKUP not in server_permissions:
# if the user doesn't have Schedule permission, return an error
- return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
+ return self.finish_json(
+ 400,
+ {
+ "status": "error",
+ "error": "NOT_AUTHORIZED",
+ "error_data": "Authorization Error",
+ },
+ )
try:
data = json.loads(self.request.body)
@@ -61,7 +122,7 @@ class ApiServersServerBackupsBackupIndexHandler(BaseApiHandler):
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
)
try:
- validate(data, backup_schema)
+ validate(data, BACKUP_SCHEMA)
except ValidationError as e:
return self.finish_json(
400,
@@ -74,7 +135,7 @@ class ApiServersServerBackupsBackupIndexHandler(BaseApiHandler):
try:
FileHelpers.del_file(
- os.path.join(backup_conf["backup_path"], data["filename"])
+ os.path.join(backup_conf["backup_location"], data["filename"])
)
except Exception as e:
return self.finish_json(
@@ -89,7 +150,7 @@ class ApiServersServerBackupsBackupIndexHandler(BaseApiHandler):
return self.finish_json(200, {"status": "ok"})
- def post(self, server_id: str):
+ def post(self, server_id: str, backup_id: str):
auth_data = self.authenticate_user()
if not auth_data:
return
@@ -102,7 +163,24 @@ class ApiServersServerBackupsBackupIndexHandler(BaseApiHandler):
server_permissions = self.controller.server_perms.get_permissions(mask)
if EnumPermissionsServer.BACKUP not in server_permissions:
# if the user doesn't have Schedule permission, return an error
- return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
+ return self.finish_json(
+ 400,
+ {
+ "status": "error",
+ "error": "NOT_AUTHORIZED",
+ "error_data": "Authorization Error",
+ },
+ )
+ backup_config = self.controller.management.get_backup_config(backup_id)
+ if backup_config["server_id"] != server_id:
+ return self.finish_json(
+ 400,
+ {
+ "status": "error",
+ "error": "ID_MISMATCH",
+ "error_data": "Server ID backup server ID different",
+ },
+ )
try:
data = json.loads(self.request.body)
@@ -111,7 +189,7 @@ class ApiServersServerBackupsBackupIndexHandler(BaseApiHandler):
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
)
try:
- validate(data, backup_schema)
+ validate(data, BACKUP_SCHEMA)
except ValidationError as e:
return self.finish_json(
400,
@@ -184,7 +262,6 @@ class ApiServersServerBackupsBackupIndexHandler(BaseApiHandler):
self.controller.servers.update_server(new_server_obj)
# preserve backup config
- backup_config = self.controller.management.get_backup_config(server_id)
excluded_dirs = []
server_obj = self.controller.servers.get_server_obj(server_id)
loop_backup_path = self.helper.wtol_path(server_obj.path)
@@ -221,3 +298,70 @@ class ApiServersServerBackupsBackupIndexHandler(BaseApiHandler):
)
return self.finish_json(200, {"status": "ok"})
+
+ def patch(self, server_id: str, backup_id: str):
+ auth_data = self.authenticate_user()
+ if not auth_data:
+ return
+
+ try:
+ data = json.loads(self.request.body)
+ except json.decoder.JSONDecodeError as e:
+ return self.finish_json(
+ 400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
+ )
+
+ try:
+ if auth_data[4]["superuser"]:
+ validate(data, BACKUP_PATCH_SCHEMA)
+ else:
+ validate(data, BASIC_BACKUP_PATCH_SCHEMA)
+ except ValidationError as e:
+ return self.finish_json(
+ 400,
+ {
+ "status": "error",
+ "error": "INVALID_JSON_SCHEMA",
+ "error_data": str(e),
+ },
+ )
+ backup_conf = self.controller.management.get_backup_config(backup_id)
+ if server_id not in [str(x["server_id"]) for x in auth_data[0]]:
+ # if the user doesn't have access to the server, return an error
+ return self.finish_json(
+ 400,
+ {
+ "status": "error",
+ "error": "NOT_AUTHORIZED",
+ "error_data": "Authorization Error",
+ },
+ )
+ if backup_conf["server_id"]["server_id"] != server_id:
+ return self.finish_json(
+ 400,
+ {
+ "status": "error",
+ "error": "ID_MISMATCH",
+ "error_data": "Server ID backup server ID different",
+ },
+ )
+ mask = self.controller.server_perms.get_lowest_api_perm_mask(
+ self.controller.server_perms.get_user_permissions_mask(
+ auth_data[4]["user_id"], server_id
+ ),
+ auth_data[5],
+ )
+ server_permissions = self.controller.server_perms.get_permissions(mask)
+ if EnumPermissionsServer.BACKUP not in server_permissions:
+ # if the user doesn't have Schedule permission, return an error
+ return self.finish_json(
+ 400,
+ {
+ "status": "error",
+ "error": "NOT_AUTHORIZED",
+ "error_data": "Authorization Error",
+ },
+ )
+
+ self.controller.management.update_backup_config(backup_id, data)
+ return self.finish_json(200, {"status": "ok"})
diff --git a/app/classes/web/routes/api/servers/server/backups/index.py b/app/classes/web/routes/api/servers/server/backups/index.py
index 55744ea1..51b69473 100644
--- a/app/classes/web/routes/api/servers/server/backups/index.py
+++ b/app/classes/web/routes/api/servers/server/backups/index.py
@@ -10,12 +10,12 @@ logger = logging.getLogger(__name__)
backup_patch_schema = {
"type": "object",
"properties": {
- "backup_path": {"type": "string", "minLength": 1},
+ "backup_location": {"type": "string", "minLength": 1},
"max_backups": {"type": "integer"},
"compress": {"type": "boolean"},
"shutdown": {"type": "boolean"},
- "backup_before": {"type": "string"},
- "backup_after": {"type": "string"},
+ "before": {"type": "string"},
+ "after": {"type": "string"},
"exclusions": {"type": "array"},
},
"additionalProperties": False,
@@ -28,8 +28,8 @@ basic_backup_patch_schema = {
"max_backups": {"type": "integer"},
"compress": {"type": "boolean"},
"shutdown": {"type": "boolean"},
- "backup_before": {"type": "string"},
- "backup_after": {"type": "string"},
+ "before": {"type": "string"},
+ "after": {"type": "string"},
"exclusions": {"type": "array"},
},
"additionalProperties": False,
@@ -52,9 +52,11 @@ class ApiServersServerBackupsIndexHandler(BaseApiHandler):
if EnumPermissionsServer.BACKUP not in server_permissions:
# if the user doesn't have Schedule permission, return an error
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
- self.finish_json(200, self.controller.management.get_backup_config(server_id))
+ self.finish_json(
+ 200, self.controller.management.get_backups_by_server(server_id)
+ )
- def patch(self, backup_id: str):
+ def post(self, server_id: str):
auth_data = self.authenticate_user()
if not auth_data:
return
@@ -80,8 +82,6 @@ class ApiServersServerBackupsIndexHandler(BaseApiHandler):
"error_data": str(e),
},
)
- backup_conf = self.controller.management.get_backup_config(backup_id)
- server_id = backup_conf["server_id"]
if server_id not in [str(x["server_id"]) for x in auth_data[0]]:
# if the user doesn't have access to the server, return an error
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
diff --git a/app/frontend/templates/panel/server_backup_edit.html b/app/frontend/templates/panel/server_backup_edit.html
index c68d521f..1ec54d48 100644
--- a/app/frontend/templates/panel/server_backup_edit.html
+++ b/app/frontend/templates/panel/server_backup_edit.html
@@ -67,7 +67,7 @@
-
{% end %}
@@ -107,14 +107,14 @@
{{
translate('serverBackups', 'before', data['lang']) }}
-
{% else %}
{{
translate('serverBackups', 'before', data['lang']) }}
-
{% end %}
@@ -124,14 +124,14 @@
{{
translate('serverBackups', 'after', data['lang']) }}
-
{% else %}
{{
translate('serverBackups', 'after', data['lang']) }}
-
{% end %}
@@ -206,7 +206,8 @@
-