##// END OF EJS Templates
core: added ops view to pyramid to have a PING command with pure pyramid.
marcink -
r1669:f7580c8e default
parent child Browse files
Show More
@@ -0,0 +1,35 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-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.config.routing import ADMIN_PREFIX
22
23
24 def admin_routes(config):
25 config.add_route(
26 name='ops_ping',
27 pattern='/ping')
28
29
30 def includeme(config):
31
32 config.include(admin_routes, route_prefix=ADMIN_PREFIX + '/ops')
33
34 # Scan module for configuration decorators.
35 config.scan()
@@ -0,0 +1,54 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-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 import logging
22
23 from pyramid.view import view_config
24
25 from rhodecode.apps._base import BaseAppView
26
27
28 log = logging.getLogger(__name__)
29
30
31 class OpsView(BaseAppView):
32
33 def load_default_context(self):
34 c = self._get_local_tmpl_context()
35 c.user = c.auth_user.get_instance()
36 self._register_global_c(c)
37 return c
38
39 @view_config(
40 route_name='ops_ping', request_method='GET',
41 renderer='json_ext')
42 def ops_ping(self):
43 data = {
44 'instance': self.request.registry.settings.get('instance_id'),
45 }
46 if getattr(self.request, 'user'):
47 data.update({
48 'caller_ip': self.request.user.ip_addr,
49 'caller_name': self.request.user.username,
50 })
51 return {'ok': data}
52
53
54
@@ -1,513 +1,514 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 config.include('rhodecode.apps.ops')
287
288
288 config.include('rhodecode.apps.admin')
289 config.include('rhodecode.apps.admin')
289 config.include('rhodecode.apps.channelstream')
290 config.include('rhodecode.apps.channelstream')
290 config.include('rhodecode.apps.login')
291 config.include('rhodecode.apps.login')
291 config.include('rhodecode.apps.home')
292 config.include('rhodecode.apps.home')
292 config.include('rhodecode.apps.repository')
293 config.include('rhodecode.apps.repository')
293 config.include('rhodecode.apps.user_profile')
294 config.include('rhodecode.apps.user_profile')
294 config.include('rhodecode.apps.my_account')
295 config.include('rhodecode.apps.my_account')
295 config.include('rhodecode.apps.svn_support')
296 config.include('rhodecode.apps.svn_support')
296
297
297 config.include('rhodecode.tweens')
298 config.include('rhodecode.tweens')
298 config.include('rhodecode.api')
299 config.include('rhodecode.api')
299
300
300 config.add_route(
301 config.add_route(
301 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
302 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
302
303
303 config.add_translation_dirs('rhodecode:i18n/')
304 config.add_translation_dirs('rhodecode:i18n/')
304 settings['default_locale_name'] = settings.get('lang', 'en')
305 settings['default_locale_name'] = settings.get('lang', 'en')
305
306
306 # Add subscribers.
307 # Add subscribers.
307 config.add_subscriber(create_largeobjects_dirs_if_needed, ApplicationCreated)
308 config.add_subscriber(create_largeobjects_dirs_if_needed, ApplicationCreated)
308 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
309 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
309 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
310 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
310 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
311 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
311
312
312 # Set the authorization policy.
313 # Set the authorization policy.
313 authz_policy = ACLAuthorizationPolicy()
314 authz_policy = ACLAuthorizationPolicy()
314 config.set_authorization_policy(authz_policy)
315 config.set_authorization_policy(authz_policy)
315
316
316 # Set the default renderer for HTML templates to mako.
317 # Set the default renderer for HTML templates to mako.
317 config.add_mako_renderer('.html')
318 config.add_mako_renderer('.html')
318
319
319 config.add_renderer(
320 config.add_renderer(
320 name='json_ext',
321 name='json_ext',
321 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
322 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
322
323
323 # include RhodeCode plugins
324 # include RhodeCode plugins
324 includes = aslist(settings.get('rhodecode.includes', []))
325 includes = aslist(settings.get('rhodecode.includes', []))
325 for inc in includes:
326 for inc in includes:
326 config.include(inc)
327 config.include(inc)
327
328
328 # This is the glue which allows us to migrate in chunks. By registering the
329 # This is the glue which allows us to migrate in chunks. By registering the
329 # pylons based application as the "Not Found" view in Pyramid, we will
330 # pylons based application as the "Not Found" view in Pyramid, we will
330 # fallback to the old application each time the new one does not yet know
331 # fallback to the old application each time the new one does not yet know
331 # how to handle a request.
332 # how to handle a request.
332 config.add_notfound_view(make_not_found_view(config))
333 config.add_notfound_view(make_not_found_view(config))
333
334
334 if not settings.get('debugtoolbar.enabled', False):
335 if not settings.get('debugtoolbar.enabled', False):
335 # if no toolbar, then any exception gets caught and rendered
336 # if no toolbar, then any exception gets caught and rendered
336 config.add_view(error_handler, context=Exception)
337 config.add_view(error_handler, context=Exception)
337
338
338 config.add_view(error_handler, context=HTTPError)
339 config.add_view(error_handler, context=HTTPError)
339
340
340
341
341 def includeme_first(config):
342 def includeme_first(config):
342 # redirect automatic browser favicon.ico requests to correct place
343 # redirect automatic browser favicon.ico requests to correct place
343 def favicon_redirect(context, request):
344 def favicon_redirect(context, request):
344 return HTTPFound(
345 return HTTPFound(
345 request.static_path('rhodecode:public/images/favicon.ico'))
346 request.static_path('rhodecode:public/images/favicon.ico'))
346
347
347 config.add_view(favicon_redirect, route_name='favicon')
348 config.add_view(favicon_redirect, route_name='favicon')
348 config.add_route('favicon', '/favicon.ico')
349 config.add_route('favicon', '/favicon.ico')
349
350
350 def robots_redirect(context, request):
351 def robots_redirect(context, request):
351 return HTTPFound(
352 return HTTPFound(
352 request.static_path('rhodecode:public/robots.txt'))
353 request.static_path('rhodecode:public/robots.txt'))
353
354
354 config.add_view(robots_redirect, route_name='robots')
355 config.add_view(robots_redirect, route_name='robots')
355 config.add_route('robots', '/robots.txt')
356 config.add_route('robots', '/robots.txt')
356
357
357 config.add_static_view(
358 config.add_static_view(
358 '_static/deform', 'deform:static')
359 '_static/deform', 'deform:static')
359 config.add_static_view(
360 config.add_static_view(
360 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
361 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
361
362
362
363
363 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
364 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
364 """
365 """
365 Apply outer WSGI middlewares around the application.
366 Apply outer WSGI middlewares around the application.
366
367
367 Part of this has been moved up from the Pylons layer, so that the
368 Part of this has been moved up from the Pylons layer, so that the
368 data is also available if old Pylons code is hit through an already ported
369 data is also available if old Pylons code is hit through an already ported
369 view.
370 view.
370 """
371 """
371 settings = config.registry.settings
372 settings = config.registry.settings
372
373
373 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
374 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
374 pyramid_app = HttpsFixup(pyramid_app, settings)
375 pyramid_app = HttpsFixup(pyramid_app, settings)
375
376
376 # Add RoutesMiddleware to support the pylons compatibility tween during
377 # Add RoutesMiddleware to support the pylons compatibility tween during
377 # migration to pyramid.
378 # migration to pyramid.
378 pyramid_app = SkippableRoutesMiddleware(
379 pyramid_app = SkippableRoutesMiddleware(
379 pyramid_app, config.registry._pylons_compat_config['routes.map'],
380 pyramid_app, config.registry._pylons_compat_config['routes.map'],
380 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
381 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
381
382
382 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
383 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
383
384
384 if settings['gzip_responses']:
385 if settings['gzip_responses']:
385 pyramid_app = make_gzip_middleware(
386 pyramid_app = make_gzip_middleware(
386 pyramid_app, settings, compress_level=1)
387 pyramid_app, settings, compress_level=1)
387
388
388 # this should be the outer most middleware in the wsgi stack since
389 # this should be the outer most middleware in the wsgi stack since
389 # middleware like Routes make database calls
390 # middleware like Routes make database calls
390 def pyramid_app_with_cleanup(environ, start_response):
391 def pyramid_app_with_cleanup(environ, start_response):
391 try:
392 try:
392 return pyramid_app(environ, start_response)
393 return pyramid_app(environ, start_response)
393 finally:
394 finally:
394 # Dispose current database session and rollback uncommitted
395 # Dispose current database session and rollback uncommitted
395 # transactions.
396 # transactions.
396 meta.Session.remove()
397 meta.Session.remove()
397
398
398 # In a single threaded mode server, on non sqlite db we should have
399 # In a single threaded mode server, on non sqlite db we should have
399 # '0 Current Checked out connections' at the end of a request,
400 # '0 Current Checked out connections' at the end of a request,
400 # if not, then something, somewhere is leaving a connection open
401 # if not, then something, somewhere is leaving a connection open
401 pool = meta.Base.metadata.bind.engine.pool
402 pool = meta.Base.metadata.bind.engine.pool
402 log.debug('sa pool status: %s', pool.status())
403 log.debug('sa pool status: %s', pool.status())
403
404
404
405
405 return pyramid_app_with_cleanup
406 return pyramid_app_with_cleanup
406
407
407
408
408 def sanitize_settings_and_apply_defaults(settings):
409 def sanitize_settings_and_apply_defaults(settings):
409 """
410 """
410 Applies settings defaults and does all type conversion.
411 Applies settings defaults and does all type conversion.
411
412
412 We would move all settings parsing and preparation into this place, so that
413 We would move all settings parsing and preparation into this place, so that
413 we have only one place left which deals with this part. The remaining parts
414 we have only one place left which deals with this part. The remaining parts
414 of the application would start to rely fully on well prepared settings.
415 of the application would start to rely fully on well prepared settings.
415
416
416 This piece would later be split up per topic to avoid a big fat monster
417 This piece would later be split up per topic to avoid a big fat monster
417 function.
418 function.
418 """
419 """
419
420
420 # Pyramid's mako renderer has to search in the templates folder so that the
421 # Pyramid's mako renderer has to search in the templates folder so that the
421 # old templates still work. Ported and new templates are expected to use
422 # old templates still work. Ported and new templates are expected to use
422 # real asset specifications for the includes.
423 # real asset specifications for the includes.
423 mako_directories = settings.setdefault('mako.directories', [
424 mako_directories = settings.setdefault('mako.directories', [
424 # Base templates of the original Pylons application
425 # Base templates of the original Pylons application
425 'rhodecode:templates',
426 'rhodecode:templates',
426 ])
427 ])
427 log.debug(
428 log.debug(
428 "Using the following Mako template directories: %s",
429 "Using the following Mako template directories: %s",
429 mako_directories)
430 mako_directories)
430
431
431 # Default includes, possible to change as a user
432 # Default includes, possible to change as a user
432 pyramid_includes = settings.setdefault('pyramid.includes', [
433 pyramid_includes = settings.setdefault('pyramid.includes', [
433 'rhodecode.lib.middleware.request_wrapper',
434 'rhodecode.lib.middleware.request_wrapper',
434 ])
435 ])
435 log.debug(
436 log.debug(
436 "Using the following pyramid.includes: %s",
437 "Using the following pyramid.includes: %s",
437 pyramid_includes)
438 pyramid_includes)
438
439
439 # TODO: johbo: Re-think this, usually the call to config.include
440 # TODO: johbo: Re-think this, usually the call to config.include
440 # should allow to pass in a prefix.
441 # should allow to pass in a prefix.
441 settings.setdefault('rhodecode.api.url', '/_admin/api')
442 settings.setdefault('rhodecode.api.url', '/_admin/api')
442
443
443 # Sanitize generic settings.
444 # Sanitize generic settings.
444 _list_setting(settings, 'default_encoding', 'UTF-8')
445 _list_setting(settings, 'default_encoding', 'UTF-8')
445 _bool_setting(settings, 'is_test', 'false')
446 _bool_setting(settings, 'is_test', 'false')
446 _bool_setting(settings, 'gzip_responses', 'false')
447 _bool_setting(settings, 'gzip_responses', 'false')
447
448
448 # Call split out functions that sanitize settings for each topic.
449 # Call split out functions that sanitize settings for each topic.
449 _sanitize_appenlight_settings(settings)
450 _sanitize_appenlight_settings(settings)
450 _sanitize_vcs_settings(settings)
451 _sanitize_vcs_settings(settings)
451
452
452 return settings
453 return settings
453
454
454
455
455 def _sanitize_appenlight_settings(settings):
456 def _sanitize_appenlight_settings(settings):
456 _bool_setting(settings, 'appenlight', 'false')
457 _bool_setting(settings, 'appenlight', 'false')
457
458
458
459
459 def _sanitize_vcs_settings(settings):
460 def _sanitize_vcs_settings(settings):
460 """
461 """
461 Applies settings defaults and does type conversion for all VCS related
462 Applies settings defaults and does type conversion for all VCS related
462 settings.
463 settings.
463 """
464 """
464 _string_setting(settings, 'vcs.svn.compatible_version', '')
465 _string_setting(settings, 'vcs.svn.compatible_version', '')
465 _string_setting(settings, 'git_rev_filter', '--all')
466 _string_setting(settings, 'git_rev_filter', '--all')
466 _string_setting(settings, 'vcs.hooks.protocol', 'http')
467 _string_setting(settings, 'vcs.hooks.protocol', 'http')
467 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
468 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
468 _string_setting(settings, 'vcs.server', '')
469 _string_setting(settings, 'vcs.server', '')
469 _string_setting(settings, 'vcs.server.log_level', 'debug')
470 _string_setting(settings, 'vcs.server.log_level', 'debug')
470 _string_setting(settings, 'vcs.server.protocol', 'http')
471 _string_setting(settings, 'vcs.server.protocol', 'http')
471 _bool_setting(settings, 'startup.import_repos', 'false')
472 _bool_setting(settings, 'startup.import_repos', 'false')
472 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
473 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
473 _bool_setting(settings, 'vcs.server.enable', 'true')
474 _bool_setting(settings, 'vcs.server.enable', 'true')
474 _bool_setting(settings, 'vcs.start_server', 'false')
475 _bool_setting(settings, 'vcs.start_server', 'false')
475 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
476 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
476 _int_setting(settings, 'vcs.connection_timeout', 3600)
477 _int_setting(settings, 'vcs.connection_timeout', 3600)
477
478
478 # Support legacy values of vcs.scm_app_implementation. Legacy
479 # Support legacy values of vcs.scm_app_implementation. Legacy
479 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
480 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
480 # which is now mapped to 'http'.
481 # which is now mapped to 'http'.
481 scm_app_impl = settings['vcs.scm_app_implementation']
482 scm_app_impl = settings['vcs.scm_app_implementation']
482 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
483 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
483 settings['vcs.scm_app_implementation'] = 'http'
484 settings['vcs.scm_app_implementation'] = 'http'
484
485
485
486
486 def _int_setting(settings, name, default):
487 def _int_setting(settings, name, default):
487 settings[name] = int(settings.get(name, default))
488 settings[name] = int(settings.get(name, default))
488
489
489
490
490 def _bool_setting(settings, name, default):
491 def _bool_setting(settings, name, default):
491 input = settings.get(name, default)
492 input = settings.get(name, default)
492 if isinstance(input, unicode):
493 if isinstance(input, unicode):
493 input = input.encode('utf8')
494 input = input.encode('utf8')
494 settings[name] = asbool(input)
495 settings[name] = asbool(input)
495
496
496
497
497 def _list_setting(settings, name, default):
498 def _list_setting(settings, name, default):
498 raw_value = settings.get(name, default)
499 raw_value = settings.get(name, default)
499
500
500 old_separator = ','
501 old_separator = ','
501 if old_separator in raw_value:
502 if old_separator in raw_value:
502 # If we get a comma separated list, pass it to our own function.
503 # If we get a comma separated list, pass it to our own function.
503 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
504 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
504 else:
505 else:
505 # Otherwise we assume it uses pyramids space/newline separation.
506 # Otherwise we assume it uses pyramids space/newline separation.
506 settings[name] = aslist(raw_value)
507 settings[name] = aslist(raw_value)
507
508
508
509
509 def _string_setting(settings, name, default, lower=True):
510 def _string_setting(settings, name, default, lower=True):
510 value = settings.get(name, default)
511 value = settings.get(name, default)
511 if lower:
512 if lower:
512 value = value.lower()
513 value = value.lower()
513 settings[name] = value
514 settings[name] = value
@@ -1,776 +1,777 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 import hashlib
21 import hashlib
22 import logging
22 import logging
23 from collections import namedtuple
23 from collections import namedtuple
24 from functools import wraps
24 from functools import wraps
25
25
26 from rhodecode.lib import caches
26 from rhodecode.lib import caches
27 from rhodecode.lib.utils2 import (
27 from rhodecode.lib.utils2 import (
28 Optional, AttributeDict, safe_str, remove_prefix, str2bool)
28 Optional, AttributeDict, safe_str, remove_prefix, str2bool)
29 from rhodecode.lib.vcs.backends import base
29 from rhodecode.lib.vcs.backends import base
30 from rhodecode.model import BaseModel
30 from rhodecode.model import BaseModel
31 from rhodecode.model.db import (
31 from rhodecode.model.db import (
32 RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi, RhodeCodeSetting)
32 RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi, RhodeCodeSetting)
33 from rhodecode.model.meta import Session
33 from rhodecode.model.meta import Session
34
34
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 UiSetting = namedtuple(
39 UiSetting = namedtuple(
40 'UiSetting', ['section', 'key', 'value', 'active'])
40 'UiSetting', ['section', 'key', 'value', 'active'])
41
41
42 SOCIAL_PLUGINS_LIST = ['github', 'bitbucket', 'twitter', 'google']
42 SOCIAL_PLUGINS_LIST = ['github', 'bitbucket', 'twitter', 'google']
43
43
44
44
45 class SettingNotFound(Exception):
45 class SettingNotFound(Exception):
46 def __init__(self):
46 def __init__(self):
47 super(SettingNotFound, self).__init__('Setting is not found')
47 super(SettingNotFound, self).__init__('Setting is not found')
48
48
49
49
50 class SettingsModel(BaseModel):
50 class SettingsModel(BaseModel):
51 BUILTIN_HOOKS = (
51 BUILTIN_HOOKS = (
52 RhodeCodeUi.HOOK_REPO_SIZE, RhodeCodeUi.HOOK_PUSH,
52 RhodeCodeUi.HOOK_REPO_SIZE, RhodeCodeUi.HOOK_PUSH,
53 RhodeCodeUi.HOOK_PRE_PUSH, RhodeCodeUi.HOOK_PRETX_PUSH,
53 RhodeCodeUi.HOOK_PRE_PUSH, RhodeCodeUi.HOOK_PRETX_PUSH,
54 RhodeCodeUi.HOOK_PULL, RhodeCodeUi.HOOK_PRE_PULL)
54 RhodeCodeUi.HOOK_PULL, RhodeCodeUi.HOOK_PRE_PULL)
55 HOOKS_SECTION = 'hooks'
55 HOOKS_SECTION = 'hooks'
56
56
57 def __init__(self, sa=None, repo=None):
57 def __init__(self, sa=None, repo=None):
58 self.repo = repo
58 self.repo = repo
59 self.UiDbModel = RepoRhodeCodeUi if repo else RhodeCodeUi
59 self.UiDbModel = RepoRhodeCodeUi if repo else RhodeCodeUi
60 self.SettingsDbModel = (
60 self.SettingsDbModel = (
61 RepoRhodeCodeSetting if repo else RhodeCodeSetting)
61 RepoRhodeCodeSetting if repo else RhodeCodeSetting)
62 super(SettingsModel, self).__init__(sa)
62 super(SettingsModel, self).__init__(sa)
63
63
64 def get_ui_by_key(self, key):
64 def get_ui_by_key(self, key):
65 q = self.UiDbModel.query()
65 q = self.UiDbModel.query()
66 q = q.filter(self.UiDbModel.ui_key == key)
66 q = q.filter(self.UiDbModel.ui_key == key)
67 q = self._filter_by_repo(RepoRhodeCodeUi, q)
67 q = self._filter_by_repo(RepoRhodeCodeUi, q)
68 return q.scalar()
68 return q.scalar()
69
69
70 def get_ui_by_section(self, section):
70 def get_ui_by_section(self, section):
71 q = self.UiDbModel.query()
71 q = self.UiDbModel.query()
72 q = q.filter(self.UiDbModel.ui_section == section)
72 q = q.filter(self.UiDbModel.ui_section == section)
73 q = self._filter_by_repo(RepoRhodeCodeUi, q)
73 q = self._filter_by_repo(RepoRhodeCodeUi, q)
74 return q.all()
74 return q.all()
75
75
76 def get_ui_by_section_and_key(self, section, key):
76 def get_ui_by_section_and_key(self, section, key):
77 q = self.UiDbModel.query()
77 q = self.UiDbModel.query()
78 q = q.filter(self.UiDbModel.ui_section == section)
78 q = q.filter(self.UiDbModel.ui_section == section)
79 q = q.filter(self.UiDbModel.ui_key == key)
79 q = q.filter(self.UiDbModel.ui_key == key)
80 q = self._filter_by_repo(RepoRhodeCodeUi, q)
80 q = self._filter_by_repo(RepoRhodeCodeUi, q)
81 return q.scalar()
81 return q.scalar()
82
82
83 def get_ui(self, section=None, key=None):
83 def get_ui(self, section=None, key=None):
84 q = self.UiDbModel.query()
84 q = self.UiDbModel.query()
85 q = self._filter_by_repo(RepoRhodeCodeUi, q)
85 q = self._filter_by_repo(RepoRhodeCodeUi, q)
86
86
87 if section:
87 if section:
88 q = q.filter(self.UiDbModel.ui_section == section)
88 q = q.filter(self.UiDbModel.ui_section == section)
89 if key:
89 if key:
90 q = q.filter(self.UiDbModel.ui_key == key)
90 q = q.filter(self.UiDbModel.ui_key == key)
91
91
92 # TODO: mikhail: add caching
92 # TODO: mikhail: add caching
93 result = [
93 result = [
94 UiSetting(
94 UiSetting(
95 section=safe_str(r.ui_section), key=safe_str(r.ui_key),
95 section=safe_str(r.ui_section), key=safe_str(r.ui_key),
96 value=safe_str(r.ui_value), active=r.ui_active
96 value=safe_str(r.ui_value), active=r.ui_active
97 )
97 )
98 for r in q.all()
98 for r in q.all()
99 ]
99 ]
100 return result
100 return result
101
101
102 def get_builtin_hooks(self):
102 def get_builtin_hooks(self):
103 q = self.UiDbModel.query()
103 q = self.UiDbModel.query()
104 q = q.filter(self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
104 q = q.filter(self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
105 return self._get_hooks(q)
105 return self._get_hooks(q)
106
106
107 def get_custom_hooks(self):
107 def get_custom_hooks(self):
108 q = self.UiDbModel.query()
108 q = self.UiDbModel.query()
109 q = q.filter(~self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
109 q = q.filter(~self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
110 return self._get_hooks(q)
110 return self._get_hooks(q)
111
111
112 def create_ui_section_value(self, section, val, key=None, active=True):
112 def create_ui_section_value(self, section, val, key=None, active=True):
113 new_ui = self.UiDbModel()
113 new_ui = self.UiDbModel()
114 new_ui.ui_section = section
114 new_ui.ui_section = section
115 new_ui.ui_value = val
115 new_ui.ui_value = val
116 new_ui.ui_active = active
116 new_ui.ui_active = active
117
117
118 if self.repo:
118 if self.repo:
119 repo = self._get_repo(self.repo)
119 repo = self._get_repo(self.repo)
120 repository_id = repo.repo_id
120 repository_id = repo.repo_id
121 new_ui.repository_id = repository_id
121 new_ui.repository_id = repository_id
122
122
123 if not key:
123 if not key:
124 # keys are unique so they need appended info
124 # keys are unique so they need appended info
125 if self.repo:
125 if self.repo:
126 key = hashlib.sha1(
126 key = hashlib.sha1(
127 '{}{}{}'.format(section, val, repository_id)).hexdigest()
127 '{}{}{}'.format(section, val, repository_id)).hexdigest()
128 else:
128 else:
129 key = hashlib.sha1('{}{}'.format(section, val)).hexdigest()
129 key = hashlib.sha1('{}{}'.format(section, val)).hexdigest()
130
130
131 new_ui.ui_key = key
131 new_ui.ui_key = key
132
132
133 Session().add(new_ui)
133 Session().add(new_ui)
134 return new_ui
134 return new_ui
135
135
136 def create_or_update_hook(self, key, value):
136 def create_or_update_hook(self, key, value):
137 ui = (
137 ui = (
138 self.get_ui_by_section_and_key(self.HOOKS_SECTION, key) or
138 self.get_ui_by_section_and_key(self.HOOKS_SECTION, key) or
139 self.UiDbModel())
139 self.UiDbModel())
140 ui.ui_section = self.HOOKS_SECTION
140 ui.ui_section = self.HOOKS_SECTION
141 ui.ui_active = True
141 ui.ui_active = True
142 ui.ui_key = key
142 ui.ui_key = key
143 ui.ui_value = value
143 ui.ui_value = value
144
144
145 if self.repo:
145 if self.repo:
146 repo = self._get_repo(self.repo)
146 repo = self._get_repo(self.repo)
147 repository_id = repo.repo_id
147 repository_id = repo.repo_id
148 ui.repository_id = repository_id
148 ui.repository_id = repository_id
149
149
150 Session().add(ui)
150 Session().add(ui)
151 return ui
151 return ui
152
152
153 def delete_ui(self, id_):
153 def delete_ui(self, id_):
154 ui = self.UiDbModel.get(id_)
154 ui = self.UiDbModel.get(id_)
155 if not ui:
155 if not ui:
156 raise SettingNotFound()
156 raise SettingNotFound()
157 Session().delete(ui)
157 Session().delete(ui)
158
158
159 def get_setting_by_name(self, name):
159 def get_setting_by_name(self, name):
160 q = self._get_settings_query()
160 q = self._get_settings_query()
161 q = q.filter(self.SettingsDbModel.app_settings_name == name)
161 q = q.filter(self.SettingsDbModel.app_settings_name == name)
162 return q.scalar()
162 return q.scalar()
163
163
164 def create_or_update_setting(
164 def create_or_update_setting(
165 self, name, val=Optional(''), type_=Optional('unicode')):
165 self, name, val=Optional(''), type_=Optional('unicode')):
166 """
166 """
167 Creates or updates RhodeCode setting. If updates is triggered it will
167 Creates or updates RhodeCode setting. If updates is triggered it will
168 only update parameters that are explicityl set Optional instance will
168 only update parameters that are explicityl set Optional instance will
169 be skipped
169 be skipped
170
170
171 :param name:
171 :param name:
172 :param val:
172 :param val:
173 :param type_:
173 :param type_:
174 :return:
174 :return:
175 """
175 """
176
176
177 res = self.get_setting_by_name(name)
177 res = self.get_setting_by_name(name)
178 repo = self._get_repo(self.repo) if self.repo else None
178 repo = self._get_repo(self.repo) if self.repo else None
179
179
180 if not res:
180 if not res:
181 val = Optional.extract(val)
181 val = Optional.extract(val)
182 type_ = Optional.extract(type_)
182 type_ = Optional.extract(type_)
183
183
184 args = (
184 args = (
185 (repo.repo_id, name, val, type_)
185 (repo.repo_id, name, val, type_)
186 if repo else (name, val, type_))
186 if repo else (name, val, type_))
187 res = self.SettingsDbModel(*args)
187 res = self.SettingsDbModel(*args)
188
188
189 else:
189 else:
190 if self.repo:
190 if self.repo:
191 res.repository_id = repo.repo_id
191 res.repository_id = repo.repo_id
192
192
193 res.app_settings_name = name
193 res.app_settings_name = name
194 if not isinstance(type_, Optional):
194 if not isinstance(type_, Optional):
195 # update if set
195 # update if set
196 res.app_settings_type = type_
196 res.app_settings_type = type_
197 if not isinstance(val, Optional):
197 if not isinstance(val, Optional):
198 # update if set
198 # update if set
199 res.app_settings_value = val
199 res.app_settings_value = val
200
200
201 Session().add(res)
201 Session().add(res)
202 return res
202 return res
203
203
204 def invalidate_settings_cache(self):
204 def invalidate_settings_cache(self):
205 namespace = 'rhodecode_settings'
205 namespace = 'rhodecode_settings'
206 cache_manager = caches.get_cache_manager('sql_cache_short', namespace)
206 cache_manager = caches.get_cache_manager('sql_cache_short', namespace)
207 caches.clear_cache_manager(cache_manager)
207 caches.clear_cache_manager(cache_manager)
208
208
209 def get_all_settings(self, cache=False):
209 def get_all_settings(self, cache=False):
210
210 def _compute():
211 def _compute():
211 q = self._get_settings_query()
212 q = self._get_settings_query()
212 if not q:
213 if not q:
213 raise Exception('Could not get application settings !')
214 raise Exception('Could not get application settings !')
214
215
215 settings = {
216 settings = {
216 'rhodecode_' + result.app_settings_name: result.app_settings_value
217 'rhodecode_' + result.app_settings_name: result.app_settings_value
217 for result in q
218 for result in q
218 }
219 }
219 return settings
220 return settings
220
221
221 if cache:
222 if cache:
222 log.debug('Fetching app settings using cache')
223 log.debug('Fetching app settings using cache')
223 repo = self._get_repo(self.repo) if self.repo else None
224 repo = self._get_repo(self.repo) if self.repo else None
224 namespace = 'rhodecode_settings'
225 namespace = 'rhodecode_settings'
225 cache_manager = caches.get_cache_manager(
226 cache_manager = caches.get_cache_manager(
226 'sql_cache_short', namespace)
227 'sql_cache_short', namespace)
227 _cache_key = (
228 _cache_key = (
228 "get_repo_{}_settings".format(repo.repo_id)
229 "get_repo_{}_settings".format(repo.repo_id)
229 if repo else "get_app_settings")
230 if repo else "get_app_settings")
230
231
231 return cache_manager.get(_cache_key, createfunc=_compute)
232 return cache_manager.get(_cache_key, createfunc=_compute)
232
233
233 else:
234 else:
234 return _compute()
235 return _compute()
235
236
236 def get_auth_settings(self):
237 def get_auth_settings(self):
237 q = self._get_settings_query()
238 q = self._get_settings_query()
238 q = q.filter(
239 q = q.filter(
239 self.SettingsDbModel.app_settings_name.startswith('auth_'))
240 self.SettingsDbModel.app_settings_name.startswith('auth_'))
240 rows = q.all()
241 rows = q.all()
241 auth_settings = {
242 auth_settings = {
242 row.app_settings_name: row.app_settings_value for row in rows}
243 row.app_settings_name: row.app_settings_value for row in rows}
243 return auth_settings
244 return auth_settings
244
245
245 def get_auth_plugins(self):
246 def get_auth_plugins(self):
246 auth_plugins = self.get_setting_by_name("auth_plugins")
247 auth_plugins = self.get_setting_by_name("auth_plugins")
247 return auth_plugins.app_settings_value
248 return auth_plugins.app_settings_value
248
249
249 def get_default_repo_settings(self, strip_prefix=False):
250 def get_default_repo_settings(self, strip_prefix=False):
250 q = self._get_settings_query()
251 q = self._get_settings_query()
251 q = q.filter(
252 q = q.filter(
252 self.SettingsDbModel.app_settings_name.startswith('default_'))
253 self.SettingsDbModel.app_settings_name.startswith('default_'))
253 rows = q.all()
254 rows = q.all()
254
255
255 result = {}
256 result = {}
256 for row in rows:
257 for row in rows:
257 key = row.app_settings_name
258 key = row.app_settings_name
258 if strip_prefix:
259 if strip_prefix:
259 key = remove_prefix(key, prefix='default_')
260 key = remove_prefix(key, prefix='default_')
260 result.update({key: row.app_settings_value})
261 result.update({key: row.app_settings_value})
261 return result
262 return result
262
263
263 def get_repo(self):
264 def get_repo(self):
264 repo = self._get_repo(self.repo)
265 repo = self._get_repo(self.repo)
265 if not repo:
266 if not repo:
266 raise Exception(
267 raise Exception(
267 'Repository `{}` cannot be found inside the database'.format(
268 'Repository `{}` cannot be found inside the database'.format(
268 self.repo))
269 self.repo))
269 return repo
270 return repo
270
271
271 def _filter_by_repo(self, model, query):
272 def _filter_by_repo(self, model, query):
272 if self.repo:
273 if self.repo:
273 repo = self.get_repo()
274 repo = self.get_repo()
274 query = query.filter(model.repository_id == repo.repo_id)
275 query = query.filter(model.repository_id == repo.repo_id)
275 return query
276 return query
276
277
277 def _get_hooks(self, query):
278 def _get_hooks(self, query):
278 query = query.filter(self.UiDbModel.ui_section == self.HOOKS_SECTION)
279 query = query.filter(self.UiDbModel.ui_section == self.HOOKS_SECTION)
279 query = self._filter_by_repo(RepoRhodeCodeUi, query)
280 query = self._filter_by_repo(RepoRhodeCodeUi, query)
280 return query.all()
281 return query.all()
281
282
282 def _get_settings_query(self):
283 def _get_settings_query(self):
283 q = self.SettingsDbModel.query()
284 q = self.SettingsDbModel.query()
284 return self._filter_by_repo(RepoRhodeCodeSetting, q)
285 return self._filter_by_repo(RepoRhodeCodeSetting, q)
285
286
286 def list_enabled_social_plugins(self, settings):
287 def list_enabled_social_plugins(self, settings):
287 enabled = []
288 enabled = []
288 for plug in SOCIAL_PLUGINS_LIST:
289 for plug in SOCIAL_PLUGINS_LIST:
289 if str2bool(settings.get('rhodecode_auth_{}_enabled'.format(plug)
290 if str2bool(settings.get('rhodecode_auth_{}_enabled'.format(plug)
290 )):
291 )):
291 enabled.append(plug)
292 enabled.append(plug)
292 return enabled
293 return enabled
293
294
294
295
295 def assert_repo_settings(func):
296 def assert_repo_settings(func):
296 @wraps(func)
297 @wraps(func)
297 def _wrapper(self, *args, **kwargs):
298 def _wrapper(self, *args, **kwargs):
298 if not self.repo_settings:
299 if not self.repo_settings:
299 raise Exception('Repository is not specified')
300 raise Exception('Repository is not specified')
300 return func(self, *args, **kwargs)
301 return func(self, *args, **kwargs)
301 return _wrapper
302 return _wrapper
302
303
303
304
304 class IssueTrackerSettingsModel(object):
305 class IssueTrackerSettingsModel(object):
305 INHERIT_SETTINGS = 'inherit_issue_tracker_settings'
306 INHERIT_SETTINGS = 'inherit_issue_tracker_settings'
306 SETTINGS_PREFIX = 'issuetracker_'
307 SETTINGS_PREFIX = 'issuetracker_'
307
308
308 def __init__(self, sa=None, repo=None):
309 def __init__(self, sa=None, repo=None):
309 self.global_settings = SettingsModel(sa=sa)
310 self.global_settings = SettingsModel(sa=sa)
310 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
311 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
311
312
312 @property
313 @property
313 def inherit_global_settings(self):
314 def inherit_global_settings(self):
314 if not self.repo_settings:
315 if not self.repo_settings:
315 return True
316 return True
316 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
317 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
317 return setting.app_settings_value if setting else True
318 return setting.app_settings_value if setting else True
318
319
319 @inherit_global_settings.setter
320 @inherit_global_settings.setter
320 def inherit_global_settings(self, value):
321 def inherit_global_settings(self, value):
321 if self.repo_settings:
322 if self.repo_settings:
322 settings = self.repo_settings.create_or_update_setting(
323 settings = self.repo_settings.create_or_update_setting(
323 self.INHERIT_SETTINGS, value, type_='bool')
324 self.INHERIT_SETTINGS, value, type_='bool')
324 Session().add(settings)
325 Session().add(settings)
325
326
326 def _get_keyname(self, key, uid, prefix=''):
327 def _get_keyname(self, key, uid, prefix=''):
327 return '{0}{1}{2}_{3}'.format(
328 return '{0}{1}{2}_{3}'.format(
328 prefix, self.SETTINGS_PREFIX, key, uid)
329 prefix, self.SETTINGS_PREFIX, key, uid)
329
330
330 def _make_dict_for_settings(self, qs):
331 def _make_dict_for_settings(self, qs):
331 prefix_match = self._get_keyname('pat', '', 'rhodecode_')
332 prefix_match = self._get_keyname('pat', '', 'rhodecode_')
332
333
333 issuetracker_entries = {}
334 issuetracker_entries = {}
334 # create keys
335 # create keys
335 for k, v in qs.items():
336 for k, v in qs.items():
336 if k.startswith(prefix_match):
337 if k.startswith(prefix_match):
337 uid = k[len(prefix_match):]
338 uid = k[len(prefix_match):]
338 issuetracker_entries[uid] = None
339 issuetracker_entries[uid] = None
339
340
340 # populate
341 # populate
341 for uid in issuetracker_entries:
342 for uid in issuetracker_entries:
342 issuetracker_entries[uid] = AttributeDict({
343 issuetracker_entries[uid] = AttributeDict({
343 'pat': qs.get(self._get_keyname('pat', uid, 'rhodecode_')),
344 'pat': qs.get(self._get_keyname('pat', uid, 'rhodecode_')),
344 'url': qs.get(self._get_keyname('url', uid, 'rhodecode_')),
345 'url': qs.get(self._get_keyname('url', uid, 'rhodecode_')),
345 'pref': qs.get(self._get_keyname('pref', uid, 'rhodecode_')),
346 'pref': qs.get(self._get_keyname('pref', uid, 'rhodecode_')),
346 'desc': qs.get(self._get_keyname('desc', uid, 'rhodecode_')),
347 'desc': qs.get(self._get_keyname('desc', uid, 'rhodecode_')),
347 })
348 })
348 return issuetracker_entries
349 return issuetracker_entries
349
350
350 def get_global_settings(self, cache=False):
351 def get_global_settings(self, cache=False):
351 """
352 """
352 Returns list of global issue tracker settings
353 Returns list of global issue tracker settings
353 """
354 """
354 defaults = self.global_settings.get_all_settings(cache=cache)
355 defaults = self.global_settings.get_all_settings(cache=cache)
355 settings = self._make_dict_for_settings(defaults)
356 settings = self._make_dict_for_settings(defaults)
356 return settings
357 return settings
357
358
358 def get_repo_settings(self, cache=False):
359 def get_repo_settings(self, cache=False):
359 """
360 """
360 Returns list of issue tracker settings per repository
361 Returns list of issue tracker settings per repository
361 """
362 """
362 if not self.repo_settings:
363 if not self.repo_settings:
363 raise Exception('Repository is not specified')
364 raise Exception('Repository is not specified')
364 all_settings = self.repo_settings.get_all_settings(cache=cache)
365 all_settings = self.repo_settings.get_all_settings(cache=cache)
365 settings = self._make_dict_for_settings(all_settings)
366 settings = self._make_dict_for_settings(all_settings)
366 return settings
367 return settings
367
368
368 def get_settings(self, cache=False):
369 def get_settings(self, cache=False):
369 if self.inherit_global_settings:
370 if self.inherit_global_settings:
370 return self.get_global_settings(cache=cache)
371 return self.get_global_settings(cache=cache)
371 else:
372 else:
372 return self.get_repo_settings(cache=cache)
373 return self.get_repo_settings(cache=cache)
373
374
374 def delete_entries(self, uid):
375 def delete_entries(self, uid):
375 if self.repo_settings:
376 if self.repo_settings:
376 all_patterns = self.get_repo_settings()
377 all_patterns = self.get_repo_settings()
377 settings_model = self.repo_settings
378 settings_model = self.repo_settings
378 else:
379 else:
379 all_patterns = self.get_global_settings()
380 all_patterns = self.get_global_settings()
380 settings_model = self.global_settings
381 settings_model = self.global_settings
381 entries = all_patterns.get(uid)
382 entries = all_patterns.get(uid)
382
383
383 for del_key in entries:
384 for del_key in entries:
384 setting_name = self._get_keyname(del_key, uid)
385 setting_name = self._get_keyname(del_key, uid)
385 entry = settings_model.get_setting_by_name(setting_name)
386 entry = settings_model.get_setting_by_name(setting_name)
386 if entry:
387 if entry:
387 Session().delete(entry)
388 Session().delete(entry)
388
389
389 Session().commit()
390 Session().commit()
390
391
391 def create_or_update_setting(
392 def create_or_update_setting(
392 self, name, val=Optional(''), type_=Optional('unicode')):
393 self, name, val=Optional(''), type_=Optional('unicode')):
393 if self.repo_settings:
394 if self.repo_settings:
394 setting = self.repo_settings.create_or_update_setting(
395 setting = self.repo_settings.create_or_update_setting(
395 name, val, type_)
396 name, val, type_)
396 else:
397 else:
397 setting = self.global_settings.create_or_update_setting(
398 setting = self.global_settings.create_or_update_setting(
398 name, val, type_)
399 name, val, type_)
399 return setting
400 return setting
400
401
401
402
402 class VcsSettingsModel(object):
403 class VcsSettingsModel(object):
403
404
404 INHERIT_SETTINGS = 'inherit_vcs_settings'
405 INHERIT_SETTINGS = 'inherit_vcs_settings'
405 GENERAL_SETTINGS = (
406 GENERAL_SETTINGS = (
406 'use_outdated_comments',
407 'use_outdated_comments',
407 'pr_merge_enabled',
408 'pr_merge_enabled',
408 'hg_use_rebase_for_merging')
409 'hg_use_rebase_for_merging')
409
410
410 HOOKS_SETTINGS = (
411 HOOKS_SETTINGS = (
411 ('hooks', 'changegroup.repo_size'),
412 ('hooks', 'changegroup.repo_size'),
412 ('hooks', 'changegroup.push_logger'),
413 ('hooks', 'changegroup.push_logger'),
413 ('hooks', 'outgoing.pull_logger'),)
414 ('hooks', 'outgoing.pull_logger'),)
414 HG_SETTINGS = (
415 HG_SETTINGS = (
415 ('extensions', 'largefiles'),
416 ('extensions', 'largefiles'),
416 ('phases', 'publish'),)
417 ('phases', 'publish'),)
417 GIT_SETTINGS = (
418 GIT_SETTINGS = (
418 ('vcs_git_lfs', 'enabled'),)
419 ('vcs_git_lfs', 'enabled'),)
419
420
420 GLOBAL_HG_SETTINGS = (
421 GLOBAL_HG_SETTINGS = (
421 ('extensions', 'largefiles'),
422 ('extensions', 'largefiles'),
422 ('largefiles', 'usercache'),
423 ('largefiles', 'usercache'),
423 ('phases', 'publish'),
424 ('phases', 'publish'),
424 ('extensions', 'hgsubversion'))
425 ('extensions', 'hgsubversion'))
425 GLOBAL_GIT_SETTINGS = (
426 GLOBAL_GIT_SETTINGS = (
426 ('vcs_git_lfs', 'enabled'),
427 ('vcs_git_lfs', 'enabled'),
427 ('vcs_git_lfs', 'store_location'))
428 ('vcs_git_lfs', 'store_location'))
428 GLOBAL_SVN_SETTINGS = (
429 GLOBAL_SVN_SETTINGS = (
429 ('vcs_svn_proxy', 'http_requests_enabled'),
430 ('vcs_svn_proxy', 'http_requests_enabled'),
430 ('vcs_svn_proxy', 'http_server_url'))
431 ('vcs_svn_proxy', 'http_server_url'))
431
432
432 SVN_BRANCH_SECTION = 'vcs_svn_branch'
433 SVN_BRANCH_SECTION = 'vcs_svn_branch'
433 SVN_TAG_SECTION = 'vcs_svn_tag'
434 SVN_TAG_SECTION = 'vcs_svn_tag'
434 SSL_SETTING = ('web', 'push_ssl')
435 SSL_SETTING = ('web', 'push_ssl')
435 PATH_SETTING = ('paths', '/')
436 PATH_SETTING = ('paths', '/')
436
437
437 def __init__(self, sa=None, repo=None):
438 def __init__(self, sa=None, repo=None):
438 self.global_settings = SettingsModel(sa=sa)
439 self.global_settings = SettingsModel(sa=sa)
439 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
440 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
440 self._ui_settings = (
441 self._ui_settings = (
441 self.HG_SETTINGS + self.GIT_SETTINGS + self.HOOKS_SETTINGS)
442 self.HG_SETTINGS + self.GIT_SETTINGS + self.HOOKS_SETTINGS)
442 self._svn_sections = (self.SVN_BRANCH_SECTION, self.SVN_TAG_SECTION)
443 self._svn_sections = (self.SVN_BRANCH_SECTION, self.SVN_TAG_SECTION)
443
444
444 @property
445 @property
445 @assert_repo_settings
446 @assert_repo_settings
446 def inherit_global_settings(self):
447 def inherit_global_settings(self):
447 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
448 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
448 return setting.app_settings_value if setting else True
449 return setting.app_settings_value if setting else True
449
450
450 @inherit_global_settings.setter
451 @inherit_global_settings.setter
451 @assert_repo_settings
452 @assert_repo_settings
452 def inherit_global_settings(self, value):
453 def inherit_global_settings(self, value):
453 self.repo_settings.create_or_update_setting(
454 self.repo_settings.create_or_update_setting(
454 self.INHERIT_SETTINGS, value, type_='bool')
455 self.INHERIT_SETTINGS, value, type_='bool')
455
456
456 def get_global_svn_branch_patterns(self):
457 def get_global_svn_branch_patterns(self):
457 return self.global_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
458 return self.global_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
458
459
459 @assert_repo_settings
460 @assert_repo_settings
460 def get_repo_svn_branch_patterns(self):
461 def get_repo_svn_branch_patterns(self):
461 return self.repo_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
462 return self.repo_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
462
463
463 def get_global_svn_tag_patterns(self):
464 def get_global_svn_tag_patterns(self):
464 return self.global_settings.get_ui_by_section(self.SVN_TAG_SECTION)
465 return self.global_settings.get_ui_by_section(self.SVN_TAG_SECTION)
465
466
466 @assert_repo_settings
467 @assert_repo_settings
467 def get_repo_svn_tag_patterns(self):
468 def get_repo_svn_tag_patterns(self):
468 return self.repo_settings.get_ui_by_section(self.SVN_TAG_SECTION)
469 return self.repo_settings.get_ui_by_section(self.SVN_TAG_SECTION)
469
470
470 def get_global_settings(self):
471 def get_global_settings(self):
471 return self._collect_all_settings(global_=True)
472 return self._collect_all_settings(global_=True)
472
473
473 @assert_repo_settings
474 @assert_repo_settings
474 def get_repo_settings(self):
475 def get_repo_settings(self):
475 return self._collect_all_settings(global_=False)
476 return self._collect_all_settings(global_=False)
476
477
477 @assert_repo_settings
478 @assert_repo_settings
478 def create_or_update_repo_settings(
479 def create_or_update_repo_settings(
479 self, data, inherit_global_settings=False):
480 self, data, inherit_global_settings=False):
480 from rhodecode.model.scm import ScmModel
481 from rhodecode.model.scm import ScmModel
481
482
482 self.inherit_global_settings = inherit_global_settings
483 self.inherit_global_settings = inherit_global_settings
483
484
484 repo = self.repo_settings.get_repo()
485 repo = self.repo_settings.get_repo()
485 if not inherit_global_settings:
486 if not inherit_global_settings:
486 if repo.repo_type == 'svn':
487 if repo.repo_type == 'svn':
487 self.create_repo_svn_settings(data)
488 self.create_repo_svn_settings(data)
488 else:
489 else:
489 self.create_or_update_repo_hook_settings(data)
490 self.create_or_update_repo_hook_settings(data)
490 self.create_or_update_repo_pr_settings(data)
491 self.create_or_update_repo_pr_settings(data)
491
492
492 if repo.repo_type == 'hg':
493 if repo.repo_type == 'hg':
493 self.create_or_update_repo_hg_settings(data)
494 self.create_or_update_repo_hg_settings(data)
494
495
495 if repo.repo_type == 'git':
496 if repo.repo_type == 'git':
496 self.create_or_update_repo_git_settings(data)
497 self.create_or_update_repo_git_settings(data)
497
498
498 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
499 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
499
500
500 @assert_repo_settings
501 @assert_repo_settings
501 def create_or_update_repo_hook_settings(self, data):
502 def create_or_update_repo_hook_settings(self, data):
502 for section, key in self.HOOKS_SETTINGS:
503 for section, key in self.HOOKS_SETTINGS:
503 data_key = self._get_form_ui_key(section, key)
504 data_key = self._get_form_ui_key(section, key)
504 if data_key not in data:
505 if data_key not in data:
505 raise ValueError(
506 raise ValueError(
506 'The given data does not contain {} key'.format(data_key))
507 'The given data does not contain {} key'.format(data_key))
507
508
508 active = data.get(data_key)
509 active = data.get(data_key)
509 repo_setting = self.repo_settings.get_ui_by_section_and_key(
510 repo_setting = self.repo_settings.get_ui_by_section_and_key(
510 section, key)
511 section, key)
511 if not repo_setting:
512 if not repo_setting:
512 global_setting = self.global_settings.\
513 global_setting = self.global_settings.\
513 get_ui_by_section_and_key(section, key)
514 get_ui_by_section_and_key(section, key)
514 self.repo_settings.create_ui_section_value(
515 self.repo_settings.create_ui_section_value(
515 section, global_setting.ui_value, key=key, active=active)
516 section, global_setting.ui_value, key=key, active=active)
516 else:
517 else:
517 repo_setting.ui_active = active
518 repo_setting.ui_active = active
518 Session().add(repo_setting)
519 Session().add(repo_setting)
519
520
520 def update_global_hook_settings(self, data):
521 def update_global_hook_settings(self, data):
521 for section, key in self.HOOKS_SETTINGS:
522 for section, key in self.HOOKS_SETTINGS:
522 data_key = self._get_form_ui_key(section, key)
523 data_key = self._get_form_ui_key(section, key)
523 if data_key not in data:
524 if data_key not in data:
524 raise ValueError(
525 raise ValueError(
525 'The given data does not contain {} key'.format(data_key))
526 'The given data does not contain {} key'.format(data_key))
526 active = data.get(data_key)
527 active = data.get(data_key)
527 repo_setting = self.global_settings.get_ui_by_section_and_key(
528 repo_setting = self.global_settings.get_ui_by_section_and_key(
528 section, key)
529 section, key)
529 repo_setting.ui_active = active
530 repo_setting.ui_active = active
530 Session().add(repo_setting)
531 Session().add(repo_setting)
531
532
532 @assert_repo_settings
533 @assert_repo_settings
533 def create_or_update_repo_pr_settings(self, data):
534 def create_or_update_repo_pr_settings(self, data):
534 return self._create_or_update_general_settings(
535 return self._create_or_update_general_settings(
535 self.repo_settings, data)
536 self.repo_settings, data)
536
537
537 def create_or_update_global_pr_settings(self, data):
538 def create_or_update_global_pr_settings(self, data):
538 return self._create_or_update_general_settings(
539 return self._create_or_update_general_settings(
539 self.global_settings, data)
540 self.global_settings, data)
540
541
541 @assert_repo_settings
542 @assert_repo_settings
542 def create_repo_svn_settings(self, data):
543 def create_repo_svn_settings(self, data):
543 return self._create_svn_settings(self.repo_settings, data)
544 return self._create_svn_settings(self.repo_settings, data)
544
545
545 @assert_repo_settings
546 @assert_repo_settings
546 def create_or_update_repo_hg_settings(self, data):
547 def create_or_update_repo_hg_settings(self, data):
547 largefiles, phases = \
548 largefiles, phases = \
548 self.HG_SETTINGS
549 self.HG_SETTINGS
549 largefiles_key, phases_key = \
550 largefiles_key, phases_key = \
550 self._get_settings_keys(self.HG_SETTINGS, data)
551 self._get_settings_keys(self.HG_SETTINGS, data)
551
552
552 self._create_or_update_ui(
553 self._create_or_update_ui(
553 self.repo_settings, *largefiles, value='',
554 self.repo_settings, *largefiles, value='',
554 active=data[largefiles_key])
555 active=data[largefiles_key])
555 self._create_or_update_ui(
556 self._create_or_update_ui(
556 self.repo_settings, *phases, value=safe_str(data[phases_key]))
557 self.repo_settings, *phases, value=safe_str(data[phases_key]))
557
558
558 def create_or_update_global_hg_settings(self, data):
559 def create_or_update_global_hg_settings(self, data):
559 largefiles, largefiles_store, phases, hgsubversion \
560 largefiles, largefiles_store, phases, hgsubversion \
560 = self.GLOBAL_HG_SETTINGS
561 = self.GLOBAL_HG_SETTINGS
561 largefiles_key, largefiles_store_key, phases_key, subversion_key \
562 largefiles_key, largefiles_store_key, phases_key, subversion_key \
562 = self._get_settings_keys(self.GLOBAL_HG_SETTINGS, data)
563 = self._get_settings_keys(self.GLOBAL_HG_SETTINGS, data)
563 self._create_or_update_ui(
564 self._create_or_update_ui(
564 self.global_settings, *largefiles, value='',
565 self.global_settings, *largefiles, value='',
565 active=data[largefiles_key])
566 active=data[largefiles_key])
566 self._create_or_update_ui(
567 self._create_or_update_ui(
567 self.global_settings, *largefiles_store,
568 self.global_settings, *largefiles_store,
568 value=data[largefiles_store_key])
569 value=data[largefiles_store_key])
569 self._create_or_update_ui(
570 self._create_or_update_ui(
570 self.global_settings, *phases, value=safe_str(data[phases_key]))
571 self.global_settings, *phases, value=safe_str(data[phases_key]))
571 self._create_or_update_ui(
572 self._create_or_update_ui(
572 self.global_settings, *hgsubversion, active=data[subversion_key])
573 self.global_settings, *hgsubversion, active=data[subversion_key])
573
574
574 def create_or_update_repo_git_settings(self, data):
575 def create_or_update_repo_git_settings(self, data):
575 # NOTE(marcink): # comma make unpack work properly
576 # NOTE(marcink): # comma make unpack work properly
576 lfs_enabled, \
577 lfs_enabled, \
577 = self.GIT_SETTINGS
578 = self.GIT_SETTINGS
578
579
579 lfs_enabled_key, \
580 lfs_enabled_key, \
580 = self._get_settings_keys(self.GIT_SETTINGS, data)
581 = self._get_settings_keys(self.GIT_SETTINGS, data)
581
582
582 self._create_or_update_ui(
583 self._create_or_update_ui(
583 self.repo_settings, *lfs_enabled, value=data[lfs_enabled_key],
584 self.repo_settings, *lfs_enabled, value=data[lfs_enabled_key],
584 active=data[lfs_enabled_key])
585 active=data[lfs_enabled_key])
585
586
586 def create_or_update_global_git_settings(self, data):
587 def create_or_update_global_git_settings(self, data):
587 lfs_enabled, lfs_store_location \
588 lfs_enabled, lfs_store_location \
588 = self.GLOBAL_GIT_SETTINGS
589 = self.GLOBAL_GIT_SETTINGS
589 lfs_enabled_key, lfs_store_location_key \
590 lfs_enabled_key, lfs_store_location_key \
590 = self._get_settings_keys(self.GLOBAL_GIT_SETTINGS, data)
591 = self._get_settings_keys(self.GLOBAL_GIT_SETTINGS, data)
591
592
592 self._create_or_update_ui(
593 self._create_or_update_ui(
593 self.global_settings, *lfs_enabled, value=data[lfs_enabled_key],
594 self.global_settings, *lfs_enabled, value=data[lfs_enabled_key],
594 active=data[lfs_enabled_key])
595 active=data[lfs_enabled_key])
595 self._create_or_update_ui(
596 self._create_or_update_ui(
596 self.global_settings, *lfs_store_location,
597 self.global_settings, *lfs_store_location,
597 value=data[lfs_store_location_key])
598 value=data[lfs_store_location_key])
598
599
599 def create_or_update_global_svn_settings(self, data):
600 def create_or_update_global_svn_settings(self, data):
600 # branch/tags patterns
601 # branch/tags patterns
601 self._create_svn_settings(self.global_settings, data)
602 self._create_svn_settings(self.global_settings, data)
602
603
603 http_requests_enabled, http_server_url = self.GLOBAL_SVN_SETTINGS
604 http_requests_enabled, http_server_url = self.GLOBAL_SVN_SETTINGS
604 http_requests_enabled_key, http_server_url_key = self._get_settings_keys(
605 http_requests_enabled_key, http_server_url_key = self._get_settings_keys(
605 self.GLOBAL_SVN_SETTINGS, data)
606 self.GLOBAL_SVN_SETTINGS, data)
606
607
607 self._create_or_update_ui(
608 self._create_or_update_ui(
608 self.global_settings, *http_requests_enabled,
609 self.global_settings, *http_requests_enabled,
609 value=safe_str(data[http_requests_enabled_key]))
610 value=safe_str(data[http_requests_enabled_key]))
610 self._create_or_update_ui(
611 self._create_or_update_ui(
611 self.global_settings, *http_server_url,
612 self.global_settings, *http_server_url,
612 value=data[http_server_url_key])
613 value=data[http_server_url_key])
613
614
614 def update_global_ssl_setting(self, value):
615 def update_global_ssl_setting(self, value):
615 self._create_or_update_ui(
616 self._create_or_update_ui(
616 self.global_settings, *self.SSL_SETTING, value=value)
617 self.global_settings, *self.SSL_SETTING, value=value)
617
618
618 def update_global_path_setting(self, value):
619 def update_global_path_setting(self, value):
619 self._create_or_update_ui(
620 self._create_or_update_ui(
620 self.global_settings, *self.PATH_SETTING, value=value)
621 self.global_settings, *self.PATH_SETTING, value=value)
621
622
622 @assert_repo_settings
623 @assert_repo_settings
623 def delete_repo_svn_pattern(self, id_):
624 def delete_repo_svn_pattern(self, id_):
624 self.repo_settings.delete_ui(id_)
625 self.repo_settings.delete_ui(id_)
625
626
626 def delete_global_svn_pattern(self, id_):
627 def delete_global_svn_pattern(self, id_):
627 self.global_settings.delete_ui(id_)
628 self.global_settings.delete_ui(id_)
628
629
629 @assert_repo_settings
630 @assert_repo_settings
630 def get_repo_ui_settings(self, section=None, key=None):
631 def get_repo_ui_settings(self, section=None, key=None):
631 global_uis = self.global_settings.get_ui(section, key)
632 global_uis = self.global_settings.get_ui(section, key)
632 repo_uis = self.repo_settings.get_ui(section, key)
633 repo_uis = self.repo_settings.get_ui(section, key)
633 filtered_repo_uis = self._filter_ui_settings(repo_uis)
634 filtered_repo_uis = self._filter_ui_settings(repo_uis)
634 filtered_repo_uis_keys = [
635 filtered_repo_uis_keys = [
635 (s.section, s.key) for s in filtered_repo_uis]
636 (s.section, s.key) for s in filtered_repo_uis]
636
637
637 def _is_global_ui_filtered(ui):
638 def _is_global_ui_filtered(ui):
638 return (
639 return (
639 (ui.section, ui.key) in filtered_repo_uis_keys
640 (ui.section, ui.key) in filtered_repo_uis_keys
640 or ui.section in self._svn_sections)
641 or ui.section in self._svn_sections)
641
642
642 filtered_global_uis = [
643 filtered_global_uis = [
643 ui for ui in global_uis if not _is_global_ui_filtered(ui)]
644 ui for ui in global_uis if not _is_global_ui_filtered(ui)]
644
645
645 return filtered_global_uis + filtered_repo_uis
646 return filtered_global_uis + filtered_repo_uis
646
647
647 def get_global_ui_settings(self, section=None, key=None):
648 def get_global_ui_settings(self, section=None, key=None):
648 return self.global_settings.get_ui(section, key)
649 return self.global_settings.get_ui(section, key)
649
650
650 def get_ui_settings_as_config_obj(self, section=None, key=None):
651 def get_ui_settings_as_config_obj(self, section=None, key=None):
651 config = base.Config()
652 config = base.Config()
652
653
653 ui_settings = self.get_ui_settings(section=section, key=key)
654 ui_settings = self.get_ui_settings(section=section, key=key)
654
655
655 for entry in ui_settings:
656 for entry in ui_settings:
656 config.set(entry.section, entry.key, entry.value)
657 config.set(entry.section, entry.key, entry.value)
657
658
658 return config
659 return config
659
660
660 def get_ui_settings(self, section=None, key=None):
661 def get_ui_settings(self, section=None, key=None):
661 if not self.repo_settings or self.inherit_global_settings:
662 if not self.repo_settings or self.inherit_global_settings:
662 return self.get_global_ui_settings(section, key)
663 return self.get_global_ui_settings(section, key)
663 else:
664 else:
664 return self.get_repo_ui_settings(section, key)
665 return self.get_repo_ui_settings(section, key)
665
666
666 def get_svn_patterns(self, section=None):
667 def get_svn_patterns(self, section=None):
667 if not self.repo_settings:
668 if not self.repo_settings:
668 return self.get_global_ui_settings(section)
669 return self.get_global_ui_settings(section)
669 else:
670 else:
670 return self.get_repo_ui_settings(section)
671 return self.get_repo_ui_settings(section)
671
672
672 @assert_repo_settings
673 @assert_repo_settings
673 def get_repo_general_settings(self):
674 def get_repo_general_settings(self):
674 global_settings = self.global_settings.get_all_settings()
675 global_settings = self.global_settings.get_all_settings()
675 repo_settings = self.repo_settings.get_all_settings()
676 repo_settings = self.repo_settings.get_all_settings()
676 filtered_repo_settings = self._filter_general_settings(repo_settings)
677 filtered_repo_settings = self._filter_general_settings(repo_settings)
677 global_settings.update(filtered_repo_settings)
678 global_settings.update(filtered_repo_settings)
678 return global_settings
679 return global_settings
679
680
680 def get_global_general_settings(self):
681 def get_global_general_settings(self):
681 return self.global_settings.get_all_settings()
682 return self.global_settings.get_all_settings()
682
683
683 def get_general_settings(self):
684 def get_general_settings(self):
684 if not self.repo_settings or self.inherit_global_settings:
685 if not self.repo_settings or self.inherit_global_settings:
685 return self.get_global_general_settings()
686 return self.get_global_general_settings()
686 else:
687 else:
687 return self.get_repo_general_settings()
688 return self.get_repo_general_settings()
688
689
689 def get_repos_location(self):
690 def get_repos_location(self):
690 return self.global_settings.get_ui_by_key('/').ui_value
691 return self.global_settings.get_ui_by_key('/').ui_value
691
692
692 def _filter_ui_settings(self, settings):
693 def _filter_ui_settings(self, settings):
693 filtered_settings = [
694 filtered_settings = [
694 s for s in settings if self._should_keep_setting(s)]
695 s for s in settings if self._should_keep_setting(s)]
695 return filtered_settings
696 return filtered_settings
696
697
697 def _should_keep_setting(self, setting):
698 def _should_keep_setting(self, setting):
698 keep = (
699 keep = (
699 (setting.section, setting.key) in self._ui_settings or
700 (setting.section, setting.key) in self._ui_settings or
700 setting.section in self._svn_sections)
701 setting.section in self._svn_sections)
701 return keep
702 return keep
702
703
703 def _filter_general_settings(self, settings):
704 def _filter_general_settings(self, settings):
704 keys = ['rhodecode_{}'.format(key) for key in self.GENERAL_SETTINGS]
705 keys = ['rhodecode_{}'.format(key) for key in self.GENERAL_SETTINGS]
705 return {
706 return {
706 k: settings[k]
707 k: settings[k]
707 for k in settings if k in keys}
708 for k in settings if k in keys}
708
709
709 def _collect_all_settings(self, global_=False):
710 def _collect_all_settings(self, global_=False):
710 settings = self.global_settings if global_ else self.repo_settings
711 settings = self.global_settings if global_ else self.repo_settings
711 result = {}
712 result = {}
712
713
713 for section, key in self._ui_settings:
714 for section, key in self._ui_settings:
714 ui = settings.get_ui_by_section_and_key(section, key)
715 ui = settings.get_ui_by_section_and_key(section, key)
715 result_key = self._get_form_ui_key(section, key)
716 result_key = self._get_form_ui_key(section, key)
716
717
717 if ui:
718 if ui:
718 if section in ('hooks', 'extensions'):
719 if section in ('hooks', 'extensions'):
719 result[result_key] = ui.ui_active
720 result[result_key] = ui.ui_active
720 elif result_key in ['vcs_git_lfs_enabled']:
721 elif result_key in ['vcs_git_lfs_enabled']:
721 result[result_key] = ui.ui_active
722 result[result_key] = ui.ui_active
722 else:
723 else:
723 result[result_key] = ui.ui_value
724 result[result_key] = ui.ui_value
724
725
725 for name in self.GENERAL_SETTINGS:
726 for name in self.GENERAL_SETTINGS:
726 setting = settings.get_setting_by_name(name)
727 setting = settings.get_setting_by_name(name)
727 if setting:
728 if setting:
728 result_key = 'rhodecode_{}'.format(name)
729 result_key = 'rhodecode_{}'.format(name)
729 result[result_key] = setting.app_settings_value
730 result[result_key] = setting.app_settings_value
730
731
731 return result
732 return result
732
733
733 def _get_form_ui_key(self, section, key):
734 def _get_form_ui_key(self, section, key):
734 return '{section}_{key}'.format(
735 return '{section}_{key}'.format(
735 section=section, key=key.replace('.', '_'))
736 section=section, key=key.replace('.', '_'))
736
737
737 def _create_or_update_ui(
738 def _create_or_update_ui(
738 self, settings, section, key, value=None, active=None):
739 self, settings, section, key, value=None, active=None):
739 ui = settings.get_ui_by_section_and_key(section, key)
740 ui = settings.get_ui_by_section_and_key(section, key)
740 if not ui:
741 if not ui:
741 active = True if active is None else active
742 active = True if active is None else active
742 settings.create_ui_section_value(
743 settings.create_ui_section_value(
743 section, value, key=key, active=active)
744 section, value, key=key, active=active)
744 else:
745 else:
745 if active is not None:
746 if active is not None:
746 ui.ui_active = active
747 ui.ui_active = active
747 if value is not None:
748 if value is not None:
748 ui.ui_value = value
749 ui.ui_value = value
749 Session().add(ui)
750 Session().add(ui)
750
751
751 def _create_svn_settings(self, settings, data):
752 def _create_svn_settings(self, settings, data):
752 svn_settings = {
753 svn_settings = {
753 'new_svn_branch': self.SVN_BRANCH_SECTION,
754 'new_svn_branch': self.SVN_BRANCH_SECTION,
754 'new_svn_tag': self.SVN_TAG_SECTION
755 'new_svn_tag': self.SVN_TAG_SECTION
755 }
756 }
756 for key in svn_settings:
757 for key in svn_settings:
757 if data.get(key):
758 if data.get(key):
758 settings.create_ui_section_value(svn_settings[key], data[key])
759 settings.create_ui_section_value(svn_settings[key], data[key])
759
760
760 def _create_or_update_general_settings(self, settings, data):
761 def _create_or_update_general_settings(self, settings, data):
761 for name in self.GENERAL_SETTINGS:
762 for name in self.GENERAL_SETTINGS:
762 data_key = 'rhodecode_{}'.format(name)
763 data_key = 'rhodecode_{}'.format(name)
763 if data_key not in data:
764 if data_key not in data:
764 raise ValueError(
765 raise ValueError(
765 'The given data does not contain {} key'.format(data_key))
766 'The given data does not contain {} key'.format(data_key))
766 setting = settings.create_or_update_setting(
767 setting = settings.create_or_update_setting(
767 name, data[data_key], 'bool')
768 name, data[data_key], 'bool')
768 Session().add(setting)
769 Session().add(setting)
769
770
770 def _get_settings_keys(self, settings, data):
771 def _get_settings_keys(self, settings, data):
771 data_keys = [self._get_form_ui_key(*s) for s in settings]
772 data_keys = [self._get_form_ui_key(*s) for s in settings]
772 for data_key in data_keys:
773 for data_key in data_keys:
773 if data_key not in data:
774 if data_key not in data:
774 raise ValueError(
775 raise ValueError(
775 'The given data does not contain {} key'.format(data_key))
776 'The given data does not contain {} key'.format(data_key))
776 return data_keys
777 return data_keys
@@ -1,113 +1,114 b''
1
1
2 /******************************************************************************
2 /******************************************************************************
3 * *
3 * *
4 * DO NOT CHANGE THIS FILE MANUALLY *
4 * DO NOT CHANGE THIS FILE MANUALLY *
5 * *
5 * *
6 * *
6 * *
7 * This file is automatically generated when the app starts up with *
7 * This file is automatically generated when the app starts up with *
8 * generate_js_files = true *
8 * generate_js_files = true *
9 * *
9 * *
10 * To add a route here pass jsroute=True to the route definition in the app *
10 * To add a route here pass jsroute=True to the route definition in the app *
11 * *
11 * *
12 ******************************************************************************/
12 ******************************************************************************/
13 function registerRCRoutes() {
13 function registerRCRoutes() {
14 // routes registration
14 // routes registration
15 pyroutes.register('home', '/', []);
15 pyroutes.register('home', '/', []);
16 pyroutes.register('new_repo', '/_admin/create_repository', []);
16 pyroutes.register('new_repo', '/_admin/create_repository', []);
17 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
17 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
18 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
18 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
19 pyroutes.register('gists', '/_admin/gists', []);
19 pyroutes.register('gists', '/_admin/gists', []);
20 pyroutes.register('new_gist', '/_admin/gists/new', []);
20 pyroutes.register('new_gist', '/_admin/gists/new', []);
21 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
21 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
22 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
22 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
23 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
23 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
24 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
24 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
25 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/default-reviewers', ['repo_name']);
25 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/default-reviewers', ['repo_name']);
26 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
26 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
27 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
27 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
28 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
28 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
29 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
29 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
30 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
30 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
31 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
31 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
32 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
32 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
33 pyroutes.register('compare_url', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
33 pyroutes.register('compare_url', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
34 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
34 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
35 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
35 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
36 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
36 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
37 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
37 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
38 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
38 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
39 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
39 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
40 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
40 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
41 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
41 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
42 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
42 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
43 pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
43 pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
44 pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
44 pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
45 pyroutes.register('changelog_elements', '/%(repo_name)s/changelog_details', ['repo_name']);
45 pyroutes.register('changelog_elements', '/%(repo_name)s/changelog_details', ['repo_name']);
46 pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
46 pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
47 pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
47 pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
48 pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
48 pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
49 pyroutes.register('files_annotate_home', '/%(repo_name)s/annotate/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
49 pyroutes.register('files_annotate_home', '/%(repo_name)s/annotate/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
50 pyroutes.register('files_annotate_previous', '/%(repo_name)s/annotate-previous/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
50 pyroutes.register('files_annotate_previous', '/%(repo_name)s/annotate-previous/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
51 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
51 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
52 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
52 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
53 pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
53 pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
54 pyroutes.register('summary_home_slash', '/%(repo_name)s/', ['repo_name']);
54 pyroutes.register('summary_home_slash', '/%(repo_name)s/', ['repo_name']);
55 pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
55 pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
56 pyroutes.register('favicon', '/favicon.ico', []);
56 pyroutes.register('favicon', '/favicon.ico', []);
57 pyroutes.register('robots', '/robots.txt', []);
57 pyroutes.register('robots', '/robots.txt', []);
58 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
58 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
59 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
59 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
60 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
60 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
61 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
61 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
62 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
62 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
63 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
63 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
64 pyroutes.register('repo_group_integrations_home', '%(repo_group_name)s/settings/integrations', ['repo_group_name']);
64 pyroutes.register('repo_group_integrations_home', '%(repo_group_name)s/settings/integrations', ['repo_group_name']);
65 pyroutes.register('repo_group_integrations_list', '%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
65 pyroutes.register('repo_group_integrations_list', '%(repo_group_name)s/settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
66 pyroutes.register('repo_group_integrations_new', '%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
66 pyroutes.register('repo_group_integrations_new', '%(repo_group_name)s/settings/integrations/new', ['repo_group_name']);
67 pyroutes.register('repo_group_integrations_create', '%(repo_group_name)s/settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
67 pyroutes.register('repo_group_integrations_create', '%(repo_group_name)s/settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
68 pyroutes.register('repo_group_integrations_edit', '%(repo_group_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
68 pyroutes.register('repo_group_integrations_edit', '%(repo_group_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
69 pyroutes.register('repo_integrations_home', '%(repo_name)s/settings/integrations', ['repo_name']);
69 pyroutes.register('repo_integrations_home', '%(repo_name)s/settings/integrations', ['repo_name']);
70 pyroutes.register('repo_integrations_list', '%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
70 pyroutes.register('repo_integrations_list', '%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
71 pyroutes.register('repo_integrations_new', '%(repo_name)s/settings/integrations/new', ['repo_name']);
71 pyroutes.register('repo_integrations_new', '%(repo_name)s/settings/integrations/new', ['repo_name']);
72 pyroutes.register('repo_integrations_create', '%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
72 pyroutes.register('repo_integrations_create', '%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
73 pyroutes.register('repo_integrations_edit', '%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
73 pyroutes.register('repo_integrations_edit', '%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
74 pyroutes.register('ops_ping', '_admin/ops/ping', []);
74 pyroutes.register('admin_settings_open_source', '_admin/settings/open_source', []);
75 pyroutes.register('admin_settings_open_source', '_admin/settings/open_source', []);
75 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '_admin/settings/vcs/svn_generate_cfg', []);
76 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '_admin/settings/vcs/svn_generate_cfg', []);
76 pyroutes.register('admin_settings_system', '_admin/settings/system', []);
77 pyroutes.register('admin_settings_system', '_admin/settings/system', []);
77 pyroutes.register('admin_settings_system_update', '_admin/settings/system/updates', []);
78 pyroutes.register('admin_settings_system_update', '_admin/settings/system/updates', []);
78 pyroutes.register('admin_settings_sessions', '_admin/settings/sessions', []);
79 pyroutes.register('admin_settings_sessions', '_admin/settings/sessions', []);
79 pyroutes.register('admin_settings_sessions_cleanup', '_admin/settings/sessions/cleanup', []);
80 pyroutes.register('admin_settings_sessions_cleanup', '_admin/settings/sessions/cleanup', []);
80 pyroutes.register('users', '_admin/users', []);
81 pyroutes.register('users', '_admin/users', []);
81 pyroutes.register('users_data', '_admin/users_data', []);
82 pyroutes.register('users_data', '_admin/users_data', []);
82 pyroutes.register('edit_user_auth_tokens', '_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
83 pyroutes.register('edit_user_auth_tokens', '_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
83 pyroutes.register('edit_user_auth_tokens_add', '_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
84 pyroutes.register('edit_user_auth_tokens_add', '_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
84 pyroutes.register('edit_user_auth_tokens_delete', '_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
85 pyroutes.register('edit_user_auth_tokens_delete', '_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
85 pyroutes.register('edit_user_groups_management', '_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
86 pyroutes.register('edit_user_groups_management', '_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
86 pyroutes.register('edit_user_groups_management_updates', '_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
87 pyroutes.register('edit_user_groups_management_updates', '_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
87 pyroutes.register('edit_user_audit_logs', '_admin/users/%(user_id)s/edit/audit', ['user_id']);
88 pyroutes.register('edit_user_audit_logs', '_admin/users/%(user_id)s/edit/audit', ['user_id']);
88 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
89 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
89 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
90 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
90 pyroutes.register('channelstream_proxy', '/_channelstream', []);
91 pyroutes.register('channelstream_proxy', '/_channelstream', []);
91 pyroutes.register('login', '/_admin/login', []);
92 pyroutes.register('login', '/_admin/login', []);
92 pyroutes.register('logout', '/_admin/logout', []);
93 pyroutes.register('logout', '/_admin/logout', []);
93 pyroutes.register('register', '/_admin/register', []);
94 pyroutes.register('register', '/_admin/register', []);
94 pyroutes.register('reset_password', '/_admin/password_reset', []);
95 pyroutes.register('reset_password', '/_admin/password_reset', []);
95 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
96 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
96 pyroutes.register('user_autocomplete_data', '/_users', []);
97 pyroutes.register('user_autocomplete_data', '/_users', []);
97 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
98 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
98 pyroutes.register('repo_list_data', '/_repos', []);
99 pyroutes.register('repo_list_data', '/_repos', []);
99 pyroutes.register('goto_switcher_data', '/_goto_data', []);
100 pyroutes.register('goto_switcher_data', '/_goto_data', []);
100 pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']);
101 pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']);
101 pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']);
102 pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']);
102 pyroutes.register('strip', '/%(repo_name)s/strip', ['repo_name']);
103 pyroutes.register('strip', '/%(repo_name)s/strip', ['repo_name']);
103 pyroutes.register('strip_check', '/%(repo_name)s/strip_check', ['repo_name']);
104 pyroutes.register('strip_check', '/%(repo_name)s/strip_check', ['repo_name']);
104 pyroutes.register('strip_execute', '/%(repo_name)s/strip_execute', ['repo_name']);
105 pyroutes.register('strip_execute', '/%(repo_name)s/strip_execute', ['repo_name']);
105 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
106 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
106 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
107 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
107 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
108 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
108 pyroutes.register('my_account_password_update', '/_admin/my_account/password', []);
109 pyroutes.register('my_account_password_update', '/_admin/my_account/password', []);
109 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
110 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
110 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
111 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
111 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
112 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
112 pyroutes.register('apiv2', '/_admin/api', []);
113 pyroutes.register('apiv2', '/_admin/api', []);
113 }
114 }
General Comments 0
You need to be logged in to leave comments. Login now