2
0
mirror of https://expo.survex.com/repositories/troggle/.git synced 2025-12-13 20:57:06 +00:00

Attempt at append_slash, and backtrack.

This commit is contained in:
2025-02-18 19:59:12 +02:00
parent 95190324fb
commit cc06e2e1f4
8 changed files with 73 additions and 53 deletions

View File

@@ -1,6 +1,6 @@
from django.conf import settings
from troggle.core.models.troggle import Expedition
# from troggle.core.models.troggle import Expedition
"""This is the only troggle-specific 'context processor' that troggle uses
in the processing of Django templates

View File

@@ -1,31 +1,48 @@
import pathlib
from django import http
from django.conf import settings
from django.urls import Resolver404, resolve
from django.utils.deprecation import MiddlewareMixin
from troggle import settings
"""Non-standard django middleware is loaded from this file.
"""
todo = """SmartAppendSlashMiddleware(object) Not Working.
It needs re-writing to be compatible with Django v2.0 and later
It needs re-writing. Can we make this work even though we have a catchall url rule ?
"""
class SmartAppendSlashMiddleware(object):
class TroggleAppendSlashMiddleware(MiddlewareMixin):
"""
"SmartAppendSlash" middleware for taking care of URL rewriting.
This middleware appends a missing slash, if:
* the SMART_APPEND_SLASH setting is True
* the URL without the slash does not exist
* the URL with an appended slash does exist.
* the URL without the slash does not exist in urls.py
* the URL with an appended slash does exist in urls.py
Otherwise it won't touch the URL.
MODIFICATION
Since we have a universal catchall url pattern in urls.py, the usual way this works
won't ever trigger adding a slash. So we check for the existence of a file in expoweb,
not the existence of a pattern in urls.py...
but site_media..
but css etc....
CONCLUSION
This technique "works" but would be a maintence nightmare, so DO NOT USE IT
do NOT include
troggle.core.middleware.TroggleAppendSlashMiddleware
in settings.py
"""
def process_request(self, request):
"""Called for every url so return as quickly as possible
Append a slash if SMART_APPEND_SLASH is set, the resulting URL resolves and it doesn't without the /
Append a slash if TROGGLE_APPEND_SLASH is set, the resulting URL resolves and it doesn't without the /
"""
if not settings.SMART_APPEND_SLASH:
if not settings.TROGGLE_APPEND_SLASH:
return None
if request.path.endswith("/"):
@@ -33,16 +50,31 @@ class SmartAppendSlashMiddleware(object):
if request.path.endswith("_edit"):
return None
if request.path.startswith("/"):
relative_path = request.path[1:]
else:
relative_path = request.path
for root in [settings.MEDIA_ROOT, settings.JSLIB_ROOT, settings.EXPOFILES, settings.SCANS_ROOT, settings.PHOTOS_ROOT]:
full_path = root / relative_path
print(f"+++++ MIDDLEWARE checking {root} / {relative_path} ")
if full_path.is_file():
print(f"+++++ MIDDLEWARE It IS a {root} file {full_path=} so use it as-is.")
return None
else:
print(f"+++++ MIDDLEWARE NOT a {root}file {full_path=}")
host = http.HttpRequest.get_host(request)
old_url = [host, request.path]
if _resolves(old_url[1]):
return None
# if _resolves(old_url[1]):
# return None
# So: it does not resolve according to our criteria, i.e. _edit doesn't count
# So: it does not resolve according to our criteria, i.e. _edit doesn't count, and URL resolves doesn't count because of the catch all
new_url = old_url[:]
new_url[1] = new_url[1] + "/"
if not _resolves(new_url[1]):
print(f"+++++ MIDDLEWARE add SLASH and resolves {old_url=} => {new_url=}")
return None
else:
if settings.DEBUG and request.method == "POST":

View File

@@ -393,7 +393,6 @@ def logbookedit(request, year=None, slug=None):
text = lbe.text
rows = max(5,len(text)/50)
print("IDENT",identified_login, who_are_you)
return render(
request,
"logbookform.html",

View File

@@ -733,7 +733,6 @@ def dwgupload(request, folder=None, gitdisable="no"):
if identified_login:
# disable editing the git id string as we get it from the logged-on user data
print(f"IDENTIFIED {identified_login}")
form.fields["who_are_you"].widget.attrs["readonly"]="readonly"
response = render(
request,

View File

@@ -359,7 +359,7 @@ div#header {
margin-left:auto;
margin-right:auto;
Dheight:50px;
background-image: url( ../loserBanner.jpg);
background-image: url( /site_media/loserBanner.jpg);
border-bottom:thin solid #000;
font-family: Arial, Helvetica, sans-serif;
font-variant: normal;

View File

@@ -48,6 +48,7 @@ ALLOWED_HOSTS = ["*", "expo.survex.com", ".survex.com", "localhost", "127.0.0.1"
ADMINS = (
('Wookey', 'wookey@wookware.org'),
('Philip', 'philip.sargent@klebos.eu'),
)
MANAGERS = ADMINS
@@ -78,15 +79,12 @@ FIX_PERMISSIONS = []
# SURVEX_TOPNAME = "1623-and-1626-no-schoenberg-hs"
SURVEX_TOPNAME = "troggle_import_root" # same, but without all the 'essentials' gubbins
APPEND_SLASH = (
False # never relevant because we have urls that match unknown files and produce an 'edit this page' response
)
SMART_APPEND_SLASH = True # not eorking as middleware different after Dj2.0
ROOT_URLCONF = "troggle.urls"
ROOT_URLCONF = "troggle.urls" # i.e. troggle/urls.py
LOGOUT_REDIRECT_URL = "/statistics" # see troggle/core/views/auth.py
LOGIN_REDIRECT_URL = "/controlpanel" # see troggle/core/views/auth.py
PASSWORD_RESET_TIMEOUT = 3*60*60 # password reset sends an email. The response is valid for 3 hours
#ACCOUNT_ACTIVATION_DAYS = 3 # this is only if we are using django-registration package
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
@@ -114,6 +112,8 @@ FORM_RENDERER = "django.forms.renderers.TemplatesSetting" # Required to customi
# Note that this is a radically different onion architecture from earlier versions though it looks the same,
# see https://docs.djangoproject.com/en/dev/topics/http/middleware/#upgrading-pre-django-1-10-style-middleware
# Seriously, read this: https://www.webforefront.com/django/middlewaredjango.html which is MUCH BETTER than the docs
# We are NOT using the home-built SmartAppendSlashMiddleware
MIDDLEWARE = [
#'django.middleware.security.SecurityMiddleware', # SECURE_SSL_REDIRECT and SECURE_SSL_HOST # we don't use this
"django.middleware.gzip.GZipMiddleware", # not needed when expofiles and photos served by apache
@@ -125,15 +125,14 @@ MIDDLEWARE = [
"django.contrib.messages.middleware.MessageMiddleware", # Cookie-based and session-based message support. Needed by admin system
"django.middleware.clickjacking.XFrameOptionsMiddleware", # clickjacking protection via the X-Frame-Options header
#'django.middleware.security.SecurityMiddleware', # SECURE_HSTS_SECONDS, SECURE_CONTENT_TYPE_NOSNIFF, SECURE_BROWSER_XSS_FILTER, SECURE_REFERRER_POLICY, and SECURE_SSL_REDIRECT
#'troggle.core.middleware.SmartAppendSlashMiddleware' # needs adapting after Dj2.0
#"troggle.core.middleware.TroggleAppendSlashMiddleware", # modified Feb.2025
]
WSGI_APPLICATION = "troggle.wsgi.application" # change to asgi as soon as we upgrade to Django 3.0
ACCOUNT_ACTIVATION_DAYS = 3
# AUTH_PROFILE_MODULE = 'core.person' # used by removed profiles app ?
# Append slash can't work if we have a universal catchall URL rule, and we do because all the handbook files
# do not have simple prefix. This is why we used to have an /expoweb/ prefix for everything in the website.
# APPEND_SLASH = True # using django.middleware.common.CommonMiddleware. Pointless, never happens if there is a catchall.
# TROGGLE_APPEND_SLASH = True # this is our middleware: see the code in troggle/core/middleware.py for why we do NOT use it.
QM_PATTERN = r"\[\[\s*[Qq][Mm]:([ABC]?)(\d{4})-(\d*)-(\d*)\]\]"
# Re-enable TinyMCE when Dj upgraded to v3. Also templates/editexpopage.html
@@ -148,5 +147,4 @@ TEST_RUNNER = "django.test.runner.DiscoverRunner"
print("+ finished importing troggle/settings.py, re-importing localsettings again")
from localsettings import *
# localsettings needs to take precedence. Call it to override any existing vars.

View File

@@ -24,7 +24,7 @@
pattern="[A-Za-z][A-Za-z0-9_-\.]*"/>
<label
style="padding: 0.5em 25px; margin-left: 110px"
for="renameto">If uploading a single file, you can rename it<br></label>
for="renameto"><br />If uploading a single file, you can rename it<br></label>
<br><br><br>
<button class="fancybutton2" style="padding: 0.5em 25px; margin-left: 155px" type = "submit" value = "Upload" >
Upload

44
urls.py
View File

@@ -74,6 +74,8 @@ re_path( <regular expression that matches the thing in the web browser>,
Django also provides the reverse function: given an an object, provide the URL
which is vital to writing code for the webapp. So the URL dispatch is declarative.
But this means that two URLs should NOT go to the same python target function,
(or only if the target name is different)
The API urls return TSV or JSON and are new in July 2020.
"""
@@ -101,16 +103,19 @@ todo = '''
if settings.EXPOFILESREMOTE:
expofilesurls = [
path('<path:filepath>', expofiles_redirect, name="expofiles_redirect"), # to http://expo.survex.com/expofiles
path('', expofiles_redirect, {'filepath': ""}, name="expofiles_redirect"),
path('', expofiles_redirect, {'filepath': ""}, name="expofiles_redirect"), #should not have duplicate urls as reverse() then fails
]
else:
expofilesurls = [
path('', expofilessingle, {'filepath': ""}, name="single"),
path('<path:filepath>', expofilessingle, name="single"), # local copy of EXPOFILES
path('', expofilessingle, {'filepath': ""}, name="single"),
path('<path:filepath>', expofilessingle, name="single"), # local copy of EXPOFILES, but should not have duplicate urls as reverse() then fails
]
trogglepatterns = [
# NOT intercepted by apache. Needs to come first to prevent our troggle middleware trying to "fix" it.
re_path(r'^site_media/(?P<subpath>.*)$', mediapage, {'doc_root': settings.MEDIA_ROOT}, name="mediapage"), # MEDIA_ROOT: CSS and JS
path('pubs.htm', pubspage, name="pubspage"), # ~165 hrefs to this url in expoweb files
#path('', indexpage, name="indexpage"), # ~1,212 hrefs to this url in expoweb files
path('index.htm', indexpage, name="indexpage"), # ~1,212 hrefs to this url in expoweb files
@@ -118,7 +123,7 @@ trogglepatterns = [
path('expofiles/', include(expofilesurls)), # intercepted by Apache, if it is running.
path('expofiles', include(expofilesurls)), # curious interaction with the include() here, not just a slash problem.
re_path(r'^(.*)_edit_edit$', spider, name="spider"), # web spider funny
re_path(r'^(.*)_edit_edit$', spider, name="spider"), # web spider. Intercept and manage it.
re_path(r'^caves$', caveindex, name="caveindex"),
re_path(r'^indxal.htm$', caveindex, name="caveindex"), # ~420 hrefs to this url in expoweb files
@@ -132,13 +137,13 @@ trogglepatterns = [
path('admin/', admin.site.urls), # includes admin login & logout urls & /admin/jsi18n/
# Uploads - uploading a file
path('walletedit/', walletedit, name='walletedit'),
path('walletedit/<path:path>', walletedit, name='walletedit'), # path=2020#01
path('walletedit/', walletedit, name='walletedit'), # not just an upload, also edit metadata
path('walletedit/<path:path>', walletedit, name='walletedit'), # path=2020#01
path('photoupload/', photoupload, name='photoupload'), # restricted to current year
path('photoupload/<path:folder>', photoupload, name='photoupload'), # restricted to current year
path('photoupload/<path:folder>', photoupload, name='photoupload'), # restricted to current year
path('gpxupload/', gpxupload, name='gpxupload'), # restricted to current year
path('gpxupload/<path:folder>', gpxupload, name='gpxupload'), # restricted to current year
path('dwgupload/<path:folder>', dwgupload, name='dwgupload'),
path('gpxupload/<path:folder>', gpxupload, name='gpxupload'), # restricted to current year
path('dwgupload/<path:folder>', dwgupload, name='dwgupload'),
path('dwgupload/', dwgupload, name='dwgupload'),
path('dwguploadnogit/', dwgupload, {'gitdisable': 'yes'}, name='dwguploadnogit'), # used in testing
path('dwguploadnogit/<path:folder>', dwgupload, {'gitdisable': 'yes'}, name='dwguploadnogit'), # used in testing
@@ -195,7 +200,6 @@ trogglepatterns = [
re_path(r'^logbook$', exportlogbook, name='exportlogbook'),
path('logreport/<slug:year>', logreport, name='logreport'),
path('logentrydelete/<slug:year>', logentrydelete, name='logentrydelete'),
# Internal. editfile.html template uses these internally
re_path(r'^getPeople/(?P<expeditionslug>.*)', get_people, name = "get_people"),
@@ -210,17 +214,13 @@ trogglepatterns = [
path('fix/<slug:areacode>', fix, name="fix"),
re_path(r'^newcave/$', edit_cave, name="newcave"),
re_path(r'^cave/3d/(?P<cave_id>[^/]+).3d$', cave3d, name="cave3d"),
#re_path(r'^cave/description/([^/]+)/?$', caves.caveDescription), #!!!BAD, local links fail..
#re_path(r'^cave/(?P<cave_id>[^/]+)/?$', caves.cave, name="cave"), # used only in testing !? XXXXXXXXXXXXXXXXXXXXXXXXXX
#re_path(r'^cave/(?P<cave_id>[^/]+)/?(?P<ent_letter>[^/])$', ent), #!!!BAD, local links fail..# view_caves.ent
# Edit caves and entrances
re_path(r'^(?P<path>.*)/(?P<slug>[^/]+)_cave_edit/$', edit_cave, name="edit_cave"), # edit_cave needed by cave.html template for url matching
re_path(r'^(?P<caveslug>[^/]+):(?P<entslug>[^:]+)_entrance_edit', edit_entrance, name = "editentrance"), #edit existing entrance
re_path(r'^(?P<path>.*)/(?P<caveslug>[^/]+)_entrance_new$', edit_entrance, name = "newentrance"), # new entrance for a cave
re_path(r'^(.*)_edit$', editexpopage, name="editexpopage"),
re_path(r'^(.*)_edit$', editexpopage, name="editexpopage"), # only happens if not a cave or entrance _edit page
re_path(r'^(?P<karea>162\d)(?P<subpath>.*)$', cavepage, name="cavepage"), # shorthand /1623/264 or 1623/161/top.htm or 1623/161/i/stuff.jpg
# Note that urls eg '/1623/161/l/rl89a.htm' are handled by cavepage which redirects them to 'expopage'
# Note that _edit$ for a cave description page in a subfolder e.g. /1623/204/204.html_edit gets caught here and breaks with 404
@@ -265,20 +265,16 @@ trogglepatterns = [
path('survexfilewild/', statistics.svxfilewild, name="svxfilewild"),
path('survexfilewild/<int:year>', statistics.svxfilewild, name="svxfilewild"),
# The survey scans in the wallets. This short-cuts SCANS_URL which is not used anymore and is defunct
path('survey_scans/', allscans, name="allscans"), # all the scans in all wallets
path('survey_scans/<path:path>/', walletedit, name="singlewallet"), # replaced singlewallet()
path('survey_scans/<path:path>/<file>', scansingle, name="scansingle"), # works, but html href goes direct to /expofiles/ too
path('cave/scans/<slug:caveid>', cavewallets, name="cavewallets"), # like allscans, but for just one cave
# The data about the wallets themselves, not the scans inside tehm
# The data about the wallets themselves, not the scans inside them
path('wallets/year/<int:year>', walletslistyear, name="walletslistyear"), # wallets that are for a specific year, as an integer '1985'
# re_path('wallets/person/(?P<first_name>[A-Z]*[a-z\-\'&;]*)[^a-zA-Z]*(?P<last_name>[a-z\-\']*[^a-zA-Z]*[\-]*[A-Z]*[a-zA-Z\-&;]*)/?', walletslistperson, name="walletslistperson"),
path('wallets/person/<slug:slug>', walletslistperson, name="walletslistperson"),
# The tunnel and therion drawings files pageswalletslistcave
path('drawings', dwgallfiles, name="dwgallfiles"),
path('drawings/', dwgallfiles, name="dwgallfiles"),
@@ -308,12 +304,6 @@ trogglepatterns = [
path('javascript/<path:subpath>', mediapage, {'doc_root': settings.JSLIB_ROOT}, name="mediapage"), # JSLIB_URL
# NOT intercepted by apache
re_path(r'^site_media/(?P<subpath>.*)$', mediapage, {'doc_root': settings.MEDIA_ROOT}, name="mediapage"), # MEDIA_ROOT: CSS and JS
# Fossil ? /loser/caves-1623/171/171.svx fails 404, /loser/docs/smklengths fails 404
re_path(r'^/loser/(?P<subpath>.*)$', mediapage, {'doc_root': settings.SURVEX_DATA}, name="mediapage"), # Oddly not working !?
# Helpers to edit HTML
re_path(r'^image_selector/(?P<path>.*)', image_selector, name = 'image_selector'),
@@ -323,6 +313,8 @@ trogglepatterns = [
re_path(r'^expo.kmz', expo_kmz, name = 'expo.kmz'),
# Final catchall which also serves expoweb handbook pages and imagestiny
# but a universal catchall also prevents the djang standard append_slash working, as every string resolves.
# try to fix in troggle/middleware.py
re_path(r'^(.*)$', expopage, name="expopage"), # CATCHALL assumed relative to EXPOWEB
]