##// END OF EJS Templates
my_account: Remove oauth identities views from my_account controller.
johbo -
r26:3e99070f default
parent child Browse files
Show More
@@ -1,1112 +1,1106 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 from routes import Mapper
33 33
34 34 from rhodecode.config import routing_links
35 35
36 36 # prefix for non repository related links needs to be prefixed with `/`
37 37 ADMIN_PREFIX = '/_admin'
38 38
39 39 # Default requirements for URL parts
40 40 URL_NAME_REQUIREMENTS = {
41 41 # group name can have a slash in them, but they must not end with a slash
42 42 'group_name': r'.*?[^/]',
43 43 # repo names can have a slash in them, but they must not end with a slash
44 44 'repo_name': r'.*?[^/]',
45 45 # file path eats up everything at the end
46 46 'f_path': r'.*',
47 47 # reference types
48 48 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
49 49 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
50 50 }
51 51
52 52
53 53 def make_map(config):
54 54 """Create, configure and return the routes Mapper"""
55 55 rmap = Mapper(directory=config['pylons.paths']['controllers'],
56 56 always_scan=config['debug'])
57 57 rmap.minimization = False
58 58 rmap.explicit = False
59 59
60 60 from rhodecode.lib.utils2 import str2bool
61 61 from rhodecode.model import repo, repo_group
62 62
63 63 def check_repo(environ, match_dict):
64 64 """
65 65 check for valid repository for proper 404 handling
66 66
67 67 :param environ:
68 68 :param match_dict:
69 69 """
70 70 repo_name = match_dict.get('repo_name')
71 71
72 72 if match_dict.get('f_path'):
73 73 # fix for multiple initial slashes that causes errors
74 74 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
75 75 repo_model = repo.RepoModel()
76 76 by_name_match = repo_model.get_by_repo_name(repo_name)
77 77 # if we match quickly from database, short circuit the operation,
78 78 # and validate repo based on the type.
79 79 if by_name_match:
80 80 return True
81 81
82 82 by_id_match = repo_model.get_repo_by_id(repo_name)
83 83 if by_id_match:
84 84 repo_name = by_id_match.repo_name
85 85 match_dict['repo_name'] = repo_name
86 86 return True
87 87
88 88 return False
89 89
90 90 def check_group(environ, match_dict):
91 91 """
92 92 check for valid repository group path for proper 404 handling
93 93
94 94 :param environ:
95 95 :param match_dict:
96 96 """
97 97 repo_group_name = match_dict.get('group_name')
98 98 repo_group_model = repo_group.RepoGroupModel()
99 99 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
100 100 if by_name_match:
101 101 return True
102 102
103 103 return False
104 104
105 105 def check_user_group(environ, match_dict):
106 106 """
107 107 check for valid user group for proper 404 handling
108 108
109 109 :param environ:
110 110 :param match_dict:
111 111 """
112 112 return True
113 113
114 114 def check_int(environ, match_dict):
115 115 return match_dict.get('id').isdigit()
116 116
117 117 # The ErrorController route (handles 404/500 error pages); it should
118 118 # likely stay at the top, ensuring it can always be resolved
119 119 rmap.connect('/error/{action}', controller='error')
120 120 rmap.connect('/error/{action}/{id}', controller='error')
121 121
122 122 #==========================================================================
123 123 # CUSTOM ROUTES HERE
124 124 #==========================================================================
125 125
126 126 # MAIN PAGE
127 127 rmap.connect('home', '/', controller='home', action='index')
128 128 rmap.connect('repo_switcher_data', '/_repos_and_groups', controller='home',
129 129 action='repo_switcher_data')
130 130 rmap.connect('repo_list_data', '/_repos', controller='home',
131 131 action='repo_list_data')
132 132
133 133 rmap.connect('user_autocomplete_data', '/_users', controller='home',
134 134 action='user_autocomplete_data')
135 135 rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home',
136 136 action='user_group_autocomplete_data')
137 137
138 138 rmap.connect(
139 139 'user_profile', '/_profiles/{username}', controller='users',
140 140 action='user_profile')
141 141
142 142 # TODO: johbo: Static links, to be replaced by our redirection mechanism
143 143 rmap.connect('rst_help',
144 144 'http://docutils.sourceforge.net/docs/user/rst/quickref.html',
145 145 _static=True)
146 146 rmap.connect('markdown_help',
147 147 'http://daringfireball.net/projects/markdown/syntax',
148 148 _static=True)
149 149 rmap.connect('rhodecode_official', 'https://rhodecode.com', _static=True)
150 150 rmap.connect('rhodecode_support', 'https://rhodecode.com/help/', _static=True)
151 151 rmap.connect('rhodecode_translations', 'https://rhodecode.com/translate/enterprise', _static=True)
152 152 # TODO: anderson - making this a static link since redirect won't play
153 153 # nice with POST requests
154 154 rmap.connect('enterprise_license_convert_from_old',
155 155 'https://rhodecode.com/u/license-upgrade',
156 156 _static=True)
157 157
158 158 routing_links.connect_redirection_links(rmap)
159 159
160 160 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
161 161 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
162 162
163 163 # ADMIN REPOSITORY ROUTES
164 164 with rmap.submapper(path_prefix=ADMIN_PREFIX,
165 165 controller='admin/repos') as m:
166 166 m.connect('repos', '/repos',
167 167 action='create', conditions={'method': ['POST']})
168 168 m.connect('repos', '/repos',
169 169 action='index', conditions={'method': ['GET']})
170 170 m.connect('new_repo', '/create_repository',
171 171 action='create_repository', conditions={'method': ['GET']})
172 172 m.connect('/repos/{repo_name}',
173 173 action='update', conditions={'method': ['PUT'],
174 174 'function': check_repo},
175 175 requirements=URL_NAME_REQUIREMENTS)
176 176 m.connect('delete_repo', '/repos/{repo_name}',
177 177 action='delete', conditions={'method': ['DELETE']},
178 178 requirements=URL_NAME_REQUIREMENTS)
179 179 m.connect('repo', '/repos/{repo_name}',
180 180 action='show', conditions={'method': ['GET'],
181 181 'function': check_repo},
182 182 requirements=URL_NAME_REQUIREMENTS)
183 183
184 184 # ADMIN REPOSITORY GROUPS ROUTES
185 185 with rmap.submapper(path_prefix=ADMIN_PREFIX,
186 186 controller='admin/repo_groups') as m:
187 187 m.connect('repo_groups', '/repo_groups',
188 188 action='create', conditions={'method': ['POST']})
189 189 m.connect('repo_groups', '/repo_groups',
190 190 action='index', conditions={'method': ['GET']})
191 191 m.connect('new_repo_group', '/repo_groups/new',
192 192 action='new', conditions={'method': ['GET']})
193 193 m.connect('update_repo_group', '/repo_groups/{group_name}',
194 194 action='update', conditions={'method': ['PUT'],
195 195 'function': check_group},
196 196 requirements=URL_NAME_REQUIREMENTS)
197 197
198 198 # EXTRAS REPO GROUP ROUTES
199 199 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
200 200 action='edit',
201 201 conditions={'method': ['GET'], 'function': check_group},
202 202 requirements=URL_NAME_REQUIREMENTS)
203 203 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
204 204 action='edit',
205 205 conditions={'method': ['PUT'], 'function': check_group},
206 206 requirements=URL_NAME_REQUIREMENTS)
207 207
208 208 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
209 209 action='edit_repo_group_advanced',
210 210 conditions={'method': ['GET'], 'function': check_group},
211 211 requirements=URL_NAME_REQUIREMENTS)
212 212 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
213 213 action='edit_repo_group_advanced',
214 214 conditions={'method': ['PUT'], 'function': check_group},
215 215 requirements=URL_NAME_REQUIREMENTS)
216 216
217 217 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
218 218 action='edit_repo_group_perms',
219 219 conditions={'method': ['GET'], 'function': check_group},
220 220 requirements=URL_NAME_REQUIREMENTS)
221 221 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
222 222 action='update_perms',
223 223 conditions={'method': ['PUT'], 'function': check_group},
224 224 requirements=URL_NAME_REQUIREMENTS)
225 225
226 226 m.connect('delete_repo_group', '/repo_groups/{group_name}',
227 227 action='delete', conditions={'method': ['DELETE'],
228 228 'function': check_group},
229 229 requirements=URL_NAME_REQUIREMENTS)
230 230
231 231 # ADMIN USER ROUTES
232 232 with rmap.submapper(path_prefix=ADMIN_PREFIX,
233 233 controller='admin/users') as m:
234 234 m.connect('users', '/users',
235 235 action='create', conditions={'method': ['POST']})
236 236 m.connect('users', '/users',
237 237 action='index', conditions={'method': ['GET']})
238 238 m.connect('new_user', '/users/new',
239 239 action='new', conditions={'method': ['GET']})
240 240 m.connect('update_user', '/users/{user_id}',
241 241 action='update', conditions={'method': ['PUT']})
242 242 m.connect('delete_user', '/users/{user_id}',
243 243 action='delete', conditions={'method': ['DELETE']})
244 244 m.connect('edit_user', '/users/{user_id}/edit',
245 245 action='edit', conditions={'method': ['GET']})
246 246 m.connect('user', '/users/{user_id}',
247 247 action='show', conditions={'method': ['GET']})
248 248 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
249 249 action='reset_password', conditions={'method': ['POST']})
250 250 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
251 251 action='create_personal_repo_group', conditions={'method': ['POST']})
252 252
253 253 # EXTRAS USER ROUTES
254 254 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
255 255 action='edit_advanced', conditions={'method': ['GET']})
256 256 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
257 257 action='update_advanced', conditions={'method': ['PUT']})
258 258
259 259 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
260 260 action='edit_auth_tokens', conditions={'method': ['GET']})
261 261 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
262 262 action='add_auth_token', conditions={'method': ['PUT']})
263 263 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
264 264 action='delete_auth_token', conditions={'method': ['DELETE']})
265 265
266 266 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
267 267 action='edit_global_perms', conditions={'method': ['GET']})
268 268 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
269 269 action='update_global_perms', conditions={'method': ['PUT']})
270 270
271 271 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
272 272 action='edit_perms_summary', conditions={'method': ['GET']})
273 273
274 274 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
275 275 action='edit_emails', conditions={'method': ['GET']})
276 276 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
277 277 action='add_email', conditions={'method': ['PUT']})
278 278 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
279 279 action='delete_email', conditions={'method': ['DELETE']})
280 280
281 281 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
282 282 action='edit_ips', conditions={'method': ['GET']})
283 283 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
284 284 action='add_ip', conditions={'method': ['PUT']})
285 285 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
286 286 action='delete_ip', conditions={'method': ['DELETE']})
287 287
288 288 # ADMIN USER GROUPS REST ROUTES
289 289 with rmap.submapper(path_prefix=ADMIN_PREFIX,
290 290 controller='admin/user_groups') as m:
291 291 m.connect('users_groups', '/user_groups',
292 292 action='create', conditions={'method': ['POST']})
293 293 m.connect('users_groups', '/user_groups',
294 294 action='index', conditions={'method': ['GET']})
295 295 m.connect('new_users_group', '/user_groups/new',
296 296 action='new', conditions={'method': ['GET']})
297 297 m.connect('update_users_group', '/user_groups/{user_group_id}',
298 298 action='update', conditions={'method': ['PUT']})
299 299 m.connect('delete_users_group', '/user_groups/{user_group_id}',
300 300 action='delete', conditions={'method': ['DELETE']})
301 301 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
302 302 action='edit', conditions={'method': ['GET']},
303 303 function=check_user_group)
304 304
305 305 # EXTRAS USER GROUP ROUTES
306 306 m.connect('edit_user_group_global_perms', '/user_groups/{user_group_id}/edit/global_permissions',
307 307 action='edit_global_perms', conditions={'method': ['GET']})
308 308 m.connect('edit_user_group_global_perms', '/user_groups/{user_group_id}/edit/global_permissions',
309 309 action='update_global_perms', conditions={'method': ['PUT']})
310 310 m.connect('edit_user_group_perms_summary', '/user_groups/{user_group_id}/edit/permissions_summary',
311 311 action='edit_perms_summary', conditions={'method': ['GET']})
312 312
313 313 m.connect('edit_user_group_perms', '/user_groups/{user_group_id}/edit/permissions',
314 314 action='edit_perms', conditions={'method': ['GET']})
315 315 m.connect('edit_user_group_perms', '/user_groups/{user_group_id}/edit/permissions',
316 316 action='update_perms', conditions={'method': ['PUT']})
317 317
318 318 m.connect('edit_user_group_advanced', '/user_groups/{user_group_id}/edit/advanced',
319 319 action='edit_advanced', conditions={'method': ['GET']})
320 320
321 321 m.connect('edit_user_group_members', '/user_groups/{user_group_id}/edit/members',
322 322 action='edit_members', conditions={'method': ['GET']})
323 323
324 324 # ADMIN PERMISSIONS ROUTES
325 325 with rmap.submapper(path_prefix=ADMIN_PREFIX,
326 326 controller='admin/permissions') as m:
327 327 m.connect('admin_permissions_application', '/permissions/application',
328 328 action='permission_application_update', conditions={'method': ['POST']})
329 329 m.connect('admin_permissions_application', '/permissions/application',
330 330 action='permission_application', conditions={'method': ['GET']})
331 331
332 332 m.connect('admin_permissions_global', '/permissions/global',
333 333 action='permission_global_update', conditions={'method': ['POST']})
334 334 m.connect('admin_permissions_global', '/permissions/global',
335 335 action='permission_global', conditions={'method': ['GET']})
336 336
337 337 m.connect('admin_permissions_object', '/permissions/object',
338 338 action='permission_objects_update', conditions={'method': ['POST']})
339 339 m.connect('admin_permissions_object', '/permissions/object',
340 340 action='permission_objects', conditions={'method': ['GET']})
341 341
342 342 m.connect('admin_permissions_ips', '/permissions/ips',
343 343 action='permission_ips', conditions={'method': ['POST']})
344 344 m.connect('admin_permissions_ips', '/permissions/ips',
345 345 action='permission_ips', conditions={'method': ['GET']})
346 346
347 347 m.connect('admin_permissions_overview', '/permissions/overview',
348 348 action='permission_perms', conditions={'method': ['GET']})
349 349
350 350 # ADMIN DEFAULTS REST ROUTES
351 351 with rmap.submapper(path_prefix=ADMIN_PREFIX,
352 352 controller='admin/defaults') as m:
353 353 m.connect('admin_defaults_repositories', '/defaults/repositories',
354 354 action='update_repository_defaults', conditions={'method': ['POST']})
355 355 m.connect('admin_defaults_repositories', '/defaults/repositories',
356 356 action='index', conditions={'method': ['GET']})
357 357
358 358 # ADMIN DEBUG STYLE ROUTES
359 359 if str2bool(config.get('debug_style')):
360 360 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
361 361 controller='debug_style') as m:
362 362 m.connect('debug_style_home', '',
363 363 action='index', conditions={'method': ['GET']})
364 364 m.connect('debug_style_template', '/t/{t_path}',
365 365 action='template', conditions={'method': ['GET']})
366 366
367 367 # ADMIN SETTINGS ROUTES
368 368 with rmap.submapper(path_prefix=ADMIN_PREFIX,
369 369 controller='admin/settings') as m:
370 370
371 371 # default
372 372 m.connect('admin_settings', '/settings',
373 373 action='settings_global_update',
374 374 conditions={'method': ['POST']})
375 375 m.connect('admin_settings', '/settings',
376 376 action='settings_global', conditions={'method': ['GET']})
377 377
378 378 m.connect('admin_settings_vcs', '/settings/vcs',
379 379 action='settings_vcs_update',
380 380 conditions={'method': ['POST']})
381 381 m.connect('admin_settings_vcs', '/settings/vcs',
382 382 action='settings_vcs',
383 383 conditions={'method': ['GET']})
384 384 m.connect('admin_settings_vcs', '/settings/vcs',
385 385 action='delete_svn_pattern',
386 386 conditions={'method': ['DELETE']})
387 387
388 388 m.connect('admin_settings_mapping', '/settings/mapping',
389 389 action='settings_mapping_update',
390 390 conditions={'method': ['POST']})
391 391 m.connect('admin_settings_mapping', '/settings/mapping',
392 392 action='settings_mapping', conditions={'method': ['GET']})
393 393
394 394 m.connect('admin_settings_global', '/settings/global',
395 395 action='settings_global_update',
396 396 conditions={'method': ['POST']})
397 397 m.connect('admin_settings_global', '/settings/global',
398 398 action='settings_global', conditions={'method': ['GET']})
399 399
400 400 m.connect('admin_settings_visual', '/settings/visual',
401 401 action='settings_visual_update',
402 402 conditions={'method': ['POST']})
403 403 m.connect('admin_settings_visual', '/settings/visual',
404 404 action='settings_visual', conditions={'method': ['GET']})
405 405
406 406 m.connect('admin_settings_issuetracker',
407 407 '/settings/issue-tracker', action='settings_issuetracker',
408 408 conditions={'method': ['GET']})
409 409 m.connect('admin_settings_issuetracker_save',
410 410 '/settings/issue-tracker/save',
411 411 action='settings_issuetracker_save',
412 412 conditions={'method': ['POST']})
413 413 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
414 414 action='settings_issuetracker_test',
415 415 conditions={'method': ['POST']})
416 416 m.connect('admin_issuetracker_delete',
417 417 '/settings/issue-tracker/delete',
418 418 action='settings_issuetracker_delete',
419 419 conditions={'method': ['DELETE']})
420 420
421 421 m.connect('admin_settings_email', '/settings/email',
422 422 action='settings_email_update',
423 423 conditions={'method': ['POST']})
424 424 m.connect('admin_settings_email', '/settings/email',
425 425 action='settings_email', conditions={'method': ['GET']})
426 426
427 427 m.connect('admin_settings_hooks', '/settings/hooks',
428 428 action='settings_hooks_update',
429 429 conditions={'method': ['POST', 'DELETE']})
430 430 m.connect('admin_settings_hooks', '/settings/hooks',
431 431 action='settings_hooks', conditions={'method': ['GET']})
432 432
433 433 m.connect('admin_settings_search', '/settings/search',
434 434 action='settings_search', conditions={'method': ['GET']})
435 435
436 436 m.connect('admin_settings_system', '/settings/system',
437 437 action='settings_system', conditions={'method': ['GET']})
438 438
439 439 m.connect('admin_settings_system_update', '/settings/system/updates',
440 440 action='settings_system_update', conditions={'method': ['GET']})
441 441
442 442 m.connect('admin_settings_supervisor', '/settings/supervisor',
443 443 action='settings_supervisor', conditions={'method': ['GET']})
444 444 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
445 445 action='settings_supervisor_log', conditions={'method': ['GET']})
446 446
447 447 m.connect('admin_settings_labs', '/settings/labs',
448 448 action='settings_labs_update',
449 449 conditions={'method': ['POST']})
450 450 m.connect('admin_settings_labs', '/settings/labs',
451 451 action='settings_labs', conditions={'method': ['GET']})
452 452
453 453 m.connect('admin_settings_open_source', '/settings/open_source',
454 454 action='settings_open_source',
455 455 conditions={'method': ['GET']})
456 456
457 457 # ADMIN MY ACCOUNT
458 458 with rmap.submapper(path_prefix=ADMIN_PREFIX,
459 459 controller='admin/my_account') as m:
460 460
461 461 m.connect('my_account', '/my_account',
462 462 action='my_account', conditions={'method': ['GET']})
463 463 m.connect('my_account_edit', '/my_account/edit',
464 464 action='my_account_edit', conditions={'method': ['GET']})
465 465 m.connect('my_account', '/my_account',
466 466 action='my_account_update', conditions={'method': ['POST']})
467 467
468 468 m.connect('my_account_password', '/my_account/password',
469 469 action='my_account_password', conditions={'method': ['GET']})
470 470 m.connect('my_account_password', '/my_account/password',
471 471 action='my_account_password_update', conditions={'method': ['POST']})
472 472
473 473 m.connect('my_account_repos', '/my_account/repos',
474 474 action='my_account_repos', conditions={'method': ['GET']})
475 475
476 476 m.connect('my_account_watched', '/my_account/watched',
477 477 action='my_account_watched', conditions={'method': ['GET']})
478 478
479 479 m.connect('my_account_pullrequests', '/my_account/pull_requests',
480 480 action='my_account_pullrequests', conditions={'method': ['GET']})
481 481
482 482 m.connect('my_account_perms', '/my_account/perms',
483 483 action='my_account_perms', conditions={'method': ['GET']})
484 484
485 485 m.connect('my_account_emails', '/my_account/emails',
486 486 action='my_account_emails', conditions={'method': ['GET']})
487 487 m.connect('my_account_emails', '/my_account/emails',
488 488 action='my_account_emails_add', conditions={'method': ['POST']})
489 489 m.connect('my_account_emails', '/my_account/emails',
490 490 action='my_account_emails_delete', conditions={'method': ['DELETE']})
491 491
492 492 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
493 493 action='my_account_auth_tokens', conditions={'method': ['GET']})
494 494 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
495 495 action='my_account_auth_tokens_add', conditions={'method': ['POST']})
496 496 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
497 497 action='my_account_auth_tokens_delete', conditions={'method': ['DELETE']})
498 498
499 m.connect('my_account_oauth', '/my_account/oauth',
500 action='my_account_oauth', conditions={'method': ['GET']})
501 m.connect('my_account_oauth', '/my_account/oauth',
502 action='my_account_oauth_delete',
503 conditions={'method': ['DELETE']})
504
505 499 # NOTIFICATION REST ROUTES
506 500 with rmap.submapper(path_prefix=ADMIN_PREFIX,
507 501 controller='admin/notifications') as m:
508 502 m.connect('notifications', '/notifications',
509 503 action='index', conditions={'method': ['GET']})
510 504 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
511 505 action='mark_all_read', conditions={'method': ['POST']})
512 506
513 507 m.connect('/notifications/{notification_id}',
514 508 action='update', conditions={'method': ['PUT']})
515 509 m.connect('/notifications/{notification_id}',
516 510 action='delete', conditions={'method': ['DELETE']})
517 511 m.connect('notification', '/notifications/{notification_id}',
518 512 action='show', conditions={'method': ['GET']})
519 513
520 514 # ADMIN GIST
521 515 with rmap.submapper(path_prefix=ADMIN_PREFIX,
522 516 controller='admin/gists') as m:
523 517 m.connect('gists', '/gists',
524 518 action='create', conditions={'method': ['POST']})
525 519 m.connect('gists', '/gists',
526 520 action='index', conditions={'method': ['GET']})
527 521 m.connect('new_gist', '/gists/new',
528 522 action='new', conditions={'method': ['GET']})
529 523
530 524 m.connect('/gists/{gist_id}',
531 525 action='delete', conditions={'method': ['DELETE']})
532 526 m.connect('edit_gist', '/gists/{gist_id}/edit',
533 527 action='edit_form', conditions={'method': ['GET']})
534 528 m.connect('edit_gist', '/gists/{gist_id}/edit',
535 529 action='edit', conditions={'method': ['POST']})
536 530 m.connect(
537 531 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision',
538 532 action='check_revision', conditions={'method': ['GET']})
539 533
540 534 m.connect('gist', '/gists/{gist_id}',
541 535 action='show', conditions={'method': ['GET']})
542 536 m.connect('gist_rev', '/gists/{gist_id}/{revision}',
543 537 revision='tip',
544 538 action='show', conditions={'method': ['GET']})
545 539 m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}',
546 540 revision='tip',
547 541 action='show', conditions={'method': ['GET']})
548 542 m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}',
549 543 revision='tip',
550 544 action='show', conditions={'method': ['GET']},
551 545 requirements=URL_NAME_REQUIREMENTS)
552 546
553 547 # ADMIN MAIN PAGES
554 548 with rmap.submapper(path_prefix=ADMIN_PREFIX,
555 549 controller='admin/admin') as m:
556 550 m.connect('admin_home', '', action='index')
557 551 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
558 552 action='add_repo')
559 553 m.connect(
560 554 'pull_requests_global', '/pull_requests/{pull_request_id:[0-9]+}',
561 555 action='pull_requests')
562 556
563 557 # USER JOURNAL
564 558 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
565 559 controller='journal', action='index')
566 560 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
567 561 controller='journal', action='journal_rss')
568 562 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
569 563 controller='journal', action='journal_atom')
570 564
571 565 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
572 566 controller='journal', action='public_journal')
573 567
574 568 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
575 569 controller='journal', action='public_journal_rss')
576 570
577 571 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
578 572 controller='journal', action='public_journal_rss')
579 573
580 574 rmap.connect('public_journal_atom',
581 575 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
582 576 action='public_journal_atom')
583 577
584 578 rmap.connect('public_journal_atom_old',
585 579 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
586 580 action='public_journal_atom')
587 581
588 582 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
589 583 controller='journal', action='toggle_following',
590 584 conditions={'method': ['POST']})
591 585
592 586 # FULL TEXT SEARCH
593 587 rmap.connect('search', '%s/search' % (ADMIN_PREFIX,),
594 588 controller='search')
595 589 rmap.connect('search_repo_home', '/{repo_name}/search',
596 590 controller='search',
597 591 action='index',
598 592 conditions={'function': check_repo},
599 593 requirements=URL_NAME_REQUIREMENTS)
600 594
601 595 # LOGIN/LOGOUT/REGISTER/SIGN IN
602 596 rmap.connect('login_home', '%s/login' % (ADMIN_PREFIX,), controller='login',
603 597 action='index')
604 598
605 599 rmap.connect('logout_home', '%s/logout' % (ADMIN_PREFIX,), controller='login',
606 600 action='logout', conditions={'method': ['POST']})
607 601
608 602 rmap.connect('register', '%s/register' % (ADMIN_PREFIX,), controller='login',
609 603 action='register')
610 604
611 605 rmap.connect('reset_password', '%s/password_reset' % (ADMIN_PREFIX,),
612 606 controller='login', action='password_reset')
613 607
614 608 rmap.connect('reset_password_confirmation',
615 609 '%s/password_reset_confirmation' % (ADMIN_PREFIX,),
616 610 controller='login', action='password_reset_confirmation')
617 611
618 612 rmap.connect('social_auth',
619 613 '%s/social_auth/{provider_name}' % (ADMIN_PREFIX,),
620 614 controller='login', action='social_auth')
621 615
622 616 # FEEDS
623 617 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
624 618 controller='feed', action='rss',
625 619 conditions={'function': check_repo},
626 620 requirements=URL_NAME_REQUIREMENTS)
627 621
628 622 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
629 623 controller='feed', action='atom',
630 624 conditions={'function': check_repo},
631 625 requirements=URL_NAME_REQUIREMENTS)
632 626
633 627 #==========================================================================
634 628 # REPOSITORY ROUTES
635 629 #==========================================================================
636 630
637 631 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
638 632 controller='admin/repos', action='repo_creating',
639 633 requirements=URL_NAME_REQUIREMENTS)
640 634 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
641 635 controller='admin/repos', action='repo_check',
642 636 requirements=URL_NAME_REQUIREMENTS)
643 637
644 638 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
645 639 controller='summary', action='repo_stats',
646 640 conditions={'function': check_repo},
647 641 requirements=URL_NAME_REQUIREMENTS)
648 642
649 643 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
650 644 controller='summary', action='repo_refs_data',
651 645 requirements=URL_NAME_REQUIREMENTS)
652 646 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
653 647 controller='summary', action='repo_refs_changelog_data',
654 648 requirements=URL_NAME_REQUIREMENTS)
655 649
656 650 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
657 651 controller='changeset', revision='tip',
658 652 conditions={'function': check_repo},
659 653 requirements=URL_NAME_REQUIREMENTS)
660 654 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
661 655 controller='changeset', revision='tip', action='changeset_children',
662 656 conditions={'function': check_repo},
663 657 requirements=URL_NAME_REQUIREMENTS)
664 658 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
665 659 controller='changeset', revision='tip', action='changeset_parents',
666 660 conditions={'function': check_repo},
667 661 requirements=URL_NAME_REQUIREMENTS)
668 662
669 663 # repo edit options
670 664 rmap.connect('edit_repo', '/{repo_name}/settings',
671 665 controller='admin/repos', action='edit',
672 666 conditions={'method': ['GET'], 'function': check_repo},
673 667 requirements=URL_NAME_REQUIREMENTS)
674 668
675 669 rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions',
676 670 controller='admin/repos', action='edit_permissions',
677 671 conditions={'method': ['GET'], 'function': check_repo},
678 672 requirements=URL_NAME_REQUIREMENTS)
679 673 rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions',
680 674 controller='admin/repos', action='edit_permissions_update',
681 675 conditions={'method': ['PUT'], 'function': check_repo},
682 676 requirements=URL_NAME_REQUIREMENTS)
683 677
684 678 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
685 679 controller='admin/repos', action='edit_fields',
686 680 conditions={'method': ['GET'], 'function': check_repo},
687 681 requirements=URL_NAME_REQUIREMENTS)
688 682 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
689 683 controller='admin/repos', action='create_repo_field',
690 684 conditions={'method': ['PUT'], 'function': check_repo},
691 685 requirements=URL_NAME_REQUIREMENTS)
692 686 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
693 687 controller='admin/repos', action='delete_repo_field',
694 688 conditions={'method': ['DELETE'], 'function': check_repo},
695 689 requirements=URL_NAME_REQUIREMENTS)
696 690
697 691 rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
698 692 controller='admin/repos', action='edit_advanced',
699 693 conditions={'method': ['GET'], 'function': check_repo},
700 694 requirements=URL_NAME_REQUIREMENTS)
701 695
702 696 rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
703 697 controller='admin/repos', action='edit_advanced_locking',
704 698 conditions={'method': ['PUT'], 'function': check_repo},
705 699 requirements=URL_NAME_REQUIREMENTS)
706 700 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
707 701 controller='admin/repos', action='toggle_locking',
708 702 conditions={'method': ['GET'], 'function': check_repo},
709 703 requirements=URL_NAME_REQUIREMENTS)
710 704
711 705 rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal',
712 706 controller='admin/repos', action='edit_advanced_journal',
713 707 conditions={'method': ['PUT'], 'function': check_repo},
714 708 requirements=URL_NAME_REQUIREMENTS)
715 709
716 710 rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
717 711 controller='admin/repos', action='edit_advanced_fork',
718 712 conditions={'method': ['PUT'], 'function': check_repo},
719 713 requirements=URL_NAME_REQUIREMENTS)
720 714
721 715 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
722 716 controller='admin/repos', action='edit_caches_form',
723 717 conditions={'method': ['GET'], 'function': check_repo},
724 718 requirements=URL_NAME_REQUIREMENTS)
725 719 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
726 720 controller='admin/repos', action='edit_caches',
727 721 conditions={'method': ['PUT'], 'function': check_repo},
728 722 requirements=URL_NAME_REQUIREMENTS)
729 723
730 724 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
731 725 controller='admin/repos', action='edit_remote_form',
732 726 conditions={'method': ['GET'], 'function': check_repo},
733 727 requirements=URL_NAME_REQUIREMENTS)
734 728 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
735 729 controller='admin/repos', action='edit_remote',
736 730 conditions={'method': ['PUT'], 'function': check_repo},
737 731 requirements=URL_NAME_REQUIREMENTS)
738 732
739 733 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
740 734 controller='admin/repos', action='edit_statistics_form',
741 735 conditions={'method': ['GET'], 'function': check_repo},
742 736 requirements=URL_NAME_REQUIREMENTS)
743 737 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
744 738 controller='admin/repos', action='edit_statistics',
745 739 conditions={'method': ['PUT'], 'function': check_repo},
746 740 requirements=URL_NAME_REQUIREMENTS)
747 741 rmap.connect('repo_settings_issuetracker',
748 742 '/{repo_name}/settings/issue-tracker',
749 743 controller='admin/repos', action='repo_issuetracker',
750 744 conditions={'method': ['GET'], 'function': check_repo},
751 745 requirements=URL_NAME_REQUIREMENTS)
752 746 rmap.connect('repo_issuetracker_test',
753 747 '/{repo_name}/settings/issue-tracker/test',
754 748 controller='admin/repos', action='repo_issuetracker_test',
755 749 conditions={'method': ['POST'], 'function': check_repo},
756 750 requirements=URL_NAME_REQUIREMENTS)
757 751 rmap.connect('repo_issuetracker_delete',
758 752 '/{repo_name}/settings/issue-tracker/delete',
759 753 controller='admin/repos', action='repo_issuetracker_delete',
760 754 conditions={'method': ['DELETE'], 'function': check_repo},
761 755 requirements=URL_NAME_REQUIREMENTS)
762 756 rmap.connect('repo_issuetracker_save',
763 757 '/{repo_name}/settings/issue-tracker/save',
764 758 controller='admin/repos', action='repo_issuetracker_save',
765 759 conditions={'method': ['POST'], 'function': check_repo},
766 760 requirements=URL_NAME_REQUIREMENTS)
767 761 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
768 762 controller='admin/repos', action='repo_settings_vcs_update',
769 763 conditions={'method': ['POST'], 'function': check_repo},
770 764 requirements=URL_NAME_REQUIREMENTS)
771 765 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
772 766 controller='admin/repos', action='repo_settings_vcs',
773 767 conditions={'method': ['GET'], 'function': check_repo},
774 768 requirements=URL_NAME_REQUIREMENTS)
775 769 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
776 770 controller='admin/repos', action='repo_delete_svn_pattern',
777 771 conditions={'method': ['DELETE'], 'function': check_repo},
778 772 requirements=URL_NAME_REQUIREMENTS)
779 773
780 774 # still working url for backward compat.
781 775 rmap.connect('raw_changeset_home_depraced',
782 776 '/{repo_name}/raw-changeset/{revision}',
783 777 controller='changeset', action='changeset_raw',
784 778 revision='tip', conditions={'function': check_repo},
785 779 requirements=URL_NAME_REQUIREMENTS)
786 780
787 781 # new URLs
788 782 rmap.connect('changeset_raw_home',
789 783 '/{repo_name}/changeset-diff/{revision}',
790 784 controller='changeset', action='changeset_raw',
791 785 revision='tip', conditions={'function': check_repo},
792 786 requirements=URL_NAME_REQUIREMENTS)
793 787
794 788 rmap.connect('changeset_patch_home',
795 789 '/{repo_name}/changeset-patch/{revision}',
796 790 controller='changeset', action='changeset_patch',
797 791 revision='tip', conditions={'function': check_repo},
798 792 requirements=URL_NAME_REQUIREMENTS)
799 793
800 794 rmap.connect('changeset_download_home',
801 795 '/{repo_name}/changeset-download/{revision}',
802 796 controller='changeset', action='changeset_download',
803 797 revision='tip', conditions={'function': check_repo},
804 798 requirements=URL_NAME_REQUIREMENTS)
805 799
806 800 rmap.connect('changeset_comment',
807 801 '/{repo_name}/changeset/{revision}/comment',
808 802 controller='changeset', revision='tip', action='comment',
809 803 conditions={'function': check_repo},
810 804 requirements=URL_NAME_REQUIREMENTS)
811 805
812 806 rmap.connect('changeset_comment_preview',
813 807 '/{repo_name}/changeset/comment/preview',
814 808 controller='changeset', action='preview_comment',
815 809 conditions={'function': check_repo, 'method': ['POST']},
816 810 requirements=URL_NAME_REQUIREMENTS)
817 811
818 812 rmap.connect('changeset_comment_delete',
819 813 '/{repo_name}/changeset/comment/{comment_id}/delete',
820 814 controller='changeset', action='delete_comment',
821 815 conditions={'function': check_repo, 'method': ['DELETE']},
822 816 requirements=URL_NAME_REQUIREMENTS)
823 817
824 818 rmap.connect('changeset_info', '/changeset_info/{repo_name}/{revision}',
825 819 controller='changeset', action='changeset_info',
826 820 requirements=URL_NAME_REQUIREMENTS)
827 821
828 822 rmap.connect('compare_home',
829 823 '/{repo_name}/compare',
830 824 controller='compare', action='index',
831 825 conditions={'function': check_repo},
832 826 requirements=URL_NAME_REQUIREMENTS)
833 827
834 828 rmap.connect('compare_url',
835 829 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
836 830 controller='compare', action='compare',
837 831 conditions={'function': check_repo},
838 832 requirements=URL_NAME_REQUIREMENTS)
839 833
840 834 rmap.connect('pullrequest_home',
841 835 '/{repo_name}/pull-request/new', controller='pullrequests',
842 836 action='index', conditions={'function': check_repo,
843 837 'method': ['GET']},
844 838 requirements=URL_NAME_REQUIREMENTS)
845 839
846 840 rmap.connect('pullrequest',
847 841 '/{repo_name}/pull-request/new', controller='pullrequests',
848 842 action='create', conditions={'function': check_repo,
849 843 'method': ['POST']},
850 844 requirements=URL_NAME_REQUIREMENTS)
851 845
852 846 rmap.connect('pullrequest_repo_refs',
853 847 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
854 848 controller='pullrequests',
855 849 action='get_repo_refs',
856 850 conditions={'function': check_repo, 'method': ['GET']},
857 851 requirements=URL_NAME_REQUIREMENTS)
858 852
859 853 rmap.connect('pullrequest_repo_destinations',
860 854 '/{repo_name}/pull-request/repo-destinations',
861 855 controller='pullrequests',
862 856 action='get_repo_destinations',
863 857 conditions={'function': check_repo, 'method': ['GET']},
864 858 requirements=URL_NAME_REQUIREMENTS)
865 859
866 860 rmap.connect('pullrequest_show',
867 861 '/{repo_name}/pull-request/{pull_request_id}',
868 862 controller='pullrequests',
869 863 action='show', conditions={'function': check_repo,
870 864 'method': ['GET']},
871 865 requirements=URL_NAME_REQUIREMENTS)
872 866
873 867 rmap.connect('pullrequest_update',
874 868 '/{repo_name}/pull-request/{pull_request_id}',
875 869 controller='pullrequests',
876 870 action='update', conditions={'function': check_repo,
877 871 'method': ['PUT']},
878 872 requirements=URL_NAME_REQUIREMENTS)
879 873
880 874 rmap.connect('pullrequest_merge',
881 875 '/{repo_name}/pull-request/{pull_request_id}',
882 876 controller='pullrequests',
883 877 action='merge', conditions={'function': check_repo,
884 878 'method': ['POST']},
885 879 requirements=URL_NAME_REQUIREMENTS)
886 880
887 881 rmap.connect('pullrequest_delete',
888 882 '/{repo_name}/pull-request/{pull_request_id}',
889 883 controller='pullrequests',
890 884 action='delete', conditions={'function': check_repo,
891 885 'method': ['DELETE']},
892 886 requirements=URL_NAME_REQUIREMENTS)
893 887
894 888 rmap.connect('pullrequest_show_all',
895 889 '/{repo_name}/pull-request',
896 890 controller='pullrequests',
897 891 action='show_all', conditions={'function': check_repo,
898 892 'method': ['GET']},
899 893 requirements=URL_NAME_REQUIREMENTS)
900 894
901 895 rmap.connect('pullrequest_comment',
902 896 '/{repo_name}/pull-request-comment/{pull_request_id}',
903 897 controller='pullrequests',
904 898 action='comment', conditions={'function': check_repo,
905 899 'method': ['POST']},
906 900 requirements=URL_NAME_REQUIREMENTS)
907 901
908 902 rmap.connect('pullrequest_comment_delete',
909 903 '/{repo_name}/pull-request-comment/{comment_id}/delete',
910 904 controller='pullrequests', action='delete_comment',
911 905 conditions={'function': check_repo, 'method': ['DELETE']},
912 906 requirements=URL_NAME_REQUIREMENTS)
913 907
914 908 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
915 909 controller='summary', conditions={'function': check_repo},
916 910 requirements=URL_NAME_REQUIREMENTS)
917 911
918 912 rmap.connect('branches_home', '/{repo_name}/branches',
919 913 controller='branches', conditions={'function': check_repo},
920 914 requirements=URL_NAME_REQUIREMENTS)
921 915
922 916 rmap.connect('tags_home', '/{repo_name}/tags',
923 917 controller='tags', conditions={'function': check_repo},
924 918 requirements=URL_NAME_REQUIREMENTS)
925 919
926 920 rmap.connect('bookmarks_home', '/{repo_name}/bookmarks',
927 921 controller='bookmarks', conditions={'function': check_repo},
928 922 requirements=URL_NAME_REQUIREMENTS)
929 923
930 924 rmap.connect('changelog_home', '/{repo_name}/changelog',
931 925 controller='changelog', conditions={'function': check_repo},
932 926 requirements=URL_NAME_REQUIREMENTS)
933 927
934 928 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
935 929 controller='changelog', action='changelog_summary',
936 930 conditions={'function': check_repo},
937 931 requirements=URL_NAME_REQUIREMENTS)
938 932
939 933 rmap.connect('changelog_file_home', '/{repo_name}/changelog/{revision}/{f_path}',
940 934 controller='changelog', f_path=None,
941 935 conditions={'function': check_repo},
942 936 requirements=URL_NAME_REQUIREMENTS)
943 937
944 938 rmap.connect('changelog_details', '/{repo_name}/changelog_details/{cs}',
945 939 controller='changelog', action='changelog_details',
946 940 conditions={'function': check_repo},
947 941 requirements=URL_NAME_REQUIREMENTS)
948 942
949 943 rmap.connect('files_home',
950 944 '/{repo_name}/files/{revision}/{f_path}',
951 945 controller='files', revision='tip', f_path='',
952 946 conditions={'function': check_repo},
953 947 requirements=URL_NAME_REQUIREMENTS)
954 948
955 949 rmap.connect('files_home_simple_catchrev',
956 950 '/{repo_name}/files/{revision}',
957 951 controller='files', revision='tip', f_path='',
958 952 conditions={'function': check_repo},
959 953 requirements=URL_NAME_REQUIREMENTS)
960 954
961 955 rmap.connect('files_home_simple_catchall',
962 956 '/{repo_name}/files',
963 957 controller='files', revision='tip', f_path='',
964 958 conditions={'function': check_repo},
965 959 requirements=URL_NAME_REQUIREMENTS)
966 960
967 961 rmap.connect('files_history_home',
968 962 '/{repo_name}/history/{revision}/{f_path}',
969 963 controller='files', action='history', revision='tip', f_path='',
970 964 conditions={'function': check_repo},
971 965 requirements=URL_NAME_REQUIREMENTS)
972 966
973 967 rmap.connect('files_authors_home',
974 968 '/{repo_name}/authors/{revision}/{f_path}',
975 969 controller='files', action='authors', revision='tip', f_path='',
976 970 conditions={'function': check_repo},
977 971 requirements=URL_NAME_REQUIREMENTS)
978 972
979 973 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
980 974 controller='files', action='diff', f_path='',
981 975 conditions={'function': check_repo},
982 976 requirements=URL_NAME_REQUIREMENTS)
983 977
984 978 rmap.connect('files_diff_2way_home',
985 979 '/{repo_name}/diff-2way/{f_path}',
986 980 controller='files', action='diff_2way', f_path='',
987 981 conditions={'function': check_repo},
988 982 requirements=URL_NAME_REQUIREMENTS)
989 983
990 984 rmap.connect('files_rawfile_home',
991 985 '/{repo_name}/rawfile/{revision}/{f_path}',
992 986 controller='files', action='rawfile', revision='tip',
993 987 f_path='', conditions={'function': check_repo},
994 988 requirements=URL_NAME_REQUIREMENTS)
995 989
996 990 rmap.connect('files_raw_home',
997 991 '/{repo_name}/raw/{revision}/{f_path}',
998 992 controller='files', action='raw', revision='tip', f_path='',
999 993 conditions={'function': check_repo},
1000 994 requirements=URL_NAME_REQUIREMENTS)
1001 995
1002 996 rmap.connect('files_render_home',
1003 997 '/{repo_name}/render/{revision}/{f_path}',
1004 998 controller='files', action='index', revision='tip', f_path='',
1005 999 rendered=True, conditions={'function': check_repo},
1006 1000 requirements=URL_NAME_REQUIREMENTS)
1007 1001
1008 1002 rmap.connect('files_annotate_home',
1009 1003 '/{repo_name}/annotate/{revision}/{f_path}',
1010 1004 controller='files', action='index', revision='tip',
1011 1005 f_path='', annotate=True, conditions={'function': check_repo},
1012 1006 requirements=URL_NAME_REQUIREMENTS)
1013 1007
1014 1008 rmap.connect('files_edit',
1015 1009 '/{repo_name}/edit/{revision}/{f_path}',
1016 1010 controller='files', action='edit', revision='tip',
1017 1011 f_path='',
1018 1012 conditions={'function': check_repo, 'method': ['POST']},
1019 1013 requirements=URL_NAME_REQUIREMENTS)
1020 1014
1021 1015 rmap.connect('files_edit_home',
1022 1016 '/{repo_name}/edit/{revision}/{f_path}',
1023 1017 controller='files', action='edit_home', revision='tip',
1024 1018 f_path='', conditions={'function': check_repo},
1025 1019 requirements=URL_NAME_REQUIREMENTS)
1026 1020
1027 1021 rmap.connect('files_add',
1028 1022 '/{repo_name}/add/{revision}/{f_path}',
1029 1023 controller='files', action='add', revision='tip',
1030 1024 f_path='',
1031 1025 conditions={'function': check_repo, 'method': ['POST']},
1032 1026 requirements=URL_NAME_REQUIREMENTS)
1033 1027
1034 1028 rmap.connect('files_add_home',
1035 1029 '/{repo_name}/add/{revision}/{f_path}',
1036 1030 controller='files', action='add_home', revision='tip',
1037 1031 f_path='', conditions={'function': check_repo},
1038 1032 requirements=URL_NAME_REQUIREMENTS)
1039 1033
1040 1034 rmap.connect('files_delete',
1041 1035 '/{repo_name}/delete/{revision}/{f_path}',
1042 1036 controller='files', action='delete', revision='tip',
1043 1037 f_path='',
1044 1038 conditions={'function': check_repo, 'method': ['POST']},
1045 1039 requirements=URL_NAME_REQUIREMENTS)
1046 1040
1047 1041 rmap.connect('files_delete_home',
1048 1042 '/{repo_name}/delete/{revision}/{f_path}',
1049 1043 controller='files', action='delete_home', revision='tip',
1050 1044 f_path='', conditions={'function': check_repo},
1051 1045 requirements=URL_NAME_REQUIREMENTS)
1052 1046
1053 1047 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
1054 1048 controller='files', action='archivefile',
1055 1049 conditions={'function': check_repo},
1056 1050 requirements=URL_NAME_REQUIREMENTS)
1057 1051
1058 1052 rmap.connect('files_nodelist_home',
1059 1053 '/{repo_name}/nodelist/{revision}/{f_path}',
1060 1054 controller='files', action='nodelist',
1061 1055 conditions={'function': check_repo},
1062 1056 requirements=URL_NAME_REQUIREMENTS)
1063 1057
1064 1058 rmap.connect('files_metadata_list_home',
1065 1059 '/{repo_name}/metadata_list/{revision}/{f_path}',
1066 1060 controller='files', action='metadata_list',
1067 1061 conditions={'function': check_repo},
1068 1062 requirements=URL_NAME_REQUIREMENTS)
1069 1063
1070 1064 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
1071 1065 controller='forks', action='fork_create',
1072 1066 conditions={'function': check_repo, 'method': ['POST']},
1073 1067 requirements=URL_NAME_REQUIREMENTS)
1074 1068
1075 1069 rmap.connect('repo_fork_home', '/{repo_name}/fork',
1076 1070 controller='forks', action='fork',
1077 1071 conditions={'function': check_repo},
1078 1072 requirements=URL_NAME_REQUIREMENTS)
1079 1073
1080 1074 rmap.connect('repo_forks_home', '/{repo_name}/forks',
1081 1075 controller='forks', action='forks',
1082 1076 conditions={'function': check_repo},
1083 1077 requirements=URL_NAME_REQUIREMENTS)
1084 1078
1085 1079 rmap.connect('repo_followers_home', '/{repo_name}/followers',
1086 1080 controller='followers', action='followers',
1087 1081 conditions={'function': check_repo},
1088 1082 requirements=URL_NAME_REQUIREMENTS)
1089 1083
1090 1084 # must be here for proper group/repo catching pattern
1091 1085 _connect_with_slash(
1092 1086 rmap, 'repo_group_home', '/{group_name}',
1093 1087 controller='home', action='index_repo_group',
1094 1088 conditions={'function': check_group},
1095 1089 requirements=URL_NAME_REQUIREMENTS)
1096 1090
1097 1091 # catch all, at the end
1098 1092 _connect_with_slash(
1099 1093 rmap, 'summary_home', '/{repo_name}',
1100 1094 controller='summary', action='index',
1101 1095 conditions={'function': check_repo},
1102 1096 requirements=URL_NAME_REQUIREMENTS)
1103 1097
1104 1098 return rmap
1105 1099
1106 1100
1107 1101 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1108 1102 """
1109 1103 Connect a route with an optional trailing slash in `path`.
1110 1104 """
1111 1105 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1112 1106 mapper.connect(name, path, *args, **kwargs)
@@ -1,373 +1,348 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2013-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 """
23 23 my account controller for RhodeCode admin
24 24 """
25 25
26 26 import logging
27 27
28 28 import formencode
29 29 from formencode import htmlfill
30 30 from pylons import request, tmpl_context as c, url, session
31 31 from pylons.controllers.util import redirect
32 32 from pylons.i18n.translation import _
33 33 from sqlalchemy.orm import joinedload
34 34
35 35 from rhodecode.lib import helpers as h
36 36 from rhodecode.lib import auth
37 37 from rhodecode.lib.auth import (
38 38 LoginRequired, NotAnonymous, AuthUser, generate_auth_token)
39 39 from rhodecode.lib.base import BaseController, render
40 40 from rhodecode.lib.utils2 import safe_int, md5
41 41 from rhodecode.lib.ext_json import json
42 from rhodecode.model.db import (Repository, PullRequest, PullRequestReviewers,
43 UserEmailMap, User, UserFollowing,
44 ExternalIdentity)
42 from rhodecode.model.db import (
43 Repository, PullRequest, PullRequestReviewers, UserEmailMap, User,
44 UserFollowing)
45 45 from rhodecode.model.forms import UserForm, PasswordChangeForm
46 46 from rhodecode.model.scm import RepoList
47 47 from rhodecode.model.user import UserModel
48 48 from rhodecode.model.repo import RepoModel
49 49 from rhodecode.model.auth_token import AuthTokenModel
50 50 from rhodecode.model.meta import Session
51 from rhodecode.model.settings import SettingsModel
52 51
53 52 log = logging.getLogger(__name__)
54 53
55 54
56 55 class MyAccountController(BaseController):
57 56 """REST Controller styled on the Atom Publishing Protocol"""
58 57 # To properly map this controller, ensure your config/routing.py
59 58 # file has a resource setup:
60 59 # map.resource('setting', 'settings', controller='admin/settings',
61 60 # path_prefix='/admin', name_prefix='admin_')
62 61
63 62 @LoginRequired()
64 63 @NotAnonymous()
65 64 def __before__(self):
66 65 super(MyAccountController, self).__before__()
67 66
68 67 def __load_data(self):
69 68 c.user = User.get(c.rhodecode_user.user_id)
70 69 if c.user.username == User.DEFAULT_USER:
71 70 h.flash(_("You can't edit this user since it's"
72 71 " crucial for entire application"), category='warning')
73 72 return redirect(url('users'))
74 73
75 74 def _load_my_repos_data(self, watched=False):
76 75 if watched:
77 76 admin = False
78 77 follows_repos = Session().query(UserFollowing)\
79 78 .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
80 79 .options(joinedload(UserFollowing.follows_repository))\
81 80 .all()
82 81 repo_list = [x.follows_repository for x in follows_repos]
83 82 else:
84 83 admin = True
85 84 repo_list = Repository.get_all_repos(
86 85 user_id=c.rhodecode_user.user_id)
87 86 repo_list = RepoList(repo_list, perm_set=[
88 87 'repository.read', 'repository.write', 'repository.admin'])
89 88
90 89 repos_data = RepoModel().get_repos_as_dict(
91 90 repo_list=repo_list, admin=admin)
92 91 # json used to render the grid
93 92 return json.dumps(repos_data)
94 93
95 94 @auth.CSRFRequired()
96 95 def my_account_update(self):
97 96 """
98 97 POST /_admin/my_account Updates info of my account
99 98 """
100 99 # url('my_account')
101 100 c.active = 'profile_edit'
102 101 self.__load_data()
103 102 c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id,
104 103 ip_addr=self.ip_addr)
105 104 c.extern_type = c.user.extern_type
106 105 c.extern_name = c.user.extern_name
107 106
108 107 defaults = c.user.get_dict()
109 108 update = False
110 109 _form = UserForm(edit=True,
111 110 old_data={'user_id': c.rhodecode_user.user_id,
112 111 'email': c.rhodecode_user.email})()
113 112 form_result = {}
114 113 try:
115 114 post_data = dict(request.POST)
116 115 post_data['new_password'] = ''
117 116 post_data['password_confirmation'] = ''
118 117 form_result = _form.to_python(post_data)
119 118 # skip updating those attrs for my account
120 119 skip_attrs = ['admin', 'active', 'extern_type', 'extern_name',
121 120 'new_password', 'password_confirmation']
122 121 # TODO: plugin should define if username can be updated
123 122 if c.extern_type != "rhodecode":
124 123 # forbid updating username for external accounts
125 124 skip_attrs.append('username')
126 125
127 126 UserModel().update_user(
128 127 c.rhodecode_user.user_id, skip_attrs=skip_attrs, **form_result)
129 128 h.flash(_('Your account was updated successfully'),
130 129 category='success')
131 130 Session().commit()
132 131 update = True
133 132
134 133 except formencode.Invalid as errors:
135 134 return htmlfill.render(
136 135 render('admin/my_account/my_account.html'),
137 136 defaults=errors.value,
138 137 errors=errors.error_dict or {},
139 138 prefix_error=False,
140 139 encoding="UTF-8",
141 140 force_defaults=False)
142 141 except Exception:
143 142 log.exception("Exception updating user")
144 143 h.flash(_('Error occurred during update of user %s')
145 144 % form_result.get('username'), category='error')
146 145
147 146 if update:
148 147 return redirect('my_account')
149 148
150 149 return htmlfill.render(
151 150 render('admin/my_account/my_account.html'),
152 151 defaults=defaults,
153 152 encoding="UTF-8",
154 153 force_defaults=False
155 154 )
156 155
157 156 def my_account(self):
158 157 """
159 158 GET /_admin/my_account Displays info about my account
160 159 """
161 160 # url('my_account')
162 161 c.active = 'profile'
163 162 self.__load_data()
164 163
165 164 defaults = c.user.get_dict()
166 165 return htmlfill.render(
167 166 render('admin/my_account/my_account.html'),
168 167 defaults=defaults, encoding="UTF-8", force_defaults=False)
169 168
170 169 def my_account_edit(self):
171 170 """
172 171 GET /_admin/my_account/edit Displays edit form of my account
173 172 """
174 173 c.active = 'profile_edit'
175 174 self.__load_data()
176 175 c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id,
177 176 ip_addr=self.ip_addr)
178 177 c.extern_type = c.user.extern_type
179 178 c.extern_name = c.user.extern_name
180 179
181 180 defaults = c.user.get_dict()
182 181 return htmlfill.render(
183 182 render('admin/my_account/my_account.html'),
184 183 defaults=defaults,
185 184 encoding="UTF-8",
186 185 force_defaults=False
187 186 )
188 187
189 188 @auth.CSRFRequired()
190 189 def my_account_password_update(self):
191 190 c.active = 'password'
192 191 self.__load_data()
193 192 _form = PasswordChangeForm(c.rhodecode_user.username)()
194 193 try:
195 194 form_result = _form.to_python(request.POST)
196 195 UserModel().update_user(c.rhodecode_user.user_id, **form_result)
197 196 instance = c.rhodecode_user.get_instance()
198 197 instance.update_userdata(force_password_change=False)
199 198 Session().commit()
200 199 session.setdefault('rhodecode_user', {}).update(
201 200 {'password': md5(instance.password)})
202 201 session.save()
203 202 h.flash(_("Successfully updated password"), category='success')
204 203 except formencode.Invalid as errors:
205 204 return htmlfill.render(
206 205 render('admin/my_account/my_account.html'),
207 206 defaults=errors.value,
208 207 errors=errors.error_dict or {},
209 208 prefix_error=False,
210 209 encoding="UTF-8",
211 210 force_defaults=False)
212 211 except Exception:
213 212 log.exception("Exception updating password")
214 213 h.flash(_('Error occurred during update of user password'),
215 214 category='error')
216 215 return render('admin/my_account/my_account.html')
217 216
218 217 def my_account_password(self):
219 218 c.active = 'password'
220 219 self.__load_data()
221 220 return render('admin/my_account/my_account.html')
222 221
223 222 def my_account_repos(self):
224 223 c.active = 'repos'
225 224 self.__load_data()
226 225
227 226 # json used to render the grid
228 227 c.data = self._load_my_repos_data()
229 228 return render('admin/my_account/my_account.html')
230 229
231 230 def my_account_watched(self):
232 231 c.active = 'watched'
233 232 self.__load_data()
234 233
235 234 # json used to render the grid
236 235 c.data = self._load_my_repos_data(watched=True)
237 236 return render('admin/my_account/my_account.html')
238 237
239 238 def my_account_perms(self):
240 239 c.active = 'perms'
241 240 self.__load_data()
242 241 c.perm_user = AuthUser(user_id=c.rhodecode_user.user_id,
243 242 ip_addr=self.ip_addr)
244 243
245 244 return render('admin/my_account/my_account.html')
246 245
247 246 def my_account_emails(self):
248 247 c.active = 'emails'
249 248 self.__load_data()
250 249
251 250 c.user_email_map = UserEmailMap.query()\
252 251 .filter(UserEmailMap.user == c.user).all()
253 252 return render('admin/my_account/my_account.html')
254 253
255 254 @auth.CSRFRequired()
256 255 def my_account_emails_add(self):
257 256 email = request.POST.get('new_email')
258 257
259 258 try:
260 259 UserModel().add_extra_email(c.rhodecode_user.user_id, email)
261 260 Session().commit()
262 261 h.flash(_("Added new email address `%s` for user account") % email,
263 262 category='success')
264 263 except formencode.Invalid as error:
265 264 msg = error.error_dict['email']
266 265 h.flash(msg, category='error')
267 266 except Exception:
268 267 log.exception("Exception in my_account_emails")
269 268 h.flash(_('An error occurred during email saving'),
270 269 category='error')
271 270 return redirect(url('my_account_emails'))
272 271
273 272 @auth.CSRFRequired()
274 273 def my_account_emails_delete(self):
275 274 email_id = request.POST.get('del_email_id')
276 275 user_model = UserModel()
277 276 user_model.delete_extra_email(c.rhodecode_user.user_id, email_id)
278 277 Session().commit()
279 278 h.flash(_("Removed email address from user account"),
280 279 category='success')
281 280 return redirect(url('my_account_emails'))
282 281
283 282 def my_account_pullrequests(self):
284 283 c.active = 'pullrequests'
285 284 self.__load_data()
286 285 c.show_closed = request.GET.get('pr_show_closed')
287 286
288 287 def _filter(pr):
289 288 s = sorted(pr, key=lambda o: o.created_on, reverse=True)
290 289 if not c.show_closed:
291 290 s = filter(lambda p: p.status != PullRequest.STATUS_CLOSED, s)
292 291 return s
293 292
294 293 c.my_pull_requests = _filter(
295 294 PullRequest.query().filter(
296 295 PullRequest.user_id == c.rhodecode_user.user_id).all())
297 296 my_prs = [
298 297 x.pull_request for x in PullRequestReviewers.query().filter(
299 298 PullRequestReviewers.user_id == c.rhodecode_user.user_id).all()]
300 299 c.participate_in_pull_requests = _filter(my_prs)
301 300 return render('admin/my_account/my_account.html')
302 301
303 302 def my_account_auth_tokens(self):
304 303 c.active = 'auth_tokens'
305 304 self.__load_data()
306 305 show_expired = True
307 306 c.lifetime_values = [
308 307 (str(-1), _('forever')),
309 308 (str(5), _('5 minutes')),
310 309 (str(60), _('1 hour')),
311 310 (str(60 * 24), _('1 day')),
312 311 (str(60 * 24 * 30), _('1 month')),
313 312 ]
314 313 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
315 314 c.role_values = [(x, AuthTokenModel.cls._get_role_name(x))
316 315 for x in AuthTokenModel.cls.ROLES]
317 316 c.role_options = [(c.role_values, _("Role"))]
318 317 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
319 318 c.rhodecode_user.user_id, show_expired=show_expired)
320 319 return render('admin/my_account/my_account.html')
321 320
322 321 @auth.CSRFRequired()
323 322 def my_account_auth_tokens_add(self):
324 323 lifetime = safe_int(request.POST.get('lifetime'), -1)
325 324 description = request.POST.get('description')
326 325 role = request.POST.get('role')
327 326 AuthTokenModel().create(c.rhodecode_user.user_id, description, lifetime,
328 327 role)
329 328 Session().commit()
330 329 h.flash(_("Auth token successfully created"), category='success')
331 330 return redirect(url('my_account_auth_tokens'))
332 331
333 332 @auth.CSRFRequired()
334 333 def my_account_auth_tokens_delete(self):
335 334 auth_token = request.POST.get('del_auth_token')
336 335 user_id = c.rhodecode_user.user_id
337 336 if request.POST.get('del_auth_token_builtin'):
338 337 user = User.get(user_id)
339 338 if user:
340 339 user.api_key = generate_auth_token(user.username)
341 340 Session().add(user)
342 341 Session().commit()
343 342 h.flash(_("Auth token successfully reset"), category='success')
344 343 elif auth_token:
345 344 AuthTokenModel().delete(auth_token, c.rhodecode_user.user_id)
346 345 Session().commit()
347 346 h.flash(_("Auth token successfully deleted"), category='success')
348 347
349 348 return redirect(url('my_account_auth_tokens'))
350
351 def my_account_oauth(self):
352 c.active = 'oauth'
353 self.__load_data()
354 c.user_oauth_tokens = ExternalIdentity().by_local_user_id(
355 c.rhodecode_user.user_id).all()
356 settings = SettingsModel().get_all_settings()
357 c.social_plugins = SettingsModel().list_enabled_social_plugins(
358 settings)
359 return render('admin/my_account/my_account.html')
360
361 @auth.CSRFRequired()
362 def my_account_oauth_delete(self):
363 token = ExternalIdentity.by_external_id_and_provider(
364 request.params.get('external_id'),
365 request.params.get('provider_name'),
366 local_user_id=c.rhodecode_user.user_id
367 )
368 if token:
369 Session().delete(token)
370 Session().commit()
371 h.flash(_("OAuth token successfully deleted"), category='success')
372
373 return redirect(url('my_account_oauth'))
@@ -1,47 +1,51 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('My account')} ${c.rhodecode_user.username}
6 6 %if c.rhodecode_name:
7 7 &middot; ${h.branding(c.rhodecode_name)}
8 8 %endif
9 9 </%def>
10 10
11 11 <%def name="breadcrumbs_links()">
12 12 ${_('My Account')}
13 13 </%def>
14 14
15 15 <%def name="menu_bar_nav()">
16 16 ${self.menu_items(active='admin')}
17 17 </%def>
18 18
19 19 <%def name="main()">
20 20 <div class="box">
21 21 <div class="title">
22 22 ${self.breadcrumbs()}
23 23 </div>
24 24
25 25 <div class="sidebar-col-wrapper scw-small">
26 26 ##main
27 27 <div class="sidebar">
28 28 <ul class="nav nav-pills nav-stacked">
29 29 <li class="${'active' if c.active=='profile' or c.active=='profile_edit' else ''}"><a href="${h.url('my_account')}">${_('My Profile')}</a></li>
30 30 <li class="${'active' if c.active=='password' else ''}"><a href="${h.url('my_account_password')}">${_('Password')}</a></li>
31 31 <li class="${'active' if c.active=='auth_tokens' else ''}"><a href="${h.url('my_account_auth_tokens')}">${_('Auth Tokens')}</a></li>
32 <li class="${'active' if c.active=='oauth' else ''}"><a href="${h.url('my_account_oauth')}">${_('OAuth Identities')}</a></li>
32 ## TODO: Find a better integration of oauth views into navigation.
33 %try:
34 <li class="${'active' if c.active=='oauth' else ''}"><a href="${h.route_path('my_account_oauth')}">${_('OAuth Identities')}</a></li>
35 %except KeyError:
36 %endtry
33 37 <li class="${'active' if c.active=='emails' else ''}"><a href="${h.url('my_account_emails')}">${_('My Emails')}</a></li>
34 38 <li class="${'active' if c.active=='repos' else ''}"><a href="${h.url('my_account_repos')}">${_('My Repositories')}</a></li>
35 39 <li class="${'active' if c.active=='watched' else ''}"><a href="${h.url('my_account_watched')}">${_('Watched')}</a></li>
36 40 <li class="${'active' if c.active=='pullrequests' else ''}"><a href="${h.url('my_account_pullrequests')}">${_('Pull Requests')}</a></li>
37 41 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('my_account_perms')}">${_('My Permissions')}</a></li>
38 42 </ul>
39 43 </div>
40 44
41 45 <div class="main-content-full-width">
42 46 <%include file="/admin/my_account/my_account_${c.active}.html"/>
43 47 </div>
44 48 </div>
45 49 </div>
46 50
47 51 </%def>
General Comments 0
You need to be logged in to leave comments. Login now