././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1632467929.4981709 django-maintenance-mode-0.16.1/0000755000076500000240000000000000000000000017756 5ustar00fabiocaccamostaff00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/LICENSE.txt0000644000076500000240000000212200000000000021576 0ustar00fabiocaccamostaff00000000000000The MIT License (MIT) Copyright (c) 2016 Fabio Caccamo - fabio.caccamo@gmail.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1602595695.0 django-maintenance-mode-0.16.1/MANIFEST.in0000644000076500000240000000017300000000000021515 0ustar00fabiocaccamostaff00000000000000include LICENSE.txt include README.md recursive-include maintenance_mode * recursive-exclude * *.pyc __pycache__ .DS_Store ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1632467929.4984956 django-maintenance-mode-0.16.1/PKG-INFO0000644000076500000240000003503200000000000021056 0ustar00fabiocaccamostaff00000000000000Metadata-Version: 2.1 Name: django-maintenance-mode Version: 0.16.1 Summary: django-maintenance-mode shows a 503 error page when maintenance-mode is on. Home-page: https://github.com/fabiocaccamo/django-maintenance-mode Author: Fabio Caccamo Author-email: fabio.caccamo@gmail.com License: MIT Download-URL: https://github.com/fabiocaccamo/django-maintenance-mode/archive/0.16.1.tar.gz Description: [![](https://img.shields.io/pypi/pyversions/django-maintenance-mode.svg?color=3776AB&logo=python&logoColor=white)](https://www.python.org/) [![](https://img.shields.io/pypi/djversions/django-maintenance-mode?color=0C4B33&logo=django&logoColor=white&label=django)](https://www.djangoproject.com/) [![](https://img.shields.io/pypi/v/django-maintenance-mode.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/django-maintenance-mode/) [![](https://pepy.tech/badge/django-maintenance-mode)](https://pepy.tech/project/django-maintenance-mode) [![](https://img.shields.io/github/stars/fabiocaccamo/django-maintenance-mode?logo=github)](https://github.com/fabiocaccamo/django-maintenance-mode/) [![](https://badges.pufler.dev/visits/fabiocaccamo/django-maintenance-mode?label=visitors&color=blue)](https://badges.pufler.dev) [![](https://img.shields.io/pypi/l/django-maintenance-mode.svg?color=blue)](https://github.com/fabiocaccamo/django-maintenance-mode/blob/master/LICENSE.txt) [![](https://img.shields.io/travis/fabiocaccamo/django-maintenance-mode?logo=travis&label=build)](https://travis-ci.org/fabiocaccamo/django-maintenance-mode) [![](https://img.shields.io/codecov/c/gh/fabiocaccamo/django-maintenance-mode?logo=codecov)](https://codecov.io/gh/fabiocaccamo/django-maintenance-mode) [![](https://img.shields.io/codacy/grade/918668ac85e74206a4d8d95923548d79?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/django-maintenance-mode) [![](https://img.shields.io/codeclimate/maintainability/fabiocaccamo/django-maintenance-mode?logo=code-climate)](https://codeclimate.com/github/fabiocaccamo/django-maintenance-mode/) [![](https://requires.io/github/fabiocaccamo/django-maintenance-mode/requirements.svg?branch=master)](https://requires.io/github/fabiocaccamo/django-maintenance-mode/requirements/?branch=master) # django-maintenance-mode django-maintenance-mode shows a 503 error page when **maintenance-mode** is **on**. It works at application level, so your django instance should be up. It doesn't use database and doesn't prevent database access. ## Installation 1. Run ``pip install django-maintenance-mode`` or [download django-maintenance-mode](http://pypi.python.org/pypi/django-maintenance-mode) and add the **maintenance_mode** package to your project 2. Add ``'maintenance_mode'`` to ``settings.INSTALLED_APPS`` before custom applications 3. Add ``'maintenance_mode.middleware.MaintenanceModeMiddleware'`` to ``settings.MIDDLEWARE_CLASSES``/``settings.MIDDLEWARE`` as last middleware 4. Add your custom ``templates/503.html`` file 5. Restart your application server ## Configuration (optional) ### Settings All these settings are optional, if not defined in ``settings.py`` the default values (listed below) will be used. ```python # if True the maintenance-mode will be activated MAINTENANCE_MODE = None ``` ```python # by default, to get/set the state value a local file backend is used # if you want to use the db or cache, you can create a custom backend # custom backends must extend 'maintenance_mode.backends.AbstractStateBackend' class # and implement get_value(self) and set_value(self, val) methods MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.LocalFileBackend' # alternatively it is possible to use the default storage backend MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.DefaultStorageBackend' ``` ```python # by default, a file named "maintenance_mode_state.txt" will be created in the settings.py directory # you can customize the state file path in case the default one is not writable MAINTENANCE_MODE_STATE_FILE_PATH = 'maintenance_mode_state.txt' ``` ```python # if True admin site will not be affected by the maintenance-mode page MAINTENANCE_MODE_IGNORE_ADMIN_SITE = False ``` ```python # if True anonymous users will not see the maintenance-mode page MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER = False ``` ```python # if True authenticated users will not see the maintenance-mode page MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER = False ``` ```python # if True the staff will not see the maintenance-mode page MAINTENANCE_MODE_IGNORE_STAFF = False ``` ```python # if True the superuser will not see the maintenance-mode page MAINTENANCE_MODE_IGNORE_SUPERUSER = False ``` ```python # list of ip-addresses that will not be affected by the maintenance-mode # ip-addresses will be used to compile regular expressions objects MAINTENANCE_MODE_IGNORE_IP_ADDRESSES = () ``` ```python # the path of the function that will return the client IP address given the request object -> 'myapp.mymodule.myfunction' # the default function ('maintenance_mode.utils.get_client_ip_address') returns request.META['REMOTE_ADDR'] # in some cases the default function returns None, to avoid this scenario just use 'django-ipware' MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = None ``` Retrieve user's real IP address using [`django-ipware`](https://github.com/un33k/django-ipware): ```python MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = 'ipware.ip.get_ip' ``` ```python # list of urls that will not be affected by the maintenance-mode # urls will be used to compile regular expressions objects MAINTENANCE_MODE_IGNORE_URLS = () ``` ```python # if True the maintenance mode will not return 503 response while running tests # useful for running tests while maintenance mode is on, before opening the site to public use MAINTENANCE_MODE_IGNORE_TESTS = False ``` ```python # the absolute url where users will be redirected to during maintenance-mode MAINTENANCE_MODE_REDIRECT_URL = None ``` ```python # the template that will be shown by the maintenance-mode page MAINTENANCE_MODE_TEMPLATE = '503.html' ``` ```python # the path of the function that will return the template context -> 'myapp.mymodule.myfunction' MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT = None ``` ```python # the HTTP status code to send MAINTENANCE_MODE_STATUS_CODE = 503 ``` ```python # the value in seconds of the Retry-After header during maintenance-mode MAINTENANCE_MODE_RETRY_AFTER = 3600 # 1 hour ``` #### Context Processors Add **maintenance_mode.context_processors.maintenance_mode** to your context_processors list in ``settings.py`` if you want to access the maintenance_mode status in your templates. ```python TEMPLATES = [ { # ... 'OPTIONS': { 'context_processors': [ # ... 'maintenance_mode.context_processors.maintenance_mode', # ... ], }, # ... }, ] ``` #### Logging You can disable emailing 503 errors to admins while maintenance mode is enabled: ```python LOGGING = { 'filters': { 'require_not_maintenance_mode_503': { '()': 'maintenance_mode.logging.RequireNotMaintenanceMode503', }, ... }, 'handlers': { ... }, ... } ``` ### Context Managers You can force a block of code execution to run under maintenance mode or not using context managers: ```python from maintenance_mode.core import maintenance_mode_off, maintenance_mode_on with maintenance_mode_on(): # do stuff pass with maintenance_mode_off(): # do stuff pass ``` ### URLs Add **maintenance_mode.urls** to ``urls.py`` if you want superusers able to set maintenance_mode using urls. ```python urlpatterns = [ # ... url(r'^maintenance-mode/', include('maintenance_mode.urls')), # ... ] ``` ### Views You can force maintenance mode on/off at view level using view decorators: ```python from maintenance_mode.decorators import force_maintenance_mode_off, force_maintenance_mode_on @force_maintenance_mode_off def my_view_a(request): # never return 503 response pass @force_maintenance_mode_on def my_view_b(request): # always return 503 response pass ``` ## Usage ### Python ```python from maintenance_mode.core import get_maintenance_mode, set_maintenance_mode set_maintenance_mode(True) if get_maintenance_mode(): set_maintenance_mode(False) ``` or ```python from django.core.management import call_command from django.core.management.base import BaseCommand class Command(BaseCommand): def handle(self, *args, **options): call_command('maintenance_mode', 'on') # call your command(s) call_command('maintenance_mode', 'off') ``` ### Templates ```html {% if maintenance_mode %} {% endif %} ``` ### Terminal Run ``python manage.py maintenance_mode `` *(**This is not Heroku-friendly because** any execution of heroku run* `manage.py` *will be run on a separate worker dyno, not the web one. Therefore **the state-file is set but on the wrong machine. You should use a custom*** `MAINTENANCE_MODE_STATE_BACKEND`*.)* ### URLs Superusers can change maintenance-mode using the following urls: ``/maintenance-mode/off/`` ``/maintenance-mode/on/`` ## Testing ```bash # create python virtual environment virtualenv testing_django_maintenance_mode # activate virtualenv cd testing_django_maintenance_mode && . bin/activate # clone repo git clone https://github.com/fabiocaccamo/django-maintenance-mode.git src && cd src # run tests tox # or python setup.py test # or python -m django test --settings "tests.settings" ``` ## License Released under [MIT License](LICENSE.txt). --- ## See also - [`django-admin-interface`](https://github.com/fabiocaccamo/django-admin-interface) - the default admin interface made customizable by the admin itself. popup windows replaced by modals. 🧙 ⚡ - [`django-colorfield`](https://github.com/fabiocaccamo/django-colorfield) - simple color field for models with a nice color-picker in the admin. 🎨 - [`django-extra-settings`](https://github.com/fabiocaccamo/django-extra-settings) - config and manage typed extra settings using just the django admin. ⚙️ - [`django-redirects`](https://github.com/fabiocaccamo/django-redirects) - redirects with full control. ↪️ - [`django-treenode`](https://github.com/fabiocaccamo/django-treenode) - probably the best abstract model / admin for your tree based stuff. 🌳 - [`python-benedict`](https://github.com/fabiocaccamo/python-benedict) - dict subclass with keylist/keypath support, I/O shortcuts (base64, csv, json, pickle, plist, query-string, toml, xml, yaml) and many utilities. 📘 - [`python-codicefiscale`](https://github.com/fabiocaccamo/python-codicefiscale) - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. 🇮🇹 💳 - [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - file-system utilities for lazy devs. 🧟‍♂️ Keywords: django,maintenance,mode,offline,under,503,service,temporarily,unavailable Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Framework :: Django Classifier: Framework :: Django :: 1.7 Classifier: Framework :: Django :: 1.8 Classifier: Framework :: Django :: 1.9 Classifier: Framework :: Django :: 1.10 Classifier: Framework :: Django :: 1.11 Classifier: Framework :: Django :: 2.0 Classifier: Framework :: Django :: 2.1 Classifier: Framework :: Django :: 2.2 Classifier: Framework :: Django :: 3.0 Classifier: Framework :: Django :: 3.1 Classifier: Framework :: Django :: 3.2 Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Topic :: Software Development :: Build Tools Requires: django(>=1.7) Description-Content-Type: text/markdown ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1632467519.0 django-maintenance-mode-0.16.1/README.md0000644000076500000240000002454600000000000021250 0ustar00fabiocaccamostaff00000000000000[![](https://img.shields.io/pypi/pyversions/django-maintenance-mode.svg?color=3776AB&logo=python&logoColor=white)](https://www.python.org/) [![](https://img.shields.io/pypi/djversions/django-maintenance-mode?color=0C4B33&logo=django&logoColor=white&label=django)](https://www.djangoproject.com/) [![](https://img.shields.io/pypi/v/django-maintenance-mode.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/django-maintenance-mode/) [![](https://pepy.tech/badge/django-maintenance-mode)](https://pepy.tech/project/django-maintenance-mode) [![](https://img.shields.io/github/stars/fabiocaccamo/django-maintenance-mode?logo=github)](https://github.com/fabiocaccamo/django-maintenance-mode/) [![](https://badges.pufler.dev/visits/fabiocaccamo/django-maintenance-mode?label=visitors&color=blue)](https://badges.pufler.dev) [![](https://img.shields.io/pypi/l/django-maintenance-mode.svg?color=blue)](https://github.com/fabiocaccamo/django-maintenance-mode/blob/master/LICENSE.txt) [![](https://img.shields.io/travis/fabiocaccamo/django-maintenance-mode?logo=travis&label=build)](https://travis-ci.org/fabiocaccamo/django-maintenance-mode) [![](https://img.shields.io/codecov/c/gh/fabiocaccamo/django-maintenance-mode?logo=codecov)](https://codecov.io/gh/fabiocaccamo/django-maintenance-mode) [![](https://img.shields.io/codacy/grade/918668ac85e74206a4d8d95923548d79?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/django-maintenance-mode) [![](https://img.shields.io/codeclimate/maintainability/fabiocaccamo/django-maintenance-mode?logo=code-climate)](https://codeclimate.com/github/fabiocaccamo/django-maintenance-mode/) [![](https://requires.io/github/fabiocaccamo/django-maintenance-mode/requirements.svg?branch=master)](https://requires.io/github/fabiocaccamo/django-maintenance-mode/requirements/?branch=master) # django-maintenance-mode django-maintenance-mode shows a 503 error page when **maintenance-mode** is **on**. It works at application level, so your django instance should be up. It doesn't use database and doesn't prevent database access. ## Installation 1. Run ``pip install django-maintenance-mode`` or [download django-maintenance-mode](http://pypi.python.org/pypi/django-maintenance-mode) and add the **maintenance_mode** package to your project 2. Add ``'maintenance_mode'`` to ``settings.INSTALLED_APPS`` before custom applications 3. Add ``'maintenance_mode.middleware.MaintenanceModeMiddleware'`` to ``settings.MIDDLEWARE_CLASSES``/``settings.MIDDLEWARE`` as last middleware 4. Add your custom ``templates/503.html`` file 5. Restart your application server ## Configuration (optional) ### Settings All these settings are optional, if not defined in ``settings.py`` the default values (listed below) will be used. ```python # if True the maintenance-mode will be activated MAINTENANCE_MODE = None ``` ```python # by default, to get/set the state value a local file backend is used # if you want to use the db or cache, you can create a custom backend # custom backends must extend 'maintenance_mode.backends.AbstractStateBackend' class # and implement get_value(self) and set_value(self, val) methods MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.LocalFileBackend' # alternatively it is possible to use the default storage backend MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.DefaultStorageBackend' ``` ```python # by default, a file named "maintenance_mode_state.txt" will be created in the settings.py directory # you can customize the state file path in case the default one is not writable MAINTENANCE_MODE_STATE_FILE_PATH = 'maintenance_mode_state.txt' ``` ```python # if True admin site will not be affected by the maintenance-mode page MAINTENANCE_MODE_IGNORE_ADMIN_SITE = False ``` ```python # if True anonymous users will not see the maintenance-mode page MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER = False ``` ```python # if True authenticated users will not see the maintenance-mode page MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER = False ``` ```python # if True the staff will not see the maintenance-mode page MAINTENANCE_MODE_IGNORE_STAFF = False ``` ```python # if True the superuser will not see the maintenance-mode page MAINTENANCE_MODE_IGNORE_SUPERUSER = False ``` ```python # list of ip-addresses that will not be affected by the maintenance-mode # ip-addresses will be used to compile regular expressions objects MAINTENANCE_MODE_IGNORE_IP_ADDRESSES = () ``` ```python # the path of the function that will return the client IP address given the request object -> 'myapp.mymodule.myfunction' # the default function ('maintenance_mode.utils.get_client_ip_address') returns request.META['REMOTE_ADDR'] # in some cases the default function returns None, to avoid this scenario just use 'django-ipware' MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = None ``` Retrieve user's real IP address using [`django-ipware`](https://github.com/un33k/django-ipware): ```python MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = 'ipware.ip.get_ip' ``` ```python # list of urls that will not be affected by the maintenance-mode # urls will be used to compile regular expressions objects MAINTENANCE_MODE_IGNORE_URLS = () ``` ```python # if True the maintenance mode will not return 503 response while running tests # useful for running tests while maintenance mode is on, before opening the site to public use MAINTENANCE_MODE_IGNORE_TESTS = False ``` ```python # the absolute url where users will be redirected to during maintenance-mode MAINTENANCE_MODE_REDIRECT_URL = None ``` ```python # the template that will be shown by the maintenance-mode page MAINTENANCE_MODE_TEMPLATE = '503.html' ``` ```python # the path of the function that will return the template context -> 'myapp.mymodule.myfunction' MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT = None ``` ```python # the HTTP status code to send MAINTENANCE_MODE_STATUS_CODE = 503 ``` ```python # the value in seconds of the Retry-After header during maintenance-mode MAINTENANCE_MODE_RETRY_AFTER = 3600 # 1 hour ``` #### Context Processors Add **maintenance_mode.context_processors.maintenance_mode** to your context_processors list in ``settings.py`` if you want to access the maintenance_mode status in your templates. ```python TEMPLATES = [ { # ... 'OPTIONS': { 'context_processors': [ # ... 'maintenance_mode.context_processors.maintenance_mode', # ... ], }, # ... }, ] ``` #### Logging You can disable emailing 503 errors to admins while maintenance mode is enabled: ```python LOGGING = { 'filters': { 'require_not_maintenance_mode_503': { '()': 'maintenance_mode.logging.RequireNotMaintenanceMode503', }, ... }, 'handlers': { ... }, ... } ``` ### Context Managers You can force a block of code execution to run under maintenance mode or not using context managers: ```python from maintenance_mode.core import maintenance_mode_off, maintenance_mode_on with maintenance_mode_on(): # do stuff pass with maintenance_mode_off(): # do stuff pass ``` ### URLs Add **maintenance_mode.urls** to ``urls.py`` if you want superusers able to set maintenance_mode using urls. ```python urlpatterns = [ # ... url(r'^maintenance-mode/', include('maintenance_mode.urls')), # ... ] ``` ### Views You can force maintenance mode on/off at view level using view decorators: ```python from maintenance_mode.decorators import force_maintenance_mode_off, force_maintenance_mode_on @force_maintenance_mode_off def my_view_a(request): # never return 503 response pass @force_maintenance_mode_on def my_view_b(request): # always return 503 response pass ``` ## Usage ### Python ```python from maintenance_mode.core import get_maintenance_mode, set_maintenance_mode set_maintenance_mode(True) if get_maintenance_mode(): set_maintenance_mode(False) ``` or ```python from django.core.management import call_command from django.core.management.base import BaseCommand class Command(BaseCommand): def handle(self, *args, **options): call_command('maintenance_mode', 'on') # call your command(s) call_command('maintenance_mode', 'off') ``` ### Templates ```html {% if maintenance_mode %} {% endif %} ``` ### Terminal Run ``python manage.py maintenance_mode `` *(**This is not Heroku-friendly because** any execution of heroku run* `manage.py` *will be run on a separate worker dyno, not the web one. Therefore **the state-file is set but on the wrong machine. You should use a custom*** `MAINTENANCE_MODE_STATE_BACKEND`*.)* ### URLs Superusers can change maintenance-mode using the following urls: ``/maintenance-mode/off/`` ``/maintenance-mode/on/`` ## Testing ```bash # create python virtual environment virtualenv testing_django_maintenance_mode # activate virtualenv cd testing_django_maintenance_mode && . bin/activate # clone repo git clone https://github.com/fabiocaccamo/django-maintenance-mode.git src && cd src # run tests tox # or python setup.py test # or python -m django test --settings "tests.settings" ``` ## License Released under [MIT License](LICENSE.txt). --- ## See also - [`django-admin-interface`](https://github.com/fabiocaccamo/django-admin-interface) - the default admin interface made customizable by the admin itself. popup windows replaced by modals. 🧙 ⚡ - [`django-colorfield`](https://github.com/fabiocaccamo/django-colorfield) - simple color field for models with a nice color-picker in the admin. 🎨 - [`django-extra-settings`](https://github.com/fabiocaccamo/django-extra-settings) - config and manage typed extra settings using just the django admin. ⚙️ - [`django-redirects`](https://github.com/fabiocaccamo/django-redirects) - redirects with full control. ↪️ - [`django-treenode`](https://github.com/fabiocaccamo/django-treenode) - probably the best abstract model / admin for your tree based stuff. 🌳 - [`python-benedict`](https://github.com/fabiocaccamo/python-benedict) - dict subclass with keylist/keypath support, I/O shortcuts (base64, csv, json, pickle, plist, query-string, toml, xml, yaml) and many utilities. 📘 - [`python-codicefiscale`](https://github.com/fabiocaccamo/python-codicefiscale) - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. 🇮🇹 💳 - [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - file-system utilities for lazy devs. 🧟‍♂️ ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1632467929.487803 django-maintenance-mode-0.16.1/django_maintenance_mode.egg-info/0000755000076500000240000000000000000000000026260 5ustar00fabiocaccamostaff00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1632467929.0 django-maintenance-mode-0.16.1/django_maintenance_mode.egg-info/PKG-INFO0000644000076500000240000003503200000000000027360 0ustar00fabiocaccamostaff00000000000000Metadata-Version: 2.1 Name: django-maintenance-mode Version: 0.16.1 Summary: django-maintenance-mode shows a 503 error page when maintenance-mode is on. Home-page: https://github.com/fabiocaccamo/django-maintenance-mode Author: Fabio Caccamo Author-email: fabio.caccamo@gmail.com License: MIT Download-URL: https://github.com/fabiocaccamo/django-maintenance-mode/archive/0.16.1.tar.gz Description: [![](https://img.shields.io/pypi/pyversions/django-maintenance-mode.svg?color=3776AB&logo=python&logoColor=white)](https://www.python.org/) [![](https://img.shields.io/pypi/djversions/django-maintenance-mode?color=0C4B33&logo=django&logoColor=white&label=django)](https://www.djangoproject.com/) [![](https://img.shields.io/pypi/v/django-maintenance-mode.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/django-maintenance-mode/) [![](https://pepy.tech/badge/django-maintenance-mode)](https://pepy.tech/project/django-maintenance-mode) [![](https://img.shields.io/github/stars/fabiocaccamo/django-maintenance-mode?logo=github)](https://github.com/fabiocaccamo/django-maintenance-mode/) [![](https://badges.pufler.dev/visits/fabiocaccamo/django-maintenance-mode?label=visitors&color=blue)](https://badges.pufler.dev) [![](https://img.shields.io/pypi/l/django-maintenance-mode.svg?color=blue)](https://github.com/fabiocaccamo/django-maintenance-mode/blob/master/LICENSE.txt) [![](https://img.shields.io/travis/fabiocaccamo/django-maintenance-mode?logo=travis&label=build)](https://travis-ci.org/fabiocaccamo/django-maintenance-mode) [![](https://img.shields.io/codecov/c/gh/fabiocaccamo/django-maintenance-mode?logo=codecov)](https://codecov.io/gh/fabiocaccamo/django-maintenance-mode) [![](https://img.shields.io/codacy/grade/918668ac85e74206a4d8d95923548d79?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/django-maintenance-mode) [![](https://img.shields.io/codeclimate/maintainability/fabiocaccamo/django-maintenance-mode?logo=code-climate)](https://codeclimate.com/github/fabiocaccamo/django-maintenance-mode/) [![](https://requires.io/github/fabiocaccamo/django-maintenance-mode/requirements.svg?branch=master)](https://requires.io/github/fabiocaccamo/django-maintenance-mode/requirements/?branch=master) # django-maintenance-mode django-maintenance-mode shows a 503 error page when **maintenance-mode** is **on**. It works at application level, so your django instance should be up. It doesn't use database and doesn't prevent database access. ## Installation 1. Run ``pip install django-maintenance-mode`` or [download django-maintenance-mode](http://pypi.python.org/pypi/django-maintenance-mode) and add the **maintenance_mode** package to your project 2. Add ``'maintenance_mode'`` to ``settings.INSTALLED_APPS`` before custom applications 3. Add ``'maintenance_mode.middleware.MaintenanceModeMiddleware'`` to ``settings.MIDDLEWARE_CLASSES``/``settings.MIDDLEWARE`` as last middleware 4. Add your custom ``templates/503.html`` file 5. Restart your application server ## Configuration (optional) ### Settings All these settings are optional, if not defined in ``settings.py`` the default values (listed below) will be used. ```python # if True the maintenance-mode will be activated MAINTENANCE_MODE = None ``` ```python # by default, to get/set the state value a local file backend is used # if you want to use the db or cache, you can create a custom backend # custom backends must extend 'maintenance_mode.backends.AbstractStateBackend' class # and implement get_value(self) and set_value(self, val) methods MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.LocalFileBackend' # alternatively it is possible to use the default storage backend MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.DefaultStorageBackend' ``` ```python # by default, a file named "maintenance_mode_state.txt" will be created in the settings.py directory # you can customize the state file path in case the default one is not writable MAINTENANCE_MODE_STATE_FILE_PATH = 'maintenance_mode_state.txt' ``` ```python # if True admin site will not be affected by the maintenance-mode page MAINTENANCE_MODE_IGNORE_ADMIN_SITE = False ``` ```python # if True anonymous users will not see the maintenance-mode page MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER = False ``` ```python # if True authenticated users will not see the maintenance-mode page MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER = False ``` ```python # if True the staff will not see the maintenance-mode page MAINTENANCE_MODE_IGNORE_STAFF = False ``` ```python # if True the superuser will not see the maintenance-mode page MAINTENANCE_MODE_IGNORE_SUPERUSER = False ``` ```python # list of ip-addresses that will not be affected by the maintenance-mode # ip-addresses will be used to compile regular expressions objects MAINTENANCE_MODE_IGNORE_IP_ADDRESSES = () ``` ```python # the path of the function that will return the client IP address given the request object -> 'myapp.mymodule.myfunction' # the default function ('maintenance_mode.utils.get_client_ip_address') returns request.META['REMOTE_ADDR'] # in some cases the default function returns None, to avoid this scenario just use 'django-ipware' MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = None ``` Retrieve user's real IP address using [`django-ipware`](https://github.com/un33k/django-ipware): ```python MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = 'ipware.ip.get_ip' ``` ```python # list of urls that will not be affected by the maintenance-mode # urls will be used to compile regular expressions objects MAINTENANCE_MODE_IGNORE_URLS = () ``` ```python # if True the maintenance mode will not return 503 response while running tests # useful for running tests while maintenance mode is on, before opening the site to public use MAINTENANCE_MODE_IGNORE_TESTS = False ``` ```python # the absolute url where users will be redirected to during maintenance-mode MAINTENANCE_MODE_REDIRECT_URL = None ``` ```python # the template that will be shown by the maintenance-mode page MAINTENANCE_MODE_TEMPLATE = '503.html' ``` ```python # the path of the function that will return the template context -> 'myapp.mymodule.myfunction' MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT = None ``` ```python # the HTTP status code to send MAINTENANCE_MODE_STATUS_CODE = 503 ``` ```python # the value in seconds of the Retry-After header during maintenance-mode MAINTENANCE_MODE_RETRY_AFTER = 3600 # 1 hour ``` #### Context Processors Add **maintenance_mode.context_processors.maintenance_mode** to your context_processors list in ``settings.py`` if you want to access the maintenance_mode status in your templates. ```python TEMPLATES = [ { # ... 'OPTIONS': { 'context_processors': [ # ... 'maintenance_mode.context_processors.maintenance_mode', # ... ], }, # ... }, ] ``` #### Logging You can disable emailing 503 errors to admins while maintenance mode is enabled: ```python LOGGING = { 'filters': { 'require_not_maintenance_mode_503': { '()': 'maintenance_mode.logging.RequireNotMaintenanceMode503', }, ... }, 'handlers': { ... }, ... } ``` ### Context Managers You can force a block of code execution to run under maintenance mode or not using context managers: ```python from maintenance_mode.core import maintenance_mode_off, maintenance_mode_on with maintenance_mode_on(): # do stuff pass with maintenance_mode_off(): # do stuff pass ``` ### URLs Add **maintenance_mode.urls** to ``urls.py`` if you want superusers able to set maintenance_mode using urls. ```python urlpatterns = [ # ... url(r'^maintenance-mode/', include('maintenance_mode.urls')), # ... ] ``` ### Views You can force maintenance mode on/off at view level using view decorators: ```python from maintenance_mode.decorators import force_maintenance_mode_off, force_maintenance_mode_on @force_maintenance_mode_off def my_view_a(request): # never return 503 response pass @force_maintenance_mode_on def my_view_b(request): # always return 503 response pass ``` ## Usage ### Python ```python from maintenance_mode.core import get_maintenance_mode, set_maintenance_mode set_maintenance_mode(True) if get_maintenance_mode(): set_maintenance_mode(False) ``` or ```python from django.core.management import call_command from django.core.management.base import BaseCommand class Command(BaseCommand): def handle(self, *args, **options): call_command('maintenance_mode', 'on') # call your command(s) call_command('maintenance_mode', 'off') ``` ### Templates ```html {% if maintenance_mode %} {% endif %} ``` ### Terminal Run ``python manage.py maintenance_mode `` *(**This is not Heroku-friendly because** any execution of heroku run* `manage.py` *will be run on a separate worker dyno, not the web one. Therefore **the state-file is set but on the wrong machine. You should use a custom*** `MAINTENANCE_MODE_STATE_BACKEND`*.)* ### URLs Superusers can change maintenance-mode using the following urls: ``/maintenance-mode/off/`` ``/maintenance-mode/on/`` ## Testing ```bash # create python virtual environment virtualenv testing_django_maintenance_mode # activate virtualenv cd testing_django_maintenance_mode && . bin/activate # clone repo git clone https://github.com/fabiocaccamo/django-maintenance-mode.git src && cd src # run tests tox # or python setup.py test # or python -m django test --settings "tests.settings" ``` ## License Released under [MIT License](LICENSE.txt). --- ## See also - [`django-admin-interface`](https://github.com/fabiocaccamo/django-admin-interface) - the default admin interface made customizable by the admin itself. popup windows replaced by modals. 🧙 ⚡ - [`django-colorfield`](https://github.com/fabiocaccamo/django-colorfield) - simple color field for models with a nice color-picker in the admin. 🎨 - [`django-extra-settings`](https://github.com/fabiocaccamo/django-extra-settings) - config and manage typed extra settings using just the django admin. ⚙️ - [`django-redirects`](https://github.com/fabiocaccamo/django-redirects) - redirects with full control. ↪️ - [`django-treenode`](https://github.com/fabiocaccamo/django-treenode) - probably the best abstract model / admin for your tree based stuff. 🌳 - [`python-benedict`](https://github.com/fabiocaccamo/python-benedict) - dict subclass with keylist/keypath support, I/O shortcuts (base64, csv, json, pickle, plist, query-string, toml, xml, yaml) and many utilities. 📘 - [`python-codicefiscale`](https://github.com/fabiocaccamo/python-codicefiscale) - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. 🇮🇹 💳 - [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - file-system utilities for lazy devs. 🧟‍♂️ Keywords: django,maintenance,mode,offline,under,503,service,temporarily,unavailable Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Framework :: Django Classifier: Framework :: Django :: 1.7 Classifier: Framework :: Django :: 1.8 Classifier: Framework :: Django :: 1.9 Classifier: Framework :: Django :: 1.10 Classifier: Framework :: Django :: 1.11 Classifier: Framework :: Django :: 2.0 Classifier: Framework :: Django :: 2.1 Classifier: Framework :: Django :: 2.2 Classifier: Framework :: Django :: 3.0 Classifier: Framework :: Django :: 3.1 Classifier: Framework :: Django :: 3.2 Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Topic :: Software Development :: Build Tools Requires: django(>=1.7) Description-Content-Type: text/markdown ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1632467929.0 django-maintenance-mode-0.16.1/django_maintenance_mode.egg-info/SOURCES.txt0000644000076500000240000000146000000000000030145 0ustar00fabiocaccamostaff00000000000000LICENSE.txt MANIFEST.in README.md setup.cfg setup.py django_maintenance_mode.egg-info/PKG-INFO django_maintenance_mode.egg-info/SOURCES.txt django_maintenance_mode.egg-info/dependency_links.txt django_maintenance_mode.egg-info/top_level.txt maintenance_mode/__init__.py maintenance_mode/backends.py maintenance_mode/context_processors.py maintenance_mode/core.py maintenance_mode/decorators.py maintenance_mode/http.py maintenance_mode/io.py maintenance_mode/logging.py maintenance_mode/middleware.py maintenance_mode/settings.py maintenance_mode/urls.py maintenance_mode/utils.py maintenance_mode/version.py maintenance_mode/views.py maintenance_mode/management/__init__.py maintenance_mode/management/commands/__init__.py maintenance_mode/management/commands/maintenance_mode.py maintenance_mode/templates/503.html././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1632467929.0 django-maintenance-mode-0.16.1/django_maintenance_mode.egg-info/dependency_links.txt0000644000076500000240000000000100000000000032326 0ustar00fabiocaccamostaff00000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1632467929.0 django-maintenance-mode-0.16.1/django_maintenance_mode.egg-info/top_level.txt0000644000076500000240000000002100000000000031003 0ustar00fabiocaccamostaff00000000000000maintenance_mode ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1632467929.495489 django-maintenance-mode-0.16.1/maintenance_mode/0000755000076500000240000000000000000000000023244 5ustar00fabiocaccamostaff00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/maintenance_mode/__init__.py0000644000076500000240000000007700000000000025361 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- from maintenance_mode import settings ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1616499094.0 django-maintenance-mode-0.16.1/maintenance_mode/backends.py0000644000076500000240000000402100000000000025365 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- from django.conf import settings from django.core.files.base import ContentFile from django.core.files.storage import default_storage from maintenance_mode.io import read_file, write_file class AbstractStateBackend(object): @staticmethod def from_bool_to_str_value(value): value = str(int(value)) if value not in ['0', '1']: raise ValueError('state value is not 0|1') return value @staticmethod def from_str_to_bool_value(value): value = value.strip() if value not in ['0', '1']: raise ValueError('state value is not 0|1') value = bool(int(value)) return value def get_value(self): raise NotImplementedError() def set_value(self, value): raise NotImplementedError() class DefaultStorageBackend(AbstractStateBackend): """ django-maintenance-mode backend which uses the default storage. Kindly provided by Dominik George https://github.com/Natureshadow """ def get_value(self): filename = settings.MAINTENANCE_MODE_STATE_FILE_NAME try: with default_storage.open(filename, 'r') as statefile: return self.from_str_to_bool_value(statefile.read()) except IOError: return False def set_value(self, value): filename = settings.MAINTENANCE_MODE_STATE_FILE_NAME if default_storage.exists(filename): default_storage.delete(filename) content = ContentFile(self.from_bool_to_str_value(value)) default_storage.save(filename, content) class LocalFileBackend(AbstractStateBackend): """ django-maintenance-mode backend which uses the local file-sistem. """ def get_value(self): value = read_file(settings.MAINTENANCE_MODE_STATE_FILE_PATH, '0') value = self.from_str_to_bool_value(value) return value def set_value(self, value): value = self.from_bool_to_str_value(value) write_file(settings.MAINTENANCE_MODE_STATE_FILE_PATH, value) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/maintenance_mode/context_processors.py0000644000076500000240000000025200000000000027563 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- from maintenance_mode.core import get_maintenance_mode def maintenance_mode(request): return { 'maintenance_mode':get_maintenance_mode() } ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1599142392.0 django-maintenance-mode-0.16.1/maintenance_mode/core.py0000644000076500000240000000636300000000000024556 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- from django.conf import settings from django.core.exceptions import ImproperlyConfigured try: from contextlib import ContextDecorator except ImportError: # ContextDecorator was introduced in Django 1.8 from django.utils.decorators import available_attrs class ContextDecorator(object): """ A base class that enables a context manager to also be used as a decorator. """ def __call__(self, func): @wraps(func, assigned=available_attrs(func)) def inner(*args, **kwargs): with self: return func(*args, **kwargs) return inner from django.utils.module_loading import import_string from functools import wraps from maintenance_mode.backends import AbstractStateBackend def get_maintenance_mode_backend(): try: backend_class = import_string(settings.MAINTENANCE_MODE_STATE_BACKEND) if issubclass(backend_class, AbstractStateBackend) and \ backend_class != AbstractStateBackend: backend = backend_class() return backend else: raise ImproperlyConfigured( 'backend doesn\'t extend ' '\'maintenance_mode.backends.AbstractStateBackend\' class.') except ImportError: raise ImproperlyConfigured( 'backend not found, check ' '\'settings.MAINTENANCE_MODE_STATE_BACKEND\' path.') def get_maintenance_mode(): """ Get maintenance_mode state from state file. """ # If maintenance mode is defined in settings, it has priority. if settings.MAINTENANCE_MODE is not None: return settings.MAINTENANCE_MODE backend = get_maintenance_mode_backend() return backend.get_value() def set_maintenance_mode(value): """ Set maintenance_mode state to state file. """ # If maintenance mode is defined in settings, it can't be changed. if settings.MAINTENANCE_MODE is not None: raise ImproperlyConfigured( 'Maintenance mode cannot be set dynamically ' 'if defined in settings.') if not isinstance(value, bool): raise TypeError('value argument type is not boolean') backend = get_maintenance_mode_backend() backend.set_value(value) class override_maintenance_mode(ContextDecorator): """ Decorator/context manager to locally override a maintenance mode. @ivar value: Overriden value of maintenance mode @ivar old_value: Original value of maintenance mode """ def __init__(self, value): self.value = value self.old_value = None def __enter__(self): self.old_value = get_maintenance_mode() set_maintenance_mode(self.value) def __exit__(self, exc_type, exc_value, traceback): set_maintenance_mode(self.old_value) class maintenance_mode_on(override_maintenance_mode): """ Decorator/context manager to locally set maintenance mode to True. """ def __init__(self): super(maintenance_mode_on, self).__init__(True) class maintenance_mode_off(override_maintenance_mode): """ Decorator/context manager to locally set maintenance mode to False. """ def __init__(self): super(maintenance_mode_off, self).__init__(False) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/maintenance_mode/decorators.py0000644000076500000240000000111100000000000025755 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- from functools import wraps from maintenance_mode.http import get_maintenance_response def force_maintenance_mode_off(view_func): @wraps(view_func) def wrapper(request, *args, **kwargs): return view_func(request, *args, **kwargs) wrapper.__dict__['force_maintenance_mode_off'] = True return wrapper def force_maintenance_mode_on(view_func): @wraps(view_func) def wrapper(request, *args, **kwargs): return get_maintenance_response(request) wrapper.__dict__['force_maintenance_mode_on'] = True return wrapper ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/maintenance_mode/http.py0000644000076500000240000001401000000000000024571 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- import django from django.conf import settings from django.core.exceptions import ImproperlyConfigured if django.VERSION < (2, 0): from django.core.urlresolvers import ( NoReverseMatch, resolve, Resolver404, reverse, ) else: from django.urls import ( NoReverseMatch, resolve, Resolver404, reverse, ) from django.shortcuts import render, redirect from django.template import RequestContext from django.utils.cache import add_never_cache_headers from django.utils.module_loading import import_string from maintenance_mode.core import get_maintenance_mode from maintenance_mode.utils import get_client_ip_address import re try: # since python 3.7 pattern_class = re.Pattern except AttributeError: # before python 3.7 pattern_class = re._pattern_type import sys def get_maintenance_response(request): """ Return a '503 Service Unavailable' maintenance response. """ if settings.MAINTENANCE_MODE_REDIRECT_URL: return redirect(settings.MAINTENANCE_MODE_REDIRECT_URL) context = {} if settings.MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT: try: get_request_context_func = import_string( settings.MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT) except ImportError: raise ImproperlyConfigured( 'settings.MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT ' 'is not a valid function path.' ) context = get_request_context_func(request=request) kwargs = {'context': context} if django.VERSION < (1, 8): kwargs = {'context_instance': RequestContext(request, context)} response = render(request, settings.MAINTENANCE_MODE_TEMPLATE, status=settings.MAINTENANCE_MODE_STATUS_CODE, **kwargs) response['Retry-After'] = settings.MAINTENANCE_MODE_RETRY_AFTER add_never_cache_headers(response) return response def need_maintenance_response(request): """ Tells if the given request needs a maintenance response or not. """ try: view_match = resolve(request.path) view_func = view_match[0] view_dict = view_func.__dict__ view_force_maintenance_mode_off = view_dict.get( 'force_maintenance_mode_off', False) if view_force_maintenance_mode_off: # view has 'force_maintenance_mode_off' decorator return False view_force_maintenance_mode_on = view_dict.get( 'force_maintenance_mode_on', False) if view_force_maintenance_mode_on: # view has 'force_maintenance_mode_on' decorator return True except Resolver404: pass if not get_maintenance_mode(): return False try: url_off = reverse('maintenance_mode_off') resolve(url_off) if url_off == request.path_info: return False except NoReverseMatch: # maintenance_mode.urls not added pass if hasattr(request, 'user'): if django.VERSION < (1, 10): if settings.MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER \ and request.user.is_anonymous(): return False if settings.MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER \ and request.user.is_authenticated(): return False else: if settings.MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER \ and request.user.is_anonymous: return False if settings.MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER \ and request.user.is_authenticated: return False if settings.MAINTENANCE_MODE_IGNORE_STAFF \ and request.user.is_staff: return False if settings.MAINTENANCE_MODE_IGNORE_SUPERUSER \ and request.user.is_superuser: return False if settings.MAINTENANCE_MODE_IGNORE_ADMIN_SITE: try: request_path = request.path if request.path else '' if not request_path.endswith('/'): request_path += '/' admin_url = reverse('admin:index') if request_path.startswith(admin_url): return False except NoReverseMatch: # admin.urls not added pass if settings.MAINTENANCE_MODE_IGNORE_TESTS: is_testing = False if (len(sys.argv) > 0 and 'runtests' in sys.argv[0]) \ or (len(sys.argv) > 1 and sys.argv[1] == 'test'): # python runtests.py | python manage.py test | python # setup.py test | django-admin.py test is_testing = True if is_testing: return False if settings.MAINTENANCE_MODE_IGNORE_IP_ADDRESSES: if settings.MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS: try: get_client_ip_address_func = import_string( settings.MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS) except ImportError: raise ImproperlyConfigured( 'settings.MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS ' 'is not a valid function path.') else: client_ip_address = get_client_ip_address_func(request) else: client_ip_address = get_client_ip_address(request) for ip_address in settings.MAINTENANCE_MODE_IGNORE_IP_ADDRESSES: ip_address_re = re.compile(ip_address) if ip_address_re.match(client_ip_address): return False if settings.MAINTENANCE_MODE_IGNORE_URLS: for url in settings.MAINTENANCE_MODE_IGNORE_URLS: if not isinstance(url, pattern_class): url = str(url) url_re = re.compile(url) if url_re.match(request.path_info): return False if settings.MAINTENANCE_MODE_REDIRECT_URL: redirect_url_re = re.compile( settings.MAINTENANCE_MODE_REDIRECT_URL) if redirect_url_re.match(request.path_info): return False return True ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/maintenance_mode/io.py0000644000076500000240000000124200000000000024224 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- import os def read_file(file_path, default_content=''): """ Read file at the specified path. If file doesn't exist, it will be created with default-content. Returns the file content. """ if not os.path.exists(file_path): write_file(file_path, default_content) handler = open(file_path, 'r') content = handler.read() handler.close() return content or default_content def write_file(file_path, content): """ Write file at the specified path with content. If file exists, it will be overwritten. """ handler = open(file_path, 'w+') handler.write(content) handler.close() ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1632467655.0 django-maintenance-mode-0.16.1/maintenance_mode/logging.py0000644000076500000240000000115400000000000025245 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- from __future__ import absolute_import from django.conf import settings from maintenance_mode.core import get_maintenance_mode import logging class RequireNotMaintenanceMode503(logging.Filter): """ Filters out 503 errors if maintenance mode is activated. """ def filter(self, record): """ Return False if maintenance mode is on and the given record has a status code of 503. """ status_code = getattr(record, 'status_code', None) if get_maintenance_mode() and status_code == 503: return False return True ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1632467929.4960938 django-maintenance-mode-0.16.1/maintenance_mode/management/0000755000076500000240000000000000000000000025360 5ustar00fabiocaccamostaff00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/maintenance_mode/management/__init__.py0000644000076500000240000000000000000000000027457 0ustar00fabiocaccamostaff00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1632467929.4968636 django-maintenance-mode-0.16.1/maintenance_mode/management/commands/0000755000076500000240000000000000000000000027161 5ustar00fabiocaccamostaff00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/maintenance_mode/management/commands/__init__.py0000644000076500000240000000000000000000000031260 0ustar00fabiocaccamostaff00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/maintenance_mode/management/commands/maintenance_mode.py0000644000076500000240000000611100000000000033020 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- from __future__ import absolute_import import django from django.conf import settings from django.core.management.base import BaseCommand, CommandError from maintenance_mode import core class Command(BaseCommand): args = '' help = 'run python manage.py maintenance_mode %s '\ 'to change maintenance-mode state' % args def add_arguments(self, parser): parser.add_argument('state') parser.add_argument('--interactive', dest='interactive', action='store_true') def get_maintenance_mode(self): try: value = core.get_maintenance_mode() return value except IOError: raise CommandError( 'Unable to read state file at: %s' % ( settings.MAINTENANCE_MODE_STATE_FILE_NAME, )) def set_maintenance_mode(self, value): try: core.set_maintenance_mode(value) except IOError: raise CommandError( 'Unable to write state file at: %s' % ( settings.MAINTENANCE_MODE_STATE_FILE_NAME, )) def set_maintenance_mode_with_confirm(self, value, confirm_message, interactive): if interactive: if self.confirm(confirm_message): self.set_maintenance_mode(value) else: self.set_maintenance_mode(value) def confirm(self, message): # Fix for Python 2.x. try: input_func = raw_input except NameError: input_func = input answer = input_func(message) answer = answer.lower() return answer.find('y') == 0 def handle(self, *args, **options): verbosity = int(options['verbosity']) verbose = True if verbosity == 3 else False interactive = options.get('interactive', False) if django.VERSION < (1, 8): if len(args) != 1: raise CommandError( 'Expected 1 argument: %s' % (self.args, )) state = args[0] else: state = options['state'] state = state.lower() value = self.get_maintenance_mode() if state in ['on', 'yes', 'true', '1']: if value: if verbose: self.stdout.write('maintenance mode is already on') return self.set_maintenance_mode_with_confirm( True, 'maintenance mode on? (y/N) ', interactive) elif state in ['off', 'no', 'false', '0']: if not value: if verbose: self.stdout.write('maintenance mode is already off') return self.set_maintenance_mode_with_confirm( False, 'maintenance mode off? (y/N) ', interactive) else: raise CommandError('Invalid argument: \'%s\' ' 'expected %s' % (state, self.args, )) if verbose: output = 'maintenance mode: %s' % ( 'on' if self.get_maintenance_mode() else 'off', ) self.stdout.write(output) return ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/maintenance_mode/middleware.py0000644000076500000240000000127500000000000025740 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- import django if django.VERSION < (1, 10): __MaintenanceModeMiddlewareBaseClass = object else: # https://docs.djangoproject.com/en/1.10/topics/http/middleware/#upgrading-pre-django-1-10-style-middleware from django.utils.deprecation import MiddlewareMixin __MaintenanceModeMiddlewareBaseClass = MiddlewareMixin from maintenance_mode.http import ( get_maintenance_response, need_maintenance_response, ) class MaintenanceModeMiddleware(__MaintenanceModeMiddlewareBaseClass): def process_request(self, request): if need_maintenance_response(request): return get_maintenance_response(request) else: return None ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1616490814.0 django-maintenance-mode-0.16.1/maintenance_mode/settings.py0000644000076500000240000000474600000000000025471 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- from django.conf import settings from django.utils.module_loading import import_module import os if not hasattr(settings, 'MAINTENANCE_MODE'): settings.MAINTENANCE_MODE = None if not hasattr(settings, 'MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS'): settings.MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = None if not hasattr(settings, 'MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT'): settings.MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT = None if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_ADMIN_SITE'): settings.MAINTENANCE_MODE_IGNORE_ADMIN_SITE = None if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER'): settings.MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER = False if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER'): settings.MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER = False if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_IP_ADDRESSES'): settings.MAINTENANCE_MODE_IGNORE_IP_ADDRESSES = None if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_STAFF'): settings.MAINTENANCE_MODE_IGNORE_STAFF = False if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_SUPERUSER'): settings.MAINTENANCE_MODE_IGNORE_SUPERUSER = False if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_TESTS'): settings.MAINTENANCE_MODE_IGNORE_TESTS = False if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_URLS'): settings.MAINTENANCE_MODE_IGNORE_URLS = None if not hasattr(settings, 'MAINTENANCE_MODE_REDIRECT_URL'): settings.MAINTENANCE_MODE_REDIRECT_URL = None if not hasattr(settings, 'MAINTENANCE_MODE_STATE_BACKEND'): settings.MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.LocalFileBackend' if not hasattr(settings, 'MAINTENANCE_MODE_STATE_FILE_NAME'): settings.MAINTENANCE_MODE_STATE_FILE_NAME = 'maintenance_mode_state.txt' if not hasattr(settings, 'MAINTENANCE_MODE_STATE_FILE_PATH'): settings_module = import_module(os.environ['DJANGO_SETTINGS_MODULE']) settings_path = settings_module.__file__ settings_dir = os.path.dirname(settings_path) settings.MAINTENANCE_MODE_STATE_FILE_PATH = os.path.abspath( os.path.join(settings_dir, settings.MAINTENANCE_MODE_STATE_FILE_NAME)) if not hasattr(settings, 'MAINTENANCE_MODE_TEMPLATE'): settings.MAINTENANCE_MODE_TEMPLATE = '503.html' if not hasattr(settings, 'MAINTENANCE_MODE_STATUS_CODE'): settings.MAINTENANCE_MODE_STATUS_CODE = 503 if not hasattr(settings, 'MAINTENANCE_MODE_RETRY_AFTER'): settings.MAINTENANCE_MODE_RETRY_AFTER = 3600 ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1632467929.497617 django-maintenance-mode-0.16.1/maintenance_mode/templates/0000755000076500000240000000000000000000000025242 5ustar00fabiocaccamostaff00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/maintenance_mode/templates/503.html0000644000076500000240000000002700000000000026436 0ustar00fabiocaccamostaff00000000000000django-maintenance-mode././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/maintenance_mode/urls.py0000644000076500000240000000062300000000000024604 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- import django if django.VERSION < (2, 0): from django.conf.urls import url as re_path else: from django.urls import re_path from maintenance_mode.views import maintenance_mode_off, maintenance_mode_on urlpatterns = [ re_path(r'^off/$', maintenance_mode_off, name='maintenance_mode_off'), re_path(r'^on/$', maintenance_mode_on, name='maintenance_mode_on'), ] ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/maintenance_mode/utils.py0000644000076500000240000000022300000000000024753 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- def get_client_ip_address(request): """ Get the client IP Address. """ return request.META['REMOTE_ADDR'] ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1632467885.0 django-maintenance-mode-0.16.1/maintenance_mode/version.py0000644000076500000240000000006000000000000025277 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- __version__ = '0.16.1' ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1598515656.0 django-maintenance-mode-0.16.1/maintenance_mode/views.py0000644000076500000240000000122600000000000024754 0ustar00fabiocaccamostaff00000000000000# -*- coding: utf-8 -*- from django.http import HttpResponseRedirect from maintenance_mode.core import set_maintenance_mode def maintenance_mode_off(request): """ Deactivate maintenance-mode and redirect to site root. Only superusers are allowed to use this view. """ if request.user.is_superuser: set_maintenance_mode(False) return HttpResponseRedirect('/') def maintenance_mode_on(request): """ Activate maintenance-mode and redirect to site root. Only superusers are allowed to use this view. """ if request.user.is_superuser: set_maintenance_mode(True) return HttpResponseRedirect('/') ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1632467929.4989421 django-maintenance-mode-0.16.1/setup.cfg0000644000076500000240000000011700000000000021576 0ustar00fabiocaccamostaff00000000000000[metadata] description-file = README.md [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1618214676.0 django-maintenance-mode-0.16.1/setup.py0000644000076500000240000000517100000000000021474 0ustar00fabiocaccamostaff00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from setuptools import setup, find_packages import os, sys exec(open('maintenance_mode/version.py').read()) github_url = 'https://github.com/fabiocaccamo' package_name = 'django-maintenance-mode' package_url = '{}/{}'.format(github_url, package_name) package_path = os.path.abspath(os.path.dirname(__file__)) long_description_file_path = os.path.join(package_path, 'README.md') long_description_content_type = 'text/markdown' long_description = '' try: long_description_file_options = {} if sys.version_info[0] < 3 else { 'encoding':'utf-8' } with open(long_description_file_path, 'r', **long_description_file_options) as f: long_description = f.read() except IOError: pass setup( name=package_name, packages=find_packages(exclude=['contrib', 'docs', 'tests*']), version=__version__, description='django-maintenance-mode shows a 503 error page when maintenance-mode is on.', long_description=long_description, long_description_content_type=long_description_content_type, author='Fabio Caccamo', author_email='fabio.caccamo@gmail.com', url=package_url, download_url='{}/archive/{}.tar.gz'.format(package_url, __version__), keywords=['django', 'maintenance', 'mode', 'offline', 'under', '503', 'service', 'temporarily', 'unavailable'], requires=['django(>=1.7)'], classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Framework :: Django', 'Framework :: Django :: 1.7', 'Framework :: Django :: 1.8', 'Framework :: Django :: 1.9', 'Framework :: Django :: 1.10', 'Framework :: Django :: 1.11', 'Framework :: Django :: 2.0', 'Framework :: Django :: 2.1', 'Framework :: Django :: 2.2', 'Framework :: Django :: 3.0', 'Framework :: Django :: 3.1', 'Framework :: Django :: 3.2', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Topic :: Software Development :: Build Tools', ], license='MIT', test_suite='runtests.runtests' )