From c08d06d81f90a280d23513b0e0d522fd876760f7 Mon Sep 17 00:00:00 2001 From: Philip Sargent Date: Mon, 27 Oct 2025 19:41:32 +0200 Subject: [PATCH] refactored and extended gpxfix() --- core/views/uploads.py | 203 ++++++++++++++++++++------------------ templates/gpxfixform.html | 18 ++-- 2 files changed, 120 insertions(+), 101 deletions(-) diff --git a/core/views/uploads.py b/core/views/uploads.py index 4afb372..7667c41 100644 --- a/core/views/uploads.py +++ b/core/views/uploads.py @@ -88,6 +88,7 @@ class GPXfixForm(forms.Form): # not a model-form, just a form-form prospector = forms.CharField(strip=True) areacode = forms.CharField(strip=True) station = forms.CharField(strip=True) + uploadfiles = forms.FileField() class FilesRenameForm(forms.Form): # not a model-form, just a form-form @@ -550,122 +551,136 @@ def analyse_gpx(saved_filename, content): @login_required_if_public def gpxfix(request): - """Upload a GPX file containing a single track which is actually a single static point: for averaging - - + """Upload one or more GPX files containing a single track which is actually a single static point: for averaging """ def gpxvalid(name): if Path(name).suffix.lower() in [".gpx"]: return True # dangerous, we should check the actual file binary signature return False + + def _setup(): + year = current_expo() # read this from the GPX file in future! + ctx = { + "year": year, + "yearpath": Path("gpsfix") / year, + "folder": "", + "dirpath": Path(settings.EXPOFILES) / "gpsfix" / year, + "urlfile": None, + "urldir": None, + "formd": GPXfixForm(), + "filesaved": False, + "actual_saved": [], + "location_data": [], + "areacode": "", + "fixstring": "*fix p2025-WW-01 13.8229370 47.6874630 1871", + "entrancestring": "*entrance p2025-WW-01" + } + ctx["urlfile"] = f"/expofiles/gpsfix/{ctx['year']}" + ctx["urldir"] = f"/gpxfix/{ctx['year']}" + return ctx + + def _post(ctx): + formd = GPXfixForm(request.POST) + ctx["formd"] = formd - year = current_expo() # read this from the GPX file in future! - filesaved = False - actual_saved = [] - - context = {"year": year, "placeholder": "AnathemaDevice"} - - yearpath = Path(settings.EXPOFILES) / "gpsfix" / year - - - folder = "" # improve this later - dirpath = yearpath - urlfile = f"/expofiles/gpsfix/{year}" - urldir = f"/gpxfix/{year}" - - - print(f"gpxfix() {folder=} {dirpath=} {urlfile=} {urldir=}") - - - if request.method == "POST": - formd = GPXuploadForm(request.POST) - print(f"gpxfix() method=POST") - for i in request.POST: - print(" ",i) + # Check there are files to upload + multiple = request.FILES.getlist("uploadfiles") + if not multiple: + # user supplied no files — attach a form error and return to show it + print(f"gpxfix(): no files to upload {multiple}") + formd.add_error("uploadfiles", "No files uploaded.") # does not seem to be visible on form? + ctx["formd"] = formd + return ctx + # ensure base year folder exists try: - (yearpath).mkdir(parents=True, exist_ok=True) - except: - message = f'\n !! Permissions failure ?! 0 attempting to mkdir "{(yearpath)}"' + ctx["yearpath"].mkdir(parents=True, exist_ok=True) + except Exception as e: + message = f'\n !! Permissions failure ?! 0 attempting to mkdir "{ctx["yearpath"]}": {e}' print(message) - raise return render(request, "errors/generic.html", {"message": message}) + # if a prospector field was submitted, validate it if "prospector" in request.POST: - print(f"gpxfix() {request.POST=}\n {request.POST['prospector']=}") if formd.is_valid(): newprospector = sanitize_name(request.POST["prospector"]) - print(f"gpxfix() {newprospector=}") - else: - print(f"gpxfix() no prospector field") - print(f"gpxfix() {request.FILES=}") - for i in request.FILES: - print(" ",i) + print(f"gpxfix() prospector named: {newprospector}") + + ctx["areacode"] = request.POST["areacode"].strip() + + fs = FileSystemStorage(ctx["dirpath"]) + ctx["actual_saved"] = [] + ctx["location_data"] = [] + + for f in multiple: + if gpxvalid(f.name): + try: + saved_filename = fs.save(f.name, content=f) + except Exception as e: + print(f'\n !! Permissions failure ?! on attempting to save "{f.name}" in "{ctx["dirpath"]}": {e}') + # if save partially succeeded, guard against referencing undefined vars + continue + filepath = ctx["dirpath"] / saved_filename + if filepath.is_file(): + ctx["actual_saved"].append(saved_filename) + ctx["filesaved"] = True + # analyse_gpx may use the uploaded content object + try: + ctx["location_data"].append(analyse_gpx(saved_filename, f)) + except Exception as e: + print(f"gpxfix(): analyse_gpx failed for {saved_filename}: {e}") + else: + print(f"gpxfix(): not a GPX file {f.name=}") + + ctx["fixstring"] = f"*fix {request.POST["station"]} 13.8229370 47.6874630 1871 # {request.POST["prospector"]}: {multiple[0]}" + ctx["entrancestring"] = f"*entrance {request.POST["station"]}" + return ctx - - if not formd.is_valid(): - print(f"gpxfix() Form is not valid {formd=}") - else: - print(f"gpxfix() about to look at request.FILES") - #f = request.FILES["uploadfiles"] - multiple = request.FILES.getlist("uploadfiles") - fs = FileSystemStorage(dirpath) + def _get(ctx): + files = [] + dirs = [] + try: + for f in ctx["dirpath"].iterdir(): + if f.is_dir(): + dirs.append(f.name) + if f.is_file(): + files.append(f.name) + except FileNotFoundError: + files.append("(no folder yet - would be created)") + except Exception as e: + print(f"gpxfix() EXCEPTION\n {e}") + ctx["files"] = sorted(files) if files else [] + ctx["dirs"] = sorted(dirs) if dirs else [] + return ctx + # main flow + ctx = _setup() - actual_saved = [] - location_data = [] - if multiple: - for f in multiple: - if gpxvalid(f.name): - try: # crashes in Django os.chmod call if on WSL, but does save file! - saved_filename = fs.save(f.name, content=f) - except: - print( - f'\n !! Permissions failure ?! on attempting to save "{f.name}" in "{dirpath}" {renameto=}' - ) - if "saved_filename" in locals(): - if saved_filename.is_file(): - actual_saved.append(saved_filename) - filesaved = True - location_data.append(analyse_gpx(saved_filename, f)) - else: - print(f"gpxfix(): not a GPX file {f.name=}") - - print(f"gpxfix() drop through") - files = [] - dirs = [] - formd = GPXfixForm() - print(f"gpxfix() {formd=} ") - try: - for f in dirpath.iterdir(): - if f.is_dir(): - dirs.append(f.name) - if f.is_file(): - files.append(f.name) - except FileNotFoundError: - files.append("(no folder yet - would be created)") - except Exception as e: - print(f"gpxfix() EXCEPTION\n {e}") - if len(files) > 0: - files = sorted(files) + if request.method == "POST": + ctx = _post(ctx) + # if form invalid, still show GET-like view (ctx includes form with errors) + if isinstance(ctx, dict) and "formd" in ctx and not ctx["formd"].is_valid(): + ctx = _get(ctx) + else: + ctx = _get(ctx) - if dirs: - dirs = sorted(dirs) - - print(f"gpxfix() about to render..") return render( request, "gpxfixform.html", { - "form": formd, - **context, - "urlfile": urlfile, - "urldir": urldir, - "folder": folder, - "files": files, - "dirs": dirs, - "filesaved": filesaved, - "actual_saved": actual_saved, + "form": ctx.get("formd", GPXfixForm()), + "year": ctx["year"], + "urlfile": ctx["urlfile"], + "urldir": ctx["urldir"], + "yearpath": ctx["yearpath"], + "folder": ctx["folder"], + "files": ctx.get("files", []), + "dirs": ctx.get("dirs", []), + "filesaved": ctx.get("filesaved", False), + "actual_saved": ctx.get("actual_saved", []), + "areacode": ctx["areacode"], + "fixstring": ctx["fixstring"], + "entrancestring": ctx["entrancestring"], }, ) diff --git a/templates/gpxfixform.html b/templates/gpxfixform.html index d0610cb..b9e3cdf 100644 --- a/templates/gpxfixform.html +++ b/templates/gpxfixform.html @@ -11,9 +11,9 @@
- {% csrf_token %} + {% csrf_token %}
-


@@ -60,8 +60,8 @@ {% endfor %}

{% endif %} - - Files already here:
+

+ Files already here: in {{yearpath}}
{% for f in files %} {{f}}
{% empty %} @@ -73,9 +73,13 @@


This GPX file has x locations of which y (_%) have been averaged to produce a a location:

-[1623]
-*fix p2025-WW-01 13.8229370 47.6874630 1871
-*entrance p2025-WW-01
+{% for f in actual_saved %}
+       
+[{{ areacode }}]
+{{ fixstring }}
+{{ entrancestring }}
+
+{% endfor %}