##// END OF EJS Templates
error-document: make sure the error document has registered helpers,...
marcink -
r1748:0fcdd9e3 default
parent child Browse files
Show More
@@ -1,45 +1,49 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-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 from rhodecode.config import routing_links
20 from rhodecode.config import routing_links
21
21
22
22
23 def includeme(config):
23 def includeme(config):
24
24
25 config.add_route(
25 config.add_route(
26 name='home',
27 pattern='/')
28
29 config.add_route(
26 name='user_autocomplete_data',
30 name='user_autocomplete_data',
27 pattern='/_users')
31 pattern='/_users')
28
32
29 config.add_route(
33 config.add_route(
30 name='user_group_autocomplete_data',
34 name='user_group_autocomplete_data',
31 pattern='/_user_groups')
35 pattern='/_user_groups')
32
36
33 config.add_route(
37 config.add_route(
34 name='repo_list_data',
38 name='repo_list_data',
35 pattern='/_repos')
39 pattern='/_repos')
36
40
37 config.add_route(
41 config.add_route(
38 name='goto_switcher_data',
42 name='goto_switcher_data',
39 pattern='/_goto_data')
43 pattern='/_goto_data')
40
44
41 # register our static links via redirection mechanismy
45 # register our static links via redirection mechanism
42 routing_links.connect_redirection_links(config)
46 routing_links.connect_redirection_links(config)
43
47
44 # Scan module for configuration decorators.
48 # Scan module for configuration decorators.
45 config.scan()
49 config.scan()
@@ -1,514 +1,515 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_js_routes_if_enabled,
56 scan_repositories_if_enabled, write_js_routes_if_enabled,
57 write_metadata_if_needed)
57 write_metadata_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 from rhodecode.lib import helpers
225
226
226 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
227 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
227
228
228 base_response = HTTPInternalServerError()
229 base_response = HTTPInternalServerError()
229 # prefer original exception for the response since it may have headers set
230 # prefer original exception for the response since it may have headers set
230 if isinstance(exception, HTTPException):
231 if isinstance(exception, HTTPException):
231 base_response = exception
232 base_response = exception
232
233
233 def is_http_error(response):
234 def is_http_error(response):
234 # error which should have traceback
235 # error which should have traceback
235 return response.status_code > 499
236 return response.status_code > 499
236
237
237 if is_http_error(base_response):
238 if is_http_error(base_response):
238 log.exception(
239 log.exception(
239 'error occurred handling this request for path: %s', request.path)
240 'error occurred handling this request for path: %s', request.path)
240
241
241 c = AttributeDict()
242 c = AttributeDict()
242 c.error_message = base_response.status
243 c.error_message = base_response.status
243 c.error_explanation = base_response.explanation or str(base_response)
244 c.error_explanation = base_response.explanation or str(base_response)
244 c.visual = AttributeDict()
245 c.visual = AttributeDict()
245
246
246 c.visual.rhodecode_support_url = (
247 c.visual.rhodecode_support_url = (
247 request.registry.settings.get('rhodecode_support_url') or
248 request.registry.settings.get('rhodecode_support_url') or
248 request.route_url('rhodecode_support')
249 request.route_url('rhodecode_support')
249 )
250 )
250 c.redirect_time = 0
251 c.redirect_time = 0
251 c.rhodecode_name = rhodecode_title
252 c.rhodecode_name = rhodecode_title
252 if not c.rhodecode_name:
253 if not c.rhodecode_name:
253 c.rhodecode_name = 'Rhodecode'
254 c.rhodecode_name = 'Rhodecode'
254
255
255 c.causes = []
256 c.causes = []
256 if hasattr(base_response, 'causes'):
257 if hasattr(base_response, 'causes'):
257 c.causes = base_response.causes
258 c.causes = base_response.causes
258
259 c.messages = helpers.flash.pop_messages()
259 response = render_to_response(
260 response = render_to_response(
260 '/errors/error_document.mako', {'c': c}, request=request,
261 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
261 response=base_response)
262 response=base_response)
262
263
263 return response
264 return response
264
265
265
266
266 def includeme(config):
267 def includeme(config):
267 settings = config.registry.settings
268 settings = config.registry.settings
268
269
269 # plugin information
270 # plugin information
270 config.registry.rhodecode_plugins = OrderedDict()
271 config.registry.rhodecode_plugins = OrderedDict()
271
272
272 config.add_directive(
273 config.add_directive(
273 'register_rhodecode_plugin', register_rhodecode_plugin)
274 'register_rhodecode_plugin', register_rhodecode_plugin)
274
275
275 if asbool(settings.get('appenlight', 'false')):
276 if asbool(settings.get('appenlight', 'false')):
276 config.include('appenlight_client.ext.pyramid_tween')
277 config.include('appenlight_client.ext.pyramid_tween')
277
278
278 # Includes which are required. The application would fail without them.
279 # Includes which are required. The application would fail without them.
279 config.include('pyramid_mako')
280 config.include('pyramid_mako')
280 config.include('pyramid_beaker')
281 config.include('pyramid_beaker')
281
282
282 config.include('rhodecode.authentication')
283 config.include('rhodecode.authentication')
283 config.include('rhodecode.integrations')
284 config.include('rhodecode.integrations')
284
285
285 # apps
286 # apps
286 config.include('rhodecode.apps._base')
287 config.include('rhodecode.apps._base')
287 config.include('rhodecode.apps.ops')
288 config.include('rhodecode.apps.ops')
288
289
289 config.include('rhodecode.apps.admin')
290 config.include('rhodecode.apps.admin')
290 config.include('rhodecode.apps.channelstream')
291 config.include('rhodecode.apps.channelstream')
291 config.include('rhodecode.apps.login')
292 config.include('rhodecode.apps.login')
292 config.include('rhodecode.apps.home')
293 config.include('rhodecode.apps.home')
293 config.include('rhodecode.apps.repository')
294 config.include('rhodecode.apps.repository')
294 config.include('rhodecode.apps.search')
295 config.include('rhodecode.apps.search')
295 config.include('rhodecode.apps.user_profile')
296 config.include('rhodecode.apps.user_profile')
296 config.include('rhodecode.apps.my_account')
297 config.include('rhodecode.apps.my_account')
297 config.include('rhodecode.apps.svn_support')
298 config.include('rhodecode.apps.svn_support')
298
299
299 config.include('rhodecode.tweens')
300 config.include('rhodecode.tweens')
300 config.include('rhodecode.api')
301 config.include('rhodecode.api')
301
302
302 config.add_route(
303 config.add_route(
303 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
304 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
304
305
305 config.add_translation_dirs('rhodecode:i18n/')
306 config.add_translation_dirs('rhodecode:i18n/')
306 settings['default_locale_name'] = settings.get('lang', 'en')
307 settings['default_locale_name'] = settings.get('lang', 'en')
307
308
308 # Add subscribers.
309 # Add subscribers.
309 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
310 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
310 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
311 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
311 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
312 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
312
313
313 # Set the authorization policy.
314 # Set the authorization policy.
314 authz_policy = ACLAuthorizationPolicy()
315 authz_policy = ACLAuthorizationPolicy()
315 config.set_authorization_policy(authz_policy)
316 config.set_authorization_policy(authz_policy)
316
317
317 # Set the default renderer for HTML templates to mako.
318 # Set the default renderer for HTML templates to mako.
318 config.add_mako_renderer('.html')
319 config.add_mako_renderer('.html')
319
320
320 config.add_renderer(
321 config.add_renderer(
321 name='json_ext',
322 name='json_ext',
322 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
323 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
323
324
324 # include RhodeCode plugins
325 # include RhodeCode plugins
325 includes = aslist(settings.get('rhodecode.includes', []))
326 includes = aslist(settings.get('rhodecode.includes', []))
326 for inc in includes:
327 for inc in includes:
327 config.include(inc)
328 config.include(inc)
328
329
329 # This is the glue which allows us to migrate in chunks. By registering the
330 # This is the glue which allows us to migrate in chunks. By registering the
330 # pylons based application as the "Not Found" view in Pyramid, we will
331 # pylons based application as the "Not Found" view in Pyramid, we will
331 # fallback to the old application each time the new one does not yet know
332 # fallback to the old application each time the new one does not yet know
332 # how to handle a request.
333 # how to handle a request.
333 config.add_notfound_view(make_not_found_view(config))
334 config.add_notfound_view(make_not_found_view(config))
334
335
335 if not settings.get('debugtoolbar.enabled', False):
336 if not settings.get('debugtoolbar.enabled', False):
336 # if no toolbar, then any exception gets caught and rendered
337 # if no toolbar, then any exception gets caught and rendered
337 config.add_view(error_handler, context=Exception)
338 config.add_view(error_handler, context=Exception)
338
339
339 config.add_view(error_handler, context=HTTPError)
340 config.add_view(error_handler, context=HTTPError)
340
341
341
342
342 def includeme_first(config):
343 def includeme_first(config):
343 # redirect automatic browser favicon.ico requests to correct place
344 # redirect automatic browser favicon.ico requests to correct place
344 def favicon_redirect(context, request):
345 def favicon_redirect(context, request):
345 return HTTPFound(
346 return HTTPFound(
346 request.static_path('rhodecode:public/images/favicon.ico'))
347 request.static_path('rhodecode:public/images/favicon.ico'))
347
348
348 config.add_view(favicon_redirect, route_name='favicon')
349 config.add_view(favicon_redirect, route_name='favicon')
349 config.add_route('favicon', '/favicon.ico')
350 config.add_route('favicon', '/favicon.ico')
350
351
351 def robots_redirect(context, request):
352 def robots_redirect(context, request):
352 return HTTPFound(
353 return HTTPFound(
353 request.static_path('rhodecode:public/robots.txt'))
354 request.static_path('rhodecode:public/robots.txt'))
354
355
355 config.add_view(robots_redirect, route_name='robots')
356 config.add_view(robots_redirect, route_name='robots')
356 config.add_route('robots', '/robots.txt')
357 config.add_route('robots', '/robots.txt')
357
358
358 config.add_static_view(
359 config.add_static_view(
359 '_static/deform', 'deform:static')
360 '_static/deform', 'deform:static')
360 config.add_static_view(
361 config.add_static_view(
361 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
362 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
362
363
363
364
364 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
365 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
365 """
366 """
366 Apply outer WSGI middlewares around the application.
367 Apply outer WSGI middlewares around the application.
367
368
368 Part of this has been moved up from the Pylons layer, so that the
369 Part of this has been moved up from the Pylons layer, so that the
369 data is also available if old Pylons code is hit through an already ported
370 data is also available if old Pylons code is hit through an already ported
370 view.
371 view.
371 """
372 """
372 settings = config.registry.settings
373 settings = config.registry.settings
373
374
374 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
375 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
375 pyramid_app = HttpsFixup(pyramid_app, settings)
376 pyramid_app = HttpsFixup(pyramid_app, settings)
376
377
377 # Add RoutesMiddleware to support the pylons compatibility tween during
378 # Add RoutesMiddleware to support the pylons compatibility tween during
378 # migration to pyramid.
379 # migration to pyramid.
379 pyramid_app = SkippableRoutesMiddleware(
380 pyramid_app = SkippableRoutesMiddleware(
380 pyramid_app, config.registry._pylons_compat_config['routes.map'],
381 pyramid_app, config.registry._pylons_compat_config['routes.map'],
381 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
382 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
382
383
383 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
384 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
384
385
385 if settings['gzip_responses']:
386 if settings['gzip_responses']:
386 pyramid_app = make_gzip_middleware(
387 pyramid_app = make_gzip_middleware(
387 pyramid_app, settings, compress_level=1)
388 pyramid_app, settings, compress_level=1)
388
389
389 # this should be the outer most middleware in the wsgi stack since
390 # this should be the outer most middleware in the wsgi stack since
390 # middleware like Routes make database calls
391 # middleware like Routes make database calls
391 def pyramid_app_with_cleanup(environ, start_response):
392 def pyramid_app_with_cleanup(environ, start_response):
392 try:
393 try:
393 return pyramid_app(environ, start_response)
394 return pyramid_app(environ, start_response)
394 finally:
395 finally:
395 # Dispose current database session and rollback uncommitted
396 # Dispose current database session and rollback uncommitted
396 # transactions.
397 # transactions.
397 meta.Session.remove()
398 meta.Session.remove()
398
399
399 # In a single threaded mode server, on non sqlite db we should have
400 # In a single threaded mode server, on non sqlite db we should have
400 # '0 Current Checked out connections' at the end of a request,
401 # '0 Current Checked out connections' at the end of a request,
401 # if not, then something, somewhere is leaving a connection open
402 # if not, then something, somewhere is leaving a connection open
402 pool = meta.Base.metadata.bind.engine.pool
403 pool = meta.Base.metadata.bind.engine.pool
403 log.debug('sa pool status: %s', pool.status())
404 log.debug('sa pool status: %s', pool.status())
404
405
405
406
406 return pyramid_app_with_cleanup
407 return pyramid_app_with_cleanup
407
408
408
409
409 def sanitize_settings_and_apply_defaults(settings):
410 def sanitize_settings_and_apply_defaults(settings):
410 """
411 """
411 Applies settings defaults and does all type conversion.
412 Applies settings defaults and does all type conversion.
412
413
413 We would move all settings parsing and preparation into this place, so that
414 We would move all settings parsing and preparation into this place, so that
414 we have only one place left which deals with this part. The remaining parts
415 we have only one place left which deals with this part. The remaining parts
415 of the application would start to rely fully on well prepared settings.
416 of the application would start to rely fully on well prepared settings.
416
417
417 This piece would later be split up per topic to avoid a big fat monster
418 This piece would later be split up per topic to avoid a big fat monster
418 function.
419 function.
419 """
420 """
420
421
421 # Pyramid's mako renderer has to search in the templates folder so that the
422 # Pyramid's mako renderer has to search in the templates folder so that the
422 # old templates still work. Ported and new templates are expected to use
423 # old templates still work. Ported and new templates are expected to use
423 # real asset specifications for the includes.
424 # real asset specifications for the includes.
424 mako_directories = settings.setdefault('mako.directories', [
425 mako_directories = settings.setdefault('mako.directories', [
425 # Base templates of the original Pylons application
426 # Base templates of the original Pylons application
426 'rhodecode:templates',
427 'rhodecode:templates',
427 ])
428 ])
428 log.debug(
429 log.debug(
429 "Using the following Mako template directories: %s",
430 "Using the following Mako template directories: %s",
430 mako_directories)
431 mako_directories)
431
432
432 # Default includes, possible to change as a user
433 # Default includes, possible to change as a user
433 pyramid_includes = settings.setdefault('pyramid.includes', [
434 pyramid_includes = settings.setdefault('pyramid.includes', [
434 'rhodecode.lib.middleware.request_wrapper',
435 'rhodecode.lib.middleware.request_wrapper',
435 ])
436 ])
436 log.debug(
437 log.debug(
437 "Using the following pyramid.includes: %s",
438 "Using the following pyramid.includes: %s",
438 pyramid_includes)
439 pyramid_includes)
439
440
440 # TODO: johbo: Re-think this, usually the call to config.include
441 # TODO: johbo: Re-think this, usually the call to config.include
441 # should allow to pass in a prefix.
442 # should allow to pass in a prefix.
442 settings.setdefault('rhodecode.api.url', '/_admin/api')
443 settings.setdefault('rhodecode.api.url', '/_admin/api')
443
444
444 # Sanitize generic settings.
445 # Sanitize generic settings.
445 _list_setting(settings, 'default_encoding', 'UTF-8')
446 _list_setting(settings, 'default_encoding', 'UTF-8')
446 _bool_setting(settings, 'is_test', 'false')
447 _bool_setting(settings, 'is_test', 'false')
447 _bool_setting(settings, 'gzip_responses', 'false')
448 _bool_setting(settings, 'gzip_responses', 'false')
448
449
449 # Call split out functions that sanitize settings for each topic.
450 # Call split out functions that sanitize settings for each topic.
450 _sanitize_appenlight_settings(settings)
451 _sanitize_appenlight_settings(settings)
451 _sanitize_vcs_settings(settings)
452 _sanitize_vcs_settings(settings)
452
453
453 return settings
454 return settings
454
455
455
456
456 def _sanitize_appenlight_settings(settings):
457 def _sanitize_appenlight_settings(settings):
457 _bool_setting(settings, 'appenlight', 'false')
458 _bool_setting(settings, 'appenlight', 'false')
458
459
459
460
460 def _sanitize_vcs_settings(settings):
461 def _sanitize_vcs_settings(settings):
461 """
462 """
462 Applies settings defaults and does type conversion for all VCS related
463 Applies settings defaults and does type conversion for all VCS related
463 settings.
464 settings.
464 """
465 """
465 _string_setting(settings, 'vcs.svn.compatible_version', '')
466 _string_setting(settings, 'vcs.svn.compatible_version', '')
466 _string_setting(settings, 'git_rev_filter', '--all')
467 _string_setting(settings, 'git_rev_filter', '--all')
467 _string_setting(settings, 'vcs.hooks.protocol', 'http')
468 _string_setting(settings, 'vcs.hooks.protocol', 'http')
468 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
469 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
469 _string_setting(settings, 'vcs.server', '')
470 _string_setting(settings, 'vcs.server', '')
470 _string_setting(settings, 'vcs.server.log_level', 'debug')
471 _string_setting(settings, 'vcs.server.log_level', 'debug')
471 _string_setting(settings, 'vcs.server.protocol', 'http')
472 _string_setting(settings, 'vcs.server.protocol', 'http')
472 _bool_setting(settings, 'startup.import_repos', 'false')
473 _bool_setting(settings, 'startup.import_repos', 'false')
473 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
474 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
474 _bool_setting(settings, 'vcs.server.enable', 'true')
475 _bool_setting(settings, 'vcs.server.enable', 'true')
475 _bool_setting(settings, 'vcs.start_server', 'false')
476 _bool_setting(settings, 'vcs.start_server', 'false')
476 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
477 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
477 _int_setting(settings, 'vcs.connection_timeout', 3600)
478 _int_setting(settings, 'vcs.connection_timeout', 3600)
478
479
479 # Support legacy values of vcs.scm_app_implementation. Legacy
480 # Support legacy values of vcs.scm_app_implementation. Legacy
480 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
481 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
481 # which is now mapped to 'http'.
482 # which is now mapped to 'http'.
482 scm_app_impl = settings['vcs.scm_app_implementation']
483 scm_app_impl = settings['vcs.scm_app_implementation']
483 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
484 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
484 settings['vcs.scm_app_implementation'] = 'http'
485 settings['vcs.scm_app_implementation'] = 'http'
485
486
486
487
487 def _int_setting(settings, name, default):
488 def _int_setting(settings, name, default):
488 settings[name] = int(settings.get(name, default))
489 settings[name] = int(settings.get(name, default))
489
490
490
491
491 def _bool_setting(settings, name, default):
492 def _bool_setting(settings, name, default):
492 input = settings.get(name, default)
493 input = settings.get(name, default)
493 if isinstance(input, unicode):
494 if isinstance(input, unicode):
494 input = input.encode('utf8')
495 input = input.encode('utf8')
495 settings[name] = asbool(input)
496 settings[name] = asbool(input)
496
497
497
498
498 def _list_setting(settings, name, default):
499 def _list_setting(settings, name, default):
499 raw_value = settings.get(name, default)
500 raw_value = settings.get(name, default)
500
501
501 old_separator = ','
502 old_separator = ','
502 if old_separator in raw_value:
503 if old_separator in raw_value:
503 # If we get a comma separated list, pass it to our own function.
504 # If we get a comma separated list, pass it to our own function.
504 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
505 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
505 else:
506 else:
506 # Otherwise we assume it uses pyramids space/newline separation.
507 # Otherwise we assume it uses pyramids space/newline separation.
507 settings[name] = aslist(raw_value)
508 settings[name] = aslist(raw_value)
508
509
509
510
510 def _string_setting(settings, name, default, lower=True):
511 def _string_setting(settings, name, default, lower=True):
511 value = settings.get(name, default)
512 value = settings.get(name, default)
512 if lower:
513 if lower:
513 value = value.lower()
514 value = value.lower()
514 settings[name] = value
515 settings[name] = value
@@ -1,77 +1,76 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html>
2 <!DOCTYPE html>
3 <html xmlns="http://www.w3.org/1999/xhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml">
4 <head>
4 <head>
5 <title>Error - ${c.error_message}</title>
5 <title>Error - ${c.error_message}</title>
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <meta name="robots" content="index, nofollow"/>
7 <meta name="robots" content="index, nofollow"/>
8 <link rel="icon" href="${h.asset('images/favicon.ico')}" sizes="16x16 32x32" type="image/png" />
8 <link rel="icon" href="${h.asset('images/favicon.ico')}" sizes="16x16 32x32" type="image/png" />
9
9
10 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
10 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
11 %if c.redirect_time:
11 %if c.redirect_time:
12 <meta http-equiv="refresh" content="${c.redirect_time}; url=${c.url_redirect}"/>
12 <meta http-equiv="refresh" content="${c.redirect_time}; url=${c.url_redirect}"/>
13 %endif
13 %endif
14
14
15 <link rel="stylesheet" type="text/css" href="${h.asset('css/style.css', ver=c.rhodecode_version_hash)}" media="screen"/>
15 <link rel="stylesheet" type="text/css" href="${h.asset('css/style.css', ver=c.rhodecode_version_hash)}" media="screen"/>
16 <!--[if IE]>
16 <!--[if IE]>
17 <link rel="stylesheet" type="text/css" href="${h.asset('css/ie.css')}" media="screen"/>
17 <link rel="stylesheet" type="text/css" href="${h.asset('css/ie.css')}" media="screen"/>
18 <![endif]-->
18 <![endif]-->
19 <style>body { background:#eeeeee; }</style>
19 <style>body { background:#eeeeee; }</style>
20 <script type="text/javascript">
20 <script type="text/javascript">
21 // register templateContext to pass template variables to JS
21 // register templateContext to pass template variables to JS
22 var templateContext = {timeago: {}};
22 var templateContext = {timeago: {}};
23 </script>
23 </script>
24 <script type="text/javascript" src="${h.asset('js/scripts.js', ver=c.rhodecode_version_hash)}"></script>
24 <script type="text/javascript" src="${h.asset('js/scripts.js', ver=c.rhodecode_version_hash)}"></script>
25 </head>
25 </head>
26 <body>
26 <body>
27 <% messages = h.flash.pop_messages() %>
28
27
29 <div class="wrapper error_page">
28 <div class="wrapper error_page">
30 <div class="sidebar">
29 <div class="sidebar">
31 <a href="${h.url('home')}"><img class="error-page-logo" src="${h.asset('images/RhodeCode_Logo_Black.png')}" alt="RhodeCode"/></a>
30 <a href="${h.route_path('home')}"><img class="error-page-logo" src="${h.asset('images/RhodeCode_Logo_Black.png')}" alt="RhodeCode"/></a>
32 </div>
31 </div>
33 <div class="main-content">
32 <div class="main-content">
34 <h1>
33 <h1>
35 <span class="error-branding">
34 <span class="error-branding">
36 ${h.branding(c.rhodecode_name)}
35 ${h.branding(c.rhodecode_name)}
37 </span><br/>
36 </span><br/>
38 ${c.error_message} | <span class="error_message">${c.error_explanation}</span>
37 ${c.error_message} | <span class="error_message">${c.error_explanation}</span>
39 </h1>
38 </h1>
40 % if messages:
39 % if c.messages:
41 % for message in messages:
40 % for message in c.messages:
42 <div class="alert alert-${message.category}">${message}</div>
41 <div class="alert alert-${message.category}">${message}</div>
43 % endfor
42 % endfor
44 % endif
43 % endif
45 %if c.redirect_time:
44 %if c.redirect_time:
46 <p>${_('You will be redirected to %s in %s seconds') % (c.redirect_module,c.redirect_time)}</p>
45 <p>${_('You will be redirected to %s in %s seconds') % (c.redirect_module,c.redirect_time)}</p>
47 %endif
46 %endif
48 <div class="inner-column">
47 <div class="inner-column">
49 <h4>Possible Causes</h4>
48 <h4>Possible Causes</h4>
50 <ul>
49 <ul>
51 % if c.causes:
50 % if c.causes:
52 %for cause in c.causes:
51 %for cause in c.causes:
53 <li>${cause}</li>
52 <li>${cause}</li>
54 %endfor
53 %endfor
55 %else:
54 %else:
56 <li>The resource may have been deleted.</li>
55 <li>The resource may have been deleted.</li>
57 <li>You may not have access to this repository.</li>
56 <li>You may not have access to this repository.</li>
58 <li>The link may be incorrect.</li>
57 <li>The link may be incorrect.</li>
59 %endif
58 %endif
60 </ul>
59 </ul>
61 </div>
60 </div>
62 <div class="inner-column">
61 <div class="inner-column">
63 <h4>Support</h4>
62 <h4>Support</h4>
64 <p>For support, go to <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>.
63 <p>For support, go to <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>.
65 It may be useful to include your log file; see the log file locations <a href="${h.route_url('enterprise_log_file_locations')}">here</a>.
64 It may be useful to include your log file; see the log file locations <a href="${h.route_url('enterprise_log_file_locations')}">here</a>.
66 </p>
65 </p>
67 </div>
66 </div>
68 <div class="inner-column">
67 <div class="inner-column">
69 <h4>Documentation</h4>
68 <h4>Documentation</h4>
70 <p>For more information, see <a href="${h.route_url('enterprise_docs')}">docs.rhodecode.com</a>.</p>
69 <p>For more information, see <a href="${h.route_url('enterprise_docs')}">docs.rhodecode.com</a>.</p>
71 </div>
70 </div>
72 </div>
71 </div>
73 </div>
72 </div>
74
73
75 </body>
74 </body>
76
75
77 </html>
76 </html>
General Comments 0
You need to be logged in to leave comments. Login now