2
0
mirror of https://expo.survex.com/repositories/troggle/.git synced 2024-11-26 01:01:53 +00:00

Edit Logbook Entry mostly working

This commit is contained in:
Philip Sargent 2023-08-31 18:55:20 +03:00
parent bbb821e2f9
commit c29c12ea76
7 changed files with 276 additions and 100 deletions

View File

@ -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,6 +96,46 @@ 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.

View File

@ -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(

View File

@ -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 =="":
@ -83,27 +163,13 @@ def logbookedit(request, year=None, slug=None):
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,6 +178,8 @@ 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
@ -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()
# OK this could be done by rendering a template, but for such a small bit of HTML, it is easier to have print(f"- Creating the LogBookEntry {slug}")
# it all in one place: here 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})
# Code fragment illustration - not actually what gets saved to database
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",

View File

@ -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)

View File

@ -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%}

View File

@ -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>

View File

@ -133,7 +133,6 @@ trogglepatterns = [
# 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