##// END OF EJS Templates
Added quick links for editing permissions for users from permission overview
marcink -
r2631:f597cfb4 beta
parent child Browse files
Show More
@@ -1,573 +1,572
1 1 """
2 2 Routes configuration
3 3
4 4 The more specific and detailed routes should be defined first so they
5 5 may take precedent over the more generic routes. For more information
6 6 refer to the routes manual at http://routes.groovie.org/docs/
7 7 """
8 8 from __future__ import with_statement
9 9 from routes import Mapper
10 10
11 11 # prefix for non repository related links needs to be prefixed with `/`
12 12 ADMIN_PREFIX = '/_admin'
13 13
14 14
15 15 def make_map(config):
16 16 """Create, configure and return the routes Mapper"""
17 17 rmap = Mapper(directory=config['pylons.paths']['controllers'],
18 18 always_scan=config['debug'])
19 19 rmap.minimization = False
20 20 rmap.explicit = False
21 21
22 22 from rhodecode.lib.utils import is_valid_repo
23 23 from rhodecode.lib.utils import is_valid_repos_group
24 24
25 25 def check_repo(environ, match_dict):
26 26 """
27 27 check for valid repository for proper 404 handling
28 28
29 29 :param environ:
30 30 :param match_dict:
31 31 """
32 32 from rhodecode.model.db import Repository
33 33 repo_name = match_dict.get('repo_name')
34 34
35 35 try:
36 36 by_id = repo_name.split('_')
37 37 if len(by_id) == 2 and by_id[1].isdigit():
38 38 repo_name = Repository.get(by_id[1]).repo_name
39 39 match_dict['repo_name'] = repo_name
40 40 except:
41 41 pass
42 42
43 43 return is_valid_repo(repo_name, config['base_path'])
44 44
45 45 def check_group(environ, match_dict):
46 46 """
47 47 check for valid repositories group for proper 404 handling
48 48
49 49 :param environ:
50 50 :param match_dict:
51 51 """
52 52 repos_group_name = match_dict.get('group_name')
53 53
54 54 return is_valid_repos_group(repos_group_name, config['base_path'])
55 55
56 56 def check_int(environ, match_dict):
57 57 return match_dict.get('id').isdigit()
58 58
59 59 # The ErrorController route (handles 404/500 error pages); it should
60 60 # likely stay at the top, ensuring it can always be resolved
61 61 rmap.connect('/error/{action}', controller='error')
62 62 rmap.connect('/error/{action}/{id}', controller='error')
63 63
64 64 #==========================================================================
65 65 # CUSTOM ROUTES HERE
66 66 #==========================================================================
67 67
68 68 #MAIN PAGE
69 69 rmap.connect('home', '/', controller='home', action='index')
70 70 rmap.connect('repo_switcher', '/repos', controller='home',
71 71 action='repo_switcher')
72 72 rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*}',
73 73 controller='home', action='branch_tag_switcher')
74 74 rmap.connect('bugtracker',
75 75 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
76 76 _static=True)
77 77 rmap.connect('rst_help',
78 78 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
79 79 _static=True)
80 80 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
81 81
82 82 #ADMIN REPOSITORY REST ROUTES
83 83 with rmap.submapper(path_prefix=ADMIN_PREFIX,
84 84 controller='admin/repos') as m:
85 85 m.connect("repos", "/repos",
86 86 action="create", conditions=dict(method=["POST"]))
87 87 m.connect("repos", "/repos",
88 88 action="index", conditions=dict(method=["GET"]))
89 89 m.connect("formatted_repos", "/repos.{format}",
90 90 action="index",
91 91 conditions=dict(method=["GET"]))
92 92 m.connect("new_repo", "/repos/new",
93 93 action="new", conditions=dict(method=["GET"]))
94 94 m.connect("formatted_new_repo", "/repos/new.{format}",
95 95 action="new", conditions=dict(method=["GET"]))
96 96 m.connect("/repos/{repo_name:.*}",
97 97 action="update", conditions=dict(method=["PUT"],
98 98 function=check_repo))
99 99 m.connect("/repos/{repo_name:.*}",
100 100 action="delete", conditions=dict(method=["DELETE"],
101 101 function=check_repo))
102 102 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
103 103 action="edit", conditions=dict(method=["GET"],
104 104 function=check_repo))
105 105 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
106 106 action="edit", conditions=dict(method=["GET"],
107 107 function=check_repo))
108 108 m.connect("repo", "/repos/{repo_name:.*}",
109 109 action="show", conditions=dict(method=["GET"],
110 110 function=check_repo))
111 111 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
112 112 action="show", conditions=dict(method=["GET"],
113 113 function=check_repo))
114 114 #ajax delete repo perm user
115 115 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
116 116 action="delete_perm_user",
117 117 conditions=dict(method=["DELETE"], function=check_repo))
118 118
119 119 #ajax delete repo perm users_group
120 120 m.connect('delete_repo_users_group',
121 121 "/repos_delete_users_group/{repo_name:.*}",
122 122 action="delete_perm_users_group",
123 123 conditions=dict(method=["DELETE"], function=check_repo))
124 124
125 125 #settings actions
126 126 m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
127 127 action="repo_stats", conditions=dict(method=["DELETE"],
128 128 function=check_repo))
129 129 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
130 130 action="repo_cache", conditions=dict(method=["DELETE"],
131 131 function=check_repo))
132 132 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*}",
133 133 action="repo_public_journal", conditions=dict(method=["PUT"],
134 134 function=check_repo))
135 135 m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
136 136 action="repo_pull", conditions=dict(method=["PUT"],
137 137 function=check_repo))
138 138 m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*}",
139 139 action="repo_as_fork", conditions=dict(method=["PUT"],
140 140 function=check_repo))
141 141
142 142 with rmap.submapper(path_prefix=ADMIN_PREFIX,
143 143 controller='admin/repos_groups') as m:
144 144 m.connect("repos_groups", "/repos_groups",
145 145 action="create", conditions=dict(method=["POST"]))
146 146 m.connect("repos_groups", "/repos_groups",
147 147 action="index", conditions=dict(method=["GET"]))
148 148 m.connect("formatted_repos_groups", "/repos_groups.{format}",
149 149 action="index", conditions=dict(method=["GET"]))
150 150 m.connect("new_repos_group", "/repos_groups/new",
151 151 action="new", conditions=dict(method=["GET"]))
152 152 m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
153 153 action="new", conditions=dict(method=["GET"]))
154 154 m.connect("update_repos_group", "/repos_groups/{id}",
155 155 action="update", conditions=dict(method=["PUT"],
156 156 function=check_int))
157 157 m.connect("delete_repos_group", "/repos_groups/{id}",
158 158 action="delete", conditions=dict(method=["DELETE"],
159 159 function=check_int))
160 160 m.connect("edit_repos_group", "/repos_groups/{id}/edit",
161 action="edit", conditions=dict(method=["GET"],
162 function=check_int))
161 action="edit", conditions=dict(method=["GET"],))
163 162 m.connect("formatted_edit_repos_group",
164 163 "/repos_groups/{id}.{format}/edit",
165 164 action="edit", conditions=dict(method=["GET"],
166 165 function=check_int))
167 166 m.connect("repos_group", "/repos_groups/{id}",
168 167 action="show", conditions=dict(method=["GET"],
169 168 function=check_int))
170 169 m.connect("formatted_repos_group", "/repos_groups/{id}.{format}",
171 170 action="show", conditions=dict(method=["GET"],
172 171 function=check_int))
173 172 # ajax delete repos group perm user
174 173 m.connect('delete_repos_group_user_perm',
175 174 "/delete_repos_group_user_perm/{group_name:.*}",
176 175 action="delete_repos_group_user_perm",
177 176 conditions=dict(method=["DELETE"], function=check_group))
178 177
179 178 # ajax delete repos group perm users_group
180 179 m.connect('delete_repos_group_users_group_perm',
181 180 "/delete_repos_group_users_group_perm/{group_name:.*}",
182 181 action="delete_repos_group_users_group_perm",
183 182 conditions=dict(method=["DELETE"], function=check_group))
184 183
185 184 #ADMIN USER REST ROUTES
186 185 with rmap.submapper(path_prefix=ADMIN_PREFIX,
187 186 controller='admin/users') as m:
188 187 m.connect("users", "/users",
189 188 action="create", conditions=dict(method=["POST"]))
190 189 m.connect("users", "/users",
191 190 action="index", conditions=dict(method=["GET"]))
192 191 m.connect("formatted_users", "/users.{format}",
193 192 action="index", conditions=dict(method=["GET"]))
194 193 m.connect("new_user", "/users/new",
195 194 action="new", conditions=dict(method=["GET"]))
196 195 m.connect("formatted_new_user", "/users/new.{format}",
197 196 action="new", conditions=dict(method=["GET"]))
198 197 m.connect("update_user", "/users/{id}",
199 198 action="update", conditions=dict(method=["PUT"]))
200 199 m.connect("delete_user", "/users/{id}",
201 200 action="delete", conditions=dict(method=["DELETE"]))
202 201 m.connect("edit_user", "/users/{id}/edit",
203 202 action="edit", conditions=dict(method=["GET"]))
204 203 m.connect("formatted_edit_user",
205 204 "/users/{id}.{format}/edit",
206 205 action="edit", conditions=dict(method=["GET"]))
207 206 m.connect("user", "/users/{id}",
208 207 action="show", conditions=dict(method=["GET"]))
209 208 m.connect("formatted_user", "/users/{id}.{format}",
210 209 action="show", conditions=dict(method=["GET"]))
211 210
212 211 #EXTRAS USER ROUTES
213 212 m.connect("user_perm", "/users_perm/{id}",
214 213 action="update_perm", conditions=dict(method=["PUT"]))
215 214 m.connect("user_emails", "/users_emails/{id}",
216 215 action="add_email", conditions=dict(method=["PUT"]))
217 216 m.connect("user_emails_delete", "/users_emails/{id}",
218 217 action="delete_email", conditions=dict(method=["DELETE"]))
219 218
220 219 #ADMIN USERS GROUPS REST ROUTES
221 220 with rmap.submapper(path_prefix=ADMIN_PREFIX,
222 221 controller='admin/users_groups') as m:
223 222 m.connect("users_groups", "/users_groups",
224 223 action="create", conditions=dict(method=["POST"]))
225 224 m.connect("users_groups", "/users_groups",
226 225 action="index", conditions=dict(method=["GET"]))
227 226 m.connect("formatted_users_groups", "/users_groups.{format}",
228 227 action="index", conditions=dict(method=["GET"]))
229 228 m.connect("new_users_group", "/users_groups/new",
230 229 action="new", conditions=dict(method=["GET"]))
231 230 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
232 231 action="new", conditions=dict(method=["GET"]))
233 232 m.connect("update_users_group", "/users_groups/{id}",
234 233 action="update", conditions=dict(method=["PUT"]))
235 234 m.connect("delete_users_group", "/users_groups/{id}",
236 235 action="delete", conditions=dict(method=["DELETE"]))
237 236 m.connect("edit_users_group", "/users_groups/{id}/edit",
238 237 action="edit", conditions=dict(method=["GET"]))
239 238 m.connect("formatted_edit_users_group",
240 239 "/users_groups/{id}.{format}/edit",
241 240 action="edit", conditions=dict(method=["GET"]))
242 241 m.connect("users_group", "/users_groups/{id}",
243 242 action="show", conditions=dict(method=["GET"]))
244 243 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
245 244 action="show", conditions=dict(method=["GET"]))
246 245
247 246 #EXTRAS USER ROUTES
248 247 m.connect("users_group_perm", "/users_groups_perm/{id}",
249 248 action="update_perm", conditions=dict(method=["PUT"]))
250 249
251 250 #ADMIN GROUP REST ROUTES
252 251 rmap.resource('group', 'groups',
253 252 controller='admin/groups', path_prefix=ADMIN_PREFIX)
254 253
255 254 #ADMIN PERMISSIONS REST ROUTES
256 255 rmap.resource('permission', 'permissions',
257 256 controller='admin/permissions', path_prefix=ADMIN_PREFIX)
258 257
259 258 ##ADMIN LDAP SETTINGS
260 259 rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
261 260 controller='admin/ldap_settings', action='ldap_settings',
262 261 conditions=dict(method=["POST"]))
263 262
264 263 rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
265 264 controller='admin/ldap_settings')
266 265
267 266 #ADMIN SETTINGS REST ROUTES
268 267 with rmap.submapper(path_prefix=ADMIN_PREFIX,
269 268 controller='admin/settings') as m:
270 269 m.connect("admin_settings", "/settings",
271 270 action="create", conditions=dict(method=["POST"]))
272 271 m.connect("admin_settings", "/settings",
273 272 action="index", conditions=dict(method=["GET"]))
274 273 m.connect("formatted_admin_settings", "/settings.{format}",
275 274 action="index", conditions=dict(method=["GET"]))
276 275 m.connect("admin_new_setting", "/settings/new",
277 276 action="new", conditions=dict(method=["GET"]))
278 277 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
279 278 action="new", conditions=dict(method=["GET"]))
280 279 m.connect("/settings/{setting_id}",
281 280 action="update", conditions=dict(method=["PUT"]))
282 281 m.connect("/settings/{setting_id}",
283 282 action="delete", conditions=dict(method=["DELETE"]))
284 283 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
285 284 action="edit", conditions=dict(method=["GET"]))
286 285 m.connect("formatted_admin_edit_setting",
287 286 "/settings/{setting_id}.{format}/edit",
288 287 action="edit", conditions=dict(method=["GET"]))
289 288 m.connect("admin_setting", "/settings/{setting_id}",
290 289 action="show", conditions=dict(method=["GET"]))
291 290 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
292 291 action="show", conditions=dict(method=["GET"]))
293 292 m.connect("admin_settings_my_account", "/my_account",
294 293 action="my_account", conditions=dict(method=["GET"]))
295 294 m.connect("admin_settings_my_account_update", "/my_account_update",
296 295 action="my_account_update", conditions=dict(method=["PUT"]))
297 296 m.connect("admin_settings_create_repository", "/create_repository",
298 297 action="create_repository", conditions=dict(method=["GET"]))
299 298 m.connect("admin_settings_my_repos", "/my_account/repos",
300 299 action="my_account_my_repos", conditions=dict(method=["GET"]))
301 300 m.connect("admin_settings_my_pullrequests", "/my_account/pull_requests",
302 301 action="my_account_my_pullrequests", conditions=dict(method=["GET"]))
303 302
304 303
305 304 #NOTIFICATION REST ROUTES
306 305 with rmap.submapper(path_prefix=ADMIN_PREFIX,
307 306 controller='admin/notifications') as m:
308 307 m.connect("notifications", "/notifications",
309 308 action="create", conditions=dict(method=["POST"]))
310 309 m.connect("notifications", "/notifications",
311 310 action="index", conditions=dict(method=["GET"]))
312 311 m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
313 312 action="mark_all_read", conditions=dict(method=["GET"]))
314 313 m.connect("formatted_notifications", "/notifications.{format}",
315 314 action="index", conditions=dict(method=["GET"]))
316 315 m.connect("new_notification", "/notifications/new",
317 316 action="new", conditions=dict(method=["GET"]))
318 317 m.connect("formatted_new_notification", "/notifications/new.{format}",
319 318 action="new", conditions=dict(method=["GET"]))
320 319 m.connect("/notification/{notification_id}",
321 320 action="update", conditions=dict(method=["PUT"]))
322 321 m.connect("/notification/{notification_id}",
323 322 action="delete", conditions=dict(method=["DELETE"]))
324 323 m.connect("edit_notification", "/notification/{notification_id}/edit",
325 324 action="edit", conditions=dict(method=["GET"]))
326 325 m.connect("formatted_edit_notification",
327 326 "/notification/{notification_id}.{format}/edit",
328 327 action="edit", conditions=dict(method=["GET"]))
329 328 m.connect("notification", "/notification/{notification_id}",
330 329 action="show", conditions=dict(method=["GET"]))
331 330 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
332 331 action="show", conditions=dict(method=["GET"]))
333 332
334 333 #ADMIN MAIN PAGES
335 334 with rmap.submapper(path_prefix=ADMIN_PREFIX,
336 335 controller='admin/admin') as m:
337 336 m.connect('admin_home', '', action='index')
338 337 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
339 338 action='add_repo')
340 339
341 340 #==========================================================================
342 341 # API V2
343 342 #==========================================================================
344 343 with rmap.submapper(path_prefix=ADMIN_PREFIX,
345 344 controller='api/api') as m:
346 345 m.connect('api', '/api')
347 346
348 347 #USER JOURNAL
349 348 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
350 349 controller='journal', action='index')
351 350 rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
352 351 controller='journal', action='journal_rss')
353 352 rmap.connect('journal_atom', '%s/journal/atom' % ADMIN_PREFIX,
354 353 controller='journal', action='journal_atom')
355 354
356 355 rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
357 356 controller='journal', action="public_journal")
358 357
359 358 rmap.connect('public_journal_rss', '%s/public_journal/rss' % ADMIN_PREFIX,
360 359 controller='journal', action="public_journal_rss")
361 360
362 361 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % ADMIN_PREFIX,
363 362 controller='journal', action="public_journal_rss")
364 363
365 364 rmap.connect('public_journal_atom',
366 365 '%s/public_journal/atom' % ADMIN_PREFIX, controller='journal',
367 366 action="public_journal_atom")
368 367
369 368 rmap.connect('public_journal_atom_old',
370 369 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
371 370 action="public_journal_atom")
372 371
373 372 rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
374 373 controller='journal', action='toggle_following',
375 374 conditions=dict(method=["POST"]))
376 375
377 376 #SEARCH
378 377 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
379 378 rmap.connect('search_repo', '%s/search/{search_repo:.*}' % ADMIN_PREFIX,
380 379 controller='search')
381 380
382 381 #LOGIN/LOGOUT/REGISTER/SIGN IN
383 382 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
384 383 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
385 384 action='logout')
386 385
387 386 rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
388 387 action='register')
389 388
390 389 rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
391 390 controller='login', action='password_reset')
392 391
393 392 rmap.connect('reset_password_confirmation',
394 393 '%s/password_reset_confirmation' % ADMIN_PREFIX,
395 394 controller='login', action='password_reset_confirmation')
396 395
397 396 #FEEDS
398 397 rmap.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
399 398 controller='feed', action='rss',
400 399 conditions=dict(function=check_repo))
401 400
402 401 rmap.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
403 402 controller='feed', action='atom',
404 403 conditions=dict(function=check_repo))
405 404
406 405 #==========================================================================
407 406 # REPOSITORY ROUTES
408 407 #==========================================================================
409 408 rmap.connect('summary_home', '/{repo_name:.*}',
410 409 controller='summary',
411 410 conditions=dict(function=check_repo))
412 411
413 412 rmap.connect('repos_group_home', '/{group_name:.*}',
414 413 controller='admin/repos_groups', action="show_by_name",
415 414 conditions=dict(function=check_group))
416 415
417 416 rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
418 417 controller='changeset', revision='tip',
419 418 conditions=dict(function=check_repo))
420 419
421 420 rmap.connect('changeset_comment',
422 421 '/{repo_name:.*}/changeset/{revision}/comment',
423 422 controller='changeset', revision='tip', action='comment',
424 423 conditions=dict(function=check_repo))
425 424
426 425 rmap.connect('changeset_comment_delete',
427 426 '/{repo_name:.*}/changeset/comment/{comment_id}/delete',
428 427 controller='changeset', action='delete_comment',
429 428 conditions=dict(function=check_repo, method=["DELETE"]))
430 429
431 430 rmap.connect('raw_changeset_home',
432 431 '/{repo_name:.*}/raw-changeset/{revision}',
433 432 controller='changeset', action='raw_changeset',
434 433 revision='tip', conditions=dict(function=check_repo))
435 434
436 435 rmap.connect('compare_url',
437 436 '/{repo_name:.*}/compare/{org_ref_type}@{org_ref}...{other_ref_type}@{other_ref}',
438 437 controller='compare', action='index',
439 438 conditions=dict(function=check_repo),
440 439 requirements=dict(org_ref_type='(branch|book|tag|rev)',
441 440 other_ref_type='(branch|book|tag|rev)'))
442 441
443 442 rmap.connect('pullrequest_home',
444 443 '/{repo_name:.*}/pull-request/new', controller='pullrequests',
445 444 action='index', conditions=dict(function=check_repo,
446 445 method=["GET"]))
447 446
448 447 rmap.connect('pullrequest',
449 448 '/{repo_name:.*}/pull-request/new', controller='pullrequests',
450 449 action='create', conditions=dict(function=check_repo,
451 450 method=["POST"]))
452 451
453 452 rmap.connect('pullrequest_show',
454 453 '/{repo_name:.*}/pull-request/{pull_request_id}',
455 454 controller='pullrequests',
456 455 action='show', conditions=dict(function=check_repo,
457 456 method=["GET"]))
458 457 rmap.connect('pullrequest_update',
459 458 '/{repo_name:.*}/pull-request/{pull_request_id}',
460 459 controller='pullrequests',
461 460 action='update', conditions=dict(function=check_repo,
462 461 method=["PUT"]))
463 462
464 463 rmap.connect('pullrequest_show_all',
465 464 '/{repo_name:.*}/pull-request',
466 465 controller='pullrequests',
467 466 action='show_all', conditions=dict(function=check_repo,
468 467 method=["GET"]))
469 468
470 469 rmap.connect('pullrequest_comment',
471 470 '/{repo_name:.*}/pull-request-comment/{pull_request_id}',
472 471 controller='pullrequests',
473 472 action='comment', conditions=dict(function=check_repo,
474 473 method=["POST"]))
475 474
476 475 rmap.connect('pullrequest_comment_delete',
477 476 '/{repo_name:.*}/pull-request-comment/{comment_id}/delete',
478 477 controller='pullrequests', action='delete_comment',
479 478 conditions=dict(function=check_repo, method=["DELETE"]))
480 479
481 480 rmap.connect('summary_home', '/{repo_name:.*}/summary',
482 481 controller='summary', conditions=dict(function=check_repo))
483 482
484 483 rmap.connect('shortlog_home', '/{repo_name:.*}/shortlog',
485 484 controller='shortlog', conditions=dict(function=check_repo))
486 485
487 486 rmap.connect('branches_home', '/{repo_name:.*}/branches',
488 487 controller='branches', conditions=dict(function=check_repo))
489 488
490 489 rmap.connect('tags_home', '/{repo_name:.*}/tags',
491 490 controller='tags', conditions=dict(function=check_repo))
492 491
493 492 rmap.connect('bookmarks_home', '/{repo_name:.*}/bookmarks',
494 493 controller='bookmarks', conditions=dict(function=check_repo))
495 494
496 495 rmap.connect('changelog_home', '/{repo_name:.*}/changelog',
497 496 controller='changelog', conditions=dict(function=check_repo))
498 497
499 498 rmap.connect('changelog_details', '/{repo_name:.*}/changelog_details/{cs}',
500 499 controller='changelog', action='changelog_details',
501 500 conditions=dict(function=check_repo))
502 501
503 502 rmap.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
504 503 controller='files', revision='tip', f_path='',
505 504 conditions=dict(function=check_repo))
506 505
507 506 rmap.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
508 507 controller='files', action='diff', revision='tip', f_path='',
509 508 conditions=dict(function=check_repo))
510 509
511 510 rmap.connect('files_rawfile_home',
512 511 '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
513 512 controller='files', action='rawfile', revision='tip',
514 513 f_path='', conditions=dict(function=check_repo))
515 514
516 515 rmap.connect('files_raw_home',
517 516 '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
518 517 controller='files', action='raw', revision='tip', f_path='',
519 518 conditions=dict(function=check_repo))
520 519
521 520 rmap.connect('files_annotate_home',
522 521 '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
523 522 controller='files', action='index', revision='tip',
524 523 f_path='', annotate=True, conditions=dict(function=check_repo))
525 524
526 525 rmap.connect('files_edit_home',
527 526 '/{repo_name:.*}/edit/{revision}/{f_path:.*}',
528 527 controller='files', action='edit', revision='tip',
529 528 f_path='', conditions=dict(function=check_repo))
530 529
531 530 rmap.connect('files_add_home',
532 531 '/{repo_name:.*}/add/{revision}/{f_path:.*}',
533 532 controller='files', action='add', revision='tip',
534 533 f_path='', conditions=dict(function=check_repo))
535 534
536 535 rmap.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
537 536 controller='files', action='archivefile',
538 537 conditions=dict(function=check_repo))
539 538
540 539 rmap.connect('files_nodelist_home',
541 540 '/{repo_name:.*}/nodelist/{revision}/{f_path:.*}',
542 541 controller='files', action='nodelist',
543 542 conditions=dict(function=check_repo))
544 543
545 544 rmap.connect('repo_settings_delete', '/{repo_name:.*}/settings',
546 545 controller='settings', action="delete",
547 546 conditions=dict(method=["DELETE"], function=check_repo))
548 547
549 548 rmap.connect('repo_settings_update', '/{repo_name:.*}/settings',
550 549 controller='settings', action="update",
551 550 conditions=dict(method=["PUT"], function=check_repo))
552 551
553 552 rmap.connect('repo_settings_home', '/{repo_name:.*}/settings',
554 553 controller='settings', action='index',
555 554 conditions=dict(function=check_repo))
556 555
557 556 rmap.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
558 557 controller='forks', action='fork_create',
559 558 conditions=dict(function=check_repo, method=["POST"]))
560 559
561 560 rmap.connect('repo_fork_home', '/{repo_name:.*}/fork',
562 561 controller='forks', action='fork',
563 562 conditions=dict(function=check_repo))
564 563
565 564 rmap.connect('repo_forks_home', '/{repo_name:.*}/forks',
566 565 controller='forks', action='forks',
567 566 conditions=dict(function=check_repo))
568 567
569 568 rmap.connect('repo_followers_home', '/{repo_name:.*}/followers',
570 569 controller='followers', action='followers',
571 570 conditions=dict(function=check_repo))
572 571
573 572 return rmap
@@ -1,317 +1,316
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.repos_groups
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Repositories groups controller for RhodeCode
7 7
8 8 :created_on: Mar 23, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28 import formencode
29 29
30 30 from formencode import htmlfill
31 31
32 32 from pylons import request, tmpl_context as c, url
33 33 from pylons.controllers.util import redirect
34 34 from pylons.i18n.translation import _
35 35
36 36 from sqlalchemy.exc import IntegrityError
37 37
38 38 from rhodecode.lib import helpers as h
39 39 from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\
40 40 HasReposGroupPermissionAnyDecorator
41 41 from rhodecode.lib.base import BaseController, render
42 42 from rhodecode.model.db import RepoGroup
43 43 from rhodecode.model.repos_group import ReposGroupModel
44 44 from rhodecode.model.forms import ReposGroupForm
45 45 from rhodecode.model.meta import Session
46 46 from rhodecode.model.repo import RepoModel
47 47 from webob.exc import HTTPInternalServerError, HTTPNotFound
48 48
49 49 log = logging.getLogger(__name__)
50 50
51 51
52 52 class ReposGroupsController(BaseController):
53 53 """REST Controller styled on the Atom Publishing Protocol"""
54 54 # To properly map this controller, ensure your config/routing.py
55 55 # file has a resource setup:
56 56 # map.resource('repos_group', 'repos_groups')
57 57
58 58 @LoginRequired()
59 59 def __before__(self):
60 60 super(ReposGroupsController, self).__before__()
61 61
62 62 def __load_defaults(self):
63 63 c.repo_groups = RepoGroup.groups_choices()
64 64 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
65 65
66 66 repo_model = RepoModel()
67 67 c.users_array = repo_model.get_users_js()
68 68 c.users_groups_array = repo_model.get_users_groups_js()
69 69
70 70 def __load_data(self, group_id):
71 71 """
72 72 Load defaults settings for edit, and update
73 73
74 74 :param group_id:
75 75 """
76 76 self.__load_defaults()
77 77
78 78 repo_group = RepoGroup.get_or_404(group_id)
79 79
80 80 data = repo_group.get_dict()
81 81
82 82 data['group_name'] = repo_group.name
83 83
84 84 # fill repository users
85 85 for p in repo_group.repo_group_to_perm:
86 86 data.update({'u_perm_%s' % p.user.username:
87 87 p.permission.permission_name})
88 88
89 89 # fill repository groups
90 90 for p in repo_group.users_group_to_perm:
91 91 data.update({'g_perm_%s' % p.users_group.users_group_name:
92 92 p.permission.permission_name})
93 93
94 94 return data
95 95
96 96 @HasPermissionAnyDecorator('hg.admin')
97 97 def index(self, format='html'):
98 98 """GET /repos_groups: All items in the collection"""
99 99 # url('repos_groups')
100 100 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
101 101 c.groups = sorted(RepoGroup.query().all(), key=sk)
102 102 return render('admin/repos_groups/repos_groups_show.html')
103 103
104 104 @HasPermissionAnyDecorator('hg.admin')
105 105 def create(self):
106 106 """POST /repos_groups: Create a new item"""
107 107 # url('repos_groups')
108 108 self.__load_defaults()
109 109 repos_group_form = ReposGroupForm(available_groups =
110 110 c.repo_groups_choices)()
111 111 try:
112 112 form_result = repos_group_form.to_python(dict(request.POST))
113 113 ReposGroupModel().create(
114 114 group_name=form_result['group_name'],
115 115 group_description=form_result['group_description'],
116 116 parent=form_result['group_parent_id']
117 117 )
118 118 Session.commit()
119 119 h.flash(_('created repos group %s') \
120 120 % form_result['group_name'], category='success')
121 121 #TODO: in futureaction_logger(, '', '', '', self.sa)
122 122 except formencode.Invalid, errors:
123 123
124 124 return htmlfill.render(
125 125 render('admin/repos_groups/repos_groups_add.html'),
126 126 defaults=errors.value,
127 127 errors=errors.error_dict or {},
128 128 prefix_error=False,
129 129 encoding="UTF-8")
130 130 except Exception:
131 131 log.error(traceback.format_exc())
132 132 h.flash(_('error occurred during creation of repos group %s') \
133 133 % request.POST.get('group_name'), category='error')
134 134
135 135 return redirect(url('repos_groups'))
136 136
137 137 @HasPermissionAnyDecorator('hg.admin')
138 138 def new(self, format='html'):
139 139 """GET /repos_groups/new: Form to create a new item"""
140 140 # url('new_repos_group')
141 141 self.__load_defaults()
142 142 return render('admin/repos_groups/repos_groups_add.html')
143 143
144 144 @HasPermissionAnyDecorator('hg.admin')
145 145 def update(self, id):
146 146 """PUT /repos_groups/id: Update an existing item"""
147 147 # Forms posted to this method should contain a hidden field:
148 148 # <input type="hidden" name="_method" value="PUT" />
149 149 # Or using helpers:
150 150 # h.form(url('repos_group', id=ID),
151 151 # method='put')
152 152 # url('repos_group', id=ID)
153 153
154 154 self.__load_defaults()
155 155 c.repos_group = RepoGroup.get(id)
156 156
157 157 repos_group_form = ReposGroupForm(
158 158 edit=True,
159 159 old_data=c.repos_group.get_dict(),
160 160 available_groups=c.repo_groups_choices
161 161 )()
162 162 try:
163 163 form_result = repos_group_form.to_python(dict(request.POST))
164 164 ReposGroupModel().update(id, form_result)
165 165 Session.commit()
166 166 h.flash(_('updated repos group %s') \
167 167 % form_result['group_name'], category='success')
168 168 #TODO: in futureaction_logger(, '', '', '', self.sa)
169 169 except formencode.Invalid, errors:
170 170
171 171 return htmlfill.render(
172 172 render('admin/repos_groups/repos_groups_edit.html'),
173 173 defaults=errors.value,
174 174 errors=errors.error_dict or {},
175 175 prefix_error=False,
176 176 encoding="UTF-8")
177 177 except Exception:
178 178 log.error(traceback.format_exc())
179 179 h.flash(_('error occurred during update of repos group %s') \
180 180 % request.POST.get('group_name'), category='error')
181 181
182 182 return redirect(url('repos_groups'))
183 183
184 184 @HasPermissionAnyDecorator('hg.admin')
185 185 def delete(self, id):
186 186 """DELETE /repos_groups/id: Delete an existing item"""
187 187 # Forms posted to this method should contain a hidden field:
188 188 # <input type="hidden" name="_method" value="DELETE" />
189 189 # Or using helpers:
190 190 # h.form(url('repos_group', id=ID),
191 191 # method='delete')
192 192 # url('repos_group', id=ID)
193 193
194 194 gr = RepoGroup.get(id)
195 195 repos = gr.repositories.all()
196 196 if repos:
197 197 h.flash(_('This group contains %s repositores and cannot be '
198 198 'deleted') % len(repos),
199 199 category='error')
200 200 return redirect(url('repos_groups'))
201 201
202 202 try:
203 203 ReposGroupModel().delete(id)
204 204 Session.commit()
205 205 h.flash(_('removed repos group %s') % gr.group_name, category='success')
206 206 #TODO: in future action_logger(, '', '', '', self.sa)
207 207 except IntegrityError, e:
208 208 if e.message.find('groups_group_parent_id_fkey') != -1:
209 209 log.error(traceback.format_exc())
210 210 h.flash(_('Cannot delete this group it still contains '
211 211 'subgroups'),
212 212 category='warning')
213 213 else:
214 214 log.error(traceback.format_exc())
215 215 h.flash(_('error occurred during deletion of repos '
216 216 'group %s') % gr.group_name, category='error')
217 217
218 218 except Exception:
219 219 log.error(traceback.format_exc())
220 220 h.flash(_('error occurred during deletion of repos '
221 221 'group %s') % gr.group_name, category='error')
222 222
223 223 return redirect(url('repos_groups'))
224 224
225 225 @HasReposGroupPermissionAnyDecorator('group.admin')
226 226 def delete_repos_group_user_perm(self, group_name):
227 227 """
228 228 DELETE an existing repositories group permission user
229 229
230 230 :param group_name:
231 231 """
232 232
233 233 try:
234 234 ReposGroupModel().revoke_user_permission(
235 235 repos_group=group_name, user=request.POST['user_id']
236 236 )
237 237 Session.commit()
238 238 except Exception:
239 239 log.error(traceback.format_exc())
240 240 h.flash(_('An error occurred during deletion of group user'),
241 241 category='error')
242 242 raise HTTPInternalServerError()
243 243
244 244 @HasReposGroupPermissionAnyDecorator('group.admin')
245 245 def delete_repos_group_users_group_perm(self, group_name):
246 246 """
247 247 DELETE an existing repositories group permission users group
248 248
249 249 :param group_name:
250 250 """
251 251
252 252 try:
253 253 ReposGroupModel().revoke_users_group_permission(
254 254 repos_group=group_name,
255 255 group_name=request.POST['users_group_id']
256 256 )
257 257 Session.commit()
258 258 except Exception:
259 259 log.error(traceback.format_exc())
260 260 h.flash(_('An error occurred during deletion of group'
261 261 ' users groups'),
262 262 category='error')
263 263 raise HTTPInternalServerError()
264 264
265 265 def show_by_name(self, group_name):
266 266 """
267 267 This is a proxy that does a lookup group_name -> id, and shows
268 268 the group by id view instead
269 269 """
270 270 group_name = group_name.rstrip('/')
271 271 id_ = RepoGroup.get_by_group_name(group_name)
272 272 if id_:
273 273 return self.show(id_.group_id)
274 274 raise HTTPNotFound
275 275
276 276 @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
277 277 'group.admin')
278 278 def show(self, id, format='html'):
279 279 """GET /repos_groups/id: Show a specific item"""
280 280 # url('repos_group', id=ID)
281 281
282 282 c.group = RepoGroup.get_or_404(id)
283 283
284 284 c.group_repos = c.group.repositories.all()
285 285
286 286 #overwrite our cached list with current filter
287 287 gr_filter = c.group_repos
288 288 c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
289 289
290 290 c.repos_list = c.cached_repo_list
291 291
292 292 c.repo_cnt = 0
293 293
294 294 c.groups = self.sa.query(RepoGroup).order_by(RepoGroup.group_name)\
295 295 .filter(RepoGroup.group_parent_id == id).all()
296 296
297 297 return render('admin/repos_groups/repos_groups.html')
298 298
299 299 @HasPermissionAnyDecorator('hg.admin')
300 300 def edit(self, id, format='html'):
301 301 """GET /repos_groups/id/edit: Form to edit an existing item"""
302 302 # url('edit_repos_group', id=ID)
303 303
304 id_ = int(id)
305
306 c.repos_group = RepoGroup.get(id_)
307 defaults = self.__load_data(id_)
304 c.repos_group = ReposGroupModel()._get_repos_group(id)
305 defaults = self.__load_data(c.repos_group.group_id)
308 306
309 307 # we need to exclude this group from the group list for editing
310 c.repo_groups = filter(lambda x: x[0] != id_, c.repo_groups)
308 c.repo_groups = filter(lambda x: x[0] != c.repos_group.group_id,
309 c.repo_groups)
311 310
312 311 return htmlfill.render(
313 312 render('admin/repos_groups/repos_groups_edit.html'),
314 313 defaults=defaults,
315 314 encoding="UTF-8",
316 315 force_defaults=False
317 316 )
@@ -1,523 +1,523
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.repo
4 4 ~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Repository model for rhodecode
7 7
8 8 :created_on: Jun 5, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25 from __future__ import with_statement
26 26 import os
27 27 import shutil
28 28 import logging
29 29 import traceback
30 30 from datetime import datetime
31 31
32 32 from rhodecode.lib.vcs.backends import get_backend
33 33 from rhodecode.lib.compat import json
34 34 from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode
35 35 from rhodecode.lib.caching_query import FromCache
36 36 from rhodecode.lib.hooks import log_create_repository
37 37
38 38 from rhodecode.model import BaseModel
39 39 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
40 40 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
41 41 from rhodecode.lib import helpers as h
42 42
43 43
44 44 log = logging.getLogger(__name__)
45 45
46 46
47 47 class RepoModel(BaseModel):
48 48
49 49 cls = Repository
50 50 URL_SEPARATOR = Repository.url_sep()
51 51
52 52 def __get_users_group(self, users_group):
53 53 return self._get_instance(UsersGroup, users_group,
54 54 callback=UsersGroup.get_by_group_name)
55 55
56 def __get_repos_group(self, repos_group):
56 def _get_repos_group(self, repos_group):
57 57 return self._get_instance(RepoGroup, repos_group,
58 58 callback=RepoGroup.get_by_group_name)
59 59
60 60 @LazyProperty
61 61 def repos_path(self):
62 62 """
63 63 Get's the repositories root path from database
64 64 """
65 65
66 66 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
67 67 return q.ui_value
68 68
69 69 def get(self, repo_id, cache=False):
70 70 repo = self.sa.query(Repository)\
71 71 .filter(Repository.repo_id == repo_id)
72 72
73 73 if cache:
74 74 repo = repo.options(FromCache("sql_cache_short",
75 75 "get_repo_%s" % repo_id))
76 76 return repo.scalar()
77 77
78 78 def get_repo(self, repository):
79 79 return self._get_repo(repository)
80 80
81 81 def get_by_repo_name(self, repo_name, cache=False):
82 82 repo = self.sa.query(Repository)\
83 83 .filter(Repository.repo_name == repo_name)
84 84
85 85 if cache:
86 86 repo = repo.options(FromCache("sql_cache_short",
87 87 "get_repo_%s" % repo_name))
88 88 return repo.scalar()
89 89
90 90 def get_users_js(self):
91 91 users = self.sa.query(User).filter(User.active == True).all()
92 92 return json.dumps([
93 93 {
94 94 'id': u.user_id,
95 95 'fname': u.name,
96 96 'lname': u.lastname,
97 97 'nname': u.username,
98 98 'gravatar_lnk': h.gravatar_url(u.email, 14)
99 99 } for u in users]
100 100 )
101 101
102 102 def get_users_groups_js(self):
103 103 users_groups = self.sa.query(UsersGroup)\
104 104 .filter(UsersGroup.users_group_active == True).all()
105 105
106 106 return json.dumps([
107 107 {
108 108 'id': gr.users_group_id,
109 109 'grname': gr.users_group_name,
110 110 'grmembers': len(gr.members),
111 111 } for gr in users_groups]
112 112 )
113 113
114 114 def _get_defaults(self, repo_name):
115 115 """
116 116 Get's information about repository, and returns a dict for
117 117 usage in forms
118 118
119 119 :param repo_name:
120 120 """
121 121
122 122 repo_info = Repository.get_by_repo_name(repo_name)
123 123
124 124 if repo_info is None:
125 125 return None
126 126
127 127 defaults = repo_info.get_dict()
128 128 group, repo_name = repo_info.groups_and_repo
129 129 defaults['repo_name'] = repo_name
130 130 defaults['repo_group'] = getattr(group[-1] if group else None,
131 131 'group_id', None)
132 132
133 133 # fill owner
134 134 if repo_info.user:
135 135 defaults.update({'user': repo_info.user.username})
136 136 else:
137 137 replacement_user = User.query().filter(User.admin ==
138 138 True).first().username
139 139 defaults.update({'user': replacement_user})
140 140
141 141 # fill repository users
142 142 for p in repo_info.repo_to_perm:
143 143 defaults.update({'u_perm_%s' % p.user.username:
144 144 p.permission.permission_name})
145 145
146 146 # fill repository groups
147 147 for p in repo_info.users_group_to_perm:
148 148 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
149 149 p.permission.permission_name})
150 150
151 151 return defaults
152 152
153 153 def update(self, repo_name, form_data):
154 154 try:
155 155 cur_repo = self.get_by_repo_name(repo_name, cache=False)
156 156
157 157 # update permissions
158 158 for member, perm, member_type in form_data['perms_updates']:
159 159 if member_type == 'user':
160 160 # this updates existing one
161 161 RepoModel().grant_user_permission(
162 162 repo=cur_repo, user=member, perm=perm
163 163 )
164 164 else:
165 165 RepoModel().grant_users_group_permission(
166 166 repo=cur_repo, group_name=member, perm=perm
167 167 )
168 168 # set new permissions
169 169 for member, perm, member_type in form_data['perms_new']:
170 170 if member_type == 'user':
171 171 RepoModel().grant_user_permission(
172 172 repo=cur_repo, user=member, perm=perm
173 173 )
174 174 else:
175 175 RepoModel().grant_users_group_permission(
176 176 repo=cur_repo, group_name=member, perm=perm
177 177 )
178 178
179 179 # update current repo
180 180 for k, v in form_data.items():
181 181 if k == 'user':
182 182 cur_repo.user = User.get_by_username(v)
183 183 elif k == 'repo_name':
184 184 pass
185 185 elif k == 'repo_group':
186 186 cur_repo.group = RepoGroup.get(v)
187 187
188 188 else:
189 189 setattr(cur_repo, k, v)
190 190
191 191 new_name = cur_repo.get_new_name(form_data['repo_name'])
192 192 cur_repo.repo_name = new_name
193 193
194 194 self.sa.add(cur_repo)
195 195
196 196 if repo_name != new_name:
197 197 # rename repository
198 198 self.__rename_repo(old=repo_name, new=new_name)
199 199
200 200 return cur_repo
201 201 except:
202 202 log.error(traceback.format_exc())
203 203 raise
204 204
205 205 def create_repo(self, repo_name, repo_type, description, owner,
206 206 private=False, clone_uri=None, repos_group=None,
207 207 landing_rev='tip', just_db=False, fork_of=None,
208 208 copy_fork_permissions=False):
209 209 from rhodecode.model.scm import ScmModel
210 210
211 211 owner = self._get_user(owner)
212 212 fork_of = self._get_repo(fork_of)
213 repos_group = self.__get_repos_group(repos_group)
213 repos_group = self._get_repos_group(repos_group)
214 214 try:
215 215
216 216 # repo name is just a name of repository
217 217 # while repo_name_full is a full qualified name that is combined
218 218 # with name and path of group
219 219 repo_name_full = repo_name
220 220 repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
221 221
222 222 new_repo = Repository()
223 223 new_repo.enable_statistics = False
224 224 new_repo.repo_name = repo_name_full
225 225 new_repo.repo_type = repo_type
226 226 new_repo.user = owner
227 227 new_repo.group = repos_group
228 228 new_repo.description = description or repo_name
229 229 new_repo.private = private
230 230 new_repo.clone_uri = clone_uri
231 231 new_repo.landing_rev = landing_rev
232 232
233 233 if fork_of:
234 234 parent_repo = fork_of
235 235 new_repo.fork = parent_repo
236 236
237 237 self.sa.add(new_repo)
238 238
239 239 def _create_default_perms():
240 240 # create default permission
241 241 repo_to_perm = UserRepoToPerm()
242 242 default = 'repository.read'
243 243 for p in User.get_by_username('default').user_perms:
244 244 if p.permission.permission_name.startswith('repository.'):
245 245 default = p.permission.permission_name
246 246 break
247 247
248 248 default_perm = 'repository.none' if private else default
249 249
250 250 repo_to_perm.permission_id = self.sa.query(Permission)\
251 251 .filter(Permission.permission_name == default_perm)\
252 252 .one().permission_id
253 253
254 254 repo_to_perm.repository = new_repo
255 255 repo_to_perm.user_id = User.get_by_username('default').user_id
256 256
257 257 self.sa.add(repo_to_perm)
258 258
259 259 if fork_of:
260 260 if copy_fork_permissions:
261 261 repo = fork_of
262 262 user_perms = UserRepoToPerm.query()\
263 263 .filter(UserRepoToPerm.repository == repo).all()
264 264 group_perms = UsersGroupRepoToPerm.query()\
265 265 .filter(UsersGroupRepoToPerm.repository == repo).all()
266 266
267 267 for perm in user_perms:
268 268 UserRepoToPerm.create(perm.user, new_repo,
269 269 perm.permission)
270 270
271 271 for perm in group_perms:
272 272 UsersGroupRepoToPerm.create(perm.users_group, new_repo,
273 273 perm.permission)
274 274 else:
275 275 _create_default_perms()
276 276 else:
277 277 _create_default_perms()
278 278
279 279 if not just_db:
280 280 self.__create_repo(repo_name, repo_type,
281 281 repos_group,
282 282 clone_uri)
283 283 log_create_repository(new_repo.get_dict(),
284 284 created_by=owner.username)
285 285
286 286 # now automatically start following this repository as owner
287 287 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
288 288 owner.user_id)
289 289 return new_repo
290 290 except:
291 291 log.error(traceback.format_exc())
292 292 raise
293 293
294 294 def create(self, form_data, cur_user, just_db=False, fork=None):
295 295
296 296 repo_name = form_data['repo_name_full']
297 297 repo_type = form_data['repo_type']
298 298 description = form_data['description']
299 299 owner = cur_user
300 300 private = form_data['private']
301 301 clone_uri = form_data.get('clone_uri')
302 302 repos_group = form_data['repo_group']
303 303 landing_rev = form_data['landing_rev']
304 304 copy_fork_permissions = form_data.get('copy_permissions')
305 305 fork_of = form_data.get('fork_parent_id')
306 306 return self.create_repo(
307 307 repo_name, repo_type, description, owner, private, clone_uri,
308 308 repos_group, landing_rev, just_db, fork_of, copy_fork_permissions
309 309 )
310 310
311 311 def create_fork(self, form_data, cur_user):
312 312 """
313 313 Simple wrapper into executing celery task for fork creation
314 314
315 315 :param form_data:
316 316 :param cur_user:
317 317 """
318 318 from rhodecode.lib.celerylib import tasks, run_task
319 319 run_task(tasks.create_repo_fork, form_data, cur_user)
320 320
321 321 def delete(self, repo):
322 322 repo = self._get_repo(repo)
323 323 if repo:
324 324 try:
325 325 self.sa.delete(repo)
326 326 self.__delete_repo(repo)
327 327 except:
328 328 log.error(traceback.format_exc())
329 329 raise
330 330
331 331 def grant_user_permission(self, repo, user, perm):
332 332 """
333 333 Grant permission for user on given repository, or update existing one
334 334 if found
335 335
336 336 :param repo: Instance of Repository, repository_id, or repository name
337 337 :param user: Instance of User, user_id or username
338 338 :param perm: Instance of Permission, or permission_name
339 339 """
340 340 user = self._get_user(user)
341 341 repo = self._get_repo(repo)
342 342 permission = self._get_perm(perm)
343 343
344 344 # check if we have that permission already
345 345 obj = self.sa.query(UserRepoToPerm)\
346 346 .filter(UserRepoToPerm.user == user)\
347 347 .filter(UserRepoToPerm.repository == repo)\
348 348 .scalar()
349 349 if obj is None:
350 350 # create new !
351 351 obj = UserRepoToPerm()
352 352 obj.repository = repo
353 353 obj.user = user
354 354 obj.permission = permission
355 355 self.sa.add(obj)
356 356
357 357 def revoke_user_permission(self, repo, user):
358 358 """
359 359 Revoke permission for user on given repository
360 360
361 361 :param repo: Instance of Repository, repository_id, or repository name
362 362 :param user: Instance of User, user_id or username
363 363 """
364 364
365 365 user = self._get_user(user)
366 366 repo = self._get_repo(repo)
367 367
368 368 obj = self.sa.query(UserRepoToPerm)\
369 369 .filter(UserRepoToPerm.repository == repo)\
370 370 .filter(UserRepoToPerm.user == user)\
371 371 .one()
372 372 self.sa.delete(obj)
373 373
374 374 def grant_users_group_permission(self, repo, group_name, perm):
375 375 """
376 376 Grant permission for users group on given repository, or update
377 377 existing one if found
378 378
379 379 :param repo: Instance of Repository, repository_id, or repository name
380 380 :param group_name: Instance of UserGroup, users_group_id,
381 381 or users group name
382 382 :param perm: Instance of Permission, or permission_name
383 383 """
384 384 repo = self._get_repo(repo)
385 385 group_name = self.__get_users_group(group_name)
386 386 permission = self._get_perm(perm)
387 387
388 388 # check if we have that permission already
389 389 obj = self.sa.query(UsersGroupRepoToPerm)\
390 390 .filter(UsersGroupRepoToPerm.users_group == group_name)\
391 391 .filter(UsersGroupRepoToPerm.repository == repo)\
392 392 .scalar()
393 393
394 394 if obj is None:
395 395 # create new
396 396 obj = UsersGroupRepoToPerm()
397 397
398 398 obj.repository = repo
399 399 obj.users_group = group_name
400 400 obj.permission = permission
401 401 self.sa.add(obj)
402 402
403 403 def revoke_users_group_permission(self, repo, group_name):
404 404 """
405 405 Revoke permission for users group on given repository
406 406
407 407 :param repo: Instance of Repository, repository_id, or repository name
408 408 :param group_name: Instance of UserGroup, users_group_id,
409 409 or users group name
410 410 """
411 411 repo = self._get_repo(repo)
412 412 group_name = self.__get_users_group(group_name)
413 413
414 414 obj = self.sa.query(UsersGroupRepoToPerm)\
415 415 .filter(UsersGroupRepoToPerm.repository == repo)\
416 416 .filter(UsersGroupRepoToPerm.users_group == group_name)\
417 417 .one()
418 418 self.sa.delete(obj)
419 419
420 420 def delete_stats(self, repo_name):
421 421 """
422 422 removes stats for given repo
423 423
424 424 :param repo_name:
425 425 """
426 426 try:
427 427 obj = self.sa.query(Statistics)\
428 428 .filter(Statistics.repository ==
429 429 self.get_by_repo_name(repo_name))\
430 430 .one()
431 431 self.sa.delete(obj)
432 432 except:
433 433 log.error(traceback.format_exc())
434 434 raise
435 435
436 436 def __create_repo(self, repo_name, alias, parent, clone_uri=False):
437 437 """
438 438 makes repository on filesystem. It's group aware means it'll create
439 439 a repository within a group, and alter the paths accordingly of
440 440 group location
441 441
442 442 :param repo_name:
443 443 :param alias:
444 444 :param parent_id:
445 445 :param clone_uri:
446 446 """
447 447 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
448 448 from rhodecode.model.scm import ScmModel
449 449
450 450 if parent:
451 451 new_parent_path = os.sep.join(parent.full_path_splitted)
452 452 else:
453 453 new_parent_path = ''
454 454
455 455 # we need to make it str for mercurial
456 456 repo_path = os.path.join(*map(lambda x: safe_str(x),
457 457 [self.repos_path, new_parent_path, repo_name]))
458 458
459 459 # check if this path is not a repository
460 460 if is_valid_repo(repo_path, self.repos_path):
461 461 raise Exception('This path %s is a valid repository' % repo_path)
462 462
463 463 # check if this path is a group
464 464 if is_valid_repos_group(repo_path, self.repos_path):
465 465 raise Exception('This path %s is a valid group' % repo_path)
466 466
467 467 log.info('creating repo %s in %s @ %s' % (
468 468 repo_name, safe_unicode(repo_path), clone_uri
469 469 )
470 470 )
471 471 backend = get_backend(alias)
472 472 if alias == 'hg':
473 473 backend(repo_path, create=True, src_url=clone_uri)
474 474 elif alias == 'git':
475 475 r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
476 476 # add rhodecode hook into this repo
477 477 ScmModel().install_git_hook(repo=r)
478 478 else:
479 479 raise Exception('Undefined alias %s' % alias)
480 480
481 481 def __rename_repo(self, old, new):
482 482 """
483 483 renames repository on filesystem
484 484
485 485 :param old: old name
486 486 :param new: new name
487 487 """
488 488 log.info('renaming repo from %s to %s' % (old, new))
489 489
490 490 old_path = os.path.join(self.repos_path, old)
491 491 new_path = os.path.join(self.repos_path, new)
492 492 if os.path.isdir(new_path):
493 493 raise Exception(
494 494 'Was trying to rename to already existing dir %s' % new_path
495 495 )
496 496 shutil.move(old_path, new_path)
497 497
498 498 def __delete_repo(self, repo):
499 499 """
500 500 removes repo from filesystem, the removal is acctually made by
501 501 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
502 502 repository is no longer valid for rhodecode, can be undeleted later on
503 503 by reverting the renames on this repository
504 504
505 505 :param repo: repo object
506 506 """
507 507 rm_path = os.path.join(self.repos_path, repo.repo_name)
508 508 log.info("Removing %s" % (rm_path))
509 509 # disable hg/git internal that it doesn't get detected as repo
510 510 alias = repo.repo_type
511 511
512 512 bare = getattr(repo.scm_instance, 'bare', False)
513 513
514 514 if not bare:
515 515 # skip this for bare git repos
516 516 shutil.move(os.path.join(rm_path, '.%s' % alias),
517 517 os.path.join(rm_path, 'rm__.%s' % alias))
518 518 # disable repo
519 519 _now = datetime.now()
520 520 _ms = str(_now.microsecond).rjust(6, '0')
521 521 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
522 522 repo.repo_name)
523 523 shutil.move(rm_path, os.path.join(self.repos_path, _d))
@@ -1,305 +1,305
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.user_group
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 users groups model for RhodeCode
7 7
8 8 :created_on: Jan 25, 2011
9 9 :author: marcink
10 10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import os
27 27 import logging
28 28 import traceback
29 29 import shutil
30 30
31 31 from rhodecode.lib.utils2 import LazyProperty
32 32
33 33 from rhodecode.model import BaseModel
34 34 from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
35 35 User, Permission, UsersGroupRepoGroupToPerm, UsersGroup
36 36
37 37 log = logging.getLogger(__name__)
38 38
39 39
40 40 class ReposGroupModel(BaseModel):
41 41
42 42 cls = RepoGroup
43 43
44 44 def __get_users_group(self, users_group):
45 45 return self._get_instance(UsersGroup, users_group,
46 46 callback=UsersGroup.get_by_group_name)
47 47
48 def __get_repos_group(self, repos_group):
48 def _get_repos_group(self, repos_group):
49 49 return self._get_instance(RepoGroup, repos_group,
50 50 callback=RepoGroup.get_by_group_name)
51 51
52 52 @LazyProperty
53 53 def repos_path(self):
54 54 """
55 55 Get's the repositories root path from database
56 56 """
57 57
58 58 q = RhodeCodeUi.get_by_key('/').one()
59 59 return q.ui_value
60 60
61 61 def _create_default_perms(self, new_group):
62 62 # create default permission
63 63 repo_group_to_perm = UserRepoGroupToPerm()
64 64 default_perm = 'group.read'
65 65 for p in User.get_by_username('default').user_perms:
66 66 if p.permission.permission_name.startswith('group.'):
67 67 default_perm = p.permission.permission_name
68 68 break
69 69
70 70 repo_group_to_perm.permission_id = self.sa.query(Permission)\
71 71 .filter(Permission.permission_name == default_perm)\
72 72 .one().permission_id
73 73
74 74 repo_group_to_perm.group = new_group
75 75 repo_group_to_perm.user_id = User.get_by_username('default').user_id
76 76
77 77 self.sa.add(repo_group_to_perm)
78 78
79 79 def __create_group(self, group_name):
80 80 """
81 81 makes repositories group on filesystem
82 82
83 83 :param repo_name:
84 84 :param parent_id:
85 85 """
86 86
87 87 create_path = os.path.join(self.repos_path, group_name)
88 88 log.debug('creating new group in %s' % create_path)
89 89
90 90 if os.path.isdir(create_path):
91 91 raise Exception('That directory already exists !')
92 92
93 93 os.makedirs(create_path)
94 94
95 95 def __rename_group(self, old, new):
96 96 """
97 97 Renames a group on filesystem
98 98
99 99 :param group_name:
100 100 """
101 101
102 102 if old == new:
103 103 log.debug('skipping group rename')
104 104 return
105 105
106 106 log.debug('renaming repos group from %s to %s' % (old, new))
107 107
108 108 old_path = os.path.join(self.repos_path, old)
109 109 new_path = os.path.join(self.repos_path, new)
110 110
111 111 log.debug('renaming repos paths from %s to %s' % (old_path, new_path))
112 112
113 113 if os.path.isdir(new_path):
114 114 raise Exception('Was trying to rename to already '
115 115 'existing dir %s' % new_path)
116 116 shutil.move(old_path, new_path)
117 117
118 118 def __delete_group(self, group):
119 119 """
120 120 Deletes a group from a filesystem
121 121
122 122 :param group: instance of group from database
123 123 """
124 124 paths = group.full_path.split(RepoGroup.url_sep())
125 125 paths = os.sep.join(paths)
126 126
127 127 rm_path = os.path.join(self.repos_path, paths)
128 128 if os.path.isdir(rm_path):
129 129 # delete only if that path really exists
130 130 os.rmdir(rm_path)
131 131
132 132 def create(self, group_name, group_description, parent=None, just_db=False):
133 133 try:
134 134 new_repos_group = RepoGroup()
135 135 new_repos_group.group_description = group_description
136 new_repos_group.parent_group = self.__get_repos_group(parent)
136 new_repos_group.parent_group = self._get_repos_group(parent)
137 137 new_repos_group.group_name = new_repos_group.get_new_name(group_name)
138 138
139 139 self.sa.add(new_repos_group)
140 140 self._create_default_perms(new_repos_group)
141 141
142 142 if not just_db:
143 143 # we need to flush here, in order to check if database won't
144 144 # throw any exceptions, create filesystem dirs at the very end
145 145 self.sa.flush()
146 146 self.__create_group(new_repos_group.group_name)
147 147
148 148 return new_repos_group
149 149 except:
150 150 log.error(traceback.format_exc())
151 151 raise
152 152
153 153 def update(self, repos_group_id, form_data):
154 154
155 155 try:
156 156 repos_group = RepoGroup.get(repos_group_id)
157 157
158 158 # update permissions
159 159 for member, perm, member_type in form_data['perms_updates']:
160 160 if member_type == 'user':
161 161 # this updates also current one if found
162 162 ReposGroupModel().grant_user_permission(
163 163 repos_group=repos_group, user=member, perm=perm
164 164 )
165 165 else:
166 166 ReposGroupModel().grant_users_group_permission(
167 167 repos_group=repos_group, group_name=member, perm=perm
168 168 )
169 169 # set new permissions
170 170 for member, perm, member_type in form_data['perms_new']:
171 171 if member_type == 'user':
172 172 ReposGroupModel().grant_user_permission(
173 173 repos_group=repos_group, user=member, perm=perm
174 174 )
175 175 else:
176 176 ReposGroupModel().grant_users_group_permission(
177 177 repos_group=repos_group, group_name=member, perm=perm
178 178 )
179 179
180 180 old_path = repos_group.full_path
181 181
182 182 # change properties
183 183 repos_group.group_description = form_data['group_description']
184 184 repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
185 185 repos_group.group_parent_id = form_data['group_parent_id']
186 186 repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
187 187 new_path = repos_group.full_path
188 188
189 189 self.sa.add(repos_group)
190 190
191 191 # we need to get all repositories from this new group and
192 192 # rename them accordingly to new group path
193 193 for r in repos_group.repositories:
194 194 r.repo_name = r.get_new_name(r.just_name)
195 195 self.sa.add(r)
196 196
197 197 self.__rename_group(old_path, new_path)
198 198
199 199 return repos_group
200 200 except:
201 201 log.error(traceback.format_exc())
202 202 raise
203 203
204 204 def delete(self, repos_group):
205 repos_group = self.__get_repos_group(repos_group)
205 repos_group = self._get_repos_group(repos_group)
206 206 try:
207 207 self.sa.delete(repos_group)
208 208 self.__delete_group(repos_group)
209 209 except:
210 210 log.exception('Error removing repos_group %s' % repos_group)
211 211 raise
212 212
213 213 def grant_user_permission(self, repos_group, user, perm):
214 214 """
215 215 Grant permission for user on given repositories group, or update
216 216 existing one if found
217 217
218 218 :param repos_group: Instance of ReposGroup, repositories_group_id,
219 219 or repositories_group name
220 220 :param user: Instance of User, user_id or username
221 221 :param perm: Instance of Permission, or permission_name
222 222 """
223 223
224 repos_group = self.__get_repos_group(repos_group)
224 repos_group = self._get_repos_group(repos_group)
225 225 user = self._get_user(user)
226 226 permission = self._get_perm(perm)
227 227
228 228 # check if we have that permission already
229 229 obj = self.sa.query(UserRepoGroupToPerm)\
230 230 .filter(UserRepoGroupToPerm.user == user)\
231 231 .filter(UserRepoGroupToPerm.group == repos_group)\
232 232 .scalar()
233 233 if obj is None:
234 234 # create new !
235 235 obj = UserRepoGroupToPerm()
236 236 obj.group = repos_group
237 237 obj.user = user
238 238 obj.permission = permission
239 239 self.sa.add(obj)
240 240
241 241 def revoke_user_permission(self, repos_group, user):
242 242 """
243 243 Revoke permission for user on given repositories group
244 244
245 245 :param repos_group: Instance of ReposGroup, repositories_group_id,
246 246 or repositories_group name
247 247 :param user: Instance of User, user_id or username
248 248 """
249 249
250 repos_group = self.__get_repos_group(repos_group)
250 repos_group = self._get_repos_group(repos_group)
251 251 user = self._get_user(user)
252 252
253 253 obj = self.sa.query(UserRepoGroupToPerm)\
254 254 .filter(UserRepoGroupToPerm.user == user)\
255 255 .filter(UserRepoGroupToPerm.group == repos_group)\
256 256 .one()
257 257 self.sa.delete(obj)
258 258
259 259 def grant_users_group_permission(self, repos_group, group_name, perm):
260 260 """
261 261 Grant permission for users group on given repositories group, or update
262 262 existing one if found
263 263
264 264 :param repos_group: Instance of ReposGroup, repositories_group_id,
265 265 or repositories_group name
266 266 :param group_name: Instance of UserGroup, users_group_id,
267 267 or users group name
268 268 :param perm: Instance of Permission, or permission_name
269 269 """
270 repos_group = self.__get_repos_group(repos_group)
270 repos_group = self._get_repos_group(repos_group)
271 271 group_name = self.__get_users_group(group_name)
272 272 permission = self._get_perm(perm)
273 273
274 274 # check if we have that permission already
275 275 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
276 276 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
277 277 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
278 278 .scalar()
279 279
280 280 if obj is None:
281 281 # create new
282 282 obj = UsersGroupRepoGroupToPerm()
283 283
284 284 obj.group = repos_group
285 285 obj.users_group = group_name
286 286 obj.permission = permission
287 287 self.sa.add(obj)
288 288
289 289 def revoke_users_group_permission(self, repos_group, group_name):
290 290 """
291 291 Revoke permission for users group on given repositories group
292 292
293 293 :param repos_group: Instance of ReposGroup, repositories_group_id,
294 294 or repositories_group name
295 295 :param group_name: Instance of UserGroup, users_group_id,
296 296 or users group name
297 297 """
298 repos_group = self.__get_repos_group(repos_group)
298 repos_group = self._get_repos_group(repos_group)
299 299 group_name = self.__get_users_group(group_name)
300 300
301 301 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
302 302 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
303 303 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
304 304 .one()
305 305 self.sa.delete(obj)
@@ -1,251 +1,261
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Edit user')} ${c.user.username} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 10 &raquo;
11 11 ${h.link_to(_('Users'),h.url('users'))}
12 12 &raquo;
13 13 ${_('edit')} "${c.user.username}"
14 14 </%def>
15 15
16 16 <%def name="page_nav()">
17 17 ${self.menu('admin')}
18 18 </%def>
19 19
20 20 <%def name="main()">
21 21 <div class="box box-left">
22 22 <!-- box / title -->
23 23 <div class="title">
24 24 ${self.breadcrumbs()}
25 25 </div>
26 26 <!-- end box / title -->
27 27 ${h.form(url('update_user', id=c.user.user_id),method='put')}
28 28 <div class="form">
29 29 <div class="field">
30 30 <div class="gravatar_box">
31 31 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
32 32 <p>
33 33 %if c.use_gravatar:
34 34 <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong>
35 35 <br/>${_('Using')} ${c.user.email}
36 36 %else:
37 37 <br/>${c.user.email}
38 38 %endif
39 39 </div>
40 40 </div>
41 41 <div class="field">
42 42 <div class="label">
43 43 <label>${_('API key')}</label> ${c.user.api_key}
44 44 </div>
45 45 </div>
46 46
47 47 <div class="fields">
48 48 <div class="field">
49 49 <div class="label">
50 50 <label for="username">${_('Username')}:</label>
51 51 </div>
52 52 <div class="input">
53 53 ${h.text('username',class_='medium')}
54 54 </div>
55 55 </div>
56 56
57 57 <div class="field">
58 58 <div class="label">
59 59 <label for="ldap_dn">${_('LDAP DN')}:</label>
60 60 </div>
61 61 <div class="input">
62 62 ${h.text('ldap_dn',class_='medium disabled',readonly="readonly")}
63 63 </div>
64 64 </div>
65 65
66 66 <div class="field">
67 67 <div class="label">
68 68 <label for="new_password">${_('New password')}:</label>
69 69 </div>
70 70 <div class="input">
71 71 ${h.password('new_password',class_='medium',autocomplete="off")}
72 72 </div>
73 73 </div>
74 74
75 75 <div class="field">
76 76 <div class="label">
77 77 <label for="password_confirmation">${_('New password confirmation')}:</label>
78 78 </div>
79 79 <div class="input">
80 80 ${h.password('password_confirmation',class_="medium",autocomplete="off")}
81 81 </div>
82 82 </div>
83 83
84 84 <div class="field">
85 85 <div class="label">
86 86 <label for="firstname">${_('First Name')}:</label>
87 87 </div>
88 88 <div class="input">
89 89 ${h.text('firstname',class_='medium')}
90 90 </div>
91 91 </div>
92 92
93 93 <div class="field">
94 94 <div class="label">
95 95 <label for="lastname">${_('Last Name')}:</label>
96 96 </div>
97 97 <div class="input">
98 98 ${h.text('lastname',class_='medium')}
99 99 </div>
100 100 </div>
101 101
102 102 <div class="field">
103 103 <div class="label">
104 104 <label for="email">${_('Email')}:</label>
105 105 </div>
106 106 <div class="input">
107 107 ${h.text('email',class_='medium')}
108 108 </div>
109 109 </div>
110 110
111 111 <div class="field">
112 112 <div class="label label-checkbox">
113 113 <label for="active">${_('Active')}:</label>
114 114 </div>
115 115 <div class="checkboxes">
116 116 ${h.checkbox('active',value=True)}
117 117 </div>
118 118 </div>
119 119
120 120 <div class="field">
121 121 <div class="label label-checkbox">
122 122 <label for="admin">${_('Admin')}:</label>
123 123 </div>
124 124 <div class="checkboxes">
125 125 ${h.checkbox('admin',value=True)}
126 126 </div>
127 127 </div>
128 128 <div class="buttons">
129 129 ${h.submit('save',_('Save'),class_="ui-btn large")}
130 130 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
131 131 </div>
132 132 </div>
133 133 </div>
134 134 ${h.end_form()}
135 135 </div>
136 136 <div class="box box-right">
137 137 <!-- box / title -->
138 138 <div class="title">
139 139 <h5>${_('Permissions')}</h5>
140 140 </div>
141 141 ${h.form(url('user_perm', id=c.user.user_id),method='put')}
142 142 <div class="form">
143 143 <!-- fields -->
144 144 <div class="fields">
145 145 <div class="field">
146 146 <div class="label label-checkbox">
147 147 <label for="create_repo_perm">${_('Create repositories')}:</label>
148 148 </div>
149 149 <div class="checkboxes">
150 150 ${h.checkbox('create_repo_perm',value=True)}
151 151 </div>
152 152 </div>
153 153 <div class="buttons">
154 154 ${h.submit('save',_('Save'),class_="ui-btn large")}
155 155 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
156 156 </div>
157 157 </div>
158 158 </div>
159 159 ${h.end_form()}
160 160
161 161 ## permissions overview
162 162 <div id="perms" class="table">
163 163 %for section in sorted(c.perm_user.permissions.keys()):
164 164 <div class="perms_section_head">${section.replace("_"," ").capitalize()}</div>
165 165
166 166 <div id='tbl_list_wrap_${section}' class="yui-skin-sam">
167 167 <table id="tbl_list_${section}">
168 168 <thead>
169 169 <tr>
170 170 <th class="left">${_('Name')}</th>
171 171 <th class="left">${_('Permission')}</th>
172 <th class="left">${_('Edit Permission')}</th>
172 173 </thead>
173 174 <tbody>
174 175 %for k in c.perm_user.permissions[section]:
175 176 <%
176 177 if section != 'global':
177 178 section_perm = c.perm_user.permissions[section].get(k)
178 179 _perm = section_perm.split('.')[-1]
179 180 else:
180 181 _perm = section_perm = None
181 182 %>
182 183 <tr>
183 184 <td>
184 185 %if section == 'repositories':
185 186 <a href="${h.url('summary_home',repo_name=k)}">${k}</a>
186 187 %elif section == 'repositories_groups':
187 188 <a href="${h.url('repos_group_home',group_name=k)}">${k}</a>
188 189 %else:
189 190 ${h.get_permission_name(k)}
190 191 %endif
191 192 </td>
192 193 <td>
193 194 %if section == 'global':
194 195 ${h.bool2icon(k.split('.')[-1] != 'none')}
195 196 %else:
196 197 <span class="perm_tag ${_perm}">${section_perm}</span>
197 198 %endif
198 </td>
199 </td>
200 <td>
201 %if section == 'repositories':
202 <a href="${h.url('edit_repo',repo_name=k,anchor='permissions_manage')}">${_('edit')}</a>
203 %elif section == 'repositories_groups':
204 <a href="${h.url('edit_repos_group',id=k,anchor='permissions_manage')}">${_('edit')}</a>
205 %else:
206 --
207 %endif
208 </td>
199 209 </tr>
200 210 %endfor
201 211 </tbody>
202 212 </table>
203 213 </div>
204 214 %endfor
205 215 </div>
206 216 </div>
207 217 <div class="box box-left">
208 218 <!-- box / title -->
209 219 <div class="title">
210 220 <h5>${_('Email addresses')}</h5>
211 221 </div>
212 222
213 223 <div class="emails_wrap">
214 224 <table class="noborder">
215 225 %for em in c.user_email_map:
216 226 <tr>
217 227 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(em.user.email,16)}"/> </div></td>
218 228 <td><div class="email">${em.email}</div></td>
219 229 <td>
220 230 ${h.form(url('user_emails_delete', id=c.user.user_id),method='delete')}
221 231 ${h.hidden('del_email',em.email_id)}
222 232 ${h.submit('remove_',_('delete'),id="remove_email_%s" % em.email_id,
223 233 class_="delete_icon action_button", onclick="return confirm('"+_('Confirm to delete this email: %s') % em.email+"');")}
224 234 ${h.end_form()}
225 235 </td>
226 236 </tr>
227 237 %endfor
228 238 </table>
229 239 </div>
230 240
231 241 ${h.form(url('user_emails', id=c.user.user_id),method='put')}
232 242 <div class="form">
233 243 <!-- fields -->
234 244 <div class="fields">
235 245 <div class="field">
236 246 <div class="label">
237 247 <label for="email">${_('New email address')}:</label>
238 248 </div>
239 249 <div class="input">
240 250 ${h.text('new_email', class_='medium')}
241 251 </div>
242 252 </div>
243 253 <div class="buttons">
244 254 ${h.submit('save',_('Add'),class_="ui-btn large")}
245 255 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
246 256 </div>
247 257 </div>
248 258 </div>
249 259 ${h.end_form()}
250 260 </div>
251 261 </%def>
General Comments 0
You need to be logged in to leave comments. Login now