From 78cedb2070c7e9d4e4eb418ecde7b60ba428273f Mon Sep 17 00:00:00 2001 From: Wookey Date: Mon, 11 Jul 2011 02:10:22 +0100 Subject: remove all the DOS linefeeds --- core/admin.py | 282 ++++---- core/forms.py | 242 +++---- core/models.py | 1400 ++++++++++++++++++------------------ core/models_survex.py | 426 +++++------ core/templatetags/link.py | 18 +- core/templatetags/survex_markup.py | 102 +-- core/templatetags/wiki_markup.py | 338 ++++----- core/view_surveys.py | 466 ++++++------ core/views.py | 16 +- core/views_caves.py | 282 ++++---- core/views_logbooks.py | 504 ++++++------- core/views_other.py | 564 +++++++-------- core/views_survex.py | 634 ++++++++-------- 13 files changed, 2637 insertions(+), 2637 deletions(-) (limited to 'core') diff --git a/core/admin.py b/core/admin.py index be4045a..fc43f23 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,141 +1,141 @@ -from troggle.core.models import * -from django.contrib import admin -from django.forms import ModelForm -import django.forms as forms -from django.http import HttpResponse -from django.core import serializers -from core.views_other import downloadLogbook -#from troggle.reversion.admin import VersionAdmin #django-reversion version control - - -class TroggleModelAdmin(admin.ModelAdmin): - - def save_model(self, request, obj, form, change): - """overriding admin save to fill the new_since parsing_field""" - obj.new_since_parsing=True - obj.save() - - class Media: - js = ('js/jquery.js','js/QM_helper.js') - -class RoleInline(admin.TabularInline): - model = SurvexPersonRole - extra = 4 - -class SurvexBlockAdmin(TroggleModelAdmin): - inlines = (RoleInline,) - -class ScannedImageInline(admin.TabularInline): - model = ScannedImage - extra = 4 - -class OtherCaveInline(admin.TabularInline): - model = OtherCaveName - extra = 1 - -class SurveyAdmin(TroggleModelAdmin): - inlines = (ScannedImageInline,) - search_fields = ('expedition__year','wallet_number') - -class QMsFoundInline(admin.TabularInline): - model=QM - fk_name='found_by' - fields=('number','grade','location_description','comment')#need to add foreignkey to cave part - extra=1 - -class PhotoInline(admin.TabularInline): - model = DPhoto - exclude = ['is_mugshot' ] - extra = 1 - -class PersonTripInline(admin.TabularInline): - model = PersonTrip - raw_id_fields = ('personexpedition',) - extra = 1 - -#class LogbookEntryAdmin(VersionAdmin): -class LogbookEntryAdmin(TroggleModelAdmin): - prepopulated_fields = {'slug':("title",)} - raw_id_fields = ('cave',) - search_fields = ('title','expedition__year') - date_heirarchy = ('date') - inlines = (PersonTripInline, PhotoInline, QMsFoundInline) - class Media: - css = { - "all": ("css/troggleadmin.css",) - } - actions=('export_logbook_entries_as_html','export_logbook_entries_as_txt') - - def export_logbook_entries_as_html(modeladmin, request, queryset): - response=downloadLogbook(request=request, queryset=queryset, extension='html') - return response - - def export_logbook_entries_as_txt(modeladmin, request, queryset): - response=downloadLogbook(request=request, queryset=queryset, extension='txt') - return response - - - -class PersonExpeditionInline(admin.TabularInline): - model = PersonExpedition - extra = 1 - -class PersonAdmin(TroggleModelAdmin): - search_fields = ('first_name','last_name') - inlines = (PersonExpeditionInline,) - -class QMAdmin(TroggleModelAdmin): - search_fields = ('found_by__cave__kataster_number','number','found_by__date') - list_display = ('__unicode__','grade','found_by','ticked_off_by') - list_display_links = ('__unicode__',) - list_editable = ('found_by','ticked_off_by','grade') - list_per_page = 20 - raw_id_fields=('found_by','ticked_off_by') - -class PersonExpeditionAdmin(TroggleModelAdmin): - search_fields = ('person__first_name','expedition__year') - -class CaveAdmin(TroggleModelAdmin): - search_fields = ('official_name','kataster_number','unofficial_number') - inlines = (OtherCaveInline,) - extra = 4 - -class EntranceAdmin(TroggleModelAdmin): - search_fields = ('caveandentrance__cave__kataster_number',) - -admin.site.register(DPhoto) -admin.site.register(Cave, CaveAdmin) -admin.site.register(Area) -#admin.site.register(OtherCaveName) -admin.site.register(CaveAndEntrance) -admin.site.register(NewSubCave) -admin.site.register(CaveDescription) -admin.site.register(Entrance, EntranceAdmin) -admin.site.register(SurvexBlock, SurvexBlockAdmin) -admin.site.register(Expedition) -admin.site.register(Person,PersonAdmin) -admin.site.register(SurvexPersonRole) -admin.site.register(PersonExpedition,PersonExpeditionAdmin) -admin.site.register(LogbookEntry, LogbookEntryAdmin) -#admin.site.register(PersonTrip) -admin.site.register(QM, QMAdmin) -admin.site.register(Survey, SurveyAdmin) -admin.site.register(ScannedImage) - -admin.site.register(SurvexScansFolder) -admin.site.register(SurvexScanSingle) - -def export_as_json(modeladmin, request, queryset): - response = HttpResponse(mimetype="text/json") - response['Content-Disposition'] = 'attachment; filename=troggle_output.json' - serializers.serialize("json", queryset, stream=response) - return response - -def export_as_xml(modeladmin, request, queryset): - response = HttpResponse(mimetype="text/xml") - response['Content-Disposition'] = 'attachment; filename=troggle_output.xml' - serializers.serialize("xml", queryset, stream=response) - return response - -#admin.site.add_action(export_as_xml) -#admin.site.add_action(export_as_json) +from troggle.core.models import * +from django.contrib import admin +from django.forms import ModelForm +import django.forms as forms +from django.http import HttpResponse +from django.core import serializers +from core.views_other import downloadLogbook +#from troggle.reversion.admin import VersionAdmin #django-reversion version control + + +class TroggleModelAdmin(admin.ModelAdmin): + + def save_model(self, request, obj, form, change): + """overriding admin save to fill the new_since parsing_field""" + obj.new_since_parsing=True + obj.save() + + class Media: + js = ('js/jquery.js','js/QM_helper.js') + +class RoleInline(admin.TabularInline): + model = SurvexPersonRole + extra = 4 + +class SurvexBlockAdmin(TroggleModelAdmin): + inlines = (RoleInline,) + +class ScannedImageInline(admin.TabularInline): + model = ScannedImage + extra = 4 + +class OtherCaveInline(admin.TabularInline): + model = OtherCaveName + extra = 1 + +class SurveyAdmin(TroggleModelAdmin): + inlines = (ScannedImageInline,) + search_fields = ('expedition__year','wallet_number') + +class QMsFoundInline(admin.TabularInline): + model=QM + fk_name='found_by' + fields=('number','grade','location_description','comment')#need to add foreignkey to cave part + extra=1 + +class PhotoInline(admin.TabularInline): + model = DPhoto + exclude = ['is_mugshot' ] + extra = 1 + +class PersonTripInline(admin.TabularInline): + model = PersonTrip + raw_id_fields = ('personexpedition',) + extra = 1 + +#class LogbookEntryAdmin(VersionAdmin): +class LogbookEntryAdmin(TroggleModelAdmin): + prepopulated_fields = {'slug':("title",)} + raw_id_fields = ('cave',) + search_fields = ('title','expedition__year') + date_heirarchy = ('date') + inlines = (PersonTripInline, PhotoInline, QMsFoundInline) + class Media: + css = { + "all": ("css/troggleadmin.css",) + } + actions=('export_logbook_entries_as_html','export_logbook_entries_as_txt') + + def export_logbook_entries_as_html(modeladmin, request, queryset): + response=downloadLogbook(request=request, queryset=queryset, extension='html') + return response + + def export_logbook_entries_as_txt(modeladmin, request, queryset): + response=downloadLogbook(request=request, queryset=queryset, extension='txt') + return response + + + +class PersonExpeditionInline(admin.TabularInline): + model = PersonExpedition + extra = 1 + +class PersonAdmin(TroggleModelAdmin): + search_fields = ('first_name','last_name') + inlines = (PersonExpeditionInline,) + +class QMAdmin(TroggleModelAdmin): + search_fields = ('found_by__cave__kataster_number','number','found_by__date') + list_display = ('__unicode__','grade','found_by','ticked_off_by') + list_display_links = ('__unicode__',) + list_editable = ('found_by','ticked_off_by','grade') + list_per_page = 20 + raw_id_fields=('found_by','ticked_off_by') + +class PersonExpeditionAdmin(TroggleModelAdmin): + search_fields = ('person__first_name','expedition__year') + +class CaveAdmin(TroggleModelAdmin): + search_fields = ('official_name','kataster_number','unofficial_number') + inlines = (OtherCaveInline,) + extra = 4 + +class EntranceAdmin(TroggleModelAdmin): + search_fields = ('caveandentrance__cave__kataster_number',) + +admin.site.register(DPhoto) +admin.site.register(Cave, CaveAdmin) +admin.site.register(Area) +#admin.site.register(OtherCaveName) +admin.site.register(CaveAndEntrance) +admin.site.register(NewSubCave) +admin.site.register(CaveDescription) +admin.site.register(Entrance, EntranceAdmin) +admin.site.register(SurvexBlock, SurvexBlockAdmin) +admin.site.register(Expedition) +admin.site.register(Person,PersonAdmin) +admin.site.register(SurvexPersonRole) +admin.site.register(PersonExpedition,PersonExpeditionAdmin) +admin.site.register(LogbookEntry, LogbookEntryAdmin) +#admin.site.register(PersonTrip) +admin.site.register(QM, QMAdmin) +admin.site.register(Survey, SurveyAdmin) +admin.site.register(ScannedImage) + +admin.site.register(SurvexScansFolder) +admin.site.register(SurvexScanSingle) + +def export_as_json(modeladmin, request, queryset): + response = HttpResponse(mimetype="text/json") + response['Content-Disposition'] = 'attachment; filename=troggle_output.json' + serializers.serialize("json", queryset, stream=response) + return response + +def export_as_xml(modeladmin, request, queryset): + response = HttpResponse(mimetype="text/xml") + response['Content-Disposition'] = 'attachment; filename=troggle_output.xml' + serializers.serialize("xml", queryset, stream=response) + return response + +#admin.site.add_action(export_as_xml) +#admin.site.add_action(export_as_json) diff --git a/core/forms.py b/core/forms.py index ec639b0..7063f23 100644 --- a/core/forms.py +++ b/core/forms.py @@ -1,121 +1,121 @@ -from django.forms import ModelForm -from models import Cave, Person, PersonExpedition, LogbookEntry, QM, Expedition -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: -# model = Cave - -#class PersonForm(ModelForm): -# class Meta: -# model = Person - -#class LogbookEntryForm(ModelForm): -# class Meta: -# model = LogbookEntry# - -# def wikiLinkHints(LogbookEntry=None): -# """ -# This function returns html-formatted paragraphs for each of the -# wikilink types that are related to this logbookentry. Each paragraph -# contains a list of all of the related wikilinks. -# -# Perhaps an admin javascript solution would be better. -# """ -# res = ["Please use the following wikilinks, which are related to this logbook entry:"] -# -# res.append(r'

QMs found:') -# for QM in LogbookEntry.instance.QMs_found.all(): -# res.append(QM.wiki_link()) - -# res.append(r'

QMs ticked off:') -# for QM in LogbookEntry.instance.QMs_ticked_off.all(): -# res.append(QM.wiki_link()) - -# res.append(r'

People') -# for persontrip in LogbookEntry.instance.persontrip_set.all(): -# res.append(persontrip.wiki_link()) -# res.append(r'

') - -# return string.join(res, r'
') - -# def __init__(self, *args, **kwargs): -# super(LogbookEntryForm, self).__init__(*args, **kwargs) -# self.fields['text'].help_text=self.wikiLinkHints()# - -class CaveForm(forms.Form): - html = forms.CharField(widget=TinyMCE(attrs={'cols': 80, 'rows': 30})) - -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): - 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 - -def get_name(pe): - if pe.nickname: - return pe.nickname - else: - return pe.person.first_name - -class UploadFileForm(forms.Form): - title = forms.CharField(max_length=50) - file = forms.FileField() - html = forms.CharField(widget=TinyMCE(attrs={'cols': 80, 'rows': 30})) - lon_utm = forms.FloatField(required=False) - lat_utm = forms.FloatField(required=False) - slug = forms.CharField(max_length=50) - date = forms.DateField(required=False) - - caves = [cave.slug for cave in Cave.objects.all()] - caves.sort() - caves = ["-----"] + caves - cave = forms.ChoiceField([(c, c) for c in caves], required=False) - - entrance = forms.ChoiceField([("-----", "Please select a cave"), ], required=False) - qm = forms.ChoiceField([("-----", "Please select a cave"), ], required=False) - - expeditions = [e.year for e in Expedition.objects.all()] - expeditions.sort() - expeditions = ["-----"] + expeditions - expedition = forms.ChoiceField([(e, e) for e in expeditions], required=False) - - logbookentry = forms.ChoiceField([("-----", "Please select an expedition"), ], required=False) - - person = forms.ChoiceField([("-----", "Please select an expedition"), ], required=False) - - survey_point = forms.CharField() - - +from django.forms import ModelForm +from models import Cave, Person, PersonExpedition, LogbookEntry, QM, Expedition +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: +# model = Cave + +#class PersonForm(ModelForm): +# class Meta: +# model = Person + +#class LogbookEntryForm(ModelForm): +# class Meta: +# model = LogbookEntry# + +# def wikiLinkHints(LogbookEntry=None): +# """ +# This function returns html-formatted paragraphs for each of the +# wikilink types that are related to this logbookentry. Each paragraph +# contains a list of all of the related wikilinks. +# +# Perhaps an admin javascript solution would be better. +# """ +# res = ["Please use the following wikilinks, which are related to this logbook entry:"] +# +# res.append(r'

QMs found:') +# for QM in LogbookEntry.instance.QMs_found.all(): +# res.append(QM.wiki_link()) + +# res.append(r'

QMs ticked off:') +# for QM in LogbookEntry.instance.QMs_ticked_off.all(): +# res.append(QM.wiki_link()) + +# res.append(r'

People') +# for persontrip in LogbookEntry.instance.persontrip_set.all(): +# res.append(persontrip.wiki_link()) +# res.append(r'

') + +# return string.join(res, r'
') + +# def __init__(self, *args, **kwargs): +# super(LogbookEntryForm, self).__init__(*args, **kwargs) +# self.fields['text'].help_text=self.wikiLinkHints()# + +class CaveForm(forms.Form): + html = forms.CharField(widget=TinyMCE(attrs={'cols': 80, 'rows': 30})) + +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): + 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 + +def get_name(pe): + if pe.nickname: + return pe.nickname + else: + return pe.person.first_name + +class UploadFileForm(forms.Form): + title = forms.CharField(max_length=50) + file = forms.FileField() + html = forms.CharField(widget=TinyMCE(attrs={'cols': 80, 'rows': 30})) + lon_utm = forms.FloatField(required=False) + lat_utm = forms.FloatField(required=False) + slug = forms.CharField(max_length=50) + date = forms.DateField(required=False) + + caves = [cave.slug for cave in Cave.objects.all()] + caves.sort() + caves = ["-----"] + caves + cave = forms.ChoiceField([(c, c) for c in caves], required=False) + + entrance = forms.ChoiceField([("-----", "Please select a cave"), ], required=False) + qm = forms.ChoiceField([("-----", "Please select a cave"), ], required=False) + + expeditions = [e.year for e in Expedition.objects.all()] + expeditions.sort() + expeditions = ["-----"] + expeditions + expedition = forms.ChoiceField([(e, e) for e in expeditions], required=False) + + logbookentry = forms.ChoiceField([("-----", "Please select an expedition"), ], required=False) + + person = forms.ChoiceField([("-----", "Please select an expedition"), ], required=False) + + survey_point = forms.CharField() + + diff --git a/core/models.py b/core/models.py index 1c08a25..c82f448 100644 --- a/core/models.py +++ b/core/models.py @@ -1,700 +1,700 @@ -import urllib, urlparse, string, os, datetime, logging, re -from django.forms import ModelForm -from django.db import models -from django.contrib import admin -from django.core.files.storage import FileSystemStorage -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 decimal import Decimal, getcontext -from django.core.urlresolvers import reverse -from imagekit.models import ImageModel -getcontext().prec=2 #use 2 significant figures for decimal calculations - -from models_survex import * - - -def get_related_by_wikilinks(wiki_text): - found=re.findall(settings.QM_PATTERN,wiki_text) - res=[] - for wikilink in found: - qmdict={'urlroot':settings.URL_ROOT,'cave':wikilink[2],'year':wikilink[1],'number':wikilink[3]} - try: - qm=QM.objects.get(found_by__cave__kataster_number = qmdict['cave'], - found_by__date__year = qmdict['year'], - number = qmdict['number']) - res.append(qm) - except QM.DoesNotExist: - print 'fail on '+str(wikilink) - - return res - -logging.basicConfig(level=logging.DEBUG, - filename=settings.LOGFILE, - filemode='w') - -#This class is for adding fields and methods which all of our models will have. -class TroggleModel(models.Model): - new_since_parsing = models.BooleanField(default=False, editable=False) - non_public = models.BooleanField(default=False) - def object_name(self): - return self._meta.object_name - - def get_admin_url(self): - return urlparse.urljoin(settings.URL_ROOT, "/admin/core/" + self.object_name().lower() + "/" + str(self.pk)) - - class Meta: - abstract = True - -class TroggleImageModel(ImageModel): - new_since_parsing = models.BooleanField(default=False, editable=False) - - def object_name(self): - return self._meta.object_name - - def get_admin_url(self): - return urlparse.urljoin(settings.URL_ROOT, "/admin/core/" + self.object_name().lower() + "/" + str(self.pk)) - - - class Meta: - abstract = True - -# -# single Expedition, usually seen by year -# -class Expedition(TroggleModel): - year = models.CharField(max_length=20, unique=True) - name = models.CharField(max_length=100) - - def __unicode__(self): - return self.year - - class Meta: - ordering = ('-year',) - get_latest_by = 'year' - - def get_absolute_url(self): - return urlparse.urljoin(settings.URL_ROOT, reverse('expedition', args=[self.year])) - - # construction function. should be moved out - def get_expedition_day(self, date): - expeditiondays = self.expeditionday_set.filter(date=date) - if expeditiondays: - assert len(expeditiondays) == 1 - return expeditiondays[0] - res = ExpeditionDay(expedition=self, date=date) - res.save() - return res - - def day_min(self): - res = self.expeditionday_set.all() - return res and res[0] or None - - def day_max(self): - res = self.expeditionday_set.all() - return res and res[len(res) - 1] or None - - - -class ExpeditionDay(TroggleModel): - expedition = models.ForeignKey("Expedition") - date = models.DateField() - - class Meta: - ordering = ('date',) - - def GetPersonTrip(self, personexpedition): - personexpeditions = self.persontrip_set.filter(expeditionday=self) - return personexpeditions and personexpeditions[0] or None - - -# -# single Person, can go on many years -# -class Person(TroggleModel): - first_name = models.CharField(max_length=100) - last_name = models.CharField(max_length=100) - is_vfho = models.BooleanField(help_text="VFHO is the Vereines für Höhlenkunde in Obersteier, a nearby Austrian caving club.") - mug_shot = models.CharField(max_length=100, blank=True,null=True) - blurb = models.TextField(blank=True,null=True) - - #href = models.CharField(max_length=200) - orderref = models.CharField(max_length=200) # for alphabetic - - #the below have been removed and made methods. I'm not sure what the b in bisnotable stands for. - AC 16 Feb - #notability = models.FloatField() # for listing the top 20 people - #bisnotable = models.BooleanField() - user = models.OneToOneField(User, null=True, blank=True) - def get_absolute_url(self): - return urlparse.urljoin(settings.URL_ROOT,reverse('person',kwargs={'first_name':self.first_name,'last_name':self.last_name})) - - class Meta: - verbose_name_plural = "People" - class Meta: - ordering = ('orderref',) # "Wookey" makes too complex for: ('last_name', 'first_name') - - def __unicode__(self): - if self.last_name: - return "%s %s" % (self.first_name, self.last_name) - return self.first_name - - - def notability(self): - notability = Decimal(0) - for personexpedition in self.personexpedition_set.all(): - if not personexpedition.is_guest: - notability += Decimal(1) / (2012 - int(personexpedition.expedition.year)) - return notability - - def bisnotable(self): - return self.notability() > Decimal(1)/Decimal(3) - - def surveyedleglength(self): - return sum([personexpedition.surveyedleglength() for personexpedition in self.personexpedition_set.all()]) - - def first(self): - return self.personexpedition_set.order_by('-expedition')[0] - def last(self): - return self.personexpedition_set.order_by('expedition')[0] - - #def Sethref(self): - #if self.last_name: - #self.href = self.first_name.lower() + "_" + self.last_name.lower() - #self.orderref = self.last_name + " " + self.first_name - #else: - # self.href = self.first_name.lower() - #self.orderref = self.first_name - #self.notability = 0.0 # set temporarily - - -# -# Person's attenance to one Expo -# -class PersonExpedition(TroggleModel): - expedition = models.ForeignKey(Expedition) - person = models.ForeignKey(Person) - slugfield = models.SlugField(max_length=50,blank=True,null=True) - - is_guest = models.BooleanField(default=False) - COMMITTEE_CHOICES = ( - ('leader','Expo leader'), - ('medical','Expo medical officer'), - ('treasurer','Expo treasurer'), - ('sponsorship','Expo sponsorship coordinator'), - ('research','Expo research coordinator'), - ) - expo_committee_position = models.CharField(blank=True,null=True,choices=COMMITTEE_CHOICES,max_length=200) - nickname = models.CharField(max_length=100,blank=True,null=True) - - def GetPersonroles(self): - res = [ ] - for personrole in self.personrole_set.order_by('survexblock'): - if res and res[-1]['survexpath'] == personrole.survexblock.survexpath: - res[-1]['roles'] += ", " + str(personrole.role) - else: - res.append({'date':personrole.survexblock.date, 'survexpath':personrole.survexblock.survexpath, 'roles':str(personrole.role)}) - return res - - class Meta: - ordering = ('-expedition',) - #order_with_respect_to = 'expedition' - - def __unicode__(self): - return "%s: (%s)" % (self.person, self.expedition) - - - #why is the below a function in personexpedition, rather than in person? - AC 14 Feb 09 - def name(self): - if self.nickname: - return "%s (%s) %s" % (self.person.first_name, self.nickname, self.person.last_name) - if self.person.last_name: - return "%s %s" % (self.person.first_name, self.person.last_name) - return self.person.first_name - - def get_absolute_url(self): - return urlparse.urljoin(settings.URL_ROOT, reverse('personexpedition',kwargs={'first_name':self.person.first_name,'last_name':self.person.last_name,'year':self.expedition.year})) - - def surveyedleglength(self): - survexblocks = [personrole.survexblock for personrole in self.personrole_set.all() ] - return sum([survexblock.totalleglength for survexblock in set(survexblocks)]) - - # would prefer to return actual person trips so we could link to first and last ones - def day_min(self): - res = self.persontrip_set.aggregate(day_min=Min("expeditionday__date")) - return res["day_min"] - - def day_max(self): - res = self.persontrip_set.all().aggregate(day_max=Max("expeditionday__date")) - return res["day_max"] - -# -# Single parsed entry from Logbook -# -class LogbookEntry(TroggleModel): - 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. - # Re: the above- so this field should be "typist" or something, not "author". - AC 15 jun 09 - #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" - # several PersonTrips point in to this object - 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})) - - def __unicode__(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() - - - # 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 __unicode__(self): - return "%s (%s)" % (self.personexpedition, self.logbook_entry.date) - - - -########################################## -# move following classes into models_cave -########################################## - -class Area(TroggleModel): - short_name = models.CharField(max_length=100) - name = models.CharField(max_length=200, blank=True, null=True) - description = models.TextField(blank=True,null=True) - parent = models.ForeignKey('Area', blank=True, null=True) - def __unicode__(self): - if self.parent: - return unicode(self.parent) + u" - " + unicode(self.short_name) - else: - return unicode(self.short_name) - def kat_area(self): - if self.short_name in ["1623", "1626"]: - return self.short_name - elif self.parent: - return self.parent.kat_area() - -class CaveAndEntrance(TroggleModel): - cave = models.ForeignKey('Cave') - entrance = models.ForeignKey('Entrance') - entrance_letter = models.CharField(max_length=20,blank=True,null=True) - def __unicode__(self): - return unicode(self.cave) + unicode(self.entrance_letter) - -class Cave(TroggleModel): - # too much here perhaps - slug = models.SlugField(max_length=50, unique = True) - official_name = models.CharField(max_length=160) - area = models.ManyToManyField(Area, blank=True, null=True) - kataster_code = models.CharField(max_length=20,blank=True,null=True) - kataster_number = models.CharField(max_length=10,blank=True, null=True) - unofficial_number = models.CharField(max_length=60,blank=True, null=True) - entrances = models.ManyToManyField('Entrance', through='CaveAndEntrance') - explorers = models.TextField(blank=True,null=True) - underground_description = models.TextField(blank=True,null=True) - equipment = models.TextField(blank=True,null=True) - references = models.TextField(blank=True,null=True) - survey = models.TextField(blank=True,null=True) - kataster_status = models.TextField(blank=True,null=True) - underground_centre_line = models.TextField(blank=True,null=True) - notes = models.TextField(blank=True,null=True) - length = models.CharField(max_length=100,blank=True,null=True) - depth = models.CharField(max_length=100,blank=True,null=True) - extent = models.CharField(max_length=100,blank=True,null=True) - survex_file = models.CharField(max_length=100,blank=True,null=True) - description_file = models.CharField(max_length=200,blank=True,null=True) - url = 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: - href = self.kataster_number - elif self.unofficial_number: - href = self.unofficial_number - else: - href = official_name.lower() - #return settings.URL_ROOT + '/cave/' + href + '/' - return urlparse.urljoin(settings.URL_ROOT, reverse('cave',kwargs={'cave_id':href,})) - - def __unicode__(self): - if self.kataster_number: - if self.kat_area(): - return self.kat_area() + u": " + self.kataster_number - else: - return unicode("l") + u": " + self.kataster_number - else: - if self.kat_area(): - return self.kat_area() + u": " + self.unofficial_number - else: - return self.unofficial_number - - def get_QMs(self): - return QM.objects.filter(found_by__cave=self) - - def new_QM_number(self, year=datetime.date.today().year): - """Given a cave and the current year, returns the next QM number.""" - try: - res=QM.objects.filter(found_by__date__year=year, found_by__cave=self).order_by('-number')[0] - except IndexError: - return 1 - return res.number+1 - - def kat_area(self): - for a in self.area.all(): - if a.kat_area(): - return a.kat_area() - - def entrances(self): - return CaveAndEntrance.objects.filter(cave=self) - - def entrancelist(self): - rs = [] - res = "" - for e in CaveAndEntrance.objects.filter(cave=self): - rs.append(e.entrance_letter) - rs.sort() - prevR = None - n = 0 - for r in rs: - if prevR: - if chr(ord(prevR) + 1 ) == r: - prevR = r - n += 1 - else: - if n == 0: - res += ", " + prevR - else: - res += "–" + prevR - else: - prevR = r - n = 0 - res += r - if n == 0: - res += ", " + prevR - else: - res += "–" + prevR - return res - -def getCaveByReference(reference): - areaname, code = reference.split("-", 1) - print areaname, code - area = Area.objects.get(short_name = areaname) - print area - foundCaves = list(Cave.objects.filter(area = area, kataster_number = code).all()) + list(Cave.objects.filter(area = area, unofficial_number = code).all()) - print list(foundCaves) - assert len(foundCaves) == 1 - return foundCaves[0] - -class OtherCaveName(TroggleModel): - name = models.CharField(max_length=160) - cave = models.ForeignKey(Cave) - def __unicode__(self): - return unicode(self.name) - - -class Entrance(TroggleModel): - slug = models.SlugField(max_length=50, unique = True) - name = models.CharField(max_length=100, blank=True,null=True) - entrance_description = models.TextField(blank=True,null=True) - explorers = models.TextField(blank=True,null=True) - map_description = models.TextField(blank=True,null=True) - location_description = models.TextField(blank=True,null=True) - approach = models.TextField(blank=True,null=True) - underground_description = models.TextField(blank=True,null=True) - photo = models.TextField(blank=True,null=True) - MARKING_CHOICES = ( - ('P', 'Paint'), - ('P?', 'Paint (?)'), - ('T', 'Tag'), - ('T?', 'Tag (?)'), - ('R', 'Retagged'), - ('S', 'Spit'), - ('S?', 'Spit (?)'), - ('U', 'Unmarked'), - ('?', 'Unknown')) - marking = models.CharField(max_length=2, choices=MARKING_CHOICES) - marking_comment = models.TextField(blank=True,null=True) - FINDABLE_CHOICES = ( - ('?', 'To be confirmed ...'), - ('S', 'Surveyed'), - ('L', 'Lost'), - ('R', 'Refindable')) - findability = models.CharField(max_length=1, choices=FINDABLE_CHOICES, blank=True, null=True) - findability_description = models.TextField(blank=True,null=True) - alt = models.TextField(blank=True, null=True) - northing = models.TextField(blank=True, null=True) - easting = models.TextField(blank=True, null=True) - tag_station = models.TextField() - exact_station = models.TextField() - other_station = models.TextField() - other_description = models.TextField(blank=True,null=True) - bearings = models.TextField(blank=True,null=True) - def __unicode__(self): - a = CaveAndEntrance.objects.filter(entrance = self) - name = u'' - if self.name: - name = unicode(self.name) + u' ' - if len(a) == 1: - return name + unicode(a[0]) - return name + unicode(a) - def marking_val(self): - for m in self.MARKING_CHOICES: - if m[0] == self.marking: - return m[1] - def findability_val(self): - for f in self.FINDABLE_CHOICES: - if f[0] == self.findability: - return f[1] - - - def get_absolute_url(self): - - ancestor_titles='/'.join([subcave.title for subcave in self.get_ancestors()]) - if ancestor_titles: - res = '/'.join((self.get_root().cave.get_absolute_url(), ancestor_titles, self.title)) - - else: - res = '/'.join((self.get_root().cave.get_absolute_url(), self.title)) - - return res - -class CaveDescription(TroggleModel): - short_name = models.CharField(max_length=50, unique = True) - long_name = models.CharField(max_length=200, blank=True, null=True) - description = models.TextField(blank=True,null=True) - linked_subcaves = models.ManyToManyField("NewSubCave", blank=True,null=True) - linked_entrances = models.ManyToManyField("Entrance", blank=True,null=True) - linked_qms = models.ManyToManyField("QM", blank=True,null=True) - - def __unicode__(self): - if self.long_name: - return unicode(self.long_name) - else: - return unicode(self.short_name) - - def get_absolute_url(self): - return urlparse.urljoin(settings.URL_ROOT, reverse('cavedescription', args=(self.short_name,))) - - def save(self): - """ - Overridden save method which stores wikilinks in text as links in database. - """ - super(CaveDescription, self).save() - qm_list=get_related_by_wikilinks(self.description) - for qm in qm_list: - self.linked_qms.add(qm) - super(CaveDescription, self).save() - -class NewSubCave(TroggleModel): - name = models.CharField(max_length=200, unique = True) - def __unicode__(self): - return unicode(self.name) - -class QM(TroggleModel): - #based on qm.csv in trunk/expoweb/smkridge/204 which has the fields: - #"Number","Grade","Area","Description","Page reference","Nearest station","Completion description","Comment" - found_by = models.ForeignKey(LogbookEntry, related_name='QMs_found',blank=True, null=True ) - ticked_off_by = models.ForeignKey(LogbookEntry, related_name='QMs_ticked_off',null=True,blank=True) - #cave = models.ForeignKey(Cave) - #expedition = models.ForeignKey(Expedition) - - number = models.IntegerField(help_text="this is the sequential number in the year", ) - GRADE_CHOICES=( - ('A', 'A: Large obvious lead'), - ('B', 'B: Average lead'), - ('C', 'C: Tight unpromising lead'), - ('D', 'D: Dig'), - ('X', 'X: Unclimbable aven') - ) - grade = models.CharField(max_length=1, choices=GRADE_CHOICES) - location_description = models.TextField(blank=True) - #should be a foreignkey to surveystation - nearest_station_description = models.CharField(max_length=400,null=True,blank=True) - nearest_station = models.CharField(max_length=200,blank=True,null=True) - area = models.CharField(max_length=100,blank=True,null=True) - completion_description = models.TextField(blank=True,null=True) - comment=models.TextField(blank=True,null=True) - - def __unicode__(self): - return u"%s %s" % (self.code(), self.grade) - - def code(self): - return u"%s-%s-%s" % (unicode(self.found_by.cave)[6:], self.found_by.date.year, self.number) - - def get_absolute_url(self): - #return settings.URL_ROOT + '/cave/' + self.found_by.cave.kataster_number + '/' + str(self.found_by.date.year) + '-' + '%02d' %self.number - return urlparse.urljoin(settings.URL_ROOT, reverse('qm',kwargs={'cave_id':self.found_by.cave.kataster_number,'year':self.found_by.date.year,'qm_id':self.number,'grade':self.grade})) - - def get_next_by_id(self): - return QM.objects.get(id=self.id+1) - - def get_previous_by_id(self): - return QM.objects.get(id=self.id-1) - - def wiki_link(self): - return u"%s%s%s" % ('[[QM:',self.code(),']]') - -photoFileStorage = FileSystemStorage(location=settings.PHOTOS_ROOT, base_url=settings.PHOTOS_URL) -class DPhoto(TroggleImageModel): - caption = models.CharField(max_length=1000,blank=True,null=True) - contains_logbookentry = models.ForeignKey(LogbookEntry,blank=True,null=True) - contains_person = models.ManyToManyField(Person,blank=True,null=True) - file = models.ImageField(storage=photoFileStorage, upload_to='.',) - is_mugshot = models.BooleanField(default=False) - contains_cave = models.ForeignKey(Cave,blank=True,null=True) - contains_entrance = models.ForeignKey(Entrance, related_name="photo_file",blank=True,null=True) - #nearest_survey_point = models.ForeignKey(SurveyStation,blank=True,null=True) - nearest_QM = models.ForeignKey(QM,blank=True,null=True) - lon_utm = models.FloatField(blank=True,null=True) - lat_utm = models.FloatField(blank=True,null=True) - - class IKOptions: - spec_module = 'core.imagekit_specs' - cache_dir = 'thumbs' - image_field = 'file' - - #content_type = models.ForeignKey(ContentType) - #object_id = models.PositiveIntegerField() - #location = generic.GenericForeignKey('content_type', 'object_id') - - def __unicode__(self): - return self.caption - -scansFileStorage = FileSystemStorage(location=settings.SURVEY_SCANS, base_url=settings.SURVEYS_URL) -def get_scan_path(instance, filename): - year=instance.survey.expedition.year - print "WN: ", type(instance.survey.wallet_number), instance.survey.wallet_number - number="%02d" % instance.survey.wallet_number + str(instance.survey.wallet_letter) #using %02d string formatting because convention was 2009#01 - return os.path.join('./',year,year+r'#'+number,instance.contents+str(instance.number_in_wallet)+r'.jpg') - -class ScannedImage(TroggleImageModel): - file = models.ImageField(storage=scansFileStorage, upload_to=get_scan_path) - scanned_by = models.ForeignKey(Person,blank=True, null=True) - scanned_on = models.DateField(null=True) - survey = models.ForeignKey('Survey') - contents = models.CharField(max_length=20,choices=(('notes','notes'),('plan','plan_sketch'),('elevation','elevation_sketch'))) - number_in_wallet = models.IntegerField(null=True) - lon_utm = models.FloatField(blank=True,null=True) - lat_utm = models.FloatField(blank=True,null=True) - - class IKOptions: - spec_module = 'core.imagekit_specs' - cache_dir = 'thumbs' - image_field = 'file' - #content_type = models.ForeignKey(ContentType) - #object_id = models.PositiveIntegerField() - #location = generic.GenericForeignKey('content_type', 'object_id') - - #This is an ugly hack to deal with the #s in our survey scan paths. The correct thing is to write a custom file storage backend which calls urlencode on the name for making file.url but not file.path. - def correctURL(self): - return string.replace(self.file.url,r'#',r'%23') - - def __unicode__(self): - return get_scan_path(self,'') - -class Survey(TroggleModel): - expedition = models.ForeignKey('Expedition') #REDUNDANT (logbook_entry) - wallet_number = models.IntegerField(blank=True,null=True) - wallet_letter = models.CharField(max_length=1,blank=True,null=True) - comments = models.TextField(blank=True,null=True) - location = models.CharField(max_length=400,blank=True,null=True) #REDUNDANT - subcave = models.ForeignKey('NewSubCave', blank=True, null=True) - #notes_scan = models.ForeignKey('ScannedImage',related_name='notes_scan',blank=True, null=True) #Replaced by contents field of ScannedImage model - survex_block = models.OneToOneField('SurvexBlock',blank=True, null=True) - logbook_entry = models.ForeignKey('LogbookEntry') - centreline_printed_on = models.DateField(blank=True, null=True) - centreline_printed_by = models.ForeignKey('Person',related_name='centreline_printed_by',blank=True,null=True) - #sketch_scan = models.ForeignKey(ScannedImage,blank=True, null=True) #Replaced by contents field of ScannedImage model - tunnel_file = models.FileField(upload_to='surveyXMLfiles',blank=True, null=True) - tunnel_main_sketch = models.ForeignKey('Survey',blank=True,null=True) - integrated_into_main_sketch_on = models.DateField(blank=True,null=True) - integrated_into_main_sketch_by = models.ForeignKey('Person' ,related_name='integrated_into_main_sketch_by', blank=True,null=True) - rendered_image = models.ImageField(upload_to='renderedSurveys',blank=True,null=True) - def __unicode__(self): - return self.expedition.year+"#"+"%02d" % int(self.wallet_number) - - def notes(self): - return self.scannedimage_set.filter(contents='notes') - - def plans(self): - return self.scannedimage_set.filter(contents='plan') - - def elevations(self): - return self.scannedimage_set.filter(contents='elevation') +import urllib, urlparse, string, os, datetime, logging, re +from django.forms import ModelForm +from django.db import models +from django.contrib import admin +from django.core.files.storage import FileSystemStorage +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 decimal import Decimal, getcontext +from django.core.urlresolvers import reverse +from imagekit.models import ImageModel +getcontext().prec=2 #use 2 significant figures for decimal calculations + +from models_survex import * + + +def get_related_by_wikilinks(wiki_text): + found=re.findall(settings.QM_PATTERN,wiki_text) + res=[] + for wikilink in found: + qmdict={'urlroot':settings.URL_ROOT,'cave':wikilink[2],'year':wikilink[1],'number':wikilink[3]} + try: + qm=QM.objects.get(found_by__cave__kataster_number = qmdict['cave'], + found_by__date__year = qmdict['year'], + number = qmdict['number']) + res.append(qm) + except QM.DoesNotExist: + print 'fail on '+str(wikilink) + + return res + +logging.basicConfig(level=logging.DEBUG, + filename=settings.LOGFILE, + filemode='w') + +#This class is for adding fields and methods which all of our models will have. +class TroggleModel(models.Model): + new_since_parsing = models.BooleanField(default=False, editable=False) + non_public = models.BooleanField(default=False) + def object_name(self): + return self._meta.object_name + + def get_admin_url(self): + return urlparse.urljoin(settings.URL_ROOT, "/admin/core/" + self.object_name().lower() + "/" + str(self.pk)) + + class Meta: + abstract = True + +class TroggleImageModel(ImageModel): + new_since_parsing = models.BooleanField(default=False, editable=False) + + def object_name(self): + return self._meta.object_name + + def get_admin_url(self): + return urlparse.urljoin(settings.URL_ROOT, "/admin/core/" + self.object_name().lower() + "/" + str(self.pk)) + + + class Meta: + abstract = True + +# +# single Expedition, usually seen by year +# +class Expedition(TroggleModel): + year = models.CharField(max_length=20, unique=True) + name = models.CharField(max_length=100) + + def __unicode__(self): + return self.year + + class Meta: + ordering = ('-year',) + get_latest_by = 'year' + + def get_absolute_url(self): + return urlparse.urljoin(settings.URL_ROOT, reverse('expedition', args=[self.year])) + + # construction function. should be moved out + def get_expedition_day(self, date): + expeditiondays = self.expeditionday_set.filter(date=date) + if expeditiondays: + assert len(expeditiondays) == 1 + return expeditiondays[0] + res = ExpeditionDay(expedition=self, date=date) + res.save() + return res + + def day_min(self): + res = self.expeditionday_set.all() + return res and res[0] or None + + def day_max(self): + res = self.expeditionday_set.all() + return res and res[len(res) - 1] or None + + + +class ExpeditionDay(TroggleModel): + expedition = models.ForeignKey("Expedition") + date = models.DateField() + + class Meta: + ordering = ('date',) + + def GetPersonTrip(self, personexpedition): + personexpeditions = self.persontrip_set.filter(expeditionday=self) + return personexpeditions and personexpeditions[0] or None + + +# +# single Person, can go on many years +# +class Person(TroggleModel): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + is_vfho = models.BooleanField(help_text="VFHO is the Vereines für Höhlenkunde in Obersteier, a nearby Austrian caving club.") + mug_shot = models.CharField(max_length=100, blank=True,null=True) + blurb = models.TextField(blank=True,null=True) + + #href = models.CharField(max_length=200) + orderref = models.CharField(max_length=200) # for alphabetic + + #the below have been removed and made methods. I'm not sure what the b in bisnotable stands for. - AC 16 Feb + #notability = models.FloatField() # for listing the top 20 people + #bisnotable = models.BooleanField() + user = models.OneToOneField(User, null=True, blank=True) + def get_absolute_url(self): + return urlparse.urljoin(settings.URL_ROOT,reverse('person',kwargs={'first_name':self.first_name,'last_name':self.last_name})) + + class Meta: + verbose_name_plural = "People" + class Meta: + ordering = ('orderref',) # "Wookey" makes too complex for: ('last_name', 'first_name') + + def __unicode__(self): + if self.last_name: + return "%s %s" % (self.first_name, self.last_name) + return self.first_name + + + def notability(self): + notability = Decimal(0) + for personexpedition in self.personexpedition_set.all(): + if not personexpedition.is_guest: + notability += Decimal(1) / (2012 - int(personexpedition.expedition.year)) + return notability + + def bisnotable(self): + return self.notability() > Decimal(1)/Decimal(3) + + def surveyedleglength(self): + return sum([personexpedition.surveyedleglength() for personexpedition in self.personexpedition_set.all()]) + + def first(self): + return self.personexpedition_set.order_by('-expedition')[0] + def last(self): + return self.personexpedition_set.order_by('expedition')[0] + + #def Sethref(self): + #if self.last_name: + #self.href = self.first_name.lower() + "_" + self.last_name.lower() + #self.orderref = self.last_name + " " + self.first_name + #else: + # self.href = self.first_name.lower() + #self.orderref = self.first_name + #self.notability = 0.0 # set temporarily + + +# +# Person's attenance to one Expo +# +class PersonExpedition(TroggleModel): + expedition = models.ForeignKey(Expedition) + person = models.ForeignKey(Person) + slugfield = models.SlugField(max_length=50,blank=True,null=True) + + is_guest = models.BooleanField(default=False) + COMMITTEE_CHOICES = ( + ('leader','Expo leader'), + ('medical','Expo medical officer'), + ('treasurer','Expo treasurer'), + ('sponsorship','Expo sponsorship coordinator'), + ('research','Expo research coordinator'), + ) + expo_committee_position = models.CharField(blank=True,null=True,choices=COMMITTEE_CHOICES,max_length=200) + nickname = models.CharField(max_length=100,blank=True,null=True) + + def GetPersonroles(self): + res = [ ] + for personrole in self.personrole_set.order_by('survexblock'): + if res and res[-1]['survexpath'] == personrole.survexblock.survexpath: + res[-1]['roles'] += ", " + str(personrole.role) + else: + res.append({'date':personrole.survexblock.date, 'survexpath':personrole.survexblock.survexpath, 'roles':str(personrole.role)}) + return res + + class Meta: + ordering = ('-expedition',) + #order_with_respect_to = 'expedition' + + def __unicode__(self): + return "%s: (%s)" % (self.person, self.expedition) + + + #why is the below a function in personexpedition, rather than in person? - AC 14 Feb 09 + def name(self): + if self.nickname: + return "%s (%s) %s" % (self.person.first_name, self.nickname, self.person.last_name) + if self.person.last_name: + return "%s %s" % (self.person.first_name, self.person.last_name) + return self.person.first_name + + def get_absolute_url(self): + return urlparse.urljoin(settings.URL_ROOT, reverse('personexpedition',kwargs={'first_name':self.person.first_name,'last_name':self.person.last_name,'year':self.expedition.year})) + + def surveyedleglength(self): + survexblocks = [personrole.survexblock for personrole in self.personrole_set.all() ] + return sum([survexblock.totalleglength for survexblock in set(survexblocks)]) + + # would prefer to return actual person trips so we could link to first and last ones + def day_min(self): + res = self.persontrip_set.aggregate(day_min=Min("expeditionday__date")) + return res["day_min"] + + def day_max(self): + res = self.persontrip_set.all().aggregate(day_max=Max("expeditionday__date")) + return res["day_max"] + +# +# Single parsed entry from Logbook +# +class LogbookEntry(TroggleModel): + 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. + # Re: the above- so this field should be "typist" or something, not "author". - AC 15 jun 09 + #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" + # several PersonTrips point in to this object + 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})) + + def __unicode__(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() + + + # 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 __unicode__(self): + return "%s (%s)" % (self.personexpedition, self.logbook_entry.date) + + + +########################################## +# move following classes into models_cave +########################################## + +class Area(TroggleModel): + short_name = models.CharField(max_length=100) + name = models.CharField(max_length=200, blank=True, null=True) + description = models.TextField(blank=True,null=True) + parent = models.ForeignKey('Area', blank=True, null=True) + def __unicode__(self): + if self.parent: + return unicode(self.parent) + u" - " + unicode(self.short_name) + else: + return unicode(self.short_name) + def kat_area(self): + if self.short_name in ["1623", "1626"]: + return self.short_name + elif self.parent: + return self.parent.kat_area() + +class CaveAndEntrance(TroggleModel): + cave = models.ForeignKey('Cave') + entrance = models.ForeignKey('Entrance') + entrance_letter = models.CharField(max_length=20,blank=True,null=True) + def __unicode__(self): + return unicode(self.cave) + unicode(self.entrance_letter) + +class Cave(TroggleModel): + # too much here perhaps + slug = models.SlugField(max_length=50, unique = True) + official_name = models.CharField(max_length=160) + area = models.ManyToManyField(Area, blank=True, null=True) + kataster_code = models.CharField(max_length=20,blank=True,null=True) + kataster_number = models.CharField(max_length=10,blank=True, null=True) + unofficial_number = models.CharField(max_length=60,blank=True, null=True) + entrances = models.ManyToManyField('Entrance', through='CaveAndEntrance') + explorers = models.TextField(blank=True,null=True) + underground_description = models.TextField(blank=True,null=True) + equipment = models.TextField(blank=True,null=True) + references = models.TextField(blank=True,null=True) + survey = models.TextField(blank=True,null=True) + kataster_status = models.TextField(blank=True,null=True) + underground_centre_line = models.TextField(blank=True,null=True) + notes = models.TextField(blank=True,null=True) + length = models.CharField(max_length=100,blank=True,null=True) + depth = models.CharField(max_length=100,blank=True,null=True) + extent = models.CharField(max_length=100,blank=True,null=True) + survex_file = models.CharField(max_length=100,blank=True,null=True) + description_file = models.CharField(max_length=200,blank=True,null=True) + url = 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: + href = self.kataster_number + elif self.unofficial_number: + href = self.unofficial_number + else: + href = official_name.lower() + #return settings.URL_ROOT + '/cave/' + href + '/' + return urlparse.urljoin(settings.URL_ROOT, reverse('cave',kwargs={'cave_id':href,})) + + def __unicode__(self): + if self.kataster_number: + if self.kat_area(): + return self.kat_area() + u": " + self.kataster_number + else: + return unicode("l") + u": " + self.kataster_number + else: + if self.kat_area(): + return self.kat_area() + u": " + self.unofficial_number + else: + return self.unofficial_number + + def get_QMs(self): + return QM.objects.filter(found_by__cave=self) + + def new_QM_number(self, year=datetime.date.today().year): + """Given a cave and the current year, returns the next QM number.""" + try: + res=QM.objects.filter(found_by__date__year=year, found_by__cave=self).order_by('-number')[0] + except IndexError: + return 1 + return res.number+1 + + def kat_area(self): + for a in self.area.all(): + if a.kat_area(): + return a.kat_area() + + def entrances(self): + return CaveAndEntrance.objects.filter(cave=self) + + def entrancelist(self): + rs = [] + res = "" + for e in CaveAndEntrance.objects.filter(cave=self): + rs.append(e.entrance_letter) + rs.sort() + prevR = None + n = 0 + for r in rs: + if prevR: + if chr(ord(prevR) + 1 ) == r: + prevR = r + n += 1 + else: + if n == 0: + res += ", " + prevR + else: + res += "–" + prevR + else: + prevR = r + n = 0 + res += r + if n == 0: + res += ", " + prevR + else: + res += "–" + prevR + return res + +def getCaveByReference(reference): + areaname, code = reference.split("-", 1) + print areaname, code + area = Area.objects.get(short_name = areaname) + print area + foundCaves = list(Cave.objects.filter(area = area, kataster_number = code).all()) + list(Cave.objects.filter(area = area, unofficial_number = code).all()) + print list(foundCaves) + assert len(foundCaves) == 1 + return foundCaves[0] + +class OtherCaveName(TroggleModel): + name = models.CharField(max_length=160) + cave = models.ForeignKey(Cave) + def __unicode__(self): + return unicode(self.name) + + +class Entrance(TroggleModel): + slug = models.SlugField(max_length=50, unique = True) + name = models.CharField(max_length=100, blank=True,null=True) + entrance_description = models.TextField(blank=True,null=True) + explorers = models.TextField(blank=True,null=True) + map_description = models.TextField(blank=True,null=True) + location_description = models.TextField(blank=True,null=True) + approach = models.TextField(blank=True,null=True) + underground_description = models.TextField(blank=True,null=True) + photo = models.TextField(blank=True,null=True) + MARKING_CHOICES = ( + ('P', 'Paint'), + ('P?', 'Paint (?)'), + ('T', 'Tag'), + ('T?', 'Tag (?)'), + ('R', 'Retagged'), + ('S', 'Spit'), + ('S?', 'Spit (?)'), + ('U', 'Unmarked'), + ('?', 'Unknown')) + marking = models.CharField(max_length=2, choices=MARKING_CHOICES) + marking_comment = models.TextField(blank=True,null=True) + FINDABLE_CHOICES = ( + ('?', 'To be confirmed ...'), + ('S', 'Surveyed'), + ('L', 'Lost'), + ('R', 'Refindable')) + findability = models.CharField(max_length=1, choices=FINDABLE_CHOICES, blank=True, null=True) + findability_description = models.TextField(blank=True,null=True) + alt = models.TextField(blank=True, null=True) + northing = models.TextField(blank=True, null=True) + easting = models.TextField(blank=True, null=True) + tag_station = models.TextField() + exact_station = models.TextField() + other_station = models.TextField() + other_description = models.TextField(blank=True,null=True) + bearings = models.TextField(blank=True,null=True) + def __unicode__(self): + a = CaveAndEntrance.objects.filter(entrance = self) + name = u'' + if self.name: + name = unicode(self.name) + u' ' + if len(a) == 1: + return name + unicode(a[0]) + return name + unicode(a) + def marking_val(self): + for m in self.MARKING_CHOICES: + if m[0] == self.marking: + return m[1] + def findability_val(self): + for f in self.FINDABLE_CHOICES: + if f[0] == self.findability: + return f[1] + + + def get_absolute_url(self): + + ancestor_titles='/'.join([subcave.title for subcave in self.get_ancestors()]) + if ancestor_titles: + res = '/'.join((self.get_root().cave.get_absolute_url(), ancestor_titles, self.title)) + + else: + res = '/'.join((self.get_root().cave.get_absolute_url(), self.title)) + + return res + +class CaveDescription(TroggleModel): + short_name = models.CharField(max_length=50, unique = True) + long_name = models.CharField(max_length=200, blank=True, null=True) + description = models.TextField(blank=True,null=True) + linked_subcaves = models.ManyToManyField("NewSubCave", blank=True,null=True) + linked_entrances = models.ManyToManyField("Entrance", blank=True,null=True) + linked_qms = models.ManyToManyField("QM", blank=True,null=True) + + def __unicode__(self): + if self.long_name: + return unicode(self.long_name) + else: + return unicode(self.short_name) + + def get_absolute_url(self): + return urlparse.urljoin(settings.URL_ROOT, reverse('cavedescription', args=(self.short_name,))) + + def save(self): + """ + Overridden save method which stores wikilinks in text as links in database. + """ + super(CaveDescription, self).save() + qm_list=get_related_by_wikilinks(self.description) + for qm in qm_list: + self.linked_qms.add(qm) + super(CaveDescription, self).save() + +class NewSubCave(TroggleModel): + name = models.CharField(max_length=200, unique = True) + def __unicode__(self): + return unicode(self.name) + +class QM(TroggleModel): + #based on qm.csv in trunk/expoweb/smkridge/204 which has the fields: + #"Number","Grade","Area","Description","Page reference","Nearest station","Completion description","Comment" + found_by = models.ForeignKey(LogbookEntry, related_name='QMs_found',blank=True, null=True ) + ticked_off_by = models.ForeignKey(LogbookEntry, related_name='QMs_ticked_off',null=True,blank=True) + #cave = models.ForeignKey(Cave) + #expedition = models.ForeignKey(Expedition) + + number = models.IntegerField(help_text="this is the sequential number in the year", ) + GRADE_CHOICES=( + ('A', 'A: Large obvious lead'), + ('B', 'B: Average lead'), + ('C', 'C: Tight unpromising lead'), + ('D', 'D: Dig'), + ('X', 'X: Unclimbable aven') + ) + grade = models.CharField(max_length=1, choices=GRADE_CHOICES) + location_description = models.TextField(blank=True) + #should be a foreignkey to surveystation + nearest_station_description = models.CharField(max_length=400,null=True,blank=True) + nearest_station = models.CharField(max_length=200,blank=True,null=True) + area = models.CharField(max_length=100,blank=True,null=True) + completion_description = models.TextField(blank=True,null=True) + comment=models.TextField(blank=True,null=True) + + def __unicode__(self): + return u"%s %s" % (self.code(), self.grade) + + def code(self): + return u"%s-%s-%s" % (unicode(self.found_by.cave)[6:], self.found_by.date.year, self.number) + + def get_absolute_url(self): + #return settings.URL_ROOT + '/cave/' + self.found_by.cave.kataster_number + '/' + str(self.found_by.date.year) + '-' + '%02d' %self.number + return urlparse.urljoin(settings.URL_ROOT, reverse('qm',kwargs={'cave_id':self.found_by.cave.kataster_number,'year':self.found_by.date.year,'qm_id':self.number,'grade':self.grade})) + + def get_next_by_id(self): + return QM.objects.get(id=self.id+1) + + def get_previous_by_id(self): + return QM.objects.get(id=self.id-1) + + def wiki_link(self): + return u"%s%s%s" % ('[[QM:',self.code(),']]') + +photoFileStorage = FileSystemStorage(location=settings.PHOTOS_ROOT, base_url=settings.PHOTOS_URL) +class DPhoto(TroggleImageModel): + caption = models.CharField(max_length=1000,blank=True,null=True) + contains_logbookentry = models.ForeignKey(LogbookEntry,blank=True,null=True) + contains_person = models.ManyToManyField(Person,blank=True,null=True) + file = models.ImageField(storage=photoFileStorage, upload_to='.',) + is_mugshot = models.BooleanField(default=False) + contains_cave = models.ForeignKey(Cave,blank=True,null=True) + contains_entrance = models.ForeignKey(Entrance, related_name="photo_file",blank=True,null=True) + #nearest_survey_point = models.ForeignKey(SurveyStation,blank=True,null=True) + nearest_QM = models.ForeignKey(QM,blank=True,null=True) + lon_utm = models.FloatField(blank=True,null=True) + lat_utm = models.FloatField(blank=True,null=True) + + class IKOptions: + spec_module = 'core.imagekit_specs' + cache_dir = 'thumbs' + image_field = 'file' + + #content_type = models.ForeignKey(ContentType) + #object_id = models.PositiveIntegerField() + #location = generic.GenericForeignKey('content_type', 'object_id') + + def __unicode__(self): + return self.caption + +scansFileStorage = FileSystemStorage(location=settings.SURVEY_SCANS, base_url=settings.SURVEYS_URL) +def get_scan_path(instance, filename): + year=instance.survey.expedition.year + print "WN: ", type(instance.survey.wallet_number), instance.survey.wallet_number + number="%02d" % instance.survey.wallet_number + str(instance.survey.wallet_letter) #using %02d string formatting because convention was 2009#01 + return os.path.join('./',year,year+r'#'+number,instance.contents+str(instance.number_in_wallet)+r'.jpg') + +class ScannedImage(TroggleImageModel): + file = models.ImageField(storage=scansFileStorage, upload_to=get_scan_path) + scanned_by = models.ForeignKey(Person,blank=True, null=True) + scanned_on = models.DateField(null=True) + survey = models.ForeignKey('Survey') + contents = models.CharField(max_length=20,choices=(('notes','notes'),('plan','plan_sketch'),('elevation','elevation_sketch'))) + number_in_wallet = models.IntegerField(null=True) + lon_utm = models.FloatField(blank=True,null=True) + lat_utm = models.FloatField(blank=True,null=True) + + class IKOptions: + spec_module = 'core.imagekit_specs' + cache_dir = 'thumbs' + image_field = 'file' + #content_type = models.ForeignKey(ContentType) + #object_id = models.PositiveIntegerField() + #location = generic.GenericForeignKey('content_type', 'object_id') + + #This is an ugly hack to deal with the #s in our survey scan paths. The correct thing is to write a custom file storage backend which calls urlencode on the name for making file.url but not file.path. + def correctURL(self): + return string.replace(self.file.url,r'#',r'%23') + + def __unicode__(self): + return get_scan_path(self,'') + +class Survey(TroggleModel): + expedition = models.ForeignKey('Expedition') #REDUNDANT (logbook_entry) + wallet_number = models.IntegerField(blank=True,null=True) + wallet_letter = models.CharField(max_length=1,blank=True,null=True) + comments = models.TextField(blank=True,null=True) + location = models.CharField(max_length=400,blank=True,null=True) #REDUNDANT + subcave = models.ForeignKey('NewSubCave', blank=True, null=True) + #notes_scan = models.ForeignKey('ScannedImage',related_name='notes_scan',blank=True, null=True) #Replaced by contents field of ScannedImage model + survex_block = models.OneToOneField('SurvexBlock',blank=True, null=True) + logbook_entry = models.ForeignKey('LogbookEntry') + centreline_printed_on = models.DateField(blank=True, null=True) + centreline_printed_by = models.ForeignKey('Person',related_name='centreline_printed_by',blank=True,null=True) + #sketch_scan = models.ForeignKey(ScannedImage,blank=True, null=True) #Replaced by contents field of ScannedImage model + tunnel_file = models.FileField(upload_to='surveyXMLfiles',blank=True, null=True) + tunnel_main_sketch = models.ForeignKey('Survey',blank=True,null=True) + integrated_into_main_sketch_on = models.DateField(blank=True,null=True) + integrated_into_main_sketch_by = models.ForeignKey('Person' ,related_name='integrated_into_main_sketch_by', blank=True,null=True) + rendered_image = models.ImageField(upload_to='renderedSurveys',blank=True,null=True) + def __unicode__(self): + return self.expedition.year+"#"+"%02d" % int(self.wallet_number) + + def notes(self): + return self.scannedimage_set.filter(contents='notes') + + def plans(self): + return self.scannedimage_set.filter(contents='plan') + + def elevations(self): + return self.scannedimage_set.filter(contents='elevation') diff --git a/core/models_survex.py b/core/models_survex.py index efd3022..1bf75ef 100644 --- a/core/models_survex.py +++ b/core/models_survex.py @@ -1,213 +1,213 @@ -from django.db import models -from django.conf import settings -import os -import urlparse -import re -from django.core.urlresolvers import reverse - - -########################################################### -# These will allow browsing and editing of the survex data -########################################################### -# Needs to add: -# Equates -# reloading - -class SurvexDirectory(models.Model): - path = models.CharField(max_length=200) - cave = models.ForeignKey('Cave', blank=True, null=True) - primarysurvexfile = models.ForeignKey('SurvexFile', related_name='primarysurvexfile', blank=True, null=True) - # could also include files in directory but not referenced - - class Meta: - ordering = ('id',) - -class SurvexFile(models.Model): - path = models.CharField(max_length=200) - survexdirectory = models.ForeignKey("SurvexDirectory", blank=True, null=True) - cave = models.ForeignKey('Cave', blank=True, null=True) - - class Meta: - ordering = ('id',) - - def exists(self): - fname = os.path.join(settings.SURVEX_DATA, self.path + ".svx") - return os.path.isfile(fname) - - def OpenFile(self): - fname = os.path.join(settings.SURVEX_DATA, self.path + ".svx") - return open(fname) - - def SetDirectory(self): - dirpath = os.path.split(self.path)[0] - survexdirectorylist = SurvexDirectory.objects.filter(cave=self.cave, path=dirpath) - if survexdirectorylist: - self.survexdirectory = survexdirectorylist[0] - else: - survexdirectory = SurvexDirectory(path=dirpath, cave=self.cave, primarysurvexfile=self) - survexdirectory.save() - self.survexdirectory = survexdirectory - self.save() - -class SurvexEquate(models.Model): - cave = models.ForeignKey('Cave', blank=True, null=True) - -class SurvexStationLookUpManager(models.Manager): - def lookup(self, name): - blocknames, sep, stationname = name.rpartition(".") - return self.get(block = SurvexBlock.objects.lookup(blocknames), - name = stationname) - -class SurvexStation(models.Model): - name = models.CharField(max_length=20) - block = models.ForeignKey('SurvexBlock') - equate = models.ForeignKey('SurvexEquate', blank=True, null=True) - objects = SurvexStationLookUpManager() - x = models.FloatField(blank=True, null=True) - y = models.FloatField(blank=True, null=True) - z = models.FloatField(blank=True, null=True) - -class SurvexLeg(models.Model): - block = models.ForeignKey('SurvexBlock') - #title = models.ForeignKey('SurvexTitle') - stationfrom = models.ForeignKey('SurvexStation', related_name='stationfrom') - stationto = models.ForeignKey('SurvexStation', related_name='stationto') - tape = models.FloatField() - compass = models.FloatField() - clino = models.FloatField() - - -# -# Single SurvexBlock -# -class SurvexBlockLookUpManager(models.Manager): - def lookup(self, name): - blocknames = name.split(".") - block = SurvexBlock.objects.get(parent=None, survexfile__path="all") - for blockname in blocknames: - block = SurvexBlock.objects.get(parent=block, name=blockname) - return block - -class SurvexBlock(models.Model): - objects = SurvexBlockLookUpManager() - name = models.CharField(max_length=100) - parent = models.ForeignKey('SurvexBlock', blank=True, null=True) - text = models.TextField() - cave = models.ForeignKey('Cave', blank=True, null=True) - - date = models.DateField(blank=True, null=True) - expeditionday = models.ForeignKey("ExpeditionDay", null=True) - expedition = models.ForeignKey('Expedition', blank=True, null=True) - - survexfile = models.ForeignKey("SurvexFile", blank=True, null=True) - begin_char = models.IntegerField() # code for where in the survex data files this block sits - survexpath = models.CharField(max_length=200) # the path for the survex stations - - survexscansfolder = models.ForeignKey("SurvexScansFolder", null=True) - #refscandir = models.CharField(max_length=100) - - totalleglength = models.FloatField() - - 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' - - def GetPersonroles(self): - res = [ ] - for personrole in self.personrole_set.order_by('personexpedition'): - if res and res[-1]['person'] == personrole.personexpedition.person: - res[-1]['roles'] += ", " + str(personrole.role) - else: - res.append({'person':personrole.personexpedition.person, 'expeditionyear':personrole.personexpedition.expedition.year, 'roles':str(personrole.role)}) - return res - - def MakeSurvexStation(self, name): - ssl = self.survexstation_set.filter(name=name) - if ssl: - assert len(ssl) == 1 - return ssl[0] - ss = SurvexStation(name=name, block=self) - ss.save() - return ss - - def DayIndex(self): - return list(self.expeditionday.survexblock_set.all()).index(self) - - -class SurvexTitle(models.Model): - survexblock = models.ForeignKey('SurvexBlock') - title = models.CharField(max_length=200) - cave = models.ForeignKey('Cave', blank=True, null=True) - -# -# member of a SurvexBlock -# -ROLE_CHOICES = ( - ('insts','Instruments'), - ('dog','Other'), - ('notes','Notes'), - ('pics','Pictures'), - ('tape','Tape measure'), - ('useless','Useless'), - ('helper','Helper'), - ('disto','Disto'), - ('consultant','Consultant'), - ) - -class SurvexPersonRole(models.Model): - survexblock = models.ForeignKey('SurvexBlock') - nrole = models.CharField(choices=ROLE_CHOICES, max_length=200, blank=True, null=True) - # increasing levels of precision - personname = models.CharField(max_length=100) - person = models.ForeignKey('Person', blank=True, null=True) - personexpedition = models.ForeignKey('PersonExpedition', blank=True, null=True) - persontrip = models.ForeignKey('PersonTrip', blank=True, null=True) - expeditionday = models.ForeignKey("ExpeditionDay", null=True) - - def __unicode__(self): - return unicode(self.person) + " - " + unicode(self.survexblock) + " - " + unicode(self.nrole) - - -class SurvexScansFolder(models.Model): - fpath = models.CharField(max_length=200) - walletname = models.CharField(max_length=200) - - class Meta: - ordering = ('walletname',) - - def get_absolute_url(self): - return urlparse.urljoin(settings.URL_ROOT, reverse('surveyscansfolder', kwargs={"path":re.sub("#", "%23", self.walletname)})) - -class SurvexScanSingle(models.Model): - ffile = models.CharField(max_length=200) - name = models.CharField(max_length=200) - survexscansfolder = models.ForeignKey("SurvexScansFolder", null=True) - - class Meta: - ordering = ('name',) - - def get_absolute_url(self): - return urlparse.urljoin(settings.URL_ROOT, reverse('surveyscansingle', kwargs={"path":re.sub("#", "%23", self.survexscansfolder.walletname), "file":self.name})) - - -class TunnelFile(models.Model): - tunnelpath = models.CharField(max_length=200) - tunnelname = models.CharField(max_length=200) - bfontcolours = models.BooleanField() - survexscansfolders = models.ManyToManyField("SurvexScansFolder") - survexscans = models.ManyToManyField("SurvexScanSingle") - survexblocks = models.ManyToManyField("SurvexBlock") - tunnelcontains = models.ManyToManyField("TunnelFile") # case when its a frame type - filesize = models.IntegerField(default=0) - npaths = models.IntegerField(default=0) - survextitles = models.ManyToManyField("SurvexTitle") - - - class Meta: - ordering = ('tunnelpath',) - +from django.db import models +from django.conf import settings +import os +import urlparse +import re +from django.core.urlresolvers import reverse + + +########################################################### +# These will allow browsing and editing of the survex data +########################################################### +# Needs to add: +# Equates +# reloading + +class SurvexDirectory(models.Model): + path = models.CharField(max_length=200) + cave = models.ForeignKey('Cave', blank=True, null=True) + primarysurvexfile = models.ForeignKey('SurvexFile', related_name='primarysurvexfile', blank=True, null=True) + # could also include files in directory but not referenced + + class Meta: + ordering = ('id',) + +class SurvexFile(models.Model): + path = models.CharField(max_length=200) + survexdirectory = models.ForeignKey("SurvexDirectory", blank=True, null=True) + cave = models.ForeignKey('Cave', blank=True, null=True) + + class Meta: + ordering = ('id',) + + def exists(self): + fname = os.path.join(settings.SURVEX_DATA, self.path + ".svx") + return os.path.isfile(fname) + + def OpenFile(self): + fname = os.path.join(settings.SURVEX_DATA, self.path + ".svx") + return open(fname) + + def SetDirectory(self): + dirpath = os.path.split(self.path)[0] + survexdirectorylist = SurvexDirectory.objects.filter(cave=self.cave, path=dirpath) + if survexdirectorylist: + self.survexdirectory = survexdirectorylist[0] + else: + survexdirectory = SurvexDirectory(path=dirpath, cave=self.cave, primarysurvexfile=self) + survexdirectory.save() + self.survexdirectory = survexdirectory + self.save() + +class SurvexEquate(models.Model): + cave = models.ForeignKey('Cave', blank=True, null=True) + +class SurvexStationLookUpManager(models.Manager): + def lookup(self, name): + blocknames, sep, stationname = name.rpartition(".") + return self.get(block = SurvexBlock.objects.lookup(blocknames), + name = stationname) + +class SurvexStation(models.Model): + name = models.CharField(max_length=20) + block = models.ForeignKey('SurvexBlock') + equate = models.ForeignKey('SurvexEquate', blank=True, null=True) + objects = SurvexStationLookUpManager() + x = models.FloatField(blank=True, null=True) + y = models.FloatField(blank=True, null=True) + z = models.FloatField(blank=True, null=True) + +class SurvexLeg(models.Model): + block = models.ForeignKey('SurvexBlock') + #title = models.ForeignKey('SurvexTitle') + stationfrom = models.ForeignKey('SurvexStation', related_name='stationfrom') + stationto = models.ForeignKey('SurvexStation', related_name='stationto') + tape = models.FloatField() + compass = models.FloatField() + clino = models.FloatField() + + +# +# Single SurvexBlock +# +class SurvexBlockLookUpManager(models.Manager): + def lookup(self, name): + blocknames = name.split(".") + block = SurvexBlock.objects.get(parent=None, survexfile__path="all") + for blockname in blocknames: + block = SurvexBlock.objects.get(parent=block, name=blockname) + return block + +class SurvexBlock(models.Model): + objects = SurvexBlockLookUpManager() + name = models.CharField(max_length=100) + parent = models.ForeignKey('SurvexBlock', blank=True, null=True) + text = models.TextField() + cave = models.ForeignKey('Cave', blank=True, null=True) + + date = models.DateField(blank=True, null=True) + expeditionday = models.ForeignKey("ExpeditionDay", null=True) + expedition = models.ForeignKey('Expedition', blank=True, null=True) + + survexfile = models.ForeignKey("SurvexFile", blank=True, null=True) + begin_char = models.IntegerField() # code for where in the survex data files this block sits + survexpath = models.CharField(max_length=200) # the path for the survex stations + + survexscansfolder = models.ForeignKey("SurvexScansFolder", null=True) + #refscandir = models.CharField(max_length=100) + + totalleglength = models.FloatField() + + 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' + + def GetPersonroles(self): + res = [ ] + for personrole in self.personrole_set.order_by('personexpedition'): + if res and res[-1]['person'] == personrole.personexpedition.person: + res[-1]['roles'] += ", " + str(personrole.role) + else: + res.append({'person':personrole.personexpedition.person, 'expeditionyear':personrole.personexpedition.expedition.year, 'roles':str(personrole.role)}) + return res + + def MakeSurvexStation(self, name): + ssl = self.survexstation_set.filter(name=name) + if ssl: + assert len(ssl) == 1 + return ssl[0] + ss = SurvexStation(name=name, block=self) + ss.save() + return ss + + def DayIndex(self): + return list(self.expeditionday.survexblock_set.all()).index(self) + + +class SurvexTitle(models.Model): + survexblock = models.ForeignKey('SurvexBlock') + title = models.CharField(max_length=200) + cave = models.ForeignKey('Cave', blank=True, null=True) + +# +# member of a SurvexBlock +# +ROLE_CHOICES = ( + ('insts','Instruments'), + ('dog','Other'), + ('notes','Notes'), + ('pics','Pictures'), + ('tape','Tape measure'), + ('useless','Useless'), + ('helper','Helper'), + ('disto','Disto'), + ('consultant','Consultant'), + ) + +class SurvexPersonRole(models.Model): + survexblock = models.ForeignKey('SurvexBlock') + nrole = models.CharField(choices=ROLE_CHOICES, max_length=200, blank=True, null=True) + # increasing levels of precision + personname = models.CharField(max_length=100) + person = models.ForeignKey('Person', blank=True, null=True) + personexpedition = models.ForeignKey('PersonExpedition', blank=True, null=True) + persontrip = models.ForeignKey('PersonTrip', blank=True, null=True) + expeditionday = models.ForeignKey("ExpeditionDay", null=True) + + def __unicode__(self): + return unicode(self.person) + " - " + unicode(self.survexblock) + " - " + unicode(self.nrole) + + +class SurvexScansFolder(models.Model): + fpath = models.CharField(max_length=200) + walletname = models.CharField(max_length=200) + + class Meta: + ordering = ('walletname',) + + def get_absolute_url(self): + return urlparse.urljoin(settings.URL_ROOT, reverse('surveyscansfolder', kwargs={"path":re.sub("#", "%23", self.walletname)})) + +class SurvexScanSingle(models.Model): + ffile = models.CharField(max_length=200) + name = models.CharField(max_length=200) + survexscansfolder = models.ForeignKey("SurvexScansFolder", null=True) + + class Meta: + ordering = ('name',) + + def get_absolute_url(self): + return urlparse.urljoin(settings.URL_ROOT, reverse('surveyscansingle', kwargs={"path":re.sub("#", "%23", self.survexscansfolder.walletname), "file":self.name})) + + +class TunnelFile(models.Model): + tunnelpath = models.CharField(max_length=200) + tunnelname = models.CharField(max_length=200) + bfontcolours = models.BooleanField() + survexscansfolders = models.ManyToManyField("SurvexScansFolder") + survexscans = models.ManyToManyField("SurvexScanSingle") + survexblocks = models.ManyToManyField("SurvexBlock") + tunnelcontains = models.ManyToManyField("TunnelFile") # case when its a frame type + filesize = models.IntegerField(default=0) + npaths = models.IntegerField(default=0) + survextitles = models.ManyToManyField("SurvexTitle") + + + class Meta: + ordering = ('tunnelpath',) + diff --git a/core/templatetags/link.py b/core/templatetags/link.py index 63e2dac..cb861ad 100644 --- a/core/templatetags/link.py +++ b/core/templatetags/link.py @@ -1,9 +1,9 @@ -from django import template -from django.utils.safestring import mark_safe - -register = template.Library() - -@register.filter() -def link(value): - return mark_safe(""%value.get_absolute_url()+unicode(value)+"") - +from django import template +from django.utils.safestring import mark_safe + +register = template.Library() + +@register.filter() +def link(value): + return mark_safe(""%value.get_absolute_url()+unicode(value)+"") + diff --git a/core/templatetags/survex_markup.py b/core/templatetags/survex_markup.py index 464a04b..5b9aa36 100644 --- a/core/templatetags/survex_markup.py +++ b/core/templatetags/survex_markup.py @@ -1,52 +1,52 @@ -from django import template -from django.utils.html import conditional_escape -from django.template.defaultfilters import stringfilter -from django.utils.safestring import mark_safe -import re - -register = template.Library() - -# seems to add extra lines between the commented lines, which isn't so great. -regexes = [] -regexes.append((re.compile(r"(;.*)$", re.IGNORECASE|re.MULTILINE), - r'\1\n')) -regexes.append((re.compile(r"^(\s*)(\*include)(\s+)([^\s]*)(.svx)$", re.IGNORECASE|re.MULTILINE), - r'\1\2\3\4\5')) -regexes.append((re.compile(r"^(\s*)(\*include)(\s+)([^\s]*)$", re.IGNORECASE|re.MULTILINE), - r'\1\2\3\4')) -regexes.append((re.compile(r"^(\s*)(\*team\s+(?:notes|tape|insts|pics))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), - r'\1\2\3\4')) -regexes.append((re.compile(r"^(\s*)(\*(?:begin|end|copyright|date|entrance|equate|export|fix|prefix|require|SOLVE|title|truncate))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), - r'\1\2\3\4')) -regexes.append((re.compile(r"^(\s*)(\*calibrate\s+(?:TAPE|COMPASS|CLINO|COUNTER|DEPTH|DECLINATION|X|Y|Z)+)(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), - r'\1\2\3\4')) -regexes.append((re.compile(r"^(\s*)(\*data\s+(?:DEFAULT|NORMAL|DIVING|CARTESIAN|TOPOFIL|CYLPOLAR|NOSURVEY|passage)(?:\s+station|\s+from|\s+to|\s+FROMDEPTH|\s+TODEPTH|\s+DEPTHCHANGE|\s+newline|\s+direction|\s+tape|\s+compass|\s+clino|\s+northing|\s+easting|\s+altitude|\s+length|\s+bearing|\s+gradient|\s+ignoreall|\sleft|\sright|\sup|\sdown)*)$", re.IGNORECASE|re.MULTILINE), - r'\1\2')) -regexes.append((re.compile(r"^(\s*)(\*default\s+(?:CALIBRATE|DATA|UNITS)+)(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), - r'\1\2\3\4')) -regexes.append((re.compile(r"^(\s*)(\*flags\s+(?:DUPLICATE|SPLAY|SURFACE|not DUPLICATE|not SPLAY|not SURFACE))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), - r'\1\2\3\4')) -regexes.append((re.compile(r"^(\s*)(\*infer\s+(?:plumbs|equates|exports))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), - r'\1\2\3\4')) -regexes.append((re.compile(r"^(\s*)(\*instrument\s+(?:compass|clino|tape))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), - r'\1\2\3\4')) -regexes.append((re.compile(r"^(\s*)(\*instrument\s+(?:compass|clino|tape))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), - r'\1\2\3\4')) -regexes.append((re.compile(r"^(\s*)(\*sd\s+(?:TAPE|COMPASS|CLINO|COUNTER|DEPTH|DECLINATION|DX|DY|DZ))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), - r'\1\2\3\4')) -regexes.append((re.compile(r"^(\s*)(\*set\s+(?:BLANK|COMMENT|DECIMAL|EOL|KEYWORD|MINUS|NAMES|OMIT|PLUS|ROOT|SEPARATOR))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), - r'\1\2\3\4')) -regexes.append((re.compile(r"^(\s*)(\*units\s+(?:TAPE|LENGTH|COMPASS|BEARING|CLINO|GRADIENT|COUNTER|DEPTH|DECLINATION|X|Y|Z))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), - r'\1\2\3\4')) -regexes.append((re.compile(r"^(.*)$", re.IGNORECASE|re.MULTILINE), - r'
\1 
\n')) - -@register.filter() -@stringfilter -def survex_to_html(value, autoescape=None): - if autoescape: - value = conditional_escape(value) - for regex, sub in regexes: - print sub - value = regex.sub(sub, value) +from django import template +from django.utils.html import conditional_escape +from django.template.defaultfilters import stringfilter +from django.utils.safestring import mark_safe +import re + +register = template.Library() + +# seems to add extra lines between the commented lines, which isn't so great. +regexes = [] +regexes.append((re.compile(r"(;.*)$", re.IGNORECASE|re.MULTILINE), + r'\1\n')) +regexes.append((re.compile(r"^(\s*)(\*include)(\s+)([^\s]*)(.svx)$", re.IGNORECASE|re.MULTILINE), + r'\1\2\3\4\5')) +regexes.append((re.compile(r"^(\s*)(\*include)(\s+)([^\s]*)$", re.IGNORECASE|re.MULTILINE), + r'\1\2\3\4')) +regexes.append((re.compile(r"^(\s*)(\*team\s+(?:notes|tape|insts|pics))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), + r'\1\2\3\4')) +regexes.append((re.compile(r"^(\s*)(\*(?:begin|end|copyright|date|entrance|equate|export|fix|prefix|require|SOLVE|title|truncate))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), + r'\1\2\3\4')) +regexes.append((re.compile(r"^(\s*)(\*calibrate\s+(?:TAPE|COMPASS|CLINO|COUNTER|DEPTH|DECLINATION|X|Y|Z)+)(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), + r'\1\2\3\4')) +regexes.append((re.compile(r"^(\s*)(\*data\s+(?:DEFAULT|NORMAL|DIVING|CARTESIAN|TOPOFIL|CYLPOLAR|NOSURVEY|passage)(?:\s+station|\s+from|\s+to|\s+FROMDEPTH|\s+TODEPTH|\s+DEPTHCHANGE|\s+newline|\s+direction|\s+tape|\s+compass|\s+clino|\s+northing|\s+easting|\s+altitude|\s+length|\s+bearing|\s+gradient|\s+ignoreall|\sleft|\sright|\sup|\sdown)*)$", re.IGNORECASE|re.MULTILINE), + r'\1\2')) +regexes.append((re.compile(r"^(\s*)(\*default\s+(?:CALIBRATE|DATA|UNITS)+)(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), + r'\1\2\3\4')) +regexes.append((re.compile(r"^(\s*)(\*flags\s+(?:DUPLICATE|SPLAY|SURFACE|not DUPLICATE|not SPLAY|not SURFACE))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), + r'\1\2\3\4')) +regexes.append((re.compile(r"^(\s*)(\*infer\s+(?:plumbs|equates|exports))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), + r'\1\2\3\4')) +regexes.append((re.compile(r"^(\s*)(\*instrument\s+(?:compass|clino|tape))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), + r'\1\2\3\4')) +regexes.append((re.compile(r"^(\s*)(\*instrument\s+(?:compass|clino|tape))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), + r'\1\2\3\4')) +regexes.append((re.compile(r"^(\s*)(\*sd\s+(?:TAPE|COMPASS|CLINO|COUNTER|DEPTH|DECLINATION|DX|DY|DZ))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), + r'\1\2\3\4')) +regexes.append((re.compile(r"^(\s*)(\*set\s+(?:BLANK|COMMENT|DECIMAL|EOL|KEYWORD|MINUS|NAMES|OMIT|PLUS|ROOT|SEPARATOR))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), + r'\1\2\3\4')) +regexes.append((re.compile(r"^(\s*)(\*units\s+(?:TAPE|LENGTH|COMPASS|BEARING|CLINO|GRADIENT|COUNTER|DEPTH|DECLINATION|X|Y|Z))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE), + r'\1\2\3\4')) +regexes.append((re.compile(r"^(.*)$", re.IGNORECASE|re.MULTILINE), + r'
\1 
\n')) + +@register.filter() +@stringfilter +def survex_to_html(value, autoescape=None): + if autoescape: + value = conditional_escape(value) + for regex, sub in regexes: + print sub + value = regex.sub(sub, value) return mark_safe(value) \ No newline at end of file diff --git a/core/templatetags/wiki_markup.py b/core/templatetags/wiki_markup.py index 810634b..4087b12 100644 --- a/core/templatetags/wiki_markup.py +++ b/core/templatetags/wiki_markup.py @@ -1,169 +1,169 @@ -from django import template -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 core.models import QM, DPhoto, LogbookEntry, Cave -import re, urlparse - -register = template.Library() - - -@register.filter() -def plusone(n): - return n + 1 - - -def wiki_list(line, listdepth): - l = "" - for d in listdepth: - l += d - mstar = re.match(l + "\*(.*)", line) - if mstar: - listdepth.append("\*") - return ("\n" + t, l) - if prev == "#": - t, l = wiki_list(line, listdepth) - return ("\n" + t, l) - return (line, listdepth) - -@register.filter() -@stringfilter -def wiki_to_html(value, autoescape=None): - """ - This is the tag which turns wiki syntax into html. It is intended for long pieces of wiki. - Hence it splits the wiki into HTML paragraphs based on double line feeds. - """ - #find paragraphs - outValue = "" - for paragraph in re.split("\n\s*?\n", value, re.DOTALL): - outValue += "

" - outValue += wiki_to_html_short(paragraph, autoescape) - outValue += "

\n" - return mark_safe(outValue) - -@register.filter() -@stringfilter -def wiki_to_html_short(value, autoescape=None): - """ - This is the tag which turns wiki syntax into html. It is intended for short pieces of wiki. - Hence it is not split the wiki into paragraphs using where it finds double line feeds. - """ - if autoescape: - value = conditional_escape(value) - #deescape doubly escaped characters - value = re.sub("&(.*?);", r"&\1;", value, re.DOTALL) - #italics and bold - value = re.sub("''''([^']+)''''", r"\1", value, re.DOTALL) - value = re.sub("'b''([^']+)'''", r"\1", value, re.DOTALL) - value = re.sub("''([^']+)''", r"\1", value, re.DOTALL) - - #make headers - def headerrepl(matchobj): - number=len(matchobj.groups()[0]) - num=str(number) - if number>1: - return ''+matchobj.groups()[1]+'' - else: - print 'morethanone' - return matchobj.group() - value = re.sub(r"(?m)^(=+)([^=]+)(=+)$",headerrepl,value) - - #make qm links. this takes a little doing - qmMatchPattern=settings.QM_PATTERN - def qmrepl(matchobj): - """ - A function for replacing wikicode qm links with html qm links. - Given a matchobj matching a wikilink in the format - [[QM:C204-1999-24]] - If the QM does not exist, the function will return a link for creating it. - """ - qmdict={'urlroot':settings.URL_ROOT,'cave':matchobj.groups()[2],'year':matchobj.groups()[1],'number':matchobj.groups()[3]} - try: - qm=QM.objects.get(found_by__cave__kataster_number = qmdict['cave'], - found_by__date__year = qmdict['year'], - number = qmdict['number']) - return r'%s' % (qm.get_absolute_url(), qm.code, unicode(qm)) - except QM.DoesNotExist: #bother aaron to make him clean up the below code - AC - try: - placeholder=LogbookEntry.objects.get(date__year=qmdict['year'],cave__kataster_number=qmdict['cave'], title__icontains='placeholder') - except LogbookEntry.DoesNotExist: - placeholder=LogbookEntry( - date='01-01'+qmdict['year'], - cave=Cave.objects.get(kataster_number=qmdict['cave']), - title='placeholder' - ) - qm=QM(found_by = placeholder, number = qmdict['number']) - return r'%s' % (qm.get_absolute_url(), qm.code, unicode(qm)) - - value = re.sub(qmMatchPattern,qmrepl, value, re.DOTALL) - - #make photo links for [[photo:filename]] or [[photo:filename linktext]], and - #insert photos for [[display:left photo:filename]] - photoLinkPattern="\[\[\s*photo:(?P[^\s]+)\s*(?P.*)\]\]" - photoSrcPattern="\[\[\s*display:(?P