2
0
mirror of https://expo.survex.com/repositories/troggle/.git synced 2024-11-25 08:41:51 +00:00

make ?reload private and clean old error msgs

This commit is contained in:
Philip Sargent 2021-04-23 03:07:21 +01:00
parent 1a4be0f02e
commit dbd186e299
10 changed files with 172 additions and 85 deletions

View File

@ -6,20 +6,29 @@ from django.conf import settings
from troggle.core.models.caves import LogbookEntry, QM, Cave from troggle.core.models.caves import LogbookEntry, QM, Cave
import re, urllib.parse import re, urllib.parse
register = template.Library() '''Several templates are still (2021) using these filters extensively to process data
'''Several templates are still (2021) using these wiki filters extensively to process data extracted from the database, extracted from the database, and to restructure values into valid URLs to go elsewhere in the
and to restructure values into valid URLs to go elsewhere in the system, even where these are not actually 'wiki'. See system, even where these are not actually 'wiki'. See the regexes at the end of this file.
the regexes at the end of this file.
So the data in the database needs to be checked that there is no wiki-format content before these are deleted, and the
filter functions of these regexes needs to be explored in practice.
''' '''
todo = '''The data in the database and all input files
needs to be checked that there is no wiki-format content before all the functions in this
file are deleted, and the filter functions of these regexes and functions, particularly
wiki_to_html() which is used dozens of times in the templates, needs to be explored in
practice before being renamed more appropriately.
'''
register = template.Library()
@register.filter() @register.filter()
def plusone(n): def plusone(n):
'''used in templates/svxcaveseveral.html and templates/svxcavessingle.html for formatting
'''
return n + 1 return n + 1
def wiki_list(line, listdepth): def wiki_list(line, listdepth):
'''Does not seem to be used anywhere except photoSrcRepl() below'''
l = "" l = ""
for d in listdepth: for d in listdepth:
l += d l += d
@ -50,6 +59,9 @@ def wiki_to_html(value, autoescape=None):
""" """
This is the tag which turns wiki syntax into html. It is intended for long pieces of wiki. This is the tag which turns wiki syntax into html. It is intended for long pieces of wiki.
Hence it splits the wiki into HTML paragraphs based on double line feeds. Hence it splits the wiki into HTML paragraphs based on double line feeds.
But it is used as a filter when rendering many, many fields, e.g.
epersonexpedition.person|wiki_to_html_short in presonexpedition.html
""" """
#find paragraphs #find paragraphs
outValue = "" outValue = ""
@ -65,6 +77,10 @@ def wiki_to_html_short(value, autoescape=None):
""" """
This is the tag which turns wiki syntax into html. It is intended for short pieces of wiki. This is the tag which turns wiki syntax into html. It is intended for short pieces of wiki.
Hence it is not split the wiki into paragraphs using where it finds double line feeds. Hence it is not split the wiki into paragraphs using where it finds double line feeds.
But it is used as a filter when rendering many, many fields, e.g.
entrance.entrance_description|wiki_to_html in extrance.html
""" """
if autoescape: if autoescape:
value = conditional_escape(value) value = conditional_escape(value)
@ -120,6 +136,7 @@ def wiki_to_html_short(value, autoescape=None):
photoLinkPattern="\[\[\s*photo:(?P<photoName>[^\s]+)\s*(?P<linkText>.*)\]\]" photoLinkPattern="\[\[\s*photo:(?P<photoName>[^\s]+)\s*(?P<linkText>.*)\]\]"
photoSrcPattern="\[\[\s*display:(?P<style>[^\s]+) photo:(?P<photoName>[^\s]+)\s*\]\]" photoSrcPattern="\[\[\s*display:(?P<style>[^\s]+) photo:(?P<photoName>[^\s]+)\s*\]\]"
def photoLinkRepl(matchobj): def photoLinkRepl(matchobj):
'''Does not seem to be used anywhere except photoSrcRepl() below'''
matchdict=matchobj.groupdict() matchdict=matchobj.groupdict()
try: try:
linkText=matchdict['linkText'] linkText=matchdict['linkText']
@ -136,6 +153,7 @@ def wiki_to_html_short(value, autoescape=None):
return res return res
def photoSrcRepl(matchobj): def photoSrcRepl(matchobj):
'''Does not seem to be used anywhere'''
matchdict=matchobj.groupdict() matchdict=matchobj.groupdict()
style=matchdict['style'] style=matchdict['style']
try: try:

View File

@ -57,9 +57,22 @@ def expedition(request, expeditionname):
By specifying a '0' for the expected number of entries in the logbook cache, this forces the parser to By specifying a '0' for the expected number of entries in the logbook cache, this forces the parser to
re-parse the original logbook HTML file. re-parse the original logbook HTML file.
''' '''
if "reload" in request.GET: if request.user.is_authenticated:
this_expedition = Expedition.objects.get(year=int(expeditionname)) if "reload" in request.GET:
LoadLogbookForExpedition(this_expedition, 0) # 0 means re-parse this_expedition = Expedition.objects.get(year=int(expeditionname))
# Need to delete the exisitng entries or we get duplicaiton
entries = this_expedition.logbookentry_set.all()
print(f'! - expo {expeditionname} {len(entries)} entries')
for entry in entries:
print(f'! - delete entry: "{entry}"')
entry.delete()
entries = this_expedition.logbookentry_set.all()
print(f'! - expo {expeditionname} {len(entries)} entries')
LoadLogbookForExpedition(this_expedition, 0) # 0 means re-parse
logged_in = True
else:
logged_in = False
ts = TROG['pagecache']['expedition'] ts = TROG['pagecache']['expedition']
if settings.CACHEDPAGES: if settings.CACHEDPAGES:
@ -67,7 +80,7 @@ def expedition(request, expeditionname):
#print(f'! - expo {expeditionname} CACHEDPAGES {nexpos} expo pages in cache.') #print(f'! - expo {expeditionname} CACHEDPAGES {nexpos} expo pages in cache.')
if expeditionname in ts: if expeditionname in ts:
#print('! - expo {expeditionanme} using cached page') #print('! - expo {expeditionanme} using cached page')
return render(request,'expedition.html', ts[expeditionname] ) return render(request,'expedition.html', { **ts[expeditionname], 'logged_in' : logged_in })
this_expedition = Expedition.objects.get(year=int(expeditionname)) this_expedition = Expedition.objects.get(year=int(expeditionname))
@ -88,11 +101,11 @@ def expedition(request, expeditionname):
ts[expeditionname] = {'expedition': this_expedition, 'expeditions':expeditions, ts[expeditionname] = {'expedition': this_expedition, 'expeditions':expeditions,
'personexpeditiondays':personexpeditiondays, 'settings':settings, 'personexpeditiondays':personexpeditiondays, 'settings':settings,
'dateditems': dateditems } 'dateditems': dateditems}
TROG['pagecache']['expedition'][expeditionname] = ts[expeditionname] TROG['pagecache']['expedition'][expeditionname] = ts[expeditionname]
nexpos = len( TROG['pagecache']['expedition']) nexpos = len( TROG['pagecache']['expedition'])
#print(f'! - expo {expeditionname} pre-render N expos:{nexpos}') #print(f'! - expo {expeditionname} pre-render N expos:{nexpos}')
return render(request,'expedition.html', ts[expeditionname] ) return render(request,'expedition.html', { **ts[expeditionname], 'logged_in' : logged_in } )
# def get_absolute_url(self): # seems to have come seriously adrift. This should be in a class?! # def get_absolute_url(self): # seems to have come seriously adrift. This should be in a class?!

View File

@ -41,11 +41,15 @@ def todos(request, module):
''' '''
from troggle.core.TESTS.tests import todo as tests from troggle.core.TESTS.tests import todo as tests
from troggle.core.views.logbooks import todo as viewlogbooks from troggle.core.views.logbooks import todo as viewlogbooks
from troggle.parsers.logbooks import todo as parserslogbooks
from troggle.core.forms import todo as forms from troggle.core.forms import todo as forms
from troggle.core.templatetags.wiki_markup import todo as wiki
tododict = {'views/other': todo, tododict = {'views/other': todo,
'tests': tests, 'tests': tests,
'views/logbooks': viewlogbooks, 'views/logbooks': viewlogbooks,
'core/forms': forms} 'parsers/logbooks': parserslogbooks,
'core/forms': forms,
'core/templatetags/wiki_markup': wiki}
return render(request,'core/todos.html', {'tododict': tododict}) return render(request,'core/todos.html', {'tododict': tododict})
def troggle404(request): # cannot get this to work. Handler404 in urls.py not right syntax def troggle404(request): # cannot get this to work. Handler404 in urls.py not right syntax
@ -215,25 +219,25 @@ def newfile(request, pslug = None):
return render(request, 'editfile.html', {'fileForm': fileform, }) return render(request, 'editfile.html', {'fileForm': fileform, })
@login_required_if_public @login_required_if_public
def simpleupload(request): def scanupload(request, year='2050'):
print(f'! - FORM simpleupload - start') print(f'! - FORM scanupload - start')
if request.method == 'POST': if request.method == 'POST':
form = SimpleUploadFileForm(request.POST,request.FILES) form = SimpleUploadFileForm(request.POST,request.FILES)
if form.is_valid(): if form.is_valid():
#form.save() # comment out so nothing saved in MEDIA_ROOT/fileuploads #form.save() # comment out so nothing saved in MEDIA_ROOT/fileuploads
f = request.FILES["simplefile"] f = request.FILES["simplefile"]
w = request.POST["title"] w = request.POST["title"]
print(f'! - FORM simpleupload uploaded {f.name}') print(f'! - FORM scanupload uploaded {f.name}')
fs = FileSystemStorage(os.path.join(settings.SURVEY_SCANS, '2021', w)) fs = FileSystemStorage(os.path.join(settings.SURVEY_SCANS, year, w))
actual_saved = fs.save(f.name, content=f) # name may chnage to avoid clash actual_saved = fs.save(f.name, content=f) # name may chnage to avoid clash
# INSERT check if name is chnaged, to allow user to abort and rename - or lets do a chaecjk anyway. # INSERT check if name is changed, to allow user to abort and rename - or lets do a chaecjk anyway.
print(f'! - FORM simpleupload {actual_saved}') print(f'! - FORM scanupload {actual_saved}')
form = SimpleUploadFileForm() form = SimpleUploadFileForm()
return render(request, 'simpleupload.html', {'form': form,'filesaved': True, 'actual_saved': actual_saved}) return render(request, 'scanuploadform.html', {'form': form,'filesaved': True, 'actual_saved': actual_saved})
else: else:
form = SimpleUploadFileForm() form = SimpleUploadFileForm()
return render(request, 'simpleupload.html', {'form':form,}) return render(request, 'scanuploadform.html', {'form':form,})

View File

@ -21,6 +21,39 @@ Parses and imports logbooks in all their wonderful confusion
# When we edit logbook entries, allow a "?" after any piece of data to say we've frigged it and # When we edit logbook entries, allow a "?" after any piece of data to say we've frigged it and
# it can be checked up later from the hard-copy if necessary; or it's not possible to determin (name, trip place, etc) # it can be checked up later from the hard-copy if necessary; or it's not possible to determin (name, trip place, etc)
''' '''
todo='''
- Put the object store 'trips' and the 'logdataissues' into TROG global object
- refactor everything with some urgency, esp. LoadLogbookForExpedition()
- delete all the autoLogbooKEntry stuff when we are absolutely certain what it does
- Logbooks log.htm exist for 1983, 84, 85, 87, 88, 89 but have no full-working parser,
or it is broken/incomplete and need hand-editing.
- import/parse/re-export-as-html the 'artisanal-format' old logbooks so that
we keep only a modern HTML05 format. Then we can retiure the old parsers and reduce the
volume of code here substantially.
- edit LoadLogbooks() to use coroutines to speed up import substantially,
but perhaps we had better profile it first?
- rewrite to use generators rather than storing everything intermediate in lists - to reduce memory impact.
- the object store will need additional functions to replicate the persontrip calculation
and storage. For the moment we leave all that to be done in the django db
- We should ensure logbook.html is utf-8 and stop this crap:
file_in = open(logbookfile,'rb')
txt = file_in.read().decode("latin1")
'''
logentries = [] # the entire logbook for one year is a single object: a list of entries
noncaveplaces = [ "QMplaceholder", "Journey", "Loser Plateau", "UNKNOWN", 'plateau',
'base camp', 'basecamp', 'top camp', 'topcamp' ]
logdataissues = {}
trips ={}
# #
# the logbook loading section # the logbook loading section
@ -77,12 +110,6 @@ def GetTripCave(place):
return None return None
logentries = [] # the entire logbook for one year is a single object: a list of entries
noncaveplaces = [ "QMplaceholder", "Journey", "Loser Plateau", "UNKNOWN", 'plateau',
'base camp', 'basecamp', 'top camp', 'topcamp' ]
logdataissues = {}
trips ={}
def EnterLogIntoDbase(date, place, title, text, trippeople, expedition, logtime_underground, entry_type="wiki"): def EnterLogIntoDbase(date, place, title, text, trippeople, expedition, logtime_underground, entry_type="wiki"):
""" saves a logbook entry and related persontrips """ saves a logbook entry and related persontrips
Does NOT save the expeditionday_id - all NULLs. why? Does NOT save the expeditionday_id - all NULLs. why?
@ -205,8 +232,10 @@ def EnterLogIntoObjStore(year, date, tripcave, triptitle, text, trippeople, tu,
#print(" - New id ",tid) #print(" - New id ",tid)
else: else:
tid= tripid1 tid= tripid1
if tid in trips: if tid in trips:
msg = " ! DUPLICATE id .{}. {} ~{}~".format(tid, trips[tid][0], trips[tid][1]) tyear, tdate, *trest = trips[tid]
msg = f" ! DUPLICATE on {tdate} id: '{tid}'"
print(msg) print(msg)
DataIssue.objects.create(parser='logbooks', message=msg) DataIssue.objects.create(parser='logbooks', message=msg)
tid= "d{}-s{:02d}".format(str(date),seq) tid= "d{}-s{:02d}".format(str(date),seq)
@ -427,6 +456,7 @@ def LoadLogbookForExpedition(expedition, expect):
""" """
# absolutely horrid. REFACTOR THIS (all my fault..) # absolutely horrid. REFACTOR THIS (all my fault..)
global logentries global logentries
global logdataissues
logbook_parseable = False logbook_parseable = False
logbook_cached = False logbook_cached = False
yearlinks = settings.LOGBOOK_PARSER_SETTINGS yearlinks = settings.LOGBOOK_PARSER_SETTINGS
@ -445,6 +475,26 @@ def LoadLogbookForExpedition(expedition, expect):
return False return False
return True return True
def cleanerrors(year):
global logdataissues
print(f' - CLEAN {year} {len(logdataissues)} data issues in total')
dataissues = DataIssue.objects.filter(parser='logbooks')
for di in dataissues:
ph = "t" + year + "-"
if re.search(ph, di.message) is not None:
print(f' - CLEANING dataissue {di.message}')
di.delete()
for te, content in logdataissues:
# tripentry = year + "." + str(logbook_entry_count)
print(f' - CLEAN {te}')
if te.startswith(year + "."):
print(f' - CLEANING logdataissue {te}')
logdataissues.pop(te)
cleanerrors(expedition.year)
if expedition.year in yearlinks: if expedition.year in yearlinks:
logbookfile = os.path.join(expologbase, yearlinks[expedition.year][0]) logbookfile = os.path.join(expologbase, yearlinks[expedition.year][0])
expedition.logbookfile = yearlinks[expedition.year][0] expedition.logbookfile = yearlinks[expedition.year][0]
@ -478,10 +528,10 @@ def LoadLogbookForExpedition(expedition, expect):
print(" -- Loaded ", len(logentries), " log entries") print(" -- Loaded ", len(logentries), " log entries")
logbook_cached = True logbook_cached = True
else: else:
print(" !- Should be ", expect, " but ", len(logentries), " found in cache") print(" !- Told to expect ", expect, " but ", len(logentries), " found in cache")
raise raise
except: except:
print(" ! Failed to load corrupt cache. Deleting it.") print(" ! Failed to load corrupt cache. (Or I was told to ignore it). Deleting it.")
os.remove(cache_filename) os.remove(cache_filename)
logentries=[] logentries=[]
raise raise
@ -554,7 +604,7 @@ def LoadLogbooks():
TROG['pagecache']['expedition'][expo.year] = None # clear cache TROG['pagecache']['expedition'][expo.year] = None # clear cache
if expo.year not in nologbook: if expo.year not in nologbook:
print((" - Logbook for: " + expo.year)) print((" - Logbook for: " + expo.year))
numentries = LoadLogbookForExpedition(expo, entries[expo.year]) numentries = LoadLogbookForExpedition(expo, entries[expo.year]) # this actually loads the logbook for one year
log.write("{} {:5d} should be {}\n".format(expo.year, numentries, entries[expo.year])) log.write("{} {:5d} should be {}\n".format(expo.year, numentries, entries[expo.year]))
nlbe[expo.year]=numentries nlbe[expo.year]=numentries
expd[expo.year]= 0 expd[expo.year]= 0
@ -588,6 +638,12 @@ locationRegex = re.compile(r'<span\s+class="location">(.*?)</span>', re.S)
caveRegex = re.compile(r'<span\s+class="cave">(.*?)</span>', re.S) caveRegex = re.compile(r'<span\s+class="cave">(.*?)</span>', re.S)
def parseAutoLogBookEntry(filename): def parseAutoLogBookEntry(filename):
'''An AutoLogBookEntry appears to be one that was created online using a form, for a single trip,
which is then stored in a separate location to the usual logbook.html
But when importing logbook.html all these individual entries also need ot be parsed.
This is all redundant as we are getting rid of the whole individual trip entry system
'''
errors = [] errors = []
f = open(filename, "r") f = open(filename, "r")
contents = f.read() contents = f.read()

View File

@ -1,3 +1,3 @@
{% extends "baseapi.html" %} {% extends "baseapi.html" %}
{% block content %}<pre>{% for k, v in tododict.items %}<b><big>{{k}}</big></b>: {{v}}<br /> {% block content %}<pre>{% for k, v in tododict.items %}<b><big>{{k}}</big></b>:<br> {{v}}<br />
{% endfor %}</pre>{% endblock %} {% endfor %}</pre>{% endblock %}

View File

@ -20,7 +20,9 @@
{% endfor %} {% endfor %}
</p> </p>
<p>See also the <a href="/years/{{expedition.year}}/">documentation index</a> for this Expo <p>See also the <a href="/years/{{expedition.year}}/">documentation index</a> for this Expo
{% if logged_in %}
<p>Reparse and reload this year's logbook by clicking here: <a href="/expedition/{{expedition.year}}?reload">RELOAD</a> <p>Reparse and reload this year's logbook by clicking here: <a href="/expedition/{{expedition.year}}?reload">RELOAD</a>
{% endif %}
<p><b>At a single glance:</b> The table shows all expo cavers and their recorded trips. <p><b>At a single glance:</b> The table shows all expo cavers and their recorded trips.
The columns are the date in the month (July or August), with a "T" for a logbook entry, and The columns are the date in the month (July or August), with a "T" for a logbook entry, and
@ -60,7 +62,9 @@ an "S" for a survey trip. The colours are the same for people on the same trip.
{% endfor %} {% endfor %}
</table> </table>
<form action="" method="GET"><input type="submit" name="reload" value="Reload"></form> {% if logged_in %}
<form action="" method="GET"><input type="submit" name="reload" value="Reload from logbook"></form>
{% endif %}
<h3>Logbooks and survey trips per day</h3> <h3>Logbooks and survey trips per day</h3>

View File

@ -0,0 +1,42 @@
{% extends "base.html" %}
{% block title %}Simple Fileupload{% endblock %}
{% block content %}
<h2>Survey Scan upload into Wallet</h2>
<div style="column-count: 2;">
<div style = "max-width:40%px; " >
{% if filesaved %}
<p style="margin-left:20%;">
<b>The file was saved as <em>'{{actual_saved}}'</em> <br><br>Upload another?</b>
</p>
<br>
{% endif %}
<form method ='post' enctype ="multipart/form-data">
{% csrf_token %}
<br>
<input type = "file" style = "margin-left:20%;"
placeholder = "Simplefile" name = "simplefile" id="files"><label for="files">Scan file(s)</label>
<br> <br>
<input type = "text" style = "margin-left:20%;"
placeholder = "Wallet id e.g. 2021#23" name = "title" value='2050#99'id="wallet"><label for="wallet"> Wallet id</label>
</div>
<div style = "max-width:30%;">
<center>
<button style = "color: #fff; border:1px; background-color:#999; margin-top:8%;
height:35px; width:80%; margin-left:19%;" type = "submit" value = "Upload" >
<strong>Upload</strong>
</button>
</center>
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -1,50 +0,0 @@
{% extends "base.html" %}
{% block title %}Simple Fileupload{% endblock %}
{% block content %}
<h2>Survey Scan upload into Wallet</h2>
<div style = "max-width:470px; " >
{% if filesaved %}
<p style="margin-left:20%;">
<b>The file was saved as <em>'{{actual_saved}}'</em> <br><br>Upload another?</b>
</p>
<br>
{% endif %}
<form method ='post' enctype ="multipart/form-data">
{% csrf_token %}
<br>
<input type = "file" style = "margin-left:20%;"
placeholder = "Simplefile" name = "simplefile" />
<br> <br>
<input type = "text" style = "margin-left:20%;"
placeholder = "Wallet id e.g. 2021#23" name = "title" value='2021#99' label="Wallet id"/>
</div>
<div style = "max-width:470px;">
<center>
<button style = "color: #fff; border:1px; background-color:#999; margin-top:8%;
height:35px; width:80%; margin-left:19%;" type = "submit" value = "Upload" >
<strong>Upload</strong>
</button>
</center>
</div>
</form>
</div>
{% endblock %}

View File

@ -10,7 +10,7 @@ from django.urls import reverse, resolve
from troggle.core.views import caves, statistics, survex from troggle.core.views import caves, statistics, survex
from troggle.core.views.surveys import surveyscansingle, surveyscansfolder, surveyscansfolders, dwgdata, dwgfilesingle, dwgfileupload from troggle.core.views.surveys import surveyscansingle, surveyscansfolder, surveyscansfolders, dwgdata, dwgfilesingle, dwgfileupload
from troggle.core.views.other import troggle404, frontpage, todos, controlpanel, frontpage, newfile, simpleupload from troggle.core.views.other import troggle404, frontpage, todos, controlpanel, frontpage, newfile, scanupload
from troggle.core.views.other import downloadlogbook, ajax_QM_number, downloadQMs from troggle.core.views.other import downloadlogbook, ajax_QM_number, downloadQMs
from troggle.core.views.caves import ent, cavepage from troggle.core.views.caves import ent, cavepage
from troggle.core.views.logbooks import get_logbook_entries, logbookentry, logbookSearch from troggle.core.views.logbooks import get_logbook_entries, logbookentry, logbookSearch
@ -75,7 +75,7 @@ trogglepatterns = [
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 re_path(r'^admin/', admin.site.urls), # includes admin login & logout urls
path('upload', simpleupload, name='simpleupload'), # includes admin login & logout urls path('scanupload', scanupload, name='scanupload'),
# setting LOGIN_URL = '/accounts/login/' is default # setting LOGIN_URL = '/accounts/login/' is default
# url ENDS WITH this string # url ENDS WITH this string