diff --git a/core/forms.py b/core/forms.py index e8e620c..8abf32a 100644 --- a/core/forms.py +++ b/core/forms.py @@ -8,8 +8,8 @@ from django.contrib.admin.widgets import AdminDateWidget from tinymce.widgets import TinyMCE -from troggle.core.models import Person, PersonExpedition, LogbookEntry, Expedition -from troggle.core.models_caves import Cave, QM, Entrance, CaveAndEntrance +from troggle.core.models import Person, PersonExpedition, Expedition +from troggle.core.models_caves import Cave, LogbookEntry, QM, Entrance, CaveAndEntrance class CaveForm(ModelForm): underground_description = forms.CharField(required = False, widget=forms.Textarea()) diff --git a/core/models.py b/core/models.py index 4243fe1..4d69481 100644 --- a/core/models.py +++ b/core/models.py @@ -5,7 +5,7 @@ import logging import re from subprocess import call -from urllib.parse import urljoin +import urllib.parse from decimal import Decimal, getcontext getcontext().prec=2 #use 2 significant figures for decimal calculations @@ -15,7 +15,6 @@ from django.db import models from django.contrib import admin from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType -#from django.db.models import Min, Max from django.conf import settings from django.core.urlresolvers import reverse from django.template import Context, loader @@ -237,119 +236,3 @@ class PersonExpedition(TroggleModel): return res["day_max"] -class LogbookEntry(TroggleModel): - """Single parsed entry from Logbook - """ - LOGBOOK_ENTRY_TYPES = ( - ("wiki", "Wiki style logbook"), - ("html", "Html style logbook") - ) - - date = models.DateField()#MJG wants to turn this into a datetime such that multiple Logbook entries on the same day can be ordered.ld() - expeditionday = models.ForeignKey("ExpeditionDay", null=True)#MJG wants to KILL THIS (redundant information) - expedition = models.ForeignKey(Expedition,blank=True,null=True) # yes this is double- - title = models.CharField(max_length=settings.MAX_LOGBOOK_ENTRY_TITLE_LENGTH) - cave_slug = models.SlugField(max_length=50) - place = models.CharField(max_length=100,blank=True,null=True,help_text="Only use this if you haven't chosen a cave") - text = models.TextField() - slug = models.SlugField(max_length=50) - filename = models.CharField(max_length=200,null=True) - entry_type = models.CharField(default="wiki",null=True,choices=LOGBOOK_ENTRY_TYPES,max_length=50) - - class Meta: - verbose_name_plural = "Logbook Entries" - # several PersonTrips point in to this object - ordering = ('-date',) - - def __getattribute__(self, item): - if item == "cave": - #Allow a logbookentries cave to be directly accessed despite not having a proper foreignkey - return models_caves.CaveSlug.objects.get(slug = self.cave_slug).cave - # parse error in python3.8 - # https://stackoverflow.com/questions/41343263/provide-classcell-example-for-python-3-6-metaclass - #https://github.com/django/django/pull/7653 - #return TroggleModel.__getattribute__(item) - #return super(LogbookEntry, self).__getattribute__(item) # works in py3.5, fails in 3.8 - return TroggleModel.__getattribute__(self,item) # works in py 3.5 AND in 3.8 - - def __init__(self, *args, **kwargs): - if "cave" in list(kwargs.keys()): - if kwargs["cave"] is not None: - kwargs["cave_slug"] = models_caves.CaveSlug.objects.get(cave=kwargs["cave"], primary=True).slug - kwargs.pop("cave") - # parse error in python3.8 - return TroggleModel.__init__(self, *args, **kwargs) # seems OK in 3.5 & 3.8! failure later elsewhere with 3.8 - #return TroggleModel().__init__(self, *args, **kwargs) # parses OK, fails at runtime in 3.8 - #return super().__init__(self, *args, **kwargs) # fails in 3.8 - #return super().__init__(*args, **kwargs) # works in py3.5 fails in 3.8 - #return super(LogbookEntry, self).__init__(*args, **kwargs) # works in py3.5 - #return TroggleModel.__init__(*args, **kwargs) # fails in py3.5, runtime fail in 3.8 - - def isLogbookEntry(self): # Function used in templates - return True - - def get_absolute_url(self): - return urllib.parse.urljoin(settings.URL_ROOT, reverse('logbookentry',kwargs={'date':self.date,'slug':self.slug})) - - def __str__(self): - return "%s: (%s)" % (self.date, self.title) - - def get_next_by_id(self): - LogbookEntry.objects.get(id=self.id+1) - - def get_previous_by_id(self): - LogbookEntry.objects.get(id=self.id-1) - - def new_QM_number(self): - """Returns """ - if self.cave: - nextQMnumber=self.cave.new_QM_number(self.date.year) - else: - return None - return nextQMnumber - - def new_QM_found_link(self): - """Produces a link to a new QM with the next number filled in and this LogbookEntry set as 'found by' """ - return settings.URL_ROOT + r'/admin/core/qm/add/?' + r'found_by=' + str(self.pk) +'&number=' + str(self.new_QM_number()) - - def DayIndex(self): - return list(self.expeditionday.logbookentry_set.all()).index(self) - - -# -# Single Person going on a trip, which may or may not be written up (accounts for different T/U for people in same logbook entry) -# -class PersonTrip(TroggleModel): - personexpedition = models.ForeignKey("PersonExpedition",null=True) - - #expeditionday = models.ForeignKey("ExpeditionDay")#MJG wants to KILL THIS (redundant information) - #date = models.DateField() #MJG wants to KILL THIS (redundant information) - time_underground = models.FloatField(help_text="In decimal hours") - logbook_entry = models.ForeignKey(LogbookEntry) - is_logbook_entry_author = models.BooleanField(default=False) - - - # sequencing by person (difficult to solve locally) - #persontrip_next = models.ForeignKey('PersonTrip', related_name='pnext', blank=True,null=True)#MJG wants to KILL THIS (and use funstion persontrip_next_auto) - #persontrip_prev = models.ForeignKey('PersonTrip', related_name='pprev', blank=True,null=True)#MJG wants to KILL THIS(and use funstion persontrip_prev_auto) - - def persontrip_next(self): - futurePTs = PersonTrip.objects.filter(personexpedition = self.personexpedition, logbook_entry__date__gt = self.logbook_entry.date).order_by('logbook_entry__date').all() - if len(futurePTs) > 0: - return futurePTs[0] - else: - return None - - def persontrip_prev(self): - pastPTs = PersonTrip.objects.filter(personexpedition = self.personexpedition, logbook_entry__date__lt = self.logbook_entry.date).order_by('-logbook_entry__date').all() - if len(pastPTs) > 0: - return pastPTs[0] - else: - return None - - def place(self): - return self.logbook_entry.cave and self.logbook_entry.cave or self.logbook_entry.place - - def __str__(self): - return "%s (%s)" % (self.personexpedition, self.logbook_entry.date) - diff --git a/core/models_caves.py b/core/models_caves.py index 4246f6d..44a5ac7 100644 --- a/core/models_caves.py +++ b/core/models_caves.py @@ -18,7 +18,7 @@ from django.conf import settings from django.core.urlresolvers import reverse from django.template import Context, loader -from troggle.core.models import * +from troggle.core.models import TroggleModel, TroggleImageModel, Person, Expedition from troggle.core.models_survex import * class Area(TroggleModel): @@ -406,6 +406,85 @@ class NewSubCave(TroggleModel): def __str__(self): return str(self.name) +class LogbookEntry(TroggleModel): + """Single parsed entry from Logbook + """ + LOGBOOK_ENTRY_TYPES = ( + ("wiki", "Wiki style logbook"), + ("html", "Html style logbook") + ) + + date = models.DateField()#MJG wants to turn this into a datetime such that multiple Logbook entries on the same day can be ordered.ld() + expeditionday = models.ForeignKey("ExpeditionDay", null=True)#MJG wants to KILL THIS (redundant information) + expedition = models.ForeignKey(Expedition,blank=True,null=True) # yes this is double- + title = models.CharField(max_length=settings.MAX_LOGBOOK_ENTRY_TITLE_LENGTH) + cave_slug = models.SlugField(max_length=50) + place = models.CharField(max_length=100,blank=True,null=True,help_text="Only use this if you haven't chosen a cave") + text = models.TextField() + slug = models.SlugField(max_length=50) + filename = models.CharField(max_length=200,null=True) + entry_type = models.CharField(default="wiki",null=True,choices=LOGBOOK_ENTRY_TYPES,max_length=50) + + class Meta: + verbose_name_plural = "Logbook Entries" + # several PersonTrips point in to this object + ordering = ('-date',) + + def __getattribute__(self, item): + if item == "cave": + #Allow a logbookentries cave to be directly accessed despite not having a proper foreignkey + return CaveSlug.objects.get(slug = self.cave_slug).cave + # parse error in python3.8 + # https://stackoverflow.com/questions/41343263/provide-classcell-example-for-python-3-6-metaclass + #https://github.com/django/django/pull/7653 + #return TroggleModel.__getattribute__(item) + #return super(LogbookEntry, self).__getattribute__(item) # works in py3.5, fails in 3.8 + return TroggleModel.__getattribute__(self,item) # works in py 3.5 AND in 3.8 + + def __init__(self, *args, **kwargs): + if "cave" in list(kwargs.keys()): + if kwargs["cave"] is not None: + kwargs["cave_slug"] = models_caves.CaveSlug.objects.get(cave=kwargs["cave"], primary=True).slug + kwargs.pop("cave") + # parse error in python3.8 + return TroggleModel.__init__(self, *args, **kwargs) # seems OK in 3.5 & 3.8! failure later elsewhere with 3.8 + #return TroggleModel().__init__(self, *args, **kwargs) # parses OK, fails at runtime in 3.8 + #return super().__init__(self, *args, **kwargs) # fails in 3.8 + #return super().__init__(*args, **kwargs) # works in py3.5 fails in 3.8 + #return super(LogbookEntry, self).__init__(*args, **kwargs) # works in py3.5 + #return TroggleModel.__init__(*args, **kwargs) # fails in py3.5, runtime fail in 3.8 + + def isLogbookEntry(self): # Function used in templates + return True + + def get_absolute_url(self): + return urllib.parse.urljoin(settings.URL_ROOT, reverse('logbookentry',kwargs={'date':self.date,'slug':self.slug})) + + def __str__(self): + return "%s: (%s)" % (self.date, self.title) + + def get_next_by_id(self): + LogbookEntry.objects.get(id=self.id+1) + + def get_previous_by_id(self): + LogbookEntry.objects.get(id=self.id-1) + + def new_QM_number(self): + """Returns """ + if self.cave: + nextQMnumber=self.cave.new_QM_number(self.date.year) + else: + return None + return nextQMnumber + + def new_QM_found_link(self): + """Produces a link to a new QM with the next number filled in and this LogbookEntry set as 'found by' """ + return settings.URL_ROOT + r'/admin/core/qm/add/?' + r'found_by=' + str(self.pk) +'&number=' + str(self.new_QM_number()) + + def DayIndex(self): + return list(self.expeditionday.logbookentry_set.all()).index(self) + + class QM(TroggleModel): #based on qm.csv in trunk/expoweb/1623/204 which has the fields: #"Number","Grade","Area","Description","Page reference","Nearest station","Completion description","Comment" @@ -510,4 +589,39 @@ class Survey(TroggleModel): def elevations(self): return self.scannedimage_set.filter(contents='elevation') +# +# Single Person going on a trip, which may or may not be written up (accounts for different T/U for people in same logbook entry) +# +class PersonTrip(TroggleModel): + personexpedition = models.ForeignKey("PersonExpedition",null=True) + + #expeditionday = models.ForeignKey("ExpeditionDay")#MJG wants to KILL THIS (redundant information) + #date = models.DateField() #MJG wants to KILL THIS (redundant information) + time_underground = models.FloatField(help_text="In decimal hours") + logbook_entry = models.ForeignKey(LogbookEntry) + is_logbook_entry_author = models.BooleanField(default=False) + + + # sequencing by person (difficult to solve locally) + #persontrip_next = models.ForeignKey('PersonTrip', related_name='pnext', blank=True,null=True)#MJG wants to KILL THIS (and use funstion persontrip_next_auto) + #persontrip_prev = models.ForeignKey('PersonTrip', related_name='pprev', blank=True,null=True)#MJG wants to KILL THIS(and use funstion persontrip_prev_auto) + + def persontrip_next(self): + futurePTs = PersonTrip.objects.filter(personexpedition = self.personexpedition, logbook_entry__date__gt = self.logbook_entry.date).order_by('logbook_entry__date').all() + if len(futurePTs) > 0: + return futurePTs[0] + else: + return None + def persontrip_prev(self): + pastPTs = PersonTrip.objects.filter(personexpedition = self.personexpedition, logbook_entry__date__lt = self.logbook_entry.date).order_by('-logbook_entry__date').all() + if len(pastPTs) > 0: + return pastPTs[0] + else: + return None + + def place(self): + return self.logbook_entry.cave and self.logbook_entry.cave or self.logbook_entry.place + + def __str__(self): + return "%s (%s)" % (self.personexpedition, self.logbook_entry.date) diff --git a/core/templatetags/wiki_markup.py b/core/templatetags/wiki_markup.py index 024b9b7..9aafb39 100644 --- a/core/templatetags/wiki_markup.py +++ b/core/templatetags/wiki_markup.py @@ -3,7 +3,7 @@ from django.utils.html import conditional_escape from django.template.defaultfilters import stringfilter from django.utils.safestring import mark_safe from django.conf import settings -from troggle.core.models import QM, LogbookEntry, Cave +from troggle.core.models_caves import LogbookEntry, QM, Cave import re, urllib.parse register = template.Library() diff --git a/core/views_caves.py b/core/views_caves.py index 31f6707..d741671 100644 --- a/core/views_caves.py +++ b/core/views_caves.py @@ -21,7 +21,8 @@ from django.shortcuts import get_object_or_404, render import troggle.settings as settings import troggle.core.models as models -from troggle.core.models_caves import CaveSlug, Cave, CaveAndEntrance, Survey, Expedition, QM, CaveDescription, EntranceSlug, Entrance, Area, SurvexStation +from troggle.core.models import Expedition +from troggle.core.models_caves import CaveSlug, Cave, CaveAndEntrance, Survey, QM, CaveDescription, EntranceSlug, Entrance, Area, SurvexStation from troggle.core.forms import CaveForm, CaveAndEntranceFormSet, VersionControlCommentForm, EntranceForm, EntranceLetterForm from troggle.helper import login_required_if_public diff --git a/core/views_logbooks.py b/core/views_logbooks.py index b02200f..1cb9f2c 100644 --- a/core/views_logbooks.py +++ b/core/views_logbooks.py @@ -14,8 +14,9 @@ from django.views.generic.list import ListView import troggle.core.models as models import troggle.parsers.logbooks as logbookparsers from troggle.core.forms import getTripForm # , get_name, PersonForm -from troggle.core.models import Expedition, LogbookEntry, Person, PersonExpedition, PersonTrip -from troggle.core.models_survex import SurvexBlock +from troggle.core.models import Expedition, Person, PersonExpedition +from troggle.core.models_caves import LogbookEntry, PersonTrip +from troggle.core.models_survex import SurvexBlock, SurvexLeg from troggle.helper import login_required_if_public from troggle.parsers.logbooks import LoadLogbookForExpedition from troggle.parsers.people import GetPersonExpeditionNameLookup @@ -226,12 +227,12 @@ def experimental(request): for survexblock in survexblocks: survexlegs.extend(survexblock.survexleg_set.all()) survexleglength += survexblock.totalleglength - legsbyexpo.append((expedition, {"nsurvexlegs":len(survexlegs), "survexleglength":survexleglength})) + legsbyexpo.append((expedition, {"nsurvexlegs":len(survexlegs), "survexleglength":survexleglength/1000})) legsbyexpo.reverse() - survexlegs = models.SurvexLeg.objects.all() + survexlegs = SurvexLeg.objects.all() totalsurvexlength = sum([survexleg.tape for survexleg in survexlegs]) - return render(request, 'experimental.html', { "nsurvexlegs":len(survexlegs), "totalsurvexlength":totalsurvexlength, "legsbyexpo":legsbyexpo }) + return render(request, 'experimental.html', { "nsurvexlegs":len(survexlegs), "totalsurvexlength":totalsurvexlength/1000, "legsbyexpo":legsbyexpo }) @login_required_if_public def newLogbookEntry(request, expeditionyear, pdate = None, pslug = None): diff --git a/core/views_other.py b/core/views_other.py index 28a6d94..827c499 100644 --- a/core/views_other.py +++ b/core/views_other.py @@ -9,8 +9,8 @@ from django.shortcuts import render from django.template import Context, loader import databaseReset -from troggle.core.models import Expedition, LogbookEntry, Person, PersonExpedition, PersonTrip -from troggle.core.models_caves import QM, Cave +from troggle.core.models import Expedition, Person, PersonExpedition +from troggle.core.models_caves import LogbookEntry, QM, Cave, PersonTrip from troggle.helper import login_required_if_public diff --git a/core/views_survex.py b/core/views_survex.py index cec4d6c..f6e692f 100644 --- a/core/views_survex.py +++ b/core/views_survex.py @@ -11,9 +11,9 @@ from django.http import HttpResponse, Http404 import troggle.settings as settings import parsers.survex -from troggle.core.models import Expedition, Person, PersonExpedition, PersonTrip, LogbookEntry +from troggle.core.models import Expedition, Person, PersonExpedition from troggle.core.models_survex import SurvexBlock, SurvexPersonRole, SurvexFile, SurvexDirectory, SurvexTitle -from troggle.core.models_caves import Cave +from troggle.core.models_caves import Cave, PersonTrip, LogbookEntry from troggle.parsers.people import GetPersonExpeditionNameLookup