2020-05-28 04:54:53 +01:00
import datetime
import os . path
import re
2023-01-19 18:35:56 +00:00
import time
2020-05-28 04:54:53 +01:00
2011-07-11 02:10:22 +01:00
import django . db . models
2023-01-19 18:35:56 +00:00
from django . db . models import Max , Min
2020-05-28 04:54:53 +01:00
from django . http import HttpResponse , HttpResponseRedirect
2021-03-28 03:48:24 +01:00
from django . shortcuts import render
2011-07-11 02:10:22 +01:00
from django . template import Context , loader
from django . template . defaultfilters import slugify
2023-01-19 18:35:56 +00:00
from django . urls import reverse
2019-02-24 13:03:34 +00:00
from django . utils import timezone
2020-05-28 04:54:53 +01:00
from django . views . generic . list import ListView
2011-07-11 02:10:22 +01:00
2023-01-19 18:35:56 +00:00
import troggle . settings as settings
2023-01-30 16:18:19 +00:00
from troggle . core . models . logbooks import LogbookEntry , PersonLogEntry
2023-01-29 20:59:56 +00:00
from troggle . core . models . survex import SurvexBlock
2023-01-19 18:35:56 +00:00
from troggle . core . models . troggle import Expedition , Person , PersonExpedition
2023-01-29 21:45:51 +00:00
from troggle . core . models . wallets import Wallet
2023-01-19 18:35:56 +00:00
from troggle . core . utils import TROG
2023-01-27 23:21:07 +00:00
from troggle . parsers . imports import import_logbook
2020-05-28 04:54:53 +01:00
from troggle . parsers . people import GetPersonExpeditionNameLookup
2023-01-19 18:35:56 +00:00
from . auth import login_required_if_public
2019-02-24 13:03:34 +00:00
2021-04-10 01:07:49 +01:00
''' These views are for logbook items when they appear in an ' expedition ' page
and for persons : their individual pages and their perseonexpedition pages .
It uses the global object TROG to hold some cached pages .
'''
2011-07-11 02:10:22 +01:00
2021-04-21 19:08:42 +01:00
todo = ''' Fix the get_person_chronology() display bug.
'''
2021-04-30 21:32:53 +01:00
def notablepersons ( request ) :
2022-04-23 20:42:46 +01:00
def notabilitykey ( person ) :
return person . notability ( )
2011-07-11 02:10:22 +01:00
persons = Person . objects . all ( )
2021-04-15 17:51:01 +01:00
# From what I can tell, "persons" seems to be the table rows, while "pcols" is the table columns. - AC 16 Feb 09
pcols = [ ]
2011-07-11 02:10:22 +01:00
ncols = 4
2020-05-31 22:35:36 +01:00
nc = int ( ( len ( persons ) + ncols - 1 ) / ncols )
2011-07-11 02:10:22 +01:00
for i in range ( ncols ) :
2021-04-15 17:51:01 +01:00
pcols . append ( persons [ i * nc : ( i + 1 ) * nc ] )
2011-07-11 02:10:22 +01:00
notablepersons = [ ]
2022-04-23 20:42:46 +01:00
# Needed recoding because of Django CVE-2021-45116
for person in persons :
if person . bisnotable ( ) :
notablepersons . append ( person )
notablepersons . sort ( key = notabilitykey , reverse = True )
2011-07-11 02:10:22 +01:00
2021-04-30 21:32:53 +01:00
return render ( request , ' notablepersons.html ' , { ' persons ' : persons , ' pcols ' : pcols , ' notablepersons ' : notablepersons } )
2011-07-11 02:10:22 +01:00
def expedition ( request , expeditionname ) :
2021-04-10 01:07:49 +01:00
''' 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 .
2023-01-30 15:28:11 +00:00
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 '
2023-01-30 16:18:19 +00:00
object , which is a field of the PersonLogEntry object :
PersonLogEntry . objects . filter ( personexpedition__expedition = expo )
2023-01-30 15:28:11 +00:00
Queries are not evaluated to hit the database until a result is actually used . Django
does lazy evaluation .
2021-04-10 01:07:49 +01:00
'''
2023-01-30 15:28:11 +00:00
try :
expo = Expedition . objects . get ( year = int ( expeditionname ) )
except :
message = f ' Expedition not found - database apparently empty, you probably need to do a full re-import of all data. '
return render ( request , ' errors/generic.html ' , { ' message ' : message } )
2021-04-23 03:07:21 +01:00
if request . user . is_authenticated :
logged_in = True
2023-01-30 15:28:11 +00:00
if " reload " in request . GET :
expo . logbookentry_set . all ( ) . delete ( )
import_logbook ( year = expo . year )
2021-04-23 03:07:21 +01:00
else :
logged_in = False
2021-04-10 01:07:49 +01:00
2023-01-29 22:11:00 +00:00
ts = TROG [ ' pagecache ' ] [ ' expedition ' ] # not much use unless single user!
2021-04-10 01:07:49 +01:00
if settings . CACHEDPAGES :
nexpos = len ( TROG [ ' pagecache ' ] [ ' expedition ' ] )
#print(f'! - expo {expeditionname} CACHEDPAGES {nexpos} expo pages in cache.')
if expeditionname in ts :
#print('! - expo {expeditionanme} using cached page')
2021-04-23 03:07:21 +01:00
return render ( request , ' expedition.html ' , { * * ts [ expeditionname ] , ' logged_in ' : logged_in } )
2021-04-10 01:07:49 +01:00
2023-01-30 15:28:11 +00:00
expeditions = Expedition . objects . all ( ) # top menu only, evaluated only when template renders
entries = expo . logbookentry_set . all ( )
blocks = expo . survexblock_set . all ( )
dateditems = list ( entries ) + list ( blocks ) # evaluates the Django query and hits db
2020-05-24 01:57:06 +01:00
dates = sorted ( set ( [ item . date for item in dateditems ] ) )
2023-01-30 15:28:11 +00:00
2023-01-30 16:18:19 +00:00
allpersonlogentries = PersonLogEntry . objects . filter ( personexpedition__expedition = expo )
2023-01-30 15:28:11 +00:00
personexpeditiondays = [ ]
for personexpedition in expo . personexpedition_set . all ( ) :
2023-01-30 16:07:44 +00:00
expotrips = allpersonlogentries . filter ( personexpedition = personexpedition ) # lazy
2023-01-30 15:28:11 +00:00
expoblocks = blocks . filter ( survexpersonrole__personexpedition = personexpedition )
2011-07-11 02:10:22 +01:00
prow = [ ]
2023-01-30 15:28:11 +00:00
2011-07-11 02:10:22 +01:00
for date in dates :
2023-01-30 15:28:11 +00:00
personentries = expotrips . filter ( logbook_entry__date = date ) # lazy
personblocks = set ( expoblocks . filter ( date = date ) ) # not lazy
pcell = { }
pcell [ " personentries " ] = personentries
pcell [ " survexblocks " ] = personblocks
if issunday := ( date . weekday ( ) == 6 ) : # WALRUS
pcell [ " sunday " ] = issunday
2011-07-11 02:10:22 +01:00
prow . append ( pcell )
personexpeditiondays . append ( { " personexpedition " : personexpedition , " personrow " : prow } )
2021-04-10 01:07:49 +01:00
2023-01-30 15:28:11 +00:00
ts [ expeditionname ] = { ' expedition ' : expo ,
' expeditions ' : expeditions ,
2021-04-10 01:07:49 +01:00
' personexpeditiondays ' : personexpeditiondays , ' settings ' : settings ,
2023-01-29 22:11:00 +00:00
' dateditems ' : dateditems , ' dates ' : dates }
2021-04-10 01:07:49 +01:00
TROG [ ' pagecache ' ] [ ' expedition ' ] [ expeditionname ] = ts [ expeditionname ]
2023-01-30 15:28:11 +00:00
2021-04-23 03:07:21 +01:00
return render ( request , ' expedition.html ' , { * * ts [ expeditionname ] , ' logged_in ' : logged_in } )
2011-07-11 02:10:22 +01:00
2020-07-26 20:48:25 +01:00
class Expeditions_tsvListView ( ListView ) :
""" This uses the Django built-in shortcut mechanism
It defaults to use a template with name < app - label > / < model - name > _list . html .
https : / / www . agiliq . com / blog / 2017 / 12 / when - and - how - use - django - listview /
https : / / developer . mozilla . org / en - US / docs / Learn / Server - side / Django / Generic_views
Either a queryset variable or set_queryset ( ) function is used , but not needed
if you want all the obejcts of a particaulr type in which case just set model = < object >
"""
template_name = ' core/expeditions_tsv_list.html ' # if not present then uses core/expedition_list.html
#queryset = Expedition.objects.all()
#context_object_name = 'expedition'
model = Expedition # equivalent to .objects.all() for a queryset
class Expeditions_jsonListView ( ListView ) :
template_name = ' core/expeditions_json_list.html '
model = Expedition
2019-02-24 13:03:34 +00:00
2011-07-11 02:10:22 +01:00
def person ( request , first_name = ' ' , last_name = ' ' , ) :
2021-04-20 22:58:41 +01:00
try :
this_person = Person . objects . get ( first_name = first_name , last_name = last_name )
except :
2022-10-11 19:47:18 +01:00
message = f ' Person not found \' { first_name } { last_name } \' - possibly Scottish? (See our <a href= " /handbook/troggle/namesredesign.html " >Proposal to fix this</a>) '
2022-10-15 17:33:30 +01:00
return render ( request , ' errors/generic.html ' , { ' message ' : message } )
2011-07-11 02:10:22 +01:00
2022-10-15 17:33:30 +01:00
return render ( request , ' person.html ' , { ' person ' : this_person } )
2011-07-11 02:10:22 +01:00
2021-04-15 17:51:01 +01:00
def get_person_chronology ( personexpedition ) :
2023-01-29 01:30:10 +00:00
'''
2021-04-30 00:24:36 +01:00
This is just a nasty convoluted way of trying the make the template do more work than it is sensible to ask it to do .
Rewrite more simply with the login in the python , not in Django template language ( you bastard Curtis ) .
2020-07-06 01:24:43 +01:00
'''
2011-07-11 02:10:22 +01:00
res = { }
2023-01-30 16:27:01 +00:00
for personlogentry in personexpedition . personlogentry_set . all ( ) :
a = res . setdefault ( personlogentry . logbook_entry . date , { } )
a . setdefault ( " personlogentries " , [ ] ) . append ( personlogentry )
2011-07-11 02:10:22 +01:00
for personrole in personexpedition . survexpersonrole_set . all ( ) :
2023-01-29 01:30:10 +00:00
if personrole . survexblock . date : # avoid bad data from another bug
a = res . setdefault ( personrole . survexblock . date , { } )
a . setdefault ( " personroles " , [ ] ) . append ( personrole . survexblock )
2011-07-11 02:10:22 +01:00
# build up the tables
2020-05-24 01:57:06 +01:00
rdates = sorted ( list ( res . keys ( ) ) )
2020-07-06 01:24:43 +01:00
2011-07-11 02:10:22 +01:00
res2 = [ ]
for rdate in rdates :
2023-01-30 16:07:44 +00:00
personlogentries = res [ rdate ] . get ( " personlogentries " , [ ] )
2020-07-06 01:24:43 +01:00
personroles = res [ rdate ] . get ( " personroles " , [ ] )
2023-01-30 16:07:44 +00:00
for n in range ( max ( len ( personlogentries ) , len ( personroles ) ) ) :
res2 . append ( ( ( n == 0 and rdate or " -- " ) , ( n < len ( personlogentries ) and personlogentries [ n ] ) , ( n < len ( personroles ) and personroles [ n ] ) ) )
2011-07-11 02:10:22 +01:00
return res2
def personexpedition ( request , first_name = ' ' , last_name = ' ' , year = ' ' ) :
person = Person . objects . get ( first_name = first_name , last_name = last_name )
2019-02-24 13:03:34 +00:00
this_expedition = Expedition . objects . get ( year = year )
personexpedition = person . personexpedition_set . get ( expedition = this_expedition )
2021-04-15 17:51:01 +01:00
personchronology = get_person_chronology ( personexpedition )
2021-04-30 00:24:36 +01:00
#for pc in personchronology:
#print(pc)
2019-03-30 17:02:07 +00:00
return render ( request , ' personexpedition.html ' , { ' personexpedition ' : personexpedition , ' personchronology ' : personchronology } )
2011-07-11 02:10:22 +01:00
def logbookentry ( request , date , slug ) :
2022-12-19 20:13:26 +00:00
# start = time.time()
trips = LogbookEntry . objects . filter ( date = date ) # all the trips not just this one
this_logbookentry = trips . filter ( date = date , slug = slug )
2021-04-24 01:23:55 +01:00
if this_logbookentry :
if len ( this_logbookentry ) > 1 :
return render ( request , ' object_list.html ' , { ' object_list ' : this_logbookentry } )
else :
2022-09-27 21:59:25 +01:00
wallets = set ( )
2022-12-19 20:13:26 +00:00
allwallets = Wallet . objects . all ( )
refwallets = allwallets . filter ( survexblock__date = date )
2022-09-27 21:59:25 +01:00
for r in refwallets :
wallets . add ( r )
2022-12-19 20:13:26 +00:00
2022-09-27 21:59:25 +01:00
# Note that w.year() only works for wallets which have a valid JSON file existing
2022-12-19 20:13:26 +00:00
# This is very slow with a big lag as w.date() is a computed field
# Noticably slow with WSL2 and NTFS filesystem, even with caching as walletdate.
jwallets = allwallets . filter ( walletdate = date )
for j in jwallets :
wallets . add ( j )
2023-01-29 21:45:51 +00:00
# thisexpo = Expedition.objects.get(year=int(date[0:4]))
# if thisexpo:
# #expeditionday = thisexpo.get_expedition_day(date)
# svxothers = SurvexBlock.objects.filter(date=date)
# else:
# svxothers = None
svxothers = SurvexBlock . objects . filter ( date = date )
2021-04-24 01:23:55 +01:00
this_logbookentry = this_logbookentry [ 0 ]
2023-01-30 16:27:01 +00:00
# This is the only page that uses personlogentry_next and personlogentry_prev
2022-11-21 16:41:52 +00:00
# and it is calculated on the fly in the model
2022-09-27 21:59:25 +01:00
return render ( request , ' logbookentry.html ' ,
{ ' logbookentry ' : this_logbookentry , ' trips ' : trips , ' svxothers ' : svxothers , ' wallets ' : wallets } )
2011-07-11 02:10:22 +01:00
else :
2021-04-24 01:23:55 +01:00
msg = ( f ' Logbook entry slug: " { slug } " not found in database on date: " { date } " ' )
print ( msg )
return render ( request , ' errors/generic.html ' , { ' message ' : msg } )
2011-07-11 02:10:22 +01:00
def get_people ( request , expeditionslug ) :
exp = Expedition . objects . get ( year = expeditionslug )
2019-03-30 17:02:07 +00:00
return render ( request , ' options.html ' , { " items " : [ ( pe . slug , pe . name ) for pe in exp . personexpedition_set . all ( ) ] } )
2011-07-11 02:10:22 +01:00
def get_logbook_entries ( request , expeditionslug ) :
exp = Expedition . objects . get ( year = expeditionslug )
2022-11-23 10:48:39 +00:00
return render ( request , ' options.html ' , { " items " : [ ( le . slug , f " { le . date } - { le . title } " ) for le in exp . logbookentry_set . all ( ) ] } )