summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/admin.py6
-rw-r--r--core/forms.py12
-rw-r--r--core/management/commands/reset_db.py2
-rw-r--r--core/models.py538
-rw-r--r--core/models_caves.py513
-rw-r--r--core/view_surveys.py2
-rw-r--r--core/views_caves.py2
-rw-r--r--core/views_logbooks.py36
-rw-r--r--core/views_other.py5
-rw-r--r--core/views_survex.py19
10 files changed, 581 insertions, 554 deletions
diff --git a/core/admin.py b/core/admin.py
index 0fe47f7..3bc14d4 100644
--- a/core/admin.py
+++ b/core/admin.py
@@ -1,10 +1,12 @@
-from troggle.core.models import *
+import django.forms as forms
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 troggle.core.views_other import downloadLogbook
+from troggle.core.models import *
+from troggle.core.models_caves import *
#from troggle.reversion.admin import VersionAdmin #django-reversion version control
diff --git a/core/forms.py b/core/forms.py
index b8d2e07..e8e620c 100644
--- a/core/forms.py
+++ b/core/forms.py
@@ -1,12 +1,16 @@
-from django.forms import ModelForm
-from .models import Cave, Person, PersonExpedition, LogbookEntry, QM, Expedition, Entrance, CaveAndEntrance
+import string
+from datetime import date
+
import django.forms as forms
+from django.forms import ModelForm
from django.forms.models import modelformset_factory
from django.contrib.admin.widgets import AdminDateWidget
-import string
-from datetime import date
+
from tinymce.widgets import TinyMCE
+from troggle.core.models import Person, PersonExpedition, LogbookEntry, Expedition
+from troggle.core.models_caves import Cave, QM, Entrance, CaveAndEntrance
+
class CaveForm(ModelForm):
underground_description = forms.CharField(required = False, widget=forms.Textarea())
explorers = forms.CharField(required = False, widget=forms.Textarea())
diff --git a/core/management/commands/reset_db.py b/core/management/commands/reset_db.py
index 2aea94a..03d143e 100644
--- a/core/management/commands/reset_db.py
+++ b/core/management/commands/reset_db.py
@@ -7,7 +7,7 @@ from django.core.urlresolvers import reverse
from django.core.management.base import BaseCommand, CommandError
from django.contrib.auth.models import User
-from troggle.core.models import Cave, Entrance
+from troggle.core.models_caves import Cave, Entrance
import troggle.flatpages.models
import settings
diff --git a/core/models.py b/core/models.py
index 42219e7..142cfa6 100644
--- a/core/models.py
+++ b/core/models.py
@@ -3,29 +3,25 @@ import os
import datetime
import logging
import re
-import subprocess
+from subprocess import call
-from urllib.request import *
-from urllib.parse import *
-from urllib.error import *
+from urllib.parse import urljoin
from decimal import Decimal, getcontext
getcontext().prec=2 #use 2 significant figures for decimal calculations
import settings
-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.db.models import Min, Max
from django.conf import settings
from django.core.urlresolvers import reverse
from django.template import Context, loader
-from troggle.core.models_survex import *
-
+import troggle.core.models_survex
+import troggle.core.models_caves as models_caves
def get_related_by_wikilinks(wiki_text):
found=re.findall(settings.QM_PATTERN,wiki_text)
@@ -33,7 +29,7 @@ def get_related_by_wikilinks(wiki_text):
for wikilink in found:
qmdict={'urlroot':settings.URL_ROOT,'cave':wikilink[2],'year':wikilink[1],'number':wikilink[3]}
try:
- cave_slugs = CaveSlug.objects.filter(cave__kataster_number = qmdict['cave'])
+ cave_slugs = models_caves.CaveSlug.objects.filter(cave__kataster_number = qmdict['cave'])
qm=QM.objects.get(found_by__cave_slug__in = cave_slugs,
found_by__date__year = qmdict['year'],
number = qmdict['number'])
@@ -73,10 +69,20 @@ class TroggleImageModel(models.Model):
def get_admin_url(self):
return urllib.parse.urljoin(settings.URL_ROOT, "/admin/core/" + self.object_name().lower() + "/" + str(self.pk))
-
class Meta:
abstract = True
+class DataIssue(TroggleModel):
+ date = models.DateTimeField(auto_now_add=True, blank=True)
+ parser = models.CharField(max_length=50, blank=True, null=True)
+ message = models.CharField(max_length=400, blank=True, null=True)
+
+ class Meta:
+ ordering = ['date']
+
+ def __str__(self):
+ return "%s - %s" % (self.parser, self.message)
+
#
# single Expedition, usually seen by year
#
@@ -231,6 +237,7 @@ class PersonExpedition(TroggleModel):
res = self.persontrip_set.all().aggregate(day_max=Max("expeditionday__date"))
return res["day_max"]
+
class LogbookEntry(TroggleModel):
"""Single parsed entry from Logbook
"""
@@ -258,7 +265,7 @@ class LogbookEntry(TroggleModel):
def __getattribute__(self, item):
if item == "cave":
#Allow a logbookentries cave to be directly accessed despite not having a proper foreignkey
- return CaveSlug.objects.get(slug = self.cave_slug).cave
+ return models_caves.CaveSlug.objects.get(slug = self.cave_slug).cave
# parse error in python3.8
# https://stackoverflow.com/questions/41343263/provide-classcell-example-for-python-3-6-metaclass
#https://github.com/django/django/pull/7653
@@ -269,7 +276,7 @@ class LogbookEntry(TroggleModel):
def __init__(self, *args, **kwargs):
if "cave" in list(kwargs.keys()):
if kwargs["cave"] is not None:
- kwargs["cave_slug"] = CaveSlug.objects.get(cave=kwargs["cave"], primary=True).slug
+ kwargs["cave_slug"] = models_caves.CaveSlug.objects.get(cave=kwargs["cave"], primary=True).slug
kwargs.pop("cave")
# parse error in python3.8
return TroggleModel.__init__(self, *args, **kwargs) # seems OK in 3.5 & 3.8! failure later elsewhere with 3.8
@@ -309,6 +316,7 @@ class LogbookEntry(TroggleModel):
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)
#
@@ -346,507 +354,3 @@ class PersonTrip(TroggleModel):
def __str__(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 __str__(self):
- if self.parent:
- return str(self.parent) + " - " + str(self.short_name)
- else:
- return str(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(models.Model):
- cave = models.ForeignKey('Cave')
- entrance = models.ForeignKey('Entrance')
- entrance_letter = models.CharField(max_length=20,blank=True,null=True)
- def __str__(self):
- return str(self.cave) + str(self.entrance_letter)
-
-class CaveSlug(models.Model):
- cave = models.ForeignKey('Cave')
- slug = models.SlugField(max_length=50, unique = True)
- primary = models.BooleanField(default=False)
-
-class Cave(TroggleModel):
- # too much here perhaps,
- 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)
- filename = models.CharField(max_length=200)
-
- #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)
-
- class Meta:
- ordering = ('kataster_code', 'unofficial_number')
-
- def hassurvey(self):
- if not self.underground_centre_line:
- return "No"
- if (self.survey.find("<img") > -1 or self.survey.find("<a") > -1 or self.survey.find("<IMG") > -1 or self.survey.find("<A") > -1):
- return "Yes"
- return "Missing"
-
- def hassurveydata(self):
- if not self.underground_centre_line:
- return "No"
- if self.survex_file:
- return "Yes"
- return "Missing"
-
- def slug(self):
- primarySlugs = self.caveslug_set.filter(primary = True)
- if primarySlugs:
- return primarySlugs[0].slug
- else:
- slugs = self.caveslug_set.filter()
- if slugs:
- return slugs[0].slug
-
- def ours(self):
- return bool(re.search(r'CUCC', self.explorers))
-
- 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 = self.official_name.lower()
- #return settings.URL_ROOT + '/cave/' + href + '/'
- return urllib.parse.urljoin(settings.URL_ROOT, reverse('cave',kwargs={'cave_id':href,}))
-
- def __str__(self, sep = ": "):
- return str("slug:"+self.slug())
-
- def get_QMs(self):
- return QM.objects.filter(found_by__cave_slug=self.caveslug_set.all())
-
- 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 singleentrance(self):
- return len(CaveAndEntrance.objects.filter(cave=self)) == 1
-
- 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 += "&ndash;" + prevR
- else:
- prevR = r
- n = 0
- res += r
- if n == 0:
- res += ", " + prevR
- else:
- res += "&ndash;" + prevR
- return res
-
- def writeDataFile(self):
- try:
- f = open(os.path.join(settings.CAVEDESCRIPTIONS, self.filename), "wb")
- except:
- subprocess.call(settings.FIX_PERMISSIONS)
- f = open(os.path.join(settings.CAVEDESCRIPTIONS, self.filename), "wb")
- t = loader.get_template('dataformat/cave.xml')
- c = Context({'cave': self})
- u = t.render(c)
- u8 = u.encode("utf-8")
- f.write(u8)
- f.close()
-
- def getArea(self):
- areas = self.area.all()
- lowestareas = list(areas)
- for area in areas:
- if area.parent in areas:
- try:
- lowestareas.remove(area.parent)
- except:
- pass
- return lowestareas[0]
-
-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)))
- if len(foundCaves) == 1:
- return foundCaves[0]
- else:
- return False
-
-class OtherCaveName(TroggleModel):
- name = models.CharField(max_length=160)
- cave = models.ForeignKey(Cave)
- def __str__(self):
- return str(self.name)
-
-class EntranceSlug(models.Model):
- entrance = models.ForeignKey('Entrance')
- slug = models.SlugField(max_length=50, unique = True)
- primary = models.BooleanField(default=False)
-
-class Entrance(TroggleModel):
- 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', 'Needs Retag'),
- ('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', 'Coordinates'),
- ('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(blank=True, null=True)
- exact_station = models.TextField(blank=True, null=True)
- other_station = models.TextField(blank=True, null=True)
- other_description = models.TextField(blank=True,null=True)
- bearings = models.TextField(blank=True,null=True)
- url = models.CharField(max_length=200,blank=True,null=True)
- filename = models.CharField(max_length=200)
- cached_primary_slug = models.CharField(max_length=200,blank=True,null=True)
-
- def __str__(self):
- return str(self.slug())
-
- def exact_location(self):
- return SurvexStation.objects.lookup(self.exact_station)
- def other_location(self):
- return SurvexStation.objects.lookup(self.other_station)
-
-
- def find_location(self):
- r = {'': 'To be entered ',
- '?': 'To be confirmed:',
- 'S': '',
- 'L': 'Lost:',
- 'R': 'Refindable:'}[self.findability]
- if self.tag_station:
- try:
- s = SurvexStation.objects.lookup(self.tag_station)
- return r + "%0.0fE %0.0fN %0.0fAlt" % (s.x, s.y, s.z)
- except:
- return r + "%s Tag Station not in dataset" % self.tag_station
- if self.exact_station:
- try:
- s = SurvexStation.objects.lookup(self.exact_station)
- return r + "%0.0fE %0.0fN %0.0fAlt" % (s.x, s.y, s.z)
- except:
- return r + "%s Exact Station not in dataset" % self.tag_station
- if self.other_station:
- try:
- s = SurvexStation.objects.lookup(self.other_station)
- return r + "%0.0fE %0.0fN %0.0fAlt %s" % (s.x, s.y, s.z, self.other_description)
- except:
- return r + "%s Other Station not in dataset" % self.tag_station
- if self.FINDABLE_CHOICES == "S":
- r += "ERROR, Entrance has been surveyed but has no survex point"
- if self.bearings:
- return r + self.bearings
- return r
-
- def best_station(self):
- if self.tag_station:
- return self.tag_station
- if self.exact_station:
- return self.exact_station
- if self.other_station:
- return self.other_station
-
- def has_photo(self):
- if self.photo:
- if (self.photo.find("<img") > -1 or self.photo.find("<a") > -1 or self.photo.find("<IMG") > -1 or self.photo.find("<A") > -1):
- return "Yes"
- else:
- return "Missing"
- else:
- return "No"
-
- 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 tag(self):
- return SurvexStation.objects.lookup(self.tag_station)
-
- def needs_surface_work(self):
- return self.findability != "S" or not self.has_photo or self.marking != "T"
-
- 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
-
- def slug(self):
- if not self.cached_primary_slug:
- primarySlugs = self.entranceslug_set.filter(primary = True)
- if primarySlugs:
- self.cached_primary_slug = primarySlugs[0].slug
- self.save()
- else:
- slugs = self.entranceslug_set.filter()
- if slugs:
- self.cached_primary_slug = slugs[0].slug
- self.save()
- return self.cached_primary_slug
-
- def writeDataFile(self):
- try:
- f = open(os.path.join(settings.ENTRANCEDESCRIPTIONS, self.filename), "w")
- except:
- subprocess.call(settings.FIX_PERMISSIONS)
- f = open(os.path.join(settings.ENTRANCEDESCRIPTIONS, self.filename), "w")
- t = loader.get_template('dataformat/entrance.xml')
- c = Context({'entrance': self})
- u = t.render(c)
- u8 = u.encode("utf-8")
- f.write(u8)
- f.close()
-
-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 __str__(self):
- if self.long_name:
- return str(self.long_name)
- else:
- return str(self.short_name)
-
- def get_absolute_url(self):
- return urllib.parse.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.
- """
- TroggleModel.save()
- #super(CaveDescription, self).save() # fails in python 3.8, OK in python 3.5
- qm_list=get_related_by_wikilinks(self.description)
- for qm in qm_list:
- self.linked_qms.add(qm)
- TroggleModel.save()
- #super(CaveDescription, self).save() # fails in python 3.8, OK in python 3.5
-
-class NewSubCave(TroggleModel):
- name = models.CharField(max_length=200, unique = True)
- def __str__(self):
- return str(self.name)
-
-class QM(TroggleModel):
- #based on qm.csv in trunk/expoweb/1623/204 which has the fields:
- #"Number","Grade","Area","Description","Page reference","Nearest station","Completion description","Comment"
- 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)
- nearest_station_description = models.CharField(max_length=400,null=True,blank=True)
- nearest_station_name = models.CharField(max_length=200,blank=True,null=True)
- nearest_station = models.ForeignKey(SurvexStation,null=True,blank=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 __str__(self):
- return "%s %s" % (self.code(), self.grade)
-
- def code(self):
- return "%s-%s-%s" % (str(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 urllib.parse.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 "%s%s%s" % ('[[QM:',self.code(),']]')
-
-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, instance.survey.wallet_letter)
- number=str(instance.survey.wallet_number)
- if str(instance.survey.wallet_letter) != "None":
- number=str(instance.survey.wallet_letter) + number #two strings formatting because convention is 2009#01 or 2009#X01
- return os.path.join('./',year,year+r'#'+number,str(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)
-
- #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 __str__(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 __str__(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')
-
-class DataIssue(TroggleModel):
- date = models.DateTimeField(auto_now_add=True, blank=True)
- parser = models.CharField(max_length=50, blank=True, null=True)
- message = models.CharField(max_length=400, blank=True, null=True)
-
- class Meta:
- ordering = ['date']
-
- def __str__(self):
- return "%s - %s" % (self.parser, self.message) \ No newline at end of file
diff --git a/core/models_caves.py b/core/models_caves.py
new file mode 100644
index 0000000..4246f6d
--- /dev/null
+++ b/core/models_caves.py
@@ -0,0 +1,513 @@
+import string
+import os
+import datetime
+import logging
+import re
+from subprocess import call
+
+from urllib.parse import urljoin
+
+import settings
+
+from django.db import models
+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 django.core.urlresolvers import reverse
+from django.template import Context, loader
+
+from troggle.core.models import *
+from troggle.core.models_survex import *
+
+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 __str__(self):
+ if self.parent:
+ return str(self.parent) + " - " + str(self.short_name)
+ else:
+ return str(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(models.Model):
+ cave = models.ForeignKey('Cave')
+ entrance = models.ForeignKey('Entrance')
+ entrance_letter = models.CharField(max_length=20,blank=True,null=True)
+ def __str__(self):
+ return str(self.cave) + str(self.entrance_letter)
+
+class CaveSlug(models.Model):
+ cave = models.ForeignKey('Cave')
+ slug = models.SlugField(max_length=50, unique = True)
+ primary = models.BooleanField(default=False)
+
+class Cave(TroggleModel):
+ # too much here perhaps,
+ 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)
+ filename = models.CharField(max_length=200)
+
+ #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)
+
+ class Meta:
+ ordering = ('kataster_code', 'unofficial_number')
+
+ def hassurvey(self):
+ if not self.underground_centre_line:
+ return "No"
+ if (self.survey.find("<img") > -1 or self.survey.find("<a") > -1 or self.survey.find("<IMG") > -1 or self.survey.find("<A") > -1):
+ return "Yes"
+ return "Missing"
+
+ def hassurveydata(self):
+ if not self.underground_centre_line:
+ return "No"
+ if self.survex_file:
+ return "Yes"
+ return "Missing"
+
+ def slug(self):
+ primarySlugs = self.caveslug_set.filter(primary = True)
+ if primarySlugs:
+ return primarySlugs[0].slug
+ else:
+ slugs = self.caveslug_set.filter()
+ if slugs:
+ return slugs[0].slug
+
+ def ours(self):
+ return bool(re.search(r'CUCC', self.explorers))
+
+ 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 = self.official_name.lower()
+ #return settings.URL_ROOT + '/cave/' + href + '/'
+ return urllib.parse.urljoin(settings.URL_ROOT, reverse('cave',kwargs={'cave_id':href,}))
+
+ def __str__(self, sep = ": "):
+ return str("slug:"+self.slug())
+
+ def get_QMs(self):
+ return QM.objects.filter(found_by__cave_slug=self.caveslug_set.all())
+
+ 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 singleentrance(self):
+ return len(CaveAndEntrance.objects.filter(cave=self)) == 1
+
+ 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 += "&ndash;" + prevR
+ else:
+ prevR = r
+ n = 0
+ res += r
+ if n == 0:
+ res += ", " + prevR
+ else:
+ res += "&ndash;" + prevR
+ return res
+
+ def writeDataFile(self):
+ try:
+ f = open(os.path.join(settings.CAVEDESCRIPTIONS, self.filename), "wb")
+ except:
+ subprocess.call(settings.FIX_PERMISSIONS)
+ f = open(os.path.join(settings.CAVEDESCRIPTIONS, self.filename), "wb")
+ t = loader.get_template('dataformat/cave.xml')
+ c = Context({'cave': self})
+ u = t.render(c)
+ u8 = u.encode("utf-8")
+ f.write(u8)
+ f.close()
+
+ def getArea(self):
+ areas = self.area.all()
+ lowestareas = list(areas)
+ for area in areas:
+ if area.parent in areas:
+ try:
+ lowestareas.remove(area.parent)
+ except:
+ pass
+ return lowestareas[0]
+
+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)))
+ if len(foundCaves) == 1:
+ return foundCaves[0]
+ else:
+ return False
+
+class OtherCaveName(TroggleModel):
+ name = models.CharField(max_length=160)
+ cave = models.ForeignKey(Cave)
+ def __str__(self):
+ return str(self.name)
+
+class EntranceSlug(models.Model):
+ entrance = models.ForeignKey('Entrance')
+ slug = models.SlugField(max_length=50, unique = True)
+ primary = models.BooleanField(default=False)
+
+class Entrance(TroggleModel):
+ 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', 'Needs Retag'),
+ ('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', 'Coordinates'),
+ ('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(blank=True, null=True)
+ exact_station = models.TextField(blank=True, null=True)
+ other_station = models.TextField(blank=True, null=True)
+ other_description = models.TextField(blank=True,null=True)
+ bearings = models.TextField(blank=True,null=True)
+ url = models.CharField(max_length=200,blank=True,null=True)
+ filename = models.CharField(max_length=200)
+ cached_primary_slug = models.CharField(max_length=200,blank=True,null=True)
+
+ def __str__(self):
+ return str(self.slug())
+
+ def exact_location(self):
+ return SurvexStation.objects.lookup(self.exact_station)
+ def other_location(self):
+ return SurvexStation.objects.lookup(self.other_station)
+
+
+ def find_location(self):
+ r = {'': 'To be entered ',
+ '?': 'To be confirmed:',
+ 'S': '',
+ 'L': 'Lost:',
+ 'R': 'Refindable:'}[self.findability]
+ if self.tag_station:
+ try:
+ s = SurvexStation.objects.lookup(self.tag_station)
+ return r + "%0.0fE %0.0fN %0.0fAlt" % (s.x, s.y, s.z)
+ except:
+ return r + "%s Tag Station not in dataset" % self.tag_station
+ if self.exact_station:
+ try:
+ s = SurvexStation.objects.lookup(self.exact_station)
+ return r + "%0.0fE %0.0fN %0.0fAlt" % (s.x, s.y, s.z)
+ except:
+ return r + "%s Exact Station not in dataset" % self.tag_station
+ if self.other_station:
+ try:
+ s = SurvexStation.objects.lookup(self.other_station)
+ return r + "%0.0fE %0.0fN %0.0fAlt %s" % (s.x, s.y, s.z, self.other_description)
+ except:
+ return r + "%s Other Station not in dataset" % self.tag_station
+ if self.FINDABLE_CHOICES == "S":
+ r += "ERROR, Entrance has been surveyed but has no survex point"
+ if self.bearings:
+ return r + self.bearings
+ return r
+
+ def best_station(self):
+ if self.tag_station:
+ return self.tag_station
+ if self.exact_station:
+ return self.exact_station
+ if self.other_station:
+ return self.other_station
+
+ def has_photo(self):
+ if self.photo:
+ if (self.photo.find("<img") > -1 or self.photo.find("<a") > -1 or self.photo.find("<IMG") > -1 or self.photo.find("<A") > -1):
+ return "Yes"
+ else:
+ return "Missing"
+ else:
+ return "No"
+
+ 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 tag(self):
+ return SurvexStation.objects.lookup(self.tag_station)
+
+ def needs_surface_work(self):
+ return self.findability != "S" or not self.has_photo or self.marking != "T"
+
+ 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
+
+ def slug(self):
+ if not self.cached_primary_slug:
+ primarySlugs = self.entranceslug_set.filter(primary = True)
+ if primarySlugs:
+ self.cached_primary_slug = primarySlugs[0].slug
+ self.save()
+ else:
+ slugs = self.entranceslug_set.filter()
+ if slugs:
+ self.cached_primary_slug = slugs[0].slug
+ self.save()
+ return self.cached_primary_slug
+
+ def writeDataFile(self):
+ try:
+ f = open(os.path.join(settings.ENTRANCEDESCRIPTIONS, self.filename), "w")
+ except:
+ subprocess.call(settings.FIX_PERMISSIONS)
+ f = open(os.path.join(settings.ENTRANCEDESCRIPTIONS, self.filename), "w")
+ t = loader.get_template('dataformat/entrance.xml')
+ c = Context({'entrance': self})
+ u = t.render(c)
+ u8 = u.encode("utf-8")
+ f.write(u8)
+ f.close()
+
+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 __str__(self):
+ if self.long_name:
+ return str(self.long_name)
+ else:
+ return str(self.short_name)
+
+ def get_absolute_url(self):
+ return urllib.parse.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.
+ """
+ TroggleModel.save()
+ #super(CaveDescription, self).save() # fails in python 3.8, OK in python 3.5
+ qm_list=get_related_by_wikilinks(self.description)
+ for qm in qm_list:
+ self.linked_qms.add(qm)
+ TroggleModel.save()
+ #super(CaveDescription, self).save() # fails in python 3.8, OK in python 3.5
+
+class NewSubCave(TroggleModel):
+ name = models.CharField(max_length=200, unique = True)
+ def __str__(self):
+ return str(self.name)
+
+class QM(TroggleModel):
+ #based on qm.csv in trunk/expoweb/1623/204 which has the fields:
+ #"Number","Grade","Area","Description","Page reference","Nearest station","Completion description","Comment"
+ 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)
+ nearest_station_description = models.CharField(max_length=400,null=True,blank=True)
+ nearest_station_name = models.CharField(max_length=200,blank=True,null=True)
+ nearest_station = models.ForeignKey(SurvexStation,null=True,blank=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 __str__(self):
+ return "%s %s" % (self.code(), self.grade)
+
+ def code(self):
+ return "%s-%s-%s" % (str(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 urllib.parse.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 "%s%s%s" % ('[[QM:',self.code(),']]')
+
+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, instance.survey.wallet_letter)
+ number=str(instance.survey.wallet_number)
+ if str(instance.survey.wallet_letter) != "None":
+ number=str(instance.survey.wallet_letter) + number #two strings formatting because convention is 2009#01 or 2009#X01
+ return os.path.join('./',year,year+r'#'+number,str(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)
+
+ #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 __str__(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 __str__(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/view_surveys.py b/core/view_surveys.py
index 65a4f30..845cab2 100644
--- a/core/view_surveys.py
+++ b/core/view_surveys.py
@@ -4,7 +4,7 @@ from django.shortcuts import render_to_response
from django.http import HttpResponse, Http404
import os, stat
import re
-from troggle.core.models import SurvexScansFolder, SurvexScanSingle, SurvexBlock, TunnelFile
+from troggle.core.models_survex import SurvexScansFolder, SurvexScanSingle, SurvexBlock, TunnelFile
import parsers.surveys
import urllib.request, urllib.parse, urllib.error
diff --git a/core/views_caves.py b/core/views_caves.py
index c306461..31f6707 100644
--- a/core/views_caves.py
+++ b/core/views_caves.py
@@ -21,7 +21,7 @@ from django.shortcuts import get_object_or_404, render
import troggle.settings as settings
import troggle.core.models as models
-from troggle.core.models import CaveSlug, Cave, CaveAndEntrance, Survey, Expedition, QM, CaveDescription, EntranceSlug, Entrance, Area, SurvexStation
+from troggle.core.models_caves import CaveSlug, Cave, CaveAndEntrance, Survey, Expedition, QM, CaveDescription, EntranceSlug, Entrance, Area, SurvexStation
from troggle.core.forms import CaveForm, CaveAndEntranceFormSet, VersionControlCommentForm, EntranceForm, EntranceLetterForm
from troggle.helper import login_required_if_public
diff --git a/core/views_logbooks.py b/core/views_logbooks.py
index b29b72e..b02200f 100644
--- a/core/views_logbooks.py
+++ b/core/views_logbooks.py
@@ -1,23 +1,27 @@
-from django.shortcuts import render_to_response, render
-from troggle.core.models import Expedition, Person, PersonExpedition, PersonTrip, LogbookEntry, SurvexBlock
-import troggle.core.models as models
-import troggle.settings as settings
+import datetime
+import os.path
+import re
+
import django.db.models
-from troggle.parsers.logbooks import LoadLogbookForExpedition
-from troggle.parsers.people import GetPersonExpeditionNameLookup
-from troggle.core.forms import getTripForm#, get_name, PersonForm
-from django.core.urlresolvers import reverse
-from django.http import HttpResponseRedirect, HttpResponse
+from django.core.urlresolvers import reverse
+from django.http import HttpResponse, HttpResponseRedirect
+from django.shortcuts import render, render_to_response
from django.template import Context, loader
-import os.path
-import troggle.parsers.logbooks as logbookparsers
from django.template.defaultfilters import slugify
-from troggle.helper import login_required_if_public
-import datetime
-
-from django.views.generic.list import ListView
from django.utils import timezone
+from django.views.generic.list import ListView
+import troggle.core.models as models
+import troggle.parsers.logbooks as logbookparsers
+from troggle.core.forms import getTripForm # , get_name, PersonForm
+from troggle.core.models import Expedition, LogbookEntry, Person, PersonExpedition, PersonTrip
+from troggle.core.models_survex import SurvexBlock
+from troggle.helper import login_required_if_public
+from troggle.parsers.logbooks import LoadLogbookForExpedition
+from troggle.parsers.people import GetPersonExpeditionNameLookup
+
+import troggle.settings as settings
+from settings import *
# Django uses Context, not RequestContext when you call render
# to_response. We always want to use RequestContext, so that
@@ -28,7 +32,6 @@ from django.utils import timezone
# will make this unnecessary.
# from troggle.alwaysUseRequestContext import render_response
-import re
@django.db.models.permalink #this allows the nice get_absolute_url syntax we are using
@@ -162,7 +165,6 @@ def personForm(request,pk):
form=PersonForm(instance=person)
return render(request,'personform.html', {'form':form,})
-from settings import *
def pathsreport(request):
pathsdict={
"ADMIN_MEDIA_PREFIX" : ADMIN_MEDIA_PREFIX,
diff --git a/core/views_other.py b/core/views_other.py
index 4da8e70..28a6d94 100644
--- a/core/views_other.py
+++ b/core/views_other.py
@@ -9,9 +9,8 @@ from django.shortcuts import render
from django.template import Context, loader
import databaseReset
-from troggle.core.models import *
-from troggle.core.models import (QM, Cave, Expedition, LogbookEntry, Person,
- PersonExpedition, PersonTrip)
+from troggle.core.models import Expedition, LogbookEntry, Person, PersonExpedition, PersonTrip
+from troggle.core.models_caves import QM, Cave
from troggle.helper import login_required_if_public
diff --git a/core/views_survex.py b/core/views_survex.py
index 0435d52..cec4d6c 100644
--- a/core/views_survex.py
+++ b/core/views_survex.py
@@ -1,19 +1,22 @@
-from django import forms
-from django.http import HttpResponseRedirect, HttpResponse
-from django.shortcuts import render_to_response, render
-from django.core.context_processors import csrf
-from django.http import HttpResponse, Http404
import re
import os
import datetime
import difflib
-from troggle.core.models import Expedition, Person, PersonExpedition, PersonTrip, LogbookEntry, Cave
-from troggle.core.models import SurvexBlock, SurvexPersonRole, SurvexFile, SurvexDirectory, SurvexTitle
-from parsers.people import GetPersonExpeditionNameLookup
+from django import forms
+from django.http import HttpResponseRedirect, HttpResponse
+from django.shortcuts import render_to_response, render
+from django.core.context_processors import csrf
+from django.http import HttpResponse, Http404
import troggle.settings as settings
import parsers.survex
+from troggle.core.models import Expedition, Person, PersonExpedition, PersonTrip, LogbookEntry
+from troggle.core.models_survex import SurvexBlock, SurvexPersonRole, SurvexFile, SurvexDirectory, SurvexTitle
+from troggle.core.models_caves import Cave
+from troggle.parsers.people import GetPersonExpeditionNameLookup
+
+
survextemplatefile = """; Locn: Totes Gebirge, Austria - Loser/Augst-Eck Plateau (kataster group 1623)
; Cave: