# For copyright and license terms, see COPYRIGHT.rst (top level of repository)
# Repository: https://github.com/C3S/portal_web
"""
Main module for the pyramid app.
"""
import os
import logging
from logging.config import fileConfig
from pyramid.config import Configurator
from pyramid.authentication import AuthTktAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
from pyramid_beaker import session_factory_from_settings
from .config import (
replace_environment_vars,
get_plugins,
notfound
)
from .models import (
Tdb,
WebUser
)
from .resources import (
WebRootFactory,
ApiRootFactory
)
log = logging.getLogger(__name__)
[docs]
def main(global_config, **settings):
"""
Configures and creates the app.
Handles configuration of
- debugpy debugging
- app config
- tryton database
- session
- policies
- subscribers
- route predicates
- view predicates
- request methods
- translation directories
- logging
- root factories
- resources
- registry
- views
Contains the main logic of the plugin system by including settings,
translation directories, logging configuration, views, ressources and
registry information of the plugins in a well defined order.
Args:
global_config (dict): Parsed [DEFAULT] section of .ini file.
**settings (dict): Parsed [app:main] section of .ini file.
Returns:
obj: a Pyramid WSGI application.
"""
# get environment
environment = os.environ.get('ENVIRONMENT')
# get plugin configuration
plugins = get_plugins(settings)
# update portal settings with plugin settings and replace environment vars
for priority in sorted(plugins, reverse=True):
settings.update(plugins[priority]['settings'])
settings = replace_environment_vars(settings)
# init app config
config = Configurator(settings=settings)
# configure tryton database
Tdb._db = settings['tryton.database']
Tdb._company = settings['tryton.company']
Tdb._user = settings['tryton.user']
Tdb._configfile = settings['tryton.configfile']
Tdb.init()
# configure session
config.set_session_factory(factory=session_factory_from_settings(settings))
# configure policies
config.set_authorization_policy(policy=ACLAuthorizationPolicy())
config.set_authentication_policy(
policy=AuthTktAuthenticationPolicy(
secret=settings['authentication.secret'],
hashalg='sha512',
callback=WebUser.groupfinder))
config.set_default_permission('administrator')
# configure subscribers
config.add_subscriber(
subscriber='.config.add_templates',
iface='pyramid.events.BeforeRender')
config.add_subscriber(
subscriber='.config.add_helpers',
iface='pyramid.events.BeforeRender')
config.add_subscriber(
subscriber='.config.add_locale',
iface='pyramid.events.NewRequest')
config.add_subscriber(
subscriber='.config.start_db_transaction',
iface='pyramid.events.BeforeTraversal')
config.add_subscriber(
subscriber='.config.context_found',
iface='pyramid.events.ContextFound')
config.add_subscriber(
subscriber='.config.stop_db_transaction',
iface='pyramid.events.NewRequest')
if settings['env'] in ['development', 'staging']:
config.add_subscriber(
subscriber='.config.debug_request',
iface='pyramid.events.NewRequest')
config.add_subscriber(
subscriber='.config.debug_context',
iface='pyramid.events.ContextFound')
config.add_subscriber(
subscriber='.config.debug_response',
iface='pyramid.events.NewResponse')
# configure predicates
config.add_route_predicate(
name='environment', factory='.config.Environment')
config.add_view_predicate(
name='environment', factory='.config.Environment')
# configure request methods
config.add_request_method(
callable='.config.web_user', name='web_user', reify=True)
config.add_request_method(
callable='.config.party', name='party', reify=True)
config.add_request_method(
callable='.config.user', name='user', reify=True)
config.add_request_method(
callable='.config.roles', name='roles', reify=True)
# configure translation directories for portal and plugins
config.add_translation_dirs(
'colander:locale/',
'deform:locale/',
'portal_web:locale/')
for priority in sorted(plugins):
translation_dir = os.path.join(
plugins[priority]['path'], plugins[priority]['name'], 'locale')
if os.path.isdir(translation_dir):
config.add_translation_dirs(translation_dir)
# configure logging for portal and plugins
for priority in sorted(plugins):
fileConfig(
plugins[priority]['path'] + '/' + environment + '.ini',
disable_existing_loggers=False)
# commit config with basic settings
config.commit()
# not found view (404 Error)
config.add_notfound_view(notfound)
# configure mailer
if int(settings['mail.to_real_world']):
config.include('pyramid_mailer')
else:
config.include('pyramid_mailer.testing')
# enable debugpy debugging (open port 52000 for portal and 52001 for api!)
if int(settings['debugger.debugpy']):
debugging_port = False
if settings['service'] == 'webgui':
debugging_port = 52000
if settings['service'] == 'webapi':
debugging_port = 52001
if debugging_port:
log.debug(settings['service'] + " debugger listening to port " +
str(debugging_port))
try:
import debugpy # unconditional import breaks test coverage
debugpy.listen(("0.0.0.0", debugging_port))
except Exception as ex:
if hasattr(ex, 'message'):
log.debug(ex.message)
else:
log.debug('debugpy debugging not possible: ' + ex.message)
# configure webfrontend for portal and plugins
if settings['service'] == 'webgui':
# web root factory
config.set_root_factory(factory=WebRootFactory)
# web resources
config.include('.includes.web_resources')
for priority in sorted(plugins):
config.include(plugins[priority]['name']+'.includes.web_resources')
# web registry
config.include('.includes.web_registry')
for priority in sorted(plugins):
config.include(plugins[priority]['name']+'.includes.web_registry')
# web views
for priority in sorted(plugins, reverse=True):
config.include(plugins[priority]['name'] + '.includes.web_views')
config.include('.includes.web_views')
# api views
if settings['api.in_web'] == 'true':
config.include('cornice')
for priority in sorted(plugins, reverse=True):
config.include(
plugins[priority]['name'] + '.includes.api_views',
route_prefix=settings['api.in_web_path'])
config.include(
'.includes.api_views',
route_prefix=settings['api.in_web_path'])
# configure api for portal and plugins
if settings['service'] == 'webapi':
config.include('cornice')
config.include('cornice_swagger')
# api root factory
config.set_root_factory(factory=ApiRootFactory)
# api views
for priority in sorted(plugins, reverse=True):
config.include(plugins[priority]['name'] + '.includes.api_views')
config.include('.includes.api_views')
return config.make_wsgi_app()