2020-05-24 01:57:06 +01:00
import os
import re
2021-05-03 00:52:51 +01:00
import subprocess
2021-03-24 15:46:35 +00:00
from pathlib import Path
2021-03-28 03:48:04 +01:00
from urllib . parse import urljoin , unquote as urlunquote
from urllib . request import urlopen
2011-06-02 19:16:16 +01:00
2021-03-21 01:33:59 +00:00
from django . shortcuts import render , redirect
2011-06-02 19:16:16 +01:00
from django . http import HttpResponse , HttpResponseRedirect , Http404
2020-06-18 21:50:16 +01:00
from django . urls import reverse , resolve
2011-06-02 19:16:16 +01:00
from django . template import Context , loader
2021-03-26 23:40:34 +00:00
from django . views . decorators . csrf import ensure_csrf_cookie
2021-03-31 17:57:43 +01:00
from django . contrib import admin
2021-03-26 23:40:34 +00:00
2011-06-02 19:16:16 +01:00
import django . forms as forms
2020-05-24 01:57:06 +01:00
2021-04-02 15:51:14 +01:00
from . login import login_required_if_public
2021-04-13 00:47:17 +01:00
from troggle . core . models . caves import Cave
2021-03-31 21:51:17 +01:00
import troggle . core . views . caves
2020-05-24 01:57:06 +01:00
import troggle . settings as settings
2011-06-02 19:16:16 +01:00
2021-04-01 21:44:03 +01:00
''' Formerly a separate package called ' flatpages ' written by Martin Green 2011.
This was NOT django . contrib . flatpages which stores HTML in the database , so the name was changed to expopages .
2021-03-30 21:48:36 +01:00
Then it was incorporated into troggle directly , rather than being an unnecessary external package .
'''
2021-04-05 14:49:06 +01:00
default_head = ''' <head>
< meta http - equiv = " Content-Type " content = " text/html; charset=iso-8859-1 " / >
< title > CUCC Expedition - index < / title >
< link rel = " stylesheet " type = " text/css " href = " ../css/main2.css " / >
< link rel = " stylesheet " type = " text/css " href = " ../../css/main2.css " / >
< link rel = " stylesheet " type = " text/css " href = " ../../../css/main2.css " / >
< / head >
< body >
< h1 > Expo < / h1 >
< h2 id = " tophead " > CUCC Expedition < / h2 >
< ul id = " links " >
< li > < a href = " /index.htm " > Home < / a > < / li >
< li > < a href = " /infodx.htm " > Main Index < / a > < / li >
< li > < a href = " /handbook/index.htm " > Handbook < / a > < / li >
< li > < a href = " /handbook/computing/onlinesystems.html " > Online systems < / a > < / li >
< li > < a href = " /pubs.htm " > Reports < / a > < / li >
< li > < a href = " /areas.htm " > Areas < / a > < / li >
< li > < a href = " /caves " > Caves < / a > < / li >
< li > < a href = " /expedition/2019 " > Troggle < / a > < / li >
< li > < form name = P method = get action = " /search " target = " _top " >
< input id = " omega-autofocus " type = search name = P value = " testing " size = 8 autofocus >
< input type = submit value = " Search " > < / li >
< / ul > '''
2021-04-28 00:48:20 +01:00
def expofiles_redirect ( request , filepath ) :
2021-03-21 01:33:59 +00:00
''' This is used only when running as a test system without a local copy of /expofiles/
2021-04-10 15:30:29 +01:00
when settings . EXPOFILESREMOTE is True
2021-03-21 01:33:59 +00:00
'''
2021-04-28 00:48:20 +01:00
return redirect ( urljoin ( ' http://expo.survex.com/expofiles/ ' , filepath ) )
2021-03-28 03:48:04 +01:00
2021-04-16 21:29:32 +01:00
def map ( request ) :
''' Serves unadorned the expoweb/map/map.html file
'''
fn = Path ( settings . EXPOWEB , ' map ' , ' map.html ' )
return HttpResponse ( content = open ( fn , " r " ) , content_type = ' text/html ' )
def mapfile ( request , path ) :
''' Serves unadorned file
'''
fn = Path ( settings . EXPOWEB , ' map ' , path )
return HttpResponse ( content = open ( fn , " r " ) , content_type = getmimetype ( fn ) )
2021-03-28 03:48:04 +01:00
def expofilessingle ( request , filepath ) :
2021-04-10 15:30:29 +01:00
''' sends a single binary file to the user, if not found, show the parent directory
If the path actually is a directory , then show that .
2021-03-28 03:48:04 +01:00
'''
2021-04-28 00:48:20 +01:00
#print(f' - expofilessingle {filepath}')
if filepath == " " or filepath == " / " :
return expofilesdir ( request , settings . EXPOFILES , " " )
2021-03-28 03:48:04 +01:00
fn = urlunquote ( filepath )
fn = Path ( settings . EXPOFILES , filepath )
if fn . is_dir ( ) :
return expofilesdir ( request , Path ( fn ) , Path ( filepath ) )
2021-04-10 15:30:29 +01:00
if fn . is_file ( ) :
return HttpResponse ( content = open ( fn , " rb " ) , content_type = getmimetype ( filepath ) ) # any file
else :
2021-04-28 00:48:20 +01:00
# not a file, so show parent directory - DANGER need to check this is limited to below expofiles
if Path ( fn ) . parent == Path ( settings . EXPOFILES ) . parent :
return expofilesdir ( request , Path ( settings . EXPOFILES ) , Path ( filepath ) . parent )
else :
return expofilesdir ( request , Path ( fn ) . parent , Path ( filepath ) . parent )
2021-03-28 03:48:04 +01:00
def expofilesdir ( request , dirpath , filepath ) :
''' does a directory display. If there is an index.html file we should display that.
2021-04-30 03:44:53 +01:00
- dirpath is a full Path ( ) resolved including local machine / expofiles /
2021-04-10 15:30:29 +01:00
- filepath is a Path ( ) and it does not have / expofiles / in it
2021-03-28 03:48:04 +01:00
'''
2021-04-28 00:48:20 +01:00
#print(f' - expofilesdir {dirpath} settings.EXPOFILESREMOTE: {settings.EXPOFILESREMOTE}')
if filepath :
urlpath = ' expofiles ' / Path ( filepath )
else :
urlpath = Path ( ' expofiles ' )
2021-04-10 15:30:29 +01:00
try :
for f in dirpath . iterdir ( ) :
pass
except FileNotFoundError :
2021-04-28 00:48:20 +01:00
#print(f' - expofilesdir error {dirpath}')
2021-04-10 15:30:29 +01:00
return expofilesdir ( request , dirpath . parent , filepath . parent )
2021-03-28 03:48:04 +01:00
fileitems = [ ]
2021-04-10 15:30:29 +01:00
diritems = [ ]
2021-03-28 03:48:04 +01:00
for f in dirpath . iterdir ( ) :
if f . is_dir ( ) :
diritems . append ( ( urlpath / f . parts [ - 1 ] , str ( f . parts [ - 1 ] ) ) )
else :
# if f.parts[-1].lower() == 'index.htm' or f.parts[-1].lower() == 'index.html': # css cwd problem
# return HttpResponse(content=open(f, "rb"),content_type=getmimetype(filepath)) # any file
# return expofilessingle(request, str(Path(filepath / f.parts[-1])))
fileitems . append ( ( Path ( urlpath ) / f . parts [ - 1 ] , str ( f . parts [ - 1 ] ) , getmimetype ( f ) ) )
return render ( request , ' dirdisplay.html ' , { ' filepath ' : urlpath , ' fileitems ' : fileitems , ' diritems ' : diritems , ' settings ' : settings } )
2021-03-21 01:33:59 +00:00
2021-03-31 17:57:43 +01:00
def expowebpage ( request , expowebpath , path ) :
2021-04-05 14:49:06 +01:00
''' Adds menus and serves an HTML page
2021-03-31 17:57:43 +01:00
'''
if not Path ( expowebpath / path ) . is_file ( ) :
return render ( request , ' pagenotfound.html ' , { ' path ' : path } )
2021-04-06 22:50:57 +01:00
with open ( os . path . normpath ( expowebpath / path ) , " r " ) as o :
2021-03-31 17:57:43 +01:00
html = o . read ( )
2021-04-06 22:50:57 +01:00
m = re . search ( r ' (.*)< \ s*head([^>]*)>(.*)< \ s*/head \ s*>(.*)< \ s*body([^>]*)>(.*)< \ s*/body \ s*>(.*) ' , html , re . DOTALL + re . IGNORECASE )
2021-03-31 17:57:43 +01:00
if m :
preheader , headerattrs , head , postheader , bodyattrs , body , postbody = m . groups ( )
else :
2021-04-06 22:50:57 +01:00
return HttpResponse ( default_head + html + ' <h3>HTML Parsing failure:<br>Page could not be parsed into header and body:<br>failure detected in expowebpage in views.expo.py</h3> Please edit this <var>:expoweb:</var> page to be in the expected full HTML format </body ' )
m = re . search ( r " <title>(.*)</title> " , head , re . DOTALL + re . IGNORECASE )
2021-03-31 17:57:43 +01:00
if m :
title , = m . groups ( )
else :
title = " "
2021-05-02 22:47:59 +01:00
m = re . search ( r " ^<meta([^>]*)noedit " , head , re . DOTALL + re . IGNORECASE )
2021-03-31 17:57:43 +01:00
if m :
editable = False
else :
editable = True
has_menu = False
2021-04-06 22:50:57 +01:00
menumatch = re . match ( r ' (.*)<div id= " menu " > ' , body , re . DOTALL + re . IGNORECASE )
2021-03-31 17:57:43 +01:00
if menumatch :
has_menu = True
2021-04-06 22:50:57 +01:00
menumatch = re . match ( r ' (.*)<ul id= " links " > ' , body , re . DOTALL + re . IGNORECASE )
2021-03-31 17:57:43 +01:00
if menumatch :
has_menu = True
2021-04-10 15:30:29 +01:00
return render ( request , ' expopage.html ' , { ' editable ' : editable , ' path ' : path , ' title ' : title ,
2021-03-31 17:57:43 +01:00
' body ' : body , ' homepage ' : ( path == " index.htm " ) , ' has_menu ' : has_menu } )
2021-03-31 23:19:48 +01:00
def mediapage ( request , subpath = None , doc_root = None ) :
2021-04-01 21:44:03 +01:00
''' This is for special prefix paths /photos/ /site_media/, /static/ etc.
2021-03-31 23:19:48 +01:00
as defined in urls . py . If given a directory , gives a failure page .
'''
2021-04-28 00:48:20 +01:00
#print(" - XXXXX_ROOT: {} ...{}".format(doc_root, subpath))
2021-03-31 23:19:48 +01:00
if doc_root is not None :
filetobeopened = Path ( doc_root , subpath )
if filetobeopened . is_dir ( ) :
return render ( request , ' nodirlist.html ' , { ' path ' : subpath } )
try :
return HttpResponse ( content = open ( filetobeopened , " rb " ) , content_type = getmimetype ( subpath ) )
except IOError :
return render ( request , ' pagenotfound.html ' , { ' path ' : subpath } )
else :
return render ( request , ' pagenotfound.html ' , { ' path ' : subpath } )
2021-03-31 17:57:43 +01:00
2021-04-01 21:44:03 +01:00
2021-03-31 16:14:36 +01:00
def expopage ( request , path ) :
2021-03-28 03:48:04 +01:00
''' Either renders an HTML page from expoweb with all the menus,
2021-03-28 23:47:47 +01:00
or serves an unadorned binary file with mime type
'''
2021-03-31 17:57:43 +01:00
#print(" - EXPOPAGES delivering the file: '{}':{} as MIME type: {}".format(request.path, path,getmimetype(path)),flush=True)
2021-03-28 03:48:04 +01:00
2021-04-07 21:53:17 +01:00
if path . startswith ( " noinfo " ) and settings . PUBLIC_SITE and not request . user . is_authenticated :
2021-03-28 03:48:04 +01:00
return HttpResponseRedirect ( urljoin ( reverse ( " auth_login " ) , ' ?next= {} ' . format ( request . path ) ) )
2011-07-11 00:13:06 +01:00
2021-03-31 17:57:43 +01:00
if path . startswith ( " admin/ " ) :
# don't even attempt to handle these sorts of mistakes
return HttpResponseRedirect ( " /admin/ " )
2021-03-24 15:46:35 +00:00
expowebpath = Path ( settings . EXPOWEB )
2020-06-20 23:08:34 +01:00
2021-03-31 17:57:43 +01:00
if path == " " :
return expowebpage ( request , expowebpath , " index.htm " )
if path . endswith ( " .htm " ) or path . endswith ( " .html " ) :
return expowebpage ( request , expowebpath , path )
if Path ( expowebpath / path ) . is_dir ( ) :
2021-04-05 15:48:48 +01:00
for p in [ " index.html " , " index.htm " ] :
if ( expowebpath / path / p ) . is_file ( ) :
# This needs to reset the path to the new subdirectory
return HttpResponseRedirect ( ' / ' + str ( Path ( path ) / p ) )
2021-03-31 17:57:43 +01:00
return render ( request , ' pagenotfound.html ' , { ' path ' : Path ( path ) / " index.html " } )
2021-03-28 03:48:04 +01:00
2021-03-31 17:57:43 +01:00
if path . endswith ( " / " ) :
# we already know it is not a directory.
# the final / may have been appended by middleware if there was no page without it
# do not redirect to a file path without the slash as we may get in a loop. Let the user fix it:
return render ( request , ' dirnotfound.html ' , { ' path ' : path , ' subpath ' : path [ 0 : - 1 ] } )
2021-03-31 23:19:48 +01:00
# So it must be a file in /expoweb/ but not .htm or .html probably an image
filetobeopened = os . path . normpath ( expowebpath / path )
2021-03-31 17:57:43 +01:00
try :
2021-03-28 03:48:04 +01:00
return HttpResponse ( content = open ( filetobeopened , " rb " ) , content_type = getmimetype ( path ) )
2021-03-31 17:57:43 +01:00
except IOError :
return render ( request , ' pagenotfound.html ' , { ' path ' : path } )
2011-07-11 22:36:48 +01:00
def getmimetype ( path ) :
2021-04-10 15:30:29 +01:00
''' Our own version rather than relying on what is provided by the python library. Note that when
Apache or nginx is used to deliver / expofiles / it will use it ' s own idea of mimetypes and
not these .
'''
2021-03-28 03:48:04 +01:00
path = str ( path )
2020-06-20 23:08:34 +01:00
if path . lower ( ) . endswith ( " .css " ) : return " text/css "
2021-03-22 02:27:19 +00:00
if path . lower ( ) . endswith ( " .txt " ) : return " text/css "
2020-06-20 23:08:34 +01:00
if path . lower ( ) . endswith ( " .js " ) : return " application/javascript "
2021-03-22 02:27:19 +00:00
if path . lower ( ) . endswith ( " .json " ) : return " application/javascript "
2021-03-28 03:48:04 +01:00
if path . lower ( ) . endswith ( " .ico " ) : return " image/vnd.microsoft.icon "
2012-08-14 14:05:15 +01:00
if path . lower ( ) . endswith ( " .png " ) : return " image/png "
if path . lower ( ) . endswith ( " .tif " ) : return " image/tif "
if path . lower ( ) . endswith ( " .gif " ) : return " image/gif "
if path . lower ( ) . endswith ( " .jpeg " ) : return " image/jpeg "
if path . lower ( ) . endswith ( " .jpg " ) : return " image/jpeg "
if path . lower ( ) . endswith ( " svg " ) : return " image/svg+xml "
2021-03-28 03:48:04 +01:00
if path . lower ( ) . endswith ( " xml " ) : return " application/xml " # we use "text/xhtml" for tunnel files
2012-08-14 14:05:15 +01:00
if path . lower ( ) . endswith ( " .pdf " ) : return " application/pdf "
if path . lower ( ) . endswith ( " .ps " ) : return " application/postscript "
if path . lower ( ) . endswith ( " .svx " ) : return " application/x-survex-svx "
if path . lower ( ) . endswith ( " .3d " ) : return " application/x-survex-3d "
if path . lower ( ) . endswith ( " .pos " ) : return " application/x-survex-pos "
if path . lower ( ) . endswith ( " .err " ) : return " application/x-survex-err "
if path . lower ( ) . endswith ( " .odt " ) : return " application/vnd.oasis.opendocument.text "
if path . lower ( ) . endswith ( " .ods " ) : return " application/vnd.oasis.opendocument.spreadsheet "
2021-03-28 03:48:04 +01:00
if path . lower ( ) . endswith ( " .docx " ) : return " application/vnd.openxmlformats-officedocument.wordprocessingml.document "
if path . lower ( ) . endswith ( " .xslx " ) : return " application/vnd.openxmlformats-officedocument.spreadsheetml.sheet "
if path . lower ( ) . endswith ( " .gz " ) : return " application/x-7z-compressed "
if path . lower ( ) . endswith ( " .7z " ) : return " application/x-7z-compressed "
if path . lower ( ) . endswith ( " .zip " ) : return " application/zip "
2011-07-11 22:36:48 +01:00
return " "
2011-06-02 19:16:16 +01:00
@login_required_if_public
2021-03-26 23:40:34 +00:00
@ensure_csrf_cookie
2021-03-31 16:14:36 +01:00
def editexpopage ( request , path ) :
2021-04-10 15:30:29 +01:00
''' Manages the ' Edit this Page ' capability for expo handbook and other html pages.
Relies on javascript to provide the in - browser editing environment .
'''
2011-07-11 00:13:06 +01:00
try :
2021-04-10 15:30:29 +01:00
# if a cave not a webpage at all.
2011-07-11 22:36:48 +01:00
r = Cave . objects . get ( url = path )
2021-03-31 21:51:17 +01:00
return troggle . core . views . caves . editCave ( request , r . cave . slug )
2011-07-11 22:36:48 +01:00
except Cave . DoesNotExist :
2011-07-11 00:13:06 +01:00
pass
2011-06-02 19:16:16 +01:00
try :
2021-03-26 23:40:34 +00:00
filepath = Path ( settings . EXPOWEB ) / path
2011-06-02 19:16:16 +01:00
o = open ( filepath , " r " )
2011-08-08 12:18:47 +01:00
html = o . read ( )
2012-08-06 11:56:20 +01:00
autogeneratedmatch = re . search ( r " \ < \ !-- \ s*(.*?(Do not edit|auto-generated).*?) \ s*-- \ > " , html , re . DOTALL + re . IGNORECASE )
if autogeneratedmatch :
return HttpResponse ( autogeneratedmatch . group ( 1 ) )
2012-08-06 11:19:48 +01:00
m = re . search ( r " (.*)<head([^>]*)>(.*)</head>(.*)<body([^>]*)>(.*)</body>(.*) " , html , re . DOTALL + re . IGNORECASE )
2011-08-08 12:18:47 +01:00
if m :
filefound = True
2012-08-06 11:19:48 +01:00
preheader , headerargs , head , postheader , bodyargs , body , postbody = m . groups ( )
2019-02-25 20:13:28 +00:00
linksmatch = re . match ( r ' (.*)(<ul \ s+id= " links " >.*) ' , body , re . DOTALL + re . IGNORECASE )
2011-08-08 13:11:57 +01:00
if linksmatch :
2012-08-06 11:19:48 +01:00
body , links = linksmatch . groups ( )
2020-06-18 15:54:40 +01:00
# if re.search(r"iso-8859-1", html):
# body = str(body, "iso-8859-1")
2011-08-08 12:18:47 +01:00
else :
2021-04-05 15:48:48 +01:00
return HttpResponse ( default_head + html + ' <h3>HTML Parsing failure:<br>Page could not be parsed into header and body:<br>failure detected in expowebpage in views.expo.py</h3> Please edit this <var>:expoweb:</var> page to be in the expected full HTML format .</body ' )
2011-06-02 19:16:16 +01:00
except IOError :
2021-03-26 23:40:34 +00:00
print ( " ### File not found ### " , filepath )
2011-08-08 12:18:47 +01:00
filefound = False
2011-06-02 19:16:16 +01:00
if request . method == ' POST ' : # If the form has been submitted...
2021-04-10 15:30:29 +01:00
pageform = ExpoPageForm ( request . POST ) # A form bound to the POST data
if pageform . is_valid ( ) : # Form valid therefore write file
print ( " ### \n " , str ( pageform ) [ 0 : 300 ] )
2021-03-26 23:40:34 +00:00
print ( " ### \n csrfmiddlewaretoken: " , request . POST [ ' csrfmiddlewaretoken ' ] )
2012-08-06 11:19:48 +01:00
if filefound :
headmatch = re . match ( r " (.*)<title>.*</title>(.*) " , head , re . DOTALL + re . IGNORECASE )
if headmatch :
2021-04-10 15:30:29 +01:00
head = headmatch . group ( 1 ) + " <title> " + pageform . cleaned_data [ " title " ] + " </title> " + headmatch . group ( 2 )
2012-08-06 11:19:48 +01:00
else :
2021-04-10 15:30:29 +01:00
head = " <title> " + pageform . cleaned_data [ " title " ] + " </title> "
2012-08-06 11:19:48 +01:00
else :
2021-04-10 15:30:29 +01:00
head = " <title> " + pageform . cleaned_data [ " title " ] + " </title> "
2012-08-06 11:19:48 +01:00
preheader = " <html> "
headerargs = " "
postheader = " "
bodyargs = " "
postbody = " </html> "
2021-04-10 15:30:29 +01:00
body = pageform . cleaned_data [ " html " ]
2012-08-06 11:19:48 +01:00
body = body . replace ( " \r " , " " )
2020-05-24 01:57:06 +01:00
result = " %s <head %s > %s </head> %s <body %s > \n %s </body> %s " % ( preheader , headerargs , head , postheader , bodyargs , body , postbody )
2021-05-03 00:52:51 +01:00
cwd = filepath . parent
filename = filepath . name
git = settings . GIT
with open ( filepath , " w " ) as f :
f . write ( result )
print ( f ' WROTE { cwd } --- { filename } ' )
subprocess . call ( [ git , " add " , filename ] , cwd = cwd )
subprocess . call ( [ git , " commit " , " -m " , ' Edit this page ' ] , cwd = cwd )
2021-04-05 14:49:06 +01:00
return HttpResponseRedirect ( reverse ( ' expopage ' , args = [ path ] ) ) # Redirect after POST
2011-06-02 19:16:16 +01:00
else :
2011-08-08 12:18:47 +01:00
if filefound :
2011-08-08 12:58:02 +01:00
m = re . search ( r " <title>(.*)</title> " , head , re . DOTALL + re . IGNORECASE )
2011-08-08 12:18:47 +01:00
if m :
title , = m . groups ( )
else :
title = " "
2021-04-10 15:30:29 +01:00
pageform = ExpoPageForm ( { " html " : body , " title " : title } )
2011-08-08 09:51:47 +01:00
else :
2021-03-26 23:40:34 +00:00
body = " ### File not found ### \n " + str ( filepath )
2021-04-10 15:30:29 +01:00
pageform = ExpoPageForm ( { " html " : body , " title " : " Missing " } )
return render ( request , ' editexpopage.html ' , { ' path ' : path , ' form ' : pageform , } )
2011-06-02 19:16:16 +01:00
2021-04-10 15:30:29 +01:00
class ExpoPageForm ( forms . Form ) :
''' The form used by the editexpopage function
'''
2011-08-08 09:51:47 +01:00
title = forms . CharField ( widget = forms . TextInput ( attrs = { ' size ' : ' 60 ' } ) )
2020-06-13 23:16:19 +01:00
html = forms . CharField ( widget = forms . Textarea ( attrs = { " cols " : 80 , " rows " : 20 } ) )