Update Makefile and fix flake8 issues.
[infos-pratiques:etalage.git] / etalage / application.py
1 # -*- coding: utf-8 -*-
2
3
4 # Etalage -- Open Data POIs portal
5 # By: Emmanuel Raviart <eraviart@easter-eggs.com>
6 #
7 # Copyright (C) 2011, 2012 Easter-eggs
8 # http://gitorious.org/infos-pratiques/etalage
9 #
10 # This file is part of Etalage.
11 #
12 # Etalage is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU Affero General Public License as
14 # published by the Free Software Foundation, either version 3 of the
15 # License, or (at your option) any later version.
16 #
17 # Etalage is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 # GNU Affero General Public License for more details.
21 #
22 # You should have received a copy of the GNU Affero General Public License
23 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
25
26 """Middleware initialization"""
27
28
29 import re
30 import urllib
31
32 from beaker.middleware import SessionMiddleware
33 from paste.cascade import Cascade
34 from paste.urlparser import StaticURLParser
35 from weberror.errormiddleware import ErrorMiddleware
36
37 from . import conf, contexts, controllers, environment, urls, wsgihelpers
38
39
40 lang_re = re.compile('^/(?P<lang>en|fr)(?=/|$)')
41 percent_encoding_re = re.compile('%[\dA-Fa-f]{2}')
42
43
44 @wsgihelpers.wsgify.middleware
45 def environment_setter(req, app):
46     """WSGI middleware that sets request-dependant environment."""
47     urls.application_url = req.application_url
48     return app
49
50
51 @wsgihelpers.wsgify.middleware
52 def language_detector(req, app):
53     """WSGI middleware that detect language symbol in requested URL or otherwise in Accept-Language header."""
54     ctx = contexts.Ctx(req)
55     match = lang_re.match(req.path_info)
56     if match is None:
57         ctx.lang = [
58             #req.accept_language.best_match([('en-US', 1), ('en', 1), ('fr-FR', 1), ('fr', 1)],
59             #    default_match = 'en').split('-', 1)[0],
60             'fr',
61             ]
62     else:
63         ctx.lang = [match.group('lang')]
64         req.script_name += req.path_info[:match.end()]
65         req.path_info = req.path_info[match.end():]
66     return req.get_response(app)
67
68
69 def make_app(global_conf, **app_conf):
70     """Create a WSGI application and return it
71
72     ``global_conf``
73         The inherited configuration for this application. Normally from
74         the [DEFAULT] section of the Paste ini file.
75
76     ``app_conf``
77         The application's local configuration. Normally specified in
78         the [app:<name>] section of the Paste ini file (where <name>
79         defaults to main).
80     """
81     # Configure the environment and fill conf dictionary.
82     environment.load_environment(global_conf, app_conf)
83
84     # Dispatch request to controllers.
85     app = controllers.make_router()
86
87     # Keep sessions.
88     app = SessionMiddleware(app, conf)
89
90     # Init request-dependant environment
91     app = environment_setter(app)
92     app = language_detector(app)
93
94     # Repair badly encoded query in request URL.
95     app = request_query_encoding_fixer(app)
96
97     # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
98
99     # Handle Python exceptions
100     if not conf['debug']:
101         app = ErrorMiddleware(app, global_conf, **conf['errorware'])
102
103     if conf['static_files']:
104         # Serve static files.
105         cascaded_apps = []
106         if conf['custom_static_files_dir'] is not None:
107             cascaded_apps.append(StaticURLParser(conf['custom_static_files_dir']))
108         cascaded_apps.append(StaticURLParser(conf['static_files_dir']))
109         cascaded_apps.append(app)
110         app = Cascade(cascaded_apps)
111
112     return app
113
114
115 @wsgihelpers.wsgify.middleware
116 def request_query_encoding_fixer(req, app):
117     """WSGI middleware that repairs a badly encoded query in request URL."""
118     query_string = req.query_string
119     if query_string is not None:
120         try:
121             urllib.unquote(query_string).decode('utf-8')
122         except UnicodeDecodeError:
123             req.query_string = percent_encoding_re.sub(
124                 lambda match: urllib.quote(urllib.unquote(match.group(0)).decode('iso-8859-1').encode('utf-8')),
125                 query_string)
126     return req.get_response(app)