WebUI: Traverse target dir to get subdirs to download/upload to (#1115)

This commit is contained in:
Daniel Markstedt 2023-03-04 16:57:32 -08:00 committed by GitHub
parent 3de66af55c
commit 5fd0dc420b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 21 deletions

View File

@ -4,7 +4,7 @@ Module for methods reading from and writing to the file system
import logging import logging
import asyncio import asyncio
from os import walk from os import walk, path
from functools import lru_cache from functools import lru_cache
from pathlib import PurePath, Path from pathlib import PurePath, Path
from zipfile import ZipFile, is_zipfile from zipfile import ZipFile, is_zipfile
@ -57,7 +57,7 @@ class FileCmds:
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
def list_config_files(self): def list_config_files(self):
""" """
Finds fils with file ending CONFIG_FILE_SUFFIX in CFG_DIR. Finds files with file ending CONFIG_FILE_SUFFIX in CFG_DIR.
Returns a (list) of (str) files_list Returns a (list) of (str) files_list
""" """
files_list = [] files_list = []
@ -67,6 +67,26 @@ class FileCmds:
files_list.append(file) files_list.append(file)
return files_list return files_list
# noinspection PyMethodMayBeStatic
def list_subdirs(self, directory):
"""
Finds subdirs within the (str) directory dir.
Returns a (list) of (str) subdir_list.
"""
subdir_list = []
# Filter out file sharing meta data dirs
excluded_dirs = ("Network Trash Folder", "Temporary Items", "TheVolumeSettingsFolder")
for root, dirs, _files in walk(directory, topdown=True):
# Strip out dirs that begin with .
dirs[:] = [d for d in dirs if not d[0] == "."]
for dir in dirs:
if dir not in excluded_dirs:
dirpath = path.join(root, dir)
subdir_list.append(dirpath.replace(directory, "", 1))
subdir_list.sort()
return subdir_list
def list_images(self): def list_images(self):
""" """
Sends a IMAGE_FILES_INFO command to the server Sends a IMAGE_FILES_INFO command to the server

View File

@ -393,8 +393,20 @@
<input name="url" id="download_url" required="" type="url"> <input name="url" id="download_url" required="" type="url">
<input type="radio" name="destination" id="disk_images" value="disk_images" checked="checked"> <input type="radio" name="destination" id="disk_images" value="disk_images" checked="checked">
<label for="disk_images">{{ _("Disk Images") }}</label> <label for="disk_images">{{ _("Disk Images") }}</label>
<select name="images_subdir" id="images_subdir">
{% for dir in images_subdirs %}
<option value="{{dir}}">{{dir}}</option>
{% endfor %}
<option value="/" selected>/</option>
</select>
<input type="radio" name="destination" id="shared_files" value="shared_files"> <input type="radio" name="destination" id="shared_files" value="shared_files">
<label for="shared_files">{{ _("Shared Files") }}</label> <label for="shared_files">{{ _("Shared Files") }}</label>
<select name="shared_subdir" id="shared_subdir">
{% for dir in shared_subdirs %}
<option value="{{dir}}">{{dir}}</option>
{% endfor %}
<option value="/" selected>/</option>
</select>
<input type="submit" value="{{ _("Download") }}" onclick="processNotify('{{ _("Downloading File...") }}')"> <input type="submit" value="{{ _("Download") }}" onclick="processNotify('{{ _("Downloading File...") }}')">
</form> </form>
</section> </section>

View File

@ -14,13 +14,20 @@
<form name="dropper" action="/files/upload" method="post" class="dropzone dz-clickable" enctype="multipart/form-data" id="dropper"> <form name="dropper" action="/files/upload" method="post" class="dropzone dz-clickable" enctype="multipart/form-data" id="dropper">
<input type="radio" name="destination" id="disk_images" value="disk_images" checked="checked"> <input type="radio" name="destination" id="disk_images" value="disk_images" checked="checked">
<label for="disk_images">{{ _("Disk Images") }}</label> <label for="disk_images">{{ _("Disk Images") }}</label>
<select name="subdir" id="subdir"> <select name="images_subdir" id="images_subdir">
{% for subdir, group in formatted_image_files.items() %} {% for dir in images_subdirs %}
<option value="{{subdir}}"{% if subdir == "images/" %} selected{% endif %}>{{subdir}}</option> <option value="{{dir}}">{{dir}}</option>
{% endfor %} {% endfor %}
<option value="/" selected>/</option>
</select> </select>
<input type="radio" name="destination" id="shared_files" value="shared_files"> <input type="radio" name="destination" id="shared_files" value="shared_files">
<label for="shared_files">{{ _("Shared Files") }}</label> <label for="shared_files">{{ _("Shared Files") }}</label>
<select name="shared_subdir" id="shared_subdir">
{% for dir in shared_subdirs %}
<option value="{{dir}}">{{dir}}</option>
{% endfor %}
<option value="/" selected>/</option>
</select>
<input type="radio" name="destination" id="piscsi_config" value="piscsi_config"> <input type="radio" name="destination" id="piscsi_config" value="piscsi_config">
<label for="piscsi_config">{{ _("PiSCSI Config") }}</label> <label for="piscsi_config">{{ _("PiSCSI Config") }}</label>
</form> </form>

View File

@ -275,6 +275,8 @@ def index():
image_suffixes_to_create=image_suffixes_to_create, image_suffixes_to_create=image_suffixes_to_create,
valid_image_suffixes=valid_image_suffixes, valid_image_suffixes=valid_image_suffixes,
drive_properties=format_drive_properties(APP.config["PISCSI_DRIVE_PROPERTIES"]), drive_properties=format_drive_properties(APP.config["PISCSI_DRIVE_PROPERTIES"]),
images_subdirs=file_cmd.list_subdirs(server_info["image_dir"]),
shared_subdirs=file_cmd.list_subdirs(FILE_SERVER_DIR),
RESERVATIONS=RESERVATIONS, RESERVATIONS=RESERVATIONS,
CFG_DIR=CFG_DIR, CFG_DIR=CFG_DIR,
FILE_SERVER_DIR=FILE_SERVER_DIR, FILE_SERVER_DIR=FILE_SERVER_DIR,
@ -314,13 +316,13 @@ def upload_page():
""" """
Sets up the data structures and kicks off the rendering of the file uploading page Sets up the data structures and kicks off the rendering of the file uploading page
""" """
image_files = file_cmd.list_images() server_info = piscsi_cmd.get_server_info()
formatted_image_files = format_image_list(image_files["files"])
return response( return response(
template="upload.html", template="upload.html",
page_title=_("PiSCSI File Upload"), page_title=_("PiSCSI File Upload"),
formatted_image_files=formatted_image_files, images_subdirs=file_cmd.list_subdirs(server_info["image_dir"]),
shared_subdirs=file_cmd.list_subdirs(FILE_SERVER_DIR),
max_file_size=int(int(MAX_FILE_SIZE) / 1024 / 1024), max_file_size=int(int(MAX_FILE_SIZE) / 1024 / 1024),
CFG_DIR=CFG_DIR, CFG_DIR=CFG_DIR,
FILE_SERVER_DIR=FILE_SERVER_DIR, FILE_SERVER_DIR=FILE_SERVER_DIR,
@ -959,11 +961,22 @@ def download_file():
""" """
destination = request.form.get("destination") destination = request.form.get("destination")
url = request.form.get("url") url = request.form.get("url")
if destination == "shared_files": images_subdir = request.form.get("images_subdir")
destination_dir = FILE_SERVER_DIR shared_subdir = request.form.get("shared_subdir")
else: if destination == "disk_images":
safe_path = is_safe_path(Path("." + images_subdir))
if not safe_path["status"]:
return make_response(safe_path["msg"], 403)
server_info = piscsi_cmd.get_server_info() server_info = piscsi_cmd.get_server_info()
destination_dir = server_info["image_dir"] destination_dir = server_info["image_dir"] + images_subdir
elif destination == "shared_files":
safe_path = is_safe_path(Path("." + shared_subdir))
if not safe_path["status"]:
return make_response(safe_path["msg"], 403)
destination_dir = FILE_SERVER_DIR + shared_subdir
else:
return response(error=True, message=_("Unknown destination"))
process = file_cmd.download_to_dir(url, destination_dir, Path(url).name) process = file_cmd.download_to_dir(url, destination_dir, Path(url).name)
process = ReturnCodeMapper.add_msg(process) process = ReturnCodeMapper.add_msg(process)
if process["status"]: if process["status"]:
@ -990,19 +1003,23 @@ def upload_file():
return make_response(auth["msg"], 403) return make_response(auth["msg"], 403)
destination = request.form.get("destination") destination = request.form.get("destination")
subdir = request.form.get("subdir").replace("images/", "", 1) images_subdir = request.form.get("images_subdir")
shared_subdir = request.form.get("shared_subdir")
if destination == "disk_images": if destination == "disk_images":
safe_path = is_safe_path(Path(subdir)) safe_path = is_safe_path(Path("." + images_subdir))
if not safe_path["status"]: if not safe_path["status"]:
return make_response(safe_path["msg"], 403) return make_response(safe_path["msg"], 403)
server_info = piscsi_cmd.get_server_info() server_info = piscsi_cmd.get_server_info()
destination_dir = Path(server_info["image_dir"]) / subdir destination_dir = server_info["image_dir"] + images_subdir
elif destination == "shared_files": elif destination == "shared_files":
destination_dir = FILE_SERVER_DIR safe_path = is_safe_path(Path("." + shared_subdir))
if not safe_path["status"]:
return make_response(safe_path["msg"], 403)
destination_dir = FILE_SERVER_DIR + shared_subdir
elif destination == "piscsi_config": elif destination == "piscsi_config":
destination_dir = CFG_DIR destination_dir = CFG_DIR
else: else:
return make_response("Unknown destination", 403) return make_response(_("Unknown destination"), 403)
return upload_with_dropzonejs(destination_dir) return upload_with_dropzonejs(destination_dir)

View File

@ -207,7 +207,8 @@ def test_extract_file(
http_client.post( http_client.post(
"/files/download_url", "/files/download_url",
data={ data={
"destination": "images", "destination": "disk_images",
"images_subdir": "/",
"url": url, "url": url,
}, },
) )
@ -254,7 +255,7 @@ def test_upload_file(http_client, delete_file):
form_data = { form_data = {
"destination": "disk_images", "destination": "disk_images",
"subdir": "", "images_subdir": "/",
"dzuuid": str(uuid.uuid4()), "dzuuid": str(uuid.uuid4()),
"dzchunkindex": chunk_number, "dzchunkindex": chunk_number,
"dzchunksize": chunk_size, "dzchunksize": chunk_size,
@ -334,6 +335,7 @@ def test_download_properties(http_client, list_files, delete_file):
def test_download_url_to_dir(env, httpserver, http_client, list_files, delete_file): def test_download_url_to_dir(env, httpserver, http_client, list_files, delete_file):
file_name = str(uuid.uuid4()) file_name = str(uuid.uuid4())
http_path = f"/images/{file_name}" http_path = f"/images/{file_name}"
subdir = "/"
url = httpserver.url_for(http_path) url = httpserver.url_for(http_path)
with open("tests/assets/test_image.hds", mode="rb") as file: with open("tests/assets/test_image.hds", mode="rb") as file:
@ -347,7 +349,8 @@ def test_download_url_to_dir(env, httpserver, http_client, list_files, delete_fi
response = http_client.post( response = http_client.post(
"/files/download_url", "/files/download_url",
data={ data={
"destination": "images", "destination": "disk_images",
"images_subdir": subdir,
"url": url, "url": url,
}, },
) )
@ -358,7 +361,8 @@ def test_download_url_to_dir(env, httpserver, http_client, list_files, delete_fi
assert response_data["status"] == STATUS_SUCCESS assert response_data["status"] == STATUS_SUCCESS
assert file_name in list_files() assert file_name in list_files()
assert ( assert (
response_data["messages"][0]["message"] == f"{file_name} downloaded to {env['images_dir']}" response_data["messages"][0]["message"]
== f"{file_name} downloaded to {env['images_dir']}{subdir}"
) )
# Cleanup # Cleanup