2023-01-19 18:35:56 +00:00
import subprocess
2024-08-09 00:02:46 +01:00
from datetime import datetime , timezone , timedelta
2023-01-19 18:35:56 +00:00
from pathlib import Path
2021-05-05 00:35:10 +01:00
from django import forms
2023-01-30 23:04:11 +00:00
from django . core . files . storage import FileSystemStorage
2024-07-23 15:38:24 +01:00
from django . http import HttpResponseRedirect
2023-07-31 13:49:54 +01:00
from django . shortcuts import render , redirect
2022-03-18 11:28:35 +00:00
2023-01-19 18:35:56 +00:00
import settings
2023-09-01 18:31:19 +01:00
2023-09-02 15:49:37 +01:00
from troggle . core . models . caves import GetCaveLookup
2023-08-31 16:55:20 +01:00
from troggle . core . models . logbooks import LogbookEntry , writelogbook , PersonLogEntry
2023-01-31 17:13:41 +00:00
from troggle . core . models . survex import DrawingFile
2023-08-31 16:55:20 +01:00
from troggle . core . models . troggle import DataIssue , Expedition , PersonExpedition
2024-07-03 17:27:37 +01:00
from troggle . core . utils import alphabet_suffix , current_expo , sanitize_name , unique_slug , write_and_commit
2023-08-31 16:55:20 +01:00
from troggle . parsers . people import GetPersonExpeditionNameLookup , known_foreigner
2023-01-30 19:04:36 +00:00
2021-05-05 00:35:10 +01:00
# from databaseReset import reinit_db # don't do this. databaseRest runs code *at import time*
2023-01-30 19:04:36 +00:00
2021-05-05 00:35:10 +01:00
from . auth import login_required_if_public
2023-01-19 18:35:56 +00:00
2023-01-30 19:04:36 +00:00
""" File upload ' views '
2023-07-31 13:49:54 +01:00
Note that there are other file upload forms in views / wallet_edit . py
and that core / forms . py contains Django class - based forms for caves and entrances .
2023-01-30 19:04:36 +00:00
"""
2021-05-05 00:35:10 +01:00
2023-01-30 19:04:36 +00:00
todo = """
2023-02-02 22:02:16 +00:00
- Ideally we should validate uploaded file as being a valid file type , not a dubious script or hack
Validate image files using a magic recogniser in walletedit ( )
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
2023-02-02 22:02:16 +00:00
- Validate Tunnel & Therion files using an XML parser in dwgupload ( ) . Though Julian says
2023-07-31 13:49:54 +01:00
tunnel is only mostly correct XML , and it does fail at least one XML parser .
2023-02-02 22:02:16 +00:00
- parse the uploaded drawing file for links to wallets and scan files as done
in parsers / drawings . py
2022-03-08 22:59:04 +00:00
- Enable folder creation in dwguploads or as a separate form
2023-07-31 13:49:54 +01:00
2023-07-31 14:16:43 +01:00
- Enable file rename on expofiles , not just for / surveyscans / ( aka wallets )
- Make file rename utility less ugly .
2023-01-30 19:04:36 +00:00
"""
2023-08-31 16:55:20 +01:00
def create_new_lbe_slug ( date ) :
onthisdate = LogbookEntry . objects . filter ( date = date )
n = len ( onthisdate )
2023-11-05 19:59:01 +00:00
print ( f " Already entries on this date: { n } \n { onthisdate } " )
2023-08-31 16:55:20 +01:00
2023-11-05 19:59:01 +00:00
suffix = alphabet_suffix ( n + 1 )
2023-09-01 18:31:19 +01:00
tid = f " { date } { suffix } "
2024-07-23 07:58:17 +01:00
if len ( tid ) < = 4 :
print ( f " BAD ERROR { tid =} " )
tid = f " { date } _ { LogbookEntry . objects . count ( ) } _ { n } " # fudged number
print ( f " { tid =} " )
2023-08-31 16:55:20 +01:00
return tid
def store_edited_entry_into_database ( date , place , title , text , others , author , tu , slug ) :
""" saves a single logbook entry and related personlogentry items
2023-09-04 18:12:09 +01:00
need to select out * guest and foreign friends from others
2023-08-31 16:55:20 +01:00
Rather similar to similarly named function in parsers / logbooks but circular reference prevents us using it directly ,
and they need refactoring anyway .
"""
year = slug [ 0 : 4 ]
expedition = Expedition . objects . get ( year = year )
cave = GetCaveLookup ( ) . get ( place . lower ( ) )
2024-07-12 16:18:05 +01:00
# print(f"store_edited_entry_into_database(): {place=} {cave=}")
2023-08-31 16:55:20 +01:00
if LogbookEntry . objects . filter ( slug = slug ) . exists ( ) :
# oops.
2023-11-05 19:59:01 +00:00
message = f " ! - DUPLICATE SLUG for logbook entry { date } - { slug } "
2023-08-31 16:55:20 +01:00
DataIssue . objects . create ( parser = " logbooks " , message = message )
slug = slug + " _ " + unique_slug ( text , 2 )
2023-10-01 10:42:47 +01:00
otherAttribs = {
2023-08-31 16:55:20 +01:00
" place " : place ,
" text " : text ,
" expedition " : expedition ,
" time_underground " : tu ,
2024-07-12 16:18:05 +01:00
" cave " : cave ,
2023-09-04 18:12:09 +01:00
" title " : f " { place } - { title } " ,
# "other_people": others
2023-08-31 16:55:20 +01:00
}
2023-10-01 10:42:47 +01:00
coUniqueAttribs = { " slug " : slug , " date " : date }
2023-08-31 16:55:20 +01:00
2023-10-01 10:42:47 +01:00
lbo = LogbookEntry . objects . create ( * * otherAttribs , * * coUniqueAttribs )
2023-08-31 16:55:20 +01:00
pt_list = [ ]
# These entities have to be PersonExpedition objects
team = others . split ( " , " )
team . append ( author )
2023-09-04 18:12:09 +01:00
odds = [ ]
2023-08-31 16:55:20 +01:00
for name in team :
name = name . strip ( )
2023-09-04 18:12:09 +01:00
if len ( name ) > 0 :
if name [ 0 ] == " * " : # a name prefix of "*" is special, just a string.
odds . append ( name )
2023-09-05 13:49:12 +01:00
print ( f " - adding * special name ' { name } ' " )
2023-09-04 18:12:09 +01:00
else :
try :
personyear = GetPersonExpeditionNameLookup ( expedition ) . get ( name . lower ( ) )
if not personyear :
odds . append ( name )
2023-09-05 13:49:12 +01:00
print ( f " - adding unrecognised expoer ' { name } ' " )
2023-09-04 18:12:09 +01:00
if known_foreigner ( name ) :
message = f " ! - Known foreigner: ' { name } ' in entry { slug =} "
print ( message )
else :
message = f " ! - No name match for: ' { name } ' in entry { slug =} "
print ( message )
DataIssue . objects . create ( parser = " logbooks " , message = message )
else :
2023-10-01 10:42:47 +01:00
coUniqueAttribs = { " personexpedition " : personyear , " nickname_used " : name , " logbook_entry " : lbo } # lbo is primary key
otherAttribs = { " time_underground " : tu , " is_logbook_entry_author " : ( name == author ) }
pt_list . append ( PersonLogEntry ( * * otherAttribs , * * coUniqueAttribs ) )
2023-09-04 18:12:09 +01:00
except :
# This should not happen. We do not raise exceptions in that function
message = f " ! - EXCEPTION: ' { name } ' in entry { slug =} "
print ( message )
DataIssue . objects . create ( parser = " logbooks " , message = message )
raise
2023-08-31 16:55:20 +01:00
PersonLogEntry . objects . bulk_create ( pt_list )
2023-09-04 18:12:09 +01:00
lbo . other_people = " , " . join ( odds )
2023-09-05 13:49:12 +01:00
print ( f " - Saving other_people ' { lbo . other_people } ' " )
2023-09-04 18:12:09 +01:00
lbo . save ( )
2021-05-05 00:35:10 +01:00
class FilesForm ( forms . Form ) : # not a model-form, just a form-form
2023-01-30 19:04:36 +00:00
uploadfiles = forms . FileField ( )
2022-08-11 19:19:52 +01:00
class FilesRenameForm ( forms . Form ) : # not a model-form, just a form-form
2023-01-30 19:04:36 +00:00
uploadfiles = forms . FileField ( )
2022-08-11 21:35:53 +01:00
renameto = forms . CharField ( strip = True , required = False )
2022-08-14 20:52:14 +01:00
2022-03-13 01:01:00 +00:00
class TextForm ( forms . Form ) : # not a model-form, just a form-form
2023-01-30 19:04:36 +00:00
photographer = forms . CharField ( strip = True )
2024-07-13 13:49:55 +01:00
class TextProspectorForm ( forms . Form ) : # not a model-form, just a form-form
prospector = forms . CharField ( strip = True )
2023-07-31 13:49:54 +01:00
class ExpofileRenameForm ( forms . Form ) : # not a model-form, just a form-form
renameto = forms . CharField ( strip = True , required = False )
2024-07-03 09:48:38 +01:00
class ExpotextfileForm ( forms . Form ) : # not a model-form, just a form-form
text = forms . CharField ( strip = True , required = False )
2023-08-06 11:47:09 +01:00
class LogbookEditForm ( forms . Form ) : # not a model-form, just a form-form
author = forms . CharField ( strip = True , required = False )
2024-07-03 09:48:38 +01:00
2024-07-03 17:27:37 +01:00
@login_required_if_public
2024-07-03 09:48:38 +01:00
def edittxtpage ( request , path , filepath ) :
""" Editing a .txt file on expoweb/
"""
2024-07-03 17:27:37 +01:00
def simple_get ( viewtext ) :
2024-07-03 09:48:38 +01:00
form = ExpotextfileForm ( )
return render (
request ,
" textfileform.html " ,
{
" form " : form ,
" path " : path ,
2024-07-03 10:34:21 +01:00
" message " : message ,
2024-07-03 09:48:38 +01:00
" filepath " : filepath ,
2024-07-03 17:27:37 +01:00
" text " : viewtext ,
2024-07-03 09:48:38 +01:00
} ,
)
2024-07-03 17:27:37 +01:00
message = " "
2024-07-03 09:48:38 +01:00
if not filepath . is_file ( ) :
print ( f " Not a file: { filepath } " )
errpage = f " <html> " + default_head + f " <h3>File not found ' { filepath } ' <br><br>failure detected in expowebpage() in views.expo.py</h3> </body> "
return HttpResponse ( errpage )
try :
2024-07-03 17:27:37 +01:00
with open ( filepath , " r " ) as f :
originaltext = f . read ( )
2024-07-03 09:48:38 +01:00
except IOError :
2024-07-03 17:27:37 +01:00
message = f ' Cannot open { filepath } for text file reading even though it is a file. '
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
2024-07-03 09:48:38 +01:00
if request . method == " GET " :
2024-07-03 17:27:37 +01:00
return simple_get ( originaltext )
2024-07-03 09:48:38 +01:00
elif request . method == " POST " :
2024-07-03 10:34:21 +01:00
form = ExpotextfileForm ( request . POST )
if not form . is_valid ( ) :
message = f ' Invalid form response for text file editing " { request . POST } " '
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
else :
2024-07-03 17:27:37 +01:00
# for i in request.POST:
# print(":: ",i, " => ", request.POST[i])
newtext = request . POST [ " text " ]
2024-07-03 10:34:21 +01:00
print ( " POST " )
if " Cancel " in request . POST :
print ( " cancel " )
2024-07-03 17:27:37 +01:00
return simple_get ( originaltext )
2024-07-03 10:34:21 +01:00
if " Save " in request . POST :
print ( " submitted for saving.. " )
2024-07-03 17:27:37 +01:00
if newtext != originaltext : # Check if content has changed at all
print ( " text changed.. saving and committing " )
try :
write_and_commit ( [ ( filepath , newtext , " utf-8 " ) ] , f " Online edit of { path } " )
except WriteAndCommitError as e :
return render ( request , " errors/generic.html " , { " message " : e . message } )
print ( " re-reading from file.. " )
try :
with open ( filepath ) as f :
rereadtext = f . read ( )
except :
print ( " ### File reading failure, but it exists.. ### " , filepath )
return render ( request , " errors/generic.html " , { " message " : e . message } )
savepath = " / " + path
print ( f " redirect { savepath } " )
return redirect ( savepath ) # Redirect after POST
else :
# no changes
pass
return simple_get ( originaltext )
else :
# mistake not POST or GET
2024-07-03 10:34:21 +01:00
message = " Something went wrong "
2024-07-03 17:27:37 +01:00
print ( message )
return simple_get ( originaltext )
2024-07-03 10:34:21 +01:00
2024-07-03 09:48:38 +01:00
2023-08-06 11:47:09 +01:00
@login_required_if_public
2023-08-10 21:17:03 +01:00
def logbookedit ( request , year = None , slug = None ) :
""" Edit a logbook entry
2023-09-05 13:49:12 +01:00
This ' validates ' the author as being on expo in the current year , but only indicates this by
putting the text of the form prompt in red ( same as for an invalid date , which is arguably more important ) .
No check is done on the other people on the trip as this is picked up anyway by parsing on import
and we don ' t really care at this point.
2023-08-06 11:47:09 +01:00
"""
2024-08-09 00:02:46 +01:00
def yesterday ( ) :
yesterday = datetime . now ( ) - timedelta ( 1 )
return yesterday . strftime ( ' % Y- % m- %d ' )
2023-09-05 15:19:09 +01:00
def validate_year ( year ) :
try :
expo = Expedition . objects . get ( year = year )
except :
2024-03-14 19:53:01 +00:00
year = current_expo ( ) # creates new Expedition object if needed
2023-09-05 15:19:09 +01:00
return year
def new_entry_form ( ) :
2024-08-09 00:02:46 +01:00
# set the date to be "yesterday" as this will, hopefully, usually be the case
2023-09-05 15:19:09 +01:00
return render (
request ,
" logbookform.html " ,
{
" form " : form ,
" year " : year ,
2024-08-09 00:02:46 +01:00
" yesterday " : yesterday ( ) ,
2023-09-05 15:19:09 +01:00
} ,
)
2023-08-10 21:17:03 +01:00
def clean_tu ( tu ) :
if tu == " " :
return 0
try :
tu = float ( tu ) / 1 # check numeric
except :
return 0
return tu
2023-08-06 11:47:09 +01:00
if not year :
2024-07-23 07:58:17 +01:00
if not slug : # not in the URL, we have not read teh POST response yet.. wich might have a slug in it
2023-09-05 15:19:09 +01:00
year = current_expo ( )
2023-08-26 16:39:29 +01:00
else :
year = slug [ 0 : 4 ]
2023-09-05 15:19:09 +01:00
try :
2024-02-05 22:16:51 +00:00
year = str ( int ( year ) ) # but maybe slug was hand-edited to be a future year..
year = validate_year ( year ) # so fix that
2023-09-05 15:19:09 +01:00
except :
year = current_expo ( )
2023-08-31 16:55:20 +01:00
author = " "
2023-08-07 22:43:12 +01:00
if request . method == " POST " :
2024-07-23 14:52:04 +01:00
prev_slug = " " # None value pending overwrite from submitted form
2023-08-07 22:43:12 +01:00
form = LogbookEditForm ( request . POST )
if not form . is_valid ( ) :
message = f ' Invalid form response for logbook entry creating " { request . POST } " '
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
else :
2023-11-05 19:59:01 +00:00
# if there is no slug then this is probably a completely new lbe and we need to enter it into the db
2023-08-31 16:55:20 +01:00
# otherwise it is an update
2023-08-07 22:43:12 +01:00
# validation all to be done yet..
2023-08-30 19:17:25 +01:00
date = request . POST [ " date " ] . strip ( )
2023-09-05 13:49:12 +01:00
author = request . POST [ " author " ] . strip ( ) # TODO check against personexpedition on submit
others = request . POST [ " others " ] . strip ( ) # TODO check each against personexpedition on submit
2023-08-31 16:55:20 +01:00
place = request . POST [ " place " ] . strip ( ) . replace ( ' - ' , ' = ' ) # no hyphens !
2023-08-08 17:23:55 +01:00
title = request . POST [ " title " ] . strip ( )
2023-08-08 17:24:18 +01:00
entry = request . POST [ " text " ] . strip ( )
2024-07-23 14:52:04 +01:00
if " prev_slug " in request . POST :
prev_slug = request . POST [ " prev_slug " ] . strip ( ) # if we are re-editing the same entry again
2023-11-07 21:20:59 +00:00
entry = entry . replace ( ' \r ' , ' ' ) # remove HTML-standard CR inserted from form.
2024-08-08 22:58:40 +01:00
entry = entry . replace ( ' \n \n ' , ' \n <p> \n ' ) # replace 2 \n with <p>
2023-08-08 17:23:55 +01:00
tu = request . POST [ " tu " ] . strip ( )
2023-08-10 21:17:03 +01:00
tu = clean_tu ( tu )
2023-08-26 16:39:29 +01:00
try :
odate = datetime . strptime ( date . replace ( " . " , " - " ) , " % Y- % m- %d " ) . date ( )
2024-08-08 22:58:40 +01:00
print ( f " { odate . year =} " )
if str ( odate . year ) == year :
dateflag = False
else :
print ( f " Trying to change the year ! No!! { odate . year =} " )
odate = datetime . strptime ( f " { year } -01-01 " , " % Y- % m- %d " ) . date ( )
dateflag = True
2023-08-26 16:39:29 +01:00
except :
odate = datetime . strptime ( f " { year } -01-01 " , " % Y- % m- %d " ) . date ( )
print ( f " ! Invalid date string { date } , setting to { odate } " )
dateflag = True
date = odate . isoformat ( )
2023-09-05 15:19:09 +01:00
year = validate_year ( year )
2023-09-05 13:49:12 +01:00
expo = Expedition . objects . get ( year = year )
personyear = GetPersonExpeditionNameLookup ( expo ) . get ( author . lower ( ) )
if personyear :
authorflag = False
else :
authorflag = True
print ( f " ! Unrecognised author: { author } " )
2024-07-23 15:18:09 +01:00
# if somehow we get a slug set to just '2024', not eg '2020-08-10b'
2024-07-23 15:38:24 +01:00
# because the URL of the page is /logbookedit/2022 for a new entry
2024-07-23 15:18:09 +01:00
# This is a hack, why can we not reproduce this bug on the dev system?
2024-07-23 15:38:24 +01:00
if slug not in locals ( ) :
2024-07-23 15:18:09 +01:00
slug = " "
2024-07-23 15:38:24 +01:00
if len ( slug ) < 11 :
slug = " "
if len ( prev_slug ) < 11 :
2024-07-23 15:18:09 +01:00
prev_slug = " "
2023-09-05 13:49:12 +01:00
2024-07-23 14:52:04 +01:00
if not prev_slug and not slug :
2023-08-31 16:55:20 +01:00
# Creating a new logbook entry with all the gubbins
slug = create_new_lbe_slug ( date )
2024-07-23 14:52:04 +01:00
if prev_slug and not slug :
# if this was a previous post, then prev_slug will have been set on the form
# we are editing a previous thing, so we don't create a new lbe
slug = prev_slug
# OK we could patch the object in place, but if the people on the trip have changed this
# would get very messy. So we delete it, and thus all the dependent objects,
# and recreate it and all its links. It might not exist though.
print ( f " - Deleting the LogBookEntry { slug } " )
LogbookEntry . objects . filter ( slug = slug ) . delete ( ) # works even if it does not exist
2023-08-31 16:55:20 +01:00
print ( f " - Creating the LogBookEntry { slug } " )
2024-02-05 20:02:03 +00:00
year = slug [ 0 : 4 ]
try :
expedition = Expedition . objects . get ( year = year )
except Expedition . DoesNotExist :
message = f ''' ! - This expo " { year } " not created yet
2024-07-23 14:52:04 +01:00
It needs to be created before you can save a logbook entry .
See / handbook / computing / newyear . html
WHAT TO DO NOW :
1. Press the Back button on your proswer to return to the screen where you typed up the entry ,
2. Copy the text of what you wrote into a new text file ,
3. Direct a nerd to fix this . It should take only a couple of minutes . '''
2024-02-05 20:02:03 +00:00
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
2023-08-31 16:55:20 +01:00
store_edited_entry_into_database ( date , place , title , entry , others , author , tu , slug )
2024-02-05 20:02:03 +00:00
2023-08-31 16:55:20 +01:00
print ( f " - Rewriting the entire { year } logbook to disc " )
filename = " logbook.html "
try :
2024-07-20 16:11:23 +01:00
print ( f " - Logbook for { year } to be exported and written out. " )
2023-09-04 18:12:09 +01:00
writelogbook ( year , filename ) # uses a template, not the code fragment below which is just a visible hint to logged on user
2023-08-31 16:55:20 +01:00
except :
message = f ' ! - Logbook saving failed - \n !! Permissions failure ?! on attempting to save file " logbook.html " '
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
2023-08-26 16:39:29 +01:00
2023-08-31 16:55:20 +01:00
# Code fragment illustration - not actually what gets saved to database
2023-08-07 22:43:12 +01:00
output = f '''
2023-08-30 19:29:51 +01:00
2023-08-31 16:55:20 +01:00
< div class = " tripdate " id = " {slug} " > { date } < / div >
2023-08-30 19:29:51 +01:00
< div class = " trippeople " > < u > { author } < / u > , { others } < / div >
< div class = " triptitle " > { place } - { title } < / div >
{ entry }
< div class = " timeug " > T / U { tu } hrs < / div >
< hr / >
'''
2023-08-31 16:55:20 +01:00
# Successful POST
# So save to database and then write out whole new logbook.html file
2023-09-05 13:49:12 +01:00
# We do author validation on the form as displayed by GET, not at the moment of POST.
# If we had JS validation then we could be more timely.
2023-08-31 16:55:20 +01:00
git = settings . GIT
2023-09-02 17:43:50 +01:00
dirpath = Path ( settings . EXPOWEB ) / " years " / str ( year )
2023-08-31 16:55:20 +01:00
lbe_add = subprocess . run (
[ git , " add " , filename ] , cwd = dirpath , capture_output = True , text = True
)
msgdata = (
lbe_add . stderr
+ " \n "
+ lbe_add . stdout
+ " \n return code: "
+ str ( lbe_add . returncode )
)
message = f ' ! - FORM Logbook Edit { slug } - Success: git ADD on server for this file { filename } . ' + msgdata
print ( message )
if lbe_add . returncode != 0 :
msgdata = (
" Ask a nerd to fix this. \n \n "
+ lbe_add . stderr
+ " \n \n "
+ lbe_add . stdout
+ " \n \n return code: "
+ str ( lbe_add . returncode )
)
message = (
f " ! - FORM Logbook Edit - CANNOT git ADD on server for this file { filename } . { slug } edits saved but not added to git. \n "
+ msgdata
)
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
lbe_commit = subprocess . run (
[ git , " commit " , " -m " , f " Logbook edited { slug } " ] ,
cwd = dirpath ,
capture_output = True ,
text = True ,
)
message = f ' ! - FORM Logbook Edit - { filename } . { slug } edits saved, added to git, and COMMITTED. \n ' + msgdata
print ( message )
#This produces return code = 1 if it commits OK
if lbe_commit . returncode != 0 :
msgdata = (
" Ask a nerd to fix this. \n \n "
+ lbe_commit . stderr
+ " \n "
+ lbe_commit . stdout
+ " \n return code: "
+ str ( lbe_commit . returncode )
)
message = (
2024-07-23 14:52:04 +01:00
f " ! - FORM Logbook Edit -Error code ' { lbe_commit . returncode } ' with git on server for { filename } . { slug } edits saved, added to git, but NOT committed. \n "
2023-08-31 16:55:20 +01:00
+ msgdata
)
print ( message )
2024-07-23 07:58:17 +01:00
if not ( lbe_commit . returncode == 1 and settings . DEVSERVER ) :
# rc=1 is OK on the development server
return render ( request , " errors/generic.html " , { " message " : message } )
2023-08-31 16:55:20 +01:00
2024-07-23 07:58:17 +01:00
# This does not change the URL in the browser, so despite a new slug being created,
# the next time this code is run it thinks a new slug needs to be created. So we should
# actually redirect to a new URL (an edit not a create) not simply return a render object.
2024-07-23 15:38:24 +01:00
# logbookedit/2022-08-21a
2024-08-08 22:58:40 +01:00
# HOWEVER by doing a redirect rather than returning a rendered page, we lose all the
# error settings e.g dateflag and authroflag so the user gets no feedback about bad data entered.
2024-08-09 00:02:46 +01:00
# so we need to pass the flags explicitly int he url and then extract them from the request in the GET bit. sigh.
2024-08-08 22:58:40 +01:00
return HttpResponseRedirect ( f " /logbookedit/ { slug } ?dateflag= { dateflag } &authorflag= { authorflag } " )
2024-07-23 15:38:24 +01:00
# return render(
# request,
# "logbookform.html",
# {
# "form": form,
# "year": year,
# "date": date, "dateflag": dateflag,
# "author": author, "authorflag": authorflag,
# "others": others,
# "place": place,
# "title": title,
# "tu": tu,
# "entry": entry,
# "output": output,
# "slug": slug,
# },
# )
2023-08-07 22:43:12 +01:00
# GET here
else :
form = LogbookEditForm ( )
2023-09-05 15:19:09 +01:00
year = validate_year ( year )
2024-08-08 22:58:40 +01:00
if request . GET . get ( ' dateflag ' , ' False ' ) == " True " :
dateflag = True
else :
dateflag = False
if request . GET . get ( ' authorflag ' , ' False ' ) == " True " :
authorflag = True
else :
authorflag = False
2023-09-05 15:19:09 +01:00
if not slug : # no slug or bad slug for an lbe which does not exist
return new_entry_form ( )
else :
2023-08-10 21:17:03 +01:00
lbes = LogbookEntry . objects . filter ( slug = slug )
2023-09-05 15:19:09 +01:00
if not lbes :
return new_entry_form ( )
else :
2023-08-10 21:17:03 +01:00
if len ( lbes ) > 1 :
2023-09-05 15:19:09 +01:00
return render ( request , " object_list.html " , { " object_list " : lbes } ) # ie a bug
2023-08-10 21:17:03 +01:00
else :
lbe = lbes [ 0 ]
print ( f " { lbe } " )
tu = clean_tu ( lbe . time_underground )
people = [ ]
2023-08-26 16:39:29 +01:00
for p in lbe . personlogentry_set . filter ( logbook_entry = lbe ) : # p is a PersonLogEntry object
2023-08-10 21:17:03 +01:00
if p . is_logbook_entry_author :
2023-08-26 16:39:29 +01:00
# author = p.personexpedition.person.fullname
author = p . nickname_used
2023-08-10 21:17:03 +01:00
else :
2023-08-26 16:39:29 +01:00
# people.append(p.personexpedition.person.fullname)
people . append ( p . nickname_used )
2023-08-10 21:17:03 +01:00
others = ' , ' . join ( people )
2023-09-05 13:49:12 +01:00
if lbe . other_people :
others = others + " , " + lbe . other_people
2023-08-10 21:17:03 +01:00
lenothers = min ( 70 , max ( 20 , len ( others ) ) )
2023-09-05 13:49:12 +01:00
2023-08-10 21:17:03 +01:00
text = lbe . text
rows = max ( 5 , len ( text ) / 50 )
return render (
request ,
" logbookform.html " ,
{
" form " : form ,
" year " : year ,
2024-08-08 22:58:40 +01:00
" date " : lbe . date . isoformat ( ) , " dateflag " : dateflag ,
" author " : author , " authorflag " : authorflag ,
2023-08-10 21:17:03 +01:00
" others " : others ,
" lenothers " : lenothers ,
" place " : lbe . place ,
" title " : lbe . title . replace ( f " { lbe . place } - " , " " ) ,
" tu " : tu ,
" entry " : text ,
" textrows " : rows ,
2023-11-04 08:40:46 +00:00
" slug " : slug ,
2023-08-31 16:55:20 +01:00
} ,
2023-08-10 21:17:03 +01:00
)
2023-09-13 16:46:10 +01:00
2023-07-31 13:49:54 +01:00
@login_required_if_public
def expofilerename ( request , filepath ) :
""" Rename any single file in /expofiles/ - eventually.
Currently this just does files within wallets i . e . in / surveyscans /
and it returns control to the original wallet edit page
"""
2023-09-22 22:48:35 +01:00
def is_rotatable ( path ) :
""" If file is a JPG but has no filename extension, then it must be renamed
before it can be rotated .
"""
print ( f " { path } : ' { Path ( path ) . suffix . lower ( ) } ' " )
if Path ( path ) . suffix . lower ( ) in [ " .png " , " .jpg " , " .jpeg " ] :
return True
else :
return False
2023-09-14 11:40:19 +01:00
def rotate_image ( ) :
2023-09-14 12:15:16 +01:00
wallet = str ( Path ( filepath ) . parent ) . lstrip ( " surveyscans/ " )
cwd = settings . SCANS_ROOT / wallet
print ( f " ROTATE \n { cwd =} \n { filename =} " )
mogrify = settings . MOGRIFY
rot = subprocess . run (
[ mogrify , " -rotate " , " 90 " , filename ] , cwd = cwd , capture_output = True , text = True
)
msgdata = (
rot . stderr
+ " \n "
+ rot . stdout
+ " \n return code: "
+ str ( rot . returncode )
)
message = f ' ! - ROTATE - Success: rotated this file { filename } . ' + msgdata
print ( message )
2023-09-14 13:08:10 +01:00
# DataIssue.objects.create(parser="mogrify", message=message)
2023-09-14 12:24:36 +01:00
2023-09-14 12:15:16 +01:00
if rot . returncode != 0 :
msgdata = (
" Ask a nerd to fix this. \n \n "
+ rot . stderr
+ " \n \n "
+ rot . stdout
+ " \n \n return code: "
+ str ( rot . returncode )
)
message = (
f " ! - ROTATE - CANNOT blurk for this file { filename } . \n "
+ msgdata
)
print ( message )
2023-09-14 12:24:36 +01:00
DataIssue . objects . create ( parser = " mogrify " , message = message )
2023-09-14 12:15:16 +01:00
2023-09-14 11:40:19 +01:00
return simple_get ( )
def simple_get ( ) :
form = ExpofileRenameForm ( )
return render (
request ,
" renameform.html " ,
{
" form " : form ,
" filepath " : filepath ,
" filename " : filename ,
" filesize " : filesize ,
" files " : files ,
" walletpath " : walletpath ,
2023-09-22 22:48:35 +01:00
" wallet " : wallet ,
2023-09-14 11:40:19 +01:00
" notpics " : notpics ,
2023-09-22 22:48:35 +01:00
" rotatable " : rotatable ,
2023-09-14 11:40:19 +01:00
} ,
)
2023-07-31 13:49:54 +01:00
if filepath :
2023-09-14 12:15:16 +01:00
# using EXPOFILES not SCANS_ROOT in case we want to extend this to other parts of the system
2023-07-31 13:49:54 +01:00
actualpath = Path ( settings . EXPOFILES ) / Path ( filepath )
else :
message = f ' \n File to rename not specified " { filepath } " '
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
if not actualpath . is_file ( ) :
message = f ' \n File not found when attempting rename " { filepath } " '
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
else :
filename = Path ( filepath ) . name
2023-09-14 11:40:19 +01:00
walletpath = Path ( filepath ) . parent
2023-09-22 22:48:35 +01:00
wallet = Path ( walletpath ) . name
2023-07-31 14:16:43 +01:00
folder = actualpath . parent
filesize = f " { actualpath . stat ( ) . st_size : , } "
2023-09-22 22:48:35 +01:00
rotatable = is_rotatable ( filename )
2023-07-31 13:49:54 +01:00
if not actualpath . is_relative_to ( Path ( settings . SCANS_ROOT ) ) :
message = f ' \n Can only do rename within wallets (expofiles/surveyscans/) currently, sorry. " { actualpath } " '
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
2023-09-14 11:40:19 +01:00
files = [ ]
dirs = [ ]
notpics = [ ]
dirpath = actualpath . parent
print ( f ' ! - FORM rename expofile - start \n { filepath =} \n { dirpath =} \n { walletpath =} ' )
if dirpath . is_dir ( ) :
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 ( ) :
2023-09-22 22:48:35 +01:00
if is_rotatable ( f . name ) : # should allow all images here which can be thumsized, not just rotatables. e.g. PDF
2023-09-14 11:40:19 +01:00
files . append ( f . name )
else :
2023-09-22 22:48:35 +01:00
notpics . append ( f . name )
2023-09-14 11:40:19 +01:00
except FileNotFoundError :
files . append (
" (Error. There should be at least one filename visible here. Try refresh.) "
)
if request . method == " GET " :
return simple_get ( )
elif request . method == " POST " :
2023-07-31 13:49:54 +01:00
form = ExpofileRenameForm ( request . POST )
2023-07-31 20:00:46 +01:00
if not form . is_valid ( ) :
message = f ' Invalid form response for file renaming " { request . POST } " '
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
2023-09-14 11:40:19 +01:00
if " rotate " in request . POST :
return rotate_image ( )
2023-07-31 13:49:54 +01:00
2023-09-14 11:40:19 +01:00
if " rename " in request . POST :
if " renametoname " not in request . POST :
print ( " renametoname not in request.POST " )
# blank filename passed it, so just treat as another GET
return simple_get ( )
renameto = sanitize_name ( request . POST [ " renametoname " ] )
2023-07-31 20:00:46 +01:00
if ( folder / renameto ) . is_file ( ) or ( folder / renameto ) . is_dir ( ) :
rename_bad = renameto
message = f ' \n Cannot rename to an existing file or folder. " { filename } " -> " { ( folder / renameto ) } " '
2023-07-31 13:49:54 +01:00
print ( message )
2023-07-31 20:00:46 +01:00
return render (
request ,
" renameform.html " ,
{
" form " : form ,
" filepath " : filepath ,
" filename " : filename ,
" filesize " : filesize ,
2023-09-14 11:40:19 +01:00
" files " : files ,
" walletpath " : walletpath ,
2023-09-22 22:48:35 +01:00
" wallet " : wallet ,
2023-09-14 11:40:19 +01:00
" notpics " : notpics ,
2023-07-31 20:00:46 +01:00
" rename_bad " : rename_bad ,
} ,
)
2023-09-14 11:40:19 +01:00
actualpath . rename ( ( folder / renameto ) )
message = f ' \n RENAMED " { filename } " -> " { ( folder / renameto ) } " '
print ( message )
walletid = actualpath . relative_to ( Path ( settings . SCANS_ROOT ) ) . parent . stem . replace ( " # " , " : " )
print ( walletid )
return redirect ( f ' /survey_scans/ { walletid } / ' )
else : # not GET or POST
print ( " UNRECOGNIZED action " )
return simple_get ( )
2023-07-31 13:49:54 +01:00
2022-03-13 01:01:00 +00:00
@login_required_if_public
def photoupload ( request , folder = None ) :
2023-01-30 19:04:36 +00:00
""" Upload photo image files into /expofiles/photos/<year>/<photographer>/
2022-03-13 01:01:00 +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 , This is simpler .
2023-01-30 19:04:36 +00:00
When uploading from a phone , it is useful to be able to rename the file to something
2022-08-11 19:19:52 +01:00
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 .
2023-07-31 13:49:54 +01:00
Pending generic file renaming capability more generally .
2023-01-30 19:04:36 +00:00
"""
2024-03-14 19:53:01 +00:00
year = current_expo ( )
# year = settings.PHOTOS_YEAR
2022-03-13 01:01:00 +00:00
filesaved = False
actual_saved = [ ]
2023-01-30 19:04:36 +00:00
context = { " year " : year , " placeholder " : " AnathemaDevice " }
2022-03-13 01:01:00 +00:00
yearpath = Path ( settings . PHOTOS_ROOT , year )
2023-01-30 19:04:36 +00:00
if folder == str ( year ) or folder == str ( year ) + " / " :
2022-03-13 01:01:00 +00:00
folder = None
2023-01-30 19:04:36 +00:00
2022-03-13 01:01:00 +00:00
if folder is None :
2023-01-30 19:04:36 +00:00
folder = " " # improve this later
2022-03-13 01:01:00 +00:00
dirpath = Path ( settings . PHOTOS_ROOT , year )
2023-01-30 19:04:36 +00:00
urlfile = f " /expofiles/photos/ { year } "
urldir = f " /photoupload/ { year } "
else : # it will contain the year as well as the photographer
2022-03-13 01:01:00 +00:00
dirpath = Path ( settings . PHOTOS_ROOT , folder )
if dirpath . is_dir ( ) :
2023-01-30 19:04:36 +00:00
urlfile = f " /expofiles/photos/ { folder } "
urldir = Path ( " /photoupload " ) / folder
2022-03-13 01:01:00 +00:00
else :
2023-01-30 19:04:36 +00:00
folder = " " # improve this later
2022-03-13 01:01:00 +00:00
dirpath = Path ( settings . PHOTOS_ROOT , year )
2023-01-30 19:04:36 +00:00
urlfile = f " /expofiles/photos/ { year } "
urldir = f " /photoupload/ { year } "
2022-08-11 19:19:52 +01:00
form = FilesRenameForm ( )
2023-01-30 19:04:36 +00:00
formd = TextForm ( )
if request . method == " POST " :
if " photographer " in request . POST :
2024-07-13 13:49:55 +01:00
# then we are creating a new folder
2022-03-13 01:01:00 +00:00
formd = TextForm ( request . POST )
if formd . is_valid ( ) :
2023-09-13 16:46:10 +01:00
newphotographer = sanitize_name ( request . POST [ " photographer " ] )
2022-11-23 21:59:42 +00:00
try :
( yearpath / newphotographer ) . mkdir ( exist_ok = True )
except :
2023-01-30 19:04:36 +00:00
message = f ' \n !! Permissions failure ?! 0 attempting to mkdir " { ( yearpath / newphotographer ) } " '
2022-11-23 21:59:42 +00:00
print ( message )
2023-01-30 19:04:36 +00:00
return render ( request , " errors/generic.html " , { " message " : message } )
2022-11-23 21:59:42 +00:00
2022-03-13 01:01:00 +00:00
else :
2024-07-13 13:49:55 +01:00
# then we are renaming the file ?
2023-01-30 19:04:36 +00:00
form = FilesRenameForm ( request . POST , request . FILES )
2022-03-13 01:01:00 +00:00
if form . is_valid ( ) :
f = request . FILES [ " uploadfiles " ]
2023-01-30 19:04:36 +00:00
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 )
2023-01-30 19:04:36 +00:00
2023-09-13 16:46:10 +01:00
renameto = sanitize_name ( request . POST [ " renameto " ] )
2023-01-30 19:04:36 +00:00
2022-03-13 01:01:00 +00:00
actual_saved = [ ]
2023-01-30 19:04:36 +00: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 != " " :
2023-01-30 19:04:36 +00:00
try : # crashes in Django os.chmod call if on WSL, but does save file!
saved_filename = fs . save ( renameto , content = f )
2022-08-11 21:35:53 +01:00
except :
2023-01-30 19:04:36 +00:00
print (
f ' \n !! Permissions failure ?! 1 attempting to save " { f . name } " in " { dirpath } " { renameto =} '
)
if " saved_filename " in locals ( ) :
2022-08-11 21:35:53 +01:00
if saved_filename . is_file ( ) :
actual_saved . append ( saved_filename )
2023-01-30 19:04:36 +00:00
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 )
2022-08-11 21:35:53 +01:00
except :
2023-01-30 19:04:36 +00:00
print (
f ' \n !! Permissions failure ?! 2 attempting to save " { f . name } " in " { dirpath } " { renameto =} '
)
if " saved_filename " in locals ( ) :
2022-08-11 21:35:53 +01:00
if saved_filename . is_file ( ) :
actual_saved . append ( saved_filename )
2023-01-30 19:04:36 +00:00
filesaved = True
else : # multiple is a list of content
2022-08-11 19:19:52 +01:00
for f in multiple :
2023-01-30 19:04:36 +00:00
try : # crashes in Django os.chmod call if on WSL, but does save file!
saved_filename = fs . save ( f . name , content = f )
2022-08-11 19:19:52 +01:00
except :
2023-01-30 19:04:36 +00:00
print (
f ' \n !! Permissions failure ?! 3 attempting to save " { f . name } " in " { dirpath } " { renameto =} '
)
if " saved_filename " in locals ( ) :
2022-08-11 19:19:52 +01:00
if saved_filename . is_file ( ) :
actual_saved . append ( saved_filename )
2023-01-30 19:04:36 +00:00
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 ( ) :
2023-01-30 19:04:36 +00:00
files . append ( f . name )
2022-03-13 01:01:00 +00:00
except FileNotFoundError :
2023-01-30 19:04:36 +00:00
files . append ( " (no folder yet - would be created) " )
if len ( files ) > 0 :
2022-03-13 01:01:00 +00:00
files = sorted ( files )
2023-01-30 19:04:36 +00:00
2022-03-13 01:01:00 +00:00
if dirs :
dirs = sorted ( dirs )
2023-01-30 19:04:36 +00:00
return render (
request ,
" photouploadform.html " ,
{
" form " : form ,
* * context ,
" urlfile " : urlfile ,
" urldir " : urldir ,
" folder " : folder ,
" files " : files ,
" dirs " : dirs ,
" filesaved " : filesaved ,
" actual_saved " : actual_saved ,
} ,
)
2024-07-13 13:49:55 +01:00
@login_required_if_public
def gpxupload ( request , folder = None ) :
""" Copy of photo upload
folder is the " path "
"""
def gpxvalid ( name ) :
if Path ( name ) . suffix . lower ( ) in [ " .xml " , " .gpx " ] :
return True # dangerous, we should check the actual file binary signature
return False
print ( f " gpxupload() { folder =} " )
year = current_expo ( )
filesaved = False
actual_saved = [ ]
context = { " year " : year , " placeholder " : " AnathemaDevice " }
yearpath = Path ( settings . EXPOFILES ) / " gpslogs " / year
if folder == str ( year ) or folder == str ( year ) + " / " :
folder = None
if folder is None :
folder = " " # improve this later
dirpath = yearpath
urlfile = f " /expofiles/gpslogs/ { year } "
urldir = f " /gpxupload/ { year } "
else : # it will contain the year as well as the prospector
dirpath = Path ( settings . EXPOFILES ) / " gpslogs " / folder
if dirpath . is_dir ( ) :
urlfile = f " /expofiles/gpslogs/ { folder } "
urldir = Path ( " /gpxupload " ) / folder
else :
folder = " " # improve this later
dirpath = yearpath
urlfile = f " /expofiles/gpslogs/ { year } "
urldir = f " /gpxupload/ { year } "
print ( f " gpxupload() { folder =} { dirpath =} { urlfile =} { urldir =} " )
form = FilesRenameForm ( )
formd = TextProspectorForm ( )
print ( f " gpxupload() { form =} { formd =} " )
if request . method == " POST " :
print ( f " gpxupload() method=POST " )
for i in request . POST :
print ( " " , i )
if " prospector " in request . POST :
2024-07-13 13:52:24 +01:00
print ( f " gpxupload() { request . POST =} \n { request . POST [ ' prospector ' ] =} " )
2024-07-13 13:49:55 +01:00
formd = TextProspectorForm ( request . POST )
if formd . is_valid ( ) :
newprospector = sanitize_name ( request . POST [ " prospector " ] )
print ( f " gpxupload() { newprospector =} " )
try :
( yearpath / newprospector ) . mkdir ( exist_ok = True )
except :
message = f ' \n !! Permissions failure ?! 0 attempting to mkdir " { ( yearpath / newprospector ) } " '
print ( message )
return render ( request , " errors/generic.html " , { " message " : message } )
else :
print ( f " gpxupload() no prospector field " )
print ( f " gpxupload() { request . FILES =} " )
for i in request . FILES :
print ( " " , i )
form = FilesRenameForm ( request . POST , request . FILES )
print ( f " gpxupload() is the FilesRenameForm valid? { form =} " )
for i in form :
print ( " " , i )
if not form . is_valid ( ) :
print ( f " gpxupload() Form is not valid { form =} " )
else :
print ( f " gpxupload() about to look at request.FILES " )
f = request . FILES [ " uploadfiles " ]
multiple = request . FILES . getlist ( " uploadfiles " )
# NO CHECK that the files being uploaded are image files
fs = FileSystemStorage ( dirpath )
renameto = sanitize_name ( request . POST [ " renameto " ] )
actual_saved = [ ]
if multiple :
if len ( multiple ) == 1 :
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 ?! 1 attempting to save " { f . name } " in " { dirpath } " { renameto =} '
)
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 ?! 2 attempting to save " { f . name } " in " { dirpath } " { renameto =} '
)
if " saved_filename " in locals ( ) :
if saved_filename . is_file ( ) :
actual_saved . append ( saved_filename )
filesaved = True
else : # multiple is a list of content
2024-07-13 13:51:19 +01:00
for f in multiple :
if gpxvalid ( f . name ) :
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 ?! 3 attempting to save " { f . name } " in " { dirpath } " { renameto =} '
)
if " saved_filename " in locals ( ) :
if saved_filename . is_file ( ) :
actual_saved . append ( saved_filename )
filesaved = True
else :
print ( f " gpxupload(): not a GPX file { f . name =} " )
2024-07-13 13:49:55 +01:00
print ( f " gpxupload() drop through " )
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) " )
except Exception as e :
print ( f " gpxupload() EXCEPTION \n { e } " )
if len ( files ) > 0 :
files = sorted ( files )
if dirs :
dirs = sorted ( dirs )
print ( f " gpxupload() about to render.. " )
return render (
request ,
" gpxuploadform.html " ,
{
" form " : form ,
* * context ,
" urlfile " : urlfile ,
" urldir " : urldir ,
" folder " : folder ,
" files " : files ,
" dirs " : dirs ,
" filesaved " : filesaved ,
" actual_saved " : actual_saved ,
} ,
)
2022-03-13 01:01:00 +00:00
2021-05-05 00:35:10 +01:00
@login_required_if_public
2023-01-30 19:04:36 +00:00
def dwgupload ( request , folder = None , gitdisable = " no " ) :
""" Upload DRAWING files (tunnel or therion) into the upload folder in :drawings
2022-03-08 22:59:04 +00:00
AND registers it into the : drawings : git repo .
2023-01-30 19:04:36 +00:00
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 .
2023-01-30 19:04:36 +00:00
2023-07-31 13:49:54 +01:00
We could validate the uploaded files as being a valid files using an XML parser , not a dubious script or hack ,
but this won ' t work on Tunnel files as Tunnel does not produce exactly valid xml
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 .
2023-01-30 19:04:36 +00:00
"""
2021-05-05 00:35:10 +01:00
def dwgvalid ( name ) :
2023-01-30 19:04:36 +00:00
if name in [
" .gitignore " ,
] :
2021-05-05 00:35:10 +01:00
return False
2023-01-30 19:04:36 +00:00
if Path ( name ) . suffix . lower ( ) in [ " .xml " , " .th " , " .th2 " , " " , " .svg " , " .txt " ] :
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 ) :
2023-01-30 19:04:36 +00:00
""" OK to display, even if we are not going to allow a new one to be uploaded """
if name in [
" .gitignore " ,
] :
2022-03-05 22:16:03 +00:00
return False
2023-01-30 19:04:36 +00:00
if Path ( name ) . suffix . lower ( ) in [
" .xml " ,
" .th " ,
" .th2 " ,
" " ,
" .svg " ,
" .txt " ,
" .jpg " ,
" .jpeg " ,
" .png " ,
" .pdf " ,
" .top " ,
" .topo " ,
] :
return True # dangerous, we should check the actual file binary signature
2022-03-05 22:16:03 +00:00
return False
2021-05-05 00:35:10 +01:00
filesaved = False
actual_saved = [ ]
refused = [ ]
2023-01-30 19:04:36 +00:00
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 :
2023-01-30 19:04:36 +00:00
folder = " " # improve this later
2021-05-05 00:35:10 +01:00
dirpath = Path ( settings . DRAWINGS_DATA )
2023-01-30 19:04:36 +00:00
urlfile = " /dwgdataraw "
urldir = " /dwgupload "
2021-05-05 00:35:10 +01:00
else :
dirpath = Path ( settings . DRAWINGS_DATA , folder )
2023-01-30 19:04:36 +00:00
urlfile = Path ( " /dwgdataraw/ " ) / folder
urldir = Path ( " /dwgupload/ " ) / folder
2021-05-05 00:35:10 +01:00
form = FilesForm ( )
2023-01-30 19:04:36 +00:00
if request . method == " POST " :
form = FilesForm ( request . POST , request . FILES )
2021-05-05 00:35:10 +01:00
if form . is_valid ( ) :
2022-08-13 19:14:57 +01:00
# print(f'! - FORM dwgupload - POST valid: "{request.FILES["uploadfiles"]}" ')
2021-05-05 00:35:10 +01:00
f = request . FILES [ " uploadfiles " ]
2023-01-30 19:04:36 +00:00
multiple = request . FILES . getlist ( " uploadfiles " )
2022-11-23 21:59:42 +00:00
savepath = Path ( settings . DRAWINGS_DATA , folder )
fs = FileSystemStorage ( savepath )
2023-01-30 19:04:36 +00:00
2021-05-05 00:35:10 +01:00
actual_saved = [ ]
refused = [ ]
2023-01-30 19:04:36 +00:00
2022-03-05 17:05:15 +00:00
# GIT see also core/views/expo.py editexpopage()
# GIT see also core/models/cave.py writetrogglefile()
2023-01-30 19:04:36 +00:00
if gitdisable != " yes " : # set in url 'dwguploadnogit/'
2021-10-31 17:25:45 +00:00
git = settings . GIT
else :
2023-01-30 19:04:36 +00:00
git = " echo "
2022-08-13 19:14:57 +01:00
# print(f'git DISABLED {f.name}')
2021-10-31 17:25:45 +00:00
2021-05-05 00:35:10 +01:00
if multiple :
for f in multiple :
2022-08-13 19:14:57 +01:00
# print(f'! - FORM dwgupload - file {f} in {multiple=}')
2021-05-05 00:35:10 +01:00
if dwgvalid ( f . name ) :
2023-01-30 19:04:36 +00:00
try : # crashes in Django os.chmod call if on WSL without metadata drvfs, but does save file!
saved_filename = fs . save ( f . name , content = f )
2022-04-06 18:43:26 +01:00
except :
2023-01-30 19:04:36 +00:00
print (
f ' ! - FORM dwgupload - \n !! Permissions failure ?! on attempting to save file " { f . name } " in " { savepath } " . Attempting to continue.. '
)
if " saved_filename " in locals ( ) :
2022-08-13 19:14:57 +01:00
if Path ( dirpath , saved_filename ) . is_file ( ) :
actual_saved . append ( saved_filename )
2023-01-30 19:04:36 +00:00
if gitdisable != " yes " :
dr_add = subprocess . run (
[ git , " add " , saved_filename ] , cwd = dirpath , capture_output = True , text = True
)
msgdata = (
dr_add . stderr
+ " \n "
+ dr_add . stdout
+ " \n return code: "
+ str ( dr_add . returncode )
)
2022-08-13 19:14:57 +01:00
# message = f'! - FORM dwgupload - Success: git ADD on server for this file {saved_filename}.' + msgdata
# print(message)
2022-04-06 18:43:26 +01:00
if dr_add . returncode != 0 :
2023-01-30 19:04:36 +00:00
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 " ! - FORM dwgupload - CANNOT git ADD on server for this file { saved_filename } . Edits saved but not added to git. \n "
+ msgdata
)
2022-08-13 19:14:57 +01:00
print ( message )
2023-01-30 19:04:36 +00:00
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
)
2022-08-13 19:14:57 +01:00
dwgfile . save ( )
else :
2023-01-30 19:04:36 +00:00
message = f " ! - FORM dwgupload - NOT A FILE { Path ( dirpath , saved_filename ) =} . "
2022-08-13 19:14:57 +01:00
print ( message )
else :
2023-01-30 19:04:36 +00:00
message = f " ! - FORM dwgupload - Save failure for { f . name } . Changes NOT saved. "
2022-08-13 19:14:57 +01:00
print ( message )
2023-01-30 19:04:36 +00:00
return render ( request , " errors/generic.html " , { " message " : message } )
2022-08-13 19:14:57 +01:00
if saved_filename != f . name :
# message = f'! - FORM dwgupload - Save RENAME {f.name} renamed as {saved_filename}. This is OK.'
# print(message)
pass
2023-01-30 19:04:36 +00:00
2021-05-05 00:35:10 +01:00
else :
refused . append ( f . name )
2022-08-13 19:14:57 +01:00
# print(f'REFUSED {f.name}')
2023-01-30 19:04:36 +00:00
if actual_saved :
2021-10-31 17:25:45 +00:00
filesaved = True
2022-03-05 22:16:03 +00:00
if len ( actual_saved ) > 1 :
dots = " ... "
else :
dots = " "
2023-01-30 19:04:36 +00:00
if gitdisable != " yes " :
dr_commit = subprocess . run (
[ git , " commit " , " -m " , f " Drawings upload - { actual_saved [ 0 ] } { dots } " ] ,
cwd = dirpath ,
capture_output = True ,
text = True ,
)
2022-08-13 19:14:57 +01:00
# message = f'! - FORM dwgupload - For uploading {actual_saved[0]}{dots}. Edits saved, added to git, and COMMITTED.\n' + msgdata
# print(message)
2022-03-05 22:16:03 +00:00
# This produces return code = 1 if it commits OK
if dr_commit . returncode != 0 :
2023-01-30 19:04:36 +00:00
msgdata = (
" Ask a nerd to fix this. \n \n "
+ dr_commit . stderr
+ " \n "
+ dr_commit . stdout
+ " \n return code: "
+ str ( dr_commit . returncode )
)
message = (
f " ! - FORM dwgupload -Error code with git on server for this { actual_saved [ 0 ] } { dots } . Edits saved, added to git, but NOT committed. \n "
+ msgdata
)
2022-08-13 19:14:57 +01:00
print ( message )
2023-01-30 19:04:36 +00:00
return render ( request , " errors/generic.html " , { " message " : message } )
2022-08-13 19:14:57 +01:00
else :
print ( f ' git disabled " { git =} " ' )
2023-01-30 19:04:36 +00:00
else : # maybe all were refused by the suffix test in dwgvalid()
message = f " ! - FORM dwgupload - Nothing actually saved. All were refused. { actual_saved =} "
2022-08-13 19:14:57 +01:00
print ( message )
2021-10-31 17:25:45 +00:00
2021-05-05 00:35:10 +01:00
files = [ ]
dirs = [ ]
2022-08-13 19:14:57 +01: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 ( ) :
2023-01-30 19:04:36 +00:00
if f . name not in [ " .git " ] :
2021-05-05 00:35:10 +01:00
dirs . append ( f . name )
continue
if f . is_file ( ) :
2023-01-30 19:04:36 +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 )
2023-01-30 19:04:36 +00:00
2021-05-05 00:35:10 +01:00
if dirs :
dirs = sorted ( dirs )
2023-01-30 19:04:36 +00:00
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 ,
} ,
)