diff options
author | Philip Sargent <philip.sargent@klebos.com> | 2022-04-02 00:03:53 +0300 |
---|---|---|
committer | Philip Sargent <philip.sargent@klebos.com> | 2022-04-02 00:03:53 +0300 |
commit | 41b2bcee4febf79d90ca83318a8d3110e46951ac (patch) | |
tree | f875c799d05fdab9410b473b80d123ecfd6db700 | |
parent | 1f3f60a6a3f0626db40d244f2b7d41c9ede28fb9 (diff) | |
download | troggle-41b2bcee4febf79d90ca83318a8d3110e46951ac.tar.gz troggle-41b2bcee4febf79d90ca83318a8d3110e46951ac.tar.bz2 troggle-41b2bcee4febf79d90ca83318a8d3110e46951ac.zip |
update oddity with VS Code and WSL2
-rw-r--r-- | _deploy/wsl/check-for-later-copy-of-localsettings.WSL.txt | 4 | ||||
-rw-r--r-- | core/views/expo.py | 736 | ||||
-rw-r--r-- | core/views/statistics.py | 346 | ||||
-rw-r--r-- | media/jslib/CaveView installation.mhtml | 328 | ||||
-rw-r--r-- | media/jslib/Releases · aardgoose-CaveView.js · GitHub.url | 4 | ||||
-rw-r--r-- | media/jslib/demo 3d cave viewer.url | 4 |
6 files changed, 711 insertions, 711 deletions
diff --git a/_deploy/wsl/check-for-later-copy-of-localsettings.WSL.txt b/_deploy/wsl/check-for-later-copy-of-localsettings.WSL.txt index 1f6a21f..db557ee 100644 --- a/_deploy/wsl/check-for-later-copy-of-localsettings.WSL.txt +++ b/_deploy/wsl/check-for-later-copy-of-localsettings.WSL.txt @@ -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.
\ No newline at end of file diff --git a/core/views/expo.py b/core/views/expo.py index 2b769db..45f588f 100644 --- a/core/views/expo.py +++ b/core/views/expo.py @@ -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}))
diff --git a/core/views/statistics.py b/core/views/statistics.py index ad77199..e276f89 100644 --- a/core/views/statistics.py +++ b/core/views/statistics.py @@ -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})
diff --git a/media/jslib/CaveView installation.mhtml b/media/jslib/CaveView installation.mhtml index 6558aa9..495e87b 100644 --- a/media/jslib/CaveView installation.mhtml +++ b/media/jslib/CaveView installation.mhtml @@ -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------
diff --git a/media/jslib/Releases · aardgoose-CaveView.js · GitHub.url b/media/jslib/Releases · aardgoose-CaveView.js · GitHub.url index 98f6119..86985f0 100644 --- a/media/jslib/Releases · aardgoose-CaveView.js · GitHub.url +++ b/media/jslib/Releases · aardgoose-CaveView.js · GitHub.url @@ -1,2 +1,2 @@ -[InternetShortcut] -URL=https://github.com/aardgoose/CaveView.js/releases +[InternetShortcut]
+URL=https://github.com/aardgoose/CaveView.js/releases
diff --git a/media/jslib/demo 3d cave viewer.url b/media/jslib/demo 3d cave viewer.url index 7031c42..3272f0d 100644 --- a/media/jslib/demo 3d cave viewer.url +++ b/media/jslib/demo 3d cave viewer.url @@ -1,2 +1,2 @@ -[InternetShortcut] -URL=https://aardgoose.github.io/CaveView.js/ +[InternetShortcut]
+URL=https://aardgoose.github.io/CaveView.js/
|