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
2023-01-30 19:04:36 +00:00
""" These views are for logbook items when they appear in an ' expedition ' page
2021-04-10 01:07:49 +01:00
and for persons : their individual pages and their perseonexpedition pages .
It uses the global object TROG to hold some cached pages .
2023-01-30 19:04:36 +00:00
"""
todo = """ Fix the get_person_chronology() display bug.
"""
2011-07-11 02:10:22 +01:00
2021-04-21 19:08:42 +01:00
2021-04-30 21:32:53 +01:00
def notablepersons ( request ) :
2022-04-23 20:42:46 +01:00
def notabilitykey ( person ) :
2023-01-30 19:04:36 +00:00
return person . notability ( )
2022-04-23 20:42:46 +01:00
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
2023-01-30 19:04:36 +00:00
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 ) :
2023-01-30 19:04:36 +00:00
pcols . append ( persons [ i * nc : ( i + 1 ) * nc ] )
2011-07-11 02:10:22 +01:00
notablepersons = [ ]
2023-01-30 19:04:36 +00:00
# Needed recoding because of Django CVE-2021-45116
2022-04-23 20:42:46 +01:00
for person in persons :
if person . bisnotable ( ) :
notablepersons . append ( person )
notablepersons . sort ( key = notabilitykey , reverse = True )
2011-07-11 02:10:22 +01:00
2023-01-30 19:04:36 +00:00
return render (
request , " notablepersons.html " , { " persons " : persons , " pcols " : pcols , " notablepersons " : notablepersons }
)
2011-07-11 02:10:22 +01:00
def expedition ( request , expeditionname ) :
2023-01-30 19:04:36 +00:00
""" Returns a rendered page for one expedition, specified by the year e.g. ' 2019 ' .
2021-04-10 01:07:49 +01:00
If page caching is enabled , it caches the dictionaries used to render the template page .
2023-01-30 19:04:36 +00:00
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 .
2023-01-30 19:04:36 +00:00
2023-01-30 15:28:11 +00:00
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 19:04:36 +00:00
Queries are not evaluated to hit the database until a result is actually used . Django
2023-01-30 15:28:11 +00:00
does lazy evaluation .
2023-01-30 19:04:36 +00:00
"""
2023-01-30 15:28:11 +00:00
try :
expo = Expedition . objects . get ( year = int ( expeditionname ) )
except :
2023-01-30 19:04:36 +00:00
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 } )
if request . user . is_authenticated :
2021-04-23 03:07:21 +01:00
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-30 19:04:36 +00:00
ts = TROG [ " pagecache " ] [ " expedition " ] # not much use unless single user!
2021-04-10 01:07:49 +01:00
if settings . CACHEDPAGES :
2023-01-30 19:04:36 +00:00
nexpos = len ( TROG [ " pagecache " ] [ " expedition " ] )
# print(f'! - expo {expeditionname} CACHEDPAGES {nexpos} expo pages in cache.')
2021-04-10 01:07:49 +01:00
if expeditionname in ts :
2023-01-30 19:04:36 +00:00
# print('! - expo {expeditionanme} using cached page')
return render ( request , " expedition.html " , { * * ts [ expeditionname ] , " logged_in " : logged_in } )
expeditions = Expedition . objects . all ( ) # top menu only, evaluated only when template renders
entries = expo . logbookentry_set . all ( )
2023-01-30 15:28:11 +00:00
blocks = expo . survexblock_set . all ( )
2023-01-30 19:04:36 +00:00
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 19:04:36 +00:00
2023-01-30 16:18:19 +00:00
allpersonlogentries = PersonLogEntry . objects . filter ( personexpedition__expedition = expo )
2023-01-30 19:04:36 +00:00
personexpodays = [ ]
2023-01-30 15:28:11 +00:00
for personexpedition in expo . personexpedition_set . all ( ) :
2023-01-30 19:04:36 +00:00
expotrips = allpersonlogentries . filter ( personexpedition = personexpedition ) # lazy
2023-01-30 15:28:11 +00:00
expoblocks = blocks . filter ( survexpersonrole__personexpedition = personexpedition )
2023-01-30 19:04:36 +00:00
prow = [ ]
2011-07-11 02:10:22 +01:00
for date in dates :
2023-01-30 19:04:36 +00:00
personentries = expotrips . filter ( logbook_entry__date = date ) # lazy
personblocks = set ( expoblocks . filter ( date = date ) ) # not lazy
2023-01-30 15:28:11 +00:00
pcell = { }
pcell [ " personentries " ] = personentries
pcell [ " survexblocks " ] = personblocks
2023-01-30 19:04:36 +00:00
if issunday := ( date . weekday ( ) == 6 ) : # WALRUS
2023-01-30 15:28:11 +00:00
pcell [ " sunday " ] = issunday
2011-07-11 02:10:22 +01:00
prow . append ( pcell )
2023-01-30 19:04:36 +00:00
personexpodays . append ( { " personexpedition " : personexpedition , " personrow " : prow } )
ts [ expeditionname ] = {
" expedition " : expo ,
" expeditions " : expeditions ,
" personexpodays " : personexpodays ,
" settings " : settings ,
" dateditems " : dateditems ,
" dates " : dates ,
}
TROG [ " pagecache " ] [ " expedition " ] [ expeditionname ] = ts [ expeditionname ]
return render ( request , " expedition.html " , { * * ts [ expeditionname ] , " logged_in " : logged_in } )
class Expeditions_tsvListView ( ListView ) :
""" This uses the Django built-in shortcut mechanism
2020-07-26 20:48:25 +01:00
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 >
"""
2023-01-30 19:04:36 +00:00
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
2020-07-26 20:48:25 +01:00
2023-01-30 19:04:36 +00:00
class Expeditions_jsonListView ( ListView ) :
template_name = " core/expeditions_json_list.html "
model = Expedition
2019-02-24 13:03:34 +00:00
2023-01-30 19:04:36 +00:00
def person (
request ,
first_name = " " ,
last_name = " " ,
) :
2021-04-20 22:58:41 +01:00
try :
2023-01-30 19:04:36 +00:00
this_person = Person . objects . get ( first_name = first_name , last_name = last_name )
2021-04-20 22:58:41 +01:00
except :
2023-01-30 19:04:36 +00: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>) "
return render ( request , " errors/generic.html " , { " message " : message } )
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-30 19:04:36 +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 ) .
2023-01-30 19:04:36 +00:00
"""
res = { }
2023-01-30 16:27:01 +00:00
for personlogentry in personexpedition . personlogentry_set . all ( ) :
2023-01-30 19:04:36 +00:00
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-30 19:04:36 +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
2023-01-30 19:04:36 +00:00
res2 = [ ]
2011-07-11 02:10:22 +01:00
for rdate in rdates :
2023-01-30 19:04:36 +00:00
personlogentries = res [ rdate ] . get ( " personlogentries " , [ ] )
personroles = res [ rdate ] . get ( " personroles " , [ ] )
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
2023-01-30 19:04:36 +00:00
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 )
2023-01-30 19:04:36 +00:00
# for pc in personchronology:
# print(pc)
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()
2023-01-30 19:04:36 +00:00
trips = LogbookEntry . objects . filter ( date = date ) # all the trips not just this one
2022-12-19 20:13:26 +00:00
this_logbookentry = trips . filter ( date = date , slug = slug )
2023-01-30 19:04:36 +00:00
2021-04-24 01:23:55 +01:00
if this_logbookentry :
2023-01-30 19:04:36 +00:00
if len ( this_logbookentry ) > 1 :
return render ( request , " object_list.html " , { " object_list " : this_logbookentry } )
2021-04-24 01:23:55 +01:00
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 )
2023-01-30 19:04:36 +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-30 16:42:56 +00:00
2023-01-29 21:45:51 +00:00
svxothers = SurvexBlock . objects . filter ( date = date )
2023-01-30 19:04:36 +00:00
this_logbookentry = this_logbookentry [ 0 ]
2023-01-30 16:42:56 +00:00
# This is the only page that uses next_.. and prev_..
2023-01-30 19:04:36 +00:00
# and it is calculated on the fly in the model
return render (
request ,
" logbookentry.html " ,
{ " logbookentry " : this_logbookentry , " trips " : trips , " svxothers " : svxothers , " wallets " : wallets } ,
)
2011-07-11 02:10:22 +01:00
else :
2023-01-30 19:04:36 +00:00
msg = f ' Logbook entry slug: " { slug } " not found in database on date: " { date } " '
2021-04-24 01:23:55 +01:00
print ( msg )
2023-01-30 19:04:36 +00:00
return render ( request , " errors/generic.html " , { " message " : msg } )
2011-07-11 02:10:22 +01:00
def get_people ( request , expeditionslug ) :
2023-01-30 19:04:36 +00:00
exp = Expedition . objects . get ( year = expeditionslug )
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 ) :
2023-01-30 19:04:36 +00:00
exp = Expedition . objects . get ( year = expeditionslug )
return render (
request , " options.html " , { " items " : [ ( le . slug , f " { le . date } - { le . title } " ) for le in exp . logbookentry_set . all ( ) ] }
)