diff options
author | Philip Sargent <philip.sargent@klebos.com> | 2022-04-05 10:37:31 +0300 |
---|---|---|
committer | Philip Sargent <philip.sargent@klebos.com> | 2022-04-05 10:38:52 +0300 |
commit | 71ed0815cc2393f68a9c2e8eeeadbe0bed619feb (patch) | |
tree | 7a3aa7522f8c0926b8429521321a94f8b4d9ca7e /core/views | |
parent | 41b2bcee4febf79d90ca83318a8d3110e46951ac (diff) | |
download | troggle-71ed0815cc2393f68a9c2e8eeeadbe0bed619feb.tar.gz troggle-71ed0815cc2393f68a9c2e8eeeadbe0bed619feb.tar.bz2 troggle-71ed0815cc2393f68a9c2e8eeeadbe0bed619feb.zip |
Revert "update oddity with VS Code and WSL2"
This reverts commit 41b2bcee4febf79d90ca83318a8d3110e46951ac.
CR LF != LF issue
Diffstat (limited to 'core/views')
-rw-r--r-- | core/views/expo.py | 736 | ||||
-rw-r--r-- | core/views/statistics.py | 346 |
2 files changed, 541 insertions, 541 deletions
diff --git a/core/views/expo.py b/core/views/expo.py index 45f588f..2b769db 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 e276f89..ad77199 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}) |