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