2
0
mirror of https://expo.survex.com/repositories/troggle/.git synced 2025-12-17 23:47:12 +00:00

fixed many problems in creating new entrances

This commit is contained in:
2023-11-07 02:12:57 +02:00
parent bd0a9332df
commit 07d9365747
8 changed files with 136 additions and 53 deletions

View File

@@ -475,6 +475,30 @@ def edit_entrance(request, path="", caveslug=None, entslug=None):
GET RID of all this entranceletter stuff. Far too overcomplexified.
We don't need it. Just the entrance slug is fine, then check uniqueness.
"""
def check_new_slugname_ok(slug, letter):
"""In Nov.2023 it is possible to create a 2nd entrance and not set an entrance letter,
which leads to a constraint uniqueness crash. FIX THIS.
The letter may be set to an existing letter, OR it may be unset, but there may
be an existing unlettered single entrance. Both of these will crash unless fixed.
"""
slugname = f"{slug}{letter}"
nents = Entrance.objects.filter(slug=slugname).count()
print(f"NUM ents {slugname=} => {nents}")
if nents == 0:
# looks good, but we need to check the CaveaAndEntrance object too
e = entrance #Entrance.objects.get(slug=slugname) # does not exist yet!
gcl = GetCaveLookup()
c = gcl[slug]
nce = CaveAndEntrance.objects.filter(cave=c, entrance=e).count()
if nce == 0 :
return slugname, letter
# That entrance already exists, or the CE does, OK.. do recursive call, starting at "b"
if letter =="":
return check_new_slugname_ok(slug, "b")
else:
nextletter = chr(ord(letter)+1)
return check_new_slugname_ok(slug, nextletter)
try:
cave = Cave.objects.get(caveslug__slug=caveslug)
@@ -495,42 +519,60 @@ def edit_entrance(request, path="", caveslug=None, entslug=None):
caveAndEntrance = CaveAndEntrance.objects.get(entrance=entrance, cave=cave)
entlettereditable = False
else:
caveAndEntrance = CaveAndEntrance(cave=cave, entrance=Entrance())
caveAndEntrance = CaveAndEntrance(cave=cave, entrance=Entrance()) # creates a new Entrance object as well as a new CE object
entlettereditable = True
if caveAndEntrance.entranceletter == "" and cave.entrances().count() > 0 :
ce = caveAndEntrance
if ce.entranceletter == "" and cave.entrances().count() > 0 :
# this should not be blank on a multiple-entrance cave
# but it doesn't trigger the entrance letter form unless entletter has a value
entlettereditable = True
entlettereditable = True # but the user has to remember to actually set it...
print(f"{entlettereditable=}")
# if the entletter is no editable, then the entletterform does not appear and so is always invalid.
# if the entletter is not editable, then the entletterform does not appear and so is always invalid.
if request.POST:
print(f"POST Online edit of entrance: '{entrance}' where {cave=}")
entform = EntranceForm(request.POST, instance=entrance)
if not entlettereditable:
entranceletter = caveAndEntrance.entranceletter
ce = caveAndEntrance
entranceletter = ce.entranceletter
else:
entletterform = EntranceLetterForm(request.POST, instance=caveAndEntrance)
entletterform = EntranceLetterForm(request.POST, instance=ce)
if entletterform.is_valid():
ce = entletterform.save(commit=False)
entranceletter = entletterform.cleaned_data["entranceletter"]
message = f"- POST valid {caveslug=} {entslug=} {path=} entletterform valid \n {entletterform=}."
print(message)
else:
print(f"- POST INVALID {caveslug=} {entslug=} {path=} entletterform invalid.")
return render(request, "errors/badslug.html", {"badslug": "entletter problem in edit_entrances()"})
# if entform.is_valid() and entletterform.is_valid():
if entform.is_valid():
# maybe this doesn't matter? It just means entranceletter unset ?
# probably because 'Cave and entrance with this Cave and Entranceletter already exists.'
message = f"- POST INVALID {caveslug=} {entslug=} {path=} entletterform invalid \n{entletterform.errors=}\n{entletterform=}."
print(message)
# if entletterform.errors:
# for field in entletterform:
# for error in field.errors:
# print(f"ERR {field=} {error=}")
# return render(request, "errors/generic.html", {"message": message})
entranceletter=""
if not entform.is_valid():
message = f"- POST INVALID {caveslug=} {entslug=} {path=} entform valid:{entform.is_valid()} entletterform valid:{entletterform.is_valid()}"
entrance = entform.save(commit=False)
print(message)
return render(request, "errors/generic.html", {"message": message})
else:
print(f"- POST {caveslug=} {entslug=} {entranceletter=} {path=}")
if entslug is None:
# we are creating a new entrance
if entranceletter:
slugname = cave.slug() + entranceletter
print(f"- POST letter {entranceletter=}")
slugname, letter = check_new_slugname_ok(cave.slug(), entranceletter)
else:
slugname = cave.slug()
slugname, letter = check_new_slugname_ok(cave.slug(), "")
ce.entranceletter = letter
entrance = ce.entrance # the one we created earlier
entrance.slug = slugname
entrance.cached_primary_slug = slugname
entrance.filename = slugname + ".html"
@@ -541,41 +583,48 @@ def edit_entrance(request, path="", caveslug=None, entslug=None):
try:
entrance.save()
except:
# fails with uniqueness constraint failure. Which is on CaveAndEntrance, not just on entrance, which is bizarre.
# fails with uniqueness constraint failure. Which is on CaveAndEntrance, not just on entrance,
# which is confusing to a user who is just editing an Entrance.
# Can happen when user specifies an existing letter! (or none, when they should set one)
print(f"SAVE EXCEPTION FAIL {entrance=}")
print(f"CAVE {cave}")
for ce in cave.entrances():
print(f"CAVE:{ce.cave} - ENT:{ce.entrance} - LETTER:'{ce.entranceletter}'")
raise
ce.entrance = entrance
# try not to do this:
# UNIQUE constraint failed: core_caveandentrance.cave_id, core_caveandentrance.entranceletter
ce.save()
entrance_file = entrance.file_output()
cave_file = cave.file_output()
print(f"- POST WRITE letter: '{ce}' {entrance=}")
write_and_commit([entrance_file, cave_file], f"Online edit of entrance {entrance.slug}")
return HttpResponseRedirect("/" + cave.url)
else: # one of the forms is not valid
print(f"- POST INVALID {caveslug=} {entslug=} {path=} entform valid:{entform.is_valid()} entletterform valid:{entletterform.is_valid()}")
if write_and_commit([entrance_file, cave_file], f"Online edit of entrance {entrance.slug}"):
return HttpResponseRedirect("/" + cave.url)
else:
efilepath, econtent, eencoding = entrance_file
cfilepath, ccontent, cencoding = cave_file
message = f"- FAIL write_and_commit \n entr:'{efilepath}'\n cave:'{cfilepath}'"
print(message)
return render(request, "errors/generic.html", {"message": message})
else: # GET the page, not POST, or if either of the forms were invalid when POSTed
entletterform = None
entletter = ""
print(f"ENTRANCE in db: entranceletter = '{caveAndEntrance.entranceletter}'")
print(f"ENTRANCE in db: entranceletter = '{ce.entranceletter}'")
if entrance:
# re-read entrance data from file.
filename = str(entrance.slug +".html")
ent = read_entrance(filename, ent=entrance)
print(f"ENTRANCE from file: entranceletter = '{caveAndEntrance.entranceletter}'")
print(f"ENTRANCE from file: entranceletter = '{ce.entranceletter}'")
entform = EntranceForm(instance=entrance)
if entslug is None:
entletterform = EntranceLetterForm()
# print(f" Getting entletter from EntranceLetterForm")
else:
entletter = caveAndEntrance.entranceletter
entletter = ce.entranceletter
if entletter == "":
entletterform = EntranceLetterForm()
print(f" Blank value: getting entletter from EntranceLetterForm")
@@ -619,7 +668,14 @@ def cave_debug(request):
{"ents": ents},
)
def caveslist(request):
caves = Cave.objects.all()
print("CAVESLIST")
return render(
request,
"caveslist.html",
{"caves": caves},
)
def get_entrances(request, caveslug):
try:
cave = Cave.objects.get(caveslug__slug=caveslug)