mirror of
https://expo.survex.com/repositories/troggle/.git
synced 2024-11-25 08:41:51 +00:00
dwg upload and django admin extra search
This commit is contained in:
parent
44b6770b6a
commit
d374779c47
@ -40,9 +40,11 @@ class SimpleTest(SimpleTestCase):
|
|||||||
import troggle.core.models.survex as models_survex
|
import troggle.core.models.survex as models_survex
|
||||||
import troggle.core.models.caves as models_caves
|
import troggle.core.models.caves as models_caves
|
||||||
from troggle.parsers.people import GetPersonExpeditionNameLookup
|
from troggle.parsers.people import GetPersonExpeditionNameLookup
|
||||||
from troggle.core.views.other import troggle404, frontpage
|
from troggle.core.views.other import frontpage
|
||||||
from troggle.core.views.caves import ent, cavepage
|
from troggle.core.views.caves import ent, cavepage
|
||||||
from troggle.core.views import scans, drawings, other, caves, statistics, survex
|
from troggle.core.views import scans, drawings, other, caves, statistics, survex, uploads
|
||||||
|
def test_import_views_uploads(self):
|
||||||
|
from troggle.core.views.uploads import dwgupload, scanupload
|
||||||
def test_import_parsers_QMs(self):
|
def test_import_parsers_QMs(self):
|
||||||
from troggle.core.models.caves import QM, Cave, LogbookEntry
|
from troggle.core.models.caves import QM, Cave, LogbookEntry
|
||||||
def test_import_parsers_people(self):
|
def test_import_parsers_people(self):
|
||||||
@ -97,7 +99,7 @@ class SimpleTest(SimpleTestCase):
|
|||||||
from troggle.core.views.logbooks import expedition, personexpedition, Expeditions_tsvListView, Expeditions_jsonListView
|
from troggle.core.views.logbooks import expedition, personexpedition, Expeditions_tsvListView, Expeditions_jsonListView
|
||||||
from troggle.core.views.logbooks import get_logbook_entries, logbookentry, logbookSearch
|
from troggle.core.views.logbooks import get_logbook_entries, logbookentry, logbookSearch
|
||||||
from troggle.core.views.logbooks import notablepersons, person, get_people
|
from troggle.core.views.logbooks import notablepersons, person, get_people
|
||||||
from troggle.core.views.other import troggle404, frontpage
|
from troggle.core.views.other import controlpanel
|
||||||
from troggle.core.views.prospect import prospecting
|
from troggle.core.views.prospect import prospecting
|
||||||
from troggle.core.views.prospect import prospecting_image
|
from troggle.core.views.prospect import prospecting_image
|
||||||
from troggle.core.views.statistics import pathsreport, stats, dataissues
|
from troggle.core.views.statistics import pathsreport, stats, dataissues
|
||||||
|
@ -86,20 +86,49 @@ class PostTests(TestCase):
|
|||||||
self.assertTrue(u.is_active, 'User \'' + u.username + '\' is INACTIVE')
|
self.assertTrue(u.is_active, 'User \'' + u.username + '\' is INACTIVE')
|
||||||
logged_in = c.login(username=u.username, password='secretword')
|
logged_in = c.login(username=u.username, password='secretword')
|
||||||
|
|
||||||
with open('README.txt','r') as testf:
|
with open('core/fixtures/test_upload_file.txt','r') as testf:
|
||||||
response = self.client.post('/scanupload/2021:00', data={'title': '2021#00', 'name': 'README.txt', 'scanfiles': testf })
|
response = self.client.post('/scanupload/2020:00', data={'name': 'test_upload_file.txt', 'uploadfiles': testf })
|
||||||
content = response.content.decode()
|
content = response.content.decode()
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(response.status_code, HTTPStatus.OK)
|
self.assertEqual(response.status_code, HTTPStatus.OK)
|
||||||
# with open('test_up.html', 'w') as f:
|
# with open('testresponse.html', 'w') as f:
|
||||||
# f.write(content)
|
# f.write(content)
|
||||||
t = re.search('<em>README', content)
|
for ph in [ r'test_upload_',
|
||||||
self.assertIsNotNone(t, 'Logged in but failed to see "<em>\'README"' )
|
r'← 2020#00 →',
|
||||||
t = re.search(' saved as', content)
|
r'Upload more?']:
|
||||||
self.assertIsNotNone(t, 'Logged in but failed to see "File(s) saved as"' )
|
phmatch = re.search(ph, content)
|
||||||
t = re.search('/expofiles/surveyscans/2021/2021%2300/README', content)
|
self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph +"'")
|
||||||
self.assertIsNotNone(t, 'Logged in but failed to see "/expofiles/..."' )
|
|
||||||
|
|
||||||
|
def test_dwg_upload(self):
|
||||||
|
'''Test file upload. Need to login first.
|
||||||
|
First upload is refused as it is a TXT file
|
||||||
|
Second upload is an image and suceeds.
|
||||||
|
'''
|
||||||
|
c = self.client
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
u = User.objects.get(username='expotest')
|
||||||
|
|
||||||
|
self.assertTrue(u.is_active, 'User \'' + u.username + '\' is INACTIVE')
|
||||||
|
logged_in = c.login(username=u.username, password='secretword')
|
||||||
|
|
||||||
|
with open('core/fixtures/test_upload_file.txt','r') as testf:
|
||||||
|
response = self.client.post('/dwgupload/uploads', data={'name': 'test_upload_file.txt', 'uploadfiles': testf })
|
||||||
|
content = response.content.decode()
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
t = re.search('Files refused:', content)
|
||||||
|
self.assertIsNotNone(t, 'Logged in but failed to see "Files refused:"' )
|
||||||
|
|
||||||
|
with open('core/fixtures/test_upload_nosuffix','r') as testf:
|
||||||
|
response = self.client.post('/dwgupload/uploads', data={'name': 'test_upload_nosuffix', 'uploadfiles': testf })
|
||||||
|
content = response.content.decode()
|
||||||
|
with open('testresponse.html', 'w') as f:
|
||||||
|
f.write(content)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
for ph in [ r'Upload more',
|
||||||
|
r' saved as ',
|
||||||
|
r'Clicking on a filename only']:
|
||||||
|
phmatch = re.search(ph, content)
|
||||||
|
self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph +"'")
|
||||||
|
|
||||||
|
|
||||||
class ComplexLoginTests(TestCase):
|
class ComplexLoginTests(TestCase):
|
||||||
|
@ -7,7 +7,8 @@ from django.core import serializers
|
|||||||
from troggle.core.views.other import exportlogbook
|
from troggle.core.views.other import exportlogbook
|
||||||
from troggle.core.models.troggle import Person, PersonExpedition, Expedition, DataIssue
|
from troggle.core.models.troggle import Person, PersonExpedition, Expedition, DataIssue
|
||||||
from troggle.core.models.caves import Cave, Area, Entrance, CaveAndEntrance, LogbookEntry, PersonTrip, QM
|
from troggle.core.models.caves import Cave, Area, Entrance, CaveAndEntrance, LogbookEntry, PersonTrip, QM
|
||||||
from troggle.core.models.survex import SurvexBlock, SurvexPersonRole, SurvexStation, Wallet, SingleScan
|
from troggle.core.models.survex import SurvexBlock, SurvexFile, SurvexPersonRole, SurvexStation, SurvexDirectory
|
||||||
|
from troggle.core.models.survex import Wallet, SingleScan, DrawingFile
|
||||||
|
|
||||||
'''This code significantly adds to the capabilities of the Django Management control panel for Troggle data.
|
'''This code significantly adds to the capabilities of the Django Management control panel for Troggle data.
|
||||||
In particular, it enables JSON export of any data with 'export_as_json'
|
In particular, it enables JSON export of any data with 'export_as_json'
|
||||||
@ -36,9 +37,9 @@ class SurvexBlockAdmin(TroggleModelAdmin):
|
|||||||
inlines = (RoleInline,)
|
inlines = (RoleInline,)
|
||||||
|
|
||||||
|
|
||||||
class SurveyAdmin(TroggleModelAdmin):
|
# class SurveyAdmin(TroggleModelAdmin):
|
||||||
#inlines = (ScannedImageInline,)
|
# #inlines = (ScannedImageInline,)
|
||||||
search_fields = ('expedition__year','wallet_number')
|
# search_fields = ('expedition__year','wallet_number')
|
||||||
|
|
||||||
|
|
||||||
class QMsFoundInline(admin.TabularInline):
|
class QMsFoundInline(admin.TabularInline):
|
||||||
@ -105,20 +106,38 @@ class CaveAdmin(TroggleModelAdmin):
|
|||||||
class EntranceAdmin(TroggleModelAdmin):
|
class EntranceAdmin(TroggleModelAdmin):
|
||||||
search_fields = ('caveandentrance__cave__kataster_number',)
|
search_fields = ('caveandentrance__cave__kataster_number',)
|
||||||
|
|
||||||
|
class SurvexStationAdmin(TroggleModelAdmin):
|
||||||
|
search_fields = ('name',)
|
||||||
|
|
||||||
|
class SurvexFileAdmin(TroggleModelAdmin):
|
||||||
|
search_fields = ('path',)
|
||||||
|
|
||||||
|
class SurvexDirectoryAdmin(TroggleModelAdmin):
|
||||||
|
search_fields = ('path', 'survexdirectory',)
|
||||||
|
|
||||||
|
class DrawingFileAdmin(TroggleModelAdmin):
|
||||||
|
search_fields = ('dwgname',)
|
||||||
|
|
||||||
|
class WalletAdmin(TroggleModelAdmin):
|
||||||
|
search_fields = ('fpath',)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Cave, CaveAdmin)
|
admin.site.register(Cave, CaveAdmin)
|
||||||
admin.site.register(Area)
|
admin.site.register(Area)
|
||||||
admin.site.register(CaveAndEntrance)
|
admin.site.register(CaveAndEntrance)
|
||||||
admin.site.register(Entrance, EntranceAdmin)
|
admin.site.register(Entrance, EntranceAdmin)
|
||||||
admin.site.register(SurvexBlock, SurvexBlockAdmin)
|
admin.site.register(SurvexBlock, SurvexBlockAdmin)
|
||||||
|
admin.site.register(DrawingFile, DrawingFileAdmin)
|
||||||
admin.site.register(Expedition)
|
admin.site.register(Expedition)
|
||||||
admin.site.register(Person,PersonAdmin)
|
admin.site.register(Person,PersonAdmin)
|
||||||
admin.site.register(SurvexPersonRole)
|
admin.site.register(SurvexPersonRole)
|
||||||
|
admin.site.register(SurvexDirectory, SurvexDirectoryAdmin)
|
||||||
|
admin.site.register(SurvexFile, SurvexFileAdmin)
|
||||||
|
admin.site.register(SurvexStation, SurvexStationAdmin)
|
||||||
admin.site.register(PersonExpedition,PersonExpeditionAdmin)
|
admin.site.register(PersonExpedition,PersonExpeditionAdmin)
|
||||||
admin.site.register(LogbookEntry, LogbookEntryAdmin)
|
admin.site.register(LogbookEntry, LogbookEntryAdmin)
|
||||||
admin.site.register(QM, QMAdmin)
|
admin.site.register(QM, QMAdmin)
|
||||||
admin.site.register(SurvexStation)
|
admin.site.register(Wallet, WalletAdmin)
|
||||||
admin.site.register(Wallet)
|
|
||||||
admin.site.register(SingleScan)
|
admin.site.register(SingleScan)
|
||||||
admin.site.register(DataIssue)
|
admin.site.register(DataIssue)
|
||||||
|
|
||||||
|
5
core/fixtures/test_upload_file.txt
Normal file
5
core/fixtures/test_upload_file.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
This file is uploaded by the integration test suite as part of the tests.
|
||||||
|
|
||||||
|
It, and any other with similar names, e.g test_upload_GPev9qN.txt can be safely deleted,
|
||||||
|
EXCEPT for the original copy which lives in troggle/core/fixtures/
|
||||||
|
|
7
core/fixtures/test_upload_nosuffix
Normal file
7
core/fixtures/test_upload_nosuffix
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
This file is uploaded by the integration test suite as part of the tests.
|
||||||
|
|
||||||
|
This has no suffix so it is pretending to be a Therion config file.
|
||||||
|
|
||||||
|
It, and any other with similar names, e.g test_upload_GPev9qN.txt can be safely deleted,
|
||||||
|
EXCEPT for the original copy which lives in troggle/core/fixtures/
|
||||||
|
|
@ -432,7 +432,7 @@ class LogbookEntry(TroggleModel):
|
|||||||
# #return super(LogbookEntry, self).__init__(*args, **kwargs) # works in py3.5
|
# #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
|
# #return TroggleModel.__init__(*args, **kwargs) # fails in py3.5, runtime fail in 3.8
|
||||||
|
|
||||||
def cave(self): # Why didn't he just make this a foreign key to Cave ? Replaces __egtattrribute__ sillyness.
|
def cave(self): # Why didn't he just make this a foreign key to Cave ? Replaces __getattrribute__ sillyness.
|
||||||
c = CaveSlug.objects.get(slug=self.cave_slug, primary=True).cave
|
c = CaveSlug.objects.get(slug=self.cave_slug, primary=True).cave
|
||||||
return c
|
return c
|
||||||
|
|
||||||
@ -540,13 +540,13 @@ class PersonTrip(TroggleModel):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f'{self.personexpedition} ({self.logbook_entry.date})'
|
return f'{self.personexpedition} ({self.logbook_entry.date})'
|
||||||
|
|
||||||
scansFileStorage = FileSystemStorage(location=settings.SURVEY_SCANS, base_url=settings.SURVEYS_URL)
|
# scansFileStorage = FileSystemStorage(location=settings.SURVEY_SCANS, base_url=settings.SURVEYS_URL)
|
||||||
def get_scan_path(instance, filename):
|
# def get_scan_path(instance, filename):
|
||||||
year=instance.survey.expedition.year
|
# year=instance.survey.expedition.year
|
||||||
number=str(instance.survey.wallet_number)
|
# number=str(instance.survey.wallet_number)
|
||||||
if str(instance.survey.wallet_letter) != "None":
|
# 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
|
# 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')
|
# return os.path.join('./',year,year+r'#'+number,str(instance.contents)+str(instance.number_in_wallet)+r'.jpg')
|
||||||
|
|
||||||
Gcavelookup = None
|
Gcavelookup = None
|
||||||
Gcave_count = None
|
Gcave_count = None
|
||||||
|
@ -15,10 +15,10 @@ class SurvexDirectory(models.Model):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('id',)
|
ordering = ('id',)
|
||||||
|
verbose_name_plural = "Survex directories"
|
||||||
|
|
||||||
# Don't change from the default as that breaks troggle webpages and internal referencing!
|
def __str__(self):
|
||||||
# def __str__(self):
|
return "[SurvexDirectory:"+str(self.path) + "-" + str(self.primarysurvexfile.path) + "-" + str(self.cave)+"]"
|
||||||
# return "[SurvexDirectory:"+str(self.path) + "-" + str(self.primarysurvexfile.path) + "-" + str(self.cave)+"]"
|
|
||||||
|
|
||||||
|
|
||||||
class SurvexFile(models.Model):
|
class SurvexFile(models.Model):
|
||||||
@ -53,7 +53,9 @@ class SurvexFile(models.Model):
|
|||||||
survexdirectory.save()
|
survexdirectory.save()
|
||||||
self.survexdirectory = survexdirectory
|
self.survexdirectory = survexdirectory
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.path
|
||||||
|
|
||||||
class SurvexStationLookUpManager(models.Manager):
|
class SurvexStationLookUpManager(models.Manager):
|
||||||
def lookup(self, name):
|
def lookup(self, name):
|
||||||
@ -122,11 +124,11 @@ class SurvexBlock(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('id',)
|
ordering = ('id',)
|
||||||
|
|
||||||
# Don't change from the original as that breaks troggle webpages and internal referencing!
|
def __str__(self):
|
||||||
# def __str__(self):
|
return "[SurvexBlock:"+ str(self.name) + "-path:" + \
|
||||||
# return "[SurvexBlock:"+ str(self.name) + "-path:" + \
|
str(self.survexpath) + "-cave:" + \
|
||||||
# str(self.survexpath) + "-cave:" + \
|
str(self.cave) + "]"
|
||||||
# str(self.cave) + "]"
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name and str(self.name) or 'no name'
|
return self.name and str(self.name) or 'no name'
|
||||||
|
|
||||||
@ -134,40 +136,19 @@ class SurvexBlock(models.Model):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def GetPersonroles(self):
|
def GetPersonroles(self):
|
||||||
'''To do: excise the 'role' bit of this while retaining personrole
|
'''
|
||||||
which is used in some later logic
|
|
||||||
|
|
||||||
But apparently never used !?
|
But apparently never used !?
|
||||||
'''
|
'''
|
||||||
res = [ ]
|
res = [ ]
|
||||||
for personrole in self.survexpersonrole_set.order_by('personexpedition'):
|
for personrole in self.survexpersonrole_set.order_by('personexpedition'):
|
||||||
# if res and res[-1]['person'] == personrole.personexpedition.person:
|
|
||||||
# res[-1]['roles'] += ", " + str(personrole.nrole)
|
|
||||||
# else:
|
|
||||||
# res.append({'person':personrole.personexpedition.person, 'expeditionyear':personrole.personexpedition.expedition.year, 'roles':str(personrole.nrole)})
|
|
||||||
res.append({'person':personrole.personexpedition.person, 'expeditionyear':personrole.personexpedition.expedition.year})
|
res.append({'person':personrole.personexpedition.person, 'expeditionyear':personrole.personexpedition.expedition.year})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def DayIndex(self):
|
def DayIndex(self):
|
||||||
return list(self.expeditionday.survexblock_set.all()).index(self)
|
return list(self.expeditionday.survexblock_set.all()).index(self)
|
||||||
#
|
|
||||||
# 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):
|
class SurvexPersonRole(models.Model):
|
||||||
survexblock = models.ForeignKey('SurvexBlock',on_delete=models.CASCADE)
|
survexblock = models.ForeignKey('SurvexBlock',on_delete=models.CASCADE)
|
||||||
# nrole = models.CharField(choices=ROLE_CHOICES, max_length=200, blank=True, null=True)
|
|
||||||
# increasing levels of precision
|
# increasing levels of precision
|
||||||
personname = models.CharField(max_length=100)
|
personname = models.CharField(max_length=100)
|
||||||
person = models.ForeignKey('Person', blank=True, null=True,on_delete=models.SET_NULL)
|
person = models.ForeignKey('Person', blank=True, null=True,on_delete=models.SET_NULL)
|
||||||
@ -176,7 +157,7 @@ class SurvexPersonRole(models.Model):
|
|||||||
expeditionday = models.ForeignKey("ExpeditionDay", null=True,on_delete=models.SET_NULL)
|
expeditionday = models.ForeignKey("ExpeditionDay", null=True,on_delete=models.SET_NULL)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.person) + " - " + str(self.survexblock) + " - " + str(self.nrole)
|
return str(self.person) + " - " + str(self.survexblock)
|
||||||
|
|
||||||
class Wallet(models.Model):
|
class Wallet(models.Model):
|
||||||
fpath = models.CharField(max_length=200)
|
fpath = models.CharField(max_length=200)
|
||||||
@ -189,7 +170,7 @@ class Wallet(models.Model):
|
|||||||
return urljoin(settings.URL_ROOT, reverse('singlewallet', kwargs={"path":re.sub("#", "%23", self.walletname)}))
|
return urljoin(settings.URL_ROOT, reverse('singlewallet', kwargs={"path":re.sub("#", "%23", self.walletname)}))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.walletname) + " (Survey Scans Folder)"
|
return str(self.walletname) + " (Wallet)"
|
||||||
|
|
||||||
class SingleScan(models.Model):
|
class SingleScan(models.Model):
|
||||||
ffile = models.CharField(max_length=200)
|
ffile = models.CharField(max_length=200)
|
||||||
@ -216,4 +197,8 @@ class DrawingFile(models.Model):
|
|||||||
survexfiles = models.ManyToManyField("SurvexFile") # direct link to SVX files - not populated yet
|
survexfiles = models.ManyToManyField("SurvexFile") # direct link to SVX files - not populated yet
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('dwgpath',)
|
ordering = ('dwgpath',)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Drawing File: " + str(self.dwgname) + " (" + str(self.filesize) + " bytes)"
|
||||||
|
|
@ -1,4 +1,5 @@
|
|||||||
import re, os
|
import re, os
|
||||||
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
@ -16,6 +17,7 @@ from troggle.parsers.imports import import_logbooks, import_QMs, import_drawings
|
|||||||
# from databaseReset import reinit_db # don't do this. databaseRest runs code *at import time*
|
# from databaseReset import reinit_db # don't do this. databaseRest runs code *at import time*
|
||||||
from troggle.core.models.troggle import Expedition, Person, PersonExpedition
|
from troggle.core.models.troggle import Expedition, Person, PersonExpedition
|
||||||
from troggle.core.models.caves import LogbookEntry, QM, Cave, PersonTrip
|
from troggle.core.models.caves import LogbookEntry, QM, Cave, PersonTrip
|
||||||
|
from troggle.core.models.survex import DrawingFile
|
||||||
from .auth import login_required_if_public
|
from .auth import login_required_if_public
|
||||||
|
|
||||||
'''Utility functions and code to serve the control panel and individual user's
|
'''Utility functions and code to serve the control panel and individual user's
|
||||||
@ -32,9 +34,7 @@ todo = '''
|
|||||||
so this is only a tool for a first pass, to be followed by extensive hand-editing!
|
so this is only a tool for a first pass, to be followed by extensive hand-editing!
|
||||||
When we have done all the old logbooks, delete this function and the two templates.
|
When we have done all the old logbooks, delete this function and the two templates.
|
||||||
|
|
||||||
-Do GIT stuff for upload forms
|
|
||||||
|
|
||||||
-Move upload forms to proper file locations
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def todos(request, module):
|
def todos(request, module):
|
||||||
@ -200,150 +200,3 @@ def exportlogbook(request,year=None,extension=None):
|
|||||||
|
|
||||||
return render(request,'controlPanel.html', {'expeditions':Expedition.objects.all(),'jobs_completed':[completed]})
|
return render(request,'controlPanel.html', {'expeditions':Expedition.objects.all(),'jobs_completed':[completed]})
|
||||||
|
|
||||||
|
|
||||||
class FilesForm(forms.Form): # not a model-form, just a form-form
|
|
||||||
uploadfiles = forms.FileField()
|
|
||||||
|
|
||||||
@login_required_if_public
|
|
||||||
def scanupload(request, wallet=None):
|
|
||||||
'''Upload scanned image files into a wallet on /expofiles
|
|
||||||
This does NOT use a Django model linked to a Django form. Just a simple Django form.
|
|
||||||
'''
|
|
||||||
filesaved = False
|
|
||||||
actual_saved = []
|
|
||||||
# print(f'! - FORM scanupload - start {wallet}')
|
|
||||||
if wallet is None:
|
|
||||||
wallet = "2021#01" # improve this later
|
|
||||||
if not re.match('(19|20)\d\d:\d\d', wallet):
|
|
||||||
wallet = "2021:01" # improve this later
|
|
||||||
|
|
||||||
year = wallet[:4]
|
|
||||||
if int(year) < 1977:
|
|
||||||
year = "1977"
|
|
||||||
if int(year) > 2050:
|
|
||||||
year = "2050"
|
|
||||||
nexty = f'{int(year)+1}'
|
|
||||||
prevy = f'{int(year)-1}'
|
|
||||||
|
|
||||||
wnumber = wallet[5:]
|
|
||||||
next = f'{int(wnumber)+1:02d}'
|
|
||||||
prev = f'{int(wnumber)-1:02d}'
|
|
||||||
|
|
||||||
if int(wnumber) == 0:
|
|
||||||
prev = f'{int(wnumber):02d}'
|
|
||||||
|
|
||||||
context = {'year': year, 'prev': prev, 'next': next, 'prevy': prevy, 'nexty': nexty}
|
|
||||||
|
|
||||||
wallet = wallet.replace(':','#')
|
|
||||||
dirpath = Path(settings.SURVEY_SCANS, year, wallet)
|
|
||||||
|
|
||||||
form = FilesForm()
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
form = FilesForm(request.POST,request.FILES)
|
|
||||||
if form.is_valid():
|
|
||||||
f = request.FILES["uploadfiles"]
|
|
||||||
multiple = request.FILES.getlist('uploadfiles')
|
|
||||||
fs = FileSystemStorage(os.path.join(settings.SURVEY_SCANS, year, wallet))
|
|
||||||
|
|
||||||
actual_saved = []
|
|
||||||
if multiple:
|
|
||||||
for f in multiple:
|
|
||||||
actual_saved.append( fs.save(f.name, content=f) )
|
|
||||||
# print(f'! - FORM scanupload multiple {actual_saved}')
|
|
||||||
filesaved = True
|
|
||||||
|
|
||||||
files = []
|
|
||||||
dirs = []
|
|
||||||
# print(f'! - FORM scanupload - start {wallet} {dirpath}')
|
|
||||||
try:
|
|
||||||
for f in dirpath.iterdir():
|
|
||||||
if f.is_dir():
|
|
||||||
dirs.append(f.name)
|
|
||||||
if f.is_file():
|
|
||||||
if f.name != 'contents.json' and f.name != 'walletindex.html':
|
|
||||||
files.append(f.name)
|
|
||||||
except FileNotFoundError:
|
|
||||||
files.append('(no wallet yet - would be created)')
|
|
||||||
if len(files) ==0 :
|
|
||||||
files.append('(no image files in wallet)')
|
|
||||||
else:
|
|
||||||
files = sorted(files)
|
|
||||||
|
|
||||||
if dirs:
|
|
||||||
dirs = sorted(dirs)
|
|
||||||
|
|
||||||
return render(request, 'scanuploadform.html',
|
|
||||||
{'form': form, 'wallet': wallet, **context, 'files': files, 'dirs': dirs, 'filesaved': filesaved, 'actual_saved': actual_saved})
|
|
||||||
|
|
||||||
@login_required_if_public
|
|
||||||
def dwgupload(request, folder=None):
|
|
||||||
'''Upload DRAWING files (tunnel or therion) into the upload folder in :drawings:
|
|
||||||
This does NOT use a Django model linked to a Django form. Just a simple Django form.
|
|
||||||
'''
|
|
||||||
def dwgvalid(name):
|
|
||||||
if name in [ '.gitignore', '.hgignore', ]:
|
|
||||||
return False
|
|
||||||
if Path(name).suffix in ['.xml', '.th', '.th2', '', '.svg', '.jpg']:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
filesaved = False
|
|
||||||
actual_saved = []
|
|
||||||
doesnotexist = ''
|
|
||||||
#print(f'! - FORM dwgupload - start "{folder}"')
|
|
||||||
if folder is None:
|
|
||||||
folder = "" # improve this later
|
|
||||||
dirpath = Path(settings.DRAWINGS_DATA)
|
|
||||||
urlfile = '/dwgdataraw'
|
|
||||||
urldir = '/dwgupload'
|
|
||||||
else:
|
|
||||||
dirpath = Path(settings.DRAWINGS_DATA, folder)
|
|
||||||
urlfile = Path('/dwgdataraw/') / folder
|
|
||||||
urldir = Path('/dwgupload/') / folder
|
|
||||||
|
|
||||||
form = FilesForm()
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
form = FilesForm(request.POST,request.FILES)
|
|
||||||
if form.is_valid():
|
|
||||||
f = request.FILES["uploadfiles"]
|
|
||||||
multiple = request.FILES.getlist('uploadfiles')
|
|
||||||
fs = FileSystemStorage(os.path.join(settings.DRAWINGS_DATA, folder))
|
|
||||||
|
|
||||||
actual_saved = []
|
|
||||||
if multiple:
|
|
||||||
for f in multiple:
|
|
||||||
if dwgvalid(f.name):
|
|
||||||
actual_saved.append( fs.save(f.name, content=f) )
|
|
||||||
# print(f'! - FORM dwgupload multiple {actual_saved}')
|
|
||||||
filesaved = True
|
|
||||||
|
|
||||||
# DO GIT STUFF & load into Database too
|
|
||||||
# parsers.surveys.SetTunnelfileInfo(dwgfile) # commented out
|
|
||||||
# dwgfile.save()
|
|
||||||
|
|
||||||
|
|
||||||
files = []
|
|
||||||
dirs = []
|
|
||||||
#print(f'! - FORM dwgupload - start {folder} \n"{dirpath}" \n"{dirpath.parent}" \n"{dirpath.exists()}"')
|
|
||||||
try:
|
|
||||||
for f in dirpath.iterdir():
|
|
||||||
if f.is_dir():
|
|
||||||
if f.name not in ['.git' ]:
|
|
||||||
dirs.append(f.name)
|
|
||||||
continue
|
|
||||||
if f.is_file():
|
|
||||||
if dwgvalid(f.name):
|
|
||||||
files.append(f.name)
|
|
||||||
continue
|
|
||||||
except FileNotFoundError:
|
|
||||||
doesnotexist = True
|
|
||||||
if files:
|
|
||||||
files = sorted(files)
|
|
||||||
|
|
||||||
if dirs:
|
|
||||||
dirs = sorted(dirs)
|
|
||||||
|
|
||||||
return render(request, 'dwguploadform.html',
|
|
||||||
{'form': form, 'doesnotexist': doesnotexist, 'urlfile': urlfile, 'urldir': urldir,'folder': folder, 'files': files, 'dirs': dirs, 'filesaved': filesaved, 'actual_saved': actual_saved})
|
|
||||||
|
188
core/views/uploads.py
Normal file
188
core/views/uploads.py
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
import re, os
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
|
from django.shortcuts import render
|
||||||
|
from django.template import Context, loader
|
||||||
|
from django.core.files.storage import FileSystemStorage, default_storage
|
||||||
|
|
||||||
|
from troggle.parsers.imports import import_caves, import_people, import_surveyscans
|
||||||
|
from troggle.parsers.imports import import_logbooks, import_QMs, import_drawingsfiles, import_survex
|
||||||
|
# from databaseReset import reinit_db # don't do this. databaseRest runs code *at import time*
|
||||||
|
from troggle.core.models.troggle import Expedition, Person, PersonExpedition
|
||||||
|
from troggle.core.models.caves import LogbookEntry, QM, Cave, PersonTrip
|
||||||
|
from troggle.core.models.survex import DrawingFile
|
||||||
|
from .auth import login_required_if_public
|
||||||
|
|
||||||
|
'''File upload 'views'
|
||||||
|
'''
|
||||||
|
|
||||||
|
todo = '''
|
||||||
|
-Move upload forms to proper file locations
|
||||||
|
'''
|
||||||
|
|
||||||
|
class FilesForm(forms.Form): # not a model-form, just a form-form
|
||||||
|
uploadfiles = forms.FileField()
|
||||||
|
|
||||||
|
@login_required_if_public
|
||||||
|
def scanupload(request, wallet=None):
|
||||||
|
'''Upload scanned image files into a wallet on /expofiles
|
||||||
|
This does NOT use a Django model linked to a Django form. Just a simple Django form.
|
||||||
|
'''
|
||||||
|
filesaved = False
|
||||||
|
actual_saved = []
|
||||||
|
# print(f'! - FORM scanupload - start {wallet}')
|
||||||
|
if wallet is None:
|
||||||
|
wallet = "2021#01" # improve this later
|
||||||
|
if not re.match('(19|20)\d\d:\d\d', wallet):
|
||||||
|
wallet = "2021:01" # improve this later
|
||||||
|
|
||||||
|
year = wallet[:4]
|
||||||
|
if int(year) < 1977:
|
||||||
|
year = "1977"
|
||||||
|
if int(year) > 2050:
|
||||||
|
year = "2050"
|
||||||
|
nexty = f'{int(year)+1}'
|
||||||
|
prevy = f'{int(year)-1}'
|
||||||
|
|
||||||
|
wnumber = wallet[5:]
|
||||||
|
next = f'{int(wnumber)+1:02d}'
|
||||||
|
prev = f'{int(wnumber)-1:02d}'
|
||||||
|
|
||||||
|
if int(wnumber) == 0:
|
||||||
|
prev = f'{int(wnumber):02d}'
|
||||||
|
|
||||||
|
context = {'year': year, 'prev': prev, 'next': next, 'prevy': prevy, 'nexty': nexty}
|
||||||
|
|
||||||
|
wallet = wallet.replace(':','#')
|
||||||
|
dirpath = Path(settings.SURVEY_SCANS, year, wallet)
|
||||||
|
|
||||||
|
form = FilesForm()
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = FilesForm(request.POST,request.FILES)
|
||||||
|
if form.is_valid():
|
||||||
|
f = request.FILES["uploadfiles"]
|
||||||
|
multiple = request.FILES.getlist('uploadfiles')
|
||||||
|
fs = FileSystemStorage(os.path.join(settings.SURVEY_SCANS, year, wallet))
|
||||||
|
|
||||||
|
actual_saved = []
|
||||||
|
if multiple:
|
||||||
|
for f in multiple:
|
||||||
|
actual_saved.append( fs.save(f.name, content=f) )
|
||||||
|
# print(f'! - FORM scanupload multiple {actual_saved}')
|
||||||
|
filesaved = True
|
||||||
|
|
||||||
|
files = []
|
||||||
|
dirs = []
|
||||||
|
# print(f'! - FORM scanupload - start {wallet} {dirpath}')
|
||||||
|
try:
|
||||||
|
for f in dirpath.iterdir():
|
||||||
|
if f.is_dir():
|
||||||
|
dirs.append(f.name)
|
||||||
|
if f.is_file():
|
||||||
|
if f.name != 'contents.json' and f.name != 'walletindex.html':
|
||||||
|
files.append(f.name)
|
||||||
|
except FileNotFoundError:
|
||||||
|
files.append('(no wallet yet - would be created)')
|
||||||
|
if len(files) ==0 :
|
||||||
|
files.append('(no image files in wallet)')
|
||||||
|
else:
|
||||||
|
files = sorted(files)
|
||||||
|
|
||||||
|
if dirs:
|
||||||
|
dirs = sorted(dirs)
|
||||||
|
|
||||||
|
return render(request, 'scanuploadform.html',
|
||||||
|
{'form': form, 'wallet': wallet, **context, 'files': files, 'dirs': dirs, 'filesaved': filesaved, 'actual_saved': actual_saved})
|
||||||
|
|
||||||
|
@login_required_if_public
|
||||||
|
def dwgupload(request, folder=None):
|
||||||
|
'''Upload DRAWING files (tunnel or therion) into the upload folder in :drawings:
|
||||||
|
This does NOT use a Django model linked to a Django form. Just a simple Django form.
|
||||||
|
|
||||||
|
We use get_or_create instead of simply creating a new object in case someone uploads the same file
|
||||||
|
several times in one session, and expects them to be overwritten in the database. Although
|
||||||
|
the actual file will be duplicated in the filesystem with different random name ammendation.
|
||||||
|
'''
|
||||||
|
def dwgvalid(name):
|
||||||
|
if name in [ '.gitignore', '.hgignore', ]:
|
||||||
|
return False
|
||||||
|
if Path(name).suffix.lower() in ['.xml', '.th', '.th2', '', '.svg', '.jpg', '.pdf', 'jpeg']:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
filesaved = False
|
||||||
|
actual_saved = []
|
||||||
|
refused = []
|
||||||
|
doesnotexist = ''
|
||||||
|
#print(f'! - FORM dwgupload - start "{folder}"')
|
||||||
|
if folder is None:
|
||||||
|
folder = "" # improve this later
|
||||||
|
dirpath = Path(settings.DRAWINGS_DATA)
|
||||||
|
urlfile = '/dwgdataraw'
|
||||||
|
urldir = '/dwgupload'
|
||||||
|
else:
|
||||||
|
dirpath = Path(settings.DRAWINGS_DATA, folder)
|
||||||
|
urlfile = Path('/dwgdataraw/') / folder
|
||||||
|
urldir = Path('/dwgupload/') / folder
|
||||||
|
|
||||||
|
form = FilesForm()
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = FilesForm(request.POST,request.FILES)
|
||||||
|
if form.is_valid():
|
||||||
|
f = request.FILES["uploadfiles"]
|
||||||
|
multiple = request.FILES.getlist('uploadfiles')
|
||||||
|
fs = FileSystemStorage(os.path.join(settings.DRAWINGS_DATA, folder))
|
||||||
|
|
||||||
|
actual_saved = []
|
||||||
|
refused = []
|
||||||
|
git = settings.GIT
|
||||||
|
if multiple:
|
||||||
|
for f in multiple:
|
||||||
|
if dwgvalid(f.name):
|
||||||
|
saved_filename = fs.save(f.name, content=f)
|
||||||
|
actual_saved.append(saved_filename)
|
||||||
|
subprocess.call([git, "add", saved_filename], cwd=dirpath)
|
||||||
|
# dwgfile = DrawingFile(dwgpath=f.name, dwgname=Path(f.name).stem, filesize=f.size)
|
||||||
|
dwgfile, created = DrawingFile.objects.get_or_create(dwgpath=saved_filename, dwgname=Path(f.name).stem, filesize=f.size)
|
||||||
|
# if not created:
|
||||||
|
# print(f'FAILED to create {saved_filename} in {dirpath}')
|
||||||
|
# else:
|
||||||
|
# print(f'{dwgfile}')
|
||||||
|
dwgfile.save()
|
||||||
|
else:
|
||||||
|
refused.append(f.name)
|
||||||
|
# print(f'! - FORM dwgupload multiple {actual_saved}')
|
||||||
|
filesaved = True
|
||||||
|
subprocess.call([git, "commit", "-m", 'dwgupload'], cwd=dirpath)
|
||||||
|
files = []
|
||||||
|
dirs = []
|
||||||
|
#print(f'! - FORM dwgupload - start {folder} \n"{dirpath}" \n"{dirpath.parent}" \n"{dirpath.exists()}"')
|
||||||
|
try:
|
||||||
|
for f in dirpath.iterdir():
|
||||||
|
if f.is_dir():
|
||||||
|
if f.name not in ['.git' ]:
|
||||||
|
dirs.append(f.name)
|
||||||
|
continue
|
||||||
|
if f.is_file():
|
||||||
|
if dwgvalid(f.name):
|
||||||
|
files.append(f.name)
|
||||||
|
continue
|
||||||
|
except FileNotFoundError:
|
||||||
|
doesnotexist = True
|
||||||
|
if files:
|
||||||
|
files = sorted(files)
|
||||||
|
|
||||||
|
if dirs:
|
||||||
|
dirs = sorted(dirs)
|
||||||
|
|
||||||
|
return render(request, 'dwguploadform.html',
|
||||||
|
{'form': form, 'doesnotexist': doesnotexist, 'urlfile': urlfile, 'urldir': urldir,'folder': folder, 'files': files, 'dirs': dirs, 'filesaved': filesaved, 'actual_saved': actual_saved, 'refused': refused})
|
@ -34,7 +34,7 @@ def get_or_create_placeholder(year):
|
|||||||
placeholder_logbook_entry, newly_created = save_carefully(LogbookEntry, lookupAttribs, nonLookupAttribs)
|
placeholder_logbook_entry, newly_created = save_carefully(LogbookEntry, lookupAttribs, nonLookupAttribs)
|
||||||
return placeholder_logbook_entry
|
return placeholder_logbook_entry
|
||||||
|
|
||||||
def find_tunnel_file(dwgfile, path):
|
def find_dwg_file(dwgfile, path):
|
||||||
'''Is given a line of text 'path' which may or may not contain a recognisable name of a scanned file
|
'''Is given a line of text 'path' which may or may not contain a recognisable name of a scanned file
|
||||||
which we have already seen when we imported all the files we could find in the surveyscans direstories
|
which we have already seen when we imported all the files we could find in the surveyscans direstories
|
||||||
'''
|
'''
|
||||||
@ -164,7 +164,7 @@ def setdwgfileinfo(dwgfile):
|
|||||||
# <pcarea area_signal="frame" sfscaledown="12.282584" sfrotatedeg="-90.76982" sfxtrans="11.676667377221136" sfytrans="-15.677173422877454" sfsketch="204description/scans/plan(38).png" sfstyle="" nodeconnzsetrelative="0.0">
|
# <pcarea area_signal="frame" sfscaledown="12.282584" sfrotatedeg="-90.76982" sfxtrans="11.676667377221136" sfytrans="-15.677173422877454" sfsketch="204description/scans/plan(38).png" sfstyle="" nodeconnzsetrelative="0.0">
|
||||||
|
|
||||||
for path, style in rx_pcpath.findall(ttext):
|
for path, style in rx_pcpath.findall(ttext):
|
||||||
find_tunnel_file(dwgfile, path.decode())
|
find_dwg_file(dwgfile, path.decode())
|
||||||
|
|
||||||
# should also scan and look for survex blocks that might have been included, and image scans
|
# should also scan and look for survex blocks that might have been included, and image scans
|
||||||
# which would populate dwgfile.survexfile
|
# which would populate dwgfile.survexfile
|
||||||
|
@ -207,7 +207,6 @@ class LoadingSurvex():
|
|||||||
if (personexpedition, tm) not in teammembers:
|
if (personexpedition, tm) not in teammembers:
|
||||||
teammembers.append((personexpedition, tm))
|
teammembers.append((personexpedition, tm))
|
||||||
personrole = SurvexPersonRole(survexblock=survexblock, personexpedition=personexpedition, personname=tm)
|
personrole = SurvexPersonRole(survexblock=survexblock, personexpedition=personexpedition, personname=tm)
|
||||||
# personrole = SurvexPersonRole(survexblock=survexblock, nrole=mteammember.group(1).lower(), personexpedition=personexpedition, personname=tm)
|
|
||||||
personrole.save()
|
personrole.save()
|
||||||
personrole.expeditionday = survexblock.expeditionday
|
personrole.expeditionday = survexblock.expeditionday
|
||||||
if personexpedition:
|
if personexpedition:
|
||||||
|
@ -22,41 +22,48 @@
|
|||||||
<p>Only drawings and drawing config files can be uploaded.
|
<p>Only drawings and drawing config files can be uploaded.
|
||||||
</div>
|
</div>
|
||||||
<div style = "max-width:70%; margin-left:20%; text-align: left" >
|
<div style = "max-width:70%; margin-left:20%; text-align: left" >
|
||||||
|
{% if refused %}
|
||||||
|
<p>
|
||||||
|
<b>Files refused: </b><br>
|
||||||
|
{% for f in refused %}
|
||||||
|
<em>{{f}}</em> <br>
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
{% if filesaved %}
|
{% if filesaved %}
|
||||||
<p>
|
<p>
|
||||||
<b>Drawing(s) saved as <br>
|
<b>Drawing(s) saved as </b><br>
|
||||||
{% for f in actual_saved %}
|
{% for f in actual_saved %}
|
||||||
<em>{{f}}</em> <br>
|
<em>{{f}}</em> <br>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<br><br>Upload more?</b>
|
<br>Upload more?</b>
|
||||||
</p>
|
</p>
|
||||||
<br>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<hr><br>
|
||||||
{% if doesnotexist %}
|
{% if doesnotexist %}
|
||||||
<p>No folder of this name.<br>
|
<p>No folder of this name.<br>
|
||||||
It would be created if you upload a file.
|
It would be created if you upload a file.
|
||||||
{% else %}
|
{% else %}
|
||||||
<strong style="font-size: 110%;">Files:</strong><br>
|
<strong style="font-size: 110%;">Files:</strong><br>
|
||||||
{% for f in files %}
|
{% for f in files %}
|
||||||
<a href="{{urlfile|urlencode}}/{{f|urlencode}}">{{f}}</a><br />
|
<a href="{{urlfile|urlencode}}/{{f|urlencode}}">{{f}}</a><br />
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p><No files here>
|
<p><No files here>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
<p><strong style="font-size: 110%;">Directories:</strong><br>
|
<p><strong style="font-size: 110%;">Directories:</strong><br>
|
||||||
{% if folder %}
|
{% if folder %}
|
||||||
<a href="{{urldir}}/..">[up]</a><br />
|
<a href="{{urldir}}/..">[up]</a><br />
|
||||||
|
{% endif %}
|
||||||
|
{% for f in dirs %}
|
||||||
|
<a href="{{urldir}}/{{f}}">/{{f}}/</a><br />
|
||||||
|
{% empty %}
|
||||||
|
<p><No subdirectories>
|
||||||
|
{% endfor %}
|
||||||
|
<p>Clicking on a filename only works if the drawing file has been imported into the system as part of a bulk-import
|
||||||
|
as we are matching it against a file recorded in the database.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for f in dirs %}
|
|
||||||
<a href="{{urldir}}/{{f}}">/{{f}}/</a><br />
|
|
||||||
{% empty %}
|
|
||||||
<p><No subdirectories>
|
|
||||||
{% endfor %}
|
|
||||||
<p>Clicking on a filename only works if the drawing file has been imported into the system as part of a bulk-import
|
|
||||||
as we are matching it against a file recorded in the database.
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
4
urls.py
4
urls.py
@ -12,8 +12,8 @@ from troggle.core.views import caves, statistics, survex
|
|||||||
from troggle.core.views.scans import scansingle, singlewallet, allwallets
|
from troggle.core.views.scans import scansingle, singlewallet, allwallets
|
||||||
from troggle.core.views.drawings import dwgallfiles, dwgfilesingle
|
from troggle.core.views.drawings import dwgallfiles, dwgfilesingle
|
||||||
#from troggle.core.views.drawings import dwgfileupload
|
#from troggle.core.views.drawings import dwgfileupload
|
||||||
from troggle.core.views.other import dwgupload
|
from troggle.core.views.uploads import dwgupload, scanupload
|
||||||
from troggle.core.views.other import troggle404, frontpage, todos, controlpanel, frontpage, scanupload
|
from troggle.core.views.other import troggle404, frontpage, todos, controlpanel, frontpage
|
||||||
from troggle.core.views.other import exportlogbook
|
from troggle.core.views.other import exportlogbook
|
||||||
from troggle.core.views.caves import ent, cavepage
|
from troggle.core.views.caves import ent, cavepage
|
||||||
from troggle.core.views.logbooks import get_logbook_entries, logbookentry, logbookSearch
|
from troggle.core.views.logbooks import get_logbook_entries, logbookentry, logbookSearch
|
||||||
|
Loading…
Reference in New Issue
Block a user