mirror of
https://expo.survex.com/repositories/troggle/.git
synced 2024-11-22 07:11:52 +00:00
Nicknames preserved, date checked
This commit is contained in:
parent
93397a774f
commit
d08a6aa204
@ -106,6 +106,7 @@ class PersonLogEntry(TroggleModel):
|
||||
time_underground = models.FloatField(help_text="In decimal hours")
|
||||
logbook_entry = models.ForeignKey(LogbookEntry, on_delete=models.CASCADE)
|
||||
is_logbook_entry_author = models.BooleanField(default=False)
|
||||
nickname_used = models.CharField(max_length=100,default="") # e.g. "Animal" or "Zonker", as it appears in the original logbook
|
||||
|
||||
class Meta:
|
||||
ordering = ("-personexpedition",)
|
||||
|
@ -17,7 +17,9 @@ and for persons: their individual pages and their perseonexpedition pages.
|
||||
It uses the global object TROG to hold some cached pages.
|
||||
"""
|
||||
|
||||
todo = """Fix the get_person_chronology() display bug.
|
||||
todo = """- Fix the get_person_chronology() display bug.
|
||||
|
||||
- Fix id= value preservation on editing
|
||||
"""
|
||||
|
||||
|
||||
@ -49,8 +51,9 @@ def expedition(request, expeditionname):
|
||||
"""Returns a rendered page for one expedition, specified by the year e.g. '2019'.
|
||||
If page caching is enabled, it caches the dictionaries used to render the template page.
|
||||
|
||||
This is not as difficult to understand as it looks. Yes there are many levels of indirection, with multiple trees being traversed at the same time. And the Django special syntax
|
||||
makes this hard for normal Python programmers.
|
||||
This is not as difficult to understand as it looks.
|
||||
Yes there are many levels of indirection, with multiple trees being traversed at the same time.
|
||||
And the Django special syntax makes this hard for normal Python programmers.
|
||||
|
||||
Remember that 'personexpedition__expedition' is interpreted by Django to mean the
|
||||
'expedition' object which is connected by a foreign key to the 'personexpedition'
|
||||
|
@ -1,5 +1,6 @@
|
||||
import subprocess
|
||||
import hashlib
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from django import forms
|
||||
@ -20,6 +21,11 @@ and that core/forms.py contains Django class-based forms for caves and entrances
|
||||
"""
|
||||
|
||||
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
|
||||
Validate image files using a magic recogniser in walletedit()
|
||||
https://pypi.org/project/reportlab/ or
|
||||
@ -62,15 +68,11 @@ class LogbookEditForm(forms.Form): # not a model-form, just a form-form
|
||||
@login_required_if_public
|
||||
def logbookedit(request, year=None, slug=None):
|
||||
"""Edit a logbook entry
|
||||
This is daft: we have the parsed identity of the person and we render it to text as 'fullname', to be re-parsed on re-importing.
|
||||
And there is no guarantee that this will be the same thing, esp. as aliases are used in the initial data input.
|
||||
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.
|
||||
And there is no guarantee that this will be the same thing.
|
||||
|
||||
So we are losing all the cute aliases that have been used over the years by this export/re-import process. Bother.
|
||||
But they have already been lost in the Great Format Conversion of 2022-23 when everything was chnaged to use the same HTML parser.
|
||||
Which is a shame.
|
||||
Fix is to add "alias_used" as a field in class PersonLogEntry, so that we can preserve
|
||||
all those cute names. But it's rather a large manual effort (with some scripting) to recover the aliases from the original logbook
|
||||
html files which are now only in the git history. Bother. Very sorry.
|
||||
Someone can put in a nickname which is invalid (e.g. 2 Sophies on expo). When is this checked?
|
||||
"""
|
||||
def clean_tu(tu):
|
||||
if tu =="":
|
||||
@ -89,12 +91,19 @@ def logbookedit(request, year=None, slug=None):
|
||||
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:
|
||||
year = 2023
|
||||
if not slug:
|
||||
year = 2023
|
||||
else:
|
||||
year = slug[0:4]
|
||||
print(year)
|
||||
|
||||
if request.method == "POST":
|
||||
form = LogbookEditForm(request.POST)
|
||||
@ -116,13 +125,26 @@ def logbookedit(request, year=None, slug=None):
|
||||
entry = entry.replace('<br>','<br />') # clean up previous hack
|
||||
tu = request.POST["tu"].strip()
|
||||
tu = clean_tu(tu)
|
||||
uniq = unique_id(entry,2)
|
||||
print(uniq)
|
||||
|
||||
try:
|
||||
odate = datetime.strptime(date.replace(".", "-"), "%Y-%m-%d").date()
|
||||
dateflag = False
|
||||
except:
|
||||
odate = datetime.strptime(f"{year}-01-01", "%Y-%m-%d").date()
|
||||
print(f"! Invalid date string {date}, setting to {odate}")
|
||||
dateflag = True
|
||||
date = odate.isoformat()
|
||||
|
||||
newslug = f"{date}_{unique_id(entry,2)}"
|
||||
if slug:
|
||||
if slug != newslug:
|
||||
print(f"! Entry id changed! from {slug} to {newslug}")
|
||||
|
||||
# OK this could be done by rendering a template, but for such a small bit of HTML, it is easier to have
|
||||
# it all in one place: here
|
||||
output = f'''
|
||||
<hr />
|
||||
<div class="tripdate" id="{date}-{uniq}">{date}</div>
|
||||
<div class="tripdate" id="{newslug}">{date}</div>
|
||||
<div class="trippeople"><u>{author}</u>, {others}</div>
|
||||
<div class="triptitle">{place} - {title}</div>
|
||||
{entry}
|
||||
@ -133,7 +155,7 @@ def logbookedit(request, year=None, slug=None):
|
||||
{
|
||||
"form": form,
|
||||
"year": year,
|
||||
"date": date,
|
||||
"date": date, "dateflag": dateflag,
|
||||
"author": author,
|
||||
"others": others,
|
||||
"place": place,
|
||||
@ -158,11 +180,13 @@ def logbookedit(request, year=None, slug=None):
|
||||
tu = clean_tu(lbe.time_underground)
|
||||
|
||||
people = []
|
||||
for p in lbe.personlogentry_set.filter(logbook_entry=lbe):
|
||||
for p in lbe.personlogentry_set.filter(logbook_entry=lbe): # p is a PersonLogEntry object
|
||||
if p.is_logbook_entry_author:
|
||||
author = p.personexpedition.person.fullname
|
||||
# author = p.personexpedition.person.fullname
|
||||
author = p.nickname_used
|
||||
else:
|
||||
people.append(p.personexpedition.person.fullname)
|
||||
# people.append(p.personexpedition.person.fullname)
|
||||
people.append(p.nickname_used)
|
||||
others =', '.join(people)
|
||||
lenothers = min(70,max(20, len(others)))
|
||||
print(f"{lenothers}")
|
||||
|
@ -22,6 +22,9 @@ Parses and imports logbooks in all their wonderful confusion
|
||||
https://expo.survex.com/handbook/computing/logbooks-parsing.html
|
||||
"""
|
||||
todo = """
|
||||
- make id= for each entry persistent and unchanging, and check cross-references in other logbooks and other HTML frahments
|
||||
e.g. cave descriptions
|
||||
|
||||
- Most of the time is during the database writing (6s out of 8s).
|
||||
|
||||
- profile the code to find bad repetitive things, of which there are many.
|
||||
@ -37,8 +40,7 @@ todo = """
|
||||
file_in = open(logbookfile,'rb')
|
||||
txt = file_in.read().decode("latin1")
|
||||
|
||||
- use Fixtures https://docs.djangoproject.com/en/dev/ref/django-admin/#django-admin-loaddata to cache
|
||||
data for old logbooks? Not worth it..
|
||||
|
||||
"""
|
||||
MAX_LOGBOOK_ENTRY_TITLE_LENGTH = 200
|
||||
BLOG_PARSER_SETTINGS = { # no default, must be explicit
|
||||
@ -127,7 +129,8 @@ def GetTripPersons(trippeople, expedition, logtime_underground, tid=None):
|
||||
if tripperson[0] != "*": # a name prefix of "*" is special
|
||||
tripperson = re.sub(rx_round_bracket, "", tripperson).strip()
|
||||
|
||||
# Whacky aliases all handled in GetPersonExpeditionNameLookup()
|
||||
# Whacky aliases all resolved in GetPersonExpeditionNameLookup()
|
||||
nickname_used = tripperson
|
||||
try:
|
||||
personyear = GetPersonExpeditionNameLookup(expedition).get(tripperson.lower())
|
||||
if not personyear:
|
||||
@ -138,9 +141,9 @@ def GetTripPersons(trippeople, expedition, logtime_underground, tid=None):
|
||||
message = f" ! - {expedition.year} No name match for: '{tripperson}' in entry {tid=} for this year."
|
||||
print(message)
|
||||
DataIssue.objects.create(parser="logbooks", message=message)
|
||||
res.append((personyear, logtime_underground))
|
||||
res.append((personyear, nickname_used, logtime_underground))
|
||||
except:
|
||||
message = f" ! - {expedition.year} EXCEPTION: '{tripperson}' in entry {tid=} for this year."
|
||||
message = f" ! - {expedition.year} EXCEPTION: '{tripperson}' ({nickname_used}) in entry {tid=} for this year."
|
||||
print(message)
|
||||
DataIssue.objects.create(parser="logbooks", message=message)
|
||||
raise
|
||||
@ -179,7 +182,7 @@ def tidy_time_underground(logtime_underground):
|
||||
def tidy_trip_persons(trippeople, title, expedition, logtime_underground, tid):
|
||||
try:
|
||||
trippersons, author = GetTripPersons(trippeople, expedition, logtime_underground, tid=tid)
|
||||
# print(f" - {author} - {logtime_underground}")
|
||||
# trippersons is a list of tuples (personyear, nickname_used, logtime_underground)
|
||||
except:
|
||||
message = f" ! - {expedition.year} Skipping logentry: {title} - GetTripPersons FAIL"
|
||||
DataIssue.objects.create(parser="logbooks", message=message)
|
||||
@ -247,14 +250,16 @@ def store_entry_into_database(date, place, tripcave, title, text, trippersons, a
|
||||
lbo = LogbookEntry.objects.create(**nonLookupAttribs, **lookupAttribs)
|
||||
|
||||
pt_list = []
|
||||
for tripperson, time_underground in trippersons:
|
||||
lookupAttribs = {"personexpedition": tripperson, "logbook_entry": lbo} # lbo is primary key
|
||||
for tripperson, nickname_used, time_underground in trippersons:
|
||||
lookupAttribs = {"personexpedition": tripperson, "nickname_used": nickname_used, "logbook_entry": lbo} # lbo is primary key
|
||||
nonLookupAttribs = {"time_underground": time_underground, "is_logbook_entry_author": (tripperson == author)}
|
||||
pt_list.append(PersonLogEntry(**nonLookupAttribs, **lookupAttribs))
|
||||
PersonLogEntry.objects.bulk_create(pt_list)
|
||||
|
||||
def parser_date(tripdate, year):
|
||||
"""Interprets dates in the expo logbooks and returns a correct datetime.date object"""
|
||||
"""Interprets dates in the expo logbooks and returns a correct datetime.date object
|
||||
Does NOT actually check that it is a truly valid date..
|
||||
"""
|
||||
dummydate = date(1970, 1, 1) # replace with _EPOCH
|
||||
month = 1
|
||||
day = 1
|
||||
|
@ -27,6 +27,12 @@
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<style>
|
||||
th, td {
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
</style>
|
||||
<table class="cavers">
|
||||
<tr><th>Caver</th><th>T/U</th><th>Prev</th><th>Next</th></tr>
|
||||
{% for personlogentry in logbookentry.personlogentry_set.all %}
|
||||
@ -36,7 +42,7 @@
|
||||
{% else %}
|
||||
<td>
|
||||
{% endif %}
|
||||
<a href="{{ personlogentry.personexpedition.get_absolute_url }}">{{personlogentry.personexpedition.person}}</a>
|
||||
<a href="{{ personlogentry.personexpedition.get_absolute_url }}">{{personlogentry.nickname_used}} ({{personlogentry.personexpedition.person}})</a>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@ -64,7 +70,7 @@
|
||||
<div id="col1">
|
||||
<div class="logbookentry">
|
||||
<b>{{logbookentry.date|date:"D d M Y"}}</b>
|
||||
{% for personlogentry in logbookentry.personlogentry_set.all %}{% if personlogentry.is_logbook_entry_author %}<br />{{personlogentry.personexpedition.person}}{% endif %}{% endfor %}
|
||||
{% for personlogentry in logbookentry.personlogentry_set.all %}{% if personlogentry.is_logbook_entry_author %}<br />{{personlogentry.nickname_used}} {% endif %}{% endfor %}
|
||||
<p>{{logbookentry.text|safe}}</p>
|
||||
</div>
|
||||
<p><a href="/logbookedit/{{logbookentry.slug|safe}}">Edit this entry</a>.
|
||||
|
@ -4,8 +4,11 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if date %}
|
||||
<h2>Edit Logbook Entry on {{date}}</h2>
|
||||
{% else %}
|
||||
<h2>New Logbook Entry in {{year}}</h2>
|
||||
|
||||
{% endif %}
|
||||
{% if save_bad %}
|
||||
<p style="font-family: monospace; font-weight: bold; color: red; font-size: 130%; text-align: center">
|
||||
|
||||
@ -24,12 +27,15 @@
|
||||
{% csrf_token %}
|
||||
<br />
|
||||
|
||||
<span {% if dateflag %}style="color:red"{% endif %}>
|
||||
<label for="date">Date of the activity</label>
|
||||
<input {% if not user.username %} disabled{% endif %}
|
||||
label = "Date" name = "date" size="12"
|
||||
title="Date of the activity, a single day, in ISO format: 2020-08-17"
|
||||
{% if date %}value="{{date}}"{% else %}placeholder="2023-08-12"{% endif %}
|
||||
{% if date %}value="{{date}}"{% else %}placeholder="2023-08-12"{% endif %}
|
||||
required />
|
||||
</span>
|
||||
|
||||
<br /><br />
|
||||
<label for="author">Your name (author) <a href="/aliases/{{year}}">[valid authors]</a></label>
|
||||
<input {% if not user.username %} disabled{% endif %}
|
||||
|
Loading…
Reference in New Issue
Block a user