2023-01-31 17:13:41 +00:00
import datetime
import json
import os
import re
import socket
import subprocess
import urllib
from pathlib import Path
from django import forms
from django . core . exceptions import MultipleObjectsReturned , ObjectDoesNotExist
from django . core . files . storage import FileSystemStorage
from django . http import HttpResponseRedirect
from django . shortcuts import render
import settings
from troggle . core . models . caves import Cave
from troggle . core . models . logbooks import LogbookEntry # , PersonLogEntry
from troggle . core . models . survex import SurvexBlock , SurvexFile , SurvexPersonRole
from troggle . core . models . troggle import DataIssue , Expedition
2024-12-15 18:54:47 +00:00
from troggle . core . models . wallets import YEAR_RANGE , Wallet , make_valid_date
from troggle . core . utils import current_expo , sanitize_name
2023-03-22 15:18:16 +00:00
from troggle . core . views . auth import login_required_if_public
2024-12-15 18:54:47 +00:00
from troggle . core . views . caves import get_cave_leniently , getCave
2023-01-31 17:13:41 +00:00
from troggle . core . views . scans import caveifywallet , oldwallet
from troggle . core . views . uploads import FilesForm
from troggle . parsers . scans import contentsjson
2023-01-31 20:28:39 +00:00
""" Main wallet editing form, which includes scan file upload into the wallet
2023-01-31 17:13:41 +00:00
"""
todo = """
2023-07-23 21:30:19 +01:00
- Nasty bug in navigating to ' previous wallet ' when we have a 2 - year gap in expos
2023-02-02 21:50:40 +00:00
The xxxx #00 wallet is not getting edited correctly. Something is off by one somewhere..
2023-01-31 17:13:41 +00:00
- Register uploaded filenames in the Django db without needing to wait for a reset & bulk file import
2023-02-02 21:50:40 +00:00
- Refactor walletedit ( ) as it contains all the wallets ' complaints ' code from the pre - 2022
script ' wallets.py '
2023-01-31 17:13:41 +00:00
2023-03-22 15:18:16 +00:00
- We should validate uploaded file as being a valid image file , not a dubious script or hack ?
2023-01-31 17:13:41 +00:00
"""
WALLET_BLANK_JSON = {
" cave " : " " ,
" date " : " " ,
" free text " : " " ,
# "description url": "1623/NNN",
" description written " : False ,
" electronic survey " : False ,
" elev drawn " : False ,
" elev not required " : False ,
" name " : " " ,
" people " : [ " Unknown " ] ,
" plan drawn " : False ,
" plan not required " : False ,
2023-02-02 17:39:56 +00:00
" notes not required " : False ,
2023-01-31 17:13:41 +00:00
" qms written " : False ,
" survex file " : [ ] ,
" survex not required " : False ,
" website updated " : False ,
}
class WalletGotoForm ( forms . Form ) : # not a model-form, just a form-form
walletgoto = forms . CharField ( strip = True , required = False )
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 )
freetext = forms . CharField ( strip = True , required = False )
plannr = forms . CharField ( strip = True , required = False )
2023-02-02 17:39:56 +00:00
notesnr = forms . CharField ( strip = True , required = False )
2023-01-31 17:13:41 +00:00
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 " ,
2023-02-02 17:39:56 +00:00
" notesnr " : " notes not required " ,
2023-01-31 17:13:41 +00:00
" survexnr " : " survex not required " ,
" qmsw " : " qms written " ,
" elevnr " : " elev not required " ,
" websiteupt " : " website updated " ,
" electronic " : " electronic survey " ,
" pland " : " plan drawn " ,
" elevd " : " elev drawn " ,
" psg " : " name " , # a name for this wallet
" freetext " : " free text " ,
" survex " : " survex file " ,
}
2023-10-21 14:22:20 +01:00
2023-01-31 17:13:41 +00:00
def get_complaints ( complaints , waldata , svxfiles , files , wallet , wurl ) :
""" Taken from old script wallets.py and edited to make more comprehensible
Loads the survex files names and processes all complaints
"""
# If skipping through the wallets on the upload form, the wallet may not yet exist
try :
w = Wallet . objects . get ( walletname = wallet )
except ObjectDoesNotExist :
return None , None
# 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 (
not waldata [ " people " ]
or waldata [ " people " ] == [ " NOBODY " ]
or waldata [ " people " ] == [ " Unknown " ]
or waldata [ " people " ] == [ " " ]
) :
complaints . append (
2023-02-01 19:10:46 +00:00
" Somebody must have done this. Look in the survex file, or in the logbook entries for this date, for the people who created this data. "
2023-01-31 17:13:41 +00:00
)
# survex, but get_ticks has already done much of this ??
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 sx in waldata [ " survex file " ] :
# this logic appears in several places, inc get_ticks(). Refactor.
if sx != " " :
if Path ( sx ) . suffix . lower ( ) != " .svx " :
sx = sx + " .svx "
svxfiles . append ( sx )
if not ( Path ( settings . SURVEX_DATA ) / sx ) . is_file ( ) :
file_complaint = f " { wallet } Incorrect survex file name. File { sx } was not found in LOSER repo "
complaints . append ( file_complaint )
message = f " ! { file_complaint } "
print ( message )
DataIssue . objects . update_or_create (
2023-10-23 00:32:44 +01:00
parser = " wallets " , message = message , url = wurl
2023-01-31 17:13:41 +00:00
) # set URL to this wallet folder
else :
try :
sxpath = str ( Path ( sx ) . with_suffix ( " " ) )
SurvexFile . objects . get ( path = sxpath )
except MultipleObjectsReturned :
# can happen if connecting a wallet to a survex file.. i think..
QSsvxfiles = SurvexFile . objects . filter ( path = sxpath )
2023-10-23 00:32:44 +01:00
message = f " ! { wallet } Urk, multiple SurvexFile objects { sxpath } "
DataIssue . objects . update_or_create (
parser = " wallets " , message = message , url = wurl
) # set URL to this wallet folder
2023-01-31 17:13:41 +00:00
for s in QSsvxfiles :
2023-09-06 20:58:14 +01:00
print ( s . path , s . cave , s . primary )
2023-01-31 17:13:41 +00:00
# QSsvxfiles[0] # dont' know how this happened, fix later..
except :
file_complaint = (
f " { wallet } Survex file { sx } exists, but is not registered in the database { sxpath } . How?.. "
)
complaints . append ( file_complaint )
message = f " ! { file_complaint } "
print ( message )
DataIssue . objects . update_or_create (
2023-10-23 00:32:44 +01:00
parser = " wallets " , message = message , url = wurl
2023-01-31 17:13:41 +00:00
) # set URL to this wallet folder
if waldata [ " survex not required " ] and waldata [ " survex file " ] != [ " " ] :
survex_complaint = (
f ' Survex is stated as not required and yet there is a survex file! ( { waldata [ " 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 )
ticks = w . get_ticks ( )
# Notes required
if ticks [ " N " ] != " green " :
complaints . append (
2023-07-29 16:21:07 +01:00
" The notes needs scanning (or renaming) or tick ' Notes not required ' checkbox. No noteNN.jpg or XXnote.jpg file was found. Needed even for an electronic survey. "
2023-01-31 17:13:41 +00:00
)
# Plan drawing required
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. "
)
# Elev drawing required
if ticks [ " E " ] != " green " :
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. "
)
2023-02-02 17:39:56 +00:00
# Therion
2023-01-31 17:13:41 +00:00
if ticks [ " T " ] != " green " :
complaints . append (
2023-07-29 16:21:07 +01:00
" Tunnel or Therion drawing files need drawing, or tick ' Plan/Elev drawn ' checkbox or ' Plan/Elev not required ' checkboxes "
2023-01-31 17:13:41 +00: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 " ] and w . year ( ) and int ( w . year ( ) ) > = 2015 :
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 (
2024-08-11 15:01:41 +01:00
" The cave description webpage is marked as needing updating using the guidebook description from the survex file. Tick the ' Cave Description wepage updated ' checkbox when this is done. "
2023-01-31 17:13:41 +00:00
)
# Find the cave, if it exists
2023-10-21 14:22:20 +01:00
# Just for wallets, we are lenient about whether the 1623- prefix has been written down.
2023-01-31 17:13:41 +00:00
if waldata [ " cave " ] :
2023-10-21 14:22:20 +01:00
caveobject = None
2023-01-31 17:13:41 +00:00
try :
caveid = waldata [ " cave " ]
if type ( caveid ) is list :
for i in caveid :
i = i . replace ( " / " , " - " )
2023-10-21 14:22:20 +01:00
caveobject = get_cave_leniently ( i )
w . caves . add ( caveobject ) # new many-to-many field
#print(w.caves)
2023-01-31 17:13:41 +00:00
else :
2023-10-21 20:31:33 +01:00
# either single cave or the square brackets have been removed
2023-10-21 14:22:20 +01:00
ids = caveid . split ( " , " )
for i in ids :
j = i . replace ( " ' " , " " ) . strip ( ' [] " ' )
#print(j)
try :
caveobject = get_cave_leniently ( j ) # may fail if garbage value ,e.g. space, in wallet data
w . caves . add ( caveobject )
except :
pass
2023-01-31 17:13:41 +00:00
# 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 :
complaints . append (
' No cave ID is given. If there is no survex file, please give something, even if it is just " 1623-000 " , " surface survey " or " scraps found in hut " '
)
caveobject = None
return complaints , caveobject
2023-03-22 15:04:34 +00:00
@login_required_if_public
2023-01-31 17:13:41 +00:00
def walletedit ( request , path = None ) :
2023-02-01 17:21:33 +00:00
""" Create a new wallet or upload scanned image files into a wallet on /expofiles
2023-01-31 17:13:41 +00:00
Also display AND EDIT the contents . json data in the wallet .
This is the main wallet display and edit page .
The Wallet object and the contents . json file are created when the user
2023-02-01 17:21:33 +00:00
creates the wallet AND THEN SAVES IT WITH A DATE .
2023-01-31 17:13:41 +00:00
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 ,
2023-09-14 11:40:33 +01:00
as it covers many very different things we do not need . This is simpler ,
or at least , it is all in one place and you can see what it does , inctead of using invisible
Django defaults that a newcomer can ' t find.
2023-07-31 13:49:54 +01:00
( See also view / uploads . py for other simpler forms , as opposed to core / forms . py
which contains a couple of Django class - based forms . )
2023-01-31 17:13:41 +00:00
2023-02-01 17:21:33 +00:00
This subsumes much of the code which was in the pre - 2022 non - troggle wallets . py script
and so this function is very long indeed and needs refactoring .
2023-07-31 13:49:54 +01:00
Much of the logic used here lives in the Class functions for Wallet .
2023-01-31 17:13:41 +00:00
REWRITE bits using the ticklist , dateify , caveify , populate etc utility functions in core . view . scans . py
"""
git = settings . GIT
filesaved = False
actual_saved = [ ]
2023-01-31 20:28:39 +00:00
2024-08-04 08:39:18 +01:00
def no_surveyscans ( year , next ) :
""" Detect if a folder of scans exists, even if no wallet Object has been created
"""
id = f " { year } # { next : 02d } "
dirpath = Path ( settings . SCANS_ROOT , year , id )
if not dirpath . is_dir ( ) :
return True
# if the folder exists, but has nothing in it, we treat it as available
if len ( os . listdir ( dirpath ) ) == 0 :
return True
else :
return False
2023-01-31 20:28:39 +00:00
def get_next_empty ( ) :
2023-02-01 19:31:29 +00:00
""" Gets the next most number for a new wallet just after the most recent one in the
2024-08-04 08:39:18 +01:00
db . But if it has no date set , then ignore it as it was only just created - is this a race condition ?
This assumes we are still in the same year as the most recent wallet .
2024-03-14 23:59:39 +00:00
2024-08-04 08:39:18 +01:00
This just looks at the wallets in the db initially , then
checks the sub folders ofexpofiles / surveyscans / [ year ] /
2024-03-14 23:59:39 +00:00
"""
latest = Wallet . objects . filter ( walletname__startswith = " 20 " , walletdate__isnull = False ) . latest ( ' walletname ' ) # last VALID wallet
2024-08-04 08:39:18 +01:00
# print(f"==latest wallet number is {latest}")
2023-01-31 20:28:39 +00:00
next = int ( latest . walletname [ 5 : ] ) + 1
2024-08-04 08:39:18 +01:00
year = latest . walletname [ : 4 ]
id = f " { year } : { next : 02d } "
if no_surveyscans ( year , next ) :
# print(f"==No scanned files found for {year=} # {next=}")
return id
else :
walletname = id . replace ( ' : ' , ' # ' )
# print(f"==making wallet {walletname}")
make_wallet ( walletname , date = True )
return get_next_empty ( ) # recursive call
2024-03-14 23:59:39 +00:00
def get_last_wallet ( ) :
last = Wallet . objects . all ( ) . order_by ( ' walletyear ' ) . last ( )
2024-08-04 08:39:18 +01:00
# print(f"==last wallet updated {last}")
2024-03-14 23:59:39 +00:00
return last
def are_we_next_year ( ) :
recent_wallet = get_last_wallet ( )
recent_year = recent_wallet . walletname [ : 4 ]
current_year = current_expo ( )
return int ( current_year ) > int ( recent_year )
2023-01-31 20:28:39 +00:00
def preprocess_path ( path ) :
if path :
wpath = urllib . parse . unquote ( path )
else :
2024-03-14 23:59:39 +00:00
# OK the url is "empty". Now we decide if we want to start the next year.
if are_we_next_year ( ) :
new_walletname = current_expo ( ) + " #00 "
# print(f"{new_walletname}")
make_wallet ( new_walletname , date = True )
nx = get_next_empty ( )
# print(nx)
return ( None , nx )
2023-01-31 20:28:39 +00:00
try :
year = wpath [ : 4 ] # if path too short, exception catches it
sepr = wpath [ 4 ]
y = int ( year ) # exception catches non-integer [:4]
wnumber = int ( wpath [ 5 : ] ) # exception catches nonumeric wallet number
if sepr != " # " and sepr != " : " :
return ( oldwallet ( request , path ) , None )
except :
# if nonumeric wpath name for example
return ( oldwallet ( request , path ) , None )
2024-12-12 17:07:14 +00:00
if not re . match ( " (19|20)[0-9][0-9][:#] \ d { 2,3} " , wpath ) :
2023-01-31 20:28:39 +00:00
return ( None , get_next_empty ( ) )
2023-02-01 19:10:46 +00:00
ymin , ymax = YEAR_RANGE
if int ( year ) < ymin :
year = str ( ymin + 2 )
if int ( year ) > ymax :
2023-02-01 17:21:33 +00:00
return ( None , get_next_empty ( ) )
2023-01-31 20:28:39 +00:00
wallet = f " { year } : { wnumber : 02d } "
return ( None , wallet )
2023-02-03 17:13:29 +00:00
def identify_most_recent_wallet ( wallet , currentyear ) :
2023-02-01 21:31:07 +00:00
""" Need to find the last wallet of the previous year
Has to cope with years when there are no wallets
Has to cope with weirdly named imported wallets from 1999 & earlier
Has to cope if the ' current ' wallet is one that happens to ' not exist ' too .
Frankly this has just become too bizarre and we should devise a quite different
navigation system .
"""
current_name = wallet . replace ( " : " , " # " )
try :
2024-03-14 23:59:39 +00:00
recent_wallet = get_last_wallet ( )
allwallets = Wallet . objects . all ( ) . order_by ( ' walletyear ' )
2023-02-01 21:31:07 +00:00
for w in allwallets :
if len ( w . walletname ) < 5 :
continue
if w . walletname [ 4 ] != " # " :
2023-02-03 17:13:29 +00:00
continue
2023-02-01 21:31:07 +00:00
if w . walletname == current_name :
break
2023-02-03 17:13:29 +00:00
if int ( w . walletyear . year ) > = int ( currentyear ) :
2023-02-01 21:31:07 +00:00
break
2023-02-03 17:13:29 +00:00
recent_wallet = w
recent_name = recent_wallet . walletname
2023-02-01 21:31:07 +00:00
except :
raise
2023-02-03 17:13:29 +00:00
recent_year = recent_name [ : 4 ]
2024-03-14 23:59:39 +00:00
recent_number = recent_name [ 5 : ]
2023-02-01 21:31:07 +00:00
2024-08-04 08:39:18 +01:00
# print(f"---identify_most_recent_wallet: {recent_year=} {recent_number=}")
2023-02-03 17:13:29 +00:00
return recent_year , recent_number
2023-02-01 21:31:07 +00:00
2023-01-31 20:28:39 +00:00
def create_nav_links ( wallet ) :
2023-02-01 21:31:07 +00:00
""" Find the previous wallet and next wallet and create navigation shortcuts """
2024-03-14 23:59:39 +00:00
#xx, yy = identify_most_recent_wallet(wallet, y)
2023-01-31 20:28:39 +00:00
y = wallet [ : 4 ]
n = wallet [ 5 : ]
2023-02-01 21:31:07 +00:00
if int ( n ) == 0 :
2023-02-03 17:13:29 +00:00
recent_year , recent_number = identify_most_recent_wallet ( wallet , y )
prevy = recent_year # same as most recent wallet
recent_number = f " { int ( recent_number ) : 02d } "
else :
prevy = f " { int ( y ) - 1 } " # the previous year
recent_year = y # current year
recent_number = f " { int ( n ) - 1 : 02d } " # previous number
nexty = f " { int ( y ) + 1 } "
next = f " { int ( n ) + 1 : 02d } "
return prevy , recent_year , recent_number , y , next , nexty
2023-01-31 17:13:41 +00:00
2023-02-03 17:13:29 +00:00
def read_json ( contents_path ) :
2023-01-31 17:13:41 +00:00
""" Read JSON from the wallet metadata file in the repo
or fills with blank data if that files can ' t be read
Should sanitise to ensure no spurious backslashes e . g . in windows style paths """
waldata = { }
if contents_path . is_file ( ) :
with open ( contents_path ) as json_file :
try :
waldata = json . load ( json_file )
except :
message = f " ! { wallet } Failed to load { contents_path } JSON file "
print ( message )
DataIssue . objects . create ( parser = " scans " , message = message , url = wurl ) # set URL to this wallet folder
raise
else : # no JSON file exists
2023-02-01 21:31:07 +00:00
print ( " --- No JSON exists, so using default copy " )
2023-01-31 17:13:41 +00:00
waldata = WALLET_BLANK_JSON . copy ( )
if not waldata [ " survex file " ] :
try :
w = Wallet . objects . get ( walletname = wallet )
b = SurvexBlock . objects . filter ( scanswallet = w )
waldata [ " survex file " ] = [ ]
for bsf in b :
waldata [ " survex file " ] . append ( bsf . survexfile . path )
except :
print ( f " --- No wallet { wallet } exists in database " )
return waldata
def save_json ( jsondict ) :
# print(f'--- Wallet directory in :drawings: repo {newfolder=} {jsondict}')
if not os . path . exists ( contents_path . parent ) :
2023-03-22 17:57:48 +00:00
print ( f " --- No wallet directory in :drawings: repo, so creating it { contents_path . parent } " )
2023-01-31 17:13:41 +00:00
os . makedirs ( contents_path . parent )
with open ( contents_path , " w " ) as jfile :
json . dump ( jsondict , jfile , indent = 1 )
# print(f'--- FINISHED saving to JSON at {contents_path}')
2024-03-14 23:59:39 +00:00
def make_wallet ( walletname , date = False ) :
2023-03-22 15:04:34 +00:00
""" We need a wallet Object so that the django template stuff can find the files
BUT we must restrict this to logged - in users otherwise spiderbots get at
the hidden Submit button and create zillions of the buggers """
2024-08-04 08:39:18 +01:00
# print(f"== make_wallet() Making new wallet {walletname}")
2023-01-31 17:13:41 +00:00
try :
w , created = Wallet . objects . get_or_create ( walletname = walletname )
2024-08-04 08:39:18 +01:00
print ( f " --- Wallet string { walletname } , wallet object { w } created new?: { created } " )
2024-03-14 23:59:39 +00:00
if date :
w . walletdate = datetime . datetime . now ( )
2024-08-04 08:39:18 +01:00
w . save ( )
2023-01-31 17:13:41 +00:00
if created :
w . fpath = Path ( settings . SCANS_ROOT , walletname [ 0 : 4 ] , walletname )
2023-02-01 21:58:48 +00:00
_ = w . year ( ) # sets the walletyear property as a side-effect
2023-01-31 17:13:41 +00:00
w . save ( )
except :
print ( f " !-- Wallet string { walletname } , FAIL TO GET or create WALLET OBJECT " )
raise
return w
def commit_json ( waldata ) :
destfolder = contents_path . parent
dr_add = subprocess . run ( [ git , " add " , contentsjson ] , cwd = destfolder , capture_output = True , text = True )
if dr_add . returncode != 0 :
msgdata = (
" Ask a nerd to fix this. \n -- "
+ dr_add . stderr
+ " \n -- "
+ dr_add . stdout
+ " \n --return code: "
+ str ( dr_add . returncode )
)
message = (
f " CANNOT git on server for this file { contentsjson } . Edits saved but not added to git. \n \n " + msgdata
)
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
else :
2023-03-22 23:30:05 +00:00
2023-01-31 17:13:41 +00:00
if socket . gethostname ( ) != " expo " :
comment = f " on dev machine ' { socket . gethostname ( ) } ' "
else :
comment = " "
if " cave " in waldata :
label = waldata [ " cave " ]
else :
if " name " in waldata :
label = waldata [ " name " ]
else :
label = " "
dr_commit = subprocess . run (
[ git , " commit " , " -m " , f " JSON update wallet { wallet } { label } { comment } " ] ,
cwd = destfolder ,
capture_output = True ,
text = True ,
)
# This produces return code = 1 if it commits OK
if dr_commit . returncode != 0 :
msgdata = (
2023-03-22 23:30:05 +00:00
" Ask a nerd to fix this. \n \n stderr: "
2023-01-31 17:13:41 +00:00
+ dr_commit . stderr
2023-03-22 23:30:05 +00:00
+ " \n \n stdout: "
2023-01-31 17:13:41 +00:00
+ dr_commit . stdout
+ " \n \n return code: "
+ str ( dr_commit . returncode )
)
message = (
f " Error code with git on server for this { contentsjson } . File is added to git, but NOT committed. \n "
+ msgdata
)
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
def get_logbook_trips ( ) :
return None
2023-02-03 17:13:29 +00:00
def no_people ( team ) :
return ( team == [ " Unknown " ]
or team == [ " " ]
or team == " " )
2023-02-03 22:19:51 +00:00
def empty_string ( thing ) :
return ( thing == [ " " ]
or thing == [ ]
or thing == " "
or thing == " [] "
or thing is None )
2023-07-23 21:30:19 +01:00
2023-02-03 22:19:51 +00:00
2023-02-03 17:13:29 +00:00
def scan_survexblocks ( svxfile ) :
""" Scans for *team people attached to all the survex blocks in this svxfile
This could be rather a lot for some compedious survex files ! So would need
culling manually and only those relevant put in the JSON file """
wallet_refs = [ ]
dates = [ ]
blocknames = [ ]
team = [ ]
try :
blocks = SurvexBlock . objects . filter ( survexfile = svxfile )
for b in blocks :
2023-02-03 22:19:51 +00:00
# print(f" - - - - {b=} {b.scanswallet.walletname} {b.date=} ")
2023-02-03 17:13:29 +00:00
if b . scanswallet :
wallet_refs . append ( b . scanswallet ) # other wallets
2023-02-03 22:19:51 +00:00
#if b.scanswallet.walletname == wallet: # only if we assume *ref all correct!
if b . date :
dates . append ( b . date )
if b . name != b . title :
blocknames . append ( str ( b . name ) + " | " + str ( b . title ) )
else :
blocknames . append ( str ( b . name ) )
QSpeople = SurvexPersonRole . objects . filter ( survexblock = b )
# print(f" - - {QSpeople=}")
for p in QSpeople :
# print(f" - - {p.personname} ")
team . append ( p . personname )
2023-02-03 17:13:29 +00:00
except :
message = " - No associated survex blocks found for this wallet "
print ( message )
2023-02-03 22:19:51 +00:00
# print(f" - - - ", wallet_refs, dates, blocknames, team)
2023-02-03 17:13:29 +00:00
return wallet_refs , dates , blocknames , team
def scan_survexfiles ( survex_paths ) :
""" Read data from the list of survex file names attached to the wallet JSON file
NEED TO ALSO CHECK survex files which have a * ref to this wallet !
"""
cave_refs = [ ]
wallet_refs = [ ]
caves = [ ]
dates = [ ]
names = [ ]
team = [ ]
if not type ( survex_paths ) == list : # a string also is a sequence type, so do it this way
survex_paths = [ survex_paths ]
2023-01-31 17:13:41 +00:00
2023-10-16 11:35:56 +01:00
for svxfl in survex_paths :
if not svxfl : # not a blank string
2023-02-03 17:13:29 +00:00
continue
2023-02-03 22:19:51 +00:00
# print(f" - - {svxf=} ")
2023-10-16 11:35:56 +01:00
svxf = Path ( svxfl )
if svxf . suffix . lower ( ) != " .svx " :
2023-10-16 17:03:54 +01:00
svxf = svxf . with_suffix ( " .svx " )
2023-10-16 11:35:56 +01:00
f = Path ( settings . SURVEX_DATA ) / svxf
2023-02-03 17:13:29 +00:00
if not f . is_file ( ) :
2023-10-21 20:31:33 +01:00
message = f " ! { wallet } Specified survex file ' { svxf } ' in wallet not found on disc, probably renamed. "
DataIssue . objects . update_or_create ( parser = " wallets " , message = message , url = wurl ) # set URL to this wallet folder
2023-10-16 11:35:56 +01:00
print ( message )
2023-02-03 17:13:29 +00:00
continue
2023-10-16 11:35:56 +01:00
fpath = svxf . parent / svxf . stem
2023-02-03 17:13:29 +00:00
# print(f' - {fpath=}')
try :
svxfile = SurvexFile . objects . get ( path = fpath )
2023-10-16 11:35:56 +01:00
except :
2023-10-21 20:31:33 +01:00
message = f " Specified and present survex file ' { fpath } ' not found in db. Database may be empty. Exception. "
2023-10-16 11:35:56 +01:00
print ( message )
# This failure will also get picked up by the "S" colour code red or orange
try :
2023-02-03 17:13:29 +00:00
if svxfile . cave :
caves . append ( svxfile . cave )
2023-10-16 11:35:56 +01:00
cave_refs . append ( svxfile . cave . slug ( ) ) # this is a string?!
2023-02-03 22:19:51 +00:00
2023-02-03 17:13:29 +00:00
2023-02-03 22:19:51 +00:00
w , d , n , t = scan_survexblocks ( svxfile )
wallet_refs . extend ( w )
dates . extend ( d )
names . extend ( n )
team . extend ( t )
2023-02-03 17:13:29 +00:00
except :
2023-10-16 11:35:56 +01:00
message = f " Exception wallet handling for { fpath } ' { svxfile . cave } ' "
2023-02-03 17:13:29 +00:00
print ( message )
# This failure will also get picked up by the "S" colour code red or orange
2023-02-03 22:19:51 +00:00
caves = list ( set ( caves ) )
if len ( caves ) == 1 :
caves = caves [ 0 ]
2023-02-03 17:13:29 +00:00
2023-02-03 22:19:51 +00:00
elif len ( caves ) > 1 :
2023-02-03 17:13:29 +00:00
print (
f " - More than one Cave { caves } in this wallet { wallet } . Not managed in this troggle release. "
)
if len ( names ) == 1 :
names = names [ 0 ]
elif len ( names ) > 1 :
names = f " several, please edit: { names } "
print (
f " - More than one block name is relevant { names } in this wallet { wallet } . Not managed in this troggle release. "
)
cave_refs = list ( set ( cave_refs ) )
firstdate = None
if dates :
firstdate = min ( dates ) . isoformat ( )
return firstdate , list ( set ( team ) ) , caves , cave_refs , wallet_refs , names
2023-01-31 17:13:41 +00:00
checkboxes = [
" description written " ,
" survex not required " ,
" qms written " ,
" website updated " ,
" plan not required " ,
" plan drawn " ,
" elev not required " ,
" elev drawn " ,
2023-02-02 17:39:56 +00:00
" notes not required " ,
2023-01-31 17:13:41 +00:00
" electronic survey " ,
]
2023-01-31 20:28:39 +00:00
redirect , wallet = preprocess_path ( path )
if redirect :
return redirect
2023-02-03 17:13:29 +00:00
prevy , recent_year , recent_number , year , next , nexty = create_nav_links ( wallet )
2023-01-31 17:13:41 +00:00
wurl = f " /walletedit/ { wallet } " . replace ( " # " , " : " )
wallet = wallet . replace ( " : " , " # " )
dirpath = Path ( settings . SCANS_ROOT , year , wallet )
contents_path = Path ( settings . DRAWINGS_DATA , " walletjson " ) / year / wallet / contentsjson
2023-02-01 17:21:33 +00:00
fresh_wallet = False
2023-01-31 17:13:41 +00:00
form = FilesForm ( )
if request . method == " POST " :
2023-02-01 19:31:29 +00:00
# print(f'--- POST processing starts {wallet=} {path=}')
2023-01-31 17:13:41 +00:00
if " psg " in request . POST : # handle metadata form
formj = WalletForm ( request . POST )
2023-02-03 22:19:51 +00:00
# Beware. All fields returned as strings. So must re-type them as
# lists etc. before using or re-saving
# Unset checkboxes do not return any value, checked ones return "True".
# So all need initialising to False
2023-01-31 17:13:41 +00:00
if formj . is_valid ( ) :
posted = request . POST . copy ( )
posted . pop ( " csrfmiddlewaretoken " ) # discard this
wd = WALLET_BLANK_JSON . copy ( )
for f in checkboxes :
wd [ f ] = False
# print(f'--- wd ${f}$ - {wd[f]}')
for f in posted :
wd [ xlate [ f ] ] = posted [ f ] . replace ( " ' " , ' " ' )
2023-02-03 22:19:51 +00:00
print ( f " ' { f } ' - { xlate [ f ] } - { posted [ f ] } " )
2023-01-31 17:13:41 +00:00
if posted [ f ] == " True " :
wd [ xlate [ f ] ] = True
2023-02-03 22:19:51 +00:00
2024-08-11 11:40:56 +01:00
newdate = make_valid_date ( " no id yet in form " , posted [ " date " ] )
2023-01-31 17:13:41 +00:00
wd [ " people " ] = wd [ " people " ] [ 1 : - 1 ] . replace ( ' " ' , " " ) . split ( " , " )
for i , elem in enumerate ( wd [ " people " ] ) :
wd [ " people " ] [ i ] = elem . strip ( )
2023-02-03 22:19:51 +00:00
if wd [ " cave " ] :
if wd [ " cave " ] [ 0 ] == " [ " :
wd [ " cave " ] = wd [ " cave " ] [ 1 : - 1 ] . replace ( ' " ' , " " ) . split ( " , " )
for i , elem in enumerate ( wd [ " cave " ] ) :
wd [ " cave " ] [ i ] = elem . strip ( )
2023-01-31 17:13:41 +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 ( )
2023-02-03 22:19:51 +00:00
2023-01-31 17:13:41 +00:00
save_json ( wd )
2023-02-03 22:19:51 +00:00
# walletobject will already exist as creation does not happen here anymore
2023-02-01 21:58:48 +00:00
walletobject = make_wallet ( wallet )
2023-02-03 22:19:51 +00:00
walletobject . walletdate = newdate # must be valid date
print ( f " ---Setting VALID new date to db { walletobject } { walletobject . walletdate } " )
walletobject . save ( )
print ( f " ---Setting VALID new date to db { walletobject } { walletobject . walletdate } " )
2023-01-31 17:13:41 +00:00
commit_json ( wd )
else :
print ( " --- INVALID JSON Update form submitted " )
print ( formj . errors )
return render ( request , " errors/generic.html " , { " message " : formj . errors } )
elif (
" walletgoto " in request . POST
) : # not editing wallet data or uploading a file.. going direct to a named wallet
formg = WalletGotoForm ( request . POST , request . FILES )
if formg . is_valid ( ) :
walletgoto = request . POST [ " walletgoto " ]
return HttpResponseRedirect ( f ' /walletedit/ { walletgoto . replace ( " # " , " : " ) } ' )
2023-02-01 21:58:48 +00:00
else : # Creating a wallet .
# NOT editing wallet data, or uploading a file. Should not overwrite metadata at all.
2023-02-01 17:21:33 +00:00
if " submitbutton " in request . POST :
print ( f " --- Submit button value { request . POST [ ' submitbutton ' ] } " )
if request . POST [ ' submitbutton ' ] == " Create " :
w = WALLET_BLANK_JSON . copy ( )
save_json ( w )
2023-02-01 19:10:46 +00:00
walletobject = make_wallet ( wallet ) # no date set yet
2023-02-01 17:21:33 +00:00
commit_json ( w )
2023-02-01 19:10:46 +00:00
2023-01-31 17:13:41 +00:00
form = FilesForm ( request . POST , request . FILES )
if form . is_valid ( ) :
# print(f'--- FORM walletedit multiple BUT EMPTY METADATA supposedly {WALLET_BLANK_JSON["date"]=}')
multiple = request . FILES . getlist ( " uploadfiles " )
fs = FileSystemStorage ( os . path . join ( dirpath ) ) # creates wallet folder if necessary
2023-02-03 17:13:29 +00:00
waldata = read_json ( contents_path )
2023-01-31 17:13:41 +00:00
actual_saved = [ ]
if multiple :
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 scanfile { f . name } " )
if " saved_filename " in locals ( ) :
if saved_filename . is_file ( ) :
actual_saved . append ( saved_filename )
# print(f'! - FORM walletedit multiple {actual_saved}')
filesaved = True
# print(f'--- FORM walletedit multiple BUT EMPTY METADATA supposedly {WALLET_BLANK_JSON["date"]=}')
save_json ( waldata )
walletobject = make_wallet ( wallet )
commit_json ( waldata )
2023-02-01 17:21:33 +00:00
else :
2023-02-01 19:10:46 +00:00
print ( " --- Upload files form invalid, which is correct if just created. " )
2023-01-31 17:13:41 +00:00
#
# Not a POST, so a GET starts here. And also control gets here after a POST is processed.
#
files = [ ]
dirs = [ ]
# print(f'! - FORM walletedit - start {wallet} {dirpath}')
if dirpath . is_dir ( ) :
create = False # wallet exists because folder exists, even if nothing in it
try :
for f in dirpath . iterdir ( ) :
if f . is_dir ( ) :
for d in f . iterdir ( ) :
dirs . append ( f " { f . name } / { d . name } " )
if f . is_file ( ) :
files . append ( f . name )
except FileNotFoundError :
files . append (
" (No wallet yet. It would be created if you upload a scan and then save the form with a date.) "
)
else :
2023-02-01 19:10:46 +00:00
# either on GET or on dropping-through after the POST creating a new wallet object:
if Wallet . objects . filter ( walletname = wallet ) . exists ( ) :
2023-02-01 17:21:33 +00:00
create = False
else :
create = True
2023-01-31 17:13:41 +00:00
if len ( files ) > 0 :
files = sorted ( files )
if dirs :
dirs = sorted ( dirs )
try :
2023-02-03 17:13:29 +00:00
waldata = read_json ( contents_path )
2023-01-31 17:13:41 +00:00
except :
message = f " Nasty failure in parsing wallets metadata in { contents_path } . Probably backslash not forward slash in filename path "
return render ( request , " errors/generic.html " , { " message " : message } )
jsonfile = Path ( settings . DRAWINGS_DATA , " walletjson " ) / wallet [ 0 : 4 ] / wallet / " contents.json "
# print(f'! - FORM walletedit - jsonfile {jsonfile}')
if not Path ( jsonfile ) . is_file ( ) :
metadataurl = " "
2023-02-03 11:34:38 +00:00
metadata = " "
2023-01-31 17:13:41 +00:00
else :
metadataurl = Path ( " /dwgdataraw " , " walletjson " ) / wallet [ 0 : 4 ] / wallet . replace ( " # " , " : " ) / " contents.json "
2023-02-03 11:34:38 +00:00
with open ( jsonfile , ' r ' ) as f :
metadata = f . read ( )
2023-01-31 17:13:41 +00:00
psg = " "
freetext = " "
chkplannr = " "
2023-02-02 17:39:56 +00:00
chknotesnr = " "
2023-01-31 17:13:41 +00:00
chkpland = " "
svxfiles = [ ]
trips = [ ]
checked = { }
context = { }
2023-02-03 17:13:29 +00:00
if not waldata : # should always be true as populated by blank data if json file doesn't exist
message = f " !! No Wallet data initialised or read ! Should not happen. "
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
2023-01-31 17:13:41 +00:00
2023-02-03 17:13:29 +00:00
refs = [ ]
if " survex file " in waldata :
date , team , caves , caverefs , wallet_refs , names = scan_survexfiles ( waldata [ " survex file " ] )
# Override the discovered values with those in the JSON file:
if not waldata [ " date " ] : # either absent or empty string
waldata [ " date " ] = date
2023-02-03 22:19:51 +00:00
if no_people ( waldata [ " people " ] ) :
2023-02-03 17:13:29 +00:00
people = team
waldata [ " people " ] = team
2023-02-03 22:19:51 +00:00
else :
people = waldata [ " people " ] # text string
2023-02-03 17:13:29 +00:00
2023-02-03 22:19:51 +00:00
if empty_string ( waldata [ " cave " ] ) :
cave = caverefs # a list, potentially
waldata [ " cave " ] = cave
2023-02-03 17:13:29 +00:00
else :
2023-02-03 22:19:51 +00:00
cave = waldata [ " cave " ] # text string
2023-02-03 17:13:29 +00:00
2023-02-03 22:19:51 +00:00
if empty_string ( waldata [ " name " ] ) :
2023-02-03 17:13:29 +00:00
psg = names
waldata [ " name " ] = names
2023-02-03 22:19:51 +00:00
else :
psg = waldata [ " name " ]
2023-02-03 17:13:29 +00:00
if " free text " in waldata :
freetext = waldata [ " free text " ]
if ' notes not required ' not in waldata : # cope with schema change
waldata [ ' notes not required ' ] = False
# find trips and survex files of the same date
2023-02-03 22:19:51 +00:00
walletobject = make_wallet ( wallet )
if waldata [ " date " ] :
2024-08-11 11:38:01 +01:00
samedate = make_valid_date ( psg , waldata [ " date " ] )
2023-02-03 17:13:29 +00:00
walletobject . walletdate = samedate
walletobject . save ( )
2023-01-31 17:13:41 +00:00
2023-02-03 17:13:29 +00:00
try :
thisexpo = Expedition . objects . get ( year = int ( year ) )
except : # creating a wallet for an expo that does not exist perhaps
message = f " Trying to access an Expo for ' { year } ' which does not exist (yet). "
message + = " See /handbook/computing/newyear.html "
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
if samedate :
2023-02-27 22:23:24 +00:00
svxothers = SurvexFile . objects . filter ( survexblock__date = samedate ) . distinct ( )
2023-02-03 17:13:29 +00:00
trips = LogbookEntry . objects . filter ( date = samedate )
2023-03-21 14:56:34 +00:00
wallets = Wallet . objects . filter ( walletdate = samedate )
2023-01-31 17:13:41 +00:00
else :
svxothers = None
trips = None
2023-03-22 15:18:16 +00:00
wallets = None
2023-01-31 17:13:41 +00:00
2023-02-03 17:13:29 +00:00
else :
svxothers = None
trips = None
2023-03-22 15:18:16 +00:00
wallets = None
2023-02-03 17:13:29 +00:00
# Survex and survex complaints, comes from json file on disc, not as pre-populated as above
complaints , caveobject = get_complaints ( [ ] , waldata , svxfiles , files , wallet , wurl )
# print(f' - {caveobject=}')
2023-01-31 17:13:41 +00:00
2023-02-03 17:13:29 +00:00
for f in checkboxes :
if waldata [ f ] :
checked [ f ] = " checked "
2023-01-31 17:13:41 +00:00
2023-02-03 17:13:29 +00:00
survexsize = str ( min ( len ( str ( waldata [ " survex file " ] ) ) , 46 ) )
try :
2023-02-03 22:19:51 +00:00
thiswallet = walletobject # Wallet.objects.get(walletname=wallet)
2023-02-03 17:13:29 +00:00
caveifywallet ( thiswallet )
thiswallet . ticks = thiswallet . get_ticks ( ) # the complaints in colour form
# fixsurvextick(thiswallet, thiswallet.ticks)
# print(f"--- {wallet} {thiswallet} walletdate={thiswallet.walletdate} immediately before form render")
except :
thiswallet = None
context = {
" year " : year ,
" recent_year " : recent_year ,
" recent_number " : recent_number ,
" next " : next ,
" prevy " : prevy ,
" nexty " : nexty ,
" files " : files ,
" dirs " : dirs ,
" waldata " : waldata ,
" svxfiles " : svxfiles ,
2023-02-03 22:19:51 +00:00
" survex " : waldata [ " survex file " ] ,
" survexsize " : survexsize ,
2023-02-03 17:13:29 +00:00
" checked " : checked ,
" trips " : trips ,
" manywallets " : [ thiswallet ] ,
2023-03-21 14:56:34 +00:00
" wallets " : wallets ,
2023-02-03 17:13:29 +00:00
" svxothers " : svxothers ,
" create " : create ,
" metadataurl " : metadataurl ,
" metadata " : metadata ,
" complaints " : complaints ,
" caveobject " : caveobject ,
" people " : people ,
" peoplesize " : str ( len ( str ( people ) ) ) ,
" filesaved " : filesaved ,
" actual_saved " : actual_saved ,
}
return render (
request ,
" walletform.html " ,
{
" form " : form ,
" wallet " : wallet ,
* * context ,
" date " : waldata [ " date " ] ,
#'url': waldata["description url"], 'urlsize': str(len(str(waldata["description url"]))),
" cave " : cave ,
" psg " : psg ,
" freetext " : freetext ,
" psgsize " : str ( max ( 12 , len ( str ( psg ) ) ) ) ,
" freetextsize " : str ( max ( 60 , len ( str ( freetext ) ) ) ) ,
} ,
)
2023-01-31 17:13:41 +00:00