Allow entrances to be edited with the correct parent url. Commit changes to caves when adding a new entrance. Order entrances alphabetically

This commit is contained in:
Martin Green 2022-08-01 16:04:22 +02:00
parent fa6758b9a0
commit f491264b9e
5 changed files with 87 additions and 51 deletions

View File

@ -116,11 +116,21 @@ class EntranceForm(ModelForm):
CaveAndEntranceFormSet = modelformset_factory(CaveAndEntrance, exclude=('cave',)) CaveAndEntranceFormSet = modelformset_factory(CaveAndEntrance, exclude=('cave',))
class EntranceLetterForm(ModelForm): class EntranceLetterForm(ModelForm):
'''Can't see what this does at all. called twice from views.caves '''Form to link entrances to caves, along with an entrance number.
Nb. The relationship between caves and entrances has historically been a many to many relationship.
With entrances gaining new caves and letters when caves are joined.
''' '''
class Meta: class Meta:
model = CaveAndEntrance model = CaveAndEntrance
exclude = ('cave', 'entrance') exclude = ('cave', 'entrance')
def full_clean(self):
super(EntranceLetterForm, self).full_clean()
try:
self.instance.validate_unique()
except forms.ValidationError as e:
self._update_errors(e)

View File

@ -62,6 +62,10 @@ class CaveAndEntrance(models.Model):
cave = models.ForeignKey('Cave',on_delete=models.CASCADE) cave = models.ForeignKey('Cave',on_delete=models.CASCADE)
entrance = models.ForeignKey('Entrance',on_delete=models.CASCADE) entrance = models.ForeignKey('Entrance',on_delete=models.CASCADE)
entrance_letter = models.CharField(max_length=20,blank=True, null=True) entrance_letter = models.CharField(max_length=20,blank=True, null=True)
class Meta:
unique_together = [['cave', 'entrance'], ['cave', 'entrance_letter']]
ordering = ['entrance_letter']
def __str__(self): def __str__(self):
return str(self.cave) + str(self.entrance_letter) return str(self.cave) + str(self.entrance_letter)
@ -176,7 +180,7 @@ class Cave(TroggleModel):
# res=QM.objects.filter(found_by__date__year=year, found_by__cave_slug=self.slug).order_by('-number')[0] # res=QM.objects.filter(found_by__date__year=year, found_by__cave_slug=self.slug).order_by('-number')[0]
# except IndexError: # except IndexError:
# return 1 # return 1
# return res.number+1 # return res.number+1CaveAndEntrance
def kat_area(self): def kat_area(self):
for a in self.area.all(): for a in self.area.all():
@ -228,7 +232,15 @@ class Cave(TroggleModel):
u = t.render(c) u = t.render(c)
writetrogglefile(filepath, u) writetrogglefile(filepath, u)
return return
def file_output(self):
filepath = Path(os.path.join(settings.CAVEDESCRIPTIONS, self.filename))
t = loader.get_template('dataformat/cave.xml')
#c = Context({'cave': self})
c = dict({'cave': self})
content = t.render(c)
return (filepath, content, "utf8")
def getArea(self): def getArea(self):
areas = self.area.all() areas = self.area.all()
@ -287,6 +299,9 @@ class Entrance(TroggleModel):
url = models.CharField(max_length=200,blank=True, null=True) url = models.CharField(max_length=200,blank=True, null=True)
filename = models.CharField(max_length=200) filename = models.CharField(max_length=200)
cached_primary_slug = models.CharField(max_length=200,blank=True, null=True) cached_primary_slug = models.CharField(max_length=200,blank=True, null=True)
class Meta:
ordering = ['caveandentrance__entrance_letter']
def __str__(self): def __str__(self):
return str(self.slug()) return str(self.slug())
@ -338,7 +353,7 @@ class Entrance(TroggleModel):
def has_photo(self): def has_photo(self):
if self.photo: if self.photo:
if (self.photo.find("<img") > -1 or self.photo.find("<a") > -1 or self.photo.find("<IMG") > -1 or self.photo.find("<A") > -1): if (self.photo.find("<img") > -1 or self.photo.find("<a") > -1 or self.photo.find("<IMG") > -1 or self.photo.find("<A") > -1):
return "Yecaves" return "Yes"
else: else:
return "Missing" return "Missing"
else: else:
@ -394,6 +409,14 @@ class Entrance(TroggleModel):
def get_file_path(self): def get_file_path(self):
return Path(settings.ENTRANCEDESCRIPTIONS, self.filename) return Path(settings.ENTRANCEDESCRIPTIONS, self.filename)
def file_output(self):
filepath = Path(os.path.join(settings.ENTRANCEDESCRIPTIONS, self.filename))
t = loader.get_template('dataformat/entrance.xml')
c = dict({'entrance': self})
content = t.render(c)
return (filepath, content, "utf8")
def writeDataFile(self): def writeDataFile(self):
filepath = os.path.join(settings.ENTRANCEDESCRIPTIONS, self.filename) filepath = os.path.join(settings.ENTRANCEDESCRIPTIONS, self.filename)

View File

@ -129,7 +129,7 @@ def write_and_commit(files, message):
kwargs = {"encoding": encoding} kwargs = {"encoding": encoding}
else: else:
mode = "wb" mode = "wb"
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} ')
@ -139,18 +139,21 @@ def write_and_commit(files, message):
except PermissionError: except PermissionError:
raise WriteAndCommitError(f'CANNOT save this file.\nPERMISSIONS incorrectly set on server for this file {filename}. Ask a nerd to fix this.') raise WriteAndCommitError(f'CANNOT save this file.\nPERMISSIONS incorrectly set on server for this file {filename}. Ask a nerd to fix this.')
cp_add = subprocess.run([git, "add", filename], cwd=cwd, capture_output=True, text=True) cp_diff = subprocess.run([git, "diff", filename], cwd=cwd, capture_output=True, text=True)
if cp_add.returncode != 0: if cp_diff.returncode == 0:
msgdata = 'Ask a nerd to fix this.\n\n' + cp_add.stderr + '\n\n' + cp_add.stdout + '\n\nreturn code: ' + str(cp_add.returncode) cp_add = subprocess.run([git, "add", filename], cwd=cwd, capture_output=True, text=True)
raise WriteAndCommitError(f'CANNOT git on server for this file {filename}. Edits saved but not added to git.\n\n' + msgdata) if cp_add.returncode != 0:
msgdata = 'Ask a nerd to fix this.\n\n' + cp_add.stderr + '\n\n' + cp_add.stdout + '\n\nreturn code: ' + str(cp_add.returncode)
raise WriteAndCommitError(f'CANNOT git on server for this file {filename}. Edits saved but not added to git.\n\n' + msgdata)
else:
print("No change %s" % filepah)
cp_commit = subprocess.run([git, "commit", "-m", message], cwd=cwd, capture_output=True, text=True) cp_commit = subprocess.run([git, "commit", "-m", message], cwd=cwd, capture_output=True, text=True)
cp_status = subprocess.run([git, "status"], cwd=cwd, capture_output=True, text=True)
# This produces return code = 1 if it commits OK, but when the repo still needs to be pushed to origin/expoweb # This produces return code = 1 if it commits OK, but when the repo still needs to be pushed to origin/expoweb
if cp_commit.returncode != 0 and cp_commit.stdout != 'nothing to commit, working tree clean': if cp_status.stdout.split("\n")[-2] != 'nothing to commit, working tree clean':
msgdata = 'Ask a nerd to fix this.\n\n' + cp_commit.stderr + '\n\n' + cp_commit.stdout + '\n\nreturn code: ' + str(cp_commit.returncode) print("FOO: ", cp_status.stdout.split("\n")[-2])
print(msgdata) msgdata = 'Ask a nerd to fix this.\n\n' + cp_status.stderr + '\n\n' + cp_status.stdout + '\n\nreturn code: ' + str(cp_status.returncode)
raise WriteAndCommitError(f'Error code with git on server for this file {filename}. Edits saved, added to git, but NOT committed.\n\n' + msgdata) raise WriteAndCommitError(f'Error code with git on server for this file {filename}. Edits saved, added to git, but NOT committed.\n\n' + msgdata)
except subprocess.SubprocessError: except subprocess.SubprocessError:
raise WriteAndCommitError(f'CANNOT git on server for this file {filename}. Subprocess error. Edits not saved.\nAsk a nerd to fix this.') raise WriteAndCommitError(f'CANNOT git on server for this file {filename}. Subprocess error. Edits not saved.\nAsk a nerd to fix this.')

View File

@ -19,6 +19,7 @@ from troggle.core.views import expo
from troggle.core.models.troggle import Expedition, DataIssue from troggle.core.models.troggle import Expedition, DataIssue
from troggle.core.models.caves import CaveSlug, Cave, CaveAndEntrance, QM, EntranceSlug, Entrance, Area, SurvexStation, GetCaveLookup from troggle.core.models.caves import CaveSlug, Cave, CaveAndEntrance, QM, EntranceSlug, Entrance, Area, SurvexStation, GetCaveLookup
from troggle.core.forms import CaveForm, CaveAndEntranceFormSet, EntranceForm, EntranceLetterForm from troggle.core.forms import CaveForm, CaveAndEntranceFormSet, EntranceForm, EntranceLetterForm
from troggle.core.utils import writetrogglefile, write_and_commit
from .auth import login_required_if_public from .auth import login_required_if_public
'''Manages the complex procedures to assemble a cave description out of the compnoents '''Manages the complex procedures to assemble a cave description out of the compnoents
@ -187,7 +188,7 @@ def file3d(request, cave, cave_id):
# These if statements need refactoring more cleanly # These if statements need refactoring more cleanly
if cave.survex_file: if cave.survex_file:
#print(" - cave.survex_file '{}'".format(cave.survex_file)) #print(" - cave.survex_file '{}'".format(cave.survex_file))
if threedpath.is_file(): if threedpath.Pathis_file():
#print(" - threedpath '{}'".format(threedpath)) #print(" - threedpath '{}'".format(threedpath))
# possible error here as several .svx files of same names in different directories will overwrite in /3d/ # possible error here as several .svx files of same names in different directories will overwrite in /3d/
if survexpath.is_file(): if survexpath.is_file():
@ -342,7 +343,8 @@ def edit_cave(request, path = "", slug=None):
ceinst.cave = cave ceinst.cave = cave
ceinst.save() ceinst.save()
try: try:
cave.writeDataFile() cave_file = cave.file_output()
write_and_commit([cave_file], "Online edit of %s" % cave)
# leave other exceptions unhandled so that they bubble up to user interface # leave other exceptions unhandled so that they bubble up to user interface
except PermissionError: except PermissionError:
message = f'CANNOT save this file.\nPERMISSIONS incorrectly set on server for this file {cave.filename}. Ask a nerd to fix this.' message = f'CANNOT save this file.\nPERMISSIONS incorrectly set on server for this file {cave.filename}. Ask a nerd to fix this.'
@ -375,27 +377,28 @@ def edit_entrance(request, path = "", caveslug=None, slug=None):
It does save the data into into the database directly, not by parsing the file. It does save the data into into the database directly, not by parsing the file.
''' '''
message = ""
if caveslug is not None: try:
try: cave = Cave.objects.get(caveslug__slug = caveslug)
cave = Cave.objects.get(caveslug__slug = caveslug) except:
except: return render(request,'errors/badslug.html', {'badslug': caveslug})
return render(request,'errors/badslug.html', {'badslug': caveslug})
else: if slug:
cave = Cave()
if slug is not None:
entrance = Entrance.objects.get(entranceslug__slug = slug) entrance = Entrance.objects.get(entranceslug__slug = slug)
caveAndEntrance = CaveAndEntrance.objects.get(entrance = entrance, cave = cave)
entlettereditable = False
else: else:
entrance = Entrance() entrance = Entrance()
caveAndEntrance = CaveAndEntrance(cave = cave, entrance = entrance)
entlettereditable = True
if request.POST: if request.POST:
form = EntranceForm(request.POST, instance = entrance) form = EntranceForm(request.POST, instance = entrance)
entletter = EntranceLetterForm(request.POST, instance = caveAndEntrance)
#versionControlForm = VersionControlCommentForm(request.POST) #versionControlForm = VersionControlCommentForm(request.POST)
if slug is None: if form.is_valid() and entletter.is_valid():
entletter = EntranceLetterForm(request.POST)
else:
entletter = None
if form.is_valid() and (slug is not None or entletter.is_valid()):
entrance = form.save(commit = False) entrance = form.save(commit = False)
entrance_letter = entletter.save(commit = False)
if slug is None: if slug is None:
if entletter.cleaned_data["entrance_letter"]: if entletter.cleaned_data["entrance_letter"]:
slugname = cave.slug() + entletter.cleaned_data["entrance_letter"] slugname = cave.slug() + entletter.cleaned_data["entrance_letter"]
@ -407,36 +410,29 @@ def edit_entrance(request, path = "", caveslug=None, slug=None):
if slug is None: if slug is None:
es = EntranceSlug(entrance = entrance, slug = slugname, primary = True) es = EntranceSlug(entrance = entrance, slug = slugname, primary = True)
es.save() es.save()
el = entletter.save(commit = False) entrance_file = entrance.file_output()
el.cave = cave cave_file = cave.file_output()
el.entrance = entrance write_and_commit([entrance_file, cave_file], "Online edit of %s%s" % (cave, entletter))
el.save() entrance.save()
try: if slug is None:
entrance.writeDataFile() entrance_letter.save()
# leave other exceptions unhandled so that they bubble up to user interface
except PermissionError:
message = f'CANNOT save this file.\nPERMISSIONS incorrectly set on server for this file {entrance.filename}. Ask a nerd to fix this.'
return render(request,'errors/generic.html', {'message': message})
except subprocess.SubprocessError:
message = f'CANNOT git on server for this file {entrance.filename}. Edits may not be committed.\nAsk a nerd to fix this.'
return render(request,'errors/generic.html', {'message': message})
return HttpResponseRedirect("/" + cave.url) return HttpResponseRedirect("/" + cave.url)
else:
message = f'! POST data is INVALID {cave}'
print(message)
else: else:
form = EntranceForm(instance = entrance) form = EntranceForm(instance = entrance)
#versionControlForm = VersionControlCommentForm() #versionControlForm = VersionControlCommentForm()
if slug is None: if slug is None:
entletter = EntranceLetterForm(request.POST) entletter = EntranceLetterForm()
else: else:
entletter = None entletter = caveAndEntrance.entrance_letter
return render(request, return render(request,
'editentrance.html', 'editentrance.html',
{'form': form, 'cave': cave, 'message': message, {'form': form,
'cave': cave,
#'versionControlForm': versionControlForm, #'versionControlForm': versionControlForm,
'entletter': entletter 'entletter': entletter,
'entlettereditable': entlettereditable
}) })
def ent(request, cave_id, ent_letter): def ent(request, cave_id, ent_letter):

View File

@ -8,8 +8,12 @@
<h1>Edit Entrance - at cave {{cave.official_name|safe}} - {{cave.kataster_number}}</h1> <h1>Edit Entrance - at cave {{cave.official_name|safe}} - {{cave.kataster_number}}</h1>
{% include 'html_editor_pop_ups.html' %} {% include 'html_editor_pop_ups.html' %}
<h2>{{message}}</h2> <h2>{{message}}</h2>
<p>{{entletter}}
<form action="" method="post">{% csrf_token %} <form action="" method="post">{% csrf_token %}
{% if entlettereditable %}
<table>{{ entletter }}</table>
{% else %}
<table><tr><th>Entrance Letter</th><td>{{ entletter }}</td></table>
{% endif %}
<table>{{ form }}</table> <table>{{ form }}</table>
{{ versionControlForm }} {{ versionControlForm }}
<p><input type="submit" value="Submit" /></p> <p><input type="submit" value="Submit" /></p>