Add a Copy image file flow to the Web UI. (#760)

* Add a Copy image file flow to the Web UI.

* Introduce a generic file creation message and use that consistently.

* Clarify code comment
This commit is contained in:
Daniel Markstedt 2022-06-14 19:03:56 -07:00 committed by GitHub
parent a5d397b3fc
commit 6397d9c9a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 91 additions and 17 deletions

View File

@ -11,6 +11,7 @@ from re import escape, findall
from time import time
from subprocess import run, CalledProcessError
from json import dump, load
from shutil import copyfile
import requests
@ -180,6 +181,25 @@ class FileCmds:
result.ParseFromString(data)
return {"status": result.status, "msg": result.msg}
def copy_image(self, file_name, new_file_name):
"""
Takes (str) file_name, (str) new_file_name
Sends a COPY_IMAGE command to the server
Returns (dict) with (bool) status and (str) msg
"""
command = proto.PbCommand()
command.operation = proto.PbOperation.COPY_IMAGE
command.params["token"] = self.ractl.token
command.params["locale"] = self.ractl.locale
command.params["from"] = file_name
command.params["to"] = new_file_name
data = self.sock_cmd.send_pb_command(command.SerializeToString())
result = proto.PbResult()
result.ParseFromString(data)
return {"status": result.status, "msg": result.msg}
# noinspection PyMethodMayBeStatic
def delete_file(self, file_path):
"""
@ -224,6 +244,28 @@ class FileCmds:
"parameters": parameters,
}
# noinspection PyMethodMayBeStatic
def copy_file(self, file_path, target_path):
"""
Takes (str) file_path and (str) target_path
Returns (dict) with (bool) status and (str) msg
"""
parameters = {
"target_path": target_path
}
if os.path.exists(PurePath(target_path).parent):
copyfile(file_path, target_path)
return {
"status": True,
"return_code": ReturnCodes.WRITEFILE_SUCCESS,
"parameters": parameters,
}
return {
"status": False,
"return_code": ReturnCodes.WRITEFILE_UNABLE_TO_WRITE,
"parameters": parameters,
}
def unzip_file(self, file_name, member=False, members=False):
"""
Takes (str) file_name, optional (str) member, optional (list) of (str) members
@ -404,11 +446,11 @@ class FileCmds:
indent=4
)
parameters = {
"file_name": file_name
"target_path": file_name
}
return {
"status": True,
"return_code": ReturnCodes.WRITECONFIG_SUCCESS,
"return_code": ReturnCodes.WRITEFILE_SUCCESS,
"parameters": parameters,
}
except (IOError, ValueError, EOFError, TypeError) as error:
@ -423,7 +465,7 @@ class FileCmds:
}
return {
"status": False,
"return_code": ReturnCodes.WRITECONFIG_COULD_NOT_WRITE,
"return_code": ReturnCodes.WRITEFILE_COULD_NOT_WRITE,
"parameters": parameters,
}
@ -515,11 +557,11 @@ class FileCmds:
with open(file_path, "w") as json_file:
dump(conf, json_file, indent=4)
parameters = {
"file_path": file_path
"target_path": file_path
}
return {
"status": True,
"return_code": ReturnCodes.WRITEDRIVEPROPS_SUCCESS,
"return_code": ReturnCodes.WRITEFILE_SUCCESS,
"parameters": parameters,
}
except (IOError, ValueError, EOFError, TypeError) as error:
@ -530,11 +572,11 @@ class FileCmds:
logging.error("Could not write to file: %s", file_path)
self.delete_file(file_path)
parameters = {
"file_path": file_path
"target_path": file_path
}
return {
"status": False,
"return_code": ReturnCodes.WRITEDRIVEPROPS_COULD_NOT_WRITE,
"return_code": ReturnCodes.WRITEFILE_COULD_NOT_WRITE,
"parameters": parameters,
}

View File

@ -12,13 +12,11 @@ class ReturnCodes:
RENAMEFILE_UNABLE_TO_MOVE = 11
DOWNLOADFILETOISO_SUCCESS = 20
DOWNLOADTODIR_SUCCESS = 30
WRITECONFIG_SUCCESS = 40
WRITECONFIG_COULD_NOT_WRITE = 41
WRITEFILE_SUCCESS = 40
WRITEFILE_COULD_NOT_WRITE = 41
READCONFIG_SUCCESS = 50
READCONFIG_COULD_NOT_READ = 51
READCONFIG_INVALID_CONFIG_FILE_FORMAT = 51
WRITEDRIVEPROPS_SUCCESS = 60
WRITEDRIVEPROPS_COULD_NOT_WRITE = 61
READCONFIG_INVALID_CONFIG_FILE_FORMAT = 52
READDRIVEPROPS_SUCCESS = 70
READDRIVEPROPS_COULD_NOT_READ = 71
ATTACHIMAGE_COULD_NOT_ATTACH = 80

View File

@ -16,15 +16,12 @@ class ReturnCodeMapper:
ReturnCodes.DOWNLOADFILETOISO_SUCCESS: _("Created CD-ROM ISO image with "
"arguments \"%(value)s\""),
ReturnCodes.DOWNLOADTODIR_SUCCESS: _("%(file_name)s downloaded to %(save_dir)s"),
ReturnCodes.WRITECONFIG_SUCCESS: _("Saved configuration file to %(file_name)s"),
ReturnCodes.WRITECONFIG_COULD_NOT_WRITE: _("Could not write to file: %(file_name)s"),
ReturnCodes.WRITEFILE_SUCCESS: _("File created: %(target_path)s"),
ReturnCodes.WRITEFILE_COULD_NOT_WRITE: _("Could not create file: %(target_path)s"),
ReturnCodes.READCONFIG_SUCCESS: _("Loaded configurations from: %(file_name)s"),
ReturnCodes.READCONFIG_COULD_NOT_READ: _("Could not read configuration "
"file: %(file_name)s"),
ReturnCodes.READCONFIG_INVALID_CONFIG_FILE_FORMAT: _("Invalid configuration file format"),
ReturnCodes.WRITEDRIVEPROPS_SUCCESS: _("Created properties file: %(file_path)s"),
ReturnCodes.WRITEDRIVEPROPS_COULD_NOT_WRITE: _("Could not write to properties "
"file: %(file_path)s"),
ReturnCodes.READDRIVEPROPS_SUCCESS: _("Read properties from file: %(file_path)s"),
ReturnCodes.READDRIVEPROPS_COULD_NOT_READ: _("Could not read properties from "
"file: %(file_path)s"),

View File

@ -283,6 +283,11 @@
<input name="new_file_name" id="new_file_name_{{ loop.index }}" type="hidden" value="">
<input type="submit" value="{{ _("Rename") }}">
</form>
<form action="/files/copy" method="post" onsubmit="var copy_file_name = prompt('{{ _("Save copy of %(file_name)s as:", file_name=file["name"]) }}', '{{ file['name'] }}'); if (copy_file_name === null) event.preventDefault(); document.getElementById('copy_file_name_{{ loop.index }}').value = copy_file_name;">
<input name="file_name" type="hidden" value="{{ file['name'] }}">
<input name="copy_file_name" id="copy_file_name_{{ loop.index }}" type="hidden" value="">
<input type="submit" value="{{ _("Copy") }}">
</form>
<form action="/files/delete" method="post" onsubmit="return confirm('{{ _("Delete file: %(file_name)s?", file_name=file["name"]) }}')">
<input name="file_name" type="hidden" value="{{ file['name'] }}">
<input type="submit" value="{{ _("Delete") }}">

View File

@ -912,6 +912,38 @@ def rename():
return redirect(url_for("index"))
@APP.route("/files/copy", methods=["POST"])
@login_required
def copy():
"""
Creates a copy of a specified file in the images dir
"""
file_name = request.form.get("file_name")
new_file_name = request.form.get("copy_file_name")
process = file_cmd.copy_image(file_name, new_file_name)
if process["status"]:
flash(_("Copy of image file saved as: %(file_name)s", file_name=new_file_name))
else:
flash(process["msg"], "error")
return redirect(url_for("index"))
# Create a copy of the drive properties file, if it exists
prop_file_path = f"{CFG_DIR}/{file_name}.{PROPERTIES_SUFFIX}"
new_prop_file_path = f"{CFG_DIR}/{new_file_name}.{PROPERTIES_SUFFIX}"
if Path(prop_file_path).is_file():
process = file_cmd.copy_file(prop_file_path, new_prop_file_path)
process = ReturnCodeMapper.add_msg(process)
if process["status"]:
flash(process["msg"])
return redirect(url_for("index"))
flash(process["msg"], "error")
return redirect(url_for("index"))
return redirect(url_for("index"))
@APP.route("/files/unzip", methods=["POST"])
@login_required
def unzip():