diff options
Diffstat (limited to 'core/models/caves.py')
-rw-r--r-- | core/models/caves.py | 709 |
1 files changed, 709 insertions, 0 deletions
diff --git a/core/models/caves.py b/core/models/caves.py new file mode 100644 index 0000000..b0ecb53 --- /dev/null +++ b/core/models/caves.py @@ -0,0 +1,709 @@ +import string +import os +import datetime +import logging +import re +import json +from subprocess import call +from collections import defaultdict + +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.urls import reverse +from django.template import Context, loader + +from troggle.core.models.troggle import TroggleModel, Person, Expedition, DataIssue +from troggle.core.models_survex import SurvexStation + +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,on_delete=models.SET_NULL) + + 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", "1624", "1627"]: + return self.short_name + elif self.parent: + return self.parent.kat_area() + +class CaveAndEntrance(models.Model): + cave = models.ForeignKey('Cave',on_delete=models.CASCADE) + entrance = models.ForeignKey('Entrance',on_delete=models.CASCADE) + 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',on_delete=models.CASCADE) + 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) + 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 urljoin(settings.URL_ROOT, reverse('cave',kwargs={'cave_id':href,})) + + def __str__(self, sep = ": "): + return str(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 += "–" + prevR + else: + prevR = r + n = 0 + res += r + if n == 0: + res += ", " + prevR + else: + res += "–" + 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}) + c = dict({'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] + +class EntranceSlug(models.Model): + entrance = models.ForeignKey('Entrance',on_delete=models.CASCADE) + 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 LogbookEntry(TroggleModel): + """Single parsed entry from Logbook + """ + LOGBOOK_ENTRY_TYPES = ( + ("wiki", "Wiki style logbook"), + ("html", "Html style logbook") + ) + date = models.DateField()#MJG wants to turn this into a datetime such that multiple Logbook entries on the same day can be ordered.ld() + expeditionday = models.ForeignKey("ExpeditionDay", null=True,on_delete=models.SET_NULL)#MJG wants to KILL THIS (redundant information) + expedition = models.ForeignKey(Expedition,blank=True, null=True,on_delete=models.SET_NULL) # yes this is double- + title = models.CharField(max_length=settings.MAX_LOGBOOK_ENTRY_TITLE_LENGTH) + cave_slug = models.SlugField(max_length=50, 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) + entry_type = models.CharField(default="wiki",null=True,choices=LOGBOOK_ENTRY_TYPES,max_length=50) + + class Meta: + verbose_name_plural = "Logbook Entries" + # several PersonTrips point in to this object + ordering = ('-date',) + + def __getattribute__(self, item): + if item == "cave": + #Allow a logbookentries cave to be directly accessed despite not having a proper foreignkey + return CaveSlug.objects.get(slug = self.cave_slug).cave + # parse error in python3.8 + # https://stackoverflow.com/questions/41343263/provide-classcell-example-for-python-3-6-metaclass + #https://github.com/django/django/pull/7653 + #return TroggleModel.__getattribute__(item) + #return super(LogbookEntry, self).__getattribute__(item) # works in py3.5, fails in 3.8 + return TroggleModel.__getattribute__(self,item) # works in py 3.5 AND in 3.8 + + def __init__(self, *args, **kwargs): + if "cave" in list(kwargs.keys()): + if kwargs["cave"] is not None: + kwargs["cave_slug"] = CaveSlug.objects.get(cave=kwargs["cave"], primary=True).slug + kwargs.pop("cave") + # parse error in python3.8 + return TroggleModel.__init__(self, *args, **kwargs) # seems OK in 3.5 & 3.8! failure later elsewhere with 3.8 + #return TroggleModel().__init__(self, *args, **kwargs) # parses OK, fails at runtime in 3.8 + #return super().__init__(self, *args, **kwargs) # fails in 3.8 + #return super().__init__(*args, **kwargs) # works in py3.5 fails in 3.8 + #return super(LogbookEntry, self).__init__(*args, **kwargs) # works in py3.5 + #return TroggleModel.__init__(*args, **kwargs) # fails in py3.5, runtime fail in 3.8 + + def isLogbookEntry(self): # Function used in templates + return True + + def get_absolute_url(self): + return urljoin(settings.URL_ROOT, reverse('logbookentry',kwargs={'date':self.date,'slug':self.slug})) + + def __str__(self): + return "%s: (%s)" % (self.date, self.title) + + def get_next_by_id(self): + LogbookEntry.objects.get(id=self.id+1) + + def get_previous_by_id(self): + LogbookEntry.objects.get(id=self.id-1) + + def new_QM_number(self): + """Returns """ + if self.cave: + nextQMnumber=self.cave.new_QM_number(self.date.year) + else: + return None + return nextQMnumber + + def new_QM_found_link(self): + """Produces a link to a new QM with the next number filled in and this LogbookEntry set as 'found by' """ + return settings.URL_ROOT + r'/admin/core/qm/add/?' + r'found_by=' + str(self.pk) +'&number=' + str(self.new_QM_number()) + + def DayIndex(self): + return list(self.expeditionday.logbookentry_set.all()).index(self) + +class QM(TroggleModel): + """This is 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,on_delete=models.SET_NULL ) + ticked_off_by = models.ForeignKey(LogbookEntry, related_name='QMs_ticked_off',blank=True, null=True,on_delete=models.SET_NULL) + 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,blank=True, null=True) + nearest_station_name = models.CharField(max_length=200,blank=True, null=True) + nearest_station = models.ForeignKey(SurvexStation,blank=True, null=True,on_delete=models.SET_NULL) + 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): + if self.found_by: + return "%s-%s-%s" % (str(self.found_by.cave)[6:], self.found_by.date.year, self.number) + else: + return "%s" % (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 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(),']]') + +class PersonTrip(TroggleModel): + """Single Person going on a trip, which may or may not be written up. + It accounts for different T/U for people in same logbook entry. + """ + personexpedition = models.ForeignKey("PersonExpedition",null=True,on_delete=models.CASCADE) + time_underground = models.FloatField(help_text="In decimal hours") + logbook_entry = models.ForeignKey(LogbookEntry,on_delete=models.CASCADE) + is_logbook_entry_author = models.BooleanField(default=False) + + def persontrip_next(self): + futurePTs = PersonTrip.objects.filter(personexpedition = self.personexpedition, logbook_entry__date__gt = self.logbook_entry.date).order_by('logbook_entry__date').all() + if len(futurePTs) > 0: + return futurePTs[0] + else: + return None + + def persontrip_prev(self): + pastPTs = PersonTrip.objects.filter(personexpedition = self.personexpedition, logbook_entry__date__lt = self.logbook_entry.date).order_by('-logbook_entry__date').all() + if len(pastPTs) > 0: + return pastPTs[0] + else: + return None + + def place(self): + return self.logbook_entry.cave and self.logbook_entry.cave or self.logbook_entry.place + + def __str__(self): + return "%s (%s)" % (self.personexpedition, self.logbook_entry.date) + +scansFileStorage = FileSystemStorage(location=settings.SURVEY_SCANS, base_url=settings.SURVEYS_URL) +def get_scan_path(instance, filename): + year=instance.survey.expedition.year + 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') + +Gcavelookup = None +Gcave_count = None +def GetCaveLookup(): + """lookup function modelled on GetPersonExpeditionNameLookup + repeated assignment each call, needs refactoring + + Does NOT detect duplicates! Needs fixing. + Needs to be a proper funciton that raises an exception if there is a duplicate. + OR we could set it to return None if there are duplictes, and require the caller to + fall back on doing the actual database query it wants rathe rthna using this cache shortcut + """ + global Gcavelookup + if Gcavelookup: + return Gcavelookup + Gcavelookup = {"NONEPLACEHOLDER": None} + global Gcave_count + Gcave_count = defaultdict(int) # sets default value to int(0) + + for cave in Cave.objects.all(): + key = cave.official_name.lower() + Gcavelookup[key] = cave + Gcave_count[key] += 1 + if cave.kataster_number: + Gcavelookup[cave.kataster_number] = cave # DUPLICATE as we have 1623-55 and 1626-55 + Gcave_count[cave.kataster_number] += 1 + if cave.unofficial_number: + Gcavelookup[cave.unofficial_number.lower()] = cave + Gcave_count[cave.unofficial_number.lower()] += 1 + if cave.filename: + # this is the slug - usually.. + Gcavelookup[cave.filename.replace(".html","").lower()] = cave + Gcave_count[cave.filename.replace(".html","").lower()] += 1 + if cave.slug(): + slug = cave.slug() + Gcavelookup[slug.lower()] = cave + Gcave_count[slug.lower()] += 1 + # These are exact matches! edit to check for prefix only! + # mostly taken from expoweb/noinfo/cave-number-index + # and Becka's email of 25 may 2020 on new kataster numbers + # this should be re-done as a JSON file upload + + # These might alse create more duplicate entries, so re-write it to check + Gcavelookup["1987-02"] = Gcavelookup["267"] + Gcavelookup["1990-01"] = Gcavelookup["171"] + Gcavelookup["1990-02"] = Gcavelookup["172"] + Gcavelookup["1990-03"] = Gcavelookup["173"] + Gcavelookup["1990-04"] = Gcavelookup["174"] + Gcavelookup["1990-05"] = Gcavelookup["175"] + Gcavelookup["1990-06"] = Gcavelookup["176"] + Gcavelookup["1990-07"] = Gcavelookup["177"] + Gcavelookup["1990-08"] = Gcavelookup["178"] + Gcavelookup["1990-09"] = Gcavelookup["179"] + Gcavelookup["1990-10"] = Gcavelookup["180"] + Gcavelookup["1990-11"] = Gcavelookup["181"] + Gcavelookup["1990-12"] = Gcavelookup["182"] + Gcavelookup["1990-13"] = Gcavelookup["183"] + Gcavelookup["1990-14"] = Gcavelookup["184"] + Gcavelookup["1990-18"] = Gcavelookup["188"] + Gcavelookup["1990-adam"] = Gcavelookup["225"] + Gcavelookup["1993-01"] = Gcavelookup["200"] + Gcavelookup["1996-02"] = Gcavelookup["224"] + Gcavelookup["1996-03"] = Gcavelookup["223"] + Gcavelookup["1996-04"] = Gcavelookup["222"] + Gcavelookup["1996wk2"] = Gcavelookup["207"] + Gcavelookup["1996wk3"] = Gcavelookup["208"] + Gcavelookup["1996wk5"] = Gcavelookup["219"] + Gcavelookup["1996wk6"] = Gcavelookup["218"] + Gcavelookup["1996wk8"] = Gcavelookup["209"] + Gcavelookup["1996wk11"] = Gcavelookup["268"] + Gcavelookup["96wk11"] = Gcavelookup["268"] + Gcavelookup["1998-01"] = Gcavelookup["201"] + Gcavelookup["1998-03"] = Gcavelookup["210"] + Gcavelookup["1999-03"] = Gcavelookup["204"] + Gcavelookup["1999-04"] = Gcavelookup["230"] + Gcavelookup["1999-10"] = Gcavelookup["162"] + Gcavelookup["1999-bo-01"] = Gcavelookup["205"] + Gcavelookup["1999-ob-01"] = Gcavelookup["205"] + Gcavelookup["1999-ob-03"] = Gcavelookup["226"] + Gcavelookup["1999-ob-04"] = Gcavelookup["227"] + Gcavelookup["2000-01"] = Gcavelookup["231"] + Gcavelookup["2000-03"] = Gcavelookup["214"] + Gcavelookup["2000-04"] = Gcavelookup["220"] + Gcavelookup["2000-05"] = Gcavelookup["215"] + Gcavelookup["2000-06"] = Gcavelookup["216"] + Gcavelookup["2000-07"] = Gcavelookup["217"] + Gcavelookup["2000-09"] = Gcavelookup["234"] + Gcavelookup["2000-aa-01"] = Gcavelookup["250"] + Gcavelookup["2001-04"] = Gcavelookup["239"] + Gcavelookup["2001-05"] = Gcavelookup["243"] + Gcavelookup["2002-01"] = Gcavelookup["249"] + Gcavelookup["2002-02"] = Gcavelookup["234"] + Gcavelookup["2002-04"] = Gcavelookup["242"] + Gcavelookup["2002-05"] = Gcavelookup["294"] + Gcavelookup["2003-01"] = Gcavelookup["256"] + Gcavelookup["2003-02"] = Gcavelookup["248"] + Gcavelookup["2003-03"] = Gcavelookup["247"] + Gcavelookup["2003-04"] = Gcavelookup["241"] + Gcavelookup["2003-05"] = Gcavelookup["246"] + Gcavelookup["2003-06"] = Gcavelookup["161"] + Gcavelookup["2003-08"] = Gcavelookup["240"] + Gcavelookup["2003-09"] = Gcavelookup["245"] + Gcavelookup["2003-10"] = Gcavelookup["244"] + Gcavelookup["2004-01"] = Gcavelookup["269"] + Gcavelookup["2004-03"] = Gcavelookup["270"] + Gcavelookup["2004-11"] = Gcavelookup["251"] + Gcavelookup["2004-12"] = Gcavelookup["161"] + Gcavelookup["2004-15"] = Gcavelookup["253"] + Gcavelookup["2004-19"] = Gcavelookup["254"] + Gcavelookup["2004-20"] = Gcavelookup["255"] + Gcavelookup["2005-04"] = Gcavelookup["204"] + Gcavelookup["2005-05"] = Gcavelookup["264"] + Gcavelookup["2005-07"] = Gcavelookup["257"] + Gcavelookup["2006-08"] = Gcavelookup["285"] + Gcavelookup["2006-09"] = Gcavelookup["298"] + Gcavelookup["2007-71"] = Gcavelookup["271"] + Gcavelookup["2010-01"] = Gcavelookup["263"] + Gcavelookup["2010-03"] = Gcavelookup["293"] + Gcavelookup["2011-01"] = Gcavelookup["292"] + Gcavelookup["2012-dd-05"] = Gcavelookup["286"] + Gcavelookup["2012-ns-13"] = Gcavelookup["292"] + Gcavelookup["2014-neo-01"] = Gcavelookup["273"] + Gcavelookup["2014-sd-01"] = Gcavelookup["274"] + Gcavelookup["2014-ms-14"] = Gcavelookup["287"] + Gcavelookup["2015-mf-06"] = Gcavelookup["288"] + Gcavelookup["2016-jb-01"] = Gcavelookup["289"] + Gcavelookup["2017-pw-01"] = Gcavelookup["277"] + Gcavelookup["2018-dm-07"] = Gcavelookup["359"] + Gcavelookup["2017_cucc_24"] = Gcavelookup["291"] # note _ not - here + Gcavelookup["2017_cucc_23"] = Gcavelookup["295"] + Gcavelookup["2017_cucc_28"] = Gcavelookup["290"] + Gcavelookup["bs17"] = Gcavelookup["283"] + + Gcavelookup["1976/b11"] = Gcavelookup["198"] + Gcavelookup["1976/b8"] = Gcavelookup["197"] + Gcavelookup["1976/b9"] = Gcavelookup["190"] + Gcavelookup["b11"] = Gcavelookup["1976/b11"] + Gcavelookup["b8"] = Gcavelookup["1976/b8"] + Gcavelookup["b9"] = Gcavelookup["1976/b9"] + + Gcavelookup["2011-01-bs30"] = Gcavelookup["190"] + Gcavelookup["bs30"] = Gcavelookup["190"] + Gcavelookup["87"] = Gcavelookup["190"] + Gcavelookup["2011-01"] = Gcavelookup["190"] + + Gcavelookup["quarriesd"] = Gcavelookup["2002-08"] + Gcavelookup["2002-x11"] = Gcavelookup["2005-08"] + Gcavelookup["2002-x12"] = Gcavelookup["2005-07"] + Gcavelookup["2002-x13"] = Gcavelookup["2005-06"] + Gcavelookup["2002-x14"] = Gcavelookup["2005-05"] + + Gcavelookup["kh"] = Gcavelookup["161"] + Gcavelookup["161-kh"] = Gcavelookup["161"] + Gcavelookup["204-steinBH"] = Gcavelookup["204"] + Gcavelookup["stonebridge"] = Gcavelookup["204"] + Gcavelookup["hauchhole"] = Gcavelookup["234"] + Gcavelookup["hauch"] = Gcavelookup["234"] + Gcavelookup["234-hauch"] = Gcavelookup["234"] + Gcavelookup["tunnocks"] = Gcavelookup["258"] + Gcavelookup["balcony"] = Gcavelookup["264"] + Gcavelookup["balkon"] = Gcavelookup["264"] + Gcavelookup["fgh"] = Gcavelookup["290"] + Gcavelookup["gsh"] = Gcavelookup["291"] + + Gcavelookup["homecoming"] = Gcavelookup["2018-dm-07"] + Gcavelookup["99ob02"] = Gcavelookup["1999-ob-02"] + + addmore = {} + for id in Gcavelookup: + addmore[id.replace("-","_")] = Gcavelookup[id] + addmore[id.replace("_","-")] = Gcavelookup[id] + Gcavelookup = {**addmore, **Gcavelookup} + + addmore ={} + for id in Gcavelookup: + if not Gcavelookup[id]: + pass + elif Gcavelookup[id].kataster_number: + addmore[id] = Gcavelookup[id].kataster_number + elif Gcavelookup[id].unofficial_number: + addmore[id] = Gcavelookup[id].unofficial_number.lower() + # with open("cave-lookup.json", 'w') as f: # no permissions on server by default + # json.dump(addmore, f) + + for c in Gcave_count: + if Gcave_count[c] > 1: + message = " ** Duplicate cave id: {}:{}:{}".format(Gcave_count[c], Gcavelookup[c], c) + #print(message) + #DataIssue.objects.create(parser='caves', message=message) + # logdataissues[Gcavelookup[c]]=message # pending troggle-wide issues logging system + + return Gcavelookup |