diff --git a/README.txt b/README.txt index 93de04535..2913653cf 100644 --- a/README.txt +++ b/README.txt @@ -1,39 +1,39 @@ -Troggle is an application for caving expedition data management, originally created for use on Cambridge University Caving Club expeditions and licensed under the GNU Lesser General Public License. - -Troggle setup -========== - -Python, Django, and Database setup ------------------------------------ -Troggle requires Django 1.1 or greater, and any version of Python that works with it. As of writing this readme, there was no actual Django 1.1 release, so Troggle required the SVN version of Django. Check Django out to somewhere on your PYTHONPATH with the following command: - -svn co http://code.djangoproject.com/svn/django/trunk/ - -If you have an older installation of Django installed on your system, the easiest way to make sure troggle is using the newest version of Django is to simply checkout into your top troggle directory, into a folder called django. - -If you want to use MySQL or Postgresql, download and install them. However, you can also use Django with Sqlite3, which is included in Python and thus requires no extra installation. - - - -Troggle itself -------------- -Choose a directory where you will keep troggle, and svn check out Troggle into it using the following command: - -svn co http://troggle.googlecode.com/svn/ - -If you want to work on the source code and be able to commit, you will need to use https instead of http, and your google account will need to be added to the troggle project members list. Contact aaron dot curtis at cantab dot net to get this set up. - -Next, you need to fill in your local settings. Copy either localsettingsubuntu.py or localsettingsserver.py to a new file called localsettings.py. Follow the instructions contained in the file to fill out your settings. - -Setting up tables and importing legacy data ------------------------------------------- -Run "python databaseReset.py reset" from the troggle directory. - -Once troggle is running, you can also log in and then go to "Import / export" data under "admin" on the menu. - -Running a Troggle server ------------------------- -For high volume use, Troggle should be run using a web server like apache. However, a quick way to get started is to use the development server built into Django. - -To do this, run "python manage.py runserver" from the troggle directory. - +Troggle is an application for caving expedition data management, originally created for use on Cambridge University Caving Club expeditions and licensed under the GNU Lesser General Public License. + +Troggle setup +========== + +Python, Django, and Database setup +----------------------------------- +Troggle requires Django 1.1 or greater, and any version of Python that works with it. As of writing this readme, there was no actual Django 1.1 release, so Troggle required the SVN version of Django. Check Django out to somewhere on your PYTHONPATH with the following command: + +svn co http://code.djangoproject.com/svn/django/trunk/ + +If you have an older installation of Django installed on your system, the easiest way to make sure troggle is using the newest version of Django is to simply checkout into your top troggle directory, into a folder called django. + +If you want to use MySQL or Postgresql, download and install them. However, you can also use Django with Sqlite3, which is included in Python and thus requires no extra installation. + + + +Troggle itself +------------- +Choose a directory where you will keep troggle, and svn check out Troggle into it using the following command: + +svn co http://troggle.googlecode.com/svn/ + +If you want to work on the source code and be able to commit, you will need to use https instead of http, and your google account will need to be added to the troggle project members list. Contact aaron dot curtis at cantab dot net to get this set up. + +Next, you need to fill in your local settings. Copy either localsettingsubuntu.py or localsettingsserver.py to a new file called localsettings.py. Follow the instructions contained in the file to fill out your settings. + +Setting up tables and importing legacy data +------------------------------------------ +Run "python databaseReset.py reset" from the troggle directory. + +Once troggle is running, you can also log in and then go to "Import / export" data under "admin" on the menu. + +Running a Troggle server +------------------------ +For high volume use, Troggle should be run using a web server like apache. However, a quick way to get started is to use the development server built into Django. + +To do this, run "python manage.py runserver" from the troggle directory. + diff --git a/core/admin.py b/core/admin.py index be4045ad7..fc43f2330 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 ec639b0be..7063f2353 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 d199073f3..c82f44838 100644 --- a/core/models.py +++ b/core/models.py @@ -1,701 +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): - return urlparse.urljoin(settings.URL_ROOT, self.url) - #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 efd302211..1bf75ef03 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 63e2daca8..cb861adae 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 464a04bc6..5b9aa36f7 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 810634b5b..4087b1279 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 - - -

Expo {{logbook_entries.0.expedition}}

- -{%for logbook_entry in logbook_entries%} -
- -
{{logbook_entry.date}}
-
{{logbook_entry.author.person}} -{% for persontrip in logbook_entry.persontrip_set.all %}{{ persontrip.personexpedition.person }} {{ persontrip.personexpedition.time_underground }}, {% endfor %} -
- -
{{logbook_entry.place}} - {{logbook_entry.title}}
- -{{logbook_entry.text|safe}} -{% endfor %} + +{{logbook_entries.0.expedition}} Expo Logbook + + + + +

Expo {{logbook_entries.0.expedition}}

+ +{%for logbook_entry in logbook_entries%} +
+ +
{{logbook_entry.date}}
+
{{logbook_entry.author.person}} +{% for persontrip in logbook_entry.persontrip_set.all %}{{ persontrip.personexpedition.person }} {{ persontrip.personexpedition.time_underground }}, {% endfor %} +
+ +
{{logbook_entry.place}} - {{logbook_entry.title}}
+ +{{logbook_entry.text|safe}} +{% endfor %} diff --git a/templates/logbook2008style.txt b/templates/logbook2008style.txt index a7fbea7c8..272599525 100644 --- a/templates/logbook2008style.txt +++ b/templates/logbook2008style.txt @@ -1,6 +1,6 @@ -=Expo {{logbook_entries.0.expedition}} logbook == -{%for logbook_entry in logbook_entries%} -==={{logbook_entry.date}} | {{logbook_entry.place}} - {{logbook_entry.title}} | {% for persontrip in logbook_entry.persontrip_set.all %}{{ persontrip.person_expedition.person }} {{ persontrip.person_expedition.time_underground }}, {% endfor %}=== - -{{logbook_entry.text|safe}} +=Expo {{logbook_entries.0.expedition}} logbook == +{%for logbook_entry in logbook_entries%} +==={{logbook_entry.date}} | {{logbook_entry.place}} - {{logbook_entry.title}} | {% for persontrip in logbook_entry.persontrip_set.all %}{{ persontrip.person_expedition.person }} {{ persontrip.person_expedition.time_underground }}, {% endfor %}=== + +{{logbook_entry.text|safe}} {% endfor %} \ No newline at end of file diff --git a/templates/logbookentry.html b/templates/logbookentry.html index 04229fbfa..a3ffc3d34 100644 --- a/templates/logbookentry.html +++ b/templates/logbookentry.html @@ -1,77 +1,77 @@ -{% extends "base.html" %} -{% load wiki_markup %} - -{% block title %}Logbook {{logbookentry.id}}{% endblock %} -{% block editLink %}Edit logbook entry {{logbookentry|wiki_to_html_short}}{% endblock %} -{% block content %} - -{% block related %}{% endblock %} -{% block nav %}{% endblock %} -

{{logbookentry.title}}

- - - -
-
-{{logbookentry.date}} - {{logbookentry.text|wiki_to_html}}
-
- - -{% if logbookentry.filename %}Edit Delete{%endif%} - - -{% endblock %} +{% extends "base.html" %} +{% load wiki_markup %} + +{% block title %}Logbook {{logbookentry.id}}{% endblock %} +{% block editLink %}Edit logbook entry {{logbookentry|wiki_to_html_short}}{% endblock %} +{% block content %} + +{% block related %}{% endblock %} +{% block nav %}{% endblock %} +

{{logbookentry.title}}

+ + + +
+
+{{logbookentry.date}} + {{logbookentry.text|wiki_to_html}}
+
+ + +{% if logbookentry.filename %}Edit Delete{%endif%} + + +{% endblock %} diff --git a/templates/newlogbookentry.html b/templates/newlogbookentry.html index 4e8eda611..36e85912f 100644 --- a/templates/newlogbookentry.html +++ b/templates/newlogbookentry.html @@ -1,83 +1,83 @@ -{% extends "base.html" %} -{% load csrffaker %} -{% block title %}Logbook {{logbookentry.id}}{% endblock %} -{% block head %} - - - - - -{{ tripForm.media }} -{% endblock %} -{% block content %} - -
{% csrf_token %} - {{ tripForm.non_field_errors }} -
- {{ tripForm.title.errors }} - - {{ tripForm.title }} -
-
- {{ tripForm.date.errors }} - - {{ tripForm.date }} -
-
- {{ tripForm.caveOrLocation.errors }} - - {{ tripForm.caveOrLocation }} -
-
- {{ tripForm.cave.errors }} - - {{ tripForm.cave }} -
-
- {{ tripForm.location.errors }} - - {{ tripForm.location }} -
- - - - - - - - - {% for form in personTripFormSet.forms %} - - - - - - {{ form.non_field_errors }} - - {% endfor %} - -
PersonTU /hoursAuthor
{{ form.name.errors }}{{ form.name }}{{ form.TU.errors }}{{ form.TU }}{{ form.author.errors }}{{ form.author }}
- {{ personTripFormSet.management_form }} -
- {{ tripForm.html.errors }} - - {{ tripForm.html }} -
-

-
- -{% endblock %} +{% extends "base.html" %} +{% load csrffaker %} +{% block title %}Logbook {{logbookentry.id}}{% endblock %} +{% block head %} + + + + + +{{ tripForm.media }} +{% endblock %} +{% block content %} + +
{% csrf_token %} + {{ tripForm.non_field_errors }} +
+ {{ tripForm.title.errors }} + + {{ tripForm.title }} +
+
+ {{ tripForm.date.errors }} + + {{ tripForm.date }} +
+
+ {{ tripForm.caveOrLocation.errors }} + + {{ tripForm.caveOrLocation }} +
+
+ {{ tripForm.cave.errors }} + + {{ tripForm.cave }} +
+
+ {{ tripForm.location.errors }} + + {{ tripForm.location }} +
+ + + + + + + + + {% for form in personTripFormSet.forms %} + + + + + + {{ form.non_field_errors }} + + {% endfor %} + +
PersonTU /hoursAuthor
{{ form.name.errors }}{{ form.name }}{{ form.TU.errors }}{{ form.TU }}{{ form.author.errors }}{{ form.author }}
+ {{ personTripFormSet.management_form }} +
+ {{ tripForm.html.errors }} + + {{ tripForm.html }} +
+

+
+ +{% endblock %} diff --git a/templates/nonpublic.html b/templates/nonpublic.html index 5befc4c00..5e44abcd4 100644 --- a/templates/nonpublic.html +++ b/templates/nonpublic.html @@ -1,9 +1,9 @@ -{% extends "base.html" %} -{% block title %} -{{instance}} is non-public -{% endblock %} - -{% block content %} -

Non-public object requested by anonymous user

-The object you requested, {{instance}}, is only viewable for logged-in users. This may be due to copyright or privacy concerns. +{% extends "base.html" %} +{% block title %} +{{instance}} is non-public +{% endblock %} + +{% block content %} +

Non-public object requested by anonymous user

+The object you requested, {{instance}}, is only viewable for logged-in users. This may be due to copyright or privacy concerns. {% endblock %} \ No newline at end of file diff --git a/templates/object_list.html b/templates/object_list.html index 7db63e031..803703f66 100644 --- a/templates/object_list.html +++ b/templates/object_list.html @@ -1,15 +1,15 @@ -{% extends "base.html" %} -{% load link %} -{% block title %}Troggle: {{object_list.1.meta.object_name}} objects{%endblock%} - -{% block contentheader %} -

{{object_list.0.object_name}} objects

-{% endblock contentheader %} - -{% block content %} - +{% extends "base.html" %} +{% load link %} +{% block title %}Troggle: {{object_list.1.meta.object_name}} objects{%endblock%} + +{% block contentheader %} +

{{object_list.0.object_name}} objects

+{% endblock contentheader %} + +{% block content %} + {% endblock content %} \ No newline at end of file diff --git a/templates/person.html b/templates/person.html index bfc9c5cc1..48dafb737 100644 --- a/templates/person.html +++ b/templates/person.html @@ -1,43 +1,43 @@ -{% extends "base.html" %} -{% load wiki_markup %} - -{% block title %}Person {{person|wiki_to_html_short}}{% endblock %} - -{% block editLink %}| Edit person {{person|wiki_to_html_short}}{% endblock %} - -{% block contentheader %} -

{{person|wiki_to_html_short}}

-{% endblock %} - -{% block content %} -{% if person.blurb %} -{{person.blurb|safe}} -{% endif %} - -{% for pic in person.photo_set.all %} -{% if pic.is_mugshot %} -
-

-

{{ pic.caption }}

-

edit {{pic}} -

-

-
-{% endif %} -{% endfor %} -
- -

{{person|wiki_to_html_short}} has been on expo in the following years:

-

-

-

- - -{% endblock %} +{% extends "base.html" %} +{% load wiki_markup %} + +{% block title %}Person {{person|wiki_to_html_short}}{% endblock %} + +{% block editLink %}| Edit person {{person|wiki_to_html_short}}{% endblock %} + +{% block contentheader %} +

{{person|wiki_to_html_short}}

+{% endblock %} + +{% block content %} +{% if person.blurb %} +{{person.blurb|safe}} +{% endif %} + +{% for pic in person.photo_set.all %} +{% if pic.is_mugshot %} +
+

+

{{ pic.caption }}

+

edit {{pic}} +

+

+
+{% endif %} +{% endfor %} +
+ +

{{person|wiki_to_html_short}} has been on expo in the following years:

+

+

+

+ + +{% endblock %} diff --git a/templates/personForm.html b/templates/personForm.html index 84ee7b79b..457723909 100644 --- a/templates/personForm.html +++ b/templates/personForm.html @@ -1,6 +1,6 @@ -{% extends "base.html" %} -{% block content %} - -{{ form }} - +{% extends "base.html" %} +{% block content %} + +{{ form }} + {% endblock %} \ No newline at end of file diff --git a/templates/personexpedition.html b/templates/personexpedition.html index 78018db4c..b88f44e4d 100644 --- a/templates/personexpedition.html +++ b/templates/personexpedition.html @@ -1,57 +1,57 @@ -{% extends "base.html" %} -{% load wiki_markup %} -{% load link %} - -{% block title %}Person {{personexpedition.person|wiki_to_html_short}} for {{personexpedition.expedition}}{% endblock %} - - -{% block content %} -

- {{personexpedition.person}} : - {{personexpedition.expedition}} -

- -

{{message}}

- -

Other years: -{% for otherpersonexpedition in personexpedition.person.personexpedition_set.all %} - {% ifequal otherpersonexpedition personexpedition %} - | {{otherpersonexpedition.expedition.year}} - {% else %} - | {{ otherpersonexpedition.expedition.year }} - {% endifequal %} -{% endfor %} -

- -

Table of all trips and surveys aligned by date

-
- - -{% for persondate in personchronology %} - - - - {% if persondate.1 %} - - - {% else %} - - {% endif %} - - {% if persondate.2 %} - - - {% else %} - - {% endif %} - - -{% endfor %} -
DateTripsSurveys
{{persondate.0}}{{persondate.1.logbook_entry.title|safe}}{{persondate.1.place|safe}} {{persondate.2}} - {% for survexpersonrole in persondate.2.survexpersonrole_set.all %} - {{survexpersonrole.nrole}} - {% endfor %} -
-
- -{% endblock %} +{% extends "base.html" %} +{% load wiki_markup %} +{% load link %} + +{% block title %}Person {{personexpedition.person|wiki_to_html_short}} for {{personexpedition.expedition}}{% endblock %} + + +{% block content %} +

+ {{personexpedition.person}} : + {{personexpedition.expedition}} +

+ +

{{message}}

+ +

Other years: +{% for otherpersonexpedition in personexpedition.person.personexpedition_set.all %} + {% ifequal otherpersonexpedition personexpedition %} + | {{otherpersonexpedition.expedition.year}} + {% else %} + | {{ otherpersonexpedition.expedition.year }} + {% endifequal %} +{% endfor %} +

+ +

Table of all trips and surveys aligned by date

+
+ + +{% for persondate in personchronology %} + + + + {% if persondate.1 %} + + + {% else %} + + {% endif %} + + {% if persondate.2 %} + + + {% else %} + + {% endif %} + + +{% endfor %} +
DateTripsSurveys
{{persondate.0}}{{persondate.1.logbook_entry.title|safe}}{{persondate.1.place|safe}} {{persondate.2}} + {% for survexpersonrole in persondate.2.survexpersonrole_set.all %} + {{survexpersonrole.nrole}} + {% endfor %} +
+
+ +{% endblock %} diff --git a/templates/personindex.html b/templates/personindex.html index 8daffc087..a6196a668 100644 --- a/templates/personindex.html +++ b/templates/personindex.html @@ -1,44 +1,44 @@ -{% extends "base.html" %} -{% load wiki_markup %} - -{% block title %}Person Index{% endblock %} - -{% block content %} - -

Notable expoers

- - -{% for person in notablepersons %} - - - - - - -{% endfor %} -
PersonFirstLastNotability
{{person|wiki_to_html_short}}{{ person.first.expedition.year }}{{ person.last.expedition.year }}{{person.notability}}
- - -

All expoers

- - -{% for persons in personss %} - -{% endfor %} - -
- - - -{% for person in persons %} - - - - - - -{% endfor %} -
PersonFirstLastSurveyed length
{{person|wiki_to_html_short}}{{person.first.expedition.year}}{{person.last.expedition.year}}{{ person.surveyedleglength }}
-
- -{% endblock %} +{% extends "base.html" %} +{% load wiki_markup %} + +{% block title %}Person Index{% endblock %} + +{% block content %} + +

Notable expoers

+ + +{% for person in notablepersons %} + + + + + + +{% endfor %} +
PersonFirstLastNotability
{{person|wiki_to_html_short}}{{ person.first.expedition.year }}{{ person.last.expedition.year }}{{person.notability}}
+ + +

All expoers

+ + +{% for persons in personss %} + +{% endfor %} + +
+ + + +{% for person in persons %} + + + + + + +{% endfor %} +
PersonFirstLastSurveyed length
{{person|wiki_to_html_short}}{{person.first.expedition.year}}{{person.last.expedition.year}}{{ person.surveyedleglength }}
+
+ +{% endblock %} diff --git a/templates/profiles/create_profile.html b/templates/profiles/create_profile.html index 7e3259799..a14716029 100644 --- a/templates/profiles/create_profile.html +++ b/templates/profiles/create_profile.html @@ -1,13 +1,13 @@ -{% extends "base.html" %} - -{% block content %} - -
-{{ form.as_p }} - -
- -{% if form.errors %} -

Please correct the errors below

-{% endif %} +{% extends "base.html" %} + +{% block content %} + +
+{{ form.as_p }} + +
+ +{% if form.errors %} +

Please correct the errors below

+{% endif %} {% endblock %} \ No newline at end of file diff --git a/templates/profiles/edit_profile.html b/templates/profiles/edit_profile.html index 7e3259799..a14716029 100644 --- a/templates/profiles/edit_profile.html +++ b/templates/profiles/edit_profile.html @@ -1,13 +1,13 @@ -{% extends "base.html" %} - -{% block content %} - -
-{{ form.as_p }} - -
- -{% if form.errors %} -

Please correct the errors below

-{% endif %} +{% extends "base.html" %} + +{% block content %} + +
+{{ form.as_p }} + +
+ +{% if form.errors %} +

Please correct the errors below

+{% endif %} {% endblock %} \ No newline at end of file diff --git a/templates/profiles/profile_detail.html b/templates/profiles/profile_detail.html index baf3fae6b..cf2fb765b 100644 --- a/templates/profiles/profile_detail.html +++ b/templates/profiles/profile_detail.html @@ -1,14 +1,14 @@ -{% extends "base.html" %} - -{% block contentheader %} -

Profile for {{ profile }}

-{% endblock %} - -{% block content %} - -{{ profile }} - -{% if form.errors %} -

Please correct the errors below

-{% endif %} +{% extends "base.html" %} + +{% block contentheader %} +

Profile for {{ profile }}

+{% endblock %} + +{% block content %} + +{{ profile }} + +{% if form.errors %} +

Please correct the errors below

+{% endif %} {% endblock %} \ No newline at end of file diff --git a/templates/profiles/select_profile.html b/templates/profiles/select_profile.html index 810efd264..e18191be0 100644 --- a/templates/profiles/select_profile.html +++ b/templates/profiles/select_profile.html @@ -1,40 +1,40 @@ -{% extends "base.html" %} - -{% block content %} - -

Troggle profile selection page

- -Hello, {{ user }}. - -

- -{% if user.person %} -This is where you go to associate a new user account with a pre-existing profile from old expo data. - -

- -However, you already have a profile- your name should be {{user.person.first_name}} {{user.person.last_name}}. If you don't believe me, go see it at:

{{ user.person.get_absolute_url }}

or edit it at: -

{{ user.person.get_admin_url }} .

- -If your account is associated with the wrong person's profile due to inebriation or incompetance during account setup, click here to dissasociate your profile from your user account. - -{% else %} - -You have an account in the system, but no profile. If you have been on expo before, please choose yourself from the list below. -

- -
-{{ form.as_p }} - -
-
- -Yes, you could choose the wrong person if you want. That would be lame. Instead, do something that's actually funny. For example, fry a random object or maybe take some mac and cheese somewhere it doesn't usually get to go. Perhaps you can start a new tradition of laminating the expo leader. - - -{% endif %} - -{% if form.errors %} -

Please correct the errors below

-{% endif %} +{% extends "base.html" %} + +{% block content %} + +

Troggle profile selection page

+ +Hello, {{ user }}. + +

+ +{% if user.person %} +This is where you go to associate a new user account with a pre-existing profile from old expo data. + +

+ +However, you already have a profile- your name should be {{user.person.first_name}} {{user.person.last_name}}. If you don't believe me, go see it at:

{{ user.person.get_absolute_url }}

or edit it at: +

{{ user.person.get_admin_url }} .

+ +If your account is associated with the wrong person's profile due to inebriation or incompetance during account setup, click here to dissasociate your profile from your user account. + +{% else %} + +You have an account in the system, but no profile. If you have been on expo before, please choose yourself from the list below. +

+ +
+{{ form.as_p }} + +
+
+ +Yes, you could choose the wrong person if you want. That would be lame. Instead, do something that's actually funny. For example, fry a random object or maybe take some mac and cheese somewhere it doesn't usually get to go. Perhaps you can start a new tradition of laminating the expo leader. + + +{% endif %} + +{% if form.errors %} +

Please correct the errors below

+{% endif %} {% endblock %} \ No newline at end of file diff --git a/templates/qm.html b/templates/qm.html index 6e2a2fb5b..f96019776 100644 --- a/templates/qm.html +++ b/templates/qm.html @@ -1,49 +1,49 @@ -{% extends "base.html" %} -{% load wiki_markup %} -{% load link %} - -{% block title %} QM: {{qm|wiki_to_html_short}} {% endblock %} - -{% block editLink %}| Edit QM {{qm|wiki_to_html_short}}{% endblock %} - - - -{% block contentheader %} - - - - - - -
Previous{{qm|wiki_to_html_short}}Next
-{% endblock %} - -{% block related %} - -{% endblock %} -

Related items

- -Parent cave: {{qm.found_by.cave|link}} -(todo: add parent survey and parent subcave) -{% block content %} - -

Location

-{{qm.location_description}} - - -

Creation

-Found by {{qm.found_by}} on {{qm.found_by.date}}. - -

Completion

-{% if ticked_off_by %} -{{qm.completion_description}} -Ticked off by: {{qm.ticked_off_by}}
-Description: {{qm.completion_description}} -{% else %} -None yet- STILL EXTANT. -{% endif %} - -

Comment

-{{qm.comment}} - -{% endblock %} +{% extends "base.html" %} +{% load wiki_markup %} +{% load link %} + +{% block title %} QM: {{qm|wiki_to_html_short}} {% endblock %} + +{% block editLink %}| Edit QM {{qm|wiki_to_html_short}}{% endblock %} + + + +{% block contentheader %} + + + + + + +
Previous{{qm|wiki_to_html_short}}Next
+{% endblock %} + +{% block related %} + +{% endblock %} +

Related items

+ +Parent cave: {{qm.found_by.cave|link}} +(todo: add parent survey and parent subcave) +{% block content %} + +

Location

+{{qm.location_description}} + + +

Creation

+Found by {{qm.found_by}} on {{qm.found_by.date}}. + +

Completion

+{% if ticked_off_by %} +{{qm.completion_description}} +Ticked off by: {{qm.ticked_off_by}}
+Description: {{qm.completion_description}} +{% else %} +None yet- STILL EXTANT. +{% endif %} + +

Comment

+{{qm.comment}} + +{% endblock %} diff --git a/templates/registration/activate.html b/templates/registration/activate.html index ba6be9280..3f95a18ec 100644 --- a/templates/registration/activate.html +++ b/templates/registration/activate.html @@ -1,25 +1,25 @@ -{% extends "base.html" %} - -{% block title %} -New troggle account registered -{% endblock %} - -{% block header %} -

activate.html

-{% endblock %} - -{% block content %} - -{% if account %} -

-Hello, {{ account }}! Your account is now activated. Now you can log in with the password you chose. Use the links in the upper right to control this in the future. -

- -

-If you have been on the expedition in the past, you already have a profile in the system; click here to find it and link it to your account. Otherwise, please create yourself a new profile. -

-{% else %} - -The activation key you entered has already been used or was invalid. -{% endif %} +{% extends "base.html" %} + +{% block title %} +New troggle account registered +{% endblock %} + +{% block header %} +

activate.html

+{% endblock %} + +{% block content %} + +{% if account %} +

+Hello, {{ account }}! Your account is now activated. Now you can log in with the password you chose. Use the links in the upper right to control this in the future. +

+ +

+If you have been on the expedition in the past, you already have a profile in the system; click here to find it and link it to your account. Otherwise, please create yourself a new profile. +

+{% else %} + +The activation key you entered has already been used or was invalid. +{% endif %} {% endblock %} diff --git a/templates/registration/activation_email.html b/templates/registration/activation_email.html index 3d560095f..abb0ad139 100644 --- a/templates/registration/activation_email.html +++ b/templates/registration/activation_email.html @@ -1,10 +1,10 @@ -

Hello {{ form.user }},

- -

Glad you're joining the CUCC EXPO team! Please go to

- -

{{ site }}{% url registration_activate activation_key %}

- -

to activate your account. Do this within {{ expiration_days }} days, or else you'll have to sign up again.

- -

Yours,
-The magical troggle

+

Hello {{ form.user }},

+ +

Glad you're joining the CUCC EXPO team! Please go to

+ +

{{ site }}{% url registration_activate activation_key %}

+ +

to activate your account. Do this within {{ expiration_days }} days, or else you'll have to sign up again.

+ +

Yours,
+The magical troggle

diff --git a/templates/registration/activation_email.txt b/templates/registration/activation_email.txt index 20aad5f8a..9b240c2e1 100644 --- a/templates/registration/activation_email.txt +++ b/templates/registration/activation_email.txt @@ -1,10 +1,10 @@ -Hello {{ form.user }}, - -Glad you're joining the CUCC EXPO team! Please go to - -{{ site }}{% url registration_activate activation_key %} - -to activate your account. Do this within {{ expiration_days }} days, or else you'll have to sign up again. - -Yours, +Hello {{ form.user }}, + +Glad you're joining the CUCC EXPO team! Please go to + +{{ site }}{% url registration_activate activation_key %} + +to activate your account. Do this within {{ expiration_days }} days, or else you'll have to sign up again. + +Yours, The magical troggle \ No newline at end of file diff --git a/templates/registration/login.html b/templates/registration/login.html index b93e4d8f9..388d41b5e 100644 --- a/templates/registration/login.html +++ b/templates/registration/login.html @@ -1,20 +1,20 @@ -{% extends "base.html" %} -{% load csrffaker %} - -{% block content %} - -{% if form.errors %} -

Your username and password didn't match. Please try again.

-{% endif %} - -
{% csrf_token %} - - - -
{{ form.username.label_tag }}{{ form.username }}
{{ form.password.label_tag }}{{ form.password }}
- - - -
- -{% endblock %} +{% extends "base.html" %} +{% load csrffaker %} + +{% block content %} + +{% if form.errors %} +

Your username and password didn't match. Please try again.

+{% endif %} + +
{% csrf_token %} + + + +
{{ form.username.label_tag }}{{ form.username }}
{{ form.password.label_tag }}{{ form.password }}
+ + + +
+ +{% endblock %} diff --git a/templates/registration/logout.html b/templates/registration/logout.html index 9e40c20d3..ef2a3b253 100644 --- a/templates/registration/logout.html +++ b/templates/registration/logout.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} -{% block content %} - You have been logged out. +{% extends "base.html" %} +{% block content %} + You have been logged out. {% endblock %} \ No newline at end of file diff --git a/templates/registration/registration_activate.html b/templates/registration/registration_activate.html index cbd540e52..6566bf445 100644 --- a/templates/registration/registration_activate.html +++ b/templates/registration/registration_activate.html @@ -1,6 +1,6 @@ -{% extends “base.html” %} -{% block body %} -Hello {{ account }}! - -Check your email to confirm the activation. There are {{ expiration_days }} days left to do it. +{% extends “base.html” %} +{% block body %} +Hello {{ account }}! + +Check your email to confirm the activation. There are {{ expiration_days }} days left to do it. {% endblock %} \ No newline at end of file diff --git a/templates/registration/registration_complete.html b/templates/registration/registration_complete.html index 78684fe86..4dac94bd8 100644 --- a/templates/registration/registration_complete.html +++ b/templates/registration/registration_complete.html @@ -1,13 +1,13 @@ -{% extends "base.html" %} - -{% block title %} -{{ block.super }}: registration complete -{% endblock %} - -{% block contentheader %} -

Registration Complete

-{% endblock %} - -{% block content %} -

Thank you for signing up. An email with the activation code has been sent to your inbox.

+{% extends "base.html" %} + +{% block title %} +{{ block.super }}: registration complete +{% endblock %} + +{% block contentheader %} +

Registration Complete

+{% endblock %} + +{% block content %} +

Thank you for signing up. An email with the activation code has been sent to your inbox.

{% endblock %} \ No newline at end of file diff --git a/templates/statistics.html b/templates/statistics.html index 1fddd674d..daca75284 100644 --- a/templates/statistics.html +++ b/templates/statistics.html @@ -1,8 +1,8 @@ -{% extends "base.html" %} -{% load wiki_markup %} - -{% block title %}Database statistics{% endblock %} - -{% block content %} -Over the course of {{ expoCount }} expeditions, {{ personCount }} people have contributed {{ caveCount }} caves and {{ logbookEntryCount }} logbook entries. +{% extends "base.html" %} +{% load wiki_markup %} + +{% block title %}Database statistics{% endblock %} + +{% block content %} +Over the course of {{ expoCount }} expeditions, {{ personCount }} people have contributed {{ caveCount }} caves and {{ logbookEntryCount }} logbook entries. {% endblock %} \ No newline at end of file diff --git a/templates/subcave.html b/templates/subcave.html index fbb8d1d64..41fb2d047 100644 --- a/templates/subcave.html +++ b/templates/subcave.html @@ -1,59 +1,59 @@ -{% extends "cavebase.html" %} -{% load wiki_markup %} -{% load mptt_tags %} -{% block title %} Subcave {{subcave}} {% endblock title %} -{% block editLink %}Edit subcave {{subcave|wiki_to_html_short}}{% endblock %} - -{% block contentheader %} - {{subcave.title}} -{% endblock contentheader %} - - - -{% block content %} -{% block related %} - -

Related places

- -

Parent

- - - -

Connected subareas

- - - -

Children

- - - - -{% endblock %} - -ok here comes the drilldown
-{% drilldown_tree_for_node subcave as drilldown %} -{% for each in drilldown %} -{{ each }}> -{% endfor %} - - -

{{subcave}}

-

- {{subcave.description}} -

- +{% extends "cavebase.html" %} +{% load wiki_markup %} +{% load mptt_tags %} +{% block title %} Subcave {{subcave}} {% endblock title %} +{% block editLink %}Edit subcave {{subcave|wiki_to_html_short}}{% endblock %} + +{% block contentheader %} + {{subcave.title}} +{% endblock contentheader %} + + + +{% block content %} +{% block related %} + +

Related places

+ +

Parent

+ + + +

Connected subareas

+ + + +

Children

+ + + + +{% endblock %} + +ok here comes the drilldown
+{% drilldown_tree_for_node subcave as drilldown %} +{% for each in drilldown %} +{{ each }}> +{% endfor %} + + +

{{subcave}}

+

+ {{subcave.description}} +

+ {% endblock content %} \ No newline at end of file diff --git a/templates/survexblock.html b/templates/survexblock.html index 31958c066..c4c1066dc 100644 --- a/templates/survexblock.html +++ b/templates/survexblock.html @@ -1,49 +1,49 @@ -{% extends "base.html" %} -{% load wiki_markup %} -{% load survex_markup %} - - -{% block title %}Survex Block{% endblock %} - -{% block content %} -

Survex Block {{survexblock.survexpath}}

- -

Link to {{survexblock.survexfile.path}}

- -

Needs duplicates removed from right hand column

-

Needs links to survex file presentation

-

Needs to start dealing with misspellings of names (prob by editing the originals)

- -
- -{% if survexblock.parent %} -

Survey block above:

-

{{survexblock.parent.survexpath}}

-{% endif %} - -{% if survexblock.survexblock_set.all %} -

Survey blocks below:

- {% for survexblockdown in survexblock.survexblock_set.all %} -

{{survexblockdown.survexpath}}

- {% endfor %} -{% endif %} - -

Date: {{survexblock.date}}

- - -{% for personrole in survexblock.GetPersonroles %} - - - - -{% endfor %} -
{{personrole.person}}{{personrole.roles}}
- - -
- -
- {{ftext|survex_to_html}} -
- -{% endblock %} +{% extends "base.html" %} +{% load wiki_markup %} +{% load survex_markup %} + + +{% block title %}Survex Block{% endblock %} + +{% block content %} +

Survex Block {{survexblock.survexpath}}

+ +

Link to {{survexblock.survexfile.path}}

+ +

Needs duplicates removed from right hand column

+

Needs links to survex file presentation

+

Needs to start dealing with misspellings of names (prob by editing the originals)

+ +
+ +{% if survexblock.parent %} +

Survey block above:

+

{{survexblock.parent.survexpath}}

+{% endif %} + +{% if survexblock.survexblock_set.all %} +

Survey blocks below:

+ {% for survexblockdown in survexblock.survexblock_set.all %} +

{{survexblockdown.survexpath}}

+ {% endfor %} +{% endif %} + +

Date: {{survexblock.date}}

+ + +{% for personrole in survexblock.GetPersonroles %} + + + + +{% endfor %} +
{{personrole.person}}{{personrole.roles}}
+ + +
+ +
+ {{ftext|survex_to_html}} +
+ +{% endblock %} diff --git a/templates/survexscansfolder.html b/templates/survexscansfolder.html index 6f8bd3aff..fe2191662 100644 --- a/templates/survexscansfolder.html +++ b/templates/survexscansfolder.html @@ -1,33 +1,33 @@ -{% extends "base.html" %} -{% load wiki_markup %} -{% load survex_markup %} - -{% block title %}Survex Scans Folder{% endblock %} - -{% block content %} - -

Survex Scans in: {{survexscansfolder.walletname}}

- -{% for survexscansingle in survexscansfolder.survexscansingle_set.all %} - - - - -{% endfor %} -
{{survexscansingle.name}} - {% for survexblock in survexscansingle.survexblock_set.all %} - {{survexblock}} - {% endfor %} -
- -

Surveys referring to this wallet

- - -{% for survexblock in survexscansfolder.survexblock_set.all %} - - - -{% endfor %} -
{{survexblock}}
- -{% endblock %} +{% extends "base.html" %} +{% load wiki_markup %} +{% load survex_markup %} + +{% block title %}Survex Scans Folder{% endblock %} + +{% block content %} + +

Survex Scans in: {{survexscansfolder.walletname}}

+ +{% for survexscansingle in survexscansfolder.survexscansingle_set.all %} + + + + +{% endfor %} +
{{survexscansingle.name}} + {% for survexblock in survexscansingle.survexblock_set.all %} + {{survexblock}} + {% endfor %} +
+ +

Surveys referring to this wallet

+ + +{% for survexblock in survexscansfolder.survexblock_set.all %} + + + +{% endfor %} +
{{survexblock}}
+ +{% endblock %} diff --git a/templates/survexscansfolders.html b/templates/survexscansfolders.html index 195b8982b..597bacfe6 100644 --- a/templates/survexscansfolders.html +++ b/templates/survexscansfolders.html @@ -1,25 +1,25 @@ -{% extends "base.html" %} -{% load wiki_markup %} -{% load survex_markup %} - -{% block title %}All Survex scans folders{% endblock %} - -{% block content %} - -

All Survex scans folders

- - -{% for survexscansfolder in survexscansfolders %} - - - - - -{% endfor %} -
Scans folderFilesSurvex blocks
{{survexscansfolder.walletname}}{{survexscansfolder.survexscansingle_set.all|length}} - {% for survexblock in survexscansfolder.survexblock_set.all %} - {{survexblock}} - {% endfor %} -
- +{% extends "base.html" %} +{% load wiki_markup %} +{% load survex_markup %} + +{% block title %}All Survex scans folders{% endblock %} + +{% block content %} + +

All Survex scans folders

+ + +{% for survexscansfolder in survexscansfolders %} + + + + + +{% endfor %} +
Scans folderFilesSurvex blocks
{{survexscansfolder.walletname}}{{survexscansfolder.survexscansingle_set.all|length}} + {% for survexblock in survexscansfolder.survexblock_set.all %} + {{survexblock}} + {% endfor %} +
+ {% endblock %} \ No newline at end of file diff --git a/templates/survey.html b/templates/survey.html index 37b2dfe9a..9dca0dfba 100644 --- a/templates/survey.html +++ b/templates/survey.html @@ -1,193 +1,193 @@ -{% extends "base.html" %} -{% load wiki_markup %} - - -{% block title %}CUCC Virtual Survey Binder: {{ current_expedition }}{{ current_survey }}{%endblock%} -{% block head %} - - - - - -{% endblock %} - -
- CUCC Expo virtual survey binder: - {% if current_survey %} - {{current_survey}} - {% else %} - {{current_expedition}} - {% endif %} -
- -{% block nav %} -
- -

Choose a year

-
- -
- -
- - -
-{% if current_expedition %} -

Choose a wallet number

-
- - -
-

Click to toggle:

-
- - - - - - -
- -{% endif %} -{% endblock %} - - -{% block content %} -
- -
-

Survey progress table for {{ current_expedition }}

- {% if current_expedition.survey_set.all %} - - - - {% for survey in current_expedition.survey_set.all %} - - {% endfor %} - - - {% for survey in current_expedition.survey_set.all %} - - {% endfor %} - - - {% for survey in current_expedition.survey_set.all %} - - {% endfor %} - - - {% for survey in current_expedition.survey_set.all %} - - {% endfor %} - - - {% for survey in current_expedition.survey_set.all %} - - {% endfor %} -
{{ survey.wallet_number }}
Notes {% if survey.notes %} - ✓ - {% endif %}
Survex file {% if survey.survex_file %} - ✓ - {% endif %}
Plans {% if survey.plans %} - ✓ - {% endif %}
Elevations {% if survey.elevations %} - ✓ - {% endif %}
- {% else %} -
[ There are no surveys in the database for this year. Put link in to add one. ]
- {% endif %} -
-
-

Scanned notes for {{ current_survey }}.

- {% for noteItem in notes %} -
-

-

File at: {{ noteItem.file.name }}
- Scanned by: {{ noteItem.scanned_by }}
- On: {{ noteItem.scanned_on }}
-

-

-
- {% endfor %} - -
-
-
survex file editor, keeping file in original structure
- who entered by
-
centreline
-
-

Scanned plan sketch files for {{ current_survey }}.

- {% for sketchItem in planSketches %} -
-

-

File at: {{ sketchItem.file.name }}
- Scanned by: {{ sketchItem.scanned_by }}
- On: {{ sketchItem.scanned_on }}
-

-

-
- {% endfor %} - -
-
link to tunnel xml file. potentially instance of tunnel applet...
-
link to main sketch file
- -
-
- -{% endblock %} +{% extends "base.html" %} +{% load wiki_markup %} + + +{% block title %}CUCC Virtual Survey Binder: {{ current_expedition }}{{ current_survey }}{%endblock%} +{% block head %} + + + + + +{% endblock %} + +
+ CUCC Expo virtual survey binder: + {% if current_survey %} + {{current_survey}} + {% else %} + {{current_expedition}} + {% endif %} +
+ +{% block nav %} +
+ +

Choose a year

+
+ +
+ +
+ + +
+{% if current_expedition %} +

Choose a wallet number

+
+ + +
+

Click to toggle:

+
+ + + + + + +
+ +{% endif %} +{% endblock %} + + +{% block content %} +
+ +
+

Survey progress table for {{ current_expedition }}

+ {% if current_expedition.survey_set.all %} + + + + {% for survey in current_expedition.survey_set.all %} + + {% endfor %} + + + {% for survey in current_expedition.survey_set.all %} + + {% endfor %} + + + {% for survey in current_expedition.survey_set.all %} + + {% endfor %} + + + {% for survey in current_expedition.survey_set.all %} + + {% endfor %} + + + {% for survey in current_expedition.survey_set.all %} + + {% endfor %} +
{{ survey.wallet_number }}
Notes {% if survey.notes %} + ✓ + {% endif %}
Survex file {% if survey.survex_file %} + ✓ + {% endif %}
Plans {% if survey.plans %} + ✓ + {% endif %}
Elevations {% if survey.elevations %} + ✓ + {% endif %}
+ {% else %} +
[ There are no surveys in the database for this year. Put link in to add one. ]
+ {% endif %} +
+
+

Scanned notes for {{ current_survey }}.

+ {% for noteItem in notes %} +
+

+

File at: {{ noteItem.file.name }}
+ Scanned by: {{ noteItem.scanned_by }}
+ On: {{ noteItem.scanned_on }}
+

+

+
+ {% endfor %} + +
+
+
survex file editor, keeping file in original structure
+ who entered by
+
centreline
+
+

Scanned plan sketch files for {{ current_survey }}.

+ {% for sketchItem in planSketches %} +
+

+

File at: {{ sketchItem.file.name }}
+ Scanned by: {{ sketchItem.scanned_by }}
+ On: {{ sketchItem.scanned_on }}
+

+

+
+ {% endfor %} + +
+
link to tunnel xml file. potentially instance of tunnel applet...
+
link to main sketch file
+ +
+
+ +{% endblock %} diff --git a/templates/svxcavesingle.html b/templates/svxcavesingle.html index 123e92ad1..1d24466f4 100644 --- a/templates/svxcavesingle.html +++ b/templates/svxcavesingle.html @@ -1,81 +1,81 @@ -{% extends "base.html" %} -{% load wiki_markup %} -{% load link %} - -{% block title %}List of survex files{% endblock %} - -{% block content %} - -

Surveys for {{cave}}

- -

-{% for survexdirectory in cave.survexdirectory_set.all %} - {{survexdirectory.path}} -{% endfor %} -

- -{% for survexdirectory in cave.survexdirectory_set.all %} -

{{survexdirectory.path}}

- - - - -{% for survexfile in survexdirectory.survexfile_set.all %} - - {% if survexfile.exists %} - - - -{% for survexblock in survexfile.survexblock_set.all %} - - - - - - - - - - - - -{% endfor %} -{% endfor %} -
Survex fileBlockDateExplorerslengthTitlesScans
- {% else %} - - {% endif %} - - {% ifequal survexfile survexdirectory.primarysurvexfile %} - {{survexfile.path}} - {% else %} - {{survexfile.path}} - {% endifequal %} -
{{survexblock.name}} - {% if survexblock.expedition %} - {{survexblock.date}} - {% else %} - {{survexblock.date}} - {% endif %} - - {% for personrole in survexblock.personrole_set.all %} - {% if personrole.personexpedition %} - {{personrole.personname}} - {% else %} - {{personrole.personname}} - {% endif %} - {% endfor %} - {{survexblock.totalleglength}} - {% for survextitle in survexblock.survextitle_set.all %} - {{survextitle.title}} - {% endfor %} - - {% if survexblock.survexscansfolder %} - {{survexblock.survexscansfolder.walletname}} - {% endif %} -
- -{% endfor %} - -{% endblock %} - +{% extends "base.html" %} +{% load wiki_markup %} +{% load link %} + +{% block title %}List of survex files{% endblock %} + +{% block content %} + +

Surveys for {{cave}}

+ +

+{% for survexdirectory in cave.survexdirectory_set.all %} + {{survexdirectory.path}} +{% endfor %} +

+ +{% for survexdirectory in cave.survexdirectory_set.all %} +

{{survexdirectory.path}}

+ + + + +{% for survexfile in survexdirectory.survexfile_set.all %} + + {% if survexfile.exists %} + + + +{% for survexblock in survexfile.survexblock_set.all %} + + + + + + + + + + + + +{% endfor %} +{% endfor %} +
Survex fileBlockDateExplorerslengthTitlesScans
+ {% else %} + + {% endif %} + + {% ifequal survexfile survexdirectory.primarysurvexfile %} + {{survexfile.path}} + {% else %} + {{survexfile.path}} + {% endifequal %} +
{{survexblock.name}} + {% if survexblock.expedition %} + {{survexblock.date}} + {% else %} + {{survexblock.date}} + {% endif %} + + {% for personrole in survexblock.personrole_set.all %} + {% if personrole.personexpedition %} + {{personrole.personname}} + {% else %} + {{personrole.personname}} + {% endif %} + {% endfor %} + {{survexblock.totalleglength}} + {% for survextitle in survexblock.survextitle_set.all %} + {{survextitle.title}} + {% endfor %} + + {% if survexblock.survexscansfolder %} + {{survexblock.survexscansfolder.walletname}} + {% endif %} +
+ +{% endfor %} + +{% endblock %} + diff --git a/templates/svxfile.html b/templates/svxfile.html index ed4318dd2..bf9f1c3b6 100644 --- a/templates/svxfile.html +++ b/templates/svxfile.html @@ -1,76 +1,76 @@ -{% extends "base.html" %} -{% load survex_markup %} - -{% block title %}{{ title }}{% endblock %} - -{% block head %} - - - - - -{% endblock %} - -{% block content %} -

Survex File: {{ title }}

- -{% if svxincludes %} -

Included files: -{% for svxinclude in svxincludes %} - {{svxinclude}} -{% endfor %} -

-{% endif %} - -
-
{{form.code}}
-
{{form.filename}} {{form.dirname}} {{form.datetime}} {{form.outputtype}}
- - - -
- -
-
-{% for diffline in difflist %}{{diffline}}
-{% endfor %}
-
- -{% if logmessage %} -{% if has_3d %} -

3d file

-{% else %} -

No 3d file

-{% endif %} -
-LOGMESSAGES
-{{logmessage}}
-
-{% endif %} -
- -{% endblock %} +{% extends "base.html" %} +{% load survex_markup %} + +{% block title %}{{ title }}{% endblock %} + +{% block head %} + + + + + +{% endblock %} + +{% block content %} +

Survex File: {{ title }}

+ +{% if svxincludes %} +

Included files: +{% for svxinclude in svxincludes %} + {{svxinclude}} +{% endfor %} +

+{% endif %} + +
+
{{form.code}}
+
{{form.filename}} {{form.dirname}} {{form.datetime}} {{form.outputtype}}
+ + + +
+ +
+
+{% for diffline in difflist %}{{diffline}}
+{% endfor %}
+
+ +{% if logmessage %} +{% if has_3d %} +

3d file

+{% else %} +

No 3d file

+{% endif %} +
+LOGMESSAGES
+{{logmessage}}
+
+{% endif %} +
+ +{% endblock %} diff --git a/templates/svxfilecavelist.html b/templates/svxfilecavelist.html index a0db893d7..52c8e83bb 100644 --- a/templates/svxfilecavelist.html +++ b/templates/svxfilecavelist.html @@ -1,66 +1,66 @@ -{% extends "base.html" %} -{% load wiki_markup %} -{% load link %} - -{% block title %}List of survex files{% endblock %} - -{% block content %} -

caves with subdirectories | caves with multiple files | caves with single files

- -

Link to all.svx for processing

- -

Caves with subdirectories

- -{% for subdircave, cavefiles, subsurvdirs in subdircaves %} -

{{cavefiles.0.1}} - dates and explorers

- - - - - - -{% for primarycavefile, subcavefiles in subsurvdirs %} - - - - -{% endfor %} -
{{cavefiles.0.1}} - {% for cavepath, cavename in cavefiles.1 %} - {{cavename}} - {% endfor %} -
{{primarycavefile.1}} - {% for cavepath, cavename in subcavefiles %} - {{cavename}} - {% endfor %} -
- -{% endfor %} - - -

Caves of multiple files

- - -{% for primarycavefile, subcavefiles in multifilecaves %} - - - - -{% endfor %} -
Dates and explorersSurvex files
- {{primarycavefile.1}} - - {{primarycavefile.1}} - - {% for cavepath, cavename in subcavefiles %} - {{cavename}} - {% endfor %} -
- -

Caves of one file

-

-{% for cavepath, cavename in onefilecaves %} - {{cavename}} -{% endfor %} -

- -{% endblock %} +{% extends "base.html" %} +{% load wiki_markup %} +{% load link %} + +{% block title %}List of survex files{% endblock %} + +{% block content %} +

caves with subdirectories | caves with multiple files | caves with single files

+ +

Link to all.svx for processing

+ +

Caves with subdirectories

+ +{% for subdircave, cavefiles, subsurvdirs in subdircaves %} +

{{cavefiles.0.1}} - dates and explorers

+ + + + + + +{% for primarycavefile, subcavefiles in subsurvdirs %} + + + + +{% endfor %} +
{{cavefiles.0.1}} + {% for cavepath, cavename in cavefiles.1 %} + {{cavename}} + {% endfor %} +
{{primarycavefile.1}} + {% for cavepath, cavename in subcavefiles %} + {{cavename}} + {% endfor %} +
+ +{% endfor %} + + +

Caves of multiple files

+ + +{% for primarycavefile, subcavefiles in multifilecaves %} + + + + +{% endfor %} +
Dates and explorersSurvex files
+ {{primarycavefile.1}} + + {{primarycavefile.1}} - + {% for cavepath, cavename in subcavefiles %} + {{cavename}} + {% endfor %} +
+ +

Caves of one file

+

+{% for cavepath, cavename in onefilecaves %} + {{cavename}} +{% endfor %} +

+ +{% endblock %} diff --git a/templates/svxfiledifflistonly.html b/templates/svxfiledifflistonly.html index f51744ee2..835125bea 100644 --- a/templates/svxfiledifflistonly.html +++ b/templates/svxfiledifflistonly.html @@ -1,18 +1,18 @@ -
- using difflistonly.html
-{% for diffline in difflist %}{{diffline}}
-{% endfor %}
-
- -{% if logmessage %} -{% if has_3d %} -

3d file

-{% else %} -

No 3d file

-{% endif %} -
-LOGMESSAGES
-{{logmessage}}
-
-{% endif %} - +
+ using difflistonly.html
+{% for diffline in difflist %}{{diffline}}
+{% endfor %}
+
+ +{% if logmessage %} +{% if has_3d %} +

3d file

+{% else %} +

No 3d file

+{% endif %} +
+LOGMESSAGES
+{{logmessage}}
+
+{% endif %} + diff --git a/templates/tasks.html b/templates/tasks.html index a429bd5df..36d35f415 100644 --- a/templates/tasks.html +++ b/templates/tasks.html @@ -1,39 +1,39 @@ -{% extends "base.html" %} -{% load wiki_markup %} -{% load link %} - -{% block title %}Cambridge Expeditions to Austria{% endblock %} - -{% block content %} -

Expo member tasks

- -

Add new data

- -
  • Upload a photo
  • -
  • Record a new trip
  • - -

    Your unfinished business

    - {% for survey in surveys_unfinished %} -
  • {{survey|link}}
  • - {% endfor %} - -

    General unfinished business

    -add wikilinks - -

    Caving recommendations

    - {% for qm in qms_recommended %} -
  • {{qm|link}}
  • - {% endfor %} - -

    Profile tasks

    - -
  • Dates present on expo
  • -
  • Mugshot
  • -
  • Blurb
  • - -{% endblock content %} - -{% block margins %} - - -{% endblock margins %} +{% extends "base.html" %} +{% load wiki_markup %} +{% load link %} + +{% block title %}Cambridge Expeditions to Austria{% endblock %} + +{% block content %} +

    Expo member tasks

    + +

    Add new data

    + +
  • Upload a photo
  • +
  • Record a new trip
  • + +

    Your unfinished business

    + {% for survey in surveys_unfinished %} +
  • {{survey|link}}
  • + {% endfor %} + +

    General unfinished business

    +add wikilinks + +

    Caving recommendations

    + {% for qm in qms_recommended %} +
  • {{qm|link}}
  • + {% endfor %} + +

    Profile tasks

    + +
  • Dates present on expo
  • +
  • Mugshot
  • +
  • Blurb
  • + +{% endblock content %} + +{% block margins %} + + +{% endblock margins %} diff --git a/templates/todo.html b/templates/todo.html index 0aafadb46..a678f50d2 100644 --- a/templates/todo.html +++ b/templates/todo.html @@ -1,61 +1,61 @@ -{% extends "base.html" %} -{% load wiki_markup %} - -{% block title %}Cambridge Expeditions to Austria{% endblock %} - -{% block content %} - -

    The unfinished front page

    - - -

    Further work

    - -

    Please see the issues tracker on google code. You can contribute new feature requests and bug reports.

    - -

    Julian's work: -

    parse 1992-1976 logbooks; (esp top 161)

    -

    detect T/U on log entries;

    -

    name matching and spelling in survex files;

    -

    Improve logbook wikihtml text

    - -

    Other work:

    -

    surf through the tunnel sketches and images

    -

    bugs with all.svx block (double dot) -

    render bitmap view of every survex block as a thumbnail

    -

    upload tunnel images and tunnel sketches

    -

    where are the subcaves;

    -

    cave section entrance match for logbook entries

    -

    simplify the survex parsing code (if necessary);

    -

    wiki survex stop linegap between comment lins

    -

    links between logbooks and survex blocks to cave things;

    -

    mini-tree of survexblocks;

    -

    connect sketches to caves to survey blocks and render thumbnailwise;

    -

    all images to start appearing in pages; and so on

    - -

    {{message}}

    - -
    - - -
    - - - -{% endblock %} +{% extends "base.html" %} +{% load wiki_markup %} + +{% block title %}Cambridge Expeditions to Austria{% endblock %} + +{% block content %} + +

    The unfinished front page

    + + +

    Further work

    + +

    Please see the issues tracker on google code. You can contribute new feature requests and bug reports.

    + +

    Julian's work: +

    parse 1992-1976 logbooks; (esp top 161)

    +

    detect T/U on log entries;

    +

    name matching and spelling in survex files;

    +

    Improve logbook wikihtml text

    + +

    Other work:

    +

    surf through the tunnel sketches and images

    +

    bugs with all.svx block (double dot) +

    render bitmap view of every survex block as a thumbnail

    +

    upload tunnel images and tunnel sketches

    +

    where are the subcaves;

    +

    cave section entrance match for logbook entries

    +

    simplify the survex parsing code (if necessary);

    +

    wiki survex stop linegap between comment lins

    +

    links between logbooks and survex blocks to cave things;

    +

    mini-tree of survexblocks;

    +

    connect sketches to caves to survey blocks and render thumbnailwise;

    +

    all images to start appearing in pages; and so on

    + +

    {{message}}

    + +
    + + +
    + + + +{% endblock %} diff --git a/templates/tunnelfiles.html b/templates/tunnelfiles.html index 3d49e5d21..caa389579 100644 --- a/templates/tunnelfiles.html +++ b/templates/tunnelfiles.html @@ -1,43 +1,43 @@ -{% extends "base.html" %} -{% load wiki_markup %} -{% load survex_markup %} - -{% block title %}Tunnel files{% endblock %} - -{% block content %} - -

    All Tunnel files

    - - -{% for tunnelfile in tunnelfiles %} - - - - - - - - - - - - - - - -{% endfor %} -
    FileFontSurvexBlocksSizePathsScans folderScan filesFrames
    {{tunnelfile.tunnelpath}}{{tunnelfile.bfontcolours}}{{tunnelfile.filesize}}{{tunnelfile.npaths}} - {% for survexscansfolder in tunnelfile.survexscansfolders.all %} - {{survexscansfolder.walletname}} - {% endfor %} - - {% for survexscansingle in tunnelfile.survexscans.all %} - {{survexscansingle.name}} - {% endfor %} - - {% for rtunnelfile in tunnelfile.tunnelcontains.all %} - {{rtunnelfile.tunnelpath}} - {% endfor %} -
    - +{% extends "base.html" %} +{% load wiki_markup %} +{% load survex_markup %} + +{% block title %}Tunnel files{% endblock %} + +{% block content %} + +

    All Tunnel files

    + + +{% for tunnelfile in tunnelfiles %} + + + + + + + + + + + + + + + +{% endfor %} +
    FileFontSurvexBlocksSizePathsScans folderScan filesFrames
    {{tunnelfile.tunnelpath}}{{tunnelfile.bfontcolours}}{{tunnelfile.filesize}}{{tunnelfile.npaths}} + {% for survexscansfolder in tunnelfile.survexscansfolders.all %} + {{survexscansfolder.walletname}} + {% endfor %} + + {% for survexscansingle in tunnelfile.survexscans.all %} + {{survexscansingle.name}} + {% endfor %} + + {% for rtunnelfile in tunnelfile.tunnelcontains.all %} + {{rtunnelfile.tunnelpath}} + {% endfor %} +
    + {% endblock %} \ No newline at end of file diff --git a/urls.py b/urls.py index f537d53c9..ea0ce0ac4 100644 --- a/urls.py +++ b/urls.py @@ -1,149 +1,149 @@ -from django.conf.urls.defaults import * -from django.conf import settings - -from core.views import * # flat import -from core.views_other import * -from core.views_caves import * -from core.views_survex import * -from core.models import * -from django.views.generic.create_update import create_object -from django.contrib import admin -from django.views.generic.list_detail import object_list -from django.contrib import admin -admin.autodiscover() - - -# type url probably means it's used. - -actualurlpatterns = patterns('', - - url(r'^troggle$', views_other.frontpage, name="frontpage"), - url(r'^todo/$', views_other.todo, name="todo"), - - url(r'^caves/?$', views_caves.caveindex, name="caveindex"), - url(r'^people/?$', views_logbooks.personindex, name="personindex"), - - url(r'^newqmnumber/?$', views_other.ajax_QM_number, ), - url(r'^lbo_suggestions/?$', logbook_entry_suggestions), - #(r'^person/(?P\d*)/?$', views_logbooks.person), - url(r'^person/(?P[A-Z]*[a-z\-\']*)[^a-zA-Z]*(?P[a-z\-\']*[^a-zA-Z]*[A-Z]*[a-z\-]*)/?', views_logbooks.person, name="person"), - #url(r'^person/(\w+_\w+)$', views_logbooks.person, name="person"), - - url(r'^expedition/(\d+)$', views_logbooks.expedition, name="expedition"), - url(r'^expeditions/?$', object_list, {'queryset':Expedition.objects.all(),'template_name':'object_list.html'},name="expeditions"), - url(r'^personexpedition/(?P[A-Z]*[a-z]*)[^a-zA-Z]*(?P[A-Z]*[a-z]*)/(?P\d+)/?$', views_logbooks.personexpedition, name="personexpedition"), - url(r'^logbookentry/(?P.*)/(?P.*)/?$', views_logbooks.logbookentry,name="logbookentry"), - url(r'^newlogbookentry/(?P.*)$', views_logbooks.newLogbookEntry, name="newLogBookEntry"), - url(r'^editlogbookentry/(?P[^/]*)/(?P[^/]*)/(?P[^/]*)/$', views_logbooks.newLogbookEntry, name="editLogBookEntry"), - url(r'^deletelogbookentry/(?P[^/]*)/(?P[^/]*)/(?P[^/]*)/$', views_logbooks.deleteLogbookEntry, name="deleteLogBookEntry"), - url(r'^newfile', views_other.newFile, name="newFile"), - - url(r'^getEntrances/(?P.*)', views_caves.get_entrances, name = "get_entrances"), - url(r'^getQMs/(?P.*)', views_caves.get_qms, name = "get_qms"), - url(r'^getPeople/(?P.*)', views_logbooks.get_people, name = "get_people"), - url(r'^getLogBookEntries/(?P.*)', views_logbooks.get_logbook_entries, name = "get_logbook_entries"), - - url(r'^cave/(?P[^/]+)/?$', views_caves.cave, name="cave"), - url(r'^caveslug/([^/]+)/?$', views_caves.caveSlug, name="caveSlug"), - url(r'^cave/entrance/([^/]+)/?$', views_caves.caveEntrance), - url(r'^cave/description/([^/]+)/?$', views_caves.caveDescription), - url(r'^cave/qms/([^/]+)/?$', views_caves.caveQMs), - url(r'^cave/logbook/([^/]+)/?$', views_caves.caveLogbook), - #url(r'^cavedescription/(?P[^/]+)/?$', views_caves.cave_description, name="cavedescription"), - #url(r'^cavedescription/?$', object_list, {'queryset':CaveDescription.objects.all(),'template_name':'object_list.html'}, name="cavedescriptions"), - #url(r'^cavehref/(.+)$', views_caves.cave, name="cave"),url(r'cave'), - - url(r'^jgtfile/(.*)$', view_surveys.jgtfile, name="jgtfile"), - url(r'^jgtuploadfile$', view_surveys.jgtuploadfile, name="jgtuploadfile"), - - url(r'^cave/(?P[^/]+)/?(?P[^/])$', ent), - #(r'^cave/(?P[^/]+)/edit/$', edit_cave), - #(r'^cavesearch', caveSearch), - - - url(r'^cave/(?P[^/]+)/(?P\d\d\d\d)-(?P\d*)(?P[ABCDX]?)?$', views_caves.qm, name="qm"), - - - url(r'^logbooksearch/(.*)/?$', views_logbooks.logbookSearch), - - - url(r'^statistics/?$', views_other.stats, name="stats"), - - url(r'^survey/?$', surveyindex, name="survey"), - url(r'^survey/(?P\d\d\d\d)\#(?P\d*)$', survey, name="survey"), - - url(r'^controlpanel/?$', views_other.controlPanel, name="controlpanel"), - url(r'^CAVETAB2\.CSV/?$', views_other.downloadCavetab, name="downloadcavetab"), - url(r'^Surveys\.csv/?$', views_other.downloadSurveys, name="downloadsurveys"), - url(r'^logbook(?P\d\d\d\d)\.(?P.*)/?$',views_other.downloadLogbook), - url(r'^logbook/?$',views_other.downloadLogbook, name="downloadlogbook"), - url(r'^cave/(?P[^/]+)/qm\.csv/?$', views_other.downloadQMs, name="downloadqms"), - (r'^downloadqms$', views_other.downloadQMs), - - url(r'^eyecandy$', views_other.eyecandy), - - (r'^admin/doc/?', include('django.contrib.admindocs.urls')), - url(r'^admin/(.*)', admin.site.root, name="admin"), - - # don't know why this needs troggle/ in here. nice to get it out - url(r'^troggle/media-admin/(?P.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ADMIN_DIR, 'show_indexes':True}), - - - (r'^accounts/', include('registration.urls')), - (r'^profiles/', include('profiles.urls')), - - -# (r'^personform/(.*)$', personForm), - - (r'^site_media/(?P.*)$', 'django.views.static.serve', - {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}), - (r'^tinymce_media/(?P.*)$', 'django.views.static.serve', - {'document_root': settings.TINY_MCE_MEDIA_ROOT, 'show_indexes': True}), - - - url(r'^survexblock/(.+)$', views_caves.survexblock, name="survexblock"), - url(r'^survexfile/(?P.*?)\.svx$', views_survex.svx, name="svx"), - url(r'^survexfile/(?P.*?)\.3d$', views_survex.threed, name="threed"), - url(r'^survexfile/(?P.*?)\.log$', views_survex.svxraw), - url(r'^survexfile/(?P.*?)\.err$', views_survex.err), - - - url(r'^survexfile/caves/$', views_survex.survexcaveslist, name="survexcaveslist"), - url(r'^survexfile/caves/(?P.*)$', views_survex.survexcavesingle, name="survexcavessingle"), - url(r'^survexfileraw/(?P.*?)\.svx$', views_survex.svxraw, name="svxraw"), - - - (r'^survey_files/listdir/(?P.*)$', view_surveys.listdir), - (r'^survey_files/download/(?P.*)$', view_surveys.download), - #(r'^survey_files/upload/(?P.*)$', view_surveys.upload), - - - - #(r'^survey_scans/(?P.*)$', 'django.views.static.serve', {'document_root': settings.SURVEY_SCANS, 'show_indexes':True}), - url(r'^survey_scans/$', view_surveys.surveyscansfolders, name="surveyscansfolders"), - url(r'^survey_scans/(?P[^/]+)/$', view_surveys.surveyscansfolder, name="surveyscansfolder"), - url(r'^survey_scans/(?P[^/]+)/(?P[^/]+(?:png|jpg))$', - view_surveys.surveyscansingle, name="surveyscansingle"), - - url(r'^tunneldata/$', view_surveys.tunneldata, name="tunneldata"), - url(r'^tunneldataraw/(?P.+?\.xml)$', view_surveys.tunnelfile, name="tunnelfile"), - url(r'^tunneldataraw/(?P.+?\.xml)/upload$',view_surveys.tunnelfileupload, name="tunnelfileupload"), - - #url(r'^tunneldatainfo/(?P.+?\.xml)$', view_surveys.tunnelfileinfo, name="tunnelfileinfo"), - - (r'^photos/(?P.*)$', 'django.views.static.serve', - {'document_root': settings.PHOTOS_ROOT, 'show_indexes':True}), - - # for those silly ideas - url(r'^experimental.*$', views_logbooks.experimental, name="experimental"), - - #url(r'^trip_report/?$',views_other.tripreport,name="trip_report") - - url(r'^(.*)_edit$', 'flatpages.views.editflatpage', name="editflatpage"), - url(r'^(.*)$', 'flatpages.views.flatpage', name="flatpage"), -) - -#Allow prefix to all urls -urlpatterns = patterns ('', - ('^%s' % settings.DIR_ROOT, include(actualurlpatterns)) -) +from django.conf.urls.defaults import * +from django.conf import settings + +from core.views import * # flat import +from core.views_other import * +from core.views_caves import * +from core.views_survex import * +from core.models import * +from django.views.generic.create_update import create_object +from django.contrib import admin +from django.views.generic.list_detail import object_list +from django.contrib import admin +admin.autodiscover() + + +# type url probably means it's used. + +actualurlpatterns = patterns('', + + url(r'^troggle$', views_other.frontpage, name="frontpage"), + url(r'^todo/$', views_other.todo, name="todo"), + + url(r'^caves/?$', views_caves.caveindex, name="caveindex"), + url(r'^people/?$', views_logbooks.personindex, name="personindex"), + + url(r'^newqmnumber/?$', views_other.ajax_QM_number, ), + url(r'^lbo_suggestions/?$', logbook_entry_suggestions), + #(r'^person/(?P\d*)/?$', views_logbooks.person), + url(r'^person/(?P[A-Z]*[a-z\-\']*)[^a-zA-Z]*(?P[a-z\-\']*[^a-zA-Z]*[A-Z]*[a-z\-]*)/?', views_logbooks.person, name="person"), + #url(r'^person/(\w+_\w+)$', views_logbooks.person, name="person"), + + url(r'^expedition/(\d+)$', views_logbooks.expedition, name="expedition"), + url(r'^expeditions/?$', object_list, {'queryset':Expedition.objects.all(),'template_name':'object_list.html'},name="expeditions"), + url(r'^personexpedition/(?P[A-Z]*[a-z]*)[^a-zA-Z]*(?P[A-Z]*[a-z]*)/(?P\d+)/?$', views_logbooks.personexpedition, name="personexpedition"), + url(r'^logbookentry/(?P.*)/(?P.*)/?$', views_logbooks.logbookentry,name="logbookentry"), + url(r'^newlogbookentry/(?P.*)$', views_logbooks.newLogbookEntry, name="newLogBookEntry"), + url(r'^editlogbookentry/(?P[^/]*)/(?P[^/]*)/(?P[^/]*)/$', views_logbooks.newLogbookEntry, name="editLogBookEntry"), + url(r'^deletelogbookentry/(?P[^/]*)/(?P[^/]*)/(?P[^/]*)/$', views_logbooks.deleteLogbookEntry, name="deleteLogBookEntry"), + url(r'^newfile', views_other.newFile, name="newFile"), + + url(r'^getEntrances/(?P.*)', views_caves.get_entrances, name = "get_entrances"), + url(r'^getQMs/(?P.*)', views_caves.get_qms, name = "get_qms"), + url(r'^getPeople/(?P.*)', views_logbooks.get_people, name = "get_people"), + url(r'^getLogBookEntries/(?P.*)', views_logbooks.get_logbook_entries, name = "get_logbook_entries"), + + url(r'^cave/(?P[^/]+)/?$', views_caves.cave, name="cave"), + url(r'^caveslug/([^/]+)/?$', views_caves.caveSlug, name="caveSlug"), + url(r'^cave/entrance/([^/]+)/?$', views_caves.caveEntrance), + url(r'^cave/description/([^/]+)/?$', views_caves.caveDescription), + url(r'^cave/qms/([^/]+)/?$', views_caves.caveQMs), + url(r'^cave/logbook/([^/]+)/?$', views_caves.caveLogbook), + #url(r'^cavedescription/(?P[^/]+)/?$', views_caves.cave_description, name="cavedescription"), + #url(r'^cavedescription/?$', object_list, {'queryset':CaveDescription.objects.all(),'template_name':'object_list.html'}, name="cavedescriptions"), + #url(r'^cavehref/(.+)$', views_caves.cave, name="cave"),url(r'cave'), + + url(r'^jgtfile/(.*)$', view_surveys.jgtfile, name="jgtfile"), + url(r'^jgtuploadfile$', view_surveys.jgtuploadfile, name="jgtuploadfile"), + + url(r'^cave/(?P[^/]+)/?(?P[^/])$', ent), + #(r'^cave/(?P[^/]+)/edit/$', edit_cave), + #(r'^cavesearch', caveSearch), + + + url(r'^cave/(?P[^/]+)/(?P\d\d\d\d)-(?P\d*)(?P[ABCDX]?)?$', views_caves.qm, name="qm"), + + + url(r'^logbooksearch/(.*)/?$', views_logbooks.logbookSearch), + + + url(r'^statistics/?$', views_other.stats, name="stats"), + + url(r'^survey/?$', surveyindex, name="survey"), + url(r'^survey/(?P\d\d\d\d)\#(?P\d*)$', survey, name="survey"), + + url(r'^controlpanel/?$', views_other.controlPanel, name="controlpanel"), + url(r'^CAVETAB2\.CSV/?$', views_other.downloadCavetab, name="downloadcavetab"), + url(r'^Surveys\.csv/?$', views_other.downloadSurveys, name="downloadsurveys"), + url(r'^logbook(?P\d\d\d\d)\.(?P.*)/?$',views_other.downloadLogbook), + url(r'^logbook/?$',views_other.downloadLogbook, name="downloadlogbook"), + url(r'^cave/(?P[^/]+)/qm\.csv/?$', views_other.downloadQMs, name="downloadqms"), + (r'^downloadqms$', views_other.downloadQMs), + + url(r'^eyecandy$', views_other.eyecandy), + + (r'^admin/doc/?', include('django.contrib.admindocs.urls')), + url(r'^admin/(.*)', admin.site.root, name="admin"), + + # don't know why this needs troggle/ in here. nice to get it out + url(r'^troggle/media-admin/(?P.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ADMIN_DIR, 'show_indexes':True}), + + + (r'^accounts/', include('registration.urls')), + (r'^profiles/', include('profiles.urls')), + + +# (r'^personform/(.*)$', personForm), + + (r'^site_media/(?P.*)$', 'django.views.static.serve', + {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}), + (r'^tinymce_media/(?P.*)$', 'django.views.static.serve', + {'document_root': settings.TINY_MCE_MEDIA_ROOT, 'show_indexes': True}), + + + url(r'^survexblock/(.+)$', views_caves.survexblock, name="survexblock"), + url(r'^survexfile/(?P.*?)\.svx$', views_survex.svx, name="svx"), + url(r'^survexfile/(?P.*?)\.3d$', views_survex.threed, name="threed"), + url(r'^survexfile/(?P.*?)\.log$', views_survex.svxraw), + url(r'^survexfile/(?P.*?)\.err$', views_survex.err), + + + url(r'^survexfile/caves/$', views_survex.survexcaveslist, name="survexcaveslist"), + url(r'^survexfile/caves/(?P.*)$', views_survex.survexcavesingle, name="survexcavessingle"), + url(r'^survexfileraw/(?P.*?)\.svx$', views_survex.svxraw, name="svxraw"), + + + (r'^survey_files/listdir/(?P.*)$', view_surveys.listdir), + (r'^survey_files/download/(?P.*)$', view_surveys.download), + #(r'^survey_files/upload/(?P.*)$', view_surveys.upload), + + + + #(r'^survey_scans/(?P.*)$', 'django.views.static.serve', {'document_root': settings.SURVEY_SCANS, 'show_indexes':True}), + url(r'^survey_scans/$', view_surveys.surveyscansfolders, name="surveyscansfolders"), + url(r'^survey_scans/(?P[^/]+)/$', view_surveys.surveyscansfolder, name="surveyscansfolder"), + url(r'^survey_scans/(?P[^/]+)/(?P[^/]+(?:png|jpg))$', + view_surveys.surveyscansingle, name="surveyscansingle"), + + url(r'^tunneldata/$', view_surveys.tunneldata, name="tunneldata"), + url(r'^tunneldataraw/(?P.+?\.xml)$', view_surveys.tunnelfile, name="tunnelfile"), + url(r'^tunneldataraw/(?P.+?\.xml)/upload$',view_surveys.tunnelfileupload, name="tunnelfileupload"), + + #url(r'^tunneldatainfo/(?P.+?\.xml)$', view_surveys.tunnelfileinfo, name="tunnelfileinfo"), + + (r'^photos/(?P.*)$', 'django.views.static.serve', + {'document_root': settings.PHOTOS_ROOT, 'show_indexes':True}), + + # for those silly ideas + url(r'^experimental.*$', views_logbooks.experimental, name="experimental"), + + #url(r'^trip_report/?$',views_other.tripreport,name="trip_report") + + url(r'^(.*)_edit$', 'flatpages.views.editflatpage', name="editflatpage"), + url(r'^(.*)$', 'flatpages.views.flatpage', name="flatpage"), +) + +#Allow prefix to all urls +urlpatterns = patterns ('', + ('^%s' % settings.DIR_ROOT, include(actualurlpatterns)) +) diff --git a/utils.py b/utils.py index 1970c7bfb..c26f1d912 100644 --- a/utils.py +++ b/utils.py @@ -1,178 +1,178 @@ -from django.conf import settings -import random, re, logging -from core.models import CaveDescription - -def weighted_choice(lst): - n = random.uniform(0,1) - for item, weight in lst: - if n < weight: - break - n = n - weight - return item - -def randomLogbookSentence(): - from troggle.core.models import LogbookEntry - randSent={} - - # needs to handle empty logbooks without crashing - - #Choose a random logbook entry - randSent['entry']=LogbookEntry.objects.order_by('?')[0] - - #Choose again if there are no sentances (this happens if it is a placeholder entry) - while len(re.findall('[A-Z].*?\.',randSent['entry'].text))==0: - randSent['entry']=LogbookEntry.objects.order_by('?')[0] - - #Choose a random sentence from that entry. Store the sentence as randSent['sentence'], and the number of that sentence in the entry as randSent['number'] - sentenceList=re.findall('[A-Z].*?\.',randSent['entry'].text) - randSent['number']=random.randrange(0,len(sentenceList)) - randSent['sentence']=sentenceList[randSent['number']] - - return randSent - - -def save_carefully(objectType, lookupAttribs={}, nonLookupAttribs={}): - """Looks up instance using lookupAttribs and carries out the following: - -if instance does not exist in DB: add instance to DB, return (new instance, True) - -if instance exists in DB and was modified using Troggle: do nothing, return (existing instance, False) - -if instance exists in DB and was not modified using Troggle: overwrite instance, return (instance, False) - - The checking is accomplished using Django's get_or_create and the new_since_parsing boolean field - defined in core.models.TroggleModel. - - """ - - instance, created=objectType.objects.get_or_create(defaults=nonLookupAttribs, **lookupAttribs) - - if not created and not instance.new_since_parsing: - for k, v in nonLookupAttribs.items(): #overwrite the existing attributes from the logbook text (except date and title) - setattr(instance, k, v) - instance.save() - - if created: - logging.info(str(instance) + ' was just added to the database for the first time. \n') - - if not created and instance.new_since_parsing: - logging.info(str(instance) + " has been modified using Troggle, so the current script left it as is. \n") - - if not created and not instance.new_since_parsing: - logging.info(str(instance) + " existed in the database unchanged since last parse. It was overwritten by the current script. \n") - return (instance, created) - -def render_with_context(req, *args, **kwargs): - """this is the snippet from http://www.djangosnippets.org/snippets/3/ - - Django uses Context, not RequestContext when you call render_to_response. - We always want to use RequestContext, so that django adds the context from - settings.TEMPLATE_CONTEXT_PROCESSORS. This way we automatically get - necessary settings variables passed to each template. So we use a custom - method, render_response instead of render_to_response. Hopefully future - Django releases will make this unnecessary.""" - - from django.shortcuts import render_to_response - from django.template import RequestContext - kwargs['context_instance'] = RequestContext(req) - return render_to_response(*args, **kwargs) - -re_body = re.compile(r"\]*\>(.*)\", re.DOTALL) -re_title = re.compile(r"\]*\>(.*)\", re.DOTALL) - -def get_html_body(text): - return get_single_match(re_body, text) - -def get_html_title(text): - return get_single_match(re_title, text) - -def get_single_match(regex, text): - match = regex.search(text) - - if match: - return match.groups()[0] - else: - return None - -def href_to_wikilinks(matchobj): - """ - Given an html link, checks for possible valid wikilinks. - - Returns the first valid wikilink. Valid means the target - object actually exists. - """ - res=CaveDescription.objects.filter(long_name__icontains=matchobj.groupdict()['text']) - if res and res[0]: - return r'[[cavedescription:'+res[0].short_name+'|'+res[0].long_name+']]' - else: - return matchobj.group() - #except: - #print 'fail' - - -re_subs = [(re.compile(r"\]*\>(.*?)\", re.DOTALL), r"'''\1'''"), - (re.compile(r"\(.*?)\", re.DOTALL), r"''\1''"), - (re.compile(r"\]*\>(.*?)\", re.DOTALL), r"=\1="), - (re.compile(r"\]*\>(.*?)\", re.DOTALL), r"==\1=="), - (re.compile(r"\]*\>(.*?)\", re.DOTALL), r"===\1==="), - (re.compile(r"\]*\>(.*?)\", re.DOTALL), r"====\1===="), - (re.compile(r"\]*\>(.*?)\", re.DOTALL), r"=====\1====="), - (re.compile(r"\]*\>(.*?)\", re.DOTALL), r"======\1======"), - (re.compile(r'()?>|\s/>()?)', re.DOTALL),r'[[display:\g photo:\g]]'), # - (re.compile(r"\(.*?)\", re.DOTALL), r"[[subcave:\1|\2]]"), #assumes that all links with id attributes are subcaves. Not great. - #interpage link needed - (re.compile(r"\(.*?)\", re.DOTALL), r"[[cavedescription:\1|\2]]"), #assumes that all links with target ids are cave descriptions. Not great. - (re.compile(r"\[\([^\s]*).*?\\]", re.DOTALL), r"[[qm:\1]]"), - (re.compile(r'.*)"?>(?P.*)'),href_to_wikilinks), - - ] - -def html_to_wiki(text, codec = "utf-8"): - if type(text) == str: - text = unicode(text, codec) - text = re.sub("

    ", r"", text) - text = re.sub("

    $", r"", text) - text = re.sub("

    ", r"\n\n", text) - out = "" - lists = "" - #lists - while text: - mstar = re.match("^(.*?)]*>\s*]*>(.*?)(.*)$", text, re.DOTALL) - munstar = re.match("^(\s*)(.*)$", text, re.DOTALL) - mhash = re.match("^(.*?)]*>\s*]*>(.*?)(.*)$", text, re.DOTALL) - munhash = re.match("^(\s*)(.*)$", text, re.DOTALL) - mitem = re.match("^(\s*)]*>(.*?)(.*)$", text, re.DOTALL) - ms = [len(m.groups()[0]) for m in [mstar, munstar, mhash, munhash, mitem] if m] - def min_(i, l): - try: - v = i.groups()[0] - l.remove(len(v)) - return len(v) < min(l, 1000000000) - except: - return False - if min_(mstar, ms): - lists += "*" - pre, val, post = mstar.groups() - out += pre + "\n" + lists + " " + val - text = post - elif min_(mhash, ms): - lists += "#" - pre, val, post = mhash.groups() - out += pre + "\n" + lists + " " + val - text = post - elif min_(mitem, ms): - pre, val, post = mitem.groups() - out += "\n" + lists + " " + val - text = post - elif min_(munstar, ms): - lists = lists[:-1] - text = munstar.groups()[1] - elif min_(munhash, ms): - lists.pop() - text = munhash.groups()[1] - else: - out += text - text = "" - #substitutions - for regex, repl in re_subs: - out = regex.sub(repl, out) - return out - - +from django.conf import settings +import random, re, logging +from core.models import CaveDescription + +def weighted_choice(lst): + n = random.uniform(0,1) + for item, weight in lst: + if n < weight: + break + n = n - weight + return item + +def randomLogbookSentence(): + from troggle.core.models import LogbookEntry + randSent={} + + # needs to handle empty logbooks without crashing + + #Choose a random logbook entry + randSent['entry']=LogbookEntry.objects.order_by('?')[0] + + #Choose again if there are no sentances (this happens if it is a placeholder entry) + while len(re.findall('[A-Z].*?\.',randSent['entry'].text))==0: + randSent['entry']=LogbookEntry.objects.order_by('?')[0] + + #Choose a random sentence from that entry. Store the sentence as randSent['sentence'], and the number of that sentence in the entry as randSent['number'] + sentenceList=re.findall('[A-Z].*?\.',randSent['entry'].text) + randSent['number']=random.randrange(0,len(sentenceList)) + randSent['sentence']=sentenceList[randSent['number']] + + return randSent + + +def save_carefully(objectType, lookupAttribs={}, nonLookupAttribs={}): + """Looks up instance using lookupAttribs and carries out the following: + -if instance does not exist in DB: add instance to DB, return (new instance, True) + -if instance exists in DB and was modified using Troggle: do nothing, return (existing instance, False) + -if instance exists in DB and was not modified using Troggle: overwrite instance, return (instance, False) + + The checking is accomplished using Django's get_or_create and the new_since_parsing boolean field + defined in core.models.TroggleModel. + + """ + + instance, created=objectType.objects.get_or_create(defaults=nonLookupAttribs, **lookupAttribs) + + if not created and not instance.new_since_parsing: + for k, v in nonLookupAttribs.items(): #overwrite the existing attributes from the logbook text (except date and title) + setattr(instance, k, v) + instance.save() + + if created: + logging.info(str(instance) + ' was just added to the database for the first time. \n') + + if not created and instance.new_since_parsing: + logging.info(str(instance) + " has been modified using Troggle, so the current script left it as is. \n") + + if not created and not instance.new_since_parsing: + logging.info(str(instance) + " existed in the database unchanged since last parse. It was overwritten by the current script. \n") + return (instance, created) + +def render_with_context(req, *args, **kwargs): + """this is the snippet from http://www.djangosnippets.org/snippets/3/ + + Django uses Context, not RequestContext when you call render_to_response. + We always want to use RequestContext, so that django adds the context from + settings.TEMPLATE_CONTEXT_PROCESSORS. This way we automatically get + necessary settings variables passed to each template. So we use a custom + method, render_response instead of render_to_response. Hopefully future + Django releases will make this unnecessary.""" + + from django.shortcuts import render_to_response + from django.template import RequestContext + kwargs['context_instance'] = RequestContext(req) + return render_to_response(*args, **kwargs) + +re_body = re.compile(r"\]*\>(.*)\", re.DOTALL) +re_title = re.compile(r"\]*\>(.*)\", re.DOTALL) + +def get_html_body(text): + return get_single_match(re_body, text) + +def get_html_title(text): + return get_single_match(re_title, text) + +def get_single_match(regex, text): + match = regex.search(text) + + if match: + return match.groups()[0] + else: + return None + +def href_to_wikilinks(matchobj): + """ + Given an html link, checks for possible valid wikilinks. + + Returns the first valid wikilink. Valid means the target + object actually exists. + """ + res=CaveDescription.objects.filter(long_name__icontains=matchobj.groupdict()['text']) + if res and res[0]: + return r'[[cavedescription:'+res[0].short_name+'|'+res[0].long_name+']]' + else: + return matchobj.group() + #except: + #print 'fail' + + +re_subs = [(re.compile(r"\]*\>(.*?)\", re.DOTALL), r"'''\1'''"), + (re.compile(r"\(.*?)\", re.DOTALL), r"''\1''"), + (re.compile(r"\]*\>(.*?)\", re.DOTALL), r"=\1="), + (re.compile(r"\]*\>(.*?)\", re.DOTALL), r"==\1=="), + (re.compile(r"\]*\>(.*?)\", re.DOTALL), r"===\1==="), + (re.compile(r"\]*\>(.*?)\", re.DOTALL), r"====\1===="), + (re.compile(r"\]*\>(.*?)\", re.DOTALL), r"=====\1====="), + (re.compile(r"\]*\>(.*?)\", re.DOTALL), r"======\1======"), + (re.compile(r'()?>|\s/>()?)', re.DOTALL),r'[[display:\g photo:\g]]'), # + (re.compile(r"\(.*?)\", re.DOTALL), r"[[subcave:\1|\2]]"), #assumes that all links with id attributes are subcaves. Not great. + #interpage link needed + (re.compile(r"\(.*?)\", re.DOTALL), r"[[cavedescription:\1|\2]]"), #assumes that all links with target ids are cave descriptions. Not great. + (re.compile(r"\[\([^\s]*).*?\\]", re.DOTALL), r"[[qm:\1]]"), + (re.compile(r'.*)"?>(?P.*)'),href_to_wikilinks), + + ] + +def html_to_wiki(text, codec = "utf-8"): + if type(text) == str: + text = unicode(text, codec) + text = re.sub("

    ", r"", text) + text = re.sub("

    $", r"", text) + text = re.sub("

    ", r"\n\n", text) + out = "" + lists = "" + #lists + while text: + mstar = re.match("^(.*?)]*>\s*]*>(.*?)(.*)$", text, re.DOTALL) + munstar = re.match("^(\s*)(.*)$", text, re.DOTALL) + mhash = re.match("^(.*?)]*>\s*]*>(.*?)(.*)$", text, re.DOTALL) + munhash = re.match("^(\s*)(.*)$", text, re.DOTALL) + mitem = re.match("^(\s*)]*>(.*?)(.*)$", text, re.DOTALL) + ms = [len(m.groups()[0]) for m in [mstar, munstar, mhash, munhash, mitem] if m] + def min_(i, l): + try: + v = i.groups()[0] + l.remove(len(v)) + return len(v) < min(l, 1000000000) + except: + return False + if min_(mstar, ms): + lists += "*" + pre, val, post = mstar.groups() + out += pre + "\n" + lists + " " + val + text = post + elif min_(mhash, ms): + lists += "#" + pre, val, post = mhash.groups() + out += pre + "\n" + lists + " " + val + text = post + elif min_(mitem, ms): + pre, val, post = mitem.groups() + out += "\n" + lists + " " + val + text = post + elif min_(munstar, ms): + lists = lists[:-1] + text = munstar.groups()[1] + elif min_(munhash, ms): + lists.pop() + text = munhash.groups()[1] + else: + out += text + text = "" + #substitutions + for regex, repl in re_subs: + out = regex.sub(repl, out) + return out + +