import datetime import json import operator import os import re from functools import reduce from pathlib import Path from urllib.parse import urljoin from django.conf import settings from django.db import models from django.urls import reverse from troggle.core.models.wallets import Wallet # from troggle.core.models.troggle import DataIssue # circular import. Hmm class SurvexDirectory(models.Model): path = models.CharField(max_length=200) cave = models.ForeignKey('Cave', blank=True, null=True,on_delete=models.SET_NULL) primarysurvexfile = models.ForeignKey('SurvexFile', related_name='primarysurvexfile', blank=True, null=True,on_delete=models.SET_NULL) # could also include files in directory but not referenced class Meta: ordering = ('id',) verbose_name_plural = "Survex directories" def __str__(self): return "[SurvexDirectory:"+str(self.path) + " | Primary svx:" + str(self.primarysurvexfile.path) +".svx ]" class SurvexFile(models.Model): path = models.CharField(max_length=200) survexdirectory = models.ForeignKey("SurvexDirectory", blank=True, null=True,on_delete=models.SET_NULL) cave = models.ForeignKey('Cave', blank=True, null=True,on_delete=models.SET_NULL) class Meta: ordering = ('id',) # Don't change from the default as that breaks troggle webpages and internal referencing! # def __str__(self): # return "[SurvexFile:"+str(self.path) + "-" + str(self.survexdirectory) + "-" + str(self.cave)+"]" 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] # pointless search every time we import a survex file if we know there are no duplicates.. # don't use this for initial import. 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() def __str__(self): return self.path class SurvexStationLookUpManager(models.Manager): def lookup(self, name): blocknames, sep, stationname = name.rpartition(".") return self.get(block = SurvexBlock.objects.lookup(blocknames), name__iexact = stationname) class SurvexStation(models.Model): name = models.CharField(max_length=100) block = models.ForeignKey('SurvexBlock', null=True,on_delete=models.SET_NULL) objects = SurvexStationLookUpManager() x = models.FloatField(blank=True, null=True) y = models.FloatField(blank=True, null=True) z = models.FloatField(blank=True, null=True) def path(self): r = self.name b = self.block while True: if b.name: r = b.name + "." + r if b.parent: b = b.parent else: return r class Meta: ordering = ('id',) def __str__(self): return self.name and str(self.name) or 'no name' # # Single SurvexBlock # class SurvexBlockLookUpManager(models.Manager): """Don't know what this does, suspect it is part of the Django admin system""" def lookup(self, name): if name == "": blocknames = [] else: blocknames = name.split(".") block = SurvexBlock.objects.get(parent=None, survexfile__path=settings.SURVEX_TOPNAME) for blockname in blocknames: block = SurvexBlock.objects.get(parent=block, name__iexact=blockname) return block class SurvexBlock(models.Model): """One begin..end block within a survex file. The basic element of a survey trip. """ objects = SurvexBlockLookUpManager() name = models.CharField(max_length=100) title = models.CharField(max_length=200) parent = models.ForeignKey('SurvexBlock', blank=True, null=True,on_delete=models.SET_NULL) cave = models.ForeignKey('Cave', blank=True, null=True,on_delete=models.SET_NULL) date = models.DateField(blank=True, null=True) #expeditionday = models.ForeignKey("ExpeditionDay", null=True,on_delete=models.SET_NULL) expedition = models.ForeignKey('Expedition', blank=True, null=True,on_delete=models.SET_NULL) survexfile = models.ForeignKey("SurvexFile", blank=True, null=True,on_delete=models.SET_NULL) survexpath = models.CharField(max_length=200) # the path for the survex stations scanswallet = models.ForeignKey("Wallet", null=True,on_delete=models.SET_NULL) # only ONE wallet per block. The most recent seen overwites.. ugh. legsall = models.IntegerField(null=True) # summary data for this block legslength = models.FloatField(null=True) class Meta: ordering = ('id',) def __str__(self): return "[SurvexBlock:"+ str(self.name) + "-path:" + \ str(self.survexpath) + "-cave:" + \ str(self.cave) + "]" def __str__(self): return self.name and str(self.name) or 'no name' def isSurvexBlock(self): # Function used in templates return True def DayIndex(self): """This is used to set different colours for the different trips on the calendar view of the expedition""" mx = 10 index = list(SurvexBlock.objects.filter(date=self.date)).index(self) if index not in range(0, mx): print(f"DayIndex: More than {mx-1} SurvexBlock items on one day '{index}' {self}") index = 0 #return list(self.survexblock_set.all()).index(self) return index class SurvexPersonRole(models.Model): survexblock = models.ForeignKey('SurvexBlock',on_delete=models.CASCADE) # increasing levels of precision, Surely we only need survexblock and person now that we have no link to a logbook entry? personname = models.CharField(max_length=100) person = models.ForeignKey('Person', blank=True, null=True,on_delete=models.SET_NULL) personexpedition = models.ForeignKey('PersonExpedition', blank=True, null=True,on_delete=models.SET_NULL) expeditionday = models.ForeignKey("ExpeditionDay", null=True,on_delete=models.SET_NULL) def __str__(self): return str(self.personname) + " - " + str(self.survexblock) class SingleScan(models.Model): """A single file holding an image. Could be raw notes, an elevation plot or whatever """ ffile = models.CharField(max_length=200) name = models.CharField(max_length=200) wallet = models.ForeignKey("Wallet", null=True,on_delete=models.SET_NULL) class Meta: ordering = ('name',) def get_absolute_url(self): return urljoin(settings.URL_ROOT, reverse('scansingle', kwargs={"path":re.sub("#", "%23", self.wallet.walletname), "file":self.name})) def __str__(self): return "Scan Image: " + str(self.name) + " in " + str(self.wallet) class DrawingFile(models.Model): """A file holding a Therion (several types) or a Tunnel drawing """ dwgpath = models.CharField(max_length=200) dwgname = models.CharField(max_length=200) dwgwallets = models.ManyToManyField("Wallet") # implicitly links via folders to scans to SVX files scans = models.ManyToManyField("SingleScan") # implicitly links via scans to SVX files dwgcontains = models.ManyToManyField("DrawingFile") # case when its a frame type filesize = models.IntegerField(default=0) npaths = models.IntegerField(default=0) survexfiles = models.ManyToManyField("SurvexFile") # direct link to SVX files - not populated yet class Meta: ordering = ('dwgpath',) def __str__(self): return "Drawing File: " + str(self.dwgname) + " (" + str(self.filesize) + " bytes)"