forked from expo/troggle
edit logbooks, new logbook format, increased database normalisation
This commit is contained in:
@@ -50,14 +50,13 @@ class PhotoInline(admin.TabularInline):
|
||||
|
||||
class PersonTripInline(admin.TabularInline):
|
||||
model = PersonTrip
|
||||
exclude = ['persontrip_next','Delete']
|
||||
raw_id_fields = ('personexpedition',)
|
||||
extra = 1
|
||||
|
||||
#class LogbookEntryAdmin(VersionAdmin):
|
||||
class LogbookEntryAdmin(TroggleModelAdmin):
|
||||
prepopulated_fields = {'slug':("title",)}
|
||||
raw_id_fields = ('cave','author')
|
||||
raw_id_fields = ('cave',)
|
||||
search_fields = ('title','expedition__year')
|
||||
date_heirarchy = ('date')
|
||||
inlines = (PersonTripInline, PhotoInline, QMsFoundInline)
|
||||
@@ -140,4 +139,4 @@ def export_as_xml(modeladmin, request, queryset):
|
||||
return response
|
||||
|
||||
#admin.site.add_action(export_as_xml)
|
||||
#admin.site.add_action(export_as_json)
|
||||
#admin.site.add_action(export_as_json)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
from django.forms import ModelForm
|
||||
from models import Cave, Person, LogbookEntry, QM
|
||||
from models import Cave, Person, PersonExpedition, LogbookEntry, QM
|
||||
import django.forms as forms
|
||||
from django.forms.formsets import formset_factory
|
||||
from django.contrib.admin.widgets import AdminDateWidget
|
||||
import string
|
||||
from datetime import date
|
||||
from tinymce.widgets import TinyMCE
|
||||
|
||||
class CaveForm(ModelForm):
|
||||
class Meta:
|
||||
@@ -45,4 +46,43 @@ class LogbookEntryForm(ModelForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(LogbookEntryForm, self).__init__(*args, **kwargs)
|
||||
self.fields['text'].help_text=self.wikiLinkHints()
|
||||
self.fields['text'].help_text=self.wikiLinkHints()
|
||||
|
||||
def getTripForm(expedition):
|
||||
|
||||
class TripForm(forms.Form):
|
||||
date = forms.DateField()
|
||||
title = forms.CharField(max_length=200)
|
||||
caves = [cave.reference() for cave in Cave.objects.all()]
|
||||
caves.sort()
|
||||
caves = ["-----"] + caves
|
||||
cave = forms.ChoiceField([(c, c) for c in caves], required=False)
|
||||
location = forms.CharField(max_length=200, required=False)
|
||||
caveOrLocation = forms.ChoiceField([("cave", "Cave"), ("location", "Location")], widget = forms.widgets.RadioSelect())
|
||||
html = forms.CharField(widget=TinyMCE(attrs={'cols': 80, 'rows': 30}))
|
||||
|
||||
def clean(self):
|
||||
print dir(self)
|
||||
if self.cleaned_data.get("caveOrLocation") == "cave" and not self.cleaned_data.get("cave"):
|
||||
self._errors["cave"] = self.error_class(["This field is required"])
|
||||
if self.cleaned_data.get("caveOrLocation") == "location" and not self.cleaned_data.get("location"):
|
||||
self._errors["location"] = self.error_class(["This field is required"])
|
||||
return self.cleaned_data
|
||||
|
||||
class PersonTripForm(forms.Form):
|
||||
def get_name(pe):
|
||||
if pe.nickname:
|
||||
return pe.nickname
|
||||
else:
|
||||
return pe.person.first_name
|
||||
names = [get_name(pe) for pe in PersonExpedition.objects.filter(expedition = expedition)]
|
||||
names.sort()
|
||||
names = ["-----"] + names
|
||||
name = forms.ChoiceField([(n, n) for n in names])
|
||||
TU = forms.FloatField(required=False)
|
||||
author = forms.BooleanField(required=False)
|
||||
|
||||
PersonTripFormSet = formset_factory(PersonTripForm, extra=1)
|
||||
|
||||
return PersonTripFormSet, TripForm
|
||||
|
||||
|
||||
@@ -232,23 +232,27 @@ class PersonExpedition(TroggleModel):
|
||||
# Single parsed entry from Logbook
|
||||
#
|
||||
class LogbookEntry(TroggleModel):
|
||||
date = models.DateField()
|
||||
expeditionday = models.ForeignKey("ExpeditionDay", null=True)
|
||||
date = models.DateField()#MJG wants to turn this into a datetime such that multiple Logbook entries on the same day can be ordered.
|
||||
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-
|
||||
author = models.ForeignKey(PersonExpedition,blank=True,null=True) # the person who writes it up doesn't have to have been on the trip.
|
||||
#author = models.ForeignKey(PersonExpedition,blank=True,null=True) # the person who writes it up doesn't have to have been on the trip.
|
||||
# Re: the above- so this field should be "typist" or something, not "author". - AC 15 jun 09
|
||||
title = models.CharField(max_length=200)
|
||||
#MJG wants to KILL THIS, as it is typically redundant with PersonTrip.is_logbook_entry_author, in the rare it was not redundanty and of actually interest it could be added to the text.
|
||||
title = models.CharField(max_length=settings.MAX_LOGBOOK_ENTRY_TITLE_LENGTH)
|
||||
cave = models.ForeignKey('Cave',blank=True,null=True)
|
||||
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)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Logbook Entries"
|
||||
verbose_name_plural = "Logbook Entries"
|
||||
# several PersonTrips point in to this object
|
||||
class Meta:
|
||||
ordering = ('-date',)
|
||||
|
||||
def isLogbookEntry(self): # Function used in templates
|
||||
return True
|
||||
|
||||
def get_absolute_url(self):
|
||||
return urlparse.urljoin(settings.URL_ROOT, reverse('logbookentry',kwargs={'date':self.date,'slug':self.slug}))
|
||||
|
||||
@@ -282,22 +286,36 @@ class LogbookEntry(TroggleModel):
|
||||
class PersonTrip(TroggleModel):
|
||||
personexpedition = models.ForeignKey("PersonExpedition",null=True)
|
||||
|
||||
expeditionday = models.ForeignKey("ExpeditionDay")
|
||||
date = models.DateField()
|
||||
#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()
|
||||
|
||||
|
||||
# sequencing by person (difficult to solve locally)
|
||||
persontrip_next = models.ForeignKey('PersonTrip', related_name='pnext', blank=True,null=True)
|
||||
persontrip_prev = models.ForeignKey('PersonTrip', related_name='pprev', blank=True,null=True)
|
||||
#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 __unicode__(self):
|
||||
return "%s (%s)" % (self.personexpedition, self.date)
|
||||
return "%s (%s)" % (self.personexpedition, self.logbook_entry.date)
|
||||
|
||||
|
||||
|
||||
@@ -350,7 +368,18 @@ class Cave(TroggleModel):
|
||||
survex_file = models.CharField(max_length=100,blank=True,null=True)
|
||||
description_file = models.CharField(max_length=200,blank=True,null=True)
|
||||
|
||||
#class Meta:
|
||||
# unique_together = (("area", "kataster_number"), ("area", "unofficial_number"))
|
||||
# FIXME Kataster Areas and CUCC defined sub areas need seperating
|
||||
|
||||
|
||||
#href = models.CharField(max_length=100)
|
||||
|
||||
def reference(self):
|
||||
if self.kataster_number:
|
||||
return "%s-%s" % (self.kat_area(), self.kataster_number)
|
||||
else:
|
||||
return "%s-%s" % (self.kat_area(), self.unofficial_number)
|
||||
|
||||
def get_absolute_url(self):
|
||||
if self.kataster_number:
|
||||
@@ -421,6 +450,14 @@ class Cave(TroggleModel):
|
||||
res += "–" + prevR
|
||||
return res
|
||||
|
||||
def getCaveByReference(reference):
|
||||
print reference
|
||||
areaname, code = reference.split("-", 1)
|
||||
area = Area.objects.get(short_name = areaname)
|
||||
foundCaves = list(Cave.objects.filter(area = area, kataster_number = code).all()) + list(Cave.objects.filter(area = area, unofficial_number = code).all())
|
||||
assert len(foundCaves) == 1
|
||||
return foundCaves[0]
|
||||
|
||||
class OtherCaveName(TroggleModel):
|
||||
name = models.CharField(max_length=160)
|
||||
cave = models.ForeignKey(Cave)
|
||||
|
||||
@@ -92,6 +92,9 @@ class SurvexBlock(models.Model):
|
||||
class Meta:
|
||||
ordering = ('id',)
|
||||
|
||||
def isSurvexBlock(self): # Function used in templates
|
||||
return True
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name and unicode(self.name) or 'no name'
|
||||
|
||||
@@ -188,4 +191,4 @@ class TunnelFile(models.Model):
|
||||
|
||||
class Meta:
|
||||
ordering = ('tunnelpath',)
|
||||
|
||||
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
from django.shortcuts import render_to_response
|
||||
from troggle.core.models import Expedition, Person, PersonExpedition, PersonTrip, LogbookEntry
|
||||
from troggle.core.models import Expedition, Person, PersonExpedition, PersonTrip, LogbookEntry, SurvexBlock
|
||||
import troggle.core.models as models
|
||||
import troggle.settings as settings
|
||||
import django.db.models
|
||||
from troggle.parsers.logbooks import LoadLogbookForExpedition
|
||||
from troggle.parsers.people import GetPersonExpeditionNameLookup
|
||||
from troggle.core.forms import PersonForm
|
||||
from troggle.core.forms import PersonForm, getTripForm
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
from django.template import Context, loader
|
||||
from utils import render_with_context
|
||||
import os.path
|
||||
import troggle.parsers.logbooks as logbookparsers
|
||||
from django.template.defaultfilters import slugify
|
||||
|
||||
|
||||
# Django uses Context, not RequestContext when you call render_to_response. We always want to use RequestContext, so that django adds the context from settings.TEMPLATE_CONTEXT_PROCESSORS. This way we automatically get necessary settings variables passed to each template. So we use a custom method, render_response instead of render_to_response. Hopefully future Django releases will make this unnecessary.
|
||||
@@ -47,18 +51,23 @@ def expedition(request, expeditionname):
|
||||
expedition = Expedition.objects.get(year=int(expeditionname))
|
||||
expeditions = Expedition.objects.all()
|
||||
personexpeditiondays = [ ]
|
||||
dateditems = list(expedition.logbookentry_set.all()) + list(expedition.survexblock_set.all())
|
||||
dates = list(set([item.date for item in dateditems]))
|
||||
dates.sort()
|
||||
for personexpedition in expedition.personexpedition_set.all():
|
||||
prow = [ ]
|
||||
for expeditionday in expedition.expeditionday_set.all():
|
||||
pcell = { "persontrips":expeditionday.persontrip_set.filter(personexpedition=personexpedition) }
|
||||
pcell["survexblocks"] = set([survexpersonrole.survexblock for survexpersonrole in expeditionday.survexpersonrole_set.filter(personexpedition=personexpedition)])
|
||||
for date in dates:
|
||||
pcell = { "persontrips": PersonTrip.objects.filter(personexpedition=personexpedition,
|
||||
logbook_entry__date=date) }
|
||||
pcell["survexblocks"] = set(SurvexBlock.objects.filter(survexpersonrole__personexpedition=personexpedition,
|
||||
date = date))
|
||||
prow.append(pcell)
|
||||
personexpeditiondays.append({"personexpedition":personexpedition, "personrow":prow})
|
||||
|
||||
message = ""
|
||||
if "reload" in request.GET:
|
||||
message = LoadLogbookForExpedition(expedition)
|
||||
return render_with_context(request,'expedition.html', {'expedition': expedition, 'expeditions':expeditions, 'personexpeditiondays':personexpeditiondays, 'message':message, 'settings':settings })
|
||||
return render_with_context(request,'expedition.html', {'expedition': expedition, 'expeditions':expeditions, 'personexpeditiondays':personexpeditiondays, 'message':message, 'settings':settings, 'dateditems': dateditems })
|
||||
|
||||
def get_absolute_url(self):
|
||||
return ('expedition', (expedition.year))
|
||||
@@ -154,3 +163,78 @@ def experimental(request):
|
||||
totalsurvexlength = sum([survexleg.tape for survexleg in survexlegs])
|
||||
return render_with_context(request, 'experimental.html', { "nsurvexlegs":len(survexlegs), "totalsurvexlength":totalsurvexlength, "legsbyexpo":legsbyexpo })
|
||||
|
||||
def newLogbookEntry(request, expeditionyear, pdate = None, pslug = None):
|
||||
expedition = Expedition.objects.get(year=expeditionyear)
|
||||
PersonTripFormSet, TripForm = getTripForm(expedition)
|
||||
if pslug and pdate:
|
||||
previousdate = datetime.date(*[int(x) for x in pdate.split("-")])
|
||||
previouslbe = LogbookEntry.objects.get(slug = pslug, date = previousdate, expedition__year = year)
|
||||
assert previouslbe.filename
|
||||
if request.method == 'POST': # If the form has been submitted...
|
||||
tripForm = TripForm(request.POST) # A form bound to the POST data
|
||||
personTripFormSet = PersonTripFormSet(request.POST)
|
||||
dateStr = tripForm.cleaned_data["date"].strftime("%Y-%m-%d")
|
||||
directory = os.path.join(settings.EXPOWEB,
|
||||
"years",
|
||||
expedition.year,
|
||||
"autologbook")
|
||||
filename = os.path.join(directory,
|
||||
dateStr + "." + slugify(tripForm.cleaned_data["title"])[:50] + ".html")
|
||||
if tripForm.is_valid() and personTripFormSet.is_valid(): # All validation rules pass
|
||||
if not os.path.isdir(directory):
|
||||
os.mkdir(directory)
|
||||
if pslug and pdate:
|
||||
delLogbookEntry(previouslbe)
|
||||
f = open(filename, "w")
|
||||
template = loader.get_template('dataformat/logbookentry.html')
|
||||
context = Context({'trip': tripForm.cleaned_data,
|
||||
'persons': personTripFormSet.cleaned_data,
|
||||
'date': dateStr,
|
||||
'expeditionyear': expeditionyear})
|
||||
f.write(template.render(context))
|
||||
f.close()
|
||||
print logbookparsers.parseAutoLogBookEntry(filename)
|
||||
return HttpResponseRedirect(reverse('expedition', args=[expedition.year])) # Redirect after POST
|
||||
else:
|
||||
if slug and date:
|
||||
if lbe.cave:
|
||||
tripForm = TripForm(date = previousdate,
|
||||
title = previouslbe.title,
|
||||
cave = previouslbe.cave.reference(),
|
||||
location = None,
|
||||
caveOrLocation = "cave",
|
||||
html = previouslbe.text)
|
||||
else:
|
||||
tripForm = TripForm(date = previousdate,
|
||||
title = previouslbe.title,
|
||||
cave = None,
|
||||
location = previouslbe.location,
|
||||
caveOrLocation = "location",
|
||||
html = previouslbe.text)
|
||||
personTripFormSet = PersonTripFormSet(initial=[{"name": py.personexpedition.name(),
|
||||
"TU": py.time_underground,
|
||||
"author": py.is_logbook_entry_author}
|
||||
for py in previouslbe.persontrip_set.all()])
|
||||
else:
|
||||
tripForm = TripForm() # An unbound form
|
||||
personTripFormSet = PersonTripFormSet()
|
||||
|
||||
return render_with_context(request, 'newlogbookentry.html', {
|
||||
'tripForm': tripForm,
|
||||
'personTripFormSet': personTripFormSet,
|
||||
|
||||
})
|
||||
|
||||
def deleteLogbookEntry(request, expeditionyear, date = None, slug = None):
|
||||
expedition = Expedition.objects.get(year=expeditionyear)
|
||||
previousdate = datetime.date(*[int(x) for x in pdate.split("-")])
|
||||
previouslbe = LogbookEntry.objects.get(slug = pslug, date = previousdate, expedition__year = year)
|
||||
delLogbookEntry(previouslbe)
|
||||
return HttpResponseRedirect(reverse('expedition', args=[expedition.year])) # Redirect after POST
|
||||
|
||||
def delLogbookEntry(lbe):
|
||||
for pt in lbe.persontrip_set.all():
|
||||
pt.delete()
|
||||
lbe.delete()
|
||||
os.delete(lbe.filename)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user