middleware: add a maintenance middleware (#65447)

This commit is contained in:
Emmanuel Cazenave 2022-06-08 16:12:13 +02:00
parent f5539aa24e
commit 5a98f211bc
4 changed files with 90 additions and 0 deletions

51
tests/test_maintenance.py Normal file
View File

@ -0,0 +1,51 @@
import os
from .utilities import create_temporary_pub, get_app
def test_maintenance_page(settings):
pub = create_temporary_pub()
app = get_app(pub)
resp = app.get('/')
assert resp.status_code == 200
site_options_path = os.path.join(pub.app_dir, 'site-options.cfg')
with open(site_options_path, 'w') as fd:
fd.write(
'''\
[variables]
maintenance_page = True
'''
)
resp = app.get('/', status=503)
assert 'This site is currently unavailable.' in resp.text
with open(site_options_path, 'w') as fd:
fd.write(
'''\
[variables]
maintenance_page = True
maintenance_page_message = foo bar
'''
)
resp = app.get('/', status=503)
assert 'This site is currently unavailable.' in resp.text
assert 'foo bar' in resp.text
settings.MAINTENANCE_PASS_THROUGH_IPS = ['127.0.0.1']
resp = app.get('/')
assert resp.status_code == 200
settings.MAINTENANCE_PASS_THROUGH_IPS = []
resp = app.get('/', status=503)
with open(site_options_path, 'w') as fd:
fd.write(
'''\
[variables]
maintenance_page = True
maintenance_pass_through_header = X-Entrouvert
'''
)
resp = app.get('/', headers={'X-Entrouvert': 'yes'})
assert resp.status_code == 200

View File

@ -19,7 +19,9 @@ import threading
import time
import urllib.parse
from django.conf import settings
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseRedirect
from django.template.response import TemplateResponse
from django.utils.deprecation import MiddlewareMixin
from quixote import get_publisher
from quixote.errors import RequestError
@ -117,3 +119,31 @@ class AfterJobsMiddleware(MiddlewareMixin):
else:
http_response.process_after_jobs()
return response
def pass_through(request, pub):
remote_addr = request.META.get('REMOTE_ADDR')
if remote_addr:
pass_through_ips = getattr(settings, 'MAINTENANCE_PASS_THROUGH_IPS', [])
if remote_addr in pass_through_ips:
return True
pass_through_header = pub.get_site_option('maintenance_pass_through_header', 'variables')
if pass_through_header and pass_through_header in request.headers:
return True
return False
class MaintenanceMiddleware(MiddlewareMixin):
def process_request(self, request):
pub = get_publisher()
maintenance_mode = pub.get_site_option('maintenance_page', 'variables')
if maintenance_mode and not pass_through(request, pub):
maintenance_message = pub.get_site_option('maintenance_page_message', 'variables')
context = {'maintenance_message': maintenance_message or ''}
return TemplateResponse(
request,
['hobo/maintenance/maintenance_page.html', 'wcs/maintenance_page.html'],
context=context,
status=503,
).render()
return self.get_response(request)

View File

@ -115,6 +115,7 @@ MIDDLEWARE = (
'wcs.middleware.PublisherInitialisationMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'wcs.compat.PublishErrorMiddleware',
'wcs.middleware.MaintenanceMiddleware',
'wcs.middleware.AfterJobsMiddleware',
)

View File

@ -0,0 +1,8 @@
{% load i18n %}
<html>
<body>
<h1>{% trans "This site is currently unavailable." %}</h1>
<p>{{ maintenance_message|default:"" }}</p>
</body>
</html>