2023-09-29 20:00:10 +01:00
import re
2023-02-27 22:23:24 +00:00
from django . db . models import Q
2021-03-28 03:48:24 +01:00
from django . shortcuts import render
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-03-16 21:06:52 +00:00
from troggle . core . models . logbooks import LogbookEntry , PersonLogEntry , QM
2023-02-27 22:23:24 +00:00
from troggle . core . models . survex import SurvexBlock , SurvexFile
2023-01-30 23:04:11 +00:00
from troggle . core . models . troggle import Expedition , Person
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
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
"""
2023-08-26 16:39:29 +01:00
todo = """ - Fix the get_person_chronology() display bug.
- Fix id = value preservation on editing
2023-01-30 19:04:36 +00:00
"""
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-08-26 16:39:29 +01: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 = (
2023-01-30 23:04:11 +00:00
" Expedition not found - database apparently empty, you probably need to do a full re-import of all data. "
2023-01-30 19:04:36 +00:00
)
return render ( request , " errors/generic.html " , { " message " : message } )
2023-09-04 16:56:32 +01:00
ts = TROG [ " pagecache " ] [ " expedition " ] # not much use unless single user!
2023-01-30 19:04:36 +00:00
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 :
2023-09-04 16:56:32 +01:00
if expeditionname in ts :
del ts [ expeditionname ] # clean out cache for page
2023-01-30 15:28:11 +00:00
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
if settings . CACHEDPAGES :
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-03-16 21:06:52 +00:00
class QMs_jsonListView ( ListView ) :
template_name = " core/QMs_json_list.html "
model = QM
2023-01-30 19:04:36 +00:00
2023-09-29 20:00:10 +01:00
rx_person = re . compile ( r " (?i)^(([A-Z]*[a-z \ - \ ' &;]*)[^a-zA-Z]*)([a-z \ - \ ' ]*[^a-zA-Z]*[ \ -]*[A-Z]*[a-zA-Z \ -&;]*)$ " )
rx_simple_person = re . compile ( r " ^([A-Z][a-z]*)[ ]*([A-Z][a-z]*)$ " )
def better_person ( request , name = " " ) :
""" Attempting to replace the name parser in urls.py with a more complex but
more understandable one in the body of the code .
Unfortuantely the get_absolute_url Django funny is making life very difficult .
This is in models / troggle . py PersonExpedition and Person
We need a defined slug for a person , however complicated their name , before we can progress further , if we
insist on using get_absolute_url ( ) .
Probably simpler and clearer to maintainers NOT to use ANY get_absolute_url ( ) in the templates .
"""
names = rx_simple_person . match ( name . strip ( " / " ) )
if names :
first_name = names . group ( 1 )
last_name = names . group ( 2 )
else :
message = f " Name not recognised ' { name } ' - possibly French? (See our <a href= \" /handbook/troggle/namesredesign.html \" >Proposal to fix this</a>) "
return render ( request , " errors/generic.html " , { " message " : message } )
try :
this_person = Person . objects . get ( first_name = first_name , last_name = last_name )
except :
message = f " Person not found { name } => ' { 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 } )
2023-01-30 19:04:36 +00:00
def person (
request ,
2023-10-01 14:10:17 +01:00
slug = " "
2023-01-30 19:04:36 +00:00
) :
2023-10-01 14:10:17 +01:00
""" Original code as it has been for years. Trying to replace with better_person
2023-10-01 10:21:34 +01:00
"""
2023-10-01 14:10:17 +01:00
this_person = Person . objects . get ( slug = slug )
return render ( request , " person.html " , { " person " : this_person } )
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>) "
2023-10-01 13:55:28 +01:00
peeps = Person . objects . filter ( first_name = first_name , last_name = last_name )
if len ( peeps ) > 1 :
message = f " Multiple people ( { len ( peeps ) } ) with this name ' { first_name } { last_name } ' - (See our <a href= \" /handbook/troggle/namesredesign.html \" >Proposal to fix this</a>) "
2023-01-30 19:04:36 +00:00
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-10-01 13:55:28 +01:00
def personexpedition ( request , slug = " " , year = " " ) :
person = Person . objects . get ( slug = slug )
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 :
2023-02-27 22:23:24 +00:00
# BUG
2023-01-30 19:04:36 +00:00
return render ( request , " object_list.html " , { " object_list " : this_logbookentry } )
2021-04-24 01:23:55 +01:00
else :
2023-02-27 22:23:24 +00:00
# https://stackoverflow.com/questions/739776/how-do-i-do-an-or-filter-in-a-django-query
wallets = Wallet . objects . filter ( Q ( survexblock__date = date ) | Q ( walletdate = date ) ) . distinct ( )
svxothers = SurvexFile . objects . filter ( survexblock__date = date ) . distinct ( )
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 ( ) ] }
)