2
0
mirror of https://expo.survex.com/repositories/troggle/.git synced 2024-11-28 18:11:52 +00:00

fix directory for uploaded cave description photos

This commit is contained in:
Philip Sargent 2024-07-10 21:07:45 +02:00
parent f5f3adf7da
commit 7908257d63
4 changed files with 132 additions and 55 deletions

View File

@ -46,7 +46,65 @@ todo = """
own directory 16xx/NNN/ even if they have no images to put in it.
"""
# def cavepagefwd(request, karea=None, subpath=None):
# """archaic, just send to the caves list page
# """
# return redirect("/caves")
def get_cave_from_slug(caveslug):
"""This is the old way of doing it, usingt eh CaveSlug intermediate object which does
the many:many relationship between slugs and caves - whcih we don't do (and never did in practice)
"""
caves = []
print(f"get_cave_from_slug(): {caveslug} ...")
areacode = caveslug[:4] # e.g. 1623
id = caveslug[5:] # e.g. 161 or 2023-MM-02
thisarea = Cave.objects.filter(areacode=areacode)
caves_k = thisarea.filter(kataster_number=id)
if len(caves_k) == 1:
caves.append(caves_k[0])
print(f"get_cave_from_slug(): {caves_k=} {len(caves_k)=}")
caves_id = thisarea.filter(unofficial_number=id)
if len(caves_id) == 1:
caves.append(caves_id[0])
print(f"get_cave_from_slug(): {caves_id=} {len(caves_id)=}")
if len(caves) > 1:
print(f"get_cave_from_slug(): {caveslug} More than 1 \n{caves}")
if len(caves) <1:
print(f"get_cave_from_slug(): {caveslug} Nowt found..")
cave = caves[0]
print(f"get_cave_from_slug(): {caveslug} FOUND {cave}")
try:
cave_zero = Cave.objects.get(caveslug__slug=caveslug)
print(f"Getting cave from '{caveslug}'")
if cave_zero != cave:
print(f"get_cave_from_slug(): {caveslug} BAD DISCREPANCY {cave_zero=} {cave=}")
else:
print(f"get_cave_from_slug(): {caveslug} SUCCESS")
return cave_zero
except:
return None
def caveslugfwd(request, slug):
"""This is ass backwards. It would be better style to have the slug-identified request be the master, and have
other paths redirect to it, rather than what we have here.
Pending a change where we remove cave.url as a field and have an explicit fixed convention instead.
"""
if not slug:
message = f"Failed to find cave from identifier given: {slug}."
return render(request, "errors/generic.html", {"message": message})
Gcavelookup = GetCaveLookup()
if slug in Gcavelookup:
cave = Gcavelookup[slug]
return redirect(f"/{cave.url}")
def getCaves(cave_id):
@ -93,7 +151,7 @@ def pad5(x):
def padnumber(x):
return re.sub("\d+", pad5, x) # SyntaxWarning: invalid escape sequence '\d'
return re.sub(r"\d+", pad5, x)
def numericalcmp(x, y):
@ -311,24 +369,7 @@ def rendercave(request, cave, slug, cave_id=""):
) # crashes here with NoReverseMatch if url not set up for 'edit_cave' in urls.py
return r
def cavepagefwd(request, karea=None, subpath=None):
"""archaic, just send to the caves list page
"""
return redirect("/caves")
def caveslugfwd(request, slug):
"""This is ass backwards. It would be better style to have the slug-identified request be the master, and have
other paths redirect to it, rather than what we have here.
Pending a change where we remove cave.url as a field and have an explicit fixed convention instead.
"""
if slug:
Gcavelookup = GetCaveLookup()
if slug in Gcavelookup:
cave = Gcavelookup[slug]
else:
message = f"Failed to find cave from identifier given: {slug}."
return render(request, "errors/generic.html", {"message": message})
return redirect(f"/{cave.url}")
def cavepage(request, karea=None, subpath=None):
"""Displays a cave description page
@ -368,9 +409,7 @@ def cavepage(request, karea=None, subpath=None):
subparts = parts[0].split(".")
caveid = subparts[0]
slug = f"{karea}-{caveid}"
caves = Cave.objects.filter(caveslug__slug=slug)
if len(caves) == 1:
cave = caves[0]
if cave:= get_cave_from_slug(slug): # walrus operator
return redirect(f"/{cave.url}")
else:
return redirect(f"/caves")
@ -410,31 +449,31 @@ def edit_cave(request, path="", slug=None):
"""
print(f"edit_cave(): {path=} {slug=}")
message = ""
if slug is not None:
print(f"{slug=}")
try:
cave = Cave.objects.get(caveslug__slug=slug)
except:
return render(request, "errors/badslug.html", {"badslug": f"{slug} - from edit_cave()"})
if slug is None:
cave = Cave() # create a New Cave
else:
cave = Cave()
print(f"{slug=}")
if not (cave:= get_cave_from_slug(slug)): # walrus operator
return render(request, "errors/badslug.html", {"badslug": f"for cave {caveslug} - from edit_cave()"})
if request.POST:
form = CaveForm(request.POST, instance=cave)
#ceFormSet = CaveAndEntranceFormSet(request.POST)
if form.is_valid(): # and ceFormSet.is_valid():
# print(f'! POST is valid. {cave}')
print(f'edit_cave(): POST is valid. Editing {cave}')
cave = form.save(commit=False)
print(cave)
# print(cave)
if not cave.filename:
cave.filename = cave.areacode + "-" + cave.number() + ".html"
if not cave.url:
cave.url = cave.areacode + "/" + cave.number()
cave.save()
form.save_m2m()
form.save_m2m() # this does the many-to-many relationship saving between caves and entrances
if slug is None:
# it is not visible on the form so it always will be None
slug = f"{cave.areacode}-{cave.number()}"
cs = CaveSlug(cave=cave, slug=slug, primary=True)
print(f"edit_cave(): New CaveSlug saved {slug}")
cs.save()
#ceinsts = ceFormSet.save(commit=False)
#for ceinst in ceinsts:
@ -450,6 +489,8 @@ def edit_cave(request, path="", slug=None):
except subprocess.SubprocessError:
message = f"CANNOT git on server for this file {cave.filename}. Edits may not be committed.\nAsk a nerd to fix this."
return render(request, "errors/generic.html", {"message": message})
except:
raise
if cave.entrances().count() > 0:
return HttpResponseRedirect("/" + cave.url)
else:
@ -458,8 +499,8 @@ def edit_cave(request, path="", slug=None):
else:
if slug is not None:
# re-read cave data from file.
#print(f"edit_cave(): {cave=} {cave.filename=}")
#print(f"edit_cave(): {cave.slug()=}")
print(f"edit_cave(): {cave=} {cave.filename=}")
print(f"edit_cave(): {cave.slug()=}")
if cave.filename:
try:
read_cave(cave.filename, cave=cave)
@ -472,7 +513,8 @@ def edit_cave(request, path="", slug=None):
else:
form = CaveForm()
#ceFormSet = CaveAndEntranceFormSet(queryset=CaveAndEntrance.objects.none())
print(f"edit_cave(): returning render()")
return render(
request,
"editcave.html",
@ -486,6 +528,7 @@ def edit_cave(request, path="", slug=None):
)
@login_required_if_public
def edit_entrance(request, path="", caveslug=None, entslug=None):
"""This is the form that edits the entrance data for a single entrance and writes out
@ -497,6 +540,9 @@ def edit_entrance(request, path="", caveslug=None, entslug=None):
It does save the data into into the database directly, not by parsing the file.
'path' comes from the urls.py regex but is usually empty (!)
So we make the proper path for storing the images ourselves.
GET RID of all this entranceletter stuff. Far too overcomplexified.
We don't need it. Just the entrance slug is fine, then check uniqueness.
"""
@ -526,9 +572,7 @@ def edit_entrance(request, path="", caveslug=None, entslug=None):
nextletter = chr(ord(letter)+1)
return check_new_slugname_ok(slug, nextletter)
try:
cave = Cave.objects.get(caveslug__slug=caveslug)
except:
if not (cave:= get_cave_from_slug(caveslug)): # walrus operator
return render(request, "errors/badslug.html", {"badslug": f"for cave {caveslug} - from edit_entrance()"})
if entslug:
@ -541,7 +585,7 @@ def edit_entrance(request, path="", caveslug=None, entslug=None):
entrance = None
if entslug:
print(f"{caveslug=} {entslug=} {path=} number of ents:{cave.entrances().count()}")
print(f"Edit Entrance {caveslug=} {entslug=} {path=} number of ents:{cave.entrances().count()}")
caveAndEntrance = CaveAndEntrance.objects.get(entrance=entrance, cave=cave)
entlettereditable = False
else:
@ -556,6 +600,11 @@ def edit_entrance(request, path="", caveslug=None, entslug=None):
print(f"{entlettereditable=}")
# if the entletter is not editable, then the entletterform does not appear and so is always invalid.
print(f"{caveslug=}")
print(f"{cave=}")
imgpath = Path(path) / cave.areacode / cave.number()
print(f"Edit Entrance {imgpath=}")
if request.POST:
print(f"POST Online edit of entrance: '{entrance}' where {cave=}")
@ -683,7 +732,7 @@ def edit_entrance(request, path="", caveslug=None, entslug=None):
"entletter": entletter,
"entletterform": entletterform, # is unset if not being used
"entlettereditable": entlettereditable,
"path": path + "/", # used for saving images if attached
"path": str(imgpath) + "/", # used for saving images if attached
},
)
@ -719,9 +768,7 @@ def caveslist(request):
{"caves": caves, "year": current_expo()},
)
def get_entrances(request, caveslug):
try:
cave = Cave.objects.get(caveslug__slug=caveslug)
except:
if not (cave:= get_cave_from_slug(caveslug)): # walrus operator
return render(request, "errors/badslug.html", {"badslug": f"{caveslug} - from get_entrances()"})
return render(
request, "options.html", {"year": current_expo(), "items": [(e.entrance.slug(), e.entrance.slug()) for e in cave.entrances()]}
@ -733,9 +780,7 @@ def caveQMs(request, slug, open=False):
relies on the template to find all the QMs for the cave specified in the slug, e.g. '1623-161'
Now working in July 2022
"""
try:
cave = Cave.objects.get(caveslug__slug=slug)
except:
if not (cave:= get_cave_from_slug(caveslug)): # walrus operator
return render(request, "errors/badslug.html", {"badslug": f"{slug} - from caveQMs()"})
if cave.non_public and settings.PUBLIC_SITE and not request.user.is_authenticated:

View File

@ -26,6 +26,11 @@ THUMBNAIL_HEIGHT = 200
It uses a lot of opinionated Django default magic, none of which I am familiar with.
Philip
The function image_selector() is only called from a template file doing a popup input form,
but it stores files directly in expoweb/i /l /t instead of in
/expoweb/1623/2018-MS-01/i , /l, /t
so ALL new caves have photos in the smae place, which makes the default upload EXTREMELY CONFUSING
"""
def get_dir(path):
@ -38,7 +43,10 @@ def get_dir(path):
def image_selector(request, path):
"""Returns available images"""
"""Returns available images
called from
templates/html_editor_scripts_css.html: $('#image_popup_content').load("{% url 'image_selector' path %}" + path, function() {
"""
directory = get_dir(path)
print(f" - image selector {directory=} {path=}")
thumbnailspath = Path(settings.EXPOWEB) / directory / "t"
@ -89,15 +97,23 @@ def reorient_image(img, exif_dict):
def new_image_form(request, path):
"""Manages a form to upload new images"""
directory = get_dir(path)
print(f"new_image_form(): {directory=} {path=}")
if request.method == "POST":
print(f"new_image_form(): POST ")
form = NewWebImageForm(request.POST, request.FILES, directory=directory)
if form.is_valid():
print(f"new_image_form(): form is valid ")
print(f"new_image_form(): files: {request.FILES["file_"]}")
f = request.FILES["file_"]
binary_data = io.BytesIO()
for chunk in f.chunks():
binary_data.write(chunk)
print(f"new_image_form(): binary chnks written")
i = Image.open(binary_data)
print(f"new_image_form(): {i=}")
if "exif" in i.info:
print(f"new_image_form(): exif: {i=}")
exif_dict = piexif.load(i.info["exif"])
i = reorient_image(i, exif_dict)
exif_dict['Exif'][41729] = b'1'
@ -109,13 +125,21 @@ def new_image_form(request, path):
else:
exif = None
print(f"new_image_form(): No exif problems")
width, height = i.size
print(f"new_image_form(): {i.size=}")
if width > MAX_IMAGE_WIDTH or height > MAX_IMAGE_HEIGHT:
print(f"new_image_form(): rescaling ")
scale = max(width / MAX_IMAGE_WIDTH, height / MAX_IMAGE_HEIGHT)
i = i.resize((int(width / scale), int(height / scale)), Image.ANTIALIAS)
print(f"new_image_form(): rescaling {scale=}")
try:
i = i.resize((int(width / scale), int(height / scale)), Image.LANCZOS)
except Exception as e:
print(f"new_image_form(): rescaling exception: {e} ")
print(f"new_image_form(): rescaled ")
tscale = max(width / THUMBNAIL_WIDTH, height / THUMBNAIL_HEIGHT)
thumbnail = i.resize((int(width / tscale), int(height / tscale)), Image.ANTIALIAS)
thumbnail = i.resize((int(width / tscale), int(height / tscale)), Image.LANCZOS)
ib = io.BytesIO()
i = i.convert('RGB')
i.save(ib, format="jpeg", quality = 75)
@ -123,6 +147,7 @@ def new_image_form(request, path):
thumbnail = thumbnail.convert('RGB')
thumbnail.save(tb, format="jpeg", quality = 70)
image_rel_path, thumb_rel_path, desc_rel_path = form.get_rel_paths()
print(f"new_image_form(): \n {image_rel_path=}\n {thumb_rel_path=}\n {desc_rel_path=}")
image_page_template = loader.get_template("image_page_template.html") # this is the .html file in the /l/ folder
image_page = image_page_template.render(
{
@ -149,14 +174,21 @@ def new_image_form(request, path):
f"{change_message} - online adding of an image",
)
except WriteAndCommitError as e:
print(f"new_image_form(): WriteAndCommitError: {e.message}")
return JsonResponse({"error": e.message})
except Exception as e:
print(f"new_image_form(): EXCEPTION: {e.message}")
return JsonResponse({"error": e.message})
linked_image_template = loader.get_template("linked_image_template.html")
html_snippet = linked_image_template.render(
{"thumbnail_url": f"/{thumb_rel_path}", "page_url": f"/{desc_rel_path}"}, request
)
return JsonResponse({"html": html_snippet})
else:
print(f"new_image_form(): not POST ")
form = NewWebImageForm(directory=directory)
print(f"new_image_form(): POST and not POST ")
template = loader.get_template("new_image_form.html")
htmlform = template.render({"form": form, "path": path}, request)
return JsonResponse({"form": htmlform})

View File

@ -16,8 +16,8 @@ the form documented at
<br>
<cave>
<non_public>{{ cave.non_public }}</non_public>{% for slug in cave.caveslug_set.all %}<!-- 'False' or 'True'. True if the cave should only be visible to logged-in users. Caves are normally public, so enter 'False' unless you know otherwise. -->
<!--<caveslug>{{ slug.slug|default_if_none:"1623-000"|safe }}</caveslug>{% endfor %}--> <!-- Ignored. No longer required, we use the filename instead e.g. 1623-315 for 1623-315.html -->
<non_public>{{ cave.non_public }}</non_public><!-- 'False' or 'True'. True if the cave should only be visible to logged-in users. Caves are normally public, so enter 'False' unless you know otherwise. -->
<!--<caveslug>{{ slug.slug|default_if_none:"1623-000"|safe }}</caveslug>--> <!-- Ignored. No longer required, we use the filename instead e.g. 1623-315 for 1623-315.html -->
<official_name>{{ cave.official_name|default_if_none:""|safe }}</official_name><!-- Name of the cave (normally in German) Use &uuml; for u+Umlaut and &ouml; for o+umlaut eg H&ouml;hle for Hohle and Gl&uuml;ck for Gluck-->
<area>{{cave.areacode |safe }}</area><!-- e.g. "1623" -->
<kataster_code>{{ cave.kataster_code|default_if_none:"-"|safe }}</kataster_code><!-- 'length-or-depth/type exploration'

View File

@ -7,7 +7,7 @@ from django.conf.urls.static import static
from troggle.core.views import statistics, survex
from troggle.core.views.auth import expologin, expologout
from troggle.core.views.caves import (cave3d, caveindex, entranceindex, caveslist,
cavepage, caveslugfwd, cavepagefwd, caveQMs, edit_cave, cave_debug,
cavepage, caveslugfwd, caveQMs, edit_cave, cave_debug,
edit_entrance, get_entrances, qm, expo_kml, expo_kmz)
from troggle.core.views.drawings import dwgallfiles, dwgfilesingle
from troggle.core.views.editor_helpers import image_selector, new_image_form
@ -173,9 +173,9 @@ trogglepatterns = [
# Note that urls eg '/1623/161/l/rl89a.htm' are handled by cavepage which redirects them to 'expopage'
# Note that _edit$ for a cave description page in a subfolder e.g. /1623/204/204.html_edit gets caught here and breaks with 404
# These re-enable archaic URLs which are in old web pages which are still public on other servers
path('smkridge/<path:subpath>', cavepagefwd, {'karea': "1623"}, name="cavepagefwd"),
path('expo/smkridge/<path:subpath>', cavepagefwd, {'karea': "1623"}, name="cavepagefwd"),
# These re-enable archaic URLs which are in old web pages which may still be public on other servers - old
# path('smkridge/<path:subpath>', cavepagefwd, {'karea': "1623"}, name="cavepagefwd"),
# path('expo/smkridge/<path:subpath>', cavepagefwd, {'karea': "1623"}, name="cavepagefwd"),
# Archaic, kept. This /expo/ prefix only works for expoweb HTML pages not troggle pages
path('expo/<path:path>', expopage, name="expopage"),