From f5c1c6a90e4c090fdcf5d1957b4eea03aa4eb440 Mon Sep 17 00:00:00 2001 From: Philip Sargent Date: Mon, 27 Oct 2025 20:06:44 +0200 Subject: [PATCH] refactored gpxupload() into new standard form --- core/views/uploads.py | 165 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 1 deletion(-) diff --git a/core/views/uploads.py b/core/views/uploads.py index 7667c415d..1be6d05c2 100644 --- a/core/views/uploads.py +++ b/core/views/uploads.py @@ -81,6 +81,7 @@ class PhotographerForm(forms.Form): # not a model-form, just a form-form class GPXuploadForm(forms.Form): # not a model-form, just a form-form """not a git repo so we do not need an "editor" to assign blame to""" + uploadfiles = forms.FileField() prospector = forms.CharField(strip=True) class GPXfixForm(forms.Form): # not a model-form, just a form-form @@ -548,7 +549,169 @@ def analyse_gpx(saved_filename, content): """For an uploaded GPX file, analyse it to get a *fix number """ print(f"analyse_gpx(): {saved_filename} -- {content.name} length: {len(content)} bytes") - + +@login_required_if_public +def gpxupload(request, folder=None): + """Copy of photo upload folder is the "path" + """ + def gpxvalid(name): + # dangerous, we should check the actual file binary signature + return Path(name).suffix.lower() in [".xml", ".gpx"] + + print(f"gpxupload() {folder=}") + + def _setup(folder_arg): + year = current_expo() + # put year/placeholder directly on ctx (no nested 'context' dict) + ctx = { + "year": year, + "placeholder": "AnathemaDevice", + "filesaved": False, + "actual_saved": [], + "yearpath": Path(settings.EXPOFILES) / "gpslogs" / year, + "formd": GPXuploadForm(), + } + + # normalize folder -> dirpath, urlfile, urldir + if folder_arg == str(year) or folder_arg == str(year) + "/": + folder_arg = None + + if folder_arg is None: + folder_arg = "" + dirpath = ctx["yearpath"] + urlfile = f"/expofiles/gpslogs/{year}" + urldir = f"/gpxupload/{year}" + else: + dirpath = Path(settings.EXPOFILES) / "gpslogs" / folder_arg + if dirpath.is_dir(): + urlfile = f"/expofiles/gpslogs/{folder_arg}" + urldir = Path("/gpxupload") / folder_arg + else: + folder_arg = "" + dirpath = ctx["yearpath"] + urlfile = f"/expofiles/gpslogs/{year}" + urldir = f"/gpxupload/{year}" + + ctx.update({"folder": folder_arg, "dirpath": dirpath, "urlfile": urlfile, "urldir": urldir}) + print(f"gpxupload() {_setup.__name__} -> {folder_arg=} {dirpath=} {urlfile=} {urldir=}") + return ctx + + def _post(ctx): + print(f"gpxupload() method=POST") + for i in request.POST: + print(" ", i) + + formd = GPXuploadForm(request.POST) + ctx["formd"] = formd + + # prospector creation branch (preserve original behavior and prints) + if "prospector" in request.POST: + print(f"gpxupload() {request.POST=}\n {request.POST.get('prospector')=}") + if formd.is_valid(): + newprospector = sanitize_name(request.POST["prospector"]) + print(f"gpxupload() {newprospector=}") + try: + (ctx["yearpath"] / newprospector).mkdir(parents=True, exist_ok=True) + except Exception as e: + message = f'\n !! Permissions failure ?! 0 attempting to mkdir "{(ctx["yearpath"] / newprospector)}": {e}' + print(message) + raise + return render(request, "errors/generic.html", {"message": message}) + return ctx + + # file upload branch + print(f"gpxupload() no prospector field") + print(f"gpxupload() {request.FILES=}") + for i in request.FILES: + print(" ", i) + + print(f"gpxupload() about to look at request.FILES") + multiple = request.FILES.getlist("uploadfiles") + if not multiple: + # user supplied no files — attach a form error and return to show it + print(f"gpxupload(): 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 + + # NO CHECK that the files being uploaded are image files + fs = FileSystemStorage(ctx["dirpath"]) + + ctx["actual_saved"] = [] + ctx["filesaved"] = False + + 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 Exception: + print( + f'\n !! Permissions failure ?! 3 attempting to save "{f.name}" in "{ctx["dirpath"]}"' + ) + if "saved_filename" in locals(): + if (ctx["dirpath"] / saved_filename).is_file(): + ctx["actual_saved"].append(saved_filename) + ctx["filesaved"] = True + continue + if (ctx["dirpath"] / saved_filename).is_file(): + ctx["actual_saved"].append(saved_filename) + ctx["filesaved"] = True + else: + print(f"gpxupload(): not a GPX file {f.name=}") + + return ctx + + 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"gpxupload() EXCEPTION\n {e}") + ctx["files"] = sorted(files) if files else [] + ctx["dirs"] = sorted(dirs) if dirs else [] + return ctx + + # main flow + ctx = _setup(folder) + + 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) + + print(f"gpxupload() drop through") + files = ctx.get("files", []) + dirs = ctx.get("dirs", []) + + print(f"gpxupload() about to render..") + return render( + request, + "gpxuploadform.html", + { + "form": ctx.get("formd", GPXuploadForm()), + "year": ctx["year"], + "placeholder": ctx["placeholder"], + "urlfile": ctx["urlfile"], + "urldir": ctx["urldir"], + "folder": ctx["folder"], + "files": files, + "dirs": dirs, + "filesaved": ctx.get("filesaved", False), + "actual_saved": ctx.get("actual_saved", []), + }, + ) + + @login_required_if_public def gpxfix(request): """Upload one or more GPX files containing a single track which is actually a single static point: for averaging