forked from expo/troggle
update oddity with VS Code and WSL2
This commit is contained in:
parent
1f3f60a6a3
commit
41b2bcee4f
@ -1,3 +1,3 @@
|
||||
The copy in this /_deploy/ folder may not be the latest if active development
|
||||
has been going on in the parent folder. Check there for a later copy of
|
||||
The copy in this /_deploy/ folder may not be the latest if active development
|
||||
has been going on in the parent folder. Check there for a later copy of
|
||||
the localsettingsWSL file.
|
@ -1,368 +1,368 @@
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from urllib.parse import urljoin, unquote as urlunquote
|
||||
from urllib.request import urlopen
|
||||
|
||||
from django.shortcuts import render, redirect
|
||||
from django.http import HttpResponse, HttpResponseRedirect, Http404
|
||||
from django.urls import reverse, resolve
|
||||
from django.template import Context, loader
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.contrib import admin
|
||||
|
||||
import django.forms as forms
|
||||
|
||||
from .auth import login_required_if_public
|
||||
from troggle.core.models.caves import Cave
|
||||
import troggle.core.views.caves
|
||||
import troggle.settings as settings
|
||||
|
||||
'''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.
|
||||
Then it was incorporated into troggle directly, rather than being an unnecessary external package.
|
||||
'''
|
||||
|
||||
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 size=8 autofocus>
|
||||
<input type=submit value="Search"></li>
|
||||
</ul>''' # this gets overwritten by templates/menu.html by django for most normal pages
|
||||
|
||||
def expofiles_redirect(request, filepath):
|
||||
'''This is used only when running as a test system without a local copy of /expofiles/
|
||||
when settings.EXPOFILESREMOTE is True
|
||||
'''
|
||||
return redirect(urljoin('http://expo.survex.com/expofiles/', filepath))
|
||||
|
||||
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))
|
||||
|
||||
def expofilessingle(request, filepath):
|
||||
'''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.
|
||||
'''
|
||||
#print(f' - expofilessingle {filepath}')
|
||||
if filepath =="" or filepath =="/":
|
||||
return expofilesdir(request, settings.EXPOFILES, "")
|
||||
|
||||
fn=urlunquote(filepath)
|
||||
fn = Path(settings.EXPOFILES,filepath)
|
||||
if fn.is_dir():
|
||||
return expofilesdir(request, Path(fn), Path(filepath))
|
||||
if fn.is_file():
|
||||
return HttpResponse(content=open(fn, "rb"),content_type=getmimetype(filepath)) # any file
|
||||
else:
|
||||
# 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)
|
||||
|
||||
def expofilesdir(request, dirpath, filepath):
|
||||
'''does a directory display. If there is an index.html file we should display that.
|
||||
- dirpath is a full Path() resolved including local machine /expofiles/
|
||||
- filepath is a Path() and it does not have /expofiles/ in it
|
||||
'''
|
||||
#print(f' - expofilesdir {dirpath} settings.EXPOFILESREMOTE: {settings.EXPOFILESREMOTE}')
|
||||
if filepath:
|
||||
urlpath = 'expofiles' / Path(filepath)
|
||||
else:
|
||||
urlpath = Path('expofiles')
|
||||
try:
|
||||
for f in dirpath.iterdir():
|
||||
pass
|
||||
except FileNotFoundError:
|
||||
#print(f' - expofilesdir error {dirpath}')
|
||||
return expofilesdir(request, dirpath.parent, filepath.parent)
|
||||
|
||||
fileitems = []
|
||||
diritems = []
|
||||
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 })
|
||||
|
||||
def expowebpage(request, expowebpath, path):
|
||||
'''Adds menus and serves an HTML page
|
||||
'''
|
||||
if not Path(expowebpath / path).is_file():
|
||||
# Should not get here if the path has suffix "_edit"
|
||||
print(f' - 404 error in expowebpage() {path}')
|
||||
return render(request, 'pagenotfound.html', {'path': path}, status="404")
|
||||
|
||||
try:
|
||||
with open(os.path.normpath(expowebpath / path), "r") as o:
|
||||
html = o.read()
|
||||
except:
|
||||
try:
|
||||
with open(os.path.normpath(expowebpath / path), "rb") as o:
|
||||
html = str(o.read()).replace("<h1>","<h1>BAD NON-UTF-8 characters here - ")
|
||||
except:
|
||||
return HttpResponse(default_head + '<h3>UTF-8 Parsing Failure:<br>Page could not be parsed using UTF-8:<br>failure detected in expowebpage in views.expo.py</h3> Please edit this <var>:expoweb:</var> page to replace dubious umlauts and £ symbols with correct HTML entities e.g. <em>&pound;;</em>. </body' )
|
||||
|
||||
m = re.search(r'(.*)<\s*head([^>]*)>(.*)<\s*/head\s*>(.*)<\s*body([^>]*)>(.*)<\s*/body\s*>(.*)', html, re.DOTALL + re.IGNORECASE)
|
||||
if m:
|
||||
preheader, headerattrs, head, postheader, bodyattrs, body, postbody = m.groups()
|
||||
else:
|
||||
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)
|
||||
if m:
|
||||
title, = m.groups()
|
||||
else:
|
||||
title = ""
|
||||
m = re.search(r"^<meta([^>]*)noedit", head, re.DOTALL + re.IGNORECASE)
|
||||
if m:
|
||||
editable = False
|
||||
else:
|
||||
editable = os.access(Path(expowebpath / path), os.W_OK) # are file permissions writeable?
|
||||
|
||||
has_menu = False
|
||||
menumatch = re.match(r'(.*)<div id="menu">', body, re.DOTALL + re.IGNORECASE)
|
||||
if menumatch:
|
||||
has_menu = True
|
||||
menumatch = re.match(r'(.*)<ul id="links">', body, re.DOTALL + re.IGNORECASE)
|
||||
if menumatch:
|
||||
has_menu = True
|
||||
return render(request, 'expopage.html', {'editable': editable, 'path': path, 'title': title,
|
||||
'body': body, 'homepage': (path == "index.htm"), 'has_menu': has_menu})
|
||||
|
||||
def mediapage(request, subpath=None, doc_root=None):
|
||||
'''This is for special prefix paths /photos/ /site_media/, /static/ etc.
|
||||
as defined in urls.py . If given a directory, gives a failure page.
|
||||
'''
|
||||
#print(" - XXXXX_ROOT: {} ...{}".format(doc_root, subpath))
|
||||
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}, status="404")
|
||||
else:
|
||||
return render(request, 'pagenotfound.html', {'path': subpath}, status="404")
|
||||
|
||||
|
||||
|
||||
def expopage(request, path):
|
||||
'''Either renders an HTML page from expoweb with all the menus,
|
||||
or serves an unadorned binary file with mime type
|
||||
'''
|
||||
#print(" - EXPOPAGES delivering the file: '{}':{} as MIME type: {}".format(request.path, path,getmimetype(path)),flush=True)
|
||||
|
||||
if path.startswith("noinfo") and settings.PUBLIC_SITE and not request.user.is_authenticated:
|
||||
return HttpResponseRedirect(urljoin(reverse("auth_login"),'?next={}'.format(request.path)))
|
||||
|
||||
if path.startswith("admin/"):
|
||||
# don't even attempt to handle these sorts of mistakes
|
||||
return HttpResponseRedirect("/admin/")
|
||||
|
||||
expowebpath = Path(settings.EXPOWEB)
|
||||
|
||||
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():
|
||||
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))
|
||||
return render(request, 'pagenotfound.html', {'path': Path(path) / "index.html"}, status="404")
|
||||
|
||||
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]})
|
||||
|
||||
# So it must be a file in /expoweb/ but not .htm or .html probably an image
|
||||
filetobeopened = os.path.normpath(expowebpath / path)
|
||||
|
||||
try:
|
||||
return HttpResponse(content=open(filetobeopened, "rb"), content_type=getmimetype(path))
|
||||
except IOError:
|
||||
return render(request, 'pagenotfound.html', {'path': path}, status="404")
|
||||
|
||||
|
||||
|
||||
def getmimetype(path):
|
||||
'''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.
|
||||
'''
|
||||
path = str(path)
|
||||
if path.lower().endswith(".css"): return "text/css"
|
||||
if path.lower().endswith(".txt"): return "text/css"
|
||||
if path.lower().endswith(".js"): return "application/javascript"
|
||||
if path.lower().endswith(".json"): return "application/javascript"
|
||||
if path.lower().endswith(".ico"): return "image/vnd.microsoft.icon"
|
||||
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"
|
||||
if path.lower().endswith("xml"): return "application/xml" # we use "text/xhtml" for tunnel files
|
||||
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"
|
||||
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"
|
||||
return ""
|
||||
|
||||
@login_required_if_public
|
||||
@ensure_csrf_cookie
|
||||
def editexpopage(request, path):
|
||||
'''Manages the 'Edit this Page' capability for expo handbook and other html pages.
|
||||
Relies on HTML5 or javascript to provide the in-browser editing environment.
|
||||
'''
|
||||
try:
|
||||
# if a cave not a webpage at all.
|
||||
r = Cave.objects.get(url = path)
|
||||
return troggle.core.views.caves.editCave(request, r.cave.slug)
|
||||
except Cave.DoesNotExist:
|
||||
pass
|
||||
|
||||
try:
|
||||
filepath = Path(settings.EXPOWEB) / path
|
||||
o = open(filepath, "r")
|
||||
html = o.read()
|
||||
autogeneratedmatch = re.search(r"\<\!--\s*(.*?(Do not edit|It is auto-generated).*?)\s*--\>", html, re.DOTALL + re.IGNORECASE)
|
||||
if autogeneratedmatch:
|
||||
return HttpResponse(autogeneratedmatch.group(1))
|
||||
m = re.search(r"(.*)<head([^>]*)>(.*)</head>(.*)<body([^>]*)>(.*)</body>(.*)", html, re.DOTALL + re.IGNORECASE)
|
||||
if m:
|
||||
filefound = True
|
||||
preheader, headerargs, head, postheader, bodyargs, body, postbody = m.groups()
|
||||
linksmatch = re.match(r'(.*)(<ul\s+id="links">.*)', body, re.DOTALL + re.IGNORECASE)
|
||||
if linksmatch:
|
||||
body, links = linksmatch.groups()
|
||||
# if re.search(r"iso-8859-1", html):
|
||||
# body = str(body, "iso-8859-1")
|
||||
else:
|
||||
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' )
|
||||
except IOError:
|
||||
print("### File not found ### ", filepath)
|
||||
filefound = False
|
||||
|
||||
|
||||
if request.method == 'POST': # If the form has been submitted...
|
||||
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])
|
||||
print("### \n csrfmiddlewaretoken: ",request.POST['csrfmiddlewaretoken'])
|
||||
if filefound:
|
||||
headmatch = re.match(r"(.*)<title>.*</title>(.*)", head, re.DOTALL + re.IGNORECASE)
|
||||
if headmatch:
|
||||
head = headmatch.group(1) + "<title>" + pageform.cleaned_data["title"] + "</title>" + headmatch.group(2)
|
||||
else:
|
||||
head = "<title>" + pageform.cleaned_data["title"] + "</title>"
|
||||
else:
|
||||
head = "<title>" + pageform.cleaned_data["title"] + "</title>"
|
||||
preheader = "<html>"
|
||||
headerargs = ""
|
||||
postheader = ""
|
||||
bodyargs = ""
|
||||
postbody = "</html>\n"
|
||||
body = pageform.cleaned_data["html"]
|
||||
body = body.replace("\r", "")
|
||||
result = "%s<head%s>%s</head>%s<body%s>\n%s</body>%s" % (preheader, headerargs, head, postheader, bodyargs, body, postbody)
|
||||
|
||||
cwd = filepath.parent
|
||||
filename = filepath.name
|
||||
git = settings.GIT
|
||||
# GIT see also core/models/cave.py writetrogglefile()
|
||||
# GIT see also core/views/uploads.py dwgupload()
|
||||
try:
|
||||
with open(filepath, "w") as f:
|
||||
print(f'WRITING{cwd}---{filename} ')
|
||||
# as the wsgi process www-data, we have group write-access but are not owner, so cannot chmod.
|
||||
# os.chmod(filepath, 0o664) # set file permissions to rw-rw-r--
|
||||
f.write(result)
|
||||
except PermissionError:
|
||||
message = f'CANNOT save this file.\nPERMISSIONS incorrectly set on server for this file {filename}. Ask a nerd to fix this.'
|
||||
return render(request,'errors/generic.html', {'message': message})
|
||||
|
||||
try:
|
||||
cp_add = subprocess.run([git, "add", filename], cwd=cwd, capture_output=True, text=True)
|
||||
if cp_add.returncode != 0:
|
||||
msgdata = 'Ask a nerd to fix this.\n\n' + cp_add.stderr + '\n\n' + cp_add.stdout + '\n\nreturn code: ' + str(cp_add.returncode)
|
||||
message = f'CANNOT git on server for this file {filename}. Edits saved but not added to git.\n\n' + msgdata
|
||||
return render(request,'errors/generic.html', {'message': message})
|
||||
|
||||
cp_commit = subprocess.run([git, "commit", "-m", f'Troggle online: Edit this page - {filename}'], cwd=cwd, capture_output=True, text=True)
|
||||
# This produces return code = 1 if it commits OK, but when the repo still needs to be pushed to origin/expoweb
|
||||
if cp_commit.returncode != 0 and cp_commit.stdout != 'nothing to commit, working tree clean':
|
||||
msgdata = 'Ask a nerd to fix this.\n\n' + cp_commit.stderr + '\n\n' + cp_commit.stdout + '\n\nreturn code: ' + str(cp_commit.returncode)
|
||||
message = f'Error code with git on server for this file {filename}. Edits saved, added to git, but NOT committed.\n\n' + msgdata
|
||||
return render(request,'errors/generic.html', {'message': message})
|
||||
|
||||
except subprocess.SubprocessError:
|
||||
message = f'CANNOT git on server for this file {filename}. Subprocess error. Edits not saved.\nAsk a nerd to fix this.'
|
||||
return render(request,'errors/generic.html', {'message': message})
|
||||
|
||||
return HttpResponseRedirect(reverse('expopage', args=[path])) # Redirect after POST
|
||||
else:
|
||||
if filefound:
|
||||
m = re.search(r"<title>(.*)</title>", head, re.DOTALL + re.IGNORECASE)
|
||||
if m:
|
||||
title, = m.groups()
|
||||
else:
|
||||
title = ""
|
||||
pageform = ExpoPageForm({"html": body, "title": title})
|
||||
else:
|
||||
body = "### File not found ###\n" + str(filepath)
|
||||
pageform = ExpoPageForm({"html": body, "title": "Missing"})
|
||||
return render(request, 'editexpopage.html', {'path': path, 'form': pageform, })
|
||||
|
||||
class ExpoPageForm(forms.Form):
|
||||
'''The form used by the editexpopage function
|
||||
'''
|
||||
title = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
|
||||
html = forms.CharField(widget=forms.Textarea(attrs={"cols":80, "rows":20}))
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from urllib.parse import urljoin, unquote as urlunquote
|
||||
from urllib.request import urlopen
|
||||
|
||||
from django.shortcuts import render, redirect
|
||||
from django.http import HttpResponse, HttpResponseRedirect, Http404
|
||||
from django.urls import reverse, resolve
|
||||
from django.template import Context, loader
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.contrib import admin
|
||||
|
||||
import django.forms as forms
|
||||
|
||||
from .auth import login_required_if_public
|
||||
from troggle.core.models.caves import Cave
|
||||
import troggle.core.views.caves
|
||||
import troggle.settings as settings
|
||||
|
||||
'''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.
|
||||
Then it was incorporated into troggle directly, rather than being an unnecessary external package.
|
||||
'''
|
||||
|
||||
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 size=8 autofocus>
|
||||
<input type=submit value="Search"></li>
|
||||
</ul>''' # this gets overwritten by templates/menu.html by django for most normal pages
|
||||
|
||||
def expofiles_redirect(request, filepath):
|
||||
'''This is used only when running as a test system without a local copy of /expofiles/
|
||||
when settings.EXPOFILESREMOTE is True
|
||||
'''
|
||||
return redirect(urljoin('http://expo.survex.com/expofiles/', filepath))
|
||||
|
||||
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))
|
||||
|
||||
def expofilessingle(request, filepath):
|
||||
'''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.
|
||||
'''
|
||||
#print(f' - expofilessingle {filepath}')
|
||||
if filepath =="" or filepath =="/":
|
||||
return expofilesdir(request, settings.EXPOFILES, "")
|
||||
|
||||
fn=urlunquote(filepath)
|
||||
fn = Path(settings.EXPOFILES,filepath)
|
||||
if fn.is_dir():
|
||||
return expofilesdir(request, Path(fn), Path(filepath))
|
||||
if fn.is_file():
|
||||
return HttpResponse(content=open(fn, "rb"),content_type=getmimetype(filepath)) # any file
|
||||
else:
|
||||
# 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)
|
||||
|
||||
def expofilesdir(request, dirpath, filepath):
|
||||
'''does a directory display. If there is an index.html file we should display that.
|
||||
- dirpath is a full Path() resolved including local machine /expofiles/
|
||||
- filepath is a Path() and it does not have /expofiles/ in it
|
||||
'''
|
||||
#print(f' - expofilesdir {dirpath} settings.EXPOFILESREMOTE: {settings.EXPOFILESREMOTE}')
|
||||
if filepath:
|
||||
urlpath = 'expofiles' / Path(filepath)
|
||||
else:
|
||||
urlpath = Path('expofiles')
|
||||
try:
|
||||
for f in dirpath.iterdir():
|
||||
pass
|
||||
except FileNotFoundError:
|
||||
#print(f' - expofilesdir error {dirpath}')
|
||||
return expofilesdir(request, dirpath.parent, filepath.parent)
|
||||
|
||||
fileitems = []
|
||||
diritems = []
|
||||
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 })
|
||||
|
||||
def expowebpage(request, expowebpath, path):
|
||||
'''Adds menus and serves an HTML page
|
||||
'''
|
||||
if not Path(expowebpath / path).is_file():
|
||||
# Should not get here if the path has suffix "_edit"
|
||||
print(f' - 404 error in expowebpage() {path}')
|
||||
return render(request, 'pagenotfound.html', {'path': path}, status="404")
|
||||
|
||||
try:
|
||||
with open(os.path.normpath(expowebpath / path), "r") as o:
|
||||
html = o.read()
|
||||
except:
|
||||
try:
|
||||
with open(os.path.normpath(expowebpath / path), "rb") as o:
|
||||
html = str(o.read()).replace("<h1>","<h1>BAD NON-UTF-8 characters here - ")
|
||||
except:
|
||||
return HttpResponse(default_head + '<h3>UTF-8 Parsing Failure:<br>Page could not be parsed using UTF-8:<br>failure detected in expowebpage in views.expo.py</h3> Please edit this <var>:expoweb:</var> page to replace dubious umlauts and £ symbols with correct HTML entities e.g. <em>&pound;;</em>. </body' )
|
||||
|
||||
m = re.search(r'(.*)<\s*head([^>]*)>(.*)<\s*/head\s*>(.*)<\s*body([^>]*)>(.*)<\s*/body\s*>(.*)', html, re.DOTALL + re.IGNORECASE)
|
||||
if m:
|
||||
preheader, headerattrs, head, postheader, bodyattrs, body, postbody = m.groups()
|
||||
else:
|
||||
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)
|
||||
if m:
|
||||
title, = m.groups()
|
||||
else:
|
||||
title = ""
|
||||
m = re.search(r"^<meta([^>]*)noedit", head, re.DOTALL + re.IGNORECASE)
|
||||
if m:
|
||||
editable = False
|
||||
else:
|
||||
editable = os.access(Path(expowebpath / path), os.W_OK) # are file permissions writeable?
|
||||
|
||||
has_menu = False
|
||||
menumatch = re.match(r'(.*)<div id="menu">', body, re.DOTALL + re.IGNORECASE)
|
||||
if menumatch:
|
||||
has_menu = True
|
||||
menumatch = re.match(r'(.*)<ul id="links">', body, re.DOTALL + re.IGNORECASE)
|
||||
if menumatch:
|
||||
has_menu = True
|
||||
return render(request, 'expopage.html', {'editable': editable, 'path': path, 'title': title,
|
||||
'body': body, 'homepage': (path == "index.htm"), 'has_menu': has_menu})
|
||||
|
||||
def mediapage(request, subpath=None, doc_root=None):
|
||||
'''This is for special prefix paths /photos/ /site_media/, /static/ etc.
|
||||
as defined in urls.py . If given a directory, gives a failure page.
|
||||
'''
|
||||
#print(" - XXXXX_ROOT: {} ...{}".format(doc_root, subpath))
|
||||
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}, status="404")
|
||||
else:
|
||||
return render(request, 'pagenotfound.html', {'path': subpath}, status="404")
|
||||
|
||||
|
||||
|
||||
def expopage(request, path):
|
||||
'''Either renders an HTML page from expoweb with all the menus,
|
||||
or serves an unadorned binary file with mime type
|
||||
'''
|
||||
#print(" - EXPOPAGES delivering the file: '{}':{} as MIME type: {}".format(request.path, path,getmimetype(path)),flush=True)
|
||||
|
||||
if path.startswith("noinfo") and settings.PUBLIC_SITE and not request.user.is_authenticated:
|
||||
return HttpResponseRedirect(urljoin(reverse("auth_login"),'?next={}'.format(request.path)))
|
||||
|
||||
if path.startswith("admin/"):
|
||||
# don't even attempt to handle these sorts of mistakes
|
||||
return HttpResponseRedirect("/admin/")
|
||||
|
||||
expowebpath = Path(settings.EXPOWEB)
|
||||
|
||||
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():
|
||||
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))
|
||||
return render(request, 'pagenotfound.html', {'path': Path(path) / "index.html"}, status="404")
|
||||
|
||||
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]})
|
||||
|
||||
# So it must be a file in /expoweb/ but not .htm or .html probably an image
|
||||
filetobeopened = os.path.normpath(expowebpath / path)
|
||||
|
||||
try:
|
||||
return HttpResponse(content=open(filetobeopened, "rb"), content_type=getmimetype(path))
|
||||
except IOError:
|
||||
return render(request, 'pagenotfound.html', {'path': path}, status="404")
|
||||
|
||||
|
||||
|
||||
def getmimetype(path):
|
||||
'''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.
|
||||
'''
|
||||
path = str(path)
|
||||
if path.lower().endswith(".css"): return "text/css"
|
||||
if path.lower().endswith(".txt"): return "text/css"
|
||||
if path.lower().endswith(".js"): return "application/javascript"
|
||||
if path.lower().endswith(".json"): return "application/javascript"
|
||||
if path.lower().endswith(".ico"): return "image/vnd.microsoft.icon"
|
||||
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"
|
||||
if path.lower().endswith("xml"): return "application/xml" # we use "text/xhtml" for tunnel files
|
||||
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"
|
||||
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"
|
||||
return ""
|
||||
|
||||
@login_required_if_public
|
||||
@ensure_csrf_cookie
|
||||
def editexpopage(request, path):
|
||||
'''Manages the 'Edit this Page' capability for expo handbook and other html pages.
|
||||
Relies on HTML5 or javascript to provide the in-browser editing environment.
|
||||
'''
|
||||
try:
|
||||
# if a cave not a webpage at all.
|
||||
r = Cave.objects.get(url = path)
|
||||
return troggle.core.views.caves.editCave(request, r.cave.slug)
|
||||
except Cave.DoesNotExist:
|
||||
pass
|
||||
|
||||
try:
|
||||
filepath = Path(settings.EXPOWEB) / path
|
||||
o = open(filepath, "r")
|
||||
html = o.read()
|
||||
autogeneratedmatch = re.search(r"\<\!--\s*(.*?(Do not edit|It is auto-generated).*?)\s*--\>", html, re.DOTALL + re.IGNORECASE)
|
||||
if autogeneratedmatch:
|
||||
return HttpResponse(autogeneratedmatch.group(1))
|
||||
m = re.search(r"(.*)<head([^>]*)>(.*)</head>(.*)<body([^>]*)>(.*)</body>(.*)", html, re.DOTALL + re.IGNORECASE)
|
||||
if m:
|
||||
filefound = True
|
||||
preheader, headerargs, head, postheader, bodyargs, body, postbody = m.groups()
|
||||
linksmatch = re.match(r'(.*)(<ul\s+id="links">.*)', body, re.DOTALL + re.IGNORECASE)
|
||||
if linksmatch:
|
||||
body, links = linksmatch.groups()
|
||||
# if re.search(r"iso-8859-1", html):
|
||||
# body = str(body, "iso-8859-1")
|
||||
else:
|
||||
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' )
|
||||
except IOError:
|
||||
print("### File not found ### ", filepath)
|
||||
filefound = False
|
||||
|
||||
|
||||
if request.method == 'POST': # If the form has been submitted...
|
||||
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])
|
||||
print("### \n csrfmiddlewaretoken: ",request.POST['csrfmiddlewaretoken'])
|
||||
if filefound:
|
||||
headmatch = re.match(r"(.*)<title>.*</title>(.*)", head, re.DOTALL + re.IGNORECASE)
|
||||
if headmatch:
|
||||
head = headmatch.group(1) + "<title>" + pageform.cleaned_data["title"] + "</title>" + headmatch.group(2)
|
||||
else:
|
||||
head = "<title>" + pageform.cleaned_data["title"] + "</title>"
|
||||
else:
|
||||
head = "<title>" + pageform.cleaned_data["title"] + "</title>"
|
||||
preheader = "<html>"
|
||||
headerargs = ""
|
||||
postheader = ""
|
||||
bodyargs = ""
|
||||
postbody = "</html>\n"
|
||||
body = pageform.cleaned_data["html"]
|
||||
body = body.replace("\r", "")
|
||||
result = "%s<head%s>%s</head>%s<body%s>\n%s</body>%s" % (preheader, headerargs, head, postheader, bodyargs, body, postbody)
|
||||
|
||||
cwd = filepath.parent
|
||||
filename = filepath.name
|
||||
git = settings.GIT
|
||||
# GIT see also core/models/cave.py writetrogglefile()
|
||||
# GIT see also core/views/uploads.py dwgupload()
|
||||
try:
|
||||
with open(filepath, "w") as f:
|
||||
print(f'WRITING{cwd}---{filename} ')
|
||||
# as the wsgi process www-data, we have group write-access but are not owner, so cannot chmod.
|
||||
# os.chmod(filepath, 0o664) # set file permissions to rw-rw-r--
|
||||
f.write(result)
|
||||
except PermissionError:
|
||||
message = f'CANNOT save this file.\nPERMISSIONS incorrectly set on server for this file {filename}. Ask a nerd to fix this.'
|
||||
return render(request,'errors/generic.html', {'message': message})
|
||||
|
||||
try:
|
||||
cp_add = subprocess.run([git, "add", filename], cwd=cwd, capture_output=True, text=True)
|
||||
if cp_add.returncode != 0:
|
||||
msgdata = 'Ask a nerd to fix this.\n\n' + cp_add.stderr + '\n\n' + cp_add.stdout + '\n\nreturn code: ' + str(cp_add.returncode)
|
||||
message = f'CANNOT git on server for this file {filename}. Edits saved but not added to git.\n\n' + msgdata
|
||||
return render(request,'errors/generic.html', {'message': message})
|
||||
|
||||
cp_commit = subprocess.run([git, "commit", "-m", f'Troggle online: Edit this page - {filename}'], cwd=cwd, capture_output=True, text=True)
|
||||
# This produces return code = 1 if it commits OK, but when the repo still needs to be pushed to origin/expoweb
|
||||
if cp_commit.returncode != 0 and cp_commit.stdout != 'nothing to commit, working tree clean':
|
||||
msgdata = 'Ask a nerd to fix this.\n\n' + cp_commit.stderr + '\n\n' + cp_commit.stdout + '\n\nreturn code: ' + str(cp_commit.returncode)
|
||||
message = f'Error code with git on server for this file {filename}. Edits saved, added to git, but NOT committed.\n\n' + msgdata
|
||||
return render(request,'errors/generic.html', {'message': message})
|
||||
|
||||
except subprocess.SubprocessError:
|
||||
message = f'CANNOT git on server for this file {filename}. Subprocess error. Edits not saved.\nAsk a nerd to fix this.'
|
||||
return render(request,'errors/generic.html', {'message': message})
|
||||
|
||||
return HttpResponseRedirect(reverse('expopage', args=[path])) # Redirect after POST
|
||||
else:
|
||||
if filefound:
|
||||
m = re.search(r"<title>(.*)</title>", head, re.DOTALL + re.IGNORECASE)
|
||||
if m:
|
||||
title, = m.groups()
|
||||
else:
|
||||
title = ""
|
||||
pageform = ExpoPageForm({"html": body, "title": title})
|
||||
else:
|
||||
body = "### File not found ###\n" + str(filepath)
|
||||
pageform = ExpoPageForm({"html": body, "title": "Missing"})
|
||||
return render(request, 'editexpopage.html', {'path': path, 'form': pageform, })
|
||||
|
||||
class ExpoPageForm(forms.Form):
|
||||
'''The form used by the editexpopage function
|
||||
'''
|
||||
title = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
|
||||
html = forms.CharField(widget=forms.Textarea(attrs={"cols":80, "rows":20}))
|
||||
|
@ -1,173 +1,173 @@
|
||||
import datetime
|
||||
import os.path
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
|
||||
import django.db.models
|
||||
from django.db.models import Min, Max
|
||||
from django.shortcuts import render
|
||||
from django.template import Context, loader
|
||||
from django.template.defaultfilters import slugify
|
||||
from django.utils import timezone
|
||||
#from django.views.generic.list import ListView
|
||||
|
||||
from troggle.core.models.troggle import Expedition, Person, PersonExpedition, DataIssue
|
||||
from troggle.core.models.caves import Cave, LogbookEntry, Entrance
|
||||
from troggle.core.models.survex import SurvexBlock, SurvexStation
|
||||
|
||||
import troggle.settings as settings
|
||||
|
||||
'''Very simple report pages summarizing data about the whole set of expeditions and of
|
||||
the status of data inconsistencies
|
||||
'''
|
||||
|
||||
def pathsreport(request):
|
||||
pathsdict = OrderedDict()
|
||||
try:
|
||||
pathsdict = {
|
||||
# "BOGUS" : str( settings.BOGUS),
|
||||
"JSLIB_URL" : str( settings.JSLIB_URL),
|
||||
"JSLIB_ROOT" : str( settings.JSLIB_ROOT),
|
||||
# "CSSLIB_URL" : str( settings.CSSLIB_URL),
|
||||
"CAVEDESCRIPTIONS" : str( settings.CAVEDESCRIPTIONS),
|
||||
"DIR_ROOT" : str( settings.DIR_ROOT),
|
||||
"ENTRANCEDESCRIPTIONS" : str( settings.ENTRANCEDESCRIPTIONS),
|
||||
"EXPOUSER_EMAIL" : str( settings.EXPOUSER_EMAIL),
|
||||
"EXPOUSERPASS" : str("<redacted>"),
|
||||
"EXPOUSER" : str( settings.EXPOUSER),
|
||||
"EXPOWEB" : str( settings.EXPOWEB),
|
||||
"EXPOWEB_URL" : str( settings.EXPOWEB_URL),
|
||||
"FILES" : str( settings.FILES),
|
||||
"LIBDIR" : str( settings.LIBDIR),
|
||||
"LOGFILE" : str( settings.LOGFILE),
|
||||
"LOGIN_REDIRECT_URL" : str( settings.LOGIN_REDIRECT_URL),
|
||||
"MEDIA_ROOT" : str( settings.MEDIA_ROOT),
|
||||
"MEDIA_URL" : str( settings.MEDIA_URL),
|
||||
"PHOTOS_URL" : str( settings.PHOTOS_URL),
|
||||
"PYTHON_PATH" : str( settings.PYTHON_PATH),
|
||||
"REPOS_ROOT_PATH" : str( settings.REPOS_ROOT_PATH),
|
||||
"ROOT_URLCONF" : str( settings.ROOT_URLCONF),
|
||||
"STATIC_URL" : str( settings.STATIC_URL),
|
||||
"SURVEX_DATA" : str( settings.SURVEX_DATA),
|
||||
"SURVEY_SCANS" : str( settings.SURVEY_SCANS),
|
||||
"SURVEYS" : str( settings.SURVEYS),
|
||||
"SURVEYS_URL" : str( settings.SURVEYS_URL),
|
||||
"SURVEXPORT" : str( settings.SURVEXPORT),
|
||||
"DRAWINGS_DATA" : str( settings.DRAWINGS_DATA),
|
||||
"URL_ROOT" : str( settings.URL_ROOT)
|
||||
}
|
||||
except:
|
||||
pathsdict["! EXCEPTION !"] = "missing or exta string constant in troggle/settings"
|
||||
|
||||
pathstype = OrderedDict()
|
||||
try:
|
||||
pathstype = {
|
||||
# "BOGUS" : type(settings.BOGUS),
|
||||
"JSLIB_URL" : type(settings.JSLIB_URL),
|
||||
"JSLIB_ROOT" : type( settings.JSLIB_ROOT),
|
||||
# "CSSLIB_URL" : type(settings.CSSLIB_URL),
|
||||
"CAVEDESCRIPTIONS" : type(settings.CAVEDESCRIPTIONS),
|
||||
"DIR_ROOT" : type(settings.DIR_ROOT),
|
||||
"ENTRANCEDESCRIPTIONS" : type(settings.ENTRANCEDESCRIPTIONS),
|
||||
"EXPOUSER_EMAIL" : type(settings.EXPOUSER_EMAIL),
|
||||
"EXPOUSERPASS" : type(settings.EXPOUSERPASS),
|
||||
"EXPOUSER" : type(settings.EXPOUSER),
|
||||
"EXPOWEB" : type(settings.EXPOWEB),
|
||||
"EXPOWEB_URL" : type(settings.EXPOWEB_URL),
|
||||
"FILES" : type(settings.FILES),
|
||||
"LIBDIR" : type( settings.LIBDIR),
|
||||
"LOGFILE" : type(settings.LOGFILE),
|
||||
"LOGIN_REDIRECT_URL" : type(settings.LOGIN_REDIRECT_URL),
|
||||
"MEDIA_ROOT" : type(settings.MEDIA_ROOT),
|
||||
"MEDIA_URL" : type(settings.MEDIA_URL),
|
||||
"PHOTOS_URL" : type(settings.PHOTOS_URL),
|
||||
"PYTHON_PATH" : type(settings.PYTHON_PATH),
|
||||
"REPOS_ROOT_PATH" : type(settings.REPOS_ROOT_PATH),
|
||||
"ROOT_URLCONF" : type(settings.ROOT_URLCONF),
|
||||
"STATIC_URL" : type(settings.STATIC_URL),
|
||||
"SURVEX_DATA" : type(settings.SURVEX_DATA),
|
||||
"SURVEY_SCANS" : type(settings.SURVEY_SCANS),
|
||||
"SURVEYS" : type(settings.SURVEYS),
|
||||
"SURVEYS_URL" : type(settings.SURVEYS_URL),
|
||||
"SURVEXPORT" : type(settings.SURVEXPORT),
|
||||
"DRAWINGS_DATA" : type(settings.DRAWINGS_DATA),
|
||||
"URL_ROOT" : type(settings.URL_ROOT)
|
||||
}
|
||||
except:
|
||||
pathstype["! EXCEPTION !"] = "missing or exta string constant in troggle/settings"
|
||||
raise
|
||||
|
||||
# settings are unique by paths are not
|
||||
ncodes = len(pathsdict)
|
||||
bycodeslist = sorted(pathsdict.items()) # a list of tuples
|
||||
bycodeslist2 = []
|
||||
|
||||
for k, p in bycodeslist:
|
||||
bycodeslist2.append((k, p, str(pathstype[k])))
|
||||
|
||||
bypaths = sorted(pathsdict.values()) # a list
|
||||
bypathslist = []
|
||||
|
||||
for p in bypaths:
|
||||
for k in pathsdict.keys():
|
||||
if pathsdict[k] == p:
|
||||
bypathslist.append((p, k, str(pathstype[k])))
|
||||
del pathsdict[k]
|
||||
break
|
||||
|
||||
return render(request, 'pathsreport.html', {
|
||||
"pathsdict":pathsdict,
|
||||
"bycodeslist":bycodeslist2,
|
||||
"bypathslist":bypathslist,
|
||||
"ncodes":ncodes})
|
||||
|
||||
def stats(request):
|
||||
statsDict={}
|
||||
statsDict['expoCount'] = "{:,}".format(Expedition.objects.count())
|
||||
statsDict['caveCount'] = "{:,}".format(Cave.objects.count())
|
||||
statsDict['personCount'] = "{:,}".format(Person.objects.count())
|
||||
statsDict['logbookEntryCount'] = "{:,}".format(LogbookEntry.objects.count())
|
||||
|
||||
legsbyexpo = [ ]
|
||||
addupsurvexlength = 0
|
||||
for expedition in Expedition.objects.all():
|
||||
survexblocks = expedition.survexblock_set.all()
|
||||
legsyear=0
|
||||
survexleglength = 0.0
|
||||
for survexblock in survexblocks:
|
||||
survexleglength += survexblock.legslength
|
||||
try:
|
||||
legsyear += int(survexblock.legsall)
|
||||
except:
|
||||
pass
|
||||
addupsurvexlength += survexleglength
|
||||
legsbyexpo.append((expedition, {"nsurvexlegs": "{:,}".format(legsyear),
|
||||
"survexleglength":"{:,.0f}".format(survexleglength)}))
|
||||
legsbyexpo.reverse()
|
||||
|
||||
renderDict = {**statsDict, **{ "addupsurvexlength":addupsurvexlength/1000, "legsbyexpo":legsbyexpo }} # new syntax
|
||||
return render(request,'statistics.html', renderDict)
|
||||
|
||||
def dataissues(request):
|
||||
'''Each issue has a parser, a message and a url linking to the offending object after loading
|
||||
'''
|
||||
def myFunc(di):
|
||||
return di.parser.lower() + di.message.lower()
|
||||
|
||||
dilist = list(DataIssue.objects.all())
|
||||
dilist.sort(key = myFunc)
|
||||
|
||||
return render(request,'dataissues.html', {'didict': dilist})
|
||||
|
||||
def eastings(request):
|
||||
'''report each Northing/Easting pair wherever recorded
|
||||
'''
|
||||
ents = []
|
||||
entrances = Entrance.objects.all()
|
||||
for e in entrances:
|
||||
if e.easting or e.northing:
|
||||
ents.append(e)
|
||||
|
||||
stations = SurvexStation.objects.all()
|
||||
|
||||
return render(request,'eastings.html', {'ents': ents, 'stations': stations})
|
||||
import datetime
|
||||
import os.path
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
|
||||
import django.db.models
|
||||
from django.db.models import Min, Max
|
||||
from django.shortcuts import render
|
||||
from django.template import Context, loader
|
||||
from django.template.defaultfilters import slugify
|
||||
from django.utils import timezone
|
||||
#from django.views.generic.list import ListView
|
||||
|
||||
from troggle.core.models.troggle import Expedition, Person, PersonExpedition, DataIssue
|
||||
from troggle.core.models.caves import Cave, LogbookEntry, Entrance
|
||||
from troggle.core.models.survex import SurvexBlock, SurvexStation
|
||||
|
||||
import troggle.settings as settings
|
||||
|
||||
'''Very simple report pages summarizing data about the whole set of expeditions and of
|
||||
the status of data inconsistencies
|
||||
'''
|
||||
|
||||
def pathsreport(request):
|
||||
pathsdict = OrderedDict()
|
||||
try:
|
||||
pathsdict = {
|
||||
# "BOGUS" : str( settings.BOGUS),
|
||||
"JSLIB_URL" : str( settings.JSLIB_URL),
|
||||
"JSLIB_ROOT" : str( settings.JSLIB_ROOT),
|
||||
# "CSSLIB_URL" : str( settings.CSSLIB_URL),
|
||||
"CAVEDESCRIPTIONS" : str( settings.CAVEDESCRIPTIONS),
|
||||
"DIR_ROOT" : str( settings.DIR_ROOT),
|
||||
"ENTRANCEDESCRIPTIONS" : str( settings.ENTRANCEDESCRIPTIONS),
|
||||
"EXPOUSER_EMAIL" : str( settings.EXPOUSER_EMAIL),
|
||||
"EXPOUSERPASS" : str("<redacted>"),
|
||||
"EXPOUSER" : str( settings.EXPOUSER),
|
||||
"EXPOWEB" : str( settings.EXPOWEB),
|
||||
"EXPOWEB_URL" : str( settings.EXPOWEB_URL),
|
||||
"FILES" : str( settings.FILES),
|
||||
"LIBDIR" : str( settings.LIBDIR),
|
||||
"LOGFILE" : str( settings.LOGFILE),
|
||||
"LOGIN_REDIRECT_URL" : str( settings.LOGIN_REDIRECT_URL),
|
||||
"MEDIA_ROOT" : str( settings.MEDIA_ROOT),
|
||||
"MEDIA_URL" : str( settings.MEDIA_URL),
|
||||
"PHOTOS_URL" : str( settings.PHOTOS_URL),
|
||||
"PYTHON_PATH" : str( settings.PYTHON_PATH),
|
||||
"REPOS_ROOT_PATH" : str( settings.REPOS_ROOT_PATH),
|
||||
"ROOT_URLCONF" : str( settings.ROOT_URLCONF),
|
||||
"STATIC_URL" : str( settings.STATIC_URL),
|
||||
"SURVEX_DATA" : str( settings.SURVEX_DATA),
|
||||
"SURVEY_SCANS" : str( settings.SURVEY_SCANS),
|
||||
"SURVEYS" : str( settings.SURVEYS),
|
||||
"SURVEYS_URL" : str( settings.SURVEYS_URL),
|
||||
"SURVEXPORT" : str( settings.SURVEXPORT),
|
||||
"DRAWINGS_DATA" : str( settings.DRAWINGS_DATA),
|
||||
"URL_ROOT" : str( settings.URL_ROOT)
|
||||
}
|
||||
except:
|
||||
pathsdict["! EXCEPTION !"] = "missing or exta string constant in troggle/settings"
|
||||
|
||||
pathstype = OrderedDict()
|
||||
try:
|
||||
pathstype = {
|
||||
# "BOGUS" : type(settings.BOGUS),
|
||||
"JSLIB_URL" : type(settings.JSLIB_URL),
|
||||
"JSLIB_ROOT" : type( settings.JSLIB_ROOT),
|
||||
# "CSSLIB_URL" : type(settings.CSSLIB_URL),
|
||||
"CAVEDESCRIPTIONS" : type(settings.CAVEDESCRIPTIONS),
|
||||
"DIR_ROOT" : type(settings.DIR_ROOT),
|
||||
"ENTRANCEDESCRIPTIONS" : type(settings.ENTRANCEDESCRIPTIONS),
|
||||
"EXPOUSER_EMAIL" : type(settings.EXPOUSER_EMAIL),
|
||||
"EXPOUSERPASS" : type(settings.EXPOUSERPASS),
|
||||
"EXPOUSER" : type(settings.EXPOUSER),
|
||||
"EXPOWEB" : type(settings.EXPOWEB),
|
||||
"EXPOWEB_URL" : type(settings.EXPOWEB_URL),
|
||||
"FILES" : type(settings.FILES),
|
||||
"LIBDIR" : type( settings.LIBDIR),
|
||||
"LOGFILE" : type(settings.LOGFILE),
|
||||
"LOGIN_REDIRECT_URL" : type(settings.LOGIN_REDIRECT_URL),
|
||||
"MEDIA_ROOT" : type(settings.MEDIA_ROOT),
|
||||
"MEDIA_URL" : type(settings.MEDIA_URL),
|
||||
"PHOTOS_URL" : type(settings.PHOTOS_URL),
|
||||
"PYTHON_PATH" : type(settings.PYTHON_PATH),
|
||||
"REPOS_ROOT_PATH" : type(settings.REPOS_ROOT_PATH),
|
||||
"ROOT_URLCONF" : type(settings.ROOT_URLCONF),
|
||||
"STATIC_URL" : type(settings.STATIC_URL),
|
||||
"SURVEX_DATA" : type(settings.SURVEX_DATA),
|
||||
"SURVEY_SCANS" : type(settings.SURVEY_SCANS),
|
||||
"SURVEYS" : type(settings.SURVEYS),
|
||||
"SURVEYS_URL" : type(settings.SURVEYS_URL),
|
||||
"SURVEXPORT" : type(settings.SURVEXPORT),
|
||||
"DRAWINGS_DATA" : type(settings.DRAWINGS_DATA),
|
||||
"URL_ROOT" : type(settings.URL_ROOT)
|
||||
}
|
||||
except:
|
||||
pathstype["! EXCEPTION !"] = "missing or exta string constant in troggle/settings"
|
||||
raise
|
||||
|
||||
# settings are unique by paths are not
|
||||
ncodes = len(pathsdict)
|
||||
bycodeslist = sorted(pathsdict.items()) # a list of tuples
|
||||
bycodeslist2 = []
|
||||
|
||||
for k, p in bycodeslist:
|
||||
bycodeslist2.append((k, p, str(pathstype[k])))
|
||||
|
||||
bypaths = sorted(pathsdict.values()) # a list
|
||||
bypathslist = []
|
||||
|
||||
for p in bypaths:
|
||||
for k in pathsdict.keys():
|
||||
if pathsdict[k] == p:
|
||||
bypathslist.append((p, k, str(pathstype[k])))
|
||||
del pathsdict[k]
|
||||
break
|
||||
|
||||
return render(request, 'pathsreport.html', {
|
||||
"pathsdict":pathsdict,
|
||||
"bycodeslist":bycodeslist2,
|
||||
"bypathslist":bypathslist,
|
||||
"ncodes":ncodes})
|
||||
|
||||
def stats(request):
|
||||
statsDict={}
|
||||
statsDict['expoCount'] = "{:,}".format(Expedition.objects.count())
|
||||
statsDict['caveCount'] = "{:,}".format(Cave.objects.count())
|
||||
statsDict['personCount'] = "{:,}".format(Person.objects.count())
|
||||
statsDict['logbookEntryCount'] = "{:,}".format(LogbookEntry.objects.count())
|
||||
|
||||
legsbyexpo = [ ]
|
||||
addupsurvexlength = 0
|
||||
for expedition in Expedition.objects.all():
|
||||
survexblocks = expedition.survexblock_set.all()
|
||||
legsyear=0
|
||||
survexleglength = 0.0
|
||||
for survexblock in survexblocks:
|
||||
survexleglength += survexblock.legslength
|
||||
try:
|
||||
legsyear += int(survexblock.legsall)
|
||||
except:
|
||||
pass
|
||||
addupsurvexlength += survexleglength
|
||||
legsbyexpo.append((expedition, {"nsurvexlegs": "{:,}".format(legsyear),
|
||||
"survexleglength":"{:,.0f}".format(survexleglength)}))
|
||||
legsbyexpo.reverse()
|
||||
|
||||
renderDict = {**statsDict, **{ "addupsurvexlength":addupsurvexlength/1000, "legsbyexpo":legsbyexpo }} # new syntax
|
||||
return render(request,'statistics.html', renderDict)
|
||||
|
||||
def dataissues(request):
|
||||
'''Each issue has a parser, a message and a url linking to the offending object after loading
|
||||
'''
|
||||
def myFunc(di):
|
||||
return di.parser.lower() + di.message.lower()
|
||||
|
||||
dilist = list(DataIssue.objects.all())
|
||||
dilist.sort(key = myFunc)
|
||||
|
||||
return render(request,'dataissues.html', {'didict': dilist})
|
||||
|
||||
def eastings(request):
|
||||
'''report each Northing/Easting pair wherever recorded
|
||||
'''
|
||||
ents = []
|
||||
entrances = Entrance.objects.all()
|
||||
for e in entrances:
|
||||
if e.easting or e.northing:
|
||||
ents.append(e)
|
||||
|
||||
stations = SurvexStation.objects.all()
|
||||
|
||||
return render(request,'eastings.html', {'ents': ents, 'stations': stations})
|
||||
|
@ -1,164 +1,164 @@
|
||||
From: <Saved by Blink>
|
||||
Snapshot-Content-Location: https://aardgoose.github.io/CaveView.js/installation.html
|
||||
Subject: CaveView installation
|
||||
Date: Sun, 24 Oct 2021 15:46:19 -0000
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/related;
|
||||
type="text/html";
|
||||
boundary="----MultipartBoundary--eCFBXfFmJiPIUIDdJDuaiHRJfZ59xqA99QxmIcmsBZ----"
|
||||
|
||||
|
||||
------MultipartBoundary--eCFBXfFmJiPIUIDdJDuaiHRJfZ59xqA99QxmIcmsBZ----
|
||||
Content-Type: text/html
|
||||
Content-ID: <frame-F25506009C17180F1D15EDA63865EFC8@mhtml.blink>
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Location: https://aardgoose.github.io/CaveView.js/installation.html
|
||||
|
||||
<!DOCTYPE html><html xmlns=3D"http://www.w3.org/1999/xhtml" xml:lang=3D"en-=
|
||||
gb" lang=3D"en-gb" dir=3D"ltr"><head><meta http-equiv=3D"Content-Type" cont=
|
||||
ent=3D"text/html; charset=3DUTF-8">
|
||||
<title>CaveView installation</title>
|
||||
=09
|
||||
<link type=3D"text/css" href=3D"https://aardgoose.github.io/CaveView.js/do=
|
||||
c.css" rel=3D"stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Cave View - installation instructions - V2 API</h1>
|
||||
<h2>Install CaveView files</h2>
|
||||
<p>A zip archive containing the required files for the latest release are =
|
||||
<a href=3D"https://github.com/aardgoose/CaveView.js/releases">here</a>.</p>
|
||||
<p>There is no need to build the JavaScript application from source files =
|
||||
unless you would like to modify the application.</p>
|
||||
<p>Unzip the archive in a convenient location on your web server </p>
|
||||
<h2>Using in a web page</h2>
|
||||
|
||||
<p>CaveView requires two files to be included in the page. Replace the plac=
|
||||
eholder %path% with the path to the unzipped files on the server in the fol=
|
||||
lowing examples.</p><p>
|
||||
|
||||
</p><h3>caveview.css</h3>
|
||||
<p>The side panel interface and on screen indicators are styled with cavevi=
|
||||
ew.css. Include this in the <strong>head</strong> section of the page.</p>
|
||||
|
||||
<pre> <link type=3D"text/css" href=3D"%path%/CaveView/css/caveview.css" =
|
||||
rel=3D"stylesheet" /></pre>
|
||||
|
||||
<h3>CaveView.js</h3>
|
||||
|
||||
<p>The CaveView application is provided in one javascript file. Include thi=
|
||||
s in the <strong>body</strong> section of the page. <strong>NOTE: The filen=
|
||||
ame has changed for the V2 API.</strong></p>
|
||||
|
||||
<pre> <script type=3D"text/javascript" src=3D"%path%/CaveView/js/CaveVie=
|
||||
w2.js" ></script></pre>
|
||||
|
||||
<h3>Add a container element</h3>
|
||||
|
||||
<p>Add an empty block element to the page, with a suitable <strong>id</stro=
|
||||
ng> attribute. This contains the application, and be sized as required. For=
|
||||
example a <strong>div</strong> element:</p>
|
||||
|
||||
<pre><div id=3D'% element-id %' ></div></pre>
|
||||
|
||||
<h3>Create a script to run the application</h3>
|
||||
|
||||
<p>The application can be loaded using javascript, typically using an load =
|
||||
event handler. Replace the placeholder %...% elements with values appropria=
|
||||
te for your site.</p>
|
||||
<pre><script type=3D"text/javascript" >
|
||||
|
||||
function onLoad () {
|
||||
|
||||
// display the user interface - and a blank canvas
|
||||
|
||||
// the configuration object specifies the location of CaveView, surveys a=
|
||||
nd terrain files
|
||||
|
||||
var viewer =3D new CV2.CaveViewer( '% element-id %', {
|
||||
home: '% location of the unzipped CaveView directory on the survey %',
|
||||
surveyDirectory: '% location of the survey files on the server %',
|
||||
terrainDirectory: '% location of the terrain files on the server %'
|
||||
} );
|
||||
|
||||
// if using the full user interface (UI)
|
||||
|
||||
var ui =3D new CV2.CaveViewUI( viewer );
|
||||
|
||||
// load a single survey to display
|
||||
|
||||
ui.loadCave( '% survey filename %' );
|
||||
|
||||
// or without the user interface
|
||||
|
||||
viewer.loadCave( '% survey filename %' );
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
||||
<p>alternatively provide a list of surveys to display, by replacing the loa=
|
||||
dCave() function call with loadCaveList() :</p>
|
||||
|
||||
<pre> ui.loadCaveList( [ '% survey filename 1 %', '% survey filename 2 %', =
|
||||
'% survey filename 3 %' ] );
|
||||
</pre>
|
||||
|
||||
<p>This can be automatically executed on page load by including a page load=
|
||||
handler in the page <strong>body</strong> tag:</p>
|
||||
<pre><body onload=3D"onload();" ></pre>
|
||||
|
||||
<p>CaveView should now display when the page is viewed.</p>
|
||||
<p>The example files included demonstrate using multiple viewers on a page,
|
||||
changing the default view settings and altering the appearance of the viewe=
|
||||
r.</p>
|
||||
|
||||
<h3>Removal</h3>
|
||||
|
||||
<p>To remove the viewer from a page and reclaim memory used promptly:</p>
|
||||
<pre> ui.dispose();
|
||||
ui =3D null;
|
||||
viewer =3D null;
|
||||
</pre>
|
||||
<p>Or if not using the UI, just the viewer:</p>
|
||||
<pre> viewer.dispose();
|
||||
viewer =3D null;
|
||||
</pre>
|
||||
|
||||
|
||||
</body></html>
|
||||
------MultipartBoundary--eCFBXfFmJiPIUIDdJDuaiHRJfZ59xqA99QxmIcmsBZ----
|
||||
Content-Type: text/css
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Location: https://aardgoose.github.io/CaveView.js/doc.css
|
||||
|
||||
@charset "utf-8";
|
||||
|
||||
h1, h2 { margin: 0px 16px 1em; }
|
||||
|
||||
h3, h4, h5, p, pre, dl { margin-left: 32px; margin-right: 32px; }
|
||||
|
||||
h2 { border-bottom: 2px solid gray; }
|
||||
|
||||
h3 { color: navy; }
|
||||
|
||||
h4 { margin-top: 2em; background-color: rgb(238, 238, 238); padding: 3px 2p=
|
||||
x 1px; }
|
||||
|
||||
* { font-family: sans-serif; }
|
||||
|
||||
pre { font-family: monospace; font-weight: bold; background-color: rgb(238,=
|
||||
238, 238); padding: 8px; }
|
||||
|
||||
dd > span { display: inline-block; padding: 0px 2px; margin-right: 5px; bac=
|
||||
kground: rgb(238, 238, 238); }
|
||||
|
||||
dd > span::before { content: "["; }
|
||||
|
||||
dd > span::after { content: "]"; }
|
||||
|
||||
dt { margin-bottom: 0.5em; font-weight: bold; color: rgb(102, 102, 102); pa=
|
||||
dding-left: 16px; }
|
||||
|
||||
dd { margin-bottom: 1em; }
|
||||
------MultipartBoundary--eCFBXfFmJiPIUIDdJDuaiHRJfZ59xqA99QxmIcmsBZ------
|
||||
From: <Saved by Blink>
|
||||
Snapshot-Content-Location: https://aardgoose.github.io/CaveView.js/installation.html
|
||||
Subject: CaveView installation
|
||||
Date: Sun, 24 Oct 2021 15:46:19 -0000
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/related;
|
||||
type="text/html";
|
||||
boundary="----MultipartBoundary--eCFBXfFmJiPIUIDdJDuaiHRJfZ59xqA99QxmIcmsBZ----"
|
||||
|
||||
|
||||
------MultipartBoundary--eCFBXfFmJiPIUIDdJDuaiHRJfZ59xqA99QxmIcmsBZ----
|
||||
Content-Type: text/html
|
||||
Content-ID: <frame-F25506009C17180F1D15EDA63865EFC8@mhtml.blink>
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Location: https://aardgoose.github.io/CaveView.js/installation.html
|
||||
|
||||
<!DOCTYPE html><html xmlns=3D"http://www.w3.org/1999/xhtml" xml:lang=3D"en-=
|
||||
gb" lang=3D"en-gb" dir=3D"ltr"><head><meta http-equiv=3D"Content-Type" cont=
|
||||
ent=3D"text/html; charset=3DUTF-8">
|
||||
<title>CaveView installation</title>
|
||||
=09
|
||||
<link type=3D"text/css" href=3D"https://aardgoose.github.io/CaveView.js/do=
|
||||
c.css" rel=3D"stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Cave View - installation instructions - V2 API</h1>
|
||||
<h2>Install CaveView files</h2>
|
||||
<p>A zip archive containing the required files for the latest release are =
|
||||
<a href=3D"https://github.com/aardgoose/CaveView.js/releases">here</a>.</p>
|
||||
<p>There is no need to build the JavaScript application from source files =
|
||||
unless you would like to modify the application.</p>
|
||||
<p>Unzip the archive in a convenient location on your web server </p>
|
||||
<h2>Using in a web page</h2>
|
||||
|
||||
<p>CaveView requires two files to be included in the page. Replace the plac=
|
||||
eholder %path% with the path to the unzipped files on the server in the fol=
|
||||
lowing examples.</p><p>
|
||||
|
||||
</p><h3>caveview.css</h3>
|
||||
<p>The side panel interface and on screen indicators are styled with cavevi=
|
||||
ew.css. Include this in the <strong>head</strong> section of the page.</p>
|
||||
|
||||
<pre> <link type=3D"text/css" href=3D"%path%/CaveView/css/caveview.css" =
|
||||
rel=3D"stylesheet" /></pre>
|
||||
|
||||
<h3>CaveView.js</h3>
|
||||
|
||||
<p>The CaveView application is provided in one javascript file. Include thi=
|
||||
s in the <strong>body</strong> section of the page. <strong>NOTE: The filen=
|
||||
ame has changed for the V2 API.</strong></p>
|
||||
|
||||
<pre> <script type=3D"text/javascript" src=3D"%path%/CaveView/js/CaveVie=
|
||||
w2.js" ></script></pre>
|
||||
|
||||
<h3>Add a container element</h3>
|
||||
|
||||
<p>Add an empty block element to the page, with a suitable <strong>id</stro=
|
||||
ng> attribute. This contains the application, and be sized as required. For=
|
||||
example a <strong>div</strong> element:</p>
|
||||
|
||||
<pre><div id=3D'% element-id %' ></div></pre>
|
||||
|
||||
<h3>Create a script to run the application</h3>
|
||||
|
||||
<p>The application can be loaded using javascript, typically using an load =
|
||||
event handler. Replace the placeholder %...% elements with values appropria=
|
||||
te for your site.</p>
|
||||
<pre><script type=3D"text/javascript" >
|
||||
|
||||
function onLoad () {
|
||||
|
||||
// display the user interface - and a blank canvas
|
||||
|
||||
// the configuration object specifies the location of CaveView, surveys a=
|
||||
nd terrain files
|
||||
|
||||
var viewer =3D new CV2.CaveViewer( '% element-id %', {
|
||||
home: '% location of the unzipped CaveView directory on the survey %',
|
||||
surveyDirectory: '% location of the survey files on the server %',
|
||||
terrainDirectory: '% location of the terrain files on the server %'
|
||||
} );
|
||||
|
||||
// if using the full user interface (UI)
|
||||
|
||||
var ui =3D new CV2.CaveViewUI( viewer );
|
||||
|
||||
// load a single survey to display
|
||||
|
||||
ui.loadCave( '% survey filename %' );
|
||||
|
||||
// or without the user interface
|
||||
|
||||
viewer.loadCave( '% survey filename %' );
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
||||
<p>alternatively provide a list of surveys to display, by replacing the loa=
|
||||
dCave() function call with loadCaveList() :</p>
|
||||
|
||||
<pre> ui.loadCaveList( [ '% survey filename 1 %', '% survey filename 2 %', =
|
||||
'% survey filename 3 %' ] );
|
||||
</pre>
|
||||
|
||||
<p>This can be automatically executed on page load by including a page load=
|
||||
handler in the page <strong>body</strong> tag:</p>
|
||||
<pre><body onload=3D"onload();" ></pre>
|
||||
|
||||
<p>CaveView should now display when the page is viewed.</p>
|
||||
<p>The example files included demonstrate using multiple viewers on a page,
|
||||
changing the default view settings and altering the appearance of the viewe=
|
||||
r.</p>
|
||||
|
||||
<h3>Removal</h3>
|
||||
|
||||
<p>To remove the viewer from a page and reclaim memory used promptly:</p>
|
||||
<pre> ui.dispose();
|
||||
ui =3D null;
|
||||
viewer =3D null;
|
||||
</pre>
|
||||
<p>Or if not using the UI, just the viewer:</p>
|
||||
<pre> viewer.dispose();
|
||||
viewer =3D null;
|
||||
</pre>
|
||||
|
||||
|
||||
</body></html>
|
||||
------MultipartBoundary--eCFBXfFmJiPIUIDdJDuaiHRJfZ59xqA99QxmIcmsBZ----
|
||||
Content-Type: text/css
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Location: https://aardgoose.github.io/CaveView.js/doc.css
|
||||
|
||||
@charset "utf-8";
|
||||
|
||||
h1, h2 { margin: 0px 16px 1em; }
|
||||
|
||||
h3, h4, h5, p, pre, dl { margin-left: 32px; margin-right: 32px; }
|
||||
|
||||
h2 { border-bottom: 2px solid gray; }
|
||||
|
||||
h3 { color: navy; }
|
||||
|
||||
h4 { margin-top: 2em; background-color: rgb(238, 238, 238); padding: 3px 2p=
|
||||
x 1px; }
|
||||
|
||||
* { font-family: sans-serif; }
|
||||
|
||||
pre { font-family: monospace; font-weight: bold; background-color: rgb(238,=
|
||||
238, 238); padding: 8px; }
|
||||
|
||||
dd > span { display: inline-block; padding: 0px 2px; margin-right: 5px; bac=
|
||||
kground: rgb(238, 238, 238); }
|
||||
|
||||
dd > span::before { content: "["; }
|
||||
|
||||
dd > span::after { content: "]"; }
|
||||
|
||||
dt { margin-bottom: 0.5em; font-weight: bold; color: rgb(102, 102, 102); pa=
|
||||
dding-left: 16px; }
|
||||
|
||||
dd { margin-bottom: 1em; }
|
||||
------MultipartBoundary--eCFBXfFmJiPIUIDdJDuaiHRJfZ59xqA99QxmIcmsBZ------
|
||||
|
@ -1,2 +1,2 @@
|
||||
[InternetShortcut]
|
||||
URL=https://github.com/aardgoose/CaveView.js/releases
|
||||
[InternetShortcut]
|
||||
URL=https://github.com/aardgoose/CaveView.js/releases
|
||||
|
@ -1,2 +1,2 @@
|
||||
[InternetShortcut]
|
||||
URL=https://aardgoose.github.io/CaveView.js/
|
||||
[InternetShortcut]
|
||||
URL=https://aardgoose.github.io/CaveView.js/
|
||||
|
Loading…
Reference in New Issue
Block a user