mirror of
https://expo.survex.com/repositories/troggle/.git
synced 2024-11-25 08:41:51 +00:00
fixed many problems in creating new entrances
This commit is contained in:
parent
bd0a9332df
commit
07d9365747
@ -210,7 +210,7 @@ class EntranceLetterForm(ModelForm):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# This only needs to be required=True for the second and subsequent entrances, not the first. Tricky.
|
# This only needs to be required=True for the second and subsequent entrances, not the first. Tricky.
|
||||||
entranceletter = forms.CharField(required=True, widget=forms.TextInput(attrs={"size": "2"}))
|
entranceletter = forms.CharField(required=False, widget=forms.TextInput(attrs={"size": "2"}))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CaveAndEntrance
|
model = CaveAndEntrance
|
||||||
|
@ -198,22 +198,13 @@ class Cave(TroggleModel):
|
|||||||
res += "–" + prevR
|
res += "–" + prevR
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def writeDataFile(self):
|
|
||||||
"""Seems to be a duplicate of file_output() ?!
|
|
||||||
REFACTOR"""
|
|
||||||
filepath = os.path.join(settings.CAVEDESCRIPTIONS, self.filename)
|
|
||||||
|
|
||||||
t = loader.get_template("dataformat/cave.xml")
|
|
||||||
now = datetime.now(timezone.utc)
|
|
||||||
print(now)
|
|
||||||
c = dict({"cave": self, "date": now})
|
|
||||||
u = t.render(c)
|
|
||||||
writetrogglefile(filepath, u)
|
|
||||||
return
|
|
||||||
|
|
||||||
def file_output(self):
|
def file_output(self):
|
||||||
"""This produces the content which wll be re-saved as the cave_data html file.
|
"""This produces the content which wll be re-saved as the cave_data html file.
|
||||||
"""
|
"""
|
||||||
|
if not self.filename:
|
||||||
|
self.filename = self.slug() + ".html"
|
||||||
|
self.save()
|
||||||
|
|
||||||
filepath = Path(settings.CAVEDESCRIPTIONS, self.filename)
|
filepath = Path(settings.CAVEDESCRIPTIONS, self.filename)
|
||||||
|
|
||||||
t = loader.get_template("dataformat/cave.xml")
|
t = loader.get_template("dataformat/cave.xml")
|
||||||
@ -222,6 +213,11 @@ class Cave(TroggleModel):
|
|||||||
content = t.render(c)
|
content = t.render(c)
|
||||||
return (filepath, content, "utf8")
|
return (filepath, content, "utf8")
|
||||||
|
|
||||||
|
def writeDataFile(self):
|
||||||
|
filepath, content, coding = self.file_output()
|
||||||
|
writetrogglefile(filepath, content)
|
||||||
|
return
|
||||||
|
|
||||||
class Entrance(TroggleModel):
|
class Entrance(TroggleModel):
|
||||||
MARKING_CHOICES = (
|
MARKING_CHOICES = (
|
||||||
("P", "Paint"),
|
("P", "Paint"),
|
||||||
@ -388,6 +384,9 @@ class Entrance(TroggleModel):
|
|||||||
return Path(settings.ENTRANCEDESCRIPTIONS, self.filename)
|
return Path(settings.ENTRANCEDESCRIPTIONS, self.filename)
|
||||||
|
|
||||||
def file_output(self):
|
def file_output(self):
|
||||||
|
if not self.filename:
|
||||||
|
self.filename = self.slug + ".html"
|
||||||
|
self.save()
|
||||||
filepath = Path(os.path.join(settings.ENTRANCEDESCRIPTIONS, self.filename))
|
filepath = Path(os.path.join(settings.ENTRANCEDESCRIPTIONS, self.filename))
|
||||||
|
|
||||||
t = loader.get_template("dataformat/entrance.xml")
|
t = loader.get_template("dataformat/entrance.xml")
|
||||||
@ -397,13 +396,8 @@ class Entrance(TroggleModel):
|
|||||||
return (filepath, content, "utf8")
|
return (filepath, content, "utf8")
|
||||||
|
|
||||||
def writeDataFile(self):
|
def writeDataFile(self):
|
||||||
filepath = os.path.join(settings.ENTRANCEDESCRIPTIONS, self.filename)
|
filepath, content, coding = self.file_output()
|
||||||
|
writetrogglefile(filepath, content)
|
||||||
t = loader.get_template("dataformat/entrance.xml")
|
|
||||||
now = datetime.now(timezone.utc)
|
|
||||||
c = dict({"entrance": self, "date": now})
|
|
||||||
u = t.render(c)
|
|
||||||
writetrogglefile(filepath, u)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def url_parent(self):
|
def url_parent(self):
|
||||||
|
@ -152,6 +152,8 @@ def write_and_commit(files, message):
|
|||||||
# GIT see also core/views/uploads.py dwgupload()
|
# GIT see also core/views/uploads.py dwgupload()
|
||||||
# GIT see also core/views/expo.py editexpopage()
|
# GIT see also core/views/expo.py editexpopage()
|
||||||
os.makedirs(os.path.dirname(filepath), exist_ok = True)
|
os.makedirs(os.path.dirname(filepath), exist_ok = True)
|
||||||
|
if filepath.is_dir():
|
||||||
|
return False
|
||||||
if encoding:
|
if encoding:
|
||||||
mode = "w"
|
mode = "w"
|
||||||
kwargs = {"encoding": encoding}
|
kwargs = {"encoding": encoding}
|
||||||
@ -160,7 +162,7 @@ def write_and_commit(files, message):
|
|||||||
kwargs = {}
|
kwargs = {}
|
||||||
try:
|
try:
|
||||||
with open(filepath, mode, **kwargs) as f:
|
with open(filepath, mode, **kwargs) as f:
|
||||||
print(f"WRITING {cwd}---{filename} ")
|
print(f"WRITING {cwd}/{filename} ")
|
||||||
f.write(content)
|
f.write(content)
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
raise WriteAndCommitError(
|
raise WriteAndCommitError(
|
||||||
@ -226,6 +228,7 @@ def write_and_commit(files, message):
|
|||||||
raise WriteAndCommitError(
|
raise WriteAndCommitError(
|
||||||
f"CANNOT git on server for this file {filename}. Subprocess error. Edits not saved.\nAsk a nerd to fix this."
|
f"CANNOT git on server for this file {filename}. Subprocess error. Edits not saved.\nAsk a nerd to fix this."
|
||||||
)
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class WriteAndCommitError(Exception):
|
class WriteAndCommitError(Exception):
|
||||||
|
@ -475,6 +475,30 @@ def edit_entrance(request, path="", caveslug=None, entslug=None):
|
|||||||
GET RID of all this entranceletter stuff. Far too overcomplexified.
|
GET RID of all this entranceletter stuff. Far too overcomplexified.
|
||||||
We don't need it. Just the entrance slug is fine, then check uniqueness.
|
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:
|
try:
|
||||||
cave = Cave.objects.get(caveslug__slug=caveslug)
|
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)
|
caveAndEntrance = CaveAndEntrance.objects.get(entrance=entrance, cave=cave)
|
||||||
entlettereditable = False
|
entlettereditable = False
|
||||||
else:
|
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
|
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
|
# this should not be blank on a multiple-entrance cave
|
||||||
# but it doesn't trigger the entrance letter form unless entletter has a value
|
# 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=}")
|
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:
|
if request.POST:
|
||||||
print(f"POST Online edit of entrance: '{entrance}' where {cave=}")
|
print(f"POST Online edit of entrance: '{entrance}' where {cave=}")
|
||||||
entform = EntranceForm(request.POST, instance=entrance)
|
entform = EntranceForm(request.POST, instance=entrance)
|
||||||
|
|
||||||
if not entlettereditable:
|
if not entlettereditable:
|
||||||
entranceletter = caveAndEntrance.entranceletter
|
entranceletter = ce.entranceletter
|
||||||
ce = caveAndEntrance
|
|
||||||
else:
|
else:
|
||||||
entletterform = EntranceLetterForm(request.POST, instance=caveAndEntrance)
|
entletterform = EntranceLetterForm(request.POST, instance=ce)
|
||||||
if entletterform.is_valid():
|
if entletterform.is_valid():
|
||||||
ce = entletterform.save(commit=False)
|
ce = entletterform.save(commit=False)
|
||||||
entranceletter = entletterform.cleaned_data["entranceletter"]
|
entranceletter = entletterform.cleaned_data["entranceletter"]
|
||||||
|
message = f"- POST valid {caveslug=} {entslug=} {path=} entletterform valid \n {entletterform=}."
|
||||||
|
print(message)
|
||||||
else:
|
else:
|
||||||
print(f"- POST INVALID {caveslug=} {entslug=} {path=} entletterform invalid.")
|
# maybe this doesn't matter? It just means entranceletter unset ?
|
||||||
return render(request, "errors/badslug.html", {"badslug": "entletter problem in edit_entrances()"})
|
# probably because 'Cave and entrance with this Cave and Entranceletter already exists.'
|
||||||
# if entform.is_valid() and entletterform.is_valid():
|
message = f"- POST INVALID {caveslug=} {entslug=} {path=} entletterform invalid \n{entletterform.errors=}\n{entletterform=}."
|
||||||
if entform.is_valid():
|
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)
|
entrance = entform.save(commit=False)
|
||||||
|
print(message)
|
||||||
|
return render(request, "errors/generic.html", {"message": message})
|
||||||
|
else:
|
||||||
|
|
||||||
print(f"- POST {caveslug=} {entslug=} {entranceletter=} {path=}")
|
print(f"- POST {caveslug=} {entslug=} {entranceletter=} {path=}")
|
||||||
if entslug is None:
|
if entslug is None:
|
||||||
|
# we are creating a new entrance
|
||||||
if entranceletter:
|
if entranceletter:
|
||||||
slugname = cave.slug() + entranceletter
|
slugname, letter = check_new_slugname_ok(cave.slug(), entranceletter)
|
||||||
print(f"- POST letter {entranceletter=}")
|
|
||||||
else:
|
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.slug = slugname
|
||||||
entrance.cached_primary_slug = slugname
|
entrance.cached_primary_slug = slugname
|
||||||
entrance.filename = slugname + ".html"
|
entrance.filename = slugname + ".html"
|
||||||
@ -541,41 +583,48 @@ def edit_entrance(request, path="", caveslug=None, entslug=None):
|
|||||||
try:
|
try:
|
||||||
entrance.save()
|
entrance.save()
|
||||||
except:
|
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"SAVE EXCEPTION FAIL {entrance=}")
|
||||||
print(f"CAVE {cave}")
|
print(f"CAVE {cave}")
|
||||||
for ce in cave.entrances():
|
for ce in cave.entrances():
|
||||||
print(f"CAVE:{ce.cave} - ENT:{ce.entrance} - LETTER:'{ce.entranceletter}'")
|
print(f"CAVE:{ce.cave} - ENT:{ce.entrance} - LETTER:'{ce.entranceletter}'")
|
||||||
raise
|
raise
|
||||||
ce.entrance = entrance
|
ce.entrance = entrance
|
||||||
|
# try not to do this:
|
||||||
|
# UNIQUE constraint failed: core_caveandentrance.cave_id, core_caveandentrance.entranceletter
|
||||||
ce.save()
|
ce.save()
|
||||||
|
|
||||||
entrance_file = entrance.file_output()
|
entrance_file = entrance.file_output()
|
||||||
cave_file = cave.file_output()
|
cave_file = cave.file_output()
|
||||||
|
|
||||||
|
|
||||||
print(f"- POST WRITE letter: '{ce}' {entrance=}")
|
print(f"- POST WRITE letter: '{ce}' {entrance=}")
|
||||||
write_and_commit([entrance_file, cave_file], f"Online edit of entrance {entrance.slug}")
|
if write_and_commit([entrance_file, cave_file], f"Online edit of entrance {entrance.slug}"):
|
||||||
return HttpResponseRedirect("/" + cave.url)
|
return HttpResponseRedirect("/" + cave.url)
|
||||||
else: # one of the forms is not valid
|
else:
|
||||||
print(f"- POST INVALID {caveslug=} {entslug=} {path=} entform valid:{entform.is_valid()} entletterform valid:{entletterform.is_valid()}")
|
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
|
else: # GET the page, not POST, or if either of the forms were invalid when POSTed
|
||||||
entletterform = None
|
entletterform = None
|
||||||
entletter = ""
|
entletter = ""
|
||||||
print(f"ENTRANCE in db: entranceletter = '{caveAndEntrance.entranceletter}'")
|
print(f"ENTRANCE in db: entranceletter = '{ce.entranceletter}'")
|
||||||
if entrance:
|
if entrance:
|
||||||
# re-read entrance data from file.
|
# re-read entrance data from file.
|
||||||
filename = str(entrance.slug +".html")
|
filename = str(entrance.slug +".html")
|
||||||
ent = read_entrance(filename, ent=entrance)
|
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)
|
entform = EntranceForm(instance=entrance)
|
||||||
if entslug is None:
|
if entslug is None:
|
||||||
entletterform = EntranceLetterForm()
|
entletterform = EntranceLetterForm()
|
||||||
# print(f" Getting entletter from EntranceLetterForm")
|
# print(f" Getting entletter from EntranceLetterForm")
|
||||||
else:
|
else:
|
||||||
entletter = caveAndEntrance.entranceletter
|
entletter = ce.entranceletter
|
||||||
if entletter == "":
|
if entletter == "":
|
||||||
entletterform = EntranceLetterForm()
|
entletterform = EntranceLetterForm()
|
||||||
print(f" Blank value: getting entletter from EntranceLetterForm")
|
print(f" Blank value: getting entletter from EntranceLetterForm")
|
||||||
@ -619,7 +668,14 @@ def cave_debug(request):
|
|||||||
{"ents": ents},
|
{"ents": ents},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def caveslist(request):
|
||||||
|
caves = Cave.objects.all()
|
||||||
|
print("CAVESLIST")
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"caveslist.html",
|
||||||
|
{"caves": caves},
|
||||||
|
)
|
||||||
def get_entrances(request, caveslug):
|
def get_entrances(request, caveslug):
|
||||||
try:
|
try:
|
||||||
cave = Cave.objects.get(caveslug__slug=caveslug)
|
cave = Cave.objects.get(caveslug__slug=caveslug)
|
||||||
|
29
templates/caveslist.html
Normal file
29
templates/caveslist.html
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}Caves List page
|
||||||
|
<!-- caveslist.html - this text visible because this template has been included -->
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h2 id="cmult">Caves</h2>
|
||||||
|
<p>Debug.. gets edited to whatever is needed by programmer..
|
||||||
|
<table>
|
||||||
|
<tr><th>Cave</th>
|
||||||
|
<th>cave filename</th>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
{% for c in caves %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{{c}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{c.filename}}
|
||||||
|
</td>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -7,11 +7,11 @@
|
|||||||
<h2>Troggle Error</h2>
|
<h2>Troggle Error</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<a href="/piclinks/wkmob.htm"><img align="right" style="margin:10px" src="/images/wkmob.jpg"></a>
|
||||||
<div class='middle3 login'>
|
<div class='middle3 login'>
|
||||||
<div class='space'></div>
|
<div class='space'></div>
|
||||||
<div class='align-center'>
|
<div class='align-center'>
|
||||||
<h3>There has been an error. This is either bad data or a bug in the software.</h3>
|
<h3>There has been an error. This is either bad data troggle can't cope with (yet), or a bug in the software.</h3>
|
||||||
<h4>
|
<h4>
|
||||||
|
|
||||||
<font color="red">
|
<font color="red">
|
||||||
|
5
urls.py
5
urls.py
@ -6,7 +6,7 @@ from django.conf.urls.static import static
|
|||||||
|
|
||||||
from troggle.core.views import statistics, survex
|
from troggle.core.views import statistics, survex
|
||||||
from troggle.core.views.auth import expologin, expologout
|
from troggle.core.views.auth import expologin, expologout
|
||||||
from troggle.core.views.caves import (cave3d, caveindex, entranceindex,
|
from troggle.core.views.caves import (cave3d, caveindex, entranceindex, caveslist,
|
||||||
cavepage, caveslugfwd, cavepagefwd, caveQMs, edit_cave, cave_debug,
|
cavepage, caveslugfwd, cavepagefwd, caveQMs, edit_cave, cave_debug,
|
||||||
edit_entrance, get_entrances, qm, expo_kml, expo_kmz)
|
edit_entrance, get_entrances, qm, expo_kml, expo_kmz)
|
||||||
from troggle.core.views.drawings import dwgallfiles, dwgfilesingle
|
from troggle.core.views.drawings import dwgallfiles, dwgfilesingle
|
||||||
@ -94,8 +94,9 @@ trogglepatterns = [
|
|||||||
re_path(r'^caves$', caveindex, name="caveindex"),
|
re_path(r'^caves$', caveindex, name="caveindex"),
|
||||||
re_path(r'^indxal.htm$', caveindex, name="caveindex"), # ~420 hrefs to this url in expoweb files
|
re_path(r'^indxal.htm$', caveindex, name="caveindex"), # ~420 hrefs to this url in expoweb files
|
||||||
re_path(r'^people/?$', notablepersons, name="notablepersons"),
|
re_path(r'^people/?$', notablepersons, name="notablepersons"),
|
||||||
|
path('caveslist', caveslist, name="caveslist"),
|
||||||
|
|
||||||
re_path(r'^entrances$', entranceindex, name="entranceindex"),
|
path('entrances', entranceindex, name="entranceindex"),
|
||||||
|
|
||||||
re_path(r'^admin/doc/', include('django.contrib.admindocs.urls')), # needs docutils Python module (http://docutils.sf.net/).
|
re_path(r'^admin/doc/', include('django.contrib.admindocs.urls')), # needs docutils Python module (http://docutils.sf.net/).
|
||||||
re_path(r'^admin/', admin.site.urls), # includes admin login & logout urls & /admin/jsi18n/
|
re_path(r'^admin/', admin.site.urls), # includes admin login & logout urls & /admin/jsi18n/
|
||||||
|
Loading…
Reference in New Issue
Block a user