2021-05-05 00:35:10 +01:00
import re , os
import subprocess
2022-03-15 17:04:43 +00:00
import json
2022-03-15 20:53:55 +00:00
import settings
2022-03-18 11:28:35 +00:00
import urllib
2022-07-17 13:01:53 +01:00
import operator
2022-03-15 20:53:55 +00:00
2021-05-05 00:35:10 +01:00
from pathlib import Path
2022-07-17 13:01:53 +01:00
from functools import reduce
2021-05-05 00:35:10 +01:00
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
2022-07-17 13:01:53 +01:00
from django . core . exceptions import ObjectDoesNotExist , MultipleObjectsReturned
2021-05-05 00:35:10 +01:00
2022-03-18 11:28:35 +00:00
2022-03-13 01:01:00 +00:00
#from troggle import settings
2021-05-05 00:35:10 +01:00
from troggle . parsers . imports import import_caves , import_people , import_surveyscans
from troggle . parsers . imports import import_logbooks , import_QMs , import_drawingsfiles , import_survex
2022-07-28 16:36:40 +01:00
from troggle . parsers . scans import wallet_blank_json , wallet_blank_html , contentsjson , indexhtml , CopyWalletData
2021-05-05 00:35:10 +01:00
# from databaseReset import reinit_db # don't do this. databaseRest runs code *at import time*
2022-03-15 20:53:55 +00:00
from troggle . core . models . troggle import DataIssue
2021-05-05 00:35:10 +01:00
from troggle . core . models . troggle import Expedition , Person , PersonExpedition
from troggle . core . models . caves import LogbookEntry , QM , Cave , PersonTrip
2022-07-28 16:36:40 +01:00
from troggle . core . models . survex import DrawingFile , Wallet
2022-03-18 12:26:32 +00:00
from troggle . core . views . scans import oldwallet , walletindex
2022-07-17 13:01:53 +01:00
from troggle . core . views . caves import getCave
2022-03-18 11:28:35 +00:00
2021-05-05 00:35:10 +01:00
from . auth import login_required_if_public
2022-03-13 01:01:00 +00:00
#from django.views.decorators.csrf import ensure_csrf_cookie, csrf_exempt
2021-05-05 00:35:10 +01:00
''' File upload ' views '
'''
todo = '''
2022-07-17 13:01:53 +01:00
- Register uploaded filenames in the Django db without needing to wait for a reset & bulk file import
- Refactor scanupload ( ) as it contains all the wallets ' complaints ' code from the old script wallets . py
2022-03-17 00:41:29 +00:00
- Need to validate uploaded file as being a valid image file , not a dubious script or hack
2022-03-08 22:59:04 +00:00
- Write equivalent GPX upload form system , similar to scanupload ( ) but in expofiles / gpslogs /
Need to validate it as being a valid GPX file using an XML parser , not a dubious script or hack
2022-04-20 21:18:05 +01:00
- Validate Tunnel & Therion files using an XML parser in dwgupload ( ) . Though Julian says tunnel is only mostly correct XML
2022-03-08 22:59:04 +00:00
2022-03-17 00:41:29 +00:00
- Validate image files using a magic recogniser in scanupload ( ) https : / / pypi . org / project / reportlab / or
https : / / stackoverflow . com / questions / 889333 / how - to - check - if - a - file - is - a - valid - image - file
2022-03-08 22:59:04 +00:00
- Enable folder creation in dwguploads or as a separate form
2022-04-20 21:18:05 +01:00
2021-05-05 00:35:10 +01:00
'''
class FilesForm ( forms . Form ) : # not a model-form, just a form-form
uploadfiles = forms . FileField ( )
2022-08-11 19:19:52 +01:00
class FilesRenameForm ( forms . Form ) : # not a model-form, just a form-form
uploadfiles = forms . FileField ( )
2022-08-11 21:35:53 +01:00
renameto = forms . CharField ( strip = True , required = False )
2022-08-11 19:19:52 +01:00
2022-03-13 01:01:00 +00:00
class TextForm ( forms . Form ) : # not a model-form, just a form-form
photographer = forms . CharField ( strip = True )
2022-03-17 00:41:29 +00:00
class WalletForm ( forms . Form ) : # not a model-form, just a form-form
descriptionw = forms . CharField ( strip = True , required = False )
people = forms . CharField ( strip = True , required = False )
survexnr = forms . CharField ( strip = True , required = False )
qmsw = forms . CharField ( strip = True , required = False )
date = forms . CharField ( strip = True , required = True ) # the only required field
websiteupt = forms . CharField ( strip = True , required = False )
elevnr = forms . CharField ( strip = True , required = False )
cave = forms . CharField ( strip = True , required = False )
psg = forms . CharField ( strip = True , required = False )
plannr = forms . CharField ( strip = True , required = False )
electronic = forms . CharField ( strip = True , required = False )
pland = forms . CharField ( strip = True , required = False )
elevd = forms . CharField ( strip = True , required = False )
url = forms . CharField ( strip = True , required = False )
survex = forms . CharField ( strip = True , required = False )
xlate = { " url " : " description url " ,
" descriptionw " : " description written " ,
" people " : " people " ,
" date " : " date " ,
" cave " : " cave " ,
" plannr " : " plan not required " ,
" survexnr " : " survex not required " ,
" qmsw " : " qms written " ,
" elevnr " : " elev not required " ,
" websiteupt " : " website updated " ,
" electronic " : " electronic survey " ,
" pland " : " plan drawn " ,
" elevd " : " elev drawn " ,
2022-07-28 16:36:40 +01:00
" psg " : " name " , # a name for this wallet
2022-03-17 00:41:29 +00:00
" survex " : " survex file " ,
}
2022-07-21 07:40:35 +01:00
def get_complaints ( complaints , waldata , svxfiles , files , wallet , wurl ) :
2022-07-17 13:01:53 +01:00
''' Taken from old script wallets.py and edited to make more comprehensible
Loads the survex files names and processes all complaints
2022-08-01 00:50:19 +01:00
2022-07-17 13:01:53 +01:00
'''
2022-08-07 20:52:29 +01:00
# If skipping through the wllets on the upload form, the wallet may not yet exist
try :
w = Wallet . objects . get ( walletname = wallet )
except ObjectDoesNotExist :
return None , None
2022-08-01 15:32:35 +01:00
ticks = w . get_ticks ( )
2022-07-17 13:41:05 +01:00
# Date
if not waldata [ " date " ] :
complaints . append ( " A date is mandatory. No data can be updated or edited unless you specify a date. Look in the survex file if there is one. " )
# People
if waldata [ " people " ] == [ " NOBODY " ] or waldata [ " people " ] == [ " Unknown " ] :
complaints . append ( " Someody must have done this. Look in the survex file, or in the logbook entries for this date, for the people who created this data. " )
2022-08-01 15:32:35 +01:00
# survex, but get_ticks has already done much of this ??
2022-07-17 13:01:53 +01:00
survex_complaint = " "
if waldata [ " survex file " ] :
if not type ( waldata [ " survex file " ] ) == list : # a string also is a sequence type, so do it this way
waldata [ " survex file " ] = [ waldata [ " survex file " ] ]
for svx in waldata [ " survex file " ] :
2022-07-28 16:36:40 +01:00
if svx != " " :
svxfiles . append ( svx )
if not ( Path ( settings . SURVEX_DATA ) / svx ) . is_file ( ) :
2022-08-07 21:26:31 +01:00
file_complaint = f " { wallet } Incorrect survex file name in { wallet } wallet data. { svx } was not found in LOSER repo "
2022-07-28 16:36:40 +01:00
complaints . append ( file_complaint )
message = f " ! { file_complaint } "
print ( message )
2022-08-07 21:26:31 +01:00
DataIssue . objects . update_or_create ( parser = ' scans ' , message = message , url = wurl ) # set URL to this wallet folder
2022-07-17 13:01:53 +01:00
if waldata [ " survex not required " ] and waldata [ " survex file " ] != " " :
survex_complaint = " Survex is stated as not required and yet there is a survex file! "
if not waldata [ " survex not required " ] and waldata [ " survex file " ] == " " :
survex_complaint = " A survex file is required, but has not been specified! "
if survex_complaint :
complaints . append ( survex_complaint )
2022-08-01 15:32:35 +01:00
2022-07-17 13:01:53 +01:00
# Notes required
2022-08-01 15:32:35 +01:00
if ticks [ ' N ' ] != " green " :
complaints . append ( " The notes needs scanning (or renaming): no noteNN.jpg or XXnote.jpg file found; and this is not an electronic survey. " )
2022-07-17 13:01:53 +01:00
# Plan drawing required
2022-08-01 15:32:35 +01:00
if ticks [ ' P ' ] != " green " :
complaints . append ( " The plan needs drawing (or renaming, or tick ' Plan drawn ' checkbox or ' Plan not required ' checkbox): no planNN.jpg or XXplan.jpg file found. " )
2022-07-17 13:01:53 +01:00
# Elev drawing required
2022-08-01 15:32:35 +01:00
if ticks [ ' E ' ] != " green " :
2022-07-17 13:01:53 +01:00
complaints . append ( " The elevation needs drawing (or renaming, or tick ' Elev drawn ' checkbox or ' Elev not required ' checkbox): no elevNN.jpg or XXelev.jpg file found. " )
2022-08-01 15:32:35 +01:00
# ETherion
if ticks [ ' T ' ] != " green " :
complaints . append ( " Tunnel or Therion drawing files need drawing. Or if this an electronic survey, please tick the ' Electronic survey ' checkbox. " )
2022-07-17 13:01:53 +01:00
# Description
if not waldata [ " description written " ] :
complaints . append ( " The guidebook description needs writing into the survex file. Tick the ' Cave description written ' checkbox when this is done. " )
# QMs
if not waldata [ " qms written " ] :
complaints . append ( " The QMs needs writing into the survex file. Tick the ' QMs written ' checkbox when this is done. " )
# Website
if not waldata [ " website updated " ] :
complaints . append ( " The cave description website is marked as needing updating using the guidebook description from the survex file. Tick the ' Website updated ' checkbox when this is done. " )
# FInd the cave, if it exists
2022-07-17 13:22:26 +01:00
if waldata [ " cave " ] :
try :
2022-07-17 13:28:20 +01:00
caveid = waldata [ " cave " ]
caveid = caveid . replace ( " / " , " - " )
caveobject = getCave ( caveid )
2022-07-17 13:22:26 +01:00
print ( f ' getCave for id " { waldata [ " cave " ] } " { caveobject } ' )
if not caveobject . url == waldata [ " description url " ] :
complaints . append ( f ' The URL of cave description \" { waldata [ " description url " ] } \" does not match the one on record for this cave which is: " { caveobject . url } " . If the wallet is not for a cave, put a useful URL here. ' )
except Cave . MultipleObjectsReturned :
complaints . append ( f ' The cave ID \' { waldata [ " cave " ] } \' is AMBIGUOUS. Please fix it. ' )
caveobject = None
except ObjectDoesNotExist :
complaints . append ( f ' The cave ID \' { waldata [ " cave " ] } \' is not recognised. Please fix it. ' )
caveobject = None
else :
2022-08-01 15:32:35 +01:00
complaints . append ( f ' No cave ID is given. Please give some text, even if it is just " surface survey " or " scraps found in hut " ' )
2022-07-17 13:01:53 +01:00
caveobject = None
2022-07-17 13:22:26 +01:00
2022-07-17 13:01:53 +01:00
return complaints , caveobject
2022-03-24 20:45:15 +00:00
# @login_required_if_public
2022-03-18 11:28:35 +00:00
def scanupload ( request , path = None ) :
2021-05-05 00:35:10 +01:00
''' Upload scanned image files into a wallet on /expofiles
2022-03-17 00:41:29 +00:00
Also display and edit the contents . json data in the wallet .
2021-05-05 00:35:10 +01:00
This does NOT use a Django model linked to a Django form . Just a simple Django form .
2022-03-08 22:59:04 +00:00
You will find the Django documentation on forms very confusing , This is simpler .
2022-07-17 13:01:53 +01:00
This subsumes much of the code which was in the old wallets . py script and so this function is very long
indeed and needs refactoring .
2022-08-01 15:32:35 +01:00
REWRITE bits using the ticklist , dateify , caveify , populate etc utility functions in core . view . scans . py
2021-05-05 00:35:10 +01:00
'''
filesaved = False
actual_saved = [ ]
2022-03-17 00:41:29 +00:00
checkboxes = [ " description written " , " survex not required " , " qms written " , " website updated " ,
" plan not required " , " plan drawn " , " elev not required " , " elev drawn " , " electronic survey " ]
2022-03-18 11:28:35 +00:00
if path :
wallet = urllib . parse . unquote ( path )
else :
wallet = " 2022#01 " # improve this later
2022-03-17 00:41:29 +00:00
2021-05-05 00:35:10 +01:00
year = wallet [ : 4 ]
2022-07-23 18:05:58 +01:00
try :
if int ( year ) < = 1998 :
#print(f'! - FORM scanupload - start {wallet} REDIRECT TO OLDWALLET')
return ( oldwallet ( request , path ) )
except :
# if nonumeric wallet name for example
2022-03-18 11:28:35 +00:00
return ( oldwallet ( request , path ) )
2022-07-23 18:05:58 +01:00
2022-03-18 12:26:32 +00:00
if str ( wallet ) . lower ( ) . endswith ( ' indexpages ' ) :
2022-03-18 20:00:15 +00:00
# print(f'! - FORM scanupload - start {wallet} REDIRECT TO OLDWALLET')
2022-03-18 12:26:32 +00:00
return ( walletindex ( request , path ) )
2022-03-18 11:28:35 +00:00
if not re . match ( ' (19|20) \ d \ d[:#] \ d \ d ' , wallet ) :
wallet = " 2022:01 " # improve this later
2022-03-18 20:00:15 +00:00
# print(f'! - FORM scanupload - start {wallet}')
2022-03-18 11:28:35 +00:00
if path :
2022-03-18 20:00:15 +00:00
pass
# print(f'! - FORM scanupload - start wallet:{wallet}: path:{path}:')
2021-05-05 00:35:10 +01:00
if int ( year ) < 1977 :
year = " 1977 "
if int ( year ) > 2050 :
year = " 2050 "
nexty = f ' { int ( year ) + 1 } '
prevy = f ' { int ( year ) - 1 } '
2022-03-18 11:28:35 +00:00
2021-05-05 00:35:10 +01:00
wnumber = wallet [ 5 : ]
next = f ' { int ( wnumber ) + 1 : 02d } '
prev = f ' { int ( wnumber ) - 1 : 02d } '
if int ( wnumber ) == 0 :
prev = f ' { int ( wnumber ) : 02d } '
2022-03-15 20:53:55 +00:00
2022-03-29 15:31:25 +01:00
wurl = f " /scanupload/ { wallet } " . replace ( ' # ' , ' : ' )
2021-05-05 00:35:10 +01:00
wallet = wallet . replace ( ' : ' , ' # ' )
2022-04-18 20:48:49 +01:00
dirpath = Path ( settings . SCANS_ROOT , year , wallet )
2022-08-06 20:23:39 +01:00
#contents_path = dirpath / contentsjson
contents_path = Path ( settings . DRAWINGS_DATA , " walletjson " ) / year / wallet / contentsjson
2021-05-05 00:35:10 +01:00
form = FilesForm ( )
2022-03-13 01:01:00 +00:00
2021-05-05 00:35:10 +01:00
if request . method == ' POST ' :
2022-03-17 00:41:29 +00:00
if " psg " in request . POST :
formj = WalletForm ( request . POST )
# Beware. All fields returned as strings. Must re-type them as lists etc. before using or re-saving
# Also lots of hassle with lists of strings interpreted as a single string
# Unset checkboxes do not return any value, checked ones return "True". So need initialising to False
if formj . is_valid ( ) :
#print(f'--- JSON Update form is VALID, saving to {contents_path}')
posted = request . POST . copy ( )
posted . pop ( " csrfmiddlewaretoken " ) # discard this
wd = wallet_blank_json
for f in checkboxes :
wd [ f ] = False
#print(f'--- wd ${f}$ - {wd[f]}')
for f in posted :
wd [ xlate [ f ] ] = posted [ f ] . replace ( " \' " , " \" " )
if posted [ f ] == " True " :
wd [ xlate [ f ] ] = True
wd [ " people " ] = wd [ " people " ] [ 1 : - 1 ] . replace ( " \" " , " " ) . split ( " , " )
for i , elem in enumerate ( wd [ " people " ] ) :
wd [ " people " ] [ i ] = elem . strip ( )
#print(f'--- ${wd["survex file"]}$ - {type(wd["survex file"])}')
2022-03-18 12:55:08 +00:00
if wd [ " survex file " ] : # allow for no survex file at all
if wd [ " survex file " ] [ 0 ] == ' [ ' :
wd [ " survex file " ] = wd [ " survex file " ] [ 1 : - 1 ]
wd [ " survex file " ] = wd [ " survex file " ] . replace ( " \" " , " " ) . split ( " , " )
for i , elem in enumerate ( wd [ " survex file " ] ) :
wd [ " survex file " ] [ i ] = elem . strip ( )
#print(f'--- {wd["survex file"]} - {type(wd["survex file"])}')
2022-03-17 00:41:29 +00:00
with open ( contents_path , " w " ) as jfile :
json . dump ( wd , jfile , indent = 1 )
# print(f'--- FINISHED saving to JSON\n')
2022-07-28 16:36:40 +01:00
# This copies the new data to the drawings repo and commit it
# needs the troggle object wallet, not a string
try :
w , created = Wallet . objects . get_or_create ( walletname = wallet )
print ( f ' wallet string { wallet } , wallet object { w } created new?: { created } ' )
if created :
w . fpath = Path ( settings . SCANS_ROOT , wallet [ 0 : 4 ] , wallet )
w . save ( )
CopyWalletData ( w )
except :
print ( f ' wallet string { wallet } , FAIL TO GET WALLET OBJECT, maybe we need to create it ? ' )
raise
2022-03-17 00:41:29 +00:00
else :
print ( f ' --- INVALID JSON Update form submitted ' )
print ( formj . errors )
return render ( request , ' errors/generic.html ' , { ' message ' : formj . errors } )
else :
form = FilesForm ( request . POST , request . FILES )
if form . is_valid ( ) :
f = request . FILES [ " uploadfiles " ]
multiple = request . FILES . getlist ( ' uploadfiles ' )
fs = FileSystemStorage ( os . path . join ( dirpath ) ) # creates wallet folder if necessary
actual_saved = [ ]
if multiple :
for f in multiple :
2022-04-06 18:43:26 +01:00
try : # crashes in Django os.chmod call if on WSL, but does save file!
saved_filename = fs . save ( f . name , content = f )
except :
print ( f ' \n !! Permissions failure ?! on attempting to save file { f . name } ' )
if ' saved_filename ' in locals ( ) :
if saved_filename . is_file ( ) :
actual_saved . append ( saved_filename )
# print(f'! - FORM scanupload multiple {actual_saved}')
filesaved = True
2022-03-17 00:41:29 +00:00
if not contents_path . is_file ( ) : # double-check
with open ( contents_path , " w " ) as json_file :
json . dump ( wallet_blank_json , json_file , sort_keys = True , indent = 1 )
index_path = dirpath / indexhtml
if not index_path . is_file ( ) : # double-check
thishtml = wallet_blank_html . replace ( " YEAR " , str ( year ) )
thishtml = thishtml . replace ( " WALLET " , str ( wallet ) )
with open ( index_path , " w " ) as html_file :
html_file . write ( thishtml )
2021-05-05 00:35:10 +01:00
files = [ ]
dirs = [ ]
# print(f'! - FORM scanupload - start {wallet} {dirpath}')
2022-03-15 17:04:43 +00:00
if dirpath . is_dir ( ) :
create = False
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. It would be created if you upload a scan) ' )
2021-05-05 00:35:10 +01:00
else :
2022-03-15 17:04:43 +00:00
create = True
if len ( files ) > 0 :
2021-05-05 00:35:10 +01:00
files = sorted ( files )
if dirs :
dirs = sorted ( dirs )
2022-03-15 19:15:45 +00:00
2022-03-15 23:00:23 +00:00
waldata = { }
2022-03-15 19:15:45 +00:00
if contents_path . is_file ( ) :
with open ( contents_path ) as json_file :
try :
waldata = json . load ( json_file )
except :
2022-03-15 23:00:23 +00:00
message = f " ! { wallet } Failed to load { contents_path } JSON file "
2022-03-15 19:15:45 +00:00
print ( message )
2022-03-15 20:53:55 +00:00
DataIssue . objects . create ( parser = ' scans ' , message = message , url = wurl ) # set URL to this wallet folder
2022-03-15 19:15:45 +00:00
raise
2022-03-15 20:53:55 +00:00
cave = " "
psg = " "
2022-03-17 00:41:29 +00:00
chkplannr = " "
chkpland = " "
svxfiles = [ ]
checked = { }
2022-03-15 23:00:23 +00:00
if waldata :
if not waldata [ " people " ] :
waldata [ " people " ] = [ " NOBODY " ]
2022-03-17 00:41:29 +00:00
if not type ( waldata [ " people " ] ) == list :
if waldata [ " people " ] [ 0 ] == ' " ' :
waldata [ " people " ] = waldata [ " people " ] [ 1 : - 1 ]
waldata [ " people " ] = list ( waldata [ " people " ] )
if not waldata [ " description url " ] :
waldata [ " description url " ] = " "
2022-03-15 23:00:23 +00:00
if waldata [ " cave " ] :
2022-07-17 13:01:53 +01:00
cave = waldata [ " cave " ] # text string
2022-03-15 23:00:23 +00:00
if waldata [ " name " ] :
psg = waldata [ " name " ]
2022-03-17 00:41:29 +00:00
2022-07-17 13:01:53 +01:00
#Survex and survex complaints
2022-07-21 07:40:35 +01:00
complaints , caveobject = get_complaints ( [ ] , waldata , svxfiles , files , wallet , wurl )
2022-03-15 23:00:23 +00:00
2022-07-17 13:01:53 +01:00
2022-03-17 00:41:29 +00:00
for f in checkboxes :
if waldata [ f ] :
checked [ f ] = " checked "
2022-07-17 13:01:53 +01:00
2022-03-17 00:41:29 +00:00
context = { ' year ' : year , ' prev ' : prev , ' next ' : next , ' prevy ' : prevy , ' nexty ' : nexty ,
' files ' : files , ' dirs ' : dirs , ' waldata ' : waldata , ' svxfiles ' : svxfiles ,
' checked ' : checked ,
' create ' : create ,
2022-07-17 13:01:53 +01:00
' complaints ' : complaints ,
' caveobject ' : caveobject ,
2022-03-17 00:41:29 +00:00
' people ' : waldata [ " people " ] , ' peoplesize ' : str ( len ( str ( waldata [ " people " ] ) ) ) ,
2022-03-15 19:15:45 +00:00
' filesaved ' : filesaved , ' actual_saved ' : actual_saved }
2021-05-05 00:35:10 +01:00
2022-07-17 13:01:53 +01:00
return render ( request , ' walletform.html ' ,
2022-03-17 00:41:29 +00:00
{ ' form ' : form , ' wallet ' : wallet , * * context ,
' date ' : waldata [ " date " ] ,
' url ' : waldata [ " description url " ] , ' urlsize ' : str ( len ( str ( waldata [ " description url " ] ) ) ) ,
' survex ' : waldata [ " survex file " ] , ' survexsize ' : str ( len ( str ( waldata [ " survex file " ] ) ) ) ,
' cave ' : cave , ' psg ' : psg , ' psgsize ' : str ( max ( 12 , len ( str ( psg ) ) ) ) } )
else : # no wallet here
context = { ' year ' : year , ' prev ' : prev , ' next ' : next , ' prevy ' : prevy , ' nexty ' : nexty ,
' files ' : files , ' dirs ' : dirs , ' waldata ' : waldata , ' svxfiles ' : svxfiles ,
' checked ' : checked ,
' create ' : create ,
' people ' : " " , ' peoplesize ' : 12 ,
' filesaved ' : filesaved , ' actual_saved ' : actual_saved }
2022-07-17 13:01:53 +01:00
return render ( request , ' walletform.html ' ,
2022-03-17 00:41:29 +00:00
{ ' form ' : form , ' wallet ' : wallet , * * context ,
' date ' : " " ,
' url ' : " " , ' urlsize ' : 12 ,
' survex ' : " " , ' survexsize ' : 12 ,
' cave ' : cave , ' psg ' : psg , ' psgsize ' : 12 } )
2021-05-05 00:35:10 +01:00
2022-03-13 01:01:00 +00:00
@login_required_if_public
def photoupload ( request , folder = None ) :
''' Upload photo image files into /expofiles/photos/<year>/<photographer>/
This does NOT use a Django model linked to a Django form . Just a simple Django form .
You will find the Django documentation on forms very confusing , This is simpler .
2022-08-11 19:19:52 +01:00
When uploading from a phone , it is useful to be able to rename the file to something
meaningful as this is difficult to do on a phone . Previously we had assumed files would
be renamed to something useful before starting the upload .
Unfortunately this only works when uploading one file at at time ,
inevitable once you think about it .
2022-03-13 01:01:00 +00:00
'''
year = settings . PHOTOS_YEAR
filesaved = False
actual_saved = [ ]
context = { ' year ' : year , ' placeholder ' : " AnathemaDevice " }
yearpath = Path ( settings . PHOTOS_ROOT , year )
if folder == str ( year ) or folder == str ( year ) + " / " :
folder = None
if folder is None :
folder = " " # improve this later
dirpath = Path ( settings . PHOTOS_ROOT , year )
urlfile = f ' /expofiles/photos/ { year } '
urldir = f ' /photoupload/ { year } '
else : # it will contain the year as well as the photographer
dirpath = Path ( settings . PHOTOS_ROOT , folder )
if dirpath . is_dir ( ) :
urlfile = f ' /expofiles/photos/ { folder } '
urldir = Path ( ' /photoupload ' ) / folder
else :
folder = " " # improve this later
dirpath = Path ( settings . PHOTOS_ROOT , year )
urlfile = f ' /expofiles/photos/ { year } '
urldir = f ' /photoupload/ { year } '
2022-08-11 19:19:52 +01:00
form = FilesRenameForm ( )
2022-03-13 01:01:00 +00:00
formd = TextForm ( )
if request . method == ' POST ' :
if " photographer " in request . POST :
formd = TextForm ( request . POST )
if formd . is_valid ( ) :
newphotographer = request . POST [ " photographer " ]
( yearpath / newphotographer ) . mkdir ( exist_ok = True )
else :
2022-08-11 19:19:52 +01:00
form = FilesRenameForm ( request . POST , request . FILES )
2022-03-13 01:01:00 +00:00
if form . is_valid ( ) :
f = request . FILES [ " uploadfiles " ]
multiple = request . FILES . getlist ( ' uploadfiles ' )
2022-03-15 23:00:23 +00:00
# NO CHECK that the files being uploaded are image files
2022-03-13 01:01:00 +00:00
fs = FileSystemStorage ( dirpath )
2022-08-11 19:19:52 +01:00
renameto = request . POST [ " renameto " ]
2022-03-13 01:01:00 +00:00
actual_saved = [ ]
2022-08-11 21:35:53 +01:00
if multiple :
2022-08-11 19:19:52 +01:00
if len ( multiple ) == 1 :
2022-08-11 21:35:53 +01:00
if renameto != " " :
try : # crashes in Django os.chmod call if on WSL, but does save file!
saved_filename = fs . save ( renameto , content = f )
except :
print ( f ' \n !! Permissions failure ?! on attempting to save file { f . name } ' )
if ' saved_filename ' in locals ( ) :
if saved_filename . is_file ( ) :
actual_saved . append ( saved_filename )
filesaved = True
else : # multiple is the uploaded content
try : # crashes in Django os.chmod call if on WSL, but does save file!
saved_filename = fs . save ( f . name , content = f )
except :
print ( f ' \n !! Permissions failure ?! on attempting to save file { f . name } ' )
if ' saved_filename ' in locals ( ) :
if saved_filename . is_file ( ) :
actual_saved . append ( saved_filename )
filesaved = True
else : # multiole is a list of content
2022-08-11 19:19:52 +01:00
for f in multiple :
try : # crashes in Django os.chmod call if on WSL, but does save file!
saved_filename = fs . save ( f . name , content = f )
except :
print ( f ' \n !! Permissions failure ?! on attempting to save file { f . name } ' )
if ' saved_filename ' in locals ( ) :
if saved_filename . is_file ( ) :
actual_saved . append ( saved_filename )
filesaved = True
2022-03-13 01:01:00 +00:00
files = [ ]
dirs = [ ]
try :
for f in dirpath . iterdir ( ) :
if f . is_dir ( ) :
dirs . append ( f . name )
if f . is_file ( ) :
files . append ( f . name )
except FileNotFoundError :
files . append ( ' (no folder yet - would be created) ' )
if len ( files ) > 0 :
files = sorted ( files )
if dirs :
dirs = sorted ( dirs )
return render ( request , ' photouploadform.html ' ,
{ ' form ' : form , * * context , ' urlfile ' : urlfile , ' urldir ' : urldir , ' folder ' : folder , ' files ' : files , ' dirs ' : dirs , ' filesaved ' : filesaved , ' actual_saved ' : actual_saved } )
2021-05-05 00:35:10 +01:00
@login_required_if_public
2021-10-31 17:25:45 +00:00
def dwgupload ( request , folder = None , gitdisable = ' no ' ) :
2022-03-08 22:59:04 +00:00
''' Upload DRAWING files (tunnel or therion) into the upload folder in :drawings
AND registers it into the : drawings : git repo .
2021-05-05 00:35:10 +01:00
This does NOT use a Django model linked to a Django form . Just a simple Django form .
2022-03-08 22:59:04 +00:00
You will find the Django documentation on forms very confusing , This is simpler .
2022-08-11 19:19:52 +01:00
We could validate the uploaded files as being a valid files using an XML parser , not a dubious script or hack
2022-03-08 22:59:04 +00:00
2021-05-05 00:35:10 +01:00
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
2022-03-05 20:29:01 +00:00
the actual file will be duplicated in the filesystem with different random name ending .
2021-05-05 00:35:10 +01:00
'''
def dwgvalid ( name ) :
2022-03-05 20:29:01 +00:00
if name in [ ' .gitignore ' , ] :
2021-05-05 00:35:10 +01:00
return False
2022-03-05 22:16:03 +00:00
if Path ( name ) . suffix . lower ( ) in [ ' .xml ' , ' .th ' , ' .th2 ' , ' ' , ' .svg ' , ' .txt ' ] :
2021-10-31 17:25:45 +00:00
return True # dangerous, we should check the actual file binary signature
2021-05-05 00:35:10 +01:00
return False
2022-03-05 22:16:03 +00:00
def dwgvaliddisp ( name ) :
''' OK to display, even if we are not going to allow a new one to be uploaded
'''
if name in [ ' .gitignore ' , ] :
return False
2022-03-15 23:00:23 +00:00
if Path ( name ) . suffix . lower ( ) in [ ' .xml ' , ' .th ' , ' .th2 ' , ' ' , ' .svg ' , ' .txt ' , ' .jpg ' , ' .jpeg ' , ' .png ' , ' .pdf ' , ' .top ' , ' .topo ' ] :
2022-03-05 22:16:03 +00:00
return True # dangerous, we should check the actual file binary signature
return False
2021-05-05 00:35:10 +01:00
filesaved = False
actual_saved = [ ]
refused = [ ]
doesnotexist = ' '
2021-10-31 17:25:45 +00:00
# print(f'! - FORM dwgupload - start "{folder}" - gitdisable "{gitdisable}"')
2021-05-05 00:35:10 +01:00
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 = [ ]
2022-03-05 17:05:15 +00:00
# GIT see also core/views/expo.py editexpopage()
# GIT see also core/models/cave.py writetrogglefile()
2021-10-31 17:25:45 +00:00
if gitdisable != ' yes ' : # set in url 'dwguploadnogit/'
git = settings . GIT
else :
git = ' echo '
2021-05-05 00:35:10 +01:00
if multiple :
for f in multiple :
if dwgvalid ( f . name ) :
2022-04-20 21:18:05 +01:00
try : # crashes in Django os.chmod call if on WSL without metadata drvfs, but does save file!
2022-04-06 18:43:26 +01:00
saved_filename = fs . save ( f . name , content = f )
except :
print ( f ' \n !! Permissions failure ?! on attempting to save file { f . name } ' )
if ' saved_filename ' in locals ( ) :
if saved_filename . is_file ( ) :
actual_saved . append ( saved_filename )
if gitdisable != ' yes ' :
dr_add = subprocess . run ( [ git , " add " , saved_filename ] , cwd = dirpath , capture_output = True , text = True )
if dr_add . returncode != 0 :
msgdata = ' Ask a nerd to fix this. \n \n ' + dr_add . stderr + ' \n \n ' + dr_add . stdout + ' \n \n return code: ' + str ( dr_add . returncode )
message = f ' CANNOT git on server for this file { saved_filename } . Edits saved but not added to git. \n \n ' + msgdata
return render ( request , ' errors/generic.html ' , { ' message ' : message } )
dwgfile , created = DrawingFile . objects . get_or_create ( dwgpath = saved_filename , dwgname = Path ( f . name ) . stem , filesize = f . size )
dwgfile . save ( )
2021-05-05 00:35:10 +01:00
else :
refused . append ( f . name )
2022-03-05 20:29:01 +00:00
print ( f ' REFUSED { f . name } ' )
2021-10-31 17:25:45 +00:00
if actual_saved : # maybe all were refused by the suffix test in dwgvalid()
filesaved = True
2022-03-05 22:16:03 +00:00
if len ( actual_saved ) > 1 :
dots = " ... "
else :
dots = " "
2021-10-31 17:25:45 +00:00
if gitdisable != ' yes ' :
2022-03-05 22:16:03 +00:00
dr_commit = subprocess . run ( [ git , " commit " , " -m " , f ' Drawings upload - { actual_saved [ 0 ] } { dots } ' ] , cwd = dirpath , capture_output = True , text = True )
# This produces return code = 1 if it commits OK
if dr_commit . returncode != 0 :
msgdata = ' Ask a nerd to fix this. \n \n ' + dr_commit . stderr + ' \n \n ' + dr_commit . stdout + ' \n \n return code: ' + str ( dr_commit . returncode )
message = f ' Error code with git on server for this { actual_saved [ 0 ] } { dots } . Edits saved, added to git, but NOT committed. \n \n ' + msgdata
return render ( request , ' errors/generic.html ' , { ' message ' : message } )
2021-10-31 17:25:45 +00:00
2021-05-05 00:35:10 +01:00
files = [ ]
dirs = [ ]
2021-10-31 17:25:45 +00:00
# print(f'! - FORM dwgupload - start {folder} \n"{dirpath}" \n"{dirpath.parent}" \n"{dirpath.exists()}"')
2021-05-05 00:35:10 +01:00
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 ( ) :
2022-03-05 22:16:03 +00:00
if dwgvaliddisp ( f . name ) :
2021-05-05 00:35:10 +01:00
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 } )