django-maintenancemode-0.11.7+git221001/ 0000755 0001751 0001751 00000000000 14322157470 017645 5 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/CHANGES.rst 0000644 0001751 0001751 00000004167 14322157470 021457 0 ustar kitterma kitterma Changes
-------
0.11.7
~~~~~~
- Fixed broken tests
0.11.6
~~~~~~
- Nothing
0.11.5
~~~~~~
- Made sure the app runs on Django 3.2, dropped support for Django < 2.x. It may
still work with Django 1.11, but this is no longer tested.
0.11.4
~~~~~~
- Changed the middleware to not fetch the user instance if both
``MAINTENANCE_ALLOW_STAFF`` and ``MAINTENANCE_ALLOW_SUPERUSER`` are
``False``.
- Added support for django 3.1.
0.11.3
~~~~~~
- Added support for django 2.x, dropped support for django < 1.11. It may
still work with django 1.8, but this is no longer tested.
0.11.2
~~~~~~
- Getting ready for Django 1.10 release.
- Dropped support for Django 1.3 and older.
0.11.1
~~~~~~
- Enable network specify in INTERNAL_IPS
0.11.0
~~~~~~
- Added management command to set maintenance mode on/off
0.10.1
~~~~~~
- Made sure the app runs on Django 1.8.
0.10.0
~~~~~~
- Got rid of dependency on setuptools
- Added ability to exclude specific paths from maintenance mode with the
``MAINTENANCE_IGNORE_URLS`` setting.
- Use RequestContext when rending the ``503.html`` template.
- Use tox for running the tests instead of buildout.
- Made sure the app runs on Django 1.4.
0.9.3
~~~~~~
- Minor documentation updates for the switch to github, expect more changes to follow soon.
0.9.2
~~~~~~
- Fixed an issue with setuptools, thanks for reporting this ksato9700
0.9.1
~~~~~~
- Tested django-maintenancemode with django-1.0 release (following the 1.0.X release branch)
- Bundled buildout.cfg and bootstrap with the source version of the project, allowing repeatable buildout
- The middleware now uses its own default config file, thanks to a patch by semente
- Use INTERNAL_IPS to check for users that need access. user.is_staff will stay in place
for backwards incompatibility. Thanks for the idea Joshua Works
- Have setup.py sdist only distribute maintenancemode itself, no longer distribute tests and buildout stuff
- Use README and CHANGES in setup.py's long_description, stolen from Jeroen's djangorecipe :)
- Updated the documentation and now use pypi as the documentation source (link there from google code)
0.9
~~~~~~
First release
django-maintenancemode-0.11.7+git221001/setup.cfg 0000644 0001751 0001751 00000003547 14322157470 021477 0 ustar kitterma kitterma [metadata]
name = django-maintenancemode
version = 0.11.7+git221001
description = django-maintenancemode allows you to temporary shutdown your site for maintenance work
long_description = file: README.rst
long_description_content_type = text/x-rst
author = Remco Wendt
author_email = remco@maykinmedia.nl
maintainer = Basil Shubin
maintainer_email = basil.shubin@gmail.com
url = https://github.com/shanx/django-maintenancemode
download_url = https://github.com/shanx/django-maintenancemode/zipball/master
license = BSD License
classifiers =
Development Status :: 5 - Production/Stable
Environment :: Web Environment
Intended Audience :: Developers
License :: OSI Approved :: BSD License
Operating System :: OS Independent
Programming Language :: Python
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Framework :: Django
Framework :: Django :: 2.2
Framework :: Django :: 3.0
Framework :: Django :: 3.1
Framework :: Django :: 3.2
[options]
zip_safe = False
include_package_data = True
packages = find:
install_requires =
django-appconf
six>=1.9.0
ipy
[options.packages.find]
exclude = example*
[options.extras_require]
develop =
tox
django
pytest-django
pytest
test =
pytest-django
pytest-cov
pytest
[bdist_wheel]
# No longer universal (Python 3 only) but leaving this section in here will
# trigger zest to build a wheel.
universal = 0
[flake8]
# Some sane defaults for the code style checker flake8
# black compatibility
max-line-length = 88
# E203 and W503 have edge cases handled by black
extend-ignore = E203, W503
exclude =
.tox
build
dist
.eggs
[tool:pytest]
DJANGO_SETTINGS_MODULE = maintenancemode.tests.settings
django-maintenancemode-0.11.7+git221001/tox.ini 0000644 0001751 0001751 00000000711 14322157470 021157 0 ustar kitterma kitterma [tox]
distribute = False
envlist =
py{36,37,38,39}-dj{22,30,31,32}
skip_missing_interpreters = True
[travis]
python =
3.6: py36
3.7: py37
3.8: py38
3.9: py39
[testenv]
usedevelop = True
extras = test
setenv =
DJANGO_SETTINGS_MODULE = maintenancemode.tests.settings
deps =
dj22: Django>=2.2,<3.0
dj30: Django>=3.0,<3.1
dj31: Django>=3.1,<3.2
dj32: Django>=3.2,<4.0
commands = pytest --cov --cov-append --cov-report=
django-maintenancemode-0.11.7+git221001/LICENSE 0000644 0001751 0001751 00000003060 14322157470 020651 0 ustar kitterma kitterma Copyright (c) 2008, Maykin Media
Copyright (c) 2012, enn.io
Copyright (c) 2015-2019, Basil Shubin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the author nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
django-maintenancemode-0.11.7+git221001/setup.py 0000644 0001751 0001751 00000000074 14322157470 021360 0 ustar kitterma kitterma #!/usr/bin/env python
from setuptools import setup
setup()
django-maintenancemode-0.11.7+git221001/example/ 0000755 0001751 0001751 00000000000 14322157470 021300 5 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/example/requirements.txt 0000644 0001751 0001751 00000000032 14322157470 024557 0 ustar kitterma kitterma django
django-appconf
ipy
django-maintenancemode-0.11.7+git221001/example/manage.py 0000755 0001751 0001751 00000000614 14322157470 023106 0 ustar kitterma kitterma #!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings")
from django.core.management import execute_from_command_line
# Allow starting the app without installing the module.
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
execute_from_command_line(sys.argv)
django-maintenancemode-0.11.7+git221001/example/urls.py 0000644 0001751 0001751 00000000174 14322157470 022641 0 ustar kitterma kitterma from django.urls import path
from .views import index
urlpatterns = [
path('', index),
path('ignored/', index),
]
django-maintenancemode-0.11.7+git221001/example/templates/ 0000755 0001751 0001751 00000000000 14322157470 023276 5 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/example/templates/503.html 0000644 0001751 0001751 00000000111 14322157470 024464 0 ustar kitterma kitterma
Temporary unavailable
You requested: {{ request_path }}
django-maintenancemode-0.11.7+git221001/example/views.py 0000644 0001751 0001751 00000000131 14322157470 023002 0 ustar kitterma kitterma from django.http import HttpResponse
def index(request):
return HttpResponse("OK")
django-maintenancemode-0.11.7+git221001/example/settings.py 0000755 0001751 0001751 00000006204 14322157470 023517 0 ustar kitterma kitterma """
Django settings for app project.
For more information on this file, see
https://docs.djangoproject.com/en/1.7/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.7/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
import re
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "YOUR_SECRET_KEY"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
PROJECT_APPS = [
"maintenancemode",
]
INSTALLED_APPS = [
"django.contrib.auth",
"django.contrib.admin",
"django.contrib.sessions",
"django.contrib.contenttypes",
"django.contrib.messages",
"django.contrib.sites",
] + PROJECT_APPS
MIDDLEWARE_CLASSES = [
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
#'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
#'django.middleware.security.SecurityMiddleware',
"maintenancemode.middleware.MaintenanceModeMiddleware",
]
MIDDLEWARE = MIDDLEWARE_CLASSES
ROOT_URLCONF = "example.urls"
SITE_ID = 1
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [
os.path.join(os.path.dirname(os.path.abspath(__file__)), "templates"),
],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
# Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.7/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/
# Absolute filesystem path to the directory that will hold user-uploaded files.
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
MEDIA_URL = "/media/"
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
STATIC_URL = "/static/"
## Maintenance Mode settings
MAINTENANCE_MODE = True # or ``False`` and use ``maintenance`` command
MAINTENANCE_IGNORE_URLS = (re.compile(r"^/ignored.*"),)
django-maintenancemode-0.11.7+git221001/example/README.rst 0000644 0001751 0001751 00000001035 14322157470 022766 0 ustar kitterma kitterma Example
=======
To run the example application, make sure you have the required
packages installed. You can do this using following commands :
.. code-block:: bash
mkvirtualenv example
pip install -r example/requirements.txt
This assumes you already have ``virtualenv`` and ``virtualenvwrapper``
installed and configured.
Next, you can setup the django instance using :
.. code-block:: bash
python example/manage.py syncdb --noinput
And run it :
.. code-block:: bash
python example/manage.py runserver
Good luck!
django-maintenancemode-0.11.7+git221001/example/__init__.py 0000644 0001751 0001751 00000000000 14322157470 023377 0 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/MANIFEST.in 0000644 0001751 0001751 00000000226 14322157470 021403 0 ustar kitterma kitterma include AUTHORS
include CHANGES.rst
include LICENSE
include README.rst
recursive-exclude example *
recursive-include maintenancemode templates *.html
django-maintenancemode-0.11.7+git221001/AUTHORS 0000644 0001751 0001751 00000000235 14322157470 020715 0 ustar kitterma kitterma django-maintenancemode is written by Remco Wendt
Feel free to contact me by mail if you have any questions, or just want to say hi.
django-maintenancemode-0.11.7+git221001/maintenancemode/ 0000755 0001751 0001751 00000000000 14322157470 022774 5 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/maintenancemode/tests/ 0000755 0001751 0001751 00000000000 14322157470 024136 5 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/maintenancemode/tests/urls.py 0000644 0001751 0001751 00000000405 14322157470 025474 0 ustar kitterma kitterma from django.urls import re_path
from django.http import HttpResponse
urlpatterns = [
re_path("^$", lambda r: HttpResponse("Rendered response page"), name="test"),
re_path("^ignored/$", lambda r: HttpResponse("Rendered response page"), name="test"),
]
django-maintenancemode-0.11.7+git221001/maintenancemode/tests/templates/ 0000755 0001751 0001751 00000000000 14322157470 026134 5 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/maintenancemode/tests/templates/503.html 0000644 0001751 0001751 00000000070 14322157470 027326 0 ustar kitterma kitterma Temporary unavailable
You requested: {{ request_path }} django-maintenancemode-0.11.7+git221001/maintenancemode/tests/conftest.py 0000644 0001751 0001751 00000000321 14322157470 026331 0 ustar kitterma kitterma """
Dummy conftest.py for maintenancemode.
If you don't know what this is for, just leave it empty.
Read more about conftest.py under:
https://pytest.org/latest/plugins.html
"""
import pytest
django-maintenancemode-0.11.7+git221001/maintenancemode/tests/settings.py 0000644 0001751 0001751 00000003064 14322157470 026353 0 ustar kitterma kitterma # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
import re
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SECRET_KEY = "DUMMY_SECRET_KEY"
INTERNAL_IPS = []
# Application definition
PROJECT_APPS = ["maintenancemode.tests", "maintenancemode"]
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.sites",
] + PROJECT_APPS
MIDDLEWARE = [
"django.contrib.sessions.middleware.SessionMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"maintenancemode.middleware.MaintenanceModeMiddleware",
]
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [os.path.join(BASE_DIR, "tests", "templates")],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
]
},
},
]
ROOT_URLCONF = "maintenancemode.tests.urls"
SITE_ID = 1
# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}}
MAINTENANCE_IGNORE_URLS = (re.compile(r"^/ignored.*"),)
django-maintenancemode-0.11.7+git221001/maintenancemode/tests/__init__.py 0000644 0001751 0001751 00000000000 14322157470 026235 0 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/maintenancemode/tests/test_middleware.py 0000644 0001751 0001751 00000014550 14322157470 027671 0 ustar kitterma kitterma import re
from django.core import management
try:
from django.utils.six import StringIO
except ImportError:
from six import StringIO
from django.contrib.auth.models import User
from django.template import TemplateDoesNotExist
from django.test import TestCase
from django.test.client import Client
from django.test.utils import override_settings
from maintenancemode import utils
@override_settings(ROOT_URLCONF="maintenancemode.tests.urls", MAINTENANCE_MODE=False)
class MaintenanceModeMiddlewareTestCase(TestCase):
def setUp(self):
utils.deactivate() # make sure maintenance mode is off
self.user = User.objects.create_user(
username="maintenance", email="maintenance@example.org", password="password"
)
def tearDown(self):
self.user.delete()
def test_default_middleware(self):
# Middleware should default to being disabled
response = self.client.get("/")
self.assertContains(response, text="Rendered response page", count=1, status_code=200)
def test_disabled_middleware(self):
# Explicitly disabling the ``MAINTENANCE_MODE`` should work
with self.settings(MAINTENANCE_MODE=False):
response = self.client.get("/")
self.assertContains(response, text="Rendered response page", count=1, status_code=200)
def test_enabled_middleware_without_template(self):
# Enabling the middleware without a proper 503 template should
# raise a template error
with self.settings(MAINTENANCE_MODE=True, TEMPLATES=[]):
self.assertRaises(TemplateDoesNotExist, self.client.get, "/")
def test_enabled_middleware_with_template(self):
# Enabling the middleware having a ``503.html`` in any of the
# template locations should return the rendered template"
with self.settings(MAINTENANCE_MODE=True):
response = self.client.get("/")
self.assertContains(response, text="Temporary unavailable", count=1, status_code=503)
self.assertContains(response, text="You requested: /", count=1, status_code=503)
def test_middleware_with_non_staff_user(self):
# A logged in user that is not a staff user should see the 503 message
self.client.login(username="maintenance", password="password")
with self.settings(MAINTENANCE_MODE=True):
response = self.client.get("/")
self.assertContains(response, text="Temporary unavailable", count=1, status_code=503)
def test_middleware_with_staff_user(self):
# A logged in user that _is_ a staff user should be able to
# use the site normally
User.objects.filter(pk=self.user.pk).update(is_staff=True)
self.client.login(username="maintenance", password="password")
with self.settings(MAINTENANCE_MODE=True):
response = self.client.get("/")
self.assertContains(response, text="Rendered response page", count=1, status_code=200)
def test_middleware_with_staff_user_denied(self):
# A logged in user that _is_ a staff user should be able to
# use the site normally
User.objects.filter(pk=self.user.pk).update(is_staff=True)
self.client.login(username="maintenance", password="password")
with self.settings(MAINTENANCE_MODE=True, MAINTENANCE_ALLOW_STAFF=False):
response = self.client.get("/")
self.assertContains(response, text="Temporary unavailable", count=1, status_code=503)
def test_middleware_with_superuser_user_denied(self):
# A logged in user that _is_ a staff user should be able to
# use the site normally
User.objects.filter(pk=self.user.pk).update(is_superuser=True)
self.client.login(username="maintenance", password="password")
with self.settings(MAINTENANCE_MODE=True, MAINTENANCE_ALLOW_SUPERUSER=False):
response = self.client.get("/")
self.assertContains(response, text="Temporary unavailable", count=1, status_code=503)
def test_middleware_with_superuser_user_allowed(self):
# A logged in user that _is_ a staff user should be able to
# use the site normally
User.objects.filter(pk=self.user.pk).update(is_superuser=True)
self.client.login(username="maintenance", password="password")
with self.settings(MAINTENANCE_MODE=True, MAINTENANCE_ALLOW_STAFF=False):
response = self.client.get("/")
self.assertContains(response, text="Rendered response page", count=1, status_code=200)
def test_middleware_with_internal_ips(self):
# A user that visits the site from an IP in ``INTERNAL_IPS``
# should be able to use the site normally
# Use a new Client instance to be able to set the REMOTE_ADDR used by INTERNAL_IPS
client = Client(REMOTE_ADDR="127.0.0.1")
with self.settings(MAINTENANCE_MODE=True, INTERNAL_IPS=("127.0.0.1",)):
response = client.get("/")
self.assertContains(response, text="Rendered response page", count=1, status_code=200)
def test_middleware_with_internal_ips_range(self):
client = Client(REMOTE_ADDR="10.10.10.1")
with self.settings(MAINTENANCE_MODE=True, INTERNAL_IPS=("10.10.10.0/24",)):
response = client.get("/")
self.assertContains(response, text="Rendered response page", count=1, status_code=200)
def test_ignored_path(self):
# A path is ignored when applying the maintanance mode and
# should be reachable normally
with self.settings(MAINTENANCE_MODE=True):
# Note that we cannot override the settings here, since they are
# ONLY used when the middleware starts up.
# For this reason, MAINTENANCE_IGNORE_URLS is set in the base
# settings file.
response = self.client.get("/ignored/")
self.assertContains(response, text="Rendered response page", count=1, status_code=200)
def test_management_command(self):
out = StringIO()
# Explicitly disabling the ``MAINTENANCE_MODE``
with self.settings(MAINTENANCE_MODE=False):
management.call_command("maintenance", "on", stdout=out)
self.assertContains(self.client.get("/"), text="Temporary unavailable", count=1, status_code=503)
management.call_command("maintenance", "off", stdout=out)
self.assertContains(self.client.get("/"), text="Rendered response page", count=1, status_code=200)
django-maintenancemode-0.11.7+git221001/maintenancemode/tests/models.py 0000644 0001751 0001751 00000000000 14322157470 025761 0 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/maintenancemode/management/ 0000755 0001751 0001751 00000000000 14322157470 025110 5 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/maintenancemode/management/commands/ 0000755 0001751 0001751 00000000000 14322157470 026711 5 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/maintenancemode/management/commands/__init__.py 0000644 0001751 0001751 00000000000 14322157470 031010 0 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/maintenancemode/management/commands/maintenance.py 0000644 0001751 0001751 00000002046 14322157470 031547 0 ustar kitterma kitterma from django.core.management.base import BaseCommand, CommandError
from maintenancemode import utils as maintenance
class Command(BaseCommand):
opts = ("on", "off", "activate", "deactivate")
def add_arguments(self, parser):
parser.add_argument("command", nargs="?", help="|".join(self.opts))
def handle(self, *args, **options):
command = options.get("command", args[0] if len(args) > 0 else None)
verbosity = int(options.get("verbosity"))
if command is not None:
if command.lower() in ("on", "activate"):
maintenance.activate()
if verbosity > 0:
self.stdout.write("Maintenance mode was activated succesfully")
elif command.lower() in ("off", "deactivate"):
maintenance.deactivate()
if verbosity > 0:
self.stdout.write("Maintenance mode was deactivated succesfully")
if command not in self.opts:
raise CommandError("Allowed commands are: %s" % "|".join(self.opts))
django-maintenancemode-0.11.7+git221001/maintenancemode/management/__init__.py 0000644 0001751 0001751 00000000000 14322157470 027207 0 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/maintenancemode/views.py 0000644 0001751 0001751 00000001643 14322157470 024507 0 ustar kitterma kitterma import django
if django.get_version() >= "1.8":
from django.template.loader import render_to_string
else:
from django.template import RequestContext, loader
def render_to_string(template_name, context=None, request=None):
context_instance = RequestContext(request) if request else None
return loader.render_to_string(template_name, context, context_instance)
from . import http
def temporary_unavailable(request, template_name="503.html"):
"""
Default 503 handler, which looks for the requested URL in the
redirects table, redirects if found, and displays 404 page if not
redirected.
Templates: ``503.html``
Context:
request_path
The path of the requested URL (e.g., '/app/pages/bad_page/')
"""
context = {
"request_path": request.path,
}
return http.HttpResponseTemporaryUnavailable(render_to_string(template_name, context))
django-maintenancemode-0.11.7+git221001/maintenancemode/http.py 0000644 0001751 0001751 00000000163 14322157470 024325 0 ustar kitterma kitterma from django.http import HttpResponse
class HttpResponseTemporaryUnavailable(HttpResponse):
status_code = 503
django-maintenancemode-0.11.7+git221001/maintenancemode/middleware.py 0000644 0001751 0001751 00000004720 14322157470 025466 0 ustar kitterma kitterma import re
from django import VERSION as django_version
from django.conf import urls
from django.urls import get_resolver
from django.urls import resolvers
from django.utils.deprecation import MiddlewareMixin
from . import utils as maintenance
from .conf import settings
urls.handler503 = "maintenancemode.views.temporary_unavailable"
urls.__all__.append("handler503")
IGNORE_URLS = tuple(re.compile(u) for u in settings.MAINTENANCE_IGNORE_URLS)
DJANGO_VERSION_MAJOR = django_version[0]
DJANGO_VERSION_MINOR = django_version[1]
class MaintenanceModeMiddleware(MiddlewareMixin):
def process_request(self, request):
# Allow access if middleware is not activated
allow_staff = getattr(settings, "MAINTENANCE_ALLOW_STAFF", True)
allow_superuser = getattr(settings, "MAINTENANCE_ALLOW_SUPERUSER", True)
if not (settings.MAINTENANCE_MODE or maintenance.status()):
return None
INTERNAL_IPS = maintenance.IPList(settings.INTERNAL_IPS)
# Preferentially check HTTP_X_FORWARDED_FOR b/c a proxy
# server might have obscured REMOTE_ADDR
for ip in request.headers.get('X-Forwarded-For', "").split(","):
if ip.strip() in INTERNAL_IPS:
return None
# Allow access if remote ip is in INTERNAL_IPS
if request.META.get("REMOTE_ADDR") in INTERNAL_IPS:
return None
# Allow access if the user doing the request is logged in and a
# staff member.
if hasattr(request, "user"):
if allow_staff and request.user.is_staff:
return None
if allow_superuser and request.user.is_superuser:
return None
# Check if a path is explicitly excluded from maintenance mode
for url in IGNORE_URLS:
if url.match(request.path_info):
return None
# Otherwise show the user the 503 page
if (DJANGO_VERSION_MAJOR == 3 and DJANGO_VERSION_MINOR < 2) or DJANGO_VERSION_MAJOR < 3:
# Checks if DJANGO version is less than 3.2.0 for breaking change
resolver = get_resolver()
callback, param_dict = resolver.resolve_error_handler("503")
return callback(request, **param_dict)
else:
# Default behaviour for django 3.2 and higher
resolver = resolvers.get_resolver(None)
resolve = resolver.resolve_error_handler
callback = resolve('503')
return callback(request)
django-maintenancemode-0.11.7+git221001/maintenancemode/conf.py 0000644 0001751 0001751 00000000537 14322157470 024300 0 ustar kitterma kitterma import os
from django.conf import settings # noqa
from appconf import AppConf
class MaintenanceSettings(AppConf):
IGNORE_URLS = ()
LOCKFILE_PATH = os.path.join(os.path.abspath(os.path.dirname(__file__)), "maintenance.lock")
MODE = False
class Meta:
prefix = "maintenance"
holder = "maintenancemode.conf.settings"
django-maintenancemode-0.11.7+git221001/maintenancemode/__init__.py 0000644 0001751 0001751 00000000000 14322157470 025073 0 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/maintenancemode/utils.py 0000644 0001751 0001751 00000001570 14322157470 024511 0 ustar kitterma kitterma import os
from .conf import settings
class IPList(list):
"""Stolen from https://djangosnippets.org/snippets/1362/"""
def __init__(self, ips):
try:
from IPy import IP
for ip in ips:
self.append(IP(ip))
except ImportError:
pass
def __contains__(self, ip):
try:
for net in self:
if ip in net:
return True
except: # noqa
pass
return False
def activate():
try:
open(settings.MAINTENANCE_LOCKFILE_PATH, "ab", 0).close()
except OSError:
pass # shit happens
def deactivate():
if os.path.isfile(settings.MAINTENANCE_LOCKFILE_PATH):
os.remove(settings.MAINTENANCE_LOCKFILE_PATH)
def status():
return settings.MAINTENANCE_MODE or os.path.isfile(settings.MAINTENANCE_LOCKFILE_PATH)
django-maintenancemode-0.11.7+git221001/maintenancemode/models.py 0000644 0001751 0001751 00000000000 14322157470 024617 0 ustar kitterma kitterma django-maintenancemode-0.11.7+git221001/README.rst 0000644 0001751 0001751 00000007610 14322157470 021340 0 ustar kitterma kitterma django-maintenancemode
======================
.. image:: https://img.shields.io/pypi/v/django-maintenancemode.svg
:target: https://pypi.python.org/pypi/django-maintenancemode/
.. image:: https://img.shields.io/pypi/dm/django-maintenancemode.svg
:target: https://pypi.python.org/pypi/django-maintenancemode/
.. image:: https://img.shields.io/github/license/shanx/django-maintenancemode.svg
:target: https://pypi.python.org/pypi/django-maintenancemode/
.. image:: https://app.travis-ci.com/bashu/django-maintenancemode.svg?branch=develop
:target: https://app.travis-ci.com/github/bashu/django-maintenancemode
.. image:: https://coveralls.io/repos/github/shanx/django-maintenancemode/badge.svg?branch=develop
:target: https://coveralls.io/github/shanx/django-maintenancemode?branch=develop
django-maintenancemode is a middleware that allows you to temporary shutdown
your site for maintenance work.
Logged in users having staff credentials can still fully use
the site as can users visiting the site from an IP address defined in
Django's ``INTERNAL_IPS``.
Authored by `Remco Wendt `_, and some great `contributors `_.
How it works
------------
``maintenancemode`` works the same way as handling 404 or 500 error in
Django work. It adds a ``handler503`` which you can override in your
main ``urls.py`` or you can add a ``503.html`` to your templates
directory.
* If user is logged in and staff member, the maintenance page is
not displayed.
* If user's IP is in ``INTERNAL_IPS``, the maintenance page is
not displayed.
* To override the default view which is used if the maintenance mode
is enabled you can simply define a ``handler503`` variable in your
ROOT_URLCONF_, similar to how you would customize other `error handlers`_,
e.g. :
.. code-block:: python
handler503 = 'example.views.maintenance_mode'
Installation
------------
1. Either checkout ``maintenancemode`` from GitHub, or install using pip :
.. code-block:: bash
pip install django-maintenancemode
2. Add ``maintenancemode`` to your ``INSTALLED_APPS`` :
.. code-block:: python
INSTALLED_APPS = (
...
'maintenancemode',
)
3. Add ``MaintenanceModeMiddleware`` to ``MIDDLEWARE_CLASSES``, make sure it comes after ``AuthenticationMiddleware`` :
.. code-block:: python
MIDDLEWARE_CLASSES = (
...
'django.contrib.auth.middleware.AuthenticationMiddleware',
'maintenancemode.middleware.MaintenanceModeMiddleware',
)
4. Add variable called ``MAINTENANCE_MODE`` in your project's ``settings.py`` file :
.. code-block:: python
MAINTENANCE_MODE = True # Setting this variable to ``True`` activates the middleware.
or set ``MAINTENANCE_MODE`` to ``False`` and use ``maintenance`` command :
.. code-block:: shell
python ./manage.py maintenance
Please see ``example`` application. This application is used to
manually test the functionalities of this package. This also serves as
a good example...
You need only Django 1.4 or above to run that. It might run on older
versions but that is not tested.
Configuration
-------------
There are various optional configuration options you can set in your ``settings.py``
.. code-block:: python
# Enable / disable maintenance mode.
# Default: False
MAINTENANCE_MODE = True # or ``False`` and use ``maintenance`` command
# Sequence of URL path regexes to exclude from the maintenance mode.
# Default: ()
MAINTENANCE_IGNORE_URLS = (
r'^/docs/.*',
r'^/contact'
)
License
-------
``django-maintenancemode`` is released under the BSD license.
.. _ROOT_URLCONF: https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf
.. _`error handlers`: https://docs.djangoproject.com/en/dev/topics/http/views/#customizing-error-views