mirror of
https://expo.survex.com/repositories/troggle/.git
synced 2024-11-22 07:11:52 +00:00
Edit Logbook Entry mostly working
This commit is contained in:
parent
bbb821e2f9
commit
c29c12ea76
@ -1,8 +1,11 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.template import loader
|
||||||
|
|
||||||
import settings
|
import settings
|
||||||
from troggle.core.models.troggle import Expedition, TroggleModel
|
from troggle.core.models.troggle import Expedition, TroggleModel
|
||||||
@ -50,7 +53,7 @@ class LogbookEntry(TroggleModel):
|
|||||||
max_length=100, blank=True, null=True, help_text="Only use this if you haven't chosen a cave"
|
max_length=100, blank=True, null=True, help_text="Only use this if you haven't chosen a cave"
|
||||||
)
|
)
|
||||||
text = models.TextField()
|
text = models.TextField()
|
||||||
slug = models.SlugField(max_length=50)
|
slug = models.SlugField(max_length=50) # this is tripid
|
||||||
time_underground = models.FloatField(null=True, help_text="In decimal hours")
|
time_underground = models.FloatField(null=True, help_text="In decimal hours")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -93,7 +96,47 @@ class LogbookEntry(TroggleModel):
|
|||||||
index = index % mx
|
index = index % mx
|
||||||
return index
|
return index
|
||||||
|
|
||||||
|
def writelogbook(year, filename):
|
||||||
|
current_expedition = Expedition.objects.get(year=year)
|
||||||
|
logbook_entries = LogbookEntry.objects.filter(expedition=current_expedition).order_by(
|
||||||
|
"slug"
|
||||||
|
) # now that slug, aka tripid, is in our standard date form, this will preserve ordering.
|
||||||
|
|
||||||
|
print(f"Logbook exported has {len(logbook_entries)} entries in it.")
|
||||||
|
|
||||||
|
extension = "html"
|
||||||
|
template = "logbook2005style.html"
|
||||||
|
|
||||||
|
t = loader.get_template(template)
|
||||||
|
logbookfile = t.render({"logbook_entries": logbook_entries})
|
||||||
|
|
||||||
|
endpath = Path(settings.EXPOWEB, "years", year, "endmatter.html")
|
||||||
|
endmatter = ""
|
||||||
|
if endpath.is_file():
|
||||||
|
try:
|
||||||
|
with open(endpath, "r") as end:
|
||||||
|
endmatter = end.read()
|
||||||
|
except:
|
||||||
|
print(" ! Very Bad Error opening " + endpath)
|
||||||
|
|
||||||
|
frontpath = Path(settings.EXPOWEB, "years", year, "frontmatter.html")
|
||||||
|
if frontpath.is_file():
|
||||||
|
try:
|
||||||
|
with open(frontpath, "r") as front:
|
||||||
|
frontmatter = front.read()
|
||||||
|
except:
|
||||||
|
print(" ! Very Bad Error opening " + frontpath)
|
||||||
|
logbookfile = re.sub(r"<body>", "<body>\n" + frontmatter + endmatter, logbookfile)
|
||||||
|
else:
|
||||||
|
logbookfile = re.sub(r"<body>", f"<body>\n<h1>Expo {year}</h1>\n" + endmatter, logbookfile)
|
||||||
|
|
||||||
|
dir = Path(settings.EXPOWEB) / "years" / year
|
||||||
|
filepath = Path(dir, filename)
|
||||||
|
with (open(filepath, "w")) as lb:
|
||||||
|
lb.writelines(logbookfile)
|
||||||
|
|
||||||
|
# print(f'Logbook exported to {filepath}')
|
||||||
|
|
||||||
class PersonLogEntry(TroggleModel):
|
class PersonLogEntry(TroggleModel):
|
||||||
"""Single Person going on a trip, which may or may not be written up.
|
"""Single Person going on a trip, which may or may not be written up.
|
||||||
It could account for different T/U for people in same logbook entry.
|
It could account for different T/U for people in same logbook entry.
|
||||||
|
@ -7,7 +7,7 @@ from django.shortcuts import render
|
|||||||
from django.template import loader
|
from django.template import loader
|
||||||
|
|
||||||
from troggle.core.models.caves import Cave
|
from troggle.core.models.caves import Cave
|
||||||
from troggle.core.models.logbooks import LogbookEntry # , PersonLogEntry
|
from troggle.core.models.logbooks import LogbookEntry, writelogbook # , PersonLogEntry
|
||||||
|
|
||||||
# from databaseReset import reinit_db # don't do this. databaseRest runs code *at import time*
|
# from databaseReset import reinit_db # don't do this. databaseRest runs code *at import time*
|
||||||
from troggle.core.models.troggle import Expedition
|
from troggle.core.models.troggle import Expedition
|
||||||
@ -169,69 +169,31 @@ def controlpanel(request):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def exportlogbook(request, year=None, extension=None):
|
def exportlogbook(request, year=None):
|
||||||
"""Constructs, from the database, a complete HTML formatted logbook
|
"""Constructs, from the database, a complete HTML formatted logbook
|
||||||
for the current year. Formats available are HTML2005. Other formats
|
for the current year. Format available is now just HTML2005.
|
||||||
have been retired.
|
Other formats have been retired.
|
||||||
|
|
||||||
There are no images stored in the database. However links to images work in the HTML text of a logbook entry.
|
There are no images stored in the database. However links to images work in the HTML text of a logbook entry.
|
||||||
|
|
||||||
This function is the recipient of the POST action os the export form in the control panel
|
This function is the recipient of the POST action as the export form in the control panel
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def lbeKey(lbe):
|
def lbeKey(lbe):
|
||||||
"""This function goes into a lexicographic sort function"""
|
"""This function goes into a lexicographic sort function - but where?!"""
|
||||||
return str(lbe.date)
|
return str(lbe.slug) # now that slugs are tripid such as 2023-07-30b
|
||||||
|
|
||||||
if not request.method == "POST":
|
if not request.method == "POST":
|
||||||
return render(request, "controlPanel.html", {"expeditions": Expedition.objects.all(), "jobs_completed": ""})
|
return render(request, "controlPanel.html", {"expeditions": Expedition.objects.all(), "jobs_completed": ""})
|
||||||
else:
|
else:
|
||||||
print(f"Logbook export {request.POST}")
|
# print(f"Logbook export {request.POST}")
|
||||||
|
|
||||||
year = request.POST["year"]
|
year = request.POST["year"]
|
||||||
current_expedition = Expedition.objects.get(year=year)
|
filename = "logbook-new-format.html"
|
||||||
logbook_entries = LogbookEntry.objects.filter(expedition=current_expedition).order_by(
|
|
||||||
"date"
|
|
||||||
) # need to be sorted by date!
|
|
||||||
|
|
||||||
print(f"Logbook has {len(logbook_entries)} entries in it.")
|
writelogbook(year, filename)
|
||||||
|
#response = HttpResponse(content_type="text/html")
|
||||||
extension = "html"
|
#response["Content-Disposition"] = "attachment; filename=" + filename
|
||||||
response = HttpResponse(content_type="text/html")
|
|
||||||
style = "2005"
|
|
||||||
|
|
||||||
filename = "logbook-new-format." + extension
|
|
||||||
template = "logbook" + style + "style." + extension
|
|
||||||
response["Content-Disposition"] = "attachment; filename=" + filename
|
|
||||||
t = loader.get_template(template)
|
|
||||||
logbookfile = t.render({"logbook_entries": logbook_entries})
|
|
||||||
|
|
||||||
endpath = Path(settings.EXPOWEB, "years", year, "endmatter.html")
|
|
||||||
endmatter = ""
|
|
||||||
if endpath.is_file():
|
|
||||||
try:
|
|
||||||
with open(endpath, "r") as end:
|
|
||||||
endmatter = end.read()
|
|
||||||
except:
|
|
||||||
print(" ! Very Bad Error opening " + endpath)
|
|
||||||
|
|
||||||
frontpath = Path(settings.EXPOWEB, "years", year, "frontmatter.html")
|
|
||||||
if frontpath.is_file():
|
|
||||||
try:
|
|
||||||
with open(frontpath, "r") as front:
|
|
||||||
frontmatter = front.read()
|
|
||||||
except:
|
|
||||||
print(" ! Very Bad Error opening " + frontpath)
|
|
||||||
logbookfile = re.sub(r"<body>", "<body>\n" + frontmatter + endmatter, logbookfile)
|
|
||||||
else:
|
|
||||||
logbookfile = re.sub(r"<body>", f"<body>\n<h1>Expo {year}</h1>\n" + endmatter, logbookfile)
|
|
||||||
|
|
||||||
dir = Path(settings.EXPOWEB) / "years" / year
|
|
||||||
filepath = Path(dir, filename)
|
|
||||||
with (open(filepath, "w")) as lb:
|
|
||||||
lb.writelines(logbookfile)
|
|
||||||
|
|
||||||
# print(f'Logbook exported to {filepath}')
|
|
||||||
completed = f'Logbook exported to <a href="/years/{filename}">{filename}</a>'
|
completed = f'Logbook exported to <a href="/years/{filename}">{filename}</a>'
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import string
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@ -8,8 +9,11 @@ from django.core.files.storage import FileSystemStorage
|
|||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
|
|
||||||
import settings
|
import settings
|
||||||
from troggle.core.models.logbooks import LogbookEntry, PersonLogEntry
|
from troggle.core.models.caves import GetCaveLookup
|
||||||
|
from troggle.core.models.logbooks import LogbookEntry, writelogbook, PersonLogEntry
|
||||||
from troggle.core.models.survex import DrawingFile
|
from troggle.core.models.survex import DrawingFile
|
||||||
|
from troggle.core.models.troggle import DataIssue, Expedition, PersonExpedition
|
||||||
|
from troggle.parsers.people import GetPersonExpeditionNameLookup, known_foreigner
|
||||||
|
|
||||||
# from databaseReset import reinit_db # don't do this. databaseRest runs code *at import time*
|
# from databaseReset import reinit_db # don't do this. databaseRest runs code *at import time*
|
||||||
|
|
||||||
@ -21,11 +25,6 @@ and that core/forms.py contains Django class-based forms for caves and entrances
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
todo = """
|
todo = """
|
||||||
- munge the URL of images in the logbook entry so that they work from both the " /logbookedit/" page,
|
|
||||||
the logbook /years/2023/ page and the logbook fragment page /logbookentry/<date>/
|
|
||||||
Note that this munging has already been done when the entry is imported into the database, so
|
|
||||||
when doing an online edit it has already been fixed.
|
|
||||||
|
|
||||||
- Ideally we should validate uploaded file as being a valid file type, not a dubious script or hack
|
- Ideally we should validate uploaded file as being a valid file type, not a dubious script or hack
|
||||||
Validate image files using a magic recogniser in walletedit()
|
Validate image files using a magic recogniser in walletedit()
|
||||||
https://pypi.org/project/reportlab/ or
|
https://pypi.org/project/reportlab/ or
|
||||||
@ -48,6 +47,89 @@ todo = """
|
|||||||
"""
|
"""
|
||||||
sha = hashlib.new('sha256')
|
sha = hashlib.new('sha256')
|
||||||
|
|
||||||
|
def unique_slug(text, n):
|
||||||
|
"""This gives each logbook entry a unique id based on the date+content, so the order of entries on a particular day
|
||||||
|
does not matter. This is a change (August 2023) from previous process.
|
||||||
|
|
||||||
|
2 hex digits would seem adequate for each expo day, but we might get a collision.
|
||||||
|
The hash is based on the content after substitution of <p> so should be stable. Which means these ids
|
||||||
|
can be used elsewhere in the troggle system as permanent slugs.
|
||||||
|
|
||||||
|
When SAVING an edited entry (as opposed to a new one) we will have a different hash so we will have to
|
||||||
|
delete the original database object
|
||||||
|
"""
|
||||||
|
sha.update(text.encode('utf-8'))
|
||||||
|
return sha.hexdigest()[0:n]
|
||||||
|
|
||||||
|
def create_new_lbe_slug(date):
|
||||||
|
onthisdate = LogbookEntry.objects.filter(date=date)
|
||||||
|
n = len(onthisdate)
|
||||||
|
# print(f" Already entries on this date: {n}\n {onthisdate}")
|
||||||
|
|
||||||
|
alphabet = list(string.ascii_lowercase)
|
||||||
|
tid = f"{date}{alphabet[n]}"
|
||||||
|
print(tid)
|
||||||
|
return tid
|
||||||
|
|
||||||
|
def store_edited_entry_into_database(date, place, title, text, others, author, tu, slug):
|
||||||
|
"""saves a single logbook entry and related personlogentry items
|
||||||
|
|
||||||
|
Rather similar to similarly named function in parsers/logbooks but circular reference prevents us using it directly,
|
||||||
|
and they need refactoring anyway.
|
||||||
|
"""
|
||||||
|
|
||||||
|
year = slug[0:4]
|
||||||
|
expedition = Expedition.objects.get(year=year)
|
||||||
|
cave = GetCaveLookup().get(place.lower())
|
||||||
|
# print(f"{place} {cave=}")
|
||||||
|
|
||||||
|
if LogbookEntry.objects.filter(slug=slug).exists():
|
||||||
|
# oops.
|
||||||
|
message = " ! - DUPLICATE SLUG for logbook entry " + tripdate + " - " + slug
|
||||||
|
DataIssue.objects.create(parser="logbooks", message=message)
|
||||||
|
slug = slug + "_" + unique_slug(text,2)
|
||||||
|
|
||||||
|
nonLookupAttribs = {
|
||||||
|
"place": place,
|
||||||
|
"text": text,
|
||||||
|
"expedition": expedition,
|
||||||
|
"time_underground": tu,
|
||||||
|
"cave_slug": str(cave),
|
||||||
|
}
|
||||||
|
lookupAttribs = {"slug": slug, "date": date, "title": title}
|
||||||
|
|
||||||
|
lbo = LogbookEntry.objects.create(**nonLookupAttribs, **lookupAttribs)
|
||||||
|
|
||||||
|
pt_list = []
|
||||||
|
# These entities have to be PersonExpedition objects
|
||||||
|
team = others.split(",")
|
||||||
|
team.append(author)
|
||||||
|
for name in team:
|
||||||
|
name = name.strip()
|
||||||
|
if name[0] != "*": # a name prefix of "*" is special, just a string.
|
||||||
|
try:
|
||||||
|
personyear = GetPersonExpeditionNameLookup(expedition).get(name.lower())
|
||||||
|
if not personyear:
|
||||||
|
if known_foreigner(name):
|
||||||
|
message = f" ! - Known foreigner: '{name}' in entry {slug=}"
|
||||||
|
print(message)
|
||||||
|
else:
|
||||||
|
message = f" ! - No name match for: '{name}' in entry {slug=}"
|
||||||
|
print(message)
|
||||||
|
DataIssue.objects.create(parser="logbooks", message=message)
|
||||||
|
else:
|
||||||
|
lookupAttribs = {"personexpedition": personyear, "nickname_used": name, "logbook_entry": lbo} # lbo is primary key
|
||||||
|
nonLookupAttribs = {"time_underground": tu, "is_logbook_entry_author": (name==author)}
|
||||||
|
pt_list.append(PersonLogEntry(**nonLookupAttribs, **lookupAttribs))
|
||||||
|
|
||||||
|
except:
|
||||||
|
# This should not happen. We do not raise exceptions in that function
|
||||||
|
message = f" ! - EXCEPTION: '{name}' in entry {slug=}"
|
||||||
|
print(message)
|
||||||
|
DataIssue.objects.create(parser="logbooks", message=message)
|
||||||
|
raise
|
||||||
|
|
||||||
|
PersonLogEntry.objects.bulk_create(pt_list)
|
||||||
|
|
||||||
class FilesForm(forms.Form): # not a model-form, just a form-form
|
class FilesForm(forms.Form): # not a model-form, just a form-form
|
||||||
uploadfiles = forms.FileField()
|
uploadfiles = forms.FileField()
|
||||||
@ -70,9 +152,7 @@ def logbookedit(request, year=None, slug=None):
|
|||||||
"""Edit a logbook entry
|
"""Edit a logbook entry
|
||||||
This is daft: we have the parsed identity of the person and we render it to text as 'nickname_used'
|
This is daft: we have the parsed identity of the person and we render it to text as 'nickname_used'
|
||||||
(or, previously, 'fullname'), to be re-parsed on re-importing.
|
(or, previously, 'fullname'), to be re-parsed on re-importing.
|
||||||
And there is no guarantee that this will be the same thing.
|
And there is no guarantee that this will be the same thing. Oh well.
|
||||||
|
|
||||||
Someone can put in a nickname which is invalid (e.g. 2 Sophies on expo). When is this checked?
|
|
||||||
"""
|
"""
|
||||||
def clean_tu(tu):
|
def clean_tu(tu):
|
||||||
if tu =="":
|
if tu =="":
|
||||||
@ -82,28 +162,14 @@ def logbookedit(request, year=None, slug=None):
|
|||||||
except:
|
except:
|
||||||
return 0
|
return 0
|
||||||
return tu
|
return tu
|
||||||
|
|
||||||
def unique_id(text, n):
|
|
||||||
"""This gives each logbook entry a unique id based on the date+content, so the order of entries on a particular day
|
|
||||||
does not matter. This is a change (August 2023) from previous process.
|
|
||||||
Otherwise we could get 2023-07-20a and 2023-07-20b swapped on exporting and re-importing logbooks
|
|
||||||
because the database does not record precedence.
|
|
||||||
2 hex digits would seem adequate for each expo day, but we might get a collision.
|
|
||||||
The hash is based on the content after substitution of <p> so should be stable. Which means these ids
|
|
||||||
can be used elsewhere in the troggle system as permanent slugs.
|
|
||||||
|
|
||||||
When SAVING an edited entry (as opposed to a new one) we will have a different hash so we will have to
|
|
||||||
delete the original database object
|
|
||||||
"""
|
|
||||||
sha.update(text.encode('utf-8'))
|
|
||||||
return sha.hexdigest()[0:n]
|
|
||||||
|
|
||||||
if not year:
|
if not year:
|
||||||
if not slug:
|
if not slug:
|
||||||
year = 2023
|
year = 2023 # we need a CURRENT_EXPO() function, we use this in a lot of places..
|
||||||
else:
|
else:
|
||||||
year = slug[0:4]
|
year = slug[0:4]
|
||||||
print(year)
|
print(year)
|
||||||
|
author = ""
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = LogbookEditForm(request.POST)
|
form = LogbookEditForm(request.POST)
|
||||||
@ -112,11 +178,13 @@ def logbookedit(request, year=None, slug=None):
|
|||||||
print(message)
|
print(message)
|
||||||
return render(request, "errors/generic.html", {"message": message})
|
return render(request, "errors/generic.html", {"message": message})
|
||||||
else:
|
else:
|
||||||
|
# if there is no slug then this is a completely new lbe and we need to enter it into the db
|
||||||
|
# otherwise it is an update
|
||||||
# validation all to be done yet..
|
# validation all to be done yet..
|
||||||
date = request.POST["date"].strip()
|
date = request.POST["date"].strip()
|
||||||
author = request.POST["author"].strip() # TODO check against personexpedition
|
author = request.POST["author"].strip() # TODO check against personexpedition
|
||||||
others = request.POST["others"].strip() # TODO check each against personexpedition
|
others = request.POST["others"].strip() # TODO check each against personexpedition
|
||||||
place = request.POST["place"].strip().replace('-','=') # no hyphens !
|
place = request.POST["place"].strip().replace(' - ',' = ') # no hyphens !
|
||||||
title = request.POST["title"].strip()
|
title = request.POST["title"].strip()
|
||||||
entry = request.POST["text"].strip()
|
entry = request.POST["text"].strip()
|
||||||
entry = entry.replace('\r','') # remove HTML-standard CR inserted
|
entry = entry.replace('\r','') # remove HTML-standard CR inserted
|
||||||
@ -135,16 +203,30 @@ def logbookedit(request, year=None, slug=None):
|
|||||||
dateflag = True
|
dateflag = True
|
||||||
date = odate.isoformat()
|
date = odate.isoformat()
|
||||||
|
|
||||||
newslug = f"{date}_{unique_id(entry,2)}"
|
if not slug:
|
||||||
if slug:
|
# Creating a new logbook entry with all the gubbins
|
||||||
if slug != newslug:
|
slug = create_new_lbe_slug(date)
|
||||||
print(f"! Entry id changed! from {slug} to {newslug}")
|
else:
|
||||||
|
# OK we could patch the object in place, but if the people on the trip have changed this
|
||||||
|
# would get very messy. So we delete it and recreate it and all its links
|
||||||
|
print(f"- Deleting the LogBookEntry {slug}")
|
||||||
|
LogbookEntry.objects.filter(slug=slug).delete()
|
||||||
|
|
||||||
|
print(f"- Creating the LogBookEntry {slug}")
|
||||||
|
store_edited_entry_into_database(date, place, title, entry, others, author, tu, slug)
|
||||||
|
print(f"- Rewriting the entire {year} logbook to disc ")
|
||||||
|
filename= "logbook.html"
|
||||||
|
try:
|
||||||
|
writelogbook(year, filename) # uses a template, not the code fragment below
|
||||||
|
except:
|
||||||
|
message = f'! - Logbook saving failed - \n!! Permissions failure ?! on attempting to save file "logbook.html"'
|
||||||
|
print(message)
|
||||||
|
return render(request, "errors/generic.html", {"message": message})
|
||||||
|
|
||||||
# OK this could be done by rendering a template, but for such a small bit of HTML, it is easier to have
|
# Code fragment illustration - not actually what gets saved to database
|
||||||
# it all in one place: here
|
|
||||||
output = f'''
|
output = f'''
|
||||||
|
|
||||||
<div class="tripdate" id="{newslug}">{date}</div>
|
<div class="tripdate" id="{slug}">{date}</div>
|
||||||
<div class="trippeople"><u>{author}</u>, {others}</div>
|
<div class="trippeople"><u>{author}</u>, {others}</div>
|
||||||
<div class="triptitle">{place} - {title}</div>
|
<div class="triptitle">{place} - {title}</div>
|
||||||
|
|
||||||
@ -154,6 +236,65 @@ def logbookedit(request, year=None, slug=None):
|
|||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
# Successful POST
|
||||||
|
# So save to database and then write out whole new logbook.html file
|
||||||
|
|
||||||
|
#TO DO author and team validation, and check that 'place' is not deleted and that *bloke not forgotten
|
||||||
|
git = settings.GIT
|
||||||
|
dirpath = Path(settings.EXPOWEB) / "years" / year
|
||||||
|
lbe_add = subprocess.run(
|
||||||
|
[git, "add", filename], cwd=dirpath, capture_output=True, text=True
|
||||||
|
)
|
||||||
|
msgdata = (
|
||||||
|
lbe_add.stderr
|
||||||
|
+ "\n"
|
||||||
|
+ lbe_add.stdout
|
||||||
|
+ "\nreturn code: "
|
||||||
|
+ str(lbe_add.returncode)
|
||||||
|
)
|
||||||
|
message = f'! - FORM Logbook Edit {slug} - Success: git ADD on server for this file {filename}.' + msgdata
|
||||||
|
print(message)
|
||||||
|
if lbe_add.returncode != 0:
|
||||||
|
msgdata = (
|
||||||
|
"Ask a nerd to fix this.\n\n"
|
||||||
|
+ lbe_add.stderr
|
||||||
|
+ "\n\n"
|
||||||
|
+ lbe_add.stdout
|
||||||
|
+ "\n\nreturn code: "
|
||||||
|
+ str(lbe_add.returncode)
|
||||||
|
)
|
||||||
|
message = (
|
||||||
|
f"! - FORM Logbook Edit - CANNOT git ADD on server for this file {filename}. {slug} edits saved but not added to git.\n"
|
||||||
|
+ msgdata
|
||||||
|
)
|
||||||
|
print(message)
|
||||||
|
return render(request, "errors/generic.html", {"message": message})
|
||||||
|
|
||||||
|
lbe_commit = subprocess.run(
|
||||||
|
[git, "commit", "-m", f"Logbook edited {slug}"],
|
||||||
|
cwd=dirpath,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
message = f'! - FORM Logbook Edit - {filename}. {slug} edits saved, added to git, and COMMITTED.\n' + msgdata
|
||||||
|
print(message)
|
||||||
|
#This produces return code = 1 if it commits OK
|
||||||
|
if lbe_commit.returncode != 0:
|
||||||
|
msgdata = (
|
||||||
|
"Ask a nerd to fix this.\n\n"
|
||||||
|
+ lbe_commit.stderr
|
||||||
|
+ "\n"
|
||||||
|
+ lbe_commit.stdout
|
||||||
|
+ "\nreturn code: "
|
||||||
|
+ str(lbe_commit.returncode)
|
||||||
|
)
|
||||||
|
message = (
|
||||||
|
f"! - FORM Logbook Edit -Error code with git on server for {filename}. {slug} edits saved, added to git, but NOT committed.\n"
|
||||||
|
+ msgdata
|
||||||
|
)
|
||||||
|
print(message)
|
||||||
|
return render(request, "errors/generic.html", {"message": message})
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"logbookform.html",
|
"logbookform.html",
|
||||||
@ -212,10 +353,10 @@ def logbookedit(request, year=None, slug=None):
|
|||||||
"tu": tu,
|
"tu": tu,
|
||||||
"entry": text,
|
"entry": text,
|
||||||
"textrows": rows,
|
"textrows": rows,
|
||||||
#"output": output,
|
},
|
||||||
},
|
|
||||||
)
|
)
|
||||||
else:
|
else: # no slug
|
||||||
|
# NEW logbook entry
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"logbookform.html",
|
"logbookform.html",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import string
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
@ -15,6 +16,7 @@ from troggle.core.models.caves import GetCaveLookup
|
|||||||
from troggle.core.models.logbooks import LogbookEntry, PersonLogEntry
|
from troggle.core.models.logbooks import LogbookEntry, PersonLogEntry
|
||||||
from troggle.core.models.troggle import DataIssue, Expedition
|
from troggle.core.models.troggle import DataIssue, Expedition
|
||||||
from troggle.core.utils import get_process_memory
|
from troggle.core.utils import get_process_memory
|
||||||
|
from troggle.core.views.uploads import unique_slug
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Parses and imports logbooks in all their wonderful confusion
|
Parses and imports logbooks in all their wonderful confusion
|
||||||
@ -106,11 +108,31 @@ ENTRIES = {
|
|||||||
|
|
||||||
logentries = [] # the entire logbook for one year is a single object: a list of entries
|
logentries = [] # the entire logbook for one year is a single object: a list of entries
|
||||||
noncaveplaces = ["travel", "Journey", "Loser Plateau", "UNKNOWN", "plateau", "base camp", "basecamp", "top camp", "topcamp"]
|
noncaveplaces = ["travel", "Journey", "Loser Plateau", "UNKNOWN", "plateau", "base camp", "basecamp", "top camp", "topcamp"]
|
||||||
|
tripsdate = {}
|
||||||
|
alphabet = []
|
||||||
|
|
||||||
def set_trip_id(year, seq):
|
def set_trip_seq_id(year, seq):
|
||||||
|
'''We have not parsed the trip date yet, so this is a sequence numer
|
||||||
|
'''
|
||||||
tid = f"{year}_s{seq:02d}"
|
tid = f"{year}_s{seq:02d}"
|
||||||
return tid
|
return tid
|
||||||
|
|
||||||
|
def reset_trip_id(date):
|
||||||
|
'''Now we have the date, we can set the tripid (the lbe slug) to be in our standard form
|
||||||
|
of <date><letter>, i.e. '2003-07-30b'
|
||||||
|
BUT this gets re-set every time the logbook is imported,
|
||||||
|
so they are not persistent as we would much prefer.
|
||||||
|
'''
|
||||||
|
global alphabet
|
||||||
|
already =tripsdate.get(date, 0) # returns zero if none found
|
||||||
|
tripsdate[date] = already +1
|
||||||
|
if not alphabet:
|
||||||
|
alphabet = list(string.ascii_lowercase)
|
||||||
|
|
||||||
|
tid = f"{date}{alphabet[already]}"
|
||||||
|
# print(tid)
|
||||||
|
return tid
|
||||||
|
|
||||||
rx_tripperson = re.compile(r"(?i)<u>(.*?)</u>$")
|
rx_tripperson = re.compile(r"(?i)<u>(.*?)</u>$")
|
||||||
rx_round_bracket = re.compile(r"[\(\[].*?[\)\]]")
|
rx_round_bracket = re.compile(r"[\(\[].*?[\)\]]")
|
||||||
|
|
||||||
@ -246,9 +268,14 @@ def store_entry_into_database(date, place, tripcave, title, text, trippersons, a
|
|||||||
"expedition": expedition,
|
"expedition": expedition,
|
||||||
"time_underground": logtime_underground,
|
"time_underground": logtime_underground,
|
||||||
"cave_slug": str(tripcave),
|
"cave_slug": str(tripcave),
|
||||||
"slug": tid,
|
|
||||||
}
|
}
|
||||||
lookupAttribs = {"date": date, "title": title}
|
lookupAttribs = {"slug": tid, "date": date, "title": title}
|
||||||
|
if LogbookEntry.objects.filter(slug=tid).exists():
|
||||||
|
# oops.
|
||||||
|
message = " ! - DUPLICATE SLUG for logbook entry " + tripdate + " - " + slug
|
||||||
|
DataIssue.objects.create(parser="logbooks", message=message)
|
||||||
|
slug = slug + "_" + unique_slug(text,2)
|
||||||
|
|
||||||
lbo = LogbookEntry.objects.create(**nonLookupAttribs, **lookupAttribs)
|
lbo = LogbookEntry.objects.create(**nonLookupAttribs, **lookupAttribs)
|
||||||
|
|
||||||
pt_list = []
|
pt_list = []
|
||||||
@ -332,7 +359,7 @@ def parser_html(year, expedition, txt, seq=""):
|
|||||||
logbook_entry_count = 0
|
logbook_entry_count = 0
|
||||||
for trippara in tripparas:
|
for trippara in tripparas:
|
||||||
logbook_entry_count += 1
|
logbook_entry_count += 1
|
||||||
tid = set_trip_id(year, logbook_entry_count)
|
tid = set_trip_seq_id(year, logbook_entry_count)
|
||||||
# print(f' - new tid:{tid} lbe count: {logbook_entry_count}')
|
# print(f' - new tid:{tid} lbe count: {logbook_entry_count}')
|
||||||
|
|
||||||
s = re.match(
|
s = re.match(
|
||||||
@ -376,6 +403,9 @@ def parser_html(year, expedition, txt, seq=""):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
ldate = parser_date(tripdate.strip(), year)
|
ldate = parser_date(tripdate.strip(), year)
|
||||||
|
|
||||||
|
# Now we have a date, we can reset tripid
|
||||||
|
tid = reset_trip_id(ldate)
|
||||||
triptitles = triptitle.split(" - ")
|
triptitles = triptitle.split(" - ")
|
||||||
if len(triptitles) >= 2:
|
if len(triptitles) >= 2:
|
||||||
place = triptitles[0]
|
place = triptitles[0]
|
||||||
@ -385,7 +415,7 @@ def parser_html(year, expedition, txt, seq=""):
|
|||||||
tripcontent = re.sub(r"<p>", "<br /><br />", tripcontent).strip()
|
tripcontent = re.sub(r"<p>", "<br /><br />", tripcontent).strip()
|
||||||
|
|
||||||
triptitle = triptitle.strip()
|
triptitle = triptitle.strip()
|
||||||
# triptitle must be unique for a given date. We fix this here.
|
# triptitle must be unique for a given date. We fix this here. [Why?!]
|
||||||
check = (ldate, triptitle)
|
check = (ldate, triptitle)
|
||||||
if check in dupl:
|
if check in dupl:
|
||||||
dupl[check] += 1
|
dupl[check] += 1
|
||||||
@ -458,7 +488,7 @@ def parser_blog(year, expedition, txt, sq=""):
|
|||||||
# print(f"{i} - {len(tripstuff)} - {tripstuff[1]}")
|
# print(f"{i} - {len(tripstuff)} - {tripstuff[1]}")
|
||||||
triphead = tripheads[i]
|
triphead = tripheads[i]
|
||||||
logbook_entry_count += 1
|
logbook_entry_count += 1
|
||||||
tid = set_trip_id(year, logbook_entry_count) + "_blog" + sq
|
tid = set_trip_seq_id(year, logbook_entry_count) + "_blog" + sq
|
||||||
# print(f" - tid: {tid}")
|
# print(f" - tid: {tid}")
|
||||||
|
|
||||||
# data-author="tcacrossley"
|
# data-author="tcacrossley"
|
||||||
@ -580,7 +610,7 @@ def parse_logbook_for_expedition(expedition, blog=False):
|
|||||||
if logbook_parseable:
|
if logbook_parseable:
|
||||||
# --------------------
|
# --------------------
|
||||||
parser = globals()[parsefunc]
|
parser = globals()[parsefunc]
|
||||||
print(f" - {year} parsing with {parsefunc} - {lb}")
|
# print(f" - {year} parsing with {parsefunc} - {lb}")
|
||||||
print(" .", end="")
|
print(" .", end="")
|
||||||
logentries = parser(year, expedition, txt, sq) # this launches the right parser
|
logentries = parser(year, expedition, txt, sq) # this launches the right parser
|
||||||
# --------------------
|
# --------------------
|
||||||
@ -595,7 +625,7 @@ def parse_logbook_for_expedition(expedition, blog=False):
|
|||||||
|
|
||||||
|
|
||||||
def LoadLogbook(year):
|
def LoadLogbook(year):
|
||||||
"""One off logbook for testing purposes, and also reloadable on '/expedition/2022?reload'
|
"""One off logbook for testing purposes, and also reloadable on '/expedition/2023?reload'
|
||||||
This is inside an atomic transaction"""
|
This is inside an atomic transaction"""
|
||||||
|
|
||||||
expo = Expedition.objects.get(year=year)
|
expo = Expedition.objects.get(year=year)
|
||||||
|
@ -14,7 +14,8 @@ maintain half a dozen parser functions.
|
|||||||
Sorry about all the crap that surrounds the image tags which has been imported along with the content
|
Sorry about all the crap that surrounds the image tags which has been imported along with the content
|
||||||
when UK Caving blogs have been parsed.
|
when UK Caving blogs have been parsed.
|
||||||
|
|
||||||
Exported on {% now 'Y-m-d H:m' %} using control panel webpage and exportlogbook() in troggle/code/views/other.py
|
Exported on {% now 'Y-m-d H:m' %} using either the control panel webpage or when editing a logbook entry online
|
||||||
|
See troggle/code/views/other.py and core.models/logbooks.py writelogbook(year, filename)
|
||||||
-->
|
-->
|
||||||
<body>
|
<body>
|
||||||
{%for logbook_entry in logbook_entries%}
|
{%for logbook_entry in logbook_entries%}
|
||||||
|
@ -79,9 +79,9 @@
|
|||||||
title="Time underground (hours)"
|
title="Time underground (hours)"
|
||||||
{% if tu %}value="{{tu}}"{% else %}placeholder="0.1" {% endif %}
|
{% if tu %}value="{{tu}}"{% else %}placeholder="0.1" {% endif %}
|
||||||
/>
|
/>
|
||||||
<br /><br /> <span style="color: red">This DOES NOT SAVE ANYTHING yet</span>
|
<br /><br />
|
||||||
<button class="fancybutton2" style="padding: 0.5em 25px; margin-left: 110px" type = "submit" value = "save" >
|
<button class="fancybutton2" style="padding: 0.5em 25px; margin-left: 110px" type = "submit" value = "save" >
|
||||||
Do logbook entry
|
Update logbook entry
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
3
urls.py
3
urls.py
@ -132,8 +132,7 @@ trogglepatterns = [
|
|||||||
re_path(r'^api/QMs_json$', QMs_jsonListView.as_view()),
|
re_path(r'^api/QMs_json$', QMs_jsonListView.as_view()),
|
||||||
|
|
||||||
# Logbook entries
|
# Logbook entries
|
||||||
re_path(r'^logbookentry/(?P<date>.*)/(?P<slug>.*)/?$', logbookentry,name="logbookentry"),
|
re_path(r'^logbookentry/(?P<date>.*)/(?P<slug>.*)/?$', logbookentry,name="logbookentry"),
|
||||||
re_path(r'^logbook(?P<year>\d\d\d\d)\.(?P<extension>.*)/?$', exportlogbook, name='exportlogbook'), # e.g. /logbook2019.html # working but old CSS in
|
|
||||||
re_path(r'^logbook$', exportlogbook, name='exportlogbook'),
|
re_path(r'^logbook$', exportlogbook, name='exportlogbook'),
|
||||||
|
|
||||||
# Internal. editfile.html template uses these internally
|
# Internal. editfile.html template uses these internally
|
||||||
|
Loading…
Reference in New Issue
Block a user