main: Separate out Django setup into a separate module

This has less to do with abstraction than to do with modularization.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit is contained in:
Sunil Mohan Adapa 2019-01-08 17:31:23 -08:00 committed by Joseph Nuthalapati
parent 3d68f38738
commit 40ecce554f
2 changed files with 177 additions and 139 deletions

View File

@ -20,17 +20,13 @@ import argparse
import importlib import importlib
import logging import logging
import os import os
import stat
import sys import sys
import axes import axes
import cherrypy import cherrypy
import django.conf
import django.core.management
import django.core.wsgi
from django.contrib.messages import constants as message_constants
from . import cfg, frontpage, log, menu, module_loader, service, setup from . import (cfg, frontpage, log, menu, module_loader, service, setup,
web_framework)
axes.default_app_config = "plinth.axes_app_config.AppConfig" axes.default_app_config = "plinth.axes_app_config.AppConfig"
precedence_commandline_arguments = ["server_dir", "develop"] precedence_commandline_arguments = ["server_dir", "develop"]
@ -93,11 +89,11 @@ def setup_server():
'engine.autoreload.on': cfg.develop, 'engine.autoreload.on': cfg.develop,
}) })
application = django.core.wsgi.get_wsgi_application() application = web_framework.get_wsgi_application()
cherrypy.tree.graft(application, cfg.server_dir) cherrypy.tree.graft(application, cfg.server_dir)
static_dir = os.path.join(cfg.file_root, 'static') static_dir = os.path.join(cfg.file_root, 'static')
_mount_static_directory(static_dir, django.conf.settings.STATIC_URL) _mount_static_directory(static_dir, web_framework.get_static_url())
custom_static_dir = cfg.custom_static_dir custom_static_dir = cfg.custom_static_dir
custom_static_url = '/plinth/custom/static' custom_static_url = '/plinth/custom/static'
@ -121,7 +117,7 @@ def setup_server():
if not os.path.isdir(static_dir): if not os.path.isdir(static_dir):
continue continue
urlprefix = "%s%s" % (django.conf.settings.STATIC_URL, module_name) urlprefix = "%s%s" % (web_framework.get_static_url(), module_name)
_mount_static_directory(static_dir, urlprefix) _mount_static_directory(static_dir, urlprefix)
cherrypy.engine.signal_handler.subscribe() cherrypy.engine.signal_handler.subscribe()
@ -132,135 +128,6 @@ def on_server_stop():
setup.stop() setup.stop()
def configure_django():
"""Setup Django configuration in the absence of .settings file"""
templates = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.request',
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'plinth.context_processors.common',
],
},
},
]
applications = [
'axes',
'captcha',
'bootstrapform',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.messages',
'stronghold',
'plinth',
]
applications += module_loader.get_modules_to_load()
sessions_directory = os.path.join(cfg.data_dir, 'sessions')
secure_proxy_ssl_header = None
if cfg.secure_proxy_ssl_header:
secure_proxy_ssl_header = (cfg.secure_proxy_ssl_header, 'https')
pwd = 'django.contrib.auth.password_validation'
django.conf.settings.configure(
ALLOWED_HOSTS=['*'],
AUTH_PASSWORD_VALIDATORS=[
{
'NAME': '{}.UserAttributeSimilarityValidator'.format(pwd),
},
{
'NAME': '{}.MinimumLengthValidator'.format(pwd),
'OPTIONS': {
'min_length': 8,
}
},
{
'NAME': '{}.CommonPasswordValidator'.format(pwd),
},
{
'NAME': '{}.NumericPasswordValidator'.format(pwd),
},
],
AXES_LOCKOUT_URL='locked/',
AXES_BEHIND_REVERSE_PROXY=True,
CACHES={
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache'
}
},
CAPTCHA_FONT_PATH=[
'/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf'
],
CAPTCHA_LENGTH=6,
CAPTCHA_FLITE_PATH='/usr/bin/flite',
DATABASES={
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': cfg.store_file
}
},
DEBUG=cfg.develop,
FORCE_SCRIPT_NAME=cfg.server_dir,
INSTALLED_APPS=applications,
IPWARE_META_PRECEDENCE_ORDER=('HTTP_X_FORWARDED_FOR', ),
LOGGING=log.get_configuration(),
LOGIN_URL='users:login',
LOGIN_REDIRECT_URL='index',
MESSAGE_TAGS={message_constants.ERROR: 'danger'},
MIDDLEWARE=(
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'stronghold.middleware.LoginRequiredMiddleware',
'plinth.middleware.AdminRequiredMiddleware',
'plinth.middleware.FirstSetupMiddleware',
'plinth.modules.first_boot.middleware.FirstBootMiddleware',
'plinth.middleware.SetupMiddleware',
),
ROOT_URLCONF='plinth.urls',
SECURE_BROWSER_XSS_FILTER=True,
SECURE_CONTENT_TYPE_NOSNIFF=True,
SECURE_PROXY_SSL_HEADER=secure_proxy_ssl_header,
SESSION_ENGINE='django.contrib.sessions.backends.file',
SESSION_FILE_PATH=sessions_directory,
STATIC_URL='/'.join([cfg.server_dir, 'static/']).replace('//', '/'),
# STRONGHOLD_PUBLIC_URLS=(r'^captcha/', ),
STRONGHOLD_PUBLIC_NAMED_URLS=(
'captcha-image',
'captcha-image-2x',
'captcha-audio',
'captcha-refresh',
),
TEMPLATES=templates,
USE_L10N=True,
USE_X_FORWARDED_HOST=cfg.use_x_forwarded_host)
django.setup(set_prefix=True)
logger.debug('Configured Django with applications - %s', applications)
logger.debug('Creating or adding new tables to data file')
verbosity = 1 if cfg.develop else 0
django.core.management.call_command('migrate', '--fake-initial',
interactive=False, verbosity=verbosity)
os.chmod(cfg.store_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
def run_setup_and_exit(module_list, allow_install=True): def run_setup_and_exit(module_list, allow_install=True):
"""Run setup on all essential modules and exit.""" """Run setup on all essential modules and exit."""
error_code = 0 error_code = 0
@ -344,7 +211,7 @@ def main():
service.init() service.init()
configure_django() web_framework.init()
logger.info('Configuration loaded from file - %s', cfg.config_file) logger.info('Configuration loaded from file - %s', cfg.config_file)
logger.info('Script prefix - %s', cfg.server_dir) logger.info('Script prefix - %s', cfg.server_dir)

171
plinth/web_framework.py Normal file
View File

@ -0,0 +1,171 @@
#
# This file is part of FreedomBox.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""
Setup Django web framework.
"""
import logging
import os
import stat
import django.conf
import django.core.management
import django.core.wsgi
from django.contrib.messages import constants as message_constants
from . import cfg, log, module_loader
logger = logging.getLogger(__name__)
def init():
"""Setup Django configuration in the absence of .settings file"""
templates = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.request',
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'plinth.context_processors.common',
],
},
},
]
applications = [
'axes',
'captcha',
'bootstrapform',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.messages',
'stronghold',
'plinth',
]
applications += module_loader.get_modules_to_load()
sessions_directory = os.path.join(cfg.data_dir, 'sessions')
secure_proxy_ssl_header = None
if cfg.secure_proxy_ssl_header:
secure_proxy_ssl_header = (cfg.secure_proxy_ssl_header, 'https')
pwd = 'django.contrib.auth.password_validation'
django.conf.settings.configure(
ALLOWED_HOSTS=['*'],
AUTH_PASSWORD_VALIDATORS=[
{
'NAME': '{}.UserAttributeSimilarityValidator'.format(pwd),
},
{
'NAME': '{}.MinimumLengthValidator'.format(pwd),
'OPTIONS': {
'min_length': 8,
}
},
{
'NAME': '{}.CommonPasswordValidator'.format(pwd),
},
{
'NAME': '{}.NumericPasswordValidator'.format(pwd),
},
],
AXES_LOCKOUT_URL='locked/',
AXES_BEHIND_REVERSE_PROXY=True,
CACHES={
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache'
}
},
CAPTCHA_FONT_PATH=[
'/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf'
],
CAPTCHA_LENGTH=6,
CAPTCHA_FLITE_PATH='/usr/bin/flite',
DATABASES={
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': cfg.store_file
}
},
DEBUG=cfg.develop,
FORCE_SCRIPT_NAME=cfg.server_dir,
INSTALLED_APPS=applications,
IPWARE_META_PRECEDENCE_ORDER=('HTTP_X_FORWARDED_FOR', ),
LOGGING=log.get_configuration(),
LOGIN_URL='users:login',
LOGIN_REDIRECT_URL='index',
MESSAGE_TAGS={message_constants.ERROR: 'danger'},
MIDDLEWARE=(
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'stronghold.middleware.LoginRequiredMiddleware',
'plinth.middleware.AdminRequiredMiddleware',
'plinth.middleware.FirstSetupMiddleware',
'plinth.modules.first_boot.middleware.FirstBootMiddleware',
'plinth.middleware.SetupMiddleware',
),
ROOT_URLCONF='plinth.urls',
SECURE_BROWSER_XSS_FILTER=True,
SECURE_CONTENT_TYPE_NOSNIFF=True,
SECURE_PROXY_SSL_HEADER=secure_proxy_ssl_header,
SESSION_ENGINE='django.contrib.sessions.backends.file',
SESSION_FILE_PATH=sessions_directory,
STATIC_URL='/'.join([cfg.server_dir, 'static/']).replace('//', '/'),
# STRONGHOLD_PUBLIC_URLS=(r'^captcha/', ),
STRONGHOLD_PUBLIC_NAMED_URLS=(
'captcha-image',
'captcha-image-2x',
'captcha-audio',
'captcha-refresh',
),
TEMPLATES=templates,
USE_L10N=True,
USE_X_FORWARDED_HOST=cfg.use_x_forwarded_host)
django.setup(set_prefix=True)
logger.debug('Configured Django with applications - %s', applications)
logger.debug('Creating or adding new tables to data file')
verbosity = 1 if cfg.develop else 0
django.core.management.call_command('migrate', '--fake-initial',
interactive=False, verbosity=verbosity)
os.chmod(cfg.store_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
def get_wsgi_application():
"""Return Django wsgi application."""
return django.core.wsgi.get_wsgi_application()
def get_static_url():
"""Return Django static URL."""
return django.conf.settings.STATIC_URL