##// END OF EJS Templates
assets: skip RoutesMiddleware matching on certain urls to avoid...
dan -
r463:7ccc440b default
parent child Browse files
Show More
@@ -1,375 +1,392 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 Pylons middleware initialization
23 23 """
24 24 import logging
25 25
26 26 from paste.registry import RegistryManager
27 27 from paste.gzipper import make_gzip_middleware
28 28 from pylons.wsgiapp import PylonsApp
29 29 from pyramid.authorization import ACLAuthorizationPolicy
30 30 from pyramid.config import Configurator
31 31 from pyramid.static import static_view
32 32 from pyramid.settings import asbool, aslist
33 33 from pyramid.wsgi import wsgiapp
34 34 from pyramid.httpexceptions import HTTPError, HTTPInternalServerError
35 35 from pylons.controllers.util import abort, redirect
36 36 import pyramid.httpexceptions as httpexceptions
37 37 from pyramid.renderers import render_to_response, render
38 38 from routes.middleware import RoutesMiddleware
39 39 import routes.util
40 40
41 41 import rhodecode
42 42 import rhodecode.integrations # do not remove this as it registers celery tasks
43 43 from rhodecode.config import patches
44 from rhodecode.config.routing import STATIC_FILE_PREFIX
44 45 from rhodecode.config.environment import (
45 46 load_environment, load_pyramid_environment)
46 47 from rhodecode.lib.middleware import csrf
47 48 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
48 49 from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper
49 50 from rhodecode.lib.middleware.https_fixup import HttpsFixup
50 51 from rhodecode.lib.middleware.vcs import VCSMiddleware
51 52 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
52 53
53 54
54 55 log = logging.getLogger(__name__)
55 56
56 57
58 # this is used to avoid avoid the route lookup overhead in routesmiddleware
59 # for certain routes which won't go to pylons to - eg. static files, debugger
60 # it is only needed for the pylons migration and can be removed once complete
61 class SkippableRoutesMiddleware(RoutesMiddleware):
62 """ Routes middleware that allows you to skip prefixes """
63
64 def __init__(self, *args, **kw):
65 self.skip_prefixes = kw.pop('skip_prefixes', [])
66 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
67
68 def __call__(self, environ, start_response):
69 for prefix in self.skip_prefixes:
70 if environ['PATH_INFO'].startswith(prefix):
71 return self.app(environ, start_response)
72
73 return super(SkippableRoutesMiddleware, self).__call__(
74 environ, start_response)
75
76
57 77 def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
58 78 """Create a Pylons WSGI application and return it
59 79
60 80 ``global_conf``
61 81 The inherited configuration for this application. Normally from
62 82 the [DEFAULT] section of the Paste ini file.
63 83
64 84 ``full_stack``
65 85 Whether or not this application provides a full WSGI stack (by
66 86 default, meaning it handles its own exceptions and errors).
67 87 Disable full_stack when this application is "managed" by
68 88 another WSGI middleware.
69 89
70 90 ``app_conf``
71 91 The application's local configuration. Normally specified in
72 92 the [app:<name>] section of the Paste ini file (where <name>
73 93 defaults to main).
74 94
75 95 """
76 96 # Apply compatibility patches
77 97 patches.kombu_1_5_1_python_2_7_11()
78 98 patches.inspect_getargspec()
79 99
80 100 # Configure the Pylons environment
81 101 config = load_environment(global_conf, app_conf)
82 102
83 103 # The Pylons WSGI app
84 104 app = PylonsApp(config=config)
85 105 if rhodecode.is_test:
86 106 app = csrf.CSRFDetector(app)
87 107
88 108 expected_origin = config.get('expected_origin')
89 109 if expected_origin:
90 110 # The API can be accessed from other Origins.
91 111 app = csrf.OriginChecker(app, expected_origin,
92 112 skip_urls=[routes.util.url_for('api')])
93 113
94 114
95 115 if asbool(full_stack):
96 116
97 117 # Appenlight monitoring and error handler
98 118 app, appenlight_client = wrap_in_appenlight_if_enabled(app, config)
99 119
100 120 # we want our low level middleware to get to the request ASAP. We don't
101 121 # need any pylons stack middleware in them
102 122 app = VCSMiddleware(app, config, appenlight_client)
103 123
104 124 # Establish the Registry for this application
105 125 app = RegistryManager(app)
106 126
107 127 app.config = config
108 128
109 129 return app
110 130
111 131
112 132 def make_pyramid_app(global_config, **settings):
113 133 """
114 134 Constructs the WSGI application based on Pyramid and wraps the Pylons based
115 135 application.
116 136
117 137 Specials:
118 138
119 139 * We migrate from Pylons to Pyramid. While doing this, we keep both
120 140 frameworks functional. This involves moving some WSGI middlewares around
121 141 and providing access to some data internals, so that the old code is
122 142 still functional.
123 143
124 144 * The application can also be integrated like a plugin via the call to
125 145 `includeme`. This is accompanied with the other utility functions which
126 146 are called. Changing this should be done with great care to not break
127 147 cases when these fragments are assembled from another place.
128 148
129 149 """
130 150 # The edition string should be available in pylons too, so we add it here
131 151 # before copying the settings.
132 152 settings.setdefault('rhodecode.edition', 'Community Edition')
133 153
134 154 # As long as our Pylons application does expect "unprepared" settings, make
135 155 # sure that we keep an unmodified copy. This avoids unintentional change of
136 156 # behavior in the old application.
137 157 settings_pylons = settings.copy()
138 158
139 159 sanitize_settings_and_apply_defaults(settings)
140 160 config = Configurator(settings=settings)
141 161 add_pylons_compat_data(config.registry, global_config, settings_pylons)
142 162
143 163 load_pyramid_environment(global_config, settings)
144 164
165 includeme_first(config)
145 166 includeme(config)
146 includeme_last(config)
147 167 pyramid_app = config.make_wsgi_app()
148 168 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
149 169 return pyramid_app
150 170
151 171
152 172 def add_pylons_compat_data(registry, global_config, settings):
153 173 """
154 174 Attach data to the registry to support the Pylons integration.
155 175 """
156 176 registry._pylons_compat_global_config = global_config
157 177 registry._pylons_compat_settings = settings
158 178
159 179
160 180 def webob_to_pyramid_http_response(webob_response):
161 181 ResponseClass = httpexceptions.status_map[webob_response.status_int]
162 182 pyramid_response = ResponseClass(webob_response.status)
163 183 pyramid_response.status = webob_response.status
164 184 pyramid_response.headers.update(webob_response.headers)
165 185 if pyramid_response.headers['content-type'] == 'text/html':
166 186 pyramid_response.headers['content-type'] = 'text/html; charset=UTF-8'
167 187 return pyramid_response
168 188
169 189
170 190 def error_handler(exception, request):
171 191 # TODO: dan: replace the old pylons error controller with this
172 192 from rhodecode.model.settings import SettingsModel
173 193 from rhodecode.lib.utils2 import AttributeDict
174 194
175 195 try:
176 196 rc_config = SettingsModel().get_all_settings()
177 197 except Exception:
178 198 log.exception('failed to fetch settings')
179 199 rc_config = {}
180 200
181 201 base_response = HTTPInternalServerError()
182 202 # prefer original exception for the response since it may have headers set
183 203 if isinstance(exception, HTTPError):
184 204 base_response = exception
185 205
186 206 c = AttributeDict()
187 207 c.error_message = base_response.status
188 208 c.error_explanation = base_response.explanation or str(base_response)
189 209 c.visual = AttributeDict()
190 210
191 211 c.visual.rhodecode_support_url = (
192 212 request.registry.settings.get('rhodecode_support_url') or
193 213 request.route_url('rhodecode_support')
194 214 )
195 215 c.redirect_time = 0
196 216 c.rhodecode_name = rc_config.get('rhodecode_title', '')
197 217 if not c.rhodecode_name:
198 218 c.rhodecode_name = 'Rhodecode'
199 219
200 220 response = render_to_response(
201 221 '/errors/error_document.html', {'c': c}, request=request,
202 222 response=base_response)
203 223
204 224 return response
205 225
206 226
207 227 def includeme(config):
208 228 settings = config.registry.settings
209 229
210 230 if asbool(settings.get('appenlight', 'false')):
211 231 config.include('appenlight_client.ext.pyramid_tween')
212 232
213 233 # Includes which are required. The application would fail without them.
214 234 config.include('pyramid_mako')
215 235 config.include('pyramid_beaker')
216 236 config.include('rhodecode.admin')
217 237 config.include('rhodecode.authentication')
218 238 config.include('rhodecode.integrations')
219 239 config.include('rhodecode.login')
220 240 config.include('rhodecode.tweens')
221 241 config.include('rhodecode.api')
222 242 config.add_route(
223 243 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
224 244
225 245 # Set the authorization policy.
226 246 authz_policy = ACLAuthorizationPolicy()
227 247 config.set_authorization_policy(authz_policy)
228 248
229 249 # Set the default renderer for HTML templates to mako.
230 250 config.add_mako_renderer('.html')
231 251
232 252 # plugin information
233 253 config.registry.rhodecode_plugins = {}
234 254
235 255 config.add_directive(
236 256 'register_rhodecode_plugin', register_rhodecode_plugin)
237 257 # include RhodeCode plugins
238 258 includes = aslist(settings.get('rhodecode.includes', []))
239 259 for inc in includes:
240 260 config.include(inc)
241 261
242 262 pylons_app = make_app(
243 263 config.registry._pylons_compat_global_config,
244 264 **config.registry._pylons_compat_settings)
245 265 config.registry._pylons_compat_config = pylons_app.config
246 266
247 267 pylons_app_as_view = wsgiapp(pylons_app)
248 268
249 269 # Protect from VCS Server error related pages when server is not available
250 270 vcs_server_enabled = asbool(settings.get('vcs.server.enable', 'true'))
251 271 if not vcs_server_enabled:
252 272 pylons_app_as_view = DisableVCSPagesWrapper(pylons_app_as_view)
253 273
254 274
255 275 def pylons_app_with_error_handler(context, request):
256 276 """
257 277 Handle exceptions from rc pylons app:
258 278
259 279 - old webob type exceptions get converted to pyramid exceptions
260 280 - pyramid exceptions are passed to the error handler view
261 281 """
262 282 try:
263 283 response = pylons_app_as_view(context, request)
264 284 if 400 <= response.status_int <= 599: # webob type error responses
265 285 return error_handler(
266 286 webob_to_pyramid_http_response(response), request)
267 287 except HTTPError as e: # pyramid type exceptions
268 288 return error_handler(e, request)
269 289 except Exception:
270 290 if settings.get('debugtoolbar.enabled', False):
271 291 raise
272 292 return error_handler(HTTPInternalServerError(), request)
273 293 return response
274 294
275 295 # This is the glue which allows us to migrate in chunks. By registering the
276 296 # pylons based application as the "Not Found" view in Pyramid, we will
277 297 # fallback to the old application each time the new one does not yet know
278 298 # how to handle a request.
279 299 config.add_notfound_view(pylons_app_with_error_handler)
280 300
281 301 if not settings.get('debugtoolbar.enabled', False):
282 302 # if no toolbar, then any exception gets caught and rendered
283 303 config.add_view(error_handler, context=Exception)
284 304
285 305 config.add_view(error_handler, context=HTTPError)
286 306
287 307
288 def includeme_last(config):
289 """
290 The static file catchall needs to be last in the view configuration.
291 """
292 settings = config.registry.settings
293 config.add_static_view('_static', path='rhodecode:public')
294
308 def includeme_first(config):
295 309 # redirect automatic browser favicon.ico requests to correct place
296 310 def favicon_redirect(context, request):
297 311 return redirect(
298 312 request.static_url('rhodecode:public/images/favicon.ico'))
313
299 314 config.add_view(favicon_redirect, route_name='favicon')
300 315 config.add_route('favicon', '/favicon.ico')
301 316
317 config.add_static_view('_static', path='rhodecode:public')
318
302 319
303 320 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
304 321 """
305 322 Apply outer WSGI middlewares around the application.
306 323
307 324 Part of this has been moved up from the Pylons layer, so that the
308 325 data is also available if old Pylons code is hit through an already ported
309 326 view.
310 327 """
311 328 settings = config.registry.settings
312 329
313 330 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
314 331 pyramid_app = HttpsFixup(pyramid_app, settings)
315 332
316 333 # Add RoutesMiddleware to support the pylons compatibility tween during
317
318 334 # migration to pyramid.
319 pyramid_app = RoutesMiddleware(
320 pyramid_app, config.registry._pylons_compat_config['routes.map'])
335 pyramid_app = SkippableRoutesMiddleware(
336 pyramid_app, config.registry._pylons_compat_config['routes.map'],
337 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
321 338
322 339 if asbool(settings.get('appenlight', 'false')):
323 340 pyramid_app, _ = wrap_in_appenlight_if_enabled(
324 341 pyramid_app, config.registry._pylons_compat_config)
325 342
326 343 if asbool(settings.get('gzip_responses', 'true')):
327 344 pyramid_app = make_gzip_middleware(
328 345 pyramid_app, settings, compress_level=1)
329 346
330 347 return pyramid_app
331 348
332 349
333 350 def sanitize_settings_and_apply_defaults(settings):
334 351 """
335 352 Applies settings defaults and does all type conversion.
336 353
337 354 We would move all settings parsing and preparation into this place, so that
338 355 we have only one place left which deals with this part. The remaining parts
339 356 of the application would start to rely fully on well prepared settings.
340 357
341 358 This piece would later be split up per topic to avoid a big fat monster
342 359 function.
343 360 """
344 361
345 362 # Pyramid's mako renderer has to search in the templates folder so that the
346 363 # old templates still work. Ported and new templates are expected to use
347 364 # real asset specifications for the includes.
348 365 mako_directories = settings.setdefault('mako.directories', [
349 366 # Base templates of the original Pylons application
350 367 'rhodecode:templates',
351 368 ])
352 369 log.debug(
353 370 "Using the following Mako template directories: %s",
354 371 mako_directories)
355 372
356 373 # Default includes, possible to change as a user
357 374 pyramid_includes = settings.setdefault('pyramid.includes', [
358 375 'rhodecode.lib.middleware.request_wrapper',
359 376 ])
360 377 log.debug(
361 378 "Using the following pyramid.includes: %s",
362 379 pyramid_includes)
363 380
364 381 # TODO: johbo: Re-think this, usually the call to config.include
365 382 # should allow to pass in a prefix.
366 383 settings.setdefault('rhodecode.api.url', '/_admin/api')
367 384
368 385 _bool_setting(settings, 'vcs.server.enable', 'true')
369 386 _bool_setting(settings, 'is_test', 'false')
370 387
371 388 return settings
372 389
373 390
374 391 def _bool_setting(settings, name, default):
375 392 settings[name] = asbool(settings.get(name, default))
@@ -1,1154 +1,1155 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 Routes configuration
23 23
24 24 The more specific and detailed routes should be defined first so they
25 25 may take precedent over the more generic routes. For more information
26 26 refer to the routes manual at http://routes.groovie.org/docs/
27 27
28 28 IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py
29 29 and _route_name variable which uses some of stored naming here to do redirects.
30 30 """
31 31 import os
32 32 import re
33 33 from routes import Mapper
34 34
35 35 from rhodecode.config import routing_links
36 36
37 37 # prefix for non repository related links needs to be prefixed with `/`
38 38 ADMIN_PREFIX = '/_admin'
39 STATIC_FILE_PREFIX = '/_static'
39 40
40 41 # Default requirements for URL parts
41 42 URL_NAME_REQUIREMENTS = {
42 43 # group name can have a slash in them, but they must not end with a slash
43 44 'group_name': r'.*?[^/]',
44 45 # repo names can have a slash in them, but they must not end with a slash
45 46 'repo_name': r'.*?[^/]',
46 47 # file path eats up everything at the end
47 48 'f_path': r'.*',
48 49 # reference types
49 50 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
50 51 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
51 52 }
52 53
53 54
54 55 def add_route_requirements(route_path, requirements):
55 56 """
56 57 Adds regex requirements to pyramid routes using a mapping dict
57 58
58 59 >>> add_route_requirements('/{action}/{id}', {'id': r'\d+'})
59 60 '/{action}/{id:\d+}'
60 61
61 62 """
62 63 for key, regex in requirements.items():
63 64 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
64 65 return route_path
65 66
66 67
67 68 class JSRoutesMapper(Mapper):
68 69 """
69 70 Wrapper for routes.Mapper to make pyroutes compatible url definitions
70 71 """
71 72 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
72 73 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
73 74 def __init__(self, *args, **kw):
74 75 super(JSRoutesMapper, self).__init__(*args, **kw)
75 76 self._jsroutes = []
76 77
77 78 def connect(self, *args, **kw):
78 79 """
79 80 Wrapper for connect to take an extra argument jsroute=True
80 81
81 82 :param jsroute: boolean, if True will add the route to the pyroutes list
82 83 """
83 84 if kw.pop('jsroute', False):
84 85 if not self._named_route_regex.match(args[0]):
85 86 raise Exception('only named routes can be added to pyroutes')
86 87 self._jsroutes.append(args[0])
87 88
88 89 super(JSRoutesMapper, self).connect(*args, **kw)
89 90
90 91 def _extract_route_information(self, route):
91 92 """
92 93 Convert a route into tuple(name, path, args), eg:
93 94 ('user_profile', '/profile/%(username)s', ['username'])
94 95 """
95 96 routepath = route.routepath
96 97 def replace(matchobj):
97 98 if matchobj.group(1):
98 99 return "%%(%s)s" % matchobj.group(1).split(':')[0]
99 100 else:
100 101 return "%%(%s)s" % matchobj.group(2)
101 102
102 103 routepath = self._argument_prog.sub(replace, routepath)
103 104 return (
104 105 route.name,
105 106 routepath,
106 107 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
107 108 for arg in self._argument_prog.findall(route.routepath)]
108 109 )
109 110
110 111 def jsroutes(self):
111 112 """
112 113 Return a list of pyroutes.js compatible routes
113 114 """
114 115 for route_name in self._jsroutes:
115 116 yield self._extract_route_information(self._routenames[route_name])
116 117
117 118
118 119 def make_map(config):
119 120 """Create, configure and return the routes Mapper"""
120 121 rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'],
121 122 always_scan=config['debug'])
122 123 rmap.minimization = False
123 124 rmap.explicit = False
124 125
125 126 from rhodecode.lib.utils2 import str2bool
126 127 from rhodecode.model import repo, repo_group
127 128
128 129 def check_repo(environ, match_dict):
129 130 """
130 131 check for valid repository for proper 404 handling
131 132
132 133 :param environ:
133 134 :param match_dict:
134 135 """
135 136 repo_name = match_dict.get('repo_name')
136 137
137 138 if match_dict.get('f_path'):
138 139 # fix for multiple initial slashes that causes errors
139 140 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
140 141 repo_model = repo.RepoModel()
141 142 by_name_match = repo_model.get_by_repo_name(repo_name)
142 143 # if we match quickly from database, short circuit the operation,
143 144 # and validate repo based on the type.
144 145 if by_name_match:
145 146 return True
146 147
147 148 by_id_match = repo_model.get_repo_by_id(repo_name)
148 149 if by_id_match:
149 150 repo_name = by_id_match.repo_name
150 151 match_dict['repo_name'] = repo_name
151 152 return True
152 153
153 154 return False
154 155
155 156 def check_group(environ, match_dict):
156 157 """
157 158 check for valid repository group path for proper 404 handling
158 159
159 160 :param environ:
160 161 :param match_dict:
161 162 """
162 163 repo_group_name = match_dict.get('group_name')
163 164 repo_group_model = repo_group.RepoGroupModel()
164 165 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
165 166 if by_name_match:
166 167 return True
167 168
168 169 return False
169 170
170 171 def check_user_group(environ, match_dict):
171 172 """
172 173 check for valid user group for proper 404 handling
173 174
174 175 :param environ:
175 176 :param match_dict:
176 177 """
177 178 return True
178 179
179 180 def check_int(environ, match_dict):
180 181 return match_dict.get('id').isdigit()
181 182
182 183
183 184 #==========================================================================
184 185 # CUSTOM ROUTES HERE
185 186 #==========================================================================
186 187
187 188 # MAIN PAGE
188 189 rmap.connect('home', '/', controller='home', action='index', jsroute=True)
189 190 rmap.connect('goto_switcher_data', '/_goto_data', controller='home',
190 191 action='goto_switcher_data')
191 192 rmap.connect('repo_list_data', '/_repos', controller='home',
192 193 action='repo_list_data')
193 194
194 195 rmap.connect('user_autocomplete_data', '/_users', controller='home',
195 196 action='user_autocomplete_data', jsroute=True)
196 197 rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home',
197 198 action='user_group_autocomplete_data')
198 199
199 200 rmap.connect(
200 201 'user_profile', '/_profiles/{username}', controller='users',
201 202 action='user_profile')
202 203
203 204 # TODO: johbo: Static links, to be replaced by our redirection mechanism
204 205 rmap.connect('rst_help',
205 206 'http://docutils.sourceforge.net/docs/user/rst/quickref.html',
206 207 _static=True)
207 208 rmap.connect('markdown_help',
208 209 'http://daringfireball.net/projects/markdown/syntax',
209 210 _static=True)
210 211 rmap.connect('rhodecode_official', 'https://rhodecode.com', _static=True)
211 212 rmap.connect('rhodecode_support', 'https://rhodecode.com/help/', _static=True)
212 213 rmap.connect('rhodecode_translations', 'https://rhodecode.com/translate/enterprise', _static=True)
213 214 # TODO: anderson - making this a static link since redirect won't play
214 215 # nice with POST requests
215 216 rmap.connect('enterprise_license_convert_from_old',
216 217 'https://rhodecode.com/u/license-upgrade',
217 218 _static=True)
218 219
219 220 routing_links.connect_redirection_links(rmap)
220 221
221 222 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
222 223 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
223 224
224 225 # ADMIN REPOSITORY ROUTES
225 226 with rmap.submapper(path_prefix=ADMIN_PREFIX,
226 227 controller='admin/repos') as m:
227 228 m.connect('repos', '/repos',
228 229 action='create', conditions={'method': ['POST']})
229 230 m.connect('repos', '/repos',
230 231 action='index', conditions={'method': ['GET']})
231 232 m.connect('new_repo', '/create_repository', jsroute=True,
232 233 action='create_repository', conditions={'method': ['GET']})
233 234 m.connect('/repos/{repo_name}',
234 235 action='update', conditions={'method': ['PUT'],
235 236 'function': check_repo},
236 237 requirements=URL_NAME_REQUIREMENTS)
237 238 m.connect('delete_repo', '/repos/{repo_name}',
238 239 action='delete', conditions={'method': ['DELETE']},
239 240 requirements=URL_NAME_REQUIREMENTS)
240 241 m.connect('repo', '/repos/{repo_name}',
241 242 action='show', conditions={'method': ['GET'],
242 243 'function': check_repo},
243 244 requirements=URL_NAME_REQUIREMENTS)
244 245
245 246 # ADMIN REPOSITORY GROUPS ROUTES
246 247 with rmap.submapper(path_prefix=ADMIN_PREFIX,
247 248 controller='admin/repo_groups') as m:
248 249 m.connect('repo_groups', '/repo_groups',
249 250 action='create', conditions={'method': ['POST']})
250 251 m.connect('repo_groups', '/repo_groups',
251 252 action='index', conditions={'method': ['GET']})
252 253 m.connect('new_repo_group', '/repo_groups/new',
253 254 action='new', conditions={'method': ['GET']})
254 255 m.connect('update_repo_group', '/repo_groups/{group_name}',
255 256 action='update', conditions={'method': ['PUT'],
256 257 'function': check_group},
257 258 requirements=URL_NAME_REQUIREMENTS)
258 259
259 260 # EXTRAS REPO GROUP ROUTES
260 261 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
261 262 action='edit',
262 263 conditions={'method': ['GET'], 'function': check_group},
263 264 requirements=URL_NAME_REQUIREMENTS)
264 265 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
265 266 action='edit',
266 267 conditions={'method': ['PUT'], 'function': check_group},
267 268 requirements=URL_NAME_REQUIREMENTS)
268 269
269 270 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
270 271 action='edit_repo_group_advanced',
271 272 conditions={'method': ['GET'], 'function': check_group},
272 273 requirements=URL_NAME_REQUIREMENTS)
273 274 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
274 275 action='edit_repo_group_advanced',
275 276 conditions={'method': ['PUT'], 'function': check_group},
276 277 requirements=URL_NAME_REQUIREMENTS)
277 278
278 279 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
279 280 action='edit_repo_group_perms',
280 281 conditions={'method': ['GET'], 'function': check_group},
281 282 requirements=URL_NAME_REQUIREMENTS)
282 283 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
283 284 action='update_perms',
284 285 conditions={'method': ['PUT'], 'function': check_group},
285 286 requirements=URL_NAME_REQUIREMENTS)
286 287
287 288 m.connect('delete_repo_group', '/repo_groups/{group_name}',
288 289 action='delete', conditions={'method': ['DELETE'],
289 290 'function': check_group},
290 291 requirements=URL_NAME_REQUIREMENTS)
291 292
292 293 # ADMIN USER ROUTES
293 294 with rmap.submapper(path_prefix=ADMIN_PREFIX,
294 295 controller='admin/users') as m:
295 296 m.connect('users', '/users',
296 297 action='create', conditions={'method': ['POST']})
297 298 m.connect('users', '/users',
298 299 action='index', conditions={'method': ['GET']})
299 300 m.connect('new_user', '/users/new',
300 301 action='new', conditions={'method': ['GET']})
301 302 m.connect('update_user', '/users/{user_id}',
302 303 action='update', conditions={'method': ['PUT']})
303 304 m.connect('delete_user', '/users/{user_id}',
304 305 action='delete', conditions={'method': ['DELETE']})
305 306 m.connect('edit_user', '/users/{user_id}/edit',
306 307 action='edit', conditions={'method': ['GET']})
307 308 m.connect('user', '/users/{user_id}',
308 309 action='show', conditions={'method': ['GET']})
309 310 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
310 311 action='reset_password', conditions={'method': ['POST']})
311 312 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
312 313 action='create_personal_repo_group', conditions={'method': ['POST']})
313 314
314 315 # EXTRAS USER ROUTES
315 316 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
316 317 action='edit_advanced', conditions={'method': ['GET']})
317 318 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
318 319 action='update_advanced', conditions={'method': ['PUT']})
319 320
320 321 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
321 322 action='edit_auth_tokens', conditions={'method': ['GET']})
322 323 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
323 324 action='add_auth_token', conditions={'method': ['PUT']})
324 325 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
325 326 action='delete_auth_token', conditions={'method': ['DELETE']})
326 327
327 328 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
328 329 action='edit_global_perms', conditions={'method': ['GET']})
329 330 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
330 331 action='update_global_perms', conditions={'method': ['PUT']})
331 332
332 333 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
333 334 action='edit_perms_summary', conditions={'method': ['GET']})
334 335
335 336 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
336 337 action='edit_emails', conditions={'method': ['GET']})
337 338 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
338 339 action='add_email', conditions={'method': ['PUT']})
339 340 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
340 341 action='delete_email', conditions={'method': ['DELETE']})
341 342
342 343 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
343 344 action='edit_ips', conditions={'method': ['GET']})
344 345 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
345 346 action='add_ip', conditions={'method': ['PUT']})
346 347 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
347 348 action='delete_ip', conditions={'method': ['DELETE']})
348 349
349 350 # ADMIN USER GROUPS REST ROUTES
350 351 with rmap.submapper(path_prefix=ADMIN_PREFIX,
351 352 controller='admin/user_groups') as m:
352 353 m.connect('users_groups', '/user_groups',
353 354 action='create', conditions={'method': ['POST']})
354 355 m.connect('users_groups', '/user_groups',
355 356 action='index', conditions={'method': ['GET']})
356 357 m.connect('new_users_group', '/user_groups/new',
357 358 action='new', conditions={'method': ['GET']})
358 359 m.connect('update_users_group', '/user_groups/{user_group_id}',
359 360 action='update', conditions={'method': ['PUT']})
360 361 m.connect('delete_users_group', '/user_groups/{user_group_id}',
361 362 action='delete', conditions={'method': ['DELETE']})
362 363 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
363 364 action='edit', conditions={'method': ['GET']},
364 365 function=check_user_group)
365 366
366 367 # EXTRAS USER GROUP ROUTES
367 368 m.connect('edit_user_group_global_perms',
368 369 '/user_groups/{user_group_id}/edit/global_permissions',
369 370 action='edit_global_perms', conditions={'method': ['GET']})
370 371 m.connect('edit_user_group_global_perms',
371 372 '/user_groups/{user_group_id}/edit/global_permissions',
372 373 action='update_global_perms', conditions={'method': ['PUT']})
373 374 m.connect('edit_user_group_perms_summary',
374 375 '/user_groups/{user_group_id}/edit/permissions_summary',
375 376 action='edit_perms_summary', conditions={'method': ['GET']})
376 377
377 378 m.connect('edit_user_group_perms',
378 379 '/user_groups/{user_group_id}/edit/permissions',
379 380 action='edit_perms', conditions={'method': ['GET']})
380 381 m.connect('edit_user_group_perms',
381 382 '/user_groups/{user_group_id}/edit/permissions',
382 383 action='update_perms', conditions={'method': ['PUT']})
383 384
384 385 m.connect('edit_user_group_advanced',
385 386 '/user_groups/{user_group_id}/edit/advanced',
386 387 action='edit_advanced', conditions={'method': ['GET']})
387 388
388 389 m.connect('edit_user_group_members',
389 390 '/user_groups/{user_group_id}/edit/members', jsroute=True,
390 391 action='edit_members', conditions={'method': ['GET']})
391 392
392 393 # ADMIN PERMISSIONS ROUTES
393 394 with rmap.submapper(path_prefix=ADMIN_PREFIX,
394 395 controller='admin/permissions') as m:
395 396 m.connect('admin_permissions_application', '/permissions/application',
396 397 action='permission_application_update', conditions={'method': ['POST']})
397 398 m.connect('admin_permissions_application', '/permissions/application',
398 399 action='permission_application', conditions={'method': ['GET']})
399 400
400 401 m.connect('admin_permissions_global', '/permissions/global',
401 402 action='permission_global_update', conditions={'method': ['POST']})
402 403 m.connect('admin_permissions_global', '/permissions/global',
403 404 action='permission_global', conditions={'method': ['GET']})
404 405
405 406 m.connect('admin_permissions_object', '/permissions/object',
406 407 action='permission_objects_update', conditions={'method': ['POST']})
407 408 m.connect('admin_permissions_object', '/permissions/object',
408 409 action='permission_objects', conditions={'method': ['GET']})
409 410
410 411 m.connect('admin_permissions_ips', '/permissions/ips',
411 412 action='permission_ips', conditions={'method': ['POST']})
412 413 m.connect('admin_permissions_ips', '/permissions/ips',
413 414 action='permission_ips', conditions={'method': ['GET']})
414 415
415 416 m.connect('admin_permissions_overview', '/permissions/overview',
416 417 action='permission_perms', conditions={'method': ['GET']})
417 418
418 419 # ADMIN DEFAULTS REST ROUTES
419 420 with rmap.submapper(path_prefix=ADMIN_PREFIX,
420 421 controller='admin/defaults') as m:
421 422 m.connect('admin_defaults_repositories', '/defaults/repositories',
422 423 action='update_repository_defaults', conditions={'method': ['POST']})
423 424 m.connect('admin_defaults_repositories', '/defaults/repositories',
424 425 action='index', conditions={'method': ['GET']})
425 426
426 427 # ADMIN DEBUG STYLE ROUTES
427 428 if str2bool(config.get('debug_style')):
428 429 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
429 430 controller='debug_style') as m:
430 431 m.connect('debug_style_home', '',
431 432 action='index', conditions={'method': ['GET']})
432 433 m.connect('debug_style_template', '/t/{t_path}',
433 434 action='template', conditions={'method': ['GET']})
434 435
435 436 # ADMIN SETTINGS ROUTES
436 437 with rmap.submapper(path_prefix=ADMIN_PREFIX,
437 438 controller='admin/settings') as m:
438 439
439 440 # default
440 441 m.connect('admin_settings', '/settings',
441 442 action='settings_global_update',
442 443 conditions={'method': ['POST']})
443 444 m.connect('admin_settings', '/settings',
444 445 action='settings_global', conditions={'method': ['GET']})
445 446
446 447 m.connect('admin_settings_vcs', '/settings/vcs',
447 448 action='settings_vcs_update',
448 449 conditions={'method': ['POST']})
449 450 m.connect('admin_settings_vcs', '/settings/vcs',
450 451 action='settings_vcs',
451 452 conditions={'method': ['GET']})
452 453 m.connect('admin_settings_vcs', '/settings/vcs',
453 454 action='delete_svn_pattern',
454 455 conditions={'method': ['DELETE']})
455 456
456 457 m.connect('admin_settings_mapping', '/settings/mapping',
457 458 action='settings_mapping_update',
458 459 conditions={'method': ['POST']})
459 460 m.connect('admin_settings_mapping', '/settings/mapping',
460 461 action='settings_mapping', conditions={'method': ['GET']})
461 462
462 463 m.connect('admin_settings_global', '/settings/global',
463 464 action='settings_global_update',
464 465 conditions={'method': ['POST']})
465 466 m.connect('admin_settings_global', '/settings/global',
466 467 action='settings_global', conditions={'method': ['GET']})
467 468
468 469 m.connect('admin_settings_visual', '/settings/visual',
469 470 action='settings_visual_update',
470 471 conditions={'method': ['POST']})
471 472 m.connect('admin_settings_visual', '/settings/visual',
472 473 action='settings_visual', conditions={'method': ['GET']})
473 474
474 475 m.connect('admin_settings_issuetracker',
475 476 '/settings/issue-tracker', action='settings_issuetracker',
476 477 conditions={'method': ['GET']})
477 478 m.connect('admin_settings_issuetracker_save',
478 479 '/settings/issue-tracker/save',
479 480 action='settings_issuetracker_save',
480 481 conditions={'method': ['POST']})
481 482 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
482 483 action='settings_issuetracker_test',
483 484 conditions={'method': ['POST']})
484 485 m.connect('admin_issuetracker_delete',
485 486 '/settings/issue-tracker/delete',
486 487 action='settings_issuetracker_delete',
487 488 conditions={'method': ['DELETE']})
488 489
489 490 m.connect('admin_settings_email', '/settings/email',
490 491 action='settings_email_update',
491 492 conditions={'method': ['POST']})
492 493 m.connect('admin_settings_email', '/settings/email',
493 494 action='settings_email', conditions={'method': ['GET']})
494 495
495 496 m.connect('admin_settings_hooks', '/settings/hooks',
496 497 action='settings_hooks_update',
497 498 conditions={'method': ['POST', 'DELETE']})
498 499 m.connect('admin_settings_hooks', '/settings/hooks',
499 500 action='settings_hooks', conditions={'method': ['GET']})
500 501
501 502 m.connect('admin_settings_search', '/settings/search',
502 503 action='settings_search', conditions={'method': ['GET']})
503 504
504 505 m.connect('admin_settings_system', '/settings/system',
505 506 action='settings_system', conditions={'method': ['GET']})
506 507
507 508 m.connect('admin_settings_system_update', '/settings/system/updates',
508 509 action='settings_system_update', conditions={'method': ['GET']})
509 510
510 511 m.connect('admin_settings_supervisor', '/settings/supervisor',
511 512 action='settings_supervisor', conditions={'method': ['GET']})
512 513 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
513 514 action='settings_supervisor_log', conditions={'method': ['GET']})
514 515
515 516 m.connect('admin_settings_labs', '/settings/labs',
516 517 action='settings_labs_update',
517 518 conditions={'method': ['POST']})
518 519 m.connect('admin_settings_labs', '/settings/labs',
519 520 action='settings_labs', conditions={'method': ['GET']})
520 521
521 522 # ADMIN MY ACCOUNT
522 523 with rmap.submapper(path_prefix=ADMIN_PREFIX,
523 524 controller='admin/my_account') as m:
524 525
525 526 m.connect('my_account', '/my_account',
526 527 action='my_account', conditions={'method': ['GET']})
527 528 m.connect('my_account_edit', '/my_account/edit',
528 529 action='my_account_edit', conditions={'method': ['GET']})
529 530 m.connect('my_account', '/my_account',
530 531 action='my_account_update', conditions={'method': ['POST']})
531 532
532 533 m.connect('my_account_password', '/my_account/password',
533 534 action='my_account_password', conditions={'method': ['GET']})
534 535 m.connect('my_account_password', '/my_account/password',
535 536 action='my_account_password_update', conditions={'method': ['POST']})
536 537
537 538 m.connect('my_account_repos', '/my_account/repos',
538 539 action='my_account_repos', conditions={'method': ['GET']})
539 540
540 541 m.connect('my_account_watched', '/my_account/watched',
541 542 action='my_account_watched', conditions={'method': ['GET']})
542 543
543 544 m.connect('my_account_pullrequests', '/my_account/pull_requests',
544 545 action='my_account_pullrequests', conditions={'method': ['GET']})
545 546
546 547 m.connect('my_account_perms', '/my_account/perms',
547 548 action='my_account_perms', conditions={'method': ['GET']})
548 549
549 550 m.connect('my_account_emails', '/my_account/emails',
550 551 action='my_account_emails', conditions={'method': ['GET']})
551 552 m.connect('my_account_emails', '/my_account/emails',
552 553 action='my_account_emails_add', conditions={'method': ['POST']})
553 554 m.connect('my_account_emails', '/my_account/emails',
554 555 action='my_account_emails_delete', conditions={'method': ['DELETE']})
555 556
556 557 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
557 558 action='my_account_auth_tokens', conditions={'method': ['GET']})
558 559 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
559 560 action='my_account_auth_tokens_add', conditions={'method': ['POST']})
560 561 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
561 562 action='my_account_auth_tokens_delete', conditions={'method': ['DELETE']})
562 563
563 564 # NOTIFICATION REST ROUTES
564 565 with rmap.submapper(path_prefix=ADMIN_PREFIX,
565 566 controller='admin/notifications') as m:
566 567 m.connect('notifications', '/notifications',
567 568 action='index', conditions={'method': ['GET']})
568 569 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
569 570 action='mark_all_read', conditions={'method': ['POST']})
570 571
571 572 m.connect('/notifications/{notification_id}',
572 573 action='update', conditions={'method': ['PUT']})
573 574 m.connect('/notifications/{notification_id}',
574 575 action='delete', conditions={'method': ['DELETE']})
575 576 m.connect('notification', '/notifications/{notification_id}',
576 577 action='show', conditions={'method': ['GET']})
577 578
578 579 # ADMIN GIST
579 580 with rmap.submapper(path_prefix=ADMIN_PREFIX,
580 581 controller='admin/gists') as m:
581 582 m.connect('gists', '/gists',
582 583 action='create', conditions={'method': ['POST']})
583 584 m.connect('gists', '/gists', jsroute=True,
584 585 action='index', conditions={'method': ['GET']})
585 586 m.connect('new_gist', '/gists/new', jsroute=True,
586 587 action='new', conditions={'method': ['GET']})
587 588
588 589 m.connect('/gists/{gist_id}',
589 590 action='delete', conditions={'method': ['DELETE']})
590 591 m.connect('edit_gist', '/gists/{gist_id}/edit',
591 592 action='edit_form', conditions={'method': ['GET']})
592 593 m.connect('edit_gist', '/gists/{gist_id}/edit',
593 594 action='edit', conditions={'method': ['POST']})
594 595 m.connect(
595 596 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision',
596 597 action='check_revision', conditions={'method': ['GET']})
597 598
598 599 m.connect('gist', '/gists/{gist_id}',
599 600 action='show', conditions={'method': ['GET']})
600 601 m.connect('gist_rev', '/gists/{gist_id}/{revision}',
601 602 revision='tip',
602 603 action='show', conditions={'method': ['GET']})
603 604 m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}',
604 605 revision='tip',
605 606 action='show', conditions={'method': ['GET']})
606 607 m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}',
607 608 revision='tip',
608 609 action='show', conditions={'method': ['GET']},
609 610 requirements=URL_NAME_REQUIREMENTS)
610 611
611 612 # ADMIN MAIN PAGES
612 613 with rmap.submapper(path_prefix=ADMIN_PREFIX,
613 614 controller='admin/admin') as m:
614 615 m.connect('admin_home', '', action='index')
615 616 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
616 617 action='add_repo')
617 618 m.connect(
618 619 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}',
619 620 action='pull_requests')
620 621 m.connect(
621 622 'pull_requests_global', '/pull-requests/{pull_request_id:[0-9]+}',
622 623 action='pull_requests')
623 624
624 625
625 626 # USER JOURNAL
626 627 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
627 628 controller='journal', action='index')
628 629 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
629 630 controller='journal', action='journal_rss')
630 631 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
631 632 controller='journal', action='journal_atom')
632 633
633 634 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
634 635 controller='journal', action='public_journal')
635 636
636 637 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
637 638 controller='journal', action='public_journal_rss')
638 639
639 640 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
640 641 controller='journal', action='public_journal_rss')
641 642
642 643 rmap.connect('public_journal_atom',
643 644 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
644 645 action='public_journal_atom')
645 646
646 647 rmap.connect('public_journal_atom_old',
647 648 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
648 649 action='public_journal_atom')
649 650
650 651 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
651 652 controller='journal', action='toggle_following', jsroute=True,
652 653 conditions={'method': ['POST']})
653 654
654 655 # FULL TEXT SEARCH
655 656 rmap.connect('search', '%s/search' % (ADMIN_PREFIX,),
656 657 controller='search')
657 658 rmap.connect('search_repo_home', '/{repo_name}/search',
658 659 controller='search',
659 660 action='index',
660 661 conditions={'function': check_repo},
661 662 requirements=URL_NAME_REQUIREMENTS)
662 663
663 664 # FEEDS
664 665 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
665 666 controller='feed', action='rss',
666 667 conditions={'function': check_repo},
667 668 requirements=URL_NAME_REQUIREMENTS)
668 669
669 670 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
670 671 controller='feed', action='atom',
671 672 conditions={'function': check_repo},
672 673 requirements=URL_NAME_REQUIREMENTS)
673 674
674 675 #==========================================================================
675 676 # REPOSITORY ROUTES
676 677 #==========================================================================
677 678
678 679 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
679 680 controller='admin/repos', action='repo_creating',
680 681 requirements=URL_NAME_REQUIREMENTS)
681 682 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
682 683 controller='admin/repos', action='repo_check',
683 684 requirements=URL_NAME_REQUIREMENTS)
684 685
685 686 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
686 687 controller='summary', action='repo_stats',
687 688 conditions={'function': check_repo},
688 689 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
689 690
690 691 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
691 692 controller='summary', action='repo_refs_data', jsroute=True,
692 693 requirements=URL_NAME_REQUIREMENTS)
693 694 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
694 695 controller='summary', action='repo_refs_changelog_data',
695 696 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
696 697
697 698 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
698 699 controller='changeset', revision='tip', jsroute=True,
699 700 conditions={'function': check_repo},
700 701 requirements=URL_NAME_REQUIREMENTS)
701 702 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
702 703 controller='changeset', revision='tip', action='changeset_children',
703 704 conditions={'function': check_repo},
704 705 requirements=URL_NAME_REQUIREMENTS)
705 706 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
706 707 controller='changeset', revision='tip', action='changeset_parents',
707 708 conditions={'function': check_repo},
708 709 requirements=URL_NAME_REQUIREMENTS)
709 710
710 711 # repo edit options
711 712 rmap.connect('edit_repo', '/{repo_name}/settings', jsroute=True,
712 713 controller='admin/repos', action='edit',
713 714 conditions={'method': ['GET'], 'function': check_repo},
714 715 requirements=URL_NAME_REQUIREMENTS)
715 716
716 717 rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions',
717 718 jsroute=True,
718 719 controller='admin/repos', action='edit_permissions',
719 720 conditions={'method': ['GET'], 'function': check_repo},
720 721 requirements=URL_NAME_REQUIREMENTS)
721 722 rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions',
722 723 controller='admin/repos', action='edit_permissions_update',
723 724 conditions={'method': ['PUT'], 'function': check_repo},
724 725 requirements=URL_NAME_REQUIREMENTS)
725 726
726 727 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
727 728 controller='admin/repos', action='edit_fields',
728 729 conditions={'method': ['GET'], 'function': check_repo},
729 730 requirements=URL_NAME_REQUIREMENTS)
730 731 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
731 732 controller='admin/repos', action='create_repo_field',
732 733 conditions={'method': ['PUT'], 'function': check_repo},
733 734 requirements=URL_NAME_REQUIREMENTS)
734 735 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
735 736 controller='admin/repos', action='delete_repo_field',
736 737 conditions={'method': ['DELETE'], 'function': check_repo},
737 738 requirements=URL_NAME_REQUIREMENTS)
738 739
739 740 rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
740 741 controller='admin/repos', action='edit_advanced',
741 742 conditions={'method': ['GET'], 'function': check_repo},
742 743 requirements=URL_NAME_REQUIREMENTS)
743 744
744 745 rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
745 746 controller='admin/repos', action='edit_advanced_locking',
746 747 conditions={'method': ['PUT'], 'function': check_repo},
747 748 requirements=URL_NAME_REQUIREMENTS)
748 749 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
749 750 controller='admin/repos', action='toggle_locking',
750 751 conditions={'method': ['GET'], 'function': check_repo},
751 752 requirements=URL_NAME_REQUIREMENTS)
752 753
753 754 rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal',
754 755 controller='admin/repos', action='edit_advanced_journal',
755 756 conditions={'method': ['PUT'], 'function': check_repo},
756 757 requirements=URL_NAME_REQUIREMENTS)
757 758
758 759 rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
759 760 controller='admin/repos', action='edit_advanced_fork',
760 761 conditions={'method': ['PUT'], 'function': check_repo},
761 762 requirements=URL_NAME_REQUIREMENTS)
762 763
763 764 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
764 765 controller='admin/repos', action='edit_caches_form',
765 766 conditions={'method': ['GET'], 'function': check_repo},
766 767 requirements=URL_NAME_REQUIREMENTS)
767 768 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
768 769 controller='admin/repos', action='edit_caches',
769 770 conditions={'method': ['PUT'], 'function': check_repo},
770 771 requirements=URL_NAME_REQUIREMENTS)
771 772
772 773 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
773 774 controller='admin/repos', action='edit_remote_form',
774 775 conditions={'method': ['GET'], 'function': check_repo},
775 776 requirements=URL_NAME_REQUIREMENTS)
776 777 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
777 778 controller='admin/repos', action='edit_remote',
778 779 conditions={'method': ['PUT'], 'function': check_repo},
779 780 requirements=URL_NAME_REQUIREMENTS)
780 781
781 782 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
782 783 controller='admin/repos', action='edit_statistics_form',
783 784 conditions={'method': ['GET'], 'function': check_repo},
784 785 requirements=URL_NAME_REQUIREMENTS)
785 786 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
786 787 controller='admin/repos', action='edit_statistics',
787 788 conditions={'method': ['PUT'], 'function': check_repo},
788 789 requirements=URL_NAME_REQUIREMENTS)
789 790 rmap.connect('repo_settings_issuetracker',
790 791 '/{repo_name}/settings/issue-tracker',
791 792 controller='admin/repos', action='repo_issuetracker',
792 793 conditions={'method': ['GET'], 'function': check_repo},
793 794 requirements=URL_NAME_REQUIREMENTS)
794 795 rmap.connect('repo_issuetracker_test',
795 796 '/{repo_name}/settings/issue-tracker/test',
796 797 controller='admin/repos', action='repo_issuetracker_test',
797 798 conditions={'method': ['POST'], 'function': check_repo},
798 799 requirements=URL_NAME_REQUIREMENTS)
799 800 rmap.connect('repo_issuetracker_delete',
800 801 '/{repo_name}/settings/issue-tracker/delete',
801 802 controller='admin/repos', action='repo_issuetracker_delete',
802 803 conditions={'method': ['DELETE'], 'function': check_repo},
803 804 requirements=URL_NAME_REQUIREMENTS)
804 805 rmap.connect('repo_issuetracker_save',
805 806 '/{repo_name}/settings/issue-tracker/save',
806 807 controller='admin/repos', action='repo_issuetracker_save',
807 808 conditions={'method': ['POST'], 'function': check_repo},
808 809 requirements=URL_NAME_REQUIREMENTS)
809 810 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
810 811 controller='admin/repos', action='repo_settings_vcs_update',
811 812 conditions={'method': ['POST'], 'function': check_repo},
812 813 requirements=URL_NAME_REQUIREMENTS)
813 814 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
814 815 controller='admin/repos', action='repo_settings_vcs',
815 816 conditions={'method': ['GET'], 'function': check_repo},
816 817 requirements=URL_NAME_REQUIREMENTS)
817 818 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
818 819 controller='admin/repos', action='repo_delete_svn_pattern',
819 820 conditions={'method': ['DELETE'], 'function': check_repo},
820 821 requirements=URL_NAME_REQUIREMENTS)
821 822
822 823 # still working url for backward compat.
823 824 rmap.connect('raw_changeset_home_depraced',
824 825 '/{repo_name}/raw-changeset/{revision}',
825 826 controller='changeset', action='changeset_raw',
826 827 revision='tip', conditions={'function': check_repo},
827 828 requirements=URL_NAME_REQUIREMENTS)
828 829
829 830 # new URLs
830 831 rmap.connect('changeset_raw_home',
831 832 '/{repo_name}/changeset-diff/{revision}',
832 833 controller='changeset', action='changeset_raw',
833 834 revision='tip', conditions={'function': check_repo},
834 835 requirements=URL_NAME_REQUIREMENTS)
835 836
836 837 rmap.connect('changeset_patch_home',
837 838 '/{repo_name}/changeset-patch/{revision}',
838 839 controller='changeset', action='changeset_patch',
839 840 revision='tip', conditions={'function': check_repo},
840 841 requirements=URL_NAME_REQUIREMENTS)
841 842
842 843 rmap.connect('changeset_download_home',
843 844 '/{repo_name}/changeset-download/{revision}',
844 845 controller='changeset', action='changeset_download',
845 846 revision='tip', conditions={'function': check_repo},
846 847 requirements=URL_NAME_REQUIREMENTS)
847 848
848 849 rmap.connect('changeset_comment',
849 850 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
850 851 controller='changeset', revision='tip', action='comment',
851 852 conditions={'function': check_repo},
852 853 requirements=URL_NAME_REQUIREMENTS)
853 854
854 855 rmap.connect('changeset_comment_preview',
855 856 '/{repo_name}/changeset/comment/preview', jsroute=True,
856 857 controller='changeset', action='preview_comment',
857 858 conditions={'function': check_repo, 'method': ['POST']},
858 859 requirements=URL_NAME_REQUIREMENTS)
859 860
860 861 rmap.connect('changeset_comment_delete',
861 862 '/{repo_name}/changeset/comment/{comment_id}/delete',
862 863 controller='changeset', action='delete_comment',
863 864 conditions={'function': check_repo, 'method': ['DELETE']},
864 865 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
865 866
866 867 rmap.connect('changeset_info', '/changeset_info/{repo_name}/{revision}',
867 868 controller='changeset', action='changeset_info',
868 869 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
869 870
870 871 rmap.connect('compare_home',
871 872 '/{repo_name}/compare',
872 873 controller='compare', action='index',
873 874 conditions={'function': check_repo},
874 875 requirements=URL_NAME_REQUIREMENTS)
875 876
876 877 rmap.connect('compare_url',
877 878 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
878 879 controller='compare', action='compare',
879 880 conditions={'function': check_repo},
880 881 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
881 882
882 883 rmap.connect('pullrequest_home',
883 884 '/{repo_name}/pull-request/new', controller='pullrequests',
884 885 action='index', conditions={'function': check_repo,
885 886 'method': ['GET']},
886 887 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
887 888
888 889 rmap.connect('pullrequest',
889 890 '/{repo_name}/pull-request/new', controller='pullrequests',
890 891 action='create', conditions={'function': check_repo,
891 892 'method': ['POST']},
892 893 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
893 894
894 895 rmap.connect('pullrequest_repo_refs',
895 896 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
896 897 controller='pullrequests',
897 898 action='get_repo_refs',
898 899 conditions={'function': check_repo, 'method': ['GET']},
899 900 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
900 901
901 902 rmap.connect('pullrequest_repo_destinations',
902 903 '/{repo_name}/pull-request/repo-destinations',
903 904 controller='pullrequests',
904 905 action='get_repo_destinations',
905 906 conditions={'function': check_repo, 'method': ['GET']},
906 907 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
907 908
908 909 rmap.connect('pullrequest_show',
909 910 '/{repo_name}/pull-request/{pull_request_id}',
910 911 controller='pullrequests',
911 912 action='show', conditions={'function': check_repo,
912 913 'method': ['GET']},
913 914 requirements=URL_NAME_REQUIREMENTS)
914 915
915 916 rmap.connect('pullrequest_update',
916 917 '/{repo_name}/pull-request/{pull_request_id}',
917 918 controller='pullrequests',
918 919 action='update', conditions={'function': check_repo,
919 920 'method': ['PUT']},
920 921 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
921 922
922 923 rmap.connect('pullrequest_merge',
923 924 '/{repo_name}/pull-request/{pull_request_id}',
924 925 controller='pullrequests',
925 926 action='merge', conditions={'function': check_repo,
926 927 'method': ['POST']},
927 928 requirements=URL_NAME_REQUIREMENTS)
928 929
929 930 rmap.connect('pullrequest_delete',
930 931 '/{repo_name}/pull-request/{pull_request_id}',
931 932 controller='pullrequests',
932 933 action='delete', conditions={'function': check_repo,
933 934 'method': ['DELETE']},
934 935 requirements=URL_NAME_REQUIREMENTS)
935 936
936 937 rmap.connect('pullrequest_show_all',
937 938 '/{repo_name}/pull-request',
938 939 controller='pullrequests',
939 940 action='show_all', conditions={'function': check_repo,
940 941 'method': ['GET']},
941 942 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
942 943
943 944 rmap.connect('pullrequest_comment',
944 945 '/{repo_name}/pull-request-comment/{pull_request_id}',
945 946 controller='pullrequests',
946 947 action='comment', conditions={'function': check_repo,
947 948 'method': ['POST']},
948 949 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
949 950
950 951 rmap.connect('pullrequest_comment_delete',
951 952 '/{repo_name}/pull-request-comment/{comment_id}/delete',
952 953 controller='pullrequests', action='delete_comment',
953 954 conditions={'function': check_repo, 'method': ['DELETE']},
954 955 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
955 956
956 957 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
957 958 controller='summary', conditions={'function': check_repo},
958 959 requirements=URL_NAME_REQUIREMENTS)
959 960
960 961 rmap.connect('branches_home', '/{repo_name}/branches',
961 962 controller='branches', conditions={'function': check_repo},
962 963 requirements=URL_NAME_REQUIREMENTS)
963 964
964 965 rmap.connect('tags_home', '/{repo_name}/tags',
965 966 controller='tags', conditions={'function': check_repo},
966 967 requirements=URL_NAME_REQUIREMENTS)
967 968
968 969 rmap.connect('bookmarks_home', '/{repo_name}/bookmarks',
969 970 controller='bookmarks', conditions={'function': check_repo},
970 971 requirements=URL_NAME_REQUIREMENTS)
971 972
972 973 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
973 974 controller='changelog', conditions={'function': check_repo},
974 975 requirements=URL_NAME_REQUIREMENTS)
975 976
976 977 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
977 978 controller='changelog', action='changelog_summary',
978 979 conditions={'function': check_repo},
979 980 requirements=URL_NAME_REQUIREMENTS)
980 981
981 982 rmap.connect('changelog_file_home',
982 983 '/{repo_name}/changelog/{revision}/{f_path}',
983 984 controller='changelog', f_path=None,
984 985 conditions={'function': check_repo},
985 986 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
986 987
987 988 rmap.connect('changelog_details', '/{repo_name}/changelog_details/{cs}',
988 989 controller='changelog', action='changelog_details',
989 990 conditions={'function': check_repo},
990 991 requirements=URL_NAME_REQUIREMENTS)
991 992
992 993 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
993 994 controller='files', revision='tip', f_path='',
994 995 conditions={'function': check_repo},
995 996 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
996 997
997 998 rmap.connect('files_home_simple_catchrev',
998 999 '/{repo_name}/files/{revision}',
999 1000 controller='files', revision='tip', f_path='',
1000 1001 conditions={'function': check_repo},
1001 1002 requirements=URL_NAME_REQUIREMENTS)
1002 1003
1003 1004 rmap.connect('files_home_simple_catchall',
1004 1005 '/{repo_name}/files',
1005 1006 controller='files', revision='tip', f_path='',
1006 1007 conditions={'function': check_repo},
1007 1008 requirements=URL_NAME_REQUIREMENTS)
1008 1009
1009 1010 rmap.connect('files_history_home',
1010 1011 '/{repo_name}/history/{revision}/{f_path}',
1011 1012 controller='files', action='history', revision='tip', f_path='',
1012 1013 conditions={'function': check_repo},
1013 1014 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1014 1015
1015 1016 rmap.connect('files_authors_home',
1016 1017 '/{repo_name}/authors/{revision}/{f_path}',
1017 1018 controller='files', action='authors', revision='tip', f_path='',
1018 1019 conditions={'function': check_repo},
1019 1020 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1020 1021
1021 1022 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
1022 1023 controller='files', action='diff', f_path='',
1023 1024 conditions={'function': check_repo},
1024 1025 requirements=URL_NAME_REQUIREMENTS)
1025 1026
1026 1027 rmap.connect('files_diff_2way_home',
1027 1028 '/{repo_name}/diff-2way/{f_path}',
1028 1029 controller='files', action='diff_2way', f_path='',
1029 1030 conditions={'function': check_repo},
1030 1031 requirements=URL_NAME_REQUIREMENTS)
1031 1032
1032 1033 rmap.connect('files_rawfile_home',
1033 1034 '/{repo_name}/rawfile/{revision}/{f_path}',
1034 1035 controller='files', action='rawfile', revision='tip',
1035 1036 f_path='', conditions={'function': check_repo},
1036 1037 requirements=URL_NAME_REQUIREMENTS)
1037 1038
1038 1039 rmap.connect('files_raw_home',
1039 1040 '/{repo_name}/raw/{revision}/{f_path}',
1040 1041 controller='files', action='raw', revision='tip', f_path='',
1041 1042 conditions={'function': check_repo},
1042 1043 requirements=URL_NAME_REQUIREMENTS)
1043 1044
1044 1045 rmap.connect('files_render_home',
1045 1046 '/{repo_name}/render/{revision}/{f_path}',
1046 1047 controller='files', action='index', revision='tip', f_path='',
1047 1048 rendered=True, conditions={'function': check_repo},
1048 1049 requirements=URL_NAME_REQUIREMENTS)
1049 1050
1050 1051 rmap.connect('files_annotate_home',
1051 1052 '/{repo_name}/annotate/{revision}/{f_path}',
1052 1053 controller='files', action='index', revision='tip',
1053 1054 f_path='', annotate=True, conditions={'function': check_repo},
1054 1055 requirements=URL_NAME_REQUIREMENTS)
1055 1056
1056 1057 rmap.connect('files_edit',
1057 1058 '/{repo_name}/edit/{revision}/{f_path}',
1058 1059 controller='files', action='edit', revision='tip',
1059 1060 f_path='',
1060 1061 conditions={'function': check_repo, 'method': ['POST']},
1061 1062 requirements=URL_NAME_REQUIREMENTS)
1062 1063
1063 1064 rmap.connect('files_edit_home',
1064 1065 '/{repo_name}/edit/{revision}/{f_path}',
1065 1066 controller='files', action='edit_home', revision='tip',
1066 1067 f_path='', conditions={'function': check_repo},
1067 1068 requirements=URL_NAME_REQUIREMENTS)
1068 1069
1069 1070 rmap.connect('files_add',
1070 1071 '/{repo_name}/add/{revision}/{f_path}',
1071 1072 controller='files', action='add', revision='tip',
1072 1073 f_path='',
1073 1074 conditions={'function': check_repo, 'method': ['POST']},
1074 1075 requirements=URL_NAME_REQUIREMENTS)
1075 1076
1076 1077 rmap.connect('files_add_home',
1077 1078 '/{repo_name}/add/{revision}/{f_path}',
1078 1079 controller='files', action='add_home', revision='tip',
1079 1080 f_path='', conditions={'function': check_repo},
1080 1081 requirements=URL_NAME_REQUIREMENTS)
1081 1082
1082 1083 rmap.connect('files_delete',
1083 1084 '/{repo_name}/delete/{revision}/{f_path}',
1084 1085 controller='files', action='delete', revision='tip',
1085 1086 f_path='',
1086 1087 conditions={'function': check_repo, 'method': ['POST']},
1087 1088 requirements=URL_NAME_REQUIREMENTS)
1088 1089
1089 1090 rmap.connect('files_delete_home',
1090 1091 '/{repo_name}/delete/{revision}/{f_path}',
1091 1092 controller='files', action='delete_home', revision='tip',
1092 1093 f_path='', conditions={'function': check_repo},
1093 1094 requirements=URL_NAME_REQUIREMENTS)
1094 1095
1095 1096 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
1096 1097 controller='files', action='archivefile',
1097 1098 conditions={'function': check_repo},
1098 1099 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1099 1100
1100 1101 rmap.connect('files_nodelist_home',
1101 1102 '/{repo_name}/nodelist/{revision}/{f_path}',
1102 1103 controller='files', action='nodelist',
1103 1104 conditions={'function': check_repo},
1104 1105 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1105 1106
1106 1107 rmap.connect('files_nodetree_full',
1107 1108 '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
1108 1109 controller='files', action='nodetree_full',
1109 1110 conditions={'function': check_repo},
1110 1111 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1111 1112
1112 1113 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
1113 1114 controller='forks', action='fork_create',
1114 1115 conditions={'function': check_repo, 'method': ['POST']},
1115 1116 requirements=URL_NAME_REQUIREMENTS)
1116 1117
1117 1118 rmap.connect('repo_fork_home', '/{repo_name}/fork',
1118 1119 controller='forks', action='fork',
1119 1120 conditions={'function': check_repo},
1120 1121 requirements=URL_NAME_REQUIREMENTS)
1121 1122
1122 1123 rmap.connect('repo_forks_home', '/{repo_name}/forks',
1123 1124 controller='forks', action='forks',
1124 1125 conditions={'function': check_repo},
1125 1126 requirements=URL_NAME_REQUIREMENTS)
1126 1127
1127 1128 rmap.connect('repo_followers_home', '/{repo_name}/followers',
1128 1129 controller='followers', action='followers',
1129 1130 conditions={'function': check_repo},
1130 1131 requirements=URL_NAME_REQUIREMENTS)
1131 1132
1132 1133 # must be here for proper group/repo catching pattern
1133 1134 _connect_with_slash(
1134 1135 rmap, 'repo_group_home', '/{group_name}',
1135 1136 controller='home', action='index_repo_group',
1136 1137 conditions={'function': check_group},
1137 1138 requirements=URL_NAME_REQUIREMENTS)
1138 1139
1139 1140 # catch all, at the end
1140 1141 _connect_with_slash(
1141 1142 rmap, 'summary_home', '/{repo_name}', jsroute=True,
1142 1143 controller='summary', action='index',
1143 1144 conditions={'function': check_repo},
1144 1145 requirements=URL_NAME_REQUIREMENTS)
1145 1146
1146 1147 return rmap
1147 1148
1148 1149
1149 1150 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1150 1151 """
1151 1152 Connect a route with an optional trailing slash in `path`.
1152 1153 """
1153 1154 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1154 1155 mapper.connect(name, path, *args, **kwargs)
General Comments 0
You need to be logged in to leave comments. Login now