##// END OF EJS Templates
core: added ext_json as custom renderer using our ext_json lib for pyramid.
marcink -
r1664:0db868e6 default
parent child Browse files
Show More
@@ -0,0 +1,37 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 from rhodecode.lib.ext_json import json
22
23
24 def pyramid_ext_json(info):
25 """
26 Custom json renderer for pyramid to use our ext_json lib
27 """
28 def _render(value, system):
29 request = system.get('request')
30 if request is not None:
31 response = request.response
32 ct = response.content_type
33 if ct == response.default_content_type:
34 response.content_type = 'application/json'
35 return json.dumps(value)
36
37 return _render
@@ -1,508 +1,512 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Pylons middleware initialization
22 Pylons middleware initialization
23 """
23 """
24 import logging
24 import logging
25 from collections import OrderedDict
25 from collections import OrderedDict
26
26
27 from paste.registry import RegistryManager
27 from paste.registry import RegistryManager
28 from paste.gzipper import make_gzip_middleware
28 from paste.gzipper import make_gzip_middleware
29 from pylons.wsgiapp import PylonsApp
29 from pylons.wsgiapp import PylonsApp
30 from pyramid.authorization import ACLAuthorizationPolicy
30 from pyramid.authorization import ACLAuthorizationPolicy
31 from pyramid.config import Configurator
31 from pyramid.config import Configurator
32 from pyramid.settings import asbool, aslist
32 from pyramid.settings import asbool, aslist
33 from pyramid.wsgi import wsgiapp
33 from pyramid.wsgi import wsgiapp
34 from pyramid.httpexceptions import (
34 from pyramid.httpexceptions import (
35 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound)
35 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound)
36 from pyramid.events import ApplicationCreated
36 from pyramid.events import ApplicationCreated
37 from pyramid.renderers import render_to_response
37 from pyramid.renderers import render_to_response
38 from routes.middleware import RoutesMiddleware
38 from routes.middleware import RoutesMiddleware
39 import routes.util
39 import routes.util
40
40
41 import rhodecode
41 import rhodecode
42 from rhodecode.model import meta
42 from rhodecode.model import meta
43 from rhodecode.config import patches
43 from rhodecode.config import patches
44 from rhodecode.config.routing import STATIC_FILE_PREFIX
44 from rhodecode.config.routing import STATIC_FILE_PREFIX
45 from rhodecode.config.environment import (
45 from rhodecode.config.environment import (
46 load_environment, load_pyramid_environment)
46 load_environment, load_pyramid_environment)
47 from rhodecode.lib.middleware import csrf
47 from rhodecode.lib.middleware import csrf
48 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
48 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
49 from rhodecode.lib.middleware.error_handling import (
49 from rhodecode.lib.middleware.error_handling import (
50 PylonsErrorHandlingMiddleware)
50 PylonsErrorHandlingMiddleware)
51 from rhodecode.lib.middleware.https_fixup import HttpsFixup
51 from rhodecode.lib.middleware.https_fixup import HttpsFixup
52 from rhodecode.lib.middleware.vcs import VCSMiddleware
52 from rhodecode.lib.middleware.vcs import VCSMiddleware
53 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
53 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
54 from rhodecode.lib.utils2 import aslist as rhodecode_aslist
54 from rhodecode.lib.utils2 import aslist as rhodecode_aslist
55 from rhodecode.subscribers import (
55 from rhodecode.subscribers import (
56 scan_repositories_if_enabled, write_metadata_if_needed,
56 scan_repositories_if_enabled, write_metadata_if_needed,
57 write_js_routes_if_enabled, create_largeobjects_dirs_if_needed)
57 write_js_routes_if_enabled, create_largeobjects_dirs_if_needed)
58
58
59
59
60 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
61
61
62
62
63 # this is used to avoid avoid the route lookup overhead in routesmiddleware
63 # this is used to avoid avoid the route lookup overhead in routesmiddleware
64 # for certain routes which won't go to pylons to - eg. static files, debugger
64 # for certain routes which won't go to pylons to - eg. static files, debugger
65 # it is only needed for the pylons migration and can be removed once complete
65 # it is only needed for the pylons migration and can be removed once complete
66 class SkippableRoutesMiddleware(RoutesMiddleware):
66 class SkippableRoutesMiddleware(RoutesMiddleware):
67 """ Routes middleware that allows you to skip prefixes """
67 """ Routes middleware that allows you to skip prefixes """
68
68
69 def __init__(self, *args, **kw):
69 def __init__(self, *args, **kw):
70 self.skip_prefixes = kw.pop('skip_prefixes', [])
70 self.skip_prefixes = kw.pop('skip_prefixes', [])
71 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
71 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
72
72
73 def __call__(self, environ, start_response):
73 def __call__(self, environ, start_response):
74 for prefix in self.skip_prefixes:
74 for prefix in self.skip_prefixes:
75 if environ['PATH_INFO'].startswith(prefix):
75 if environ['PATH_INFO'].startswith(prefix):
76 # added to avoid the case when a missing /_static route falls
76 # added to avoid the case when a missing /_static route falls
77 # through to pylons and causes an exception as pylons is
77 # through to pylons and causes an exception as pylons is
78 # expecting wsgiorg.routingargs to be set in the environ
78 # expecting wsgiorg.routingargs to be set in the environ
79 # by RoutesMiddleware.
79 # by RoutesMiddleware.
80 if 'wsgiorg.routing_args' not in environ:
80 if 'wsgiorg.routing_args' not in environ:
81 environ['wsgiorg.routing_args'] = (None, {})
81 environ['wsgiorg.routing_args'] = (None, {})
82 return self.app(environ, start_response)
82 return self.app(environ, start_response)
83
83
84 return super(SkippableRoutesMiddleware, self).__call__(
84 return super(SkippableRoutesMiddleware, self).__call__(
85 environ, start_response)
85 environ, start_response)
86
86
87
87
88 def make_app(global_conf, static_files=True, **app_conf):
88 def make_app(global_conf, static_files=True, **app_conf):
89 """Create a Pylons WSGI application and return it
89 """Create a Pylons WSGI application and return it
90
90
91 ``global_conf``
91 ``global_conf``
92 The inherited configuration for this application. Normally from
92 The inherited configuration for this application. Normally from
93 the [DEFAULT] section of the Paste ini file.
93 the [DEFAULT] section of the Paste ini file.
94
94
95 ``app_conf``
95 ``app_conf``
96 The application's local configuration. Normally specified in
96 The application's local configuration. Normally specified in
97 the [app:<name>] section of the Paste ini file (where <name>
97 the [app:<name>] section of the Paste ini file (where <name>
98 defaults to main).
98 defaults to main).
99
99
100 """
100 """
101 # Apply compatibility patches
101 # Apply compatibility patches
102 patches.kombu_1_5_1_python_2_7_11()
102 patches.kombu_1_5_1_python_2_7_11()
103 patches.inspect_getargspec()
103 patches.inspect_getargspec()
104
104
105 # Configure the Pylons environment
105 # Configure the Pylons environment
106 config = load_environment(global_conf, app_conf)
106 config = load_environment(global_conf, app_conf)
107
107
108 # The Pylons WSGI app
108 # The Pylons WSGI app
109 app = PylonsApp(config=config)
109 app = PylonsApp(config=config)
110 if rhodecode.is_test:
110 if rhodecode.is_test:
111 app = csrf.CSRFDetector(app)
111 app = csrf.CSRFDetector(app)
112
112
113 expected_origin = config.get('expected_origin')
113 expected_origin = config.get('expected_origin')
114 if expected_origin:
114 if expected_origin:
115 # The API can be accessed from other Origins.
115 # The API can be accessed from other Origins.
116 app = csrf.OriginChecker(app, expected_origin,
116 app = csrf.OriginChecker(app, expected_origin,
117 skip_urls=[routes.util.url_for('api')])
117 skip_urls=[routes.util.url_for('api')])
118
118
119 # Establish the Registry for this application
119 # Establish the Registry for this application
120 app = RegistryManager(app)
120 app = RegistryManager(app)
121
121
122 app.config = config
122 app.config = config
123
123
124 return app
124 return app
125
125
126
126
127 def make_pyramid_app(global_config, **settings):
127 def make_pyramid_app(global_config, **settings):
128 """
128 """
129 Constructs the WSGI application based on Pyramid and wraps the Pylons based
129 Constructs the WSGI application based on Pyramid and wraps the Pylons based
130 application.
130 application.
131
131
132 Specials:
132 Specials:
133
133
134 * We migrate from Pylons to Pyramid. While doing this, we keep both
134 * We migrate from Pylons to Pyramid. While doing this, we keep both
135 frameworks functional. This involves moving some WSGI middlewares around
135 frameworks functional. This involves moving some WSGI middlewares around
136 and providing access to some data internals, so that the old code is
136 and providing access to some data internals, so that the old code is
137 still functional.
137 still functional.
138
138
139 * The application can also be integrated like a plugin via the call to
139 * The application can also be integrated like a plugin via the call to
140 `includeme`. This is accompanied with the other utility functions which
140 `includeme`. This is accompanied with the other utility functions which
141 are called. Changing this should be done with great care to not break
141 are called. Changing this should be done with great care to not break
142 cases when these fragments are assembled from another place.
142 cases when these fragments are assembled from another place.
143
143
144 """
144 """
145 # The edition string should be available in pylons too, so we add it here
145 # The edition string should be available in pylons too, so we add it here
146 # before copying the settings.
146 # before copying the settings.
147 settings.setdefault('rhodecode.edition', 'Community Edition')
147 settings.setdefault('rhodecode.edition', 'Community Edition')
148
148
149 # As long as our Pylons application does expect "unprepared" settings, make
149 # As long as our Pylons application does expect "unprepared" settings, make
150 # sure that we keep an unmodified copy. This avoids unintentional change of
150 # sure that we keep an unmodified copy. This avoids unintentional change of
151 # behavior in the old application.
151 # behavior in the old application.
152 settings_pylons = settings.copy()
152 settings_pylons = settings.copy()
153
153
154 sanitize_settings_and_apply_defaults(settings)
154 sanitize_settings_and_apply_defaults(settings)
155 config = Configurator(settings=settings)
155 config = Configurator(settings=settings)
156 add_pylons_compat_data(config.registry, global_config, settings_pylons)
156 add_pylons_compat_data(config.registry, global_config, settings_pylons)
157
157
158 load_pyramid_environment(global_config, settings)
158 load_pyramid_environment(global_config, settings)
159
159
160 includeme_first(config)
160 includeme_first(config)
161 includeme(config)
161 includeme(config)
162 pyramid_app = config.make_wsgi_app()
162 pyramid_app = config.make_wsgi_app()
163 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
163 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
164 pyramid_app.config = config
164 pyramid_app.config = config
165
165
166 # creating the app uses a connection - return it after we are done
166 # creating the app uses a connection - return it after we are done
167 meta.Session.remove()
167 meta.Session.remove()
168
168
169 return pyramid_app
169 return pyramid_app
170
170
171
171
172 def make_not_found_view(config):
172 def make_not_found_view(config):
173 """
173 """
174 This creates the view which should be registered as not-found-view to
174 This creates the view which should be registered as not-found-view to
175 pyramid. Basically it contains of the old pylons app, converted to a view.
175 pyramid. Basically it contains of the old pylons app, converted to a view.
176 Additionally it is wrapped by some other middlewares.
176 Additionally it is wrapped by some other middlewares.
177 """
177 """
178 settings = config.registry.settings
178 settings = config.registry.settings
179 vcs_server_enabled = settings['vcs.server.enable']
179 vcs_server_enabled = settings['vcs.server.enable']
180
180
181 # Make pylons app from unprepared settings.
181 # Make pylons app from unprepared settings.
182 pylons_app = make_app(
182 pylons_app = make_app(
183 config.registry._pylons_compat_global_config,
183 config.registry._pylons_compat_global_config,
184 **config.registry._pylons_compat_settings)
184 **config.registry._pylons_compat_settings)
185 config.registry._pylons_compat_config = pylons_app.config
185 config.registry._pylons_compat_config = pylons_app.config
186
186
187 # Appenlight monitoring.
187 # Appenlight monitoring.
188 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
188 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
189 pylons_app, settings)
189 pylons_app, settings)
190
190
191 # The pylons app is executed inside of the pyramid 404 exception handler.
191 # The pylons app is executed inside of the pyramid 404 exception handler.
192 # Exceptions which are raised inside of it are not handled by pyramid
192 # Exceptions which are raised inside of it are not handled by pyramid
193 # again. Therefore we add a middleware that invokes the error handler in
193 # again. Therefore we add a middleware that invokes the error handler in
194 # case of an exception or error response. This way we return proper error
194 # case of an exception or error response. This way we return proper error
195 # HTML pages in case of an error.
195 # HTML pages in case of an error.
196 reraise = (settings.get('debugtoolbar.enabled', False) or
196 reraise = (settings.get('debugtoolbar.enabled', False) or
197 rhodecode.disable_error_handler)
197 rhodecode.disable_error_handler)
198 pylons_app = PylonsErrorHandlingMiddleware(
198 pylons_app = PylonsErrorHandlingMiddleware(
199 pylons_app, error_handler, reraise)
199 pylons_app, error_handler, reraise)
200
200
201 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find a
201 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find a
202 # view to handle the request. Therefore it is wrapped around the pylons
202 # view to handle the request. Therefore it is wrapped around the pylons
203 # app. It has to be outside of the error handling otherwise error responses
203 # app. It has to be outside of the error handling otherwise error responses
204 # from the vcsserver are converted to HTML error pages. This confuses the
204 # from the vcsserver are converted to HTML error pages. This confuses the
205 # command line tools and the user won't get a meaningful error message.
205 # command line tools and the user won't get a meaningful error message.
206 if vcs_server_enabled:
206 if vcs_server_enabled:
207 pylons_app = VCSMiddleware(
207 pylons_app = VCSMiddleware(
208 pylons_app, settings, appenlight_client, registry=config.registry)
208 pylons_app, settings, appenlight_client, registry=config.registry)
209
209
210 # Convert WSGI app to pyramid view and return it.
210 # Convert WSGI app to pyramid view and return it.
211 return wsgiapp(pylons_app)
211 return wsgiapp(pylons_app)
212
212
213
213
214 def add_pylons_compat_data(registry, global_config, settings):
214 def add_pylons_compat_data(registry, global_config, settings):
215 """
215 """
216 Attach data to the registry to support the Pylons integration.
216 Attach data to the registry to support the Pylons integration.
217 """
217 """
218 registry._pylons_compat_global_config = global_config
218 registry._pylons_compat_global_config = global_config
219 registry._pylons_compat_settings = settings
219 registry._pylons_compat_settings = settings
220
220
221
221
222 def error_handler(exception, request):
222 def error_handler(exception, request):
223 import rhodecode
223 import rhodecode
224 from rhodecode.lib.utils2 import AttributeDict
224 from rhodecode.lib.utils2 import AttributeDict
225
225
226 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
226 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
227
227
228 base_response = HTTPInternalServerError()
228 base_response = HTTPInternalServerError()
229 # prefer original exception for the response since it may have headers set
229 # prefer original exception for the response since it may have headers set
230 if isinstance(exception, HTTPException):
230 if isinstance(exception, HTTPException):
231 base_response = exception
231 base_response = exception
232
232
233 def is_http_error(response):
233 def is_http_error(response):
234 # error which should have traceback
234 # error which should have traceback
235 return response.status_code > 499
235 return response.status_code > 499
236
236
237 if is_http_error(base_response):
237 if is_http_error(base_response):
238 log.exception(
238 log.exception(
239 'error occurred handling this request for path: %s', request.path)
239 'error occurred handling this request for path: %s', request.path)
240
240
241 c = AttributeDict()
241 c = AttributeDict()
242 c.error_message = base_response.status
242 c.error_message = base_response.status
243 c.error_explanation = base_response.explanation or str(base_response)
243 c.error_explanation = base_response.explanation or str(base_response)
244 c.visual = AttributeDict()
244 c.visual = AttributeDict()
245
245
246 c.visual.rhodecode_support_url = (
246 c.visual.rhodecode_support_url = (
247 request.registry.settings.get('rhodecode_support_url') or
247 request.registry.settings.get('rhodecode_support_url') or
248 request.route_url('rhodecode_support')
248 request.route_url('rhodecode_support')
249 )
249 )
250 c.redirect_time = 0
250 c.redirect_time = 0
251 c.rhodecode_name = rhodecode_title
251 c.rhodecode_name = rhodecode_title
252 if not c.rhodecode_name:
252 if not c.rhodecode_name:
253 c.rhodecode_name = 'Rhodecode'
253 c.rhodecode_name = 'Rhodecode'
254
254
255 c.causes = []
255 c.causes = []
256 if hasattr(base_response, 'causes'):
256 if hasattr(base_response, 'causes'):
257 c.causes = base_response.causes
257 c.causes = base_response.causes
258
258
259 response = render_to_response(
259 response = render_to_response(
260 '/errors/error_document.mako', {'c': c}, request=request,
260 '/errors/error_document.mako', {'c': c}, request=request,
261 response=base_response)
261 response=base_response)
262
262
263 return response
263 return response
264
264
265
265
266 def includeme(config):
266 def includeme(config):
267 settings = config.registry.settings
267 settings = config.registry.settings
268
268
269 # plugin information
269 # plugin information
270 config.registry.rhodecode_plugins = OrderedDict()
270 config.registry.rhodecode_plugins = OrderedDict()
271
271
272 config.add_directive(
272 config.add_directive(
273 'register_rhodecode_plugin', register_rhodecode_plugin)
273 'register_rhodecode_plugin', register_rhodecode_plugin)
274
274
275 if asbool(settings.get('appenlight', 'false')):
275 if asbool(settings.get('appenlight', 'false')):
276 config.include('appenlight_client.ext.pyramid_tween')
276 config.include('appenlight_client.ext.pyramid_tween')
277
277
278 # Includes which are required. The application would fail without them.
278 # Includes which are required. The application would fail without them.
279 config.include('pyramid_mako')
279 config.include('pyramid_mako')
280 config.include('pyramid_beaker')
280 config.include('pyramid_beaker')
281
281
282 config.include('rhodecode.authentication')
282 config.include('rhodecode.authentication')
283 config.include('rhodecode.integrations')
283 config.include('rhodecode.integrations')
284
284
285 # apps
285 # apps
286 config.include('rhodecode.apps._base')
286 config.include('rhodecode.apps._base')
287
287
288 config.include('rhodecode.apps.admin')
288 config.include('rhodecode.apps.admin')
289 config.include('rhodecode.apps.channelstream')
289 config.include('rhodecode.apps.channelstream')
290 config.include('rhodecode.apps.login')
290 config.include('rhodecode.apps.login')
291 config.include('rhodecode.apps.repository')
291 config.include('rhodecode.apps.repository')
292 config.include('rhodecode.apps.user_profile')
292 config.include('rhodecode.apps.user_profile')
293 config.include('rhodecode.apps.my_account')
293 config.include('rhodecode.apps.my_account')
294 config.include('rhodecode.apps.svn_support')
294 config.include('rhodecode.apps.svn_support')
295
295
296 config.include('rhodecode.tweens')
296 config.include('rhodecode.tweens')
297 config.include('rhodecode.api')
297 config.include('rhodecode.api')
298
298
299 config.add_route(
299 config.add_route(
300 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
300 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
301
301
302 config.add_translation_dirs('rhodecode:i18n/')
302 config.add_translation_dirs('rhodecode:i18n/')
303 settings['default_locale_name'] = settings.get('lang', 'en')
303 settings['default_locale_name'] = settings.get('lang', 'en')
304
304
305 # Add subscribers.
305 # Add subscribers.
306 config.add_subscriber(create_largeobjects_dirs_if_needed, ApplicationCreated)
306 config.add_subscriber(create_largeobjects_dirs_if_needed, ApplicationCreated)
307 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
307 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
308 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
308 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
309 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
309 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
310
310
311 # Set the authorization policy.
311 # Set the authorization policy.
312 authz_policy = ACLAuthorizationPolicy()
312 authz_policy = ACLAuthorizationPolicy()
313 config.set_authorization_policy(authz_policy)
313 config.set_authorization_policy(authz_policy)
314
314
315 # Set the default renderer for HTML templates to mako.
315 # Set the default renderer for HTML templates to mako.
316 config.add_mako_renderer('.html')
316 config.add_mako_renderer('.html')
317
317
318 config.add_renderer(
319 name='json_ext',
320 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
321
318 # include RhodeCode plugins
322 # include RhodeCode plugins
319 includes = aslist(settings.get('rhodecode.includes', []))
323 includes = aslist(settings.get('rhodecode.includes', []))
320 for inc in includes:
324 for inc in includes:
321 config.include(inc)
325 config.include(inc)
322
326
323 # This is the glue which allows us to migrate in chunks. By registering the
327 # This is the glue which allows us to migrate in chunks. By registering the
324 # pylons based application as the "Not Found" view in Pyramid, we will
328 # pylons based application as the "Not Found" view in Pyramid, we will
325 # fallback to the old application each time the new one does not yet know
329 # fallback to the old application each time the new one does not yet know
326 # how to handle a request.
330 # how to handle a request.
327 config.add_notfound_view(make_not_found_view(config))
331 config.add_notfound_view(make_not_found_view(config))
328
332
329 if not settings.get('debugtoolbar.enabled', False):
333 if not settings.get('debugtoolbar.enabled', False):
330 # if no toolbar, then any exception gets caught and rendered
334 # if no toolbar, then any exception gets caught and rendered
331 config.add_view(error_handler, context=Exception)
335 config.add_view(error_handler, context=Exception)
332
336
333 config.add_view(error_handler, context=HTTPError)
337 config.add_view(error_handler, context=HTTPError)
334
338
335
339
336 def includeme_first(config):
340 def includeme_first(config):
337 # redirect automatic browser favicon.ico requests to correct place
341 # redirect automatic browser favicon.ico requests to correct place
338 def favicon_redirect(context, request):
342 def favicon_redirect(context, request):
339 return HTTPFound(
343 return HTTPFound(
340 request.static_path('rhodecode:public/images/favicon.ico'))
344 request.static_path('rhodecode:public/images/favicon.ico'))
341
345
342 config.add_view(favicon_redirect, route_name='favicon')
346 config.add_view(favicon_redirect, route_name='favicon')
343 config.add_route('favicon', '/favicon.ico')
347 config.add_route('favicon', '/favicon.ico')
344
348
345 def robots_redirect(context, request):
349 def robots_redirect(context, request):
346 return HTTPFound(
350 return HTTPFound(
347 request.static_path('rhodecode:public/robots.txt'))
351 request.static_path('rhodecode:public/robots.txt'))
348
352
349 config.add_view(robots_redirect, route_name='robots')
353 config.add_view(robots_redirect, route_name='robots')
350 config.add_route('robots', '/robots.txt')
354 config.add_route('robots', '/robots.txt')
351
355
352 config.add_static_view(
356 config.add_static_view(
353 '_static/deform', 'deform:static')
357 '_static/deform', 'deform:static')
354 config.add_static_view(
358 config.add_static_view(
355 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
359 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
356
360
357
361
358 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
362 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
359 """
363 """
360 Apply outer WSGI middlewares around the application.
364 Apply outer WSGI middlewares around the application.
361
365
362 Part of this has been moved up from the Pylons layer, so that the
366 Part of this has been moved up from the Pylons layer, so that the
363 data is also available if old Pylons code is hit through an already ported
367 data is also available if old Pylons code is hit through an already ported
364 view.
368 view.
365 """
369 """
366 settings = config.registry.settings
370 settings = config.registry.settings
367
371
368 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
372 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
369 pyramid_app = HttpsFixup(pyramid_app, settings)
373 pyramid_app = HttpsFixup(pyramid_app, settings)
370
374
371 # Add RoutesMiddleware to support the pylons compatibility tween during
375 # Add RoutesMiddleware to support the pylons compatibility tween during
372 # migration to pyramid.
376 # migration to pyramid.
373 pyramid_app = SkippableRoutesMiddleware(
377 pyramid_app = SkippableRoutesMiddleware(
374 pyramid_app, config.registry._pylons_compat_config['routes.map'],
378 pyramid_app, config.registry._pylons_compat_config['routes.map'],
375 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
379 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
376
380
377 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
381 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
378
382
379 if settings['gzip_responses']:
383 if settings['gzip_responses']:
380 pyramid_app = make_gzip_middleware(
384 pyramid_app = make_gzip_middleware(
381 pyramid_app, settings, compress_level=1)
385 pyramid_app, settings, compress_level=1)
382
386
383 # this should be the outer most middleware in the wsgi stack since
387 # this should be the outer most middleware in the wsgi stack since
384 # middleware like Routes make database calls
388 # middleware like Routes make database calls
385 def pyramid_app_with_cleanup(environ, start_response):
389 def pyramid_app_with_cleanup(environ, start_response):
386 try:
390 try:
387 return pyramid_app(environ, start_response)
391 return pyramid_app(environ, start_response)
388 finally:
392 finally:
389 # Dispose current database session and rollback uncommitted
393 # Dispose current database session and rollback uncommitted
390 # transactions.
394 # transactions.
391 meta.Session.remove()
395 meta.Session.remove()
392
396
393 # In a single threaded mode server, on non sqlite db we should have
397 # In a single threaded mode server, on non sqlite db we should have
394 # '0 Current Checked out connections' at the end of a request,
398 # '0 Current Checked out connections' at the end of a request,
395 # if not, then something, somewhere is leaving a connection open
399 # if not, then something, somewhere is leaving a connection open
396 pool = meta.Base.metadata.bind.engine.pool
400 pool = meta.Base.metadata.bind.engine.pool
397 log.debug('sa pool status: %s', pool.status())
401 log.debug('sa pool status: %s', pool.status())
398
402
399
403
400 return pyramid_app_with_cleanup
404 return pyramid_app_with_cleanup
401
405
402
406
403 def sanitize_settings_and_apply_defaults(settings):
407 def sanitize_settings_and_apply_defaults(settings):
404 """
408 """
405 Applies settings defaults and does all type conversion.
409 Applies settings defaults and does all type conversion.
406
410
407 We would move all settings parsing and preparation into this place, so that
411 We would move all settings parsing and preparation into this place, so that
408 we have only one place left which deals with this part. The remaining parts
412 we have only one place left which deals with this part. The remaining parts
409 of the application would start to rely fully on well prepared settings.
413 of the application would start to rely fully on well prepared settings.
410
414
411 This piece would later be split up per topic to avoid a big fat monster
415 This piece would later be split up per topic to avoid a big fat monster
412 function.
416 function.
413 """
417 """
414
418
415 # Pyramid's mako renderer has to search in the templates folder so that the
419 # Pyramid's mako renderer has to search in the templates folder so that the
416 # old templates still work. Ported and new templates are expected to use
420 # old templates still work. Ported and new templates are expected to use
417 # real asset specifications for the includes.
421 # real asset specifications for the includes.
418 mako_directories = settings.setdefault('mako.directories', [
422 mako_directories = settings.setdefault('mako.directories', [
419 # Base templates of the original Pylons application
423 # Base templates of the original Pylons application
420 'rhodecode:templates',
424 'rhodecode:templates',
421 ])
425 ])
422 log.debug(
426 log.debug(
423 "Using the following Mako template directories: %s",
427 "Using the following Mako template directories: %s",
424 mako_directories)
428 mako_directories)
425
429
426 # Default includes, possible to change as a user
430 # Default includes, possible to change as a user
427 pyramid_includes = settings.setdefault('pyramid.includes', [
431 pyramid_includes = settings.setdefault('pyramid.includes', [
428 'rhodecode.lib.middleware.request_wrapper',
432 'rhodecode.lib.middleware.request_wrapper',
429 ])
433 ])
430 log.debug(
434 log.debug(
431 "Using the following pyramid.includes: %s",
435 "Using the following pyramid.includes: %s",
432 pyramid_includes)
436 pyramid_includes)
433
437
434 # TODO: johbo: Re-think this, usually the call to config.include
438 # TODO: johbo: Re-think this, usually the call to config.include
435 # should allow to pass in a prefix.
439 # should allow to pass in a prefix.
436 settings.setdefault('rhodecode.api.url', '/_admin/api')
440 settings.setdefault('rhodecode.api.url', '/_admin/api')
437
441
438 # Sanitize generic settings.
442 # Sanitize generic settings.
439 _list_setting(settings, 'default_encoding', 'UTF-8')
443 _list_setting(settings, 'default_encoding', 'UTF-8')
440 _bool_setting(settings, 'is_test', 'false')
444 _bool_setting(settings, 'is_test', 'false')
441 _bool_setting(settings, 'gzip_responses', 'false')
445 _bool_setting(settings, 'gzip_responses', 'false')
442
446
443 # Call split out functions that sanitize settings for each topic.
447 # Call split out functions that sanitize settings for each topic.
444 _sanitize_appenlight_settings(settings)
448 _sanitize_appenlight_settings(settings)
445 _sanitize_vcs_settings(settings)
449 _sanitize_vcs_settings(settings)
446
450
447 return settings
451 return settings
448
452
449
453
450 def _sanitize_appenlight_settings(settings):
454 def _sanitize_appenlight_settings(settings):
451 _bool_setting(settings, 'appenlight', 'false')
455 _bool_setting(settings, 'appenlight', 'false')
452
456
453
457
454 def _sanitize_vcs_settings(settings):
458 def _sanitize_vcs_settings(settings):
455 """
459 """
456 Applies settings defaults and does type conversion for all VCS related
460 Applies settings defaults and does type conversion for all VCS related
457 settings.
461 settings.
458 """
462 """
459 _string_setting(settings, 'vcs.svn.compatible_version', '')
463 _string_setting(settings, 'vcs.svn.compatible_version', '')
460 _string_setting(settings, 'git_rev_filter', '--all')
464 _string_setting(settings, 'git_rev_filter', '--all')
461 _string_setting(settings, 'vcs.hooks.protocol', 'http')
465 _string_setting(settings, 'vcs.hooks.protocol', 'http')
462 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
466 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
463 _string_setting(settings, 'vcs.server', '')
467 _string_setting(settings, 'vcs.server', '')
464 _string_setting(settings, 'vcs.server.log_level', 'debug')
468 _string_setting(settings, 'vcs.server.log_level', 'debug')
465 _string_setting(settings, 'vcs.server.protocol', 'http')
469 _string_setting(settings, 'vcs.server.protocol', 'http')
466 _bool_setting(settings, 'startup.import_repos', 'false')
470 _bool_setting(settings, 'startup.import_repos', 'false')
467 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
471 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
468 _bool_setting(settings, 'vcs.server.enable', 'true')
472 _bool_setting(settings, 'vcs.server.enable', 'true')
469 _bool_setting(settings, 'vcs.start_server', 'false')
473 _bool_setting(settings, 'vcs.start_server', 'false')
470 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
474 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
471 _int_setting(settings, 'vcs.connection_timeout', 3600)
475 _int_setting(settings, 'vcs.connection_timeout', 3600)
472
476
473 # Support legacy values of vcs.scm_app_implementation. Legacy
477 # Support legacy values of vcs.scm_app_implementation. Legacy
474 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
478 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
475 # which is now mapped to 'http'.
479 # which is now mapped to 'http'.
476 scm_app_impl = settings['vcs.scm_app_implementation']
480 scm_app_impl = settings['vcs.scm_app_implementation']
477 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
481 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
478 settings['vcs.scm_app_implementation'] = 'http'
482 settings['vcs.scm_app_implementation'] = 'http'
479
483
480
484
481 def _int_setting(settings, name, default):
485 def _int_setting(settings, name, default):
482 settings[name] = int(settings.get(name, default))
486 settings[name] = int(settings.get(name, default))
483
487
484
488
485 def _bool_setting(settings, name, default):
489 def _bool_setting(settings, name, default):
486 input = settings.get(name, default)
490 input = settings.get(name, default)
487 if isinstance(input, unicode):
491 if isinstance(input, unicode):
488 input = input.encode('utf8')
492 input = input.encode('utf8')
489 settings[name] = asbool(input)
493 settings[name] = asbool(input)
490
494
491
495
492 def _list_setting(settings, name, default):
496 def _list_setting(settings, name, default):
493 raw_value = settings.get(name, default)
497 raw_value = settings.get(name, default)
494
498
495 old_separator = ','
499 old_separator = ','
496 if old_separator in raw_value:
500 if old_separator in raw_value:
497 # If we get a comma separated list, pass it to our own function.
501 # If we get a comma separated list, pass it to our own function.
498 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
502 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
499 else:
503 else:
500 # Otherwise we assume it uses pyramids space/newline separation.
504 # Otherwise we assume it uses pyramids space/newline separation.
501 settings[name] = aslist(raw_value)
505 settings[name] = aslist(raw_value)
502
506
503
507
504 def _string_setting(settings, name, default, lower=True):
508 def _string_setting(settings, name, default, lower=True):
505 value = settings.get(name, default)
509 value = settings.get(name, default)
506 if lower:
510 if lower:
507 value = value.lower()
511 value = value.lower()
508 settings[name] = value
512 settings[name] = value
General Comments 0
You need to be logged in to leave comments. Login now