##// END OF EJS Templates
repository-permissions: enable shortcut to set private mode in permission page.
ergo -
r3809:d49b6555 stable
parent child Browse files
Show More
@@ -1,500 +1,504 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2019 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 from rhodecode.apps._base import add_route_with_slash
21 21
22 22
23 23 def includeme(config):
24 24
25 25 # repo creating checks, special cases that aren't repo routes
26 26 config.add_route(
27 27 name='repo_creating',
28 28 pattern='/{repo_name:.*?[^/]}/repo_creating')
29 29
30 30 config.add_route(
31 31 name='repo_creating_check',
32 32 pattern='/{repo_name:.*?[^/]}/repo_creating_check')
33 33
34 34 # Summary
35 35 # NOTE(marcink): one additional route is defined in very bottom, catch
36 36 # all pattern
37 37 config.add_route(
38 38 name='repo_summary_explicit',
39 39 pattern='/{repo_name:.*?[^/]}/summary', repo_route=True)
40 40 config.add_route(
41 41 name='repo_summary_commits',
42 42 pattern='/{repo_name:.*?[^/]}/summary-commits', repo_route=True)
43 43
44 44 # Commits
45 45 config.add_route(
46 46 name='repo_commit',
47 47 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}', repo_route=True)
48 48
49 49 config.add_route(
50 50 name='repo_commit_children',
51 51 pattern='/{repo_name:.*?[^/]}/changeset_children/{commit_id}', repo_route=True)
52 52
53 53 config.add_route(
54 54 name='repo_commit_parents',
55 55 pattern='/{repo_name:.*?[^/]}/changeset_parents/{commit_id}', repo_route=True)
56 56
57 57 config.add_route(
58 58 name='repo_commit_raw',
59 59 pattern='/{repo_name:.*?[^/]}/changeset-diff/{commit_id}', repo_route=True)
60 60
61 61 config.add_route(
62 62 name='repo_commit_patch',
63 63 pattern='/{repo_name:.*?[^/]}/changeset-patch/{commit_id}', repo_route=True)
64 64
65 65 config.add_route(
66 66 name='repo_commit_download',
67 67 pattern='/{repo_name:.*?[^/]}/changeset-download/{commit_id}', repo_route=True)
68 68
69 69 config.add_route(
70 70 name='repo_commit_data',
71 71 pattern='/{repo_name:.*?[^/]}/changeset-data/{commit_id}', repo_route=True)
72 72
73 73 config.add_route(
74 74 name='repo_commit_comment_create',
75 75 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/create', repo_route=True)
76 76
77 77 config.add_route(
78 78 name='repo_commit_comment_preview',
79 79 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/preview', repo_route=True)
80 80
81 81 config.add_route(
82 82 name='repo_commit_comment_delete',
83 83 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/{comment_id}/delete', repo_route=True)
84 84
85 85 # still working url for backward compat.
86 86 config.add_route(
87 87 name='repo_commit_raw_deprecated',
88 88 pattern='/{repo_name:.*?[^/]}/raw-changeset/{commit_id}', repo_route=True)
89 89
90 90 # Files
91 91 config.add_route(
92 92 name='repo_archivefile',
93 93 pattern='/{repo_name:.*?[^/]}/archive/{fname:.*}', repo_route=True)
94 94
95 95 config.add_route(
96 96 name='repo_files_diff',
97 97 pattern='/{repo_name:.*?[^/]}/diff/{f_path:.*}', repo_route=True)
98 98 config.add_route( # legacy route to make old links work
99 99 name='repo_files_diff_2way_redirect',
100 100 pattern='/{repo_name:.*?[^/]}/diff-2way/{f_path:.*}', repo_route=True)
101 101
102 102 config.add_route(
103 103 name='repo_files',
104 104 pattern='/{repo_name:.*?[^/]}/files/{commit_id}/{f_path:.*}', repo_route=True)
105 105 config.add_route(
106 106 name='repo_files:default_path',
107 107 pattern='/{repo_name:.*?[^/]}/files/{commit_id}/', repo_route=True)
108 108 config.add_route(
109 109 name='repo_files:default_commit',
110 110 pattern='/{repo_name:.*?[^/]}/files', repo_route=True)
111 111
112 112 config.add_route(
113 113 name='repo_files:rendered',
114 114 pattern='/{repo_name:.*?[^/]}/render/{commit_id}/{f_path:.*}', repo_route=True)
115 115
116 116 config.add_route(
117 117 name='repo_files:annotated',
118 118 pattern='/{repo_name:.*?[^/]}/annotate/{commit_id}/{f_path:.*}', repo_route=True)
119 119 config.add_route(
120 120 name='repo_files:annotated_previous',
121 121 pattern='/{repo_name:.*?[^/]}/annotate-previous/{commit_id}/{f_path:.*}', repo_route=True)
122 122
123 123 config.add_route(
124 124 name='repo_nodetree_full',
125 125 pattern='/{repo_name:.*?[^/]}/nodetree_full/{commit_id}/{f_path:.*}', repo_route=True)
126 126 config.add_route(
127 127 name='repo_nodetree_full:default_path',
128 128 pattern='/{repo_name:.*?[^/]}/nodetree_full/{commit_id}/', repo_route=True)
129 129
130 130 config.add_route(
131 131 name='repo_files_nodelist',
132 132 pattern='/{repo_name:.*?[^/]}/nodelist/{commit_id}/{f_path:.*}', repo_route=True)
133 133
134 134 config.add_route(
135 135 name='repo_file_raw',
136 136 pattern='/{repo_name:.*?[^/]}/raw/{commit_id}/{f_path:.*}', repo_route=True)
137 137
138 138 config.add_route(
139 139 name='repo_file_download',
140 140 pattern='/{repo_name:.*?[^/]}/download/{commit_id}/{f_path:.*}', repo_route=True)
141 141 config.add_route( # backward compat to keep old links working
142 142 name='repo_file_download:legacy',
143 143 pattern='/{repo_name:.*?[^/]}/rawfile/{commit_id}/{f_path:.*}',
144 144 repo_route=True)
145 145
146 146 config.add_route(
147 147 name='repo_file_history',
148 148 pattern='/{repo_name:.*?[^/]}/history/{commit_id}/{f_path:.*}', repo_route=True)
149 149
150 150 config.add_route(
151 151 name='repo_file_authors',
152 152 pattern='/{repo_name:.*?[^/]}/authors/{commit_id}/{f_path:.*}', repo_route=True)
153 153
154 154 config.add_route(
155 155 name='repo_files_remove_file',
156 156 pattern='/{repo_name:.*?[^/]}/remove_file/{commit_id}/{f_path:.*}',
157 157 repo_route=True)
158 158 config.add_route(
159 159 name='repo_files_delete_file',
160 160 pattern='/{repo_name:.*?[^/]}/delete_file/{commit_id}/{f_path:.*}',
161 161 repo_route=True)
162 162 config.add_route(
163 163 name='repo_files_edit_file',
164 164 pattern='/{repo_name:.*?[^/]}/edit_file/{commit_id}/{f_path:.*}',
165 165 repo_route=True)
166 166 config.add_route(
167 167 name='repo_files_update_file',
168 168 pattern='/{repo_name:.*?[^/]}/update_file/{commit_id}/{f_path:.*}',
169 169 repo_route=True)
170 170 config.add_route(
171 171 name='repo_files_add_file',
172 172 pattern='/{repo_name:.*?[^/]}/add_file/{commit_id}/{f_path:.*}',
173 173 repo_route=True)
174 174 config.add_route(
175 175 name='repo_files_upload_file',
176 176 pattern='/{repo_name:.*?[^/]}/upload_file/{commit_id}/{f_path:.*}',
177 177 repo_route=True)
178 178 config.add_route(
179 179 name='repo_files_create_file',
180 180 pattern='/{repo_name:.*?[^/]}/create_file/{commit_id}/{f_path:.*}',
181 181 repo_route=True)
182 182
183 183 # Refs data
184 184 config.add_route(
185 185 name='repo_refs_data',
186 186 pattern='/{repo_name:.*?[^/]}/refs-data', repo_route=True)
187 187
188 188 config.add_route(
189 189 name='repo_refs_changelog_data',
190 190 pattern='/{repo_name:.*?[^/]}/refs-data-changelog', repo_route=True)
191 191
192 192 config.add_route(
193 193 name='repo_stats',
194 194 pattern='/{repo_name:.*?[^/]}/repo_stats/{commit_id}', repo_route=True)
195 195
196 196 # Commits
197 197 config.add_route(
198 198 name='repo_commits',
199 199 pattern='/{repo_name:.*?[^/]}/commits', repo_route=True)
200 200 config.add_route(
201 201 name='repo_commits_file',
202 202 pattern='/{repo_name:.*?[^/]}/commits/{commit_id}/{f_path:.*}', repo_route=True)
203 203 config.add_route(
204 204 name='repo_commits_elements',
205 205 pattern='/{repo_name:.*?[^/]}/commits_elements', repo_route=True)
206 206 config.add_route(
207 207 name='repo_commits_elements_file',
208 208 pattern='/{repo_name:.*?[^/]}/commits_elements/{commit_id}/{f_path:.*}', repo_route=True)
209 209
210 210 # Changelog (old deprecated name for commits page)
211 211 config.add_route(
212 212 name='repo_changelog',
213 213 pattern='/{repo_name:.*?[^/]}/changelog', repo_route=True)
214 214 config.add_route(
215 215 name='repo_changelog_file',
216 216 pattern='/{repo_name:.*?[^/]}/changelog/{commit_id}/{f_path:.*}', repo_route=True)
217 217
218 218 # Compare
219 219 config.add_route(
220 220 name='repo_compare_select',
221 221 pattern='/{repo_name:.*?[^/]}/compare', repo_route=True)
222 222
223 223 config.add_route(
224 224 name='repo_compare',
225 225 pattern='/{repo_name:.*?[^/]}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}', repo_route=True)
226 226
227 227 # Tags
228 228 config.add_route(
229 229 name='tags_home',
230 230 pattern='/{repo_name:.*?[^/]}/tags', repo_route=True)
231 231
232 232 # Branches
233 233 config.add_route(
234 234 name='branches_home',
235 235 pattern='/{repo_name:.*?[^/]}/branches', repo_route=True)
236 236
237 237 # Bookmarks
238 238 config.add_route(
239 239 name='bookmarks_home',
240 240 pattern='/{repo_name:.*?[^/]}/bookmarks', repo_route=True)
241 241
242 242 # Forks
243 243 config.add_route(
244 244 name='repo_fork_new',
245 245 pattern='/{repo_name:.*?[^/]}/fork', repo_route=True,
246 246 repo_forbid_when_archived=True,
247 247 repo_accepted_types=['hg', 'git'])
248 248
249 249 config.add_route(
250 250 name='repo_fork_create',
251 251 pattern='/{repo_name:.*?[^/]}/fork/create', repo_route=True,
252 252 repo_forbid_when_archived=True,
253 253 repo_accepted_types=['hg', 'git'])
254 254
255 255 config.add_route(
256 256 name='repo_forks_show_all',
257 257 pattern='/{repo_name:.*?[^/]}/forks', repo_route=True,
258 258 repo_accepted_types=['hg', 'git'])
259 259 config.add_route(
260 260 name='repo_forks_data',
261 261 pattern='/{repo_name:.*?[^/]}/forks/data', repo_route=True,
262 262 repo_accepted_types=['hg', 'git'])
263 263
264 264 # Pull Requests
265 265 config.add_route(
266 266 name='pullrequest_show',
267 267 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}',
268 268 repo_route=True)
269 269
270 270 config.add_route(
271 271 name='pullrequest_show_all',
272 272 pattern='/{repo_name:.*?[^/]}/pull-request',
273 273 repo_route=True, repo_accepted_types=['hg', 'git'])
274 274
275 275 config.add_route(
276 276 name='pullrequest_show_all_data',
277 277 pattern='/{repo_name:.*?[^/]}/pull-request-data',
278 278 repo_route=True, repo_accepted_types=['hg', 'git'])
279 279
280 280 config.add_route(
281 281 name='pullrequest_repo_refs',
282 282 pattern='/{repo_name:.*?[^/]}/pull-request/refs/{target_repo_name:.*?[^/]}',
283 283 repo_route=True)
284 284
285 285 config.add_route(
286 286 name='pullrequest_repo_targets',
287 287 pattern='/{repo_name:.*?[^/]}/pull-request/repo-targets',
288 288 repo_route=True)
289 289
290 290 config.add_route(
291 291 name='pullrequest_new',
292 292 pattern='/{repo_name:.*?[^/]}/pull-request/new',
293 293 repo_route=True, repo_accepted_types=['hg', 'git'],
294 294 repo_forbid_when_archived=True)
295 295
296 296 config.add_route(
297 297 name='pullrequest_create',
298 298 pattern='/{repo_name:.*?[^/]}/pull-request/create',
299 299 repo_route=True, repo_accepted_types=['hg', 'git'],
300 300 repo_forbid_when_archived=True)
301 301
302 302 config.add_route(
303 303 name='pullrequest_update',
304 304 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/update',
305 305 repo_route=True, repo_forbid_when_archived=True)
306 306
307 307 config.add_route(
308 308 name='pullrequest_merge',
309 309 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/merge',
310 310 repo_route=True, repo_forbid_when_archived=True)
311 311
312 312 config.add_route(
313 313 name='pullrequest_delete',
314 314 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/delete',
315 315 repo_route=True, repo_forbid_when_archived=True)
316 316
317 317 config.add_route(
318 318 name='pullrequest_comment_create',
319 319 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment',
320 320 repo_route=True)
321 321
322 322 config.add_route(
323 323 name='pullrequest_comment_delete',
324 324 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment/{comment_id}/delete',
325 325 repo_route=True, repo_accepted_types=['hg', 'git'])
326 326
327 327 # Artifacts, (EE feature)
328 328 config.add_route(
329 329 name='repo_artifacts_list',
330 330 pattern='/{repo_name:.*?[^/]}/artifacts', repo_route=True)
331 331
332 332 # Settings
333 333 config.add_route(
334 334 name='edit_repo',
335 335 pattern='/{repo_name:.*?[^/]}/settings', repo_route=True)
336 336 # update is POST on edit_repo
337 337
338 338 # Settings advanced
339 339 config.add_route(
340 340 name='edit_repo_advanced',
341 341 pattern='/{repo_name:.*?[^/]}/settings/advanced', repo_route=True)
342 342 config.add_route(
343 343 name='edit_repo_advanced_archive',
344 344 pattern='/{repo_name:.*?[^/]}/settings/advanced/archive', repo_route=True)
345 345 config.add_route(
346 346 name='edit_repo_advanced_delete',
347 347 pattern='/{repo_name:.*?[^/]}/settings/advanced/delete', repo_route=True)
348 348 config.add_route(
349 349 name='edit_repo_advanced_locking',
350 350 pattern='/{repo_name:.*?[^/]}/settings/advanced/locking', repo_route=True)
351 351 config.add_route(
352 352 name='edit_repo_advanced_journal',
353 353 pattern='/{repo_name:.*?[^/]}/settings/advanced/journal', repo_route=True)
354 354 config.add_route(
355 355 name='edit_repo_advanced_fork',
356 356 pattern='/{repo_name:.*?[^/]}/settings/advanced/fork', repo_route=True)
357 357
358 358 config.add_route(
359 359 name='edit_repo_advanced_hooks',
360 360 pattern='/{repo_name:.*?[^/]}/settings/advanced/hooks', repo_route=True)
361 361
362 362 # Caches
363 363 config.add_route(
364 364 name='edit_repo_caches',
365 365 pattern='/{repo_name:.*?[^/]}/settings/caches', repo_route=True)
366 366
367 367 # Permissions
368 368 config.add_route(
369 369 name='edit_repo_perms',
370 370 pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True)
371 371
372 config.add_route(
373 name='edit_repo_perms_set_private',
374 pattern='/{repo_name:.*?[^/]}/settings/permissions/set_private', repo_route=True)
375
372 376 # Permissions Branch (EE feature)
373 377 config.add_route(
374 378 name='edit_repo_perms_branch',
375 379 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions', repo_route=True)
376 380 config.add_route(
377 381 name='edit_repo_perms_branch_delete',
378 382 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions/{rule_id}/delete',
379 383 repo_route=True)
380 384
381 385 # Maintenance
382 386 config.add_route(
383 387 name='edit_repo_maintenance',
384 388 pattern='/{repo_name:.*?[^/]}/settings/maintenance', repo_route=True)
385 389
386 390 config.add_route(
387 391 name='edit_repo_maintenance_execute',
388 392 pattern='/{repo_name:.*?[^/]}/settings/maintenance/execute', repo_route=True)
389 393
390 394 # Fields
391 395 config.add_route(
392 396 name='edit_repo_fields',
393 397 pattern='/{repo_name:.*?[^/]}/settings/fields', repo_route=True)
394 398 config.add_route(
395 399 name='edit_repo_fields_create',
396 400 pattern='/{repo_name:.*?[^/]}/settings/fields/create', repo_route=True)
397 401 config.add_route(
398 402 name='edit_repo_fields_delete',
399 403 pattern='/{repo_name:.*?[^/]}/settings/fields/{field_id}/delete', repo_route=True)
400 404
401 405 # Locking
402 406 config.add_route(
403 407 name='repo_edit_toggle_locking',
404 408 pattern='/{repo_name:.*?[^/]}/settings/toggle_locking', repo_route=True)
405 409
406 410 # Remote
407 411 config.add_route(
408 412 name='edit_repo_remote',
409 413 pattern='/{repo_name:.*?[^/]}/settings/remote', repo_route=True)
410 414 config.add_route(
411 415 name='edit_repo_remote_pull',
412 416 pattern='/{repo_name:.*?[^/]}/settings/remote/pull', repo_route=True)
413 417 config.add_route(
414 418 name='edit_repo_remote_push',
415 419 pattern='/{repo_name:.*?[^/]}/settings/remote/push', repo_route=True)
416 420
417 421 # Statistics
418 422 config.add_route(
419 423 name='edit_repo_statistics',
420 424 pattern='/{repo_name:.*?[^/]}/settings/statistics', repo_route=True)
421 425 config.add_route(
422 426 name='edit_repo_statistics_reset',
423 427 pattern='/{repo_name:.*?[^/]}/settings/statistics/update', repo_route=True)
424 428
425 429 # Issue trackers
426 430 config.add_route(
427 431 name='edit_repo_issuetracker',
428 432 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers', repo_route=True)
429 433 config.add_route(
430 434 name='edit_repo_issuetracker_test',
431 435 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/test', repo_route=True)
432 436 config.add_route(
433 437 name='edit_repo_issuetracker_delete',
434 438 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/delete', repo_route=True)
435 439 config.add_route(
436 440 name='edit_repo_issuetracker_update',
437 441 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/update', repo_route=True)
438 442
439 443 # VCS Settings
440 444 config.add_route(
441 445 name='edit_repo_vcs',
442 446 pattern='/{repo_name:.*?[^/]}/settings/vcs', repo_route=True)
443 447 config.add_route(
444 448 name='edit_repo_vcs_update',
445 449 pattern='/{repo_name:.*?[^/]}/settings/vcs/update', repo_route=True)
446 450
447 451 # svn pattern
448 452 config.add_route(
449 453 name='edit_repo_vcs_svn_pattern_delete',
450 454 pattern='/{repo_name:.*?[^/]}/settings/vcs/svn_pattern/delete', repo_route=True)
451 455
452 456 # Repo Review Rules (EE feature)
453 457 config.add_route(
454 458 name='repo_reviewers',
455 459 pattern='/{repo_name:.*?[^/]}/settings/review/rules', repo_route=True)
456 460
457 461 config.add_route(
458 462 name='repo_default_reviewers_data',
459 463 pattern='/{repo_name:.*?[^/]}/settings/review/default-reviewers', repo_route=True)
460 464
461 465 # Repo Automation (EE feature)
462 466 config.add_route(
463 467 name='repo_automation',
464 468 pattern='/{repo_name:.*?[^/]}/settings/automation', repo_route=True)
465 469
466 470 # Strip
467 471 config.add_route(
468 472 name='edit_repo_strip',
469 473 pattern='/{repo_name:.*?[^/]}/settings/strip', repo_route=True)
470 474
471 475 config.add_route(
472 476 name='strip_check',
473 477 pattern='/{repo_name:.*?[^/]}/settings/strip_check', repo_route=True)
474 478
475 479 config.add_route(
476 480 name='strip_execute',
477 481 pattern='/{repo_name:.*?[^/]}/settings/strip_execute', repo_route=True)
478 482
479 483 # Audit logs
480 484 config.add_route(
481 485 name='edit_repo_audit_logs',
482 486 pattern='/{repo_name:.*?[^/]}/settings/audit_logs', repo_route=True)
483 487
484 488 # ATOM/RSS Feed
485 489 config.add_route(
486 490 name='rss_feed_home',
487 491 pattern='/{repo_name:.*?[^/]}/feed/rss', repo_route=True)
488 492
489 493 config.add_route(
490 494 name='atom_feed_home',
491 495 pattern='/{repo_name:.*?[^/]}/feed/atom', repo_route=True)
492 496
493 497 # NOTE(marcink): needs to be at the end for catch-all
494 498 add_route_with_slash(
495 499 config,
496 500 name='repo_summary',
497 501 pattern='/{repo_name:.*?[^/]}', repo_route=True)
498 502
499 503 # Scan module for configuration decorators.
500 504 config.scan('.views', ignore='.tests')
@@ -1,107 +1,134 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2019 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 import logging
22 22
23 23 from pyramid.httpexceptions import HTTPFound
24 24 from pyramid.view import view_config
25 25
26 26 from rhodecode import events
27 27 from rhodecode.apps._base import RepoAppView
28 28 from rhodecode.lib import helpers as h
29 29 from rhodecode.lib import audit_logger
30 30 from rhodecode.lib.auth import (
31 31 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
32 32 from rhodecode.lib.utils2 import safe_int
33 33 from rhodecode.model.db import UserGroup
34 34 from rhodecode.model.forms import RepoPermsForm
35 35 from rhodecode.model.meta import Session
36 36 from rhodecode.model.repo import RepoModel
37 37
38 38 log = logging.getLogger(__name__)
39 39
40 40
41 41 class RepoSettingsPermissionsView(RepoAppView):
42 42
43 43 def load_default_context(self):
44 44 c = self._get_local_tmpl_context()
45 45 return c
46 46
47 47 @LoginRequired()
48 48 @HasRepoPermissionAnyDecorator('repository.admin')
49 49 @view_config(
50 50 route_name='edit_repo_perms', request_method='GET',
51 51 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
52 52 def edit_permissions(self):
53 53 _ = self.request.translate
54 54 c = self.load_default_context()
55 55 c.active = 'permissions'
56 56 if self.request.GET.get('branch_permissions'):
57 57 h.flash(_('Explicitly add user or user group with write+ '
58 58 'permission to modify their branch permissions.'),
59 59 category='notice')
60 60 return self._get_template_context(c)
61 61
62 62 @LoginRequired()
63 63 @HasRepoPermissionAnyDecorator('repository.admin')
64 64 @CSRFRequired()
65 65 @view_config(
66 66 route_name='edit_repo_perms', request_method='POST',
67 67 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
68 68 def edit_permissions_update(self):
69 69 _ = self.request.translate
70 70 c = self.load_default_context()
71 71 c.active = 'permissions'
72 72 data = self.request.POST
73 73 # store private flag outside of HTML to verify if we can modify
74 74 # default user permissions, prevents submission of FAKE post data
75 75 # into the form for private repos
76 76 data['repo_private'] = self.db_repo.private
77 77 form = RepoPermsForm(self.request.translate)().to_python(data)
78 78 changes = RepoModel().update_permissions(
79 79 self.db_repo_name, form['perm_additions'], form['perm_updates'],
80 80 form['perm_deletions'])
81 81
82 82 action_data = {
83 83 'added': changes['added'],
84 84 'updated': changes['updated'],
85 85 'deleted': changes['deleted'],
86 86 }
87 87 audit_logger.store_web(
88 88 'repo.edit.permissions', action_data=action_data,
89 89 user=self._rhodecode_user, repo=self.db_repo)
90 90
91 91 Session().commit()
92 92 h.flash(_('Repository permissions updated'), category='success')
93 93
94 94 affected_user_ids = []
95 95 for change in changes['added'] + changes['updated'] + changes['deleted']:
96 96 if change['type'] == 'user':
97 97 affected_user_ids.append(change['id'])
98 98 if change['type'] == 'user_group':
99 99 user_group = UserGroup.get(safe_int(change['id']))
100 100 if user_group:
101 101 group_members_ids = [x.user_id for x in user_group.members]
102 102 affected_user_ids.extend(group_members_ids)
103 103
104 104 events.trigger(events.UserPermissionsChange(affected_user_ids))
105 105
106 106 raise HTTPFound(
107 107 h.route_path('edit_repo_perms', repo_name=self.db_repo_name))
108
109 @LoginRequired()
110 @HasRepoPermissionAnyDecorator('repository.admin')
111 @CSRFRequired()
112 @view_config(
113 route_name='edit_repo_perms_set_private', request_method='POST',
114 renderer='json_ext')
115 def edit_permissions_set_private_repo(self):
116 _ = self.request.translate
117 self.load_default_context()
118
119 try:
120 RepoModel().update(
121 self.db_repo, **{'repo_private': True, 'repo_name': self.db_repo_name})
122 Session().commit()
123
124 h.flash(_('Repository `{}` private mode set successfully').format(self.db_repo_name),
125 category='success')
126 except Exception:
127 log.exception("Exception during update of repository")
128 h.flash(_('Error occurred during update of repository {}').format(
129 self.db_repo_name), category='error')
130
131 return {
132 'redirect_url': h.route_path('edit_repo_perms', repo_name=self.db_repo_name),
133 'private': True
134 }
@@ -1,1073 +1,1072 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2019 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 import os
22 22 import re
23 23 import shutil
24 24 import time
25 25 import logging
26 26 import traceback
27 27 import datetime
28 28
29 29 from pyramid.threadlocal import get_current_request
30 30 from zope.cachedescriptors.property import Lazy as LazyProperty
31 31
32 32 from rhodecode import events
33 33 from rhodecode.lib.auth import HasUserGroupPermissionAny
34 34 from rhodecode.lib.caching_query import FromCache
35 35 from rhodecode.lib.exceptions import AttachedForksError, AttachedPullRequestsError
36 36 from rhodecode.lib.hooks_base import log_delete_repository
37 37 from rhodecode.lib.user_log_filter import user_log_filter
38 38 from rhodecode.lib.utils import make_db_config
39 39 from rhodecode.lib.utils2 import (
40 40 safe_str, safe_unicode, remove_prefix, obfuscate_url_pw,
41 41 get_current_rhodecode_user, safe_int, datetime_to_time,
42 42 action_logger_generic)
43 43 from rhodecode.lib.vcs.backends import get_backend
44 44 from rhodecode.model import BaseModel
45 45 from rhodecode.model.db import (
46 46 _hash_key, joinedload, or_, Repository, UserRepoToPerm, UserGroupRepoToPerm,
47 47 UserRepoGroupToPerm, UserGroupRepoGroupToPerm, User, Permission,
48 48 Statistics, UserGroup, RepoGroup, RepositoryField, UserLog)
49 49
50 50 from rhodecode.model.settings import VcsSettingsModel
51 51
52 52
53 53 log = logging.getLogger(__name__)
54 54
55 55
56 56 class RepoModel(BaseModel):
57 57
58 58 cls = Repository
59 59
60 60 def _get_user_group(self, users_group):
61 61 return self._get_instance(UserGroup, users_group,
62 62 callback=UserGroup.get_by_group_name)
63 63
64 64 def _get_repo_group(self, repo_group):
65 65 return self._get_instance(RepoGroup, repo_group,
66 66 callback=RepoGroup.get_by_group_name)
67 67
68 68 def _create_default_perms(self, repository, private):
69 69 # create default permission
70 70 default = 'repository.read'
71 71 def_user = User.get_default_user()
72 72 for p in def_user.user_perms:
73 73 if p.permission.permission_name.startswith('repository.'):
74 74 default = p.permission.permission_name
75 75 break
76 76
77 77 default_perm = 'repository.none' if private else default
78 78
79 79 repo_to_perm = UserRepoToPerm()
80 80 repo_to_perm.permission = Permission.get_by_key(default_perm)
81 81
82 82 repo_to_perm.repository = repository
83 83 repo_to_perm.user_id = def_user.user_id
84 84
85 85 return repo_to_perm
86 86
87 87 @LazyProperty
88 88 def repos_path(self):
89 89 """
90 90 Gets the repositories root path from database
91 91 """
92 92 settings_model = VcsSettingsModel(sa=self.sa)
93 93 return settings_model.get_repos_location()
94 94
95 95 def get(self, repo_id):
96 96 repo = self.sa.query(Repository) \
97 97 .filter(Repository.repo_id == repo_id)
98 98
99 99 return repo.scalar()
100 100
101 101 def get_repo(self, repository):
102 102 return self._get_repo(repository)
103 103
104 104 def get_by_repo_name(self, repo_name, cache=False):
105 105 repo = self.sa.query(Repository) \
106 106 .filter(Repository.repo_name == repo_name)
107 107
108 108 if cache:
109 109 name_key = _hash_key(repo_name)
110 110 repo = repo.options(
111 111 FromCache("sql_cache_short", "get_repo_%s" % name_key))
112 112 return repo.scalar()
113 113
114 114 def _extract_id_from_repo_name(self, repo_name):
115 115 if repo_name.startswith('/'):
116 116 repo_name = repo_name.lstrip('/')
117 117 by_id_match = re.match(r'^_(\d{1,})', repo_name)
118 118 if by_id_match:
119 119 return by_id_match.groups()[0]
120 120
121 121 def get_repo_by_id(self, repo_name):
122 122 """
123 123 Extracts repo_name by id from special urls.
124 124 Example url is _11/repo_name
125 125
126 126 :param repo_name:
127 127 :return: repo object if matched else None
128 128 """
129 129
130 130 try:
131 131 _repo_id = self._extract_id_from_repo_name(repo_name)
132 132 if _repo_id:
133 133 return self.get(_repo_id)
134 134 except Exception:
135 135 log.exception('Failed to extract repo_name from URL')
136 136
137 137 return None
138 138
139 139 def get_repos_for_root(self, root, traverse=False):
140 140 if traverse:
141 141 like_expression = u'{}%'.format(safe_unicode(root))
142 142 repos = Repository.query().filter(
143 143 Repository.repo_name.like(like_expression)).all()
144 144 else:
145 145 if root and not isinstance(root, RepoGroup):
146 146 raise ValueError(
147 147 'Root must be an instance '
148 148 'of RepoGroup, got:{} instead'.format(type(root)))
149 149 repos = Repository.query().filter(Repository.group == root).all()
150 150 return repos
151 151
152 152 def get_url(self, repo, request=None, permalink=False):
153 153 if not request:
154 154 request = get_current_request()
155 155
156 156 if not request:
157 157 return
158 158
159 159 if permalink:
160 160 return request.route_url(
161 161 'repo_summary', repo_name='_{}'.format(safe_str(repo.repo_id)))
162 162 else:
163 163 return request.route_url(
164 164 'repo_summary', repo_name=safe_str(repo.repo_name))
165 165
166 166 def get_commit_url(self, repo, commit_id, request=None, permalink=False):
167 167 if not request:
168 168 request = get_current_request()
169 169
170 170 if not request:
171 171 return
172 172
173 173 if permalink:
174 174 return request.route_url(
175 175 'repo_commit', repo_name=safe_str(repo.repo_id),
176 176 commit_id=commit_id)
177 177
178 178 else:
179 179 return request.route_url(
180 180 'repo_commit', repo_name=safe_str(repo.repo_name),
181 181 commit_id=commit_id)
182 182
183 183 def get_repo_log(self, repo, filter_term):
184 184 repo_log = UserLog.query()\
185 185 .filter(or_(UserLog.repository_id == repo.repo_id,
186 186 UserLog.repository_name == repo.repo_name))\
187 187 .options(joinedload(UserLog.user))\
188 188 .options(joinedload(UserLog.repository))\
189 189 .order_by(UserLog.action_date.desc())
190 190
191 191 repo_log = user_log_filter(repo_log, filter_term)
192 192 return repo_log
193 193
194 194 @classmethod
195 195 def update_commit_cache(cls, repositories=None):
196 196 if not repositories:
197 197 repositories = Repository.getAll()
198 198 for repo in repositories:
199 199 repo.update_commit_cache()
200 200
201 201 def get_repos_as_dict(self, repo_list=None, admin=False,
202 202 super_user_actions=False, short_name=None):
203 203 _render = get_current_request().get_partial_renderer(
204 204 'rhodecode:templates/data_table/_dt_elements.mako')
205 205 c = _render.get_call_context()
206 206
207 207 def quick_menu(repo_name):
208 208 return _render('quick_menu', repo_name)
209 209
210 210 def repo_lnk(name, rtype, rstate, private, archived, fork_of):
211 211 if short_name is not None:
212 212 short_name_var = short_name
213 213 else:
214 214 short_name_var = not admin
215 215 return _render('repo_name', name, rtype, rstate, private, archived, fork_of,
216 216 short_name=short_name_var, admin=False)
217 217
218 218 def last_change(last_change):
219 219 if admin and isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
220 220 last_change = last_change + datetime.timedelta(seconds=
221 221 (datetime.datetime.now() - datetime.datetime.utcnow()).seconds)
222 222 return _render("last_change", last_change)
223 223
224 224 def rss_lnk(repo_name):
225 225 return _render("rss", repo_name)
226 226
227 227 def atom_lnk(repo_name):
228 228 return _render("atom", repo_name)
229 229
230 230 def last_rev(repo_name, cs_cache):
231 231 return _render('revision', repo_name, cs_cache.get('revision'),
232 232 cs_cache.get('raw_id'), cs_cache.get('author'),
233 233 cs_cache.get('message'), cs_cache.get('date'))
234 234
235 235 def desc(desc):
236 236 return _render('repo_desc', desc, c.visual.stylify_metatags)
237 237
238 238 def state(repo_state):
239 239 return _render("repo_state", repo_state)
240 240
241 241 def repo_actions(repo_name):
242 242 return _render('repo_actions', repo_name, super_user_actions)
243 243
244 244 def user_profile(username):
245 245 return _render('user_profile', username)
246 246
247 247 repos_data = []
248 248 for repo in repo_list:
249 249 cs_cache = repo.changeset_cache
250 250 row = {
251 251 "menu": quick_menu(repo.repo_name),
252 252
253 253 "name": repo_lnk(repo.repo_name, repo.repo_type, repo.repo_state,
254 254 repo.private, repo.archived, repo.fork),
255 255 "name_raw": repo.repo_name.lower(),
256 256
257 257 "last_change": last_change(repo.last_commit_change),
258 258 "last_change_raw": datetime_to_time(repo.last_commit_change),
259 259
260 260 "last_changeset": last_rev(repo.repo_name, cs_cache),
261 261 "last_changeset_raw": cs_cache.get('revision'),
262 262
263 263 "desc": desc(repo.description_safe),
264 264 "owner": user_profile(repo.user.username),
265 265
266 266 "state": state(repo.repo_state),
267 267 "rss": rss_lnk(repo.repo_name),
268 268
269 269 "atom": atom_lnk(repo.repo_name),
270 270 }
271 271 if admin:
272 272 row.update({
273 273 "action": repo_actions(repo.repo_name),
274 274 })
275 275 repos_data.append(row)
276 276
277 277 return repos_data
278 278
279 279 def _get_defaults(self, repo_name):
280 280 """
281 281 Gets information about repository, and returns a dict for
282 282 usage in forms
283 283
284 284 :param repo_name:
285 285 """
286 286
287 287 repo_info = Repository.get_by_repo_name(repo_name)
288 288
289 289 if repo_info is None:
290 290 return None
291 291
292 292 defaults = repo_info.get_dict()
293 293 defaults['repo_name'] = repo_info.just_name
294 294
295 295 groups = repo_info.groups_with_parents
296 296 parent_group = groups[-1] if groups else None
297 297
298 298 # we use -1 as this is how in HTML, we mark an empty group
299 299 defaults['repo_group'] = getattr(parent_group, 'group_id', -1)
300 300
301 301 keys_to_process = (
302 302 {'k': 'repo_type', 'strip': False},
303 303 {'k': 'repo_enable_downloads', 'strip': True},
304 304 {'k': 'repo_description', 'strip': True},
305 305 {'k': 'repo_enable_locking', 'strip': True},
306 306 {'k': 'repo_landing_rev', 'strip': True},
307 307 {'k': 'clone_uri', 'strip': False},
308 308 {'k': 'push_uri', 'strip': False},
309 309 {'k': 'repo_private', 'strip': True},
310 310 {'k': 'repo_enable_statistics', 'strip': True}
311 311 )
312 312
313 313 for item in keys_to_process:
314 314 attr = item['k']
315 315 if item['strip']:
316 316 attr = remove_prefix(item['k'], 'repo_')
317 317
318 318 val = defaults[attr]
319 319 if item['k'] == 'repo_landing_rev':
320 320 val = ':'.join(defaults[attr])
321 321 defaults[item['k']] = val
322 322 if item['k'] == 'clone_uri':
323 323 defaults['clone_uri_hidden'] = repo_info.clone_uri_hidden
324 324 if item['k'] == 'push_uri':
325 325 defaults['push_uri_hidden'] = repo_info.push_uri_hidden
326 326
327 327 # fill owner
328 328 if repo_info.user:
329 329 defaults.update({'user': repo_info.user.username})
330 330 else:
331 331 replacement_user = User.get_first_super_admin().username
332 332 defaults.update({'user': replacement_user})
333 333
334 334 return defaults
335 335
336 336 def update(self, repo, **kwargs):
337 337 try:
338 338 cur_repo = self._get_repo(repo)
339 339 source_repo_name = cur_repo.repo_name
340 340 if 'user' in kwargs:
341 341 cur_repo.user = User.get_by_username(kwargs['user'])
342 342
343 343 if 'repo_group' in kwargs:
344 344 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
345 345 log.debug('Updating repo %s with params:%s', cur_repo, kwargs)
346 346
347 347 update_keys = [
348 348 (1, 'repo_description'),
349 349 (1, 'repo_landing_rev'),
350 350 (1, 'repo_private'),
351 351 (1, 'repo_enable_downloads'),
352 352 (1, 'repo_enable_locking'),
353 353 (1, 'repo_enable_statistics'),
354 354 (0, 'clone_uri'),
355 355 (0, 'push_uri'),
356 356 (0, 'fork_id')
357 357 ]
358 358 for strip, k in update_keys:
359 359 if k in kwargs:
360 360 val = kwargs[k]
361 361 if strip:
362 362 k = remove_prefix(k, 'repo_')
363 363
364 364 setattr(cur_repo, k, val)
365 365
366 366 new_name = cur_repo.get_new_name(kwargs['repo_name'])
367 367 cur_repo.repo_name = new_name
368 368
369 369 # if private flag is set, reset default permission to NONE
370 370 if kwargs.get('repo_private'):
371 371 EMPTY_PERM = 'repository.none'
372 372 RepoModel().grant_user_permission(
373 373 repo=cur_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM
374 374 )
375 375
376 376 # handle extra fields
377 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX),
378 kwargs):
377 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX), kwargs):
379 378 k = RepositoryField.un_prefix_key(field)
380 379 ex_field = RepositoryField.get_by_key_name(
381 380 key=k, repo=cur_repo)
382 381 if ex_field:
383 382 ex_field.field_value = kwargs[field]
384 383 self.sa.add(ex_field)
385 384 cur_repo.updated_on = datetime.datetime.now()
386 385 self.sa.add(cur_repo)
387 386
388 387 if source_repo_name != new_name:
389 388 # rename repository
390 389 self._rename_filesystem_repo(
391 390 old=source_repo_name, new=new_name)
392 391
393 392 return cur_repo
394 393 except Exception:
395 394 log.error(traceback.format_exc())
396 395 raise
397 396
398 397 def _create_repo(self, repo_name, repo_type, description, owner,
399 398 private=False, clone_uri=None, repo_group=None,
400 399 landing_rev='rev:tip', fork_of=None,
401 400 copy_fork_permissions=False, enable_statistics=False,
402 401 enable_locking=False, enable_downloads=False,
403 402 copy_group_permissions=False,
404 403 state=Repository.STATE_PENDING):
405 404 """
406 405 Create repository inside database with PENDING state, this should be
407 406 only executed by create() repo. With exception of importing existing
408 407 repos
409 408 """
410 409 from rhodecode.model.scm import ScmModel
411 410
412 411 owner = self._get_user(owner)
413 412 fork_of = self._get_repo(fork_of)
414 413 repo_group = self._get_repo_group(safe_int(repo_group))
415 414
416 415 try:
417 416 repo_name = safe_unicode(repo_name)
418 417 description = safe_unicode(description)
419 418 # repo name is just a name of repository
420 419 # while repo_name_full is a full qualified name that is combined
421 420 # with name and path of group
422 421 repo_name_full = repo_name
423 422 repo_name = repo_name.split(Repository.NAME_SEP)[-1]
424 423
425 424 new_repo = Repository()
426 425 new_repo.repo_state = state
427 426 new_repo.enable_statistics = False
428 427 new_repo.repo_name = repo_name_full
429 428 new_repo.repo_type = repo_type
430 429 new_repo.user = owner
431 430 new_repo.group = repo_group
432 431 new_repo.description = description or repo_name
433 432 new_repo.private = private
434 433 new_repo.archived = False
435 434 new_repo.clone_uri = clone_uri
436 435 new_repo.landing_rev = landing_rev
437 436
438 437 new_repo.enable_statistics = enable_statistics
439 438 new_repo.enable_locking = enable_locking
440 439 new_repo.enable_downloads = enable_downloads
441 440
442 441 if repo_group:
443 442 new_repo.enable_locking = repo_group.enable_locking
444 443
445 444 if fork_of:
446 445 parent_repo = fork_of
447 446 new_repo.fork = parent_repo
448 447
449 448 events.trigger(events.RepoPreCreateEvent(new_repo))
450 449
451 450 self.sa.add(new_repo)
452 451
453 452 EMPTY_PERM = 'repository.none'
454 453 if fork_of and copy_fork_permissions:
455 454 repo = fork_of
456 455 user_perms = UserRepoToPerm.query() \
457 456 .filter(UserRepoToPerm.repository == repo).all()
458 457 group_perms = UserGroupRepoToPerm.query() \
459 458 .filter(UserGroupRepoToPerm.repository == repo).all()
460 459
461 460 for perm in user_perms:
462 461 UserRepoToPerm.create(
463 462 perm.user, new_repo, perm.permission)
464 463
465 464 for perm in group_perms:
466 465 UserGroupRepoToPerm.create(
467 466 perm.users_group, new_repo, perm.permission)
468 467 # in case we copy permissions and also set this repo to private
469 468 # override the default user permission to make it a private repo
470 469 if private:
471 470 RepoModel(self.sa).grant_user_permission(
472 471 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
473 472
474 473 elif repo_group and copy_group_permissions:
475 474 user_perms = UserRepoGroupToPerm.query() \
476 475 .filter(UserRepoGroupToPerm.group == repo_group).all()
477 476
478 477 group_perms = UserGroupRepoGroupToPerm.query() \
479 478 .filter(UserGroupRepoGroupToPerm.group == repo_group).all()
480 479
481 480 for perm in user_perms:
482 481 perm_name = perm.permission.permission_name.replace(
483 482 'group.', 'repository.')
484 483 perm_obj = Permission.get_by_key(perm_name)
485 484 UserRepoToPerm.create(perm.user, new_repo, perm_obj)
486 485
487 486 for perm in group_perms:
488 487 perm_name = perm.permission.permission_name.replace(
489 488 'group.', 'repository.')
490 489 perm_obj = Permission.get_by_key(perm_name)
491 490 UserGroupRepoToPerm.create(perm.users_group, new_repo, perm_obj)
492 491
493 492 if private:
494 493 RepoModel(self.sa).grant_user_permission(
495 494 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
496 495
497 496 else:
498 497 perm_obj = self._create_default_perms(new_repo, private)
499 498 self.sa.add(perm_obj)
500 499
501 500 # now automatically start following this repository as owner
502 501 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id, owner.user_id)
503 502
504 503 # we need to flush here, in order to check if database won't
505 504 # throw any exceptions, create filesystem dirs at the very end
506 505 self.sa.flush()
507 506 events.trigger(events.RepoCreateEvent(new_repo))
508 507 return new_repo
509 508
510 509 except Exception:
511 510 log.error(traceback.format_exc())
512 511 raise
513 512
514 513 def create(self, form_data, cur_user):
515 514 """
516 515 Create repository using celery tasks
517 516
518 517 :param form_data:
519 518 :param cur_user:
520 519 """
521 520 from rhodecode.lib.celerylib import tasks, run_task
522 521 return run_task(tasks.create_repo, form_data, cur_user)
523 522
524 523 def update_permissions(self, repo, perm_additions=None, perm_updates=None,
525 524 perm_deletions=None, check_perms=True,
526 525 cur_user=None):
527 526 if not perm_additions:
528 527 perm_additions = []
529 528 if not perm_updates:
530 529 perm_updates = []
531 530 if not perm_deletions:
532 531 perm_deletions = []
533 532
534 533 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
535 534
536 535 changes = {
537 536 'added': [],
538 537 'updated': [],
539 538 'deleted': []
540 539 }
541 540 # update permissions
542 541 for member_id, perm, member_type in perm_updates:
543 542 member_id = int(member_id)
544 543 if member_type == 'user':
545 544 member_name = User.get(member_id).username
546 545 # this updates also current one if found
547 546 self.grant_user_permission(
548 547 repo=repo, user=member_id, perm=perm)
549 548 elif member_type == 'user_group':
550 549 # check if we have permissions to alter this usergroup
551 550 member_name = UserGroup.get(member_id).users_group_name
552 551 if not check_perms or HasUserGroupPermissionAny(
553 552 *req_perms)(member_name, user=cur_user):
554 553 self.grant_user_group_permission(
555 554 repo=repo, group_name=member_id, perm=perm)
556 555 else:
557 556 raise ValueError("member_type must be 'user' or 'user_group' "
558 557 "got {} instead".format(member_type))
559 558 changes['updated'].append({'type': member_type, 'id': member_id,
560 559 'name': member_name, 'new_perm': perm})
561 560
562 561 # set new permissions
563 562 for member_id, perm, member_type in perm_additions:
564 563 member_id = int(member_id)
565 564 if member_type == 'user':
566 565 member_name = User.get(member_id).username
567 566 self.grant_user_permission(
568 567 repo=repo, user=member_id, perm=perm)
569 568 elif member_type == 'user_group':
570 569 # check if we have permissions to alter this usergroup
571 570 member_name = UserGroup.get(member_id).users_group_name
572 571 if not check_perms or HasUserGroupPermissionAny(
573 572 *req_perms)(member_name, user=cur_user):
574 573 self.grant_user_group_permission(
575 574 repo=repo, group_name=member_id, perm=perm)
576 575 else:
577 576 raise ValueError("member_type must be 'user' or 'user_group' "
578 577 "got {} instead".format(member_type))
579 578
580 579 changes['added'].append({'type': member_type, 'id': member_id,
581 580 'name': member_name, 'new_perm': perm})
582 581 # delete permissions
583 582 for member_id, perm, member_type in perm_deletions:
584 583 member_id = int(member_id)
585 584 if member_type == 'user':
586 585 member_name = User.get(member_id).username
587 586 self.revoke_user_permission(repo=repo, user=member_id)
588 587 elif member_type == 'user_group':
589 588 # check if we have permissions to alter this usergroup
590 589 member_name = UserGroup.get(member_id).users_group_name
591 590 if not check_perms or HasUserGroupPermissionAny(
592 591 *req_perms)(member_name, user=cur_user):
593 592 self.revoke_user_group_permission(
594 593 repo=repo, group_name=member_id)
595 594 else:
596 595 raise ValueError("member_type must be 'user' or 'user_group' "
597 596 "got {} instead".format(member_type))
598 597
599 598 changes['deleted'].append({'type': member_type, 'id': member_id,
600 599 'name': member_name, 'new_perm': perm})
601 600 return changes
602 601
603 602 def create_fork(self, form_data, cur_user):
604 603 """
605 604 Simple wrapper into executing celery task for fork creation
606 605
607 606 :param form_data:
608 607 :param cur_user:
609 608 """
610 609 from rhodecode.lib.celerylib import tasks, run_task
611 610 return run_task(tasks.create_repo_fork, form_data, cur_user)
612 611
613 612 def archive(self, repo):
614 613 """
615 614 Archive given repository. Set archive flag.
616 615
617 616 :param repo:
618 617 """
619 618 repo = self._get_repo(repo)
620 619 if repo:
621 620
622 621 try:
623 622 repo.archived = True
624 623 self.sa.add(repo)
625 624 self.sa.commit()
626 625 except Exception:
627 626 log.error(traceback.format_exc())
628 627 raise
629 628
630 629 def delete(self, repo, forks=None, pull_requests=None, fs_remove=True, cur_user=None):
631 630 """
632 631 Delete given repository, forks parameter defines what do do with
633 632 attached forks. Throws AttachedForksError if deleted repo has attached
634 633 forks
635 634
636 635 :param repo:
637 636 :param forks: str 'delete' or 'detach'
638 637 :param pull_requests: str 'delete' or None
639 638 :param fs_remove: remove(archive) repo from filesystem
640 639 """
641 640 if not cur_user:
642 641 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
643 642 repo = self._get_repo(repo)
644 643 if repo:
645 644 if forks == 'detach':
646 645 for r in repo.forks:
647 646 r.fork = None
648 647 self.sa.add(r)
649 648 elif forks == 'delete':
650 649 for r in repo.forks:
651 650 self.delete(r, forks='delete')
652 651 elif [f for f in repo.forks]:
653 652 raise AttachedForksError()
654 653
655 654 # check for pull requests
656 655 pr_sources = repo.pull_requests_source
657 656 pr_targets = repo.pull_requests_target
658 657 if pull_requests != 'delete' and (pr_sources or pr_targets):
659 658 raise AttachedPullRequestsError()
660 659
661 660 old_repo_dict = repo.get_dict()
662 661 events.trigger(events.RepoPreDeleteEvent(repo))
663 662 try:
664 663 self.sa.delete(repo)
665 664 if fs_remove:
666 665 self._delete_filesystem_repo(repo)
667 666 else:
668 667 log.debug('skipping removal from filesystem')
669 668 old_repo_dict.update({
670 669 'deleted_by': cur_user,
671 670 'deleted_on': time.time(),
672 671 })
673 672 log_delete_repository(**old_repo_dict)
674 673 events.trigger(events.RepoDeleteEvent(repo))
675 674 except Exception:
676 675 log.error(traceback.format_exc())
677 676 raise
678 677
679 678 def grant_user_permission(self, repo, user, perm):
680 679 """
681 680 Grant permission for user on given repository, or update existing one
682 681 if found
683 682
684 683 :param repo: Instance of Repository, repository_id, or repository name
685 684 :param user: Instance of User, user_id or username
686 685 :param perm: Instance of Permission, or permission_name
687 686 """
688 687 user = self._get_user(user)
689 688 repo = self._get_repo(repo)
690 689 permission = self._get_perm(perm)
691 690
692 691 # check if we have that permission already
693 692 obj = self.sa.query(UserRepoToPerm) \
694 693 .filter(UserRepoToPerm.user == user) \
695 694 .filter(UserRepoToPerm.repository == repo) \
696 695 .scalar()
697 696 if obj is None:
698 697 # create new !
699 698 obj = UserRepoToPerm()
700 699 obj.repository = repo
701 700 obj.user = user
702 701 obj.permission = permission
703 702 self.sa.add(obj)
704 703 log.debug('Granted perm %s to %s on %s', perm, user, repo)
705 704 action_logger_generic(
706 705 'granted permission: {} to user: {} on repo: {}'.format(
707 706 perm, user, repo), namespace='security.repo')
708 707 return obj
709 708
710 709 def revoke_user_permission(self, repo, user):
711 710 """
712 711 Revoke permission for user on given repository
713 712
714 713 :param repo: Instance of Repository, repository_id, or repository name
715 714 :param user: Instance of User, user_id or username
716 715 """
717 716
718 717 user = self._get_user(user)
719 718 repo = self._get_repo(repo)
720 719
721 720 obj = self.sa.query(UserRepoToPerm) \
722 721 .filter(UserRepoToPerm.repository == repo) \
723 722 .filter(UserRepoToPerm.user == user) \
724 723 .scalar()
725 724 if obj:
726 725 self.sa.delete(obj)
727 726 log.debug('Revoked perm on %s on %s', repo, user)
728 727 action_logger_generic(
729 728 'revoked permission from user: {} on repo: {}'.format(
730 729 user, repo), namespace='security.repo')
731 730
732 731 def grant_user_group_permission(self, repo, group_name, perm):
733 732 """
734 733 Grant permission for user group on given repository, or update
735 734 existing one if found
736 735
737 736 :param repo: Instance of Repository, repository_id, or repository name
738 737 :param group_name: Instance of UserGroup, users_group_id,
739 738 or user group name
740 739 :param perm: Instance of Permission, or permission_name
741 740 """
742 741 repo = self._get_repo(repo)
743 742 group_name = self._get_user_group(group_name)
744 743 permission = self._get_perm(perm)
745 744
746 745 # check if we have that permission already
747 746 obj = self.sa.query(UserGroupRepoToPerm) \
748 747 .filter(UserGroupRepoToPerm.users_group == group_name) \
749 748 .filter(UserGroupRepoToPerm.repository == repo) \
750 749 .scalar()
751 750
752 751 if obj is None:
753 752 # create new
754 753 obj = UserGroupRepoToPerm()
755 754
756 755 obj.repository = repo
757 756 obj.users_group = group_name
758 757 obj.permission = permission
759 758 self.sa.add(obj)
760 759 log.debug('Granted perm %s to %s on %s', perm, group_name, repo)
761 760 action_logger_generic(
762 761 'granted permission: {} to usergroup: {} on repo: {}'.format(
763 762 perm, group_name, repo), namespace='security.repo')
764 763
765 764 return obj
766 765
767 766 def revoke_user_group_permission(self, repo, group_name):
768 767 """
769 768 Revoke permission for user group on given repository
770 769
771 770 :param repo: Instance of Repository, repository_id, or repository name
772 771 :param group_name: Instance of UserGroup, users_group_id,
773 772 or user group name
774 773 """
775 774 repo = self._get_repo(repo)
776 775 group_name = self._get_user_group(group_name)
777 776
778 777 obj = self.sa.query(UserGroupRepoToPerm) \
779 778 .filter(UserGroupRepoToPerm.repository == repo) \
780 779 .filter(UserGroupRepoToPerm.users_group == group_name) \
781 780 .scalar()
782 781 if obj:
783 782 self.sa.delete(obj)
784 783 log.debug('Revoked perm to %s on %s', repo, group_name)
785 784 action_logger_generic(
786 785 'revoked permission from usergroup: {} on repo: {}'.format(
787 786 group_name, repo), namespace='security.repo')
788 787
789 788 def delete_stats(self, repo_name):
790 789 """
791 790 removes stats for given repo
792 791
793 792 :param repo_name:
794 793 """
795 794 repo = self._get_repo(repo_name)
796 795 try:
797 796 obj = self.sa.query(Statistics) \
798 797 .filter(Statistics.repository == repo).scalar()
799 798 if obj:
800 799 self.sa.delete(obj)
801 800 except Exception:
802 801 log.error(traceback.format_exc())
803 802 raise
804 803
805 804 def add_repo_field(self, repo_name, field_key, field_label, field_value='',
806 805 field_type='str', field_desc=''):
807 806
808 807 repo = self._get_repo(repo_name)
809 808
810 809 new_field = RepositoryField()
811 810 new_field.repository = repo
812 811 new_field.field_key = field_key
813 812 new_field.field_type = field_type # python type
814 813 new_field.field_value = field_value
815 814 new_field.field_desc = field_desc
816 815 new_field.field_label = field_label
817 816 self.sa.add(new_field)
818 817 return new_field
819 818
820 819 def delete_repo_field(self, repo_name, field_key):
821 820 repo = self._get_repo(repo_name)
822 821 field = RepositoryField.get_by_key_name(field_key, repo)
823 822 if field:
824 823 self.sa.delete(field)
825 824
826 825 def _create_filesystem_repo(self, repo_name, repo_type, repo_group,
827 826 clone_uri=None, repo_store_location=None,
828 827 use_global_config=False):
829 828 """
830 829 makes repository on filesystem. It's group aware means it'll create
831 830 a repository within a group, and alter the paths accordingly of
832 831 group location
833 832
834 833 :param repo_name:
835 834 :param alias:
836 835 :param parent:
837 836 :param clone_uri:
838 837 :param repo_store_location:
839 838 """
840 839 from rhodecode.lib.utils import is_valid_repo, is_valid_repo_group
841 840 from rhodecode.model.scm import ScmModel
842 841
843 842 if Repository.NAME_SEP in repo_name:
844 843 raise ValueError(
845 844 'repo_name must not contain groups got `%s`' % repo_name)
846 845
847 846 if isinstance(repo_group, RepoGroup):
848 847 new_parent_path = os.sep.join(repo_group.full_path_splitted)
849 848 else:
850 849 new_parent_path = repo_group or ''
851 850
852 851 if repo_store_location:
853 852 _paths = [repo_store_location]
854 853 else:
855 854 _paths = [self.repos_path, new_parent_path, repo_name]
856 855 # we need to make it str for mercurial
857 856 repo_path = os.path.join(*map(lambda x: safe_str(x), _paths))
858 857
859 858 # check if this path is not a repository
860 859 if is_valid_repo(repo_path, self.repos_path):
861 860 raise Exception('This path %s is a valid repository' % repo_path)
862 861
863 862 # check if this path is a group
864 863 if is_valid_repo_group(repo_path, self.repos_path):
865 864 raise Exception('This path %s is a valid group' % repo_path)
866 865
867 866 log.info('creating repo %s in %s from url: `%s`',
868 867 repo_name, safe_unicode(repo_path),
869 868 obfuscate_url_pw(clone_uri))
870 869
871 870 backend = get_backend(repo_type)
872 871
873 872 config_repo = None if use_global_config else repo_name
874 873 if config_repo and new_parent_path:
875 874 config_repo = Repository.NAME_SEP.join(
876 875 (new_parent_path, config_repo))
877 876 config = make_db_config(clear_session=False, repo=config_repo)
878 877 config.set('extensions', 'largefiles', '')
879 878
880 879 # patch and reset hooks section of UI config to not run any
881 880 # hooks on creating remote repo
882 881 config.clear_section('hooks')
883 882
884 883 # TODO: johbo: Unify this, hardcoded "bare=True" does not look nice
885 884 if repo_type == 'git':
886 885 repo = backend(
887 886 repo_path, config=config, create=True, src_url=clone_uri,
888 887 bare=True)
889 888 else:
890 889 repo = backend(
891 890 repo_path, config=config, create=True, src_url=clone_uri)
892 891
893 892 repo.install_hooks()
894 893
895 894 log.debug('Created repo %s with %s backend',
896 895 safe_unicode(repo_name), safe_unicode(repo_type))
897 896 return repo
898 897
899 898 def _rename_filesystem_repo(self, old, new):
900 899 """
901 900 renames repository on filesystem
902 901
903 902 :param old: old name
904 903 :param new: new name
905 904 """
906 905 log.info('renaming repo from %s to %s', old, new)
907 906
908 907 old_path = os.path.join(self.repos_path, old)
909 908 new_path = os.path.join(self.repos_path, new)
910 909 if os.path.isdir(new_path):
911 910 raise Exception(
912 911 'Was trying to rename to already existing dir %s' % new_path
913 912 )
914 913 shutil.move(old_path, new_path)
915 914
916 915 def _delete_filesystem_repo(self, repo):
917 916 """
918 917 removes repo from filesystem, the removal is acctually made by
919 918 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
920 919 repository is no longer valid for rhodecode, can be undeleted later on
921 920 by reverting the renames on this repository
922 921
923 922 :param repo: repo object
924 923 """
925 924 rm_path = os.path.join(self.repos_path, repo.repo_name)
926 925 repo_group = repo.group
927 926 log.info("Removing repository %s", rm_path)
928 927 # disable hg/git internal that it doesn't get detected as repo
929 928 alias = repo.repo_type
930 929
931 930 config = make_db_config(clear_session=False)
932 931 config.set('extensions', 'largefiles', '')
933 932 bare = getattr(repo.scm_instance(config=config), 'bare', False)
934 933
935 934 # skip this for bare git repos
936 935 if not bare:
937 936 # disable VCS repo
938 937 vcs_path = os.path.join(rm_path, '.%s' % alias)
939 938 if os.path.exists(vcs_path):
940 939 shutil.move(vcs_path, os.path.join(rm_path, 'rm__.%s' % alias))
941 940
942 941 _now = datetime.datetime.now()
943 942 _ms = str(_now.microsecond).rjust(6, '0')
944 943 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
945 944 repo.just_name)
946 945 if repo_group:
947 946 # if repository is in group, prefix the removal path with the group
948 947 args = repo_group.full_path_splitted + [_d]
949 948 _d = os.path.join(*args)
950 949
951 950 if os.path.isdir(rm_path):
952 951 shutil.move(rm_path, os.path.join(self.repos_path, _d))
953 952
954 953 # finally cleanup diff-cache if it exists
955 954 cached_diffs_dir = repo.cached_diffs_dir
956 955 if os.path.isdir(cached_diffs_dir):
957 956 shutil.rmtree(cached_diffs_dir)
958 957
959 958
960 959 class ReadmeFinder:
961 960 """
962 961 Utility which knows how to find a readme for a specific commit.
963 962
964 963 The main idea is that this is a configurable algorithm. When creating an
965 964 instance you can define parameters, currently only the `default_renderer`.
966 965 Based on this configuration the method :meth:`search` behaves slightly
967 966 different.
968 967 """
969 968
970 969 readme_re = re.compile(r'^readme(\.[^\.]+)?$', re.IGNORECASE)
971 970 path_re = re.compile(r'^docs?', re.IGNORECASE)
972 971
973 972 default_priorities = {
974 973 None: 0,
975 974 '.text': 2,
976 975 '.txt': 3,
977 976 '.rst': 1,
978 977 '.rest': 2,
979 978 '.md': 1,
980 979 '.mkdn': 2,
981 980 '.mdown': 3,
982 981 '.markdown': 4,
983 982 }
984 983
985 984 path_priority = {
986 985 'doc': 0,
987 986 'docs': 1,
988 987 }
989 988
990 989 FALLBACK_PRIORITY = 99
991 990
992 991 RENDERER_TO_EXTENSION = {
993 992 'rst': ['.rst', '.rest'],
994 993 'markdown': ['.md', 'mkdn', '.mdown', '.markdown'],
995 994 }
996 995
997 996 def __init__(self, default_renderer=None):
998 997 self._default_renderer = default_renderer
999 998 self._renderer_extensions = self.RENDERER_TO_EXTENSION.get(
1000 999 default_renderer, [])
1001 1000
1002 1001 def search(self, commit, path='/'):
1003 1002 """
1004 1003 Find a readme in the given `commit`.
1005 1004 """
1006 1005 nodes = commit.get_nodes(path)
1007 1006 matches = self._match_readmes(nodes)
1008 1007 matches = self._sort_according_to_priority(matches)
1009 1008 if matches:
1010 1009 return matches[0].node
1011 1010
1012 1011 paths = self._match_paths(nodes)
1013 1012 paths = self._sort_paths_according_to_priority(paths)
1014 1013 for path in paths:
1015 1014 match = self.search(commit, path=path)
1016 1015 if match:
1017 1016 return match
1018 1017
1019 1018 return None
1020 1019
1021 1020 def _match_readmes(self, nodes):
1022 1021 for node in nodes:
1023 1022 if not node.is_file():
1024 1023 continue
1025 1024 path = node.path.rsplit('/', 1)[-1]
1026 1025 match = self.readme_re.match(path)
1027 1026 if match:
1028 1027 extension = match.group(1)
1029 1028 yield ReadmeMatch(node, match, self._priority(extension))
1030 1029
1031 1030 def _match_paths(self, nodes):
1032 1031 for node in nodes:
1033 1032 if not node.is_dir():
1034 1033 continue
1035 1034 match = self.path_re.match(node.path)
1036 1035 if match:
1037 1036 yield node.path
1038 1037
1039 1038 def _priority(self, extension):
1040 1039 renderer_priority = (
1041 1040 0 if extension in self._renderer_extensions else 1)
1042 1041 extension_priority = self.default_priorities.get(
1043 1042 extension, self.FALLBACK_PRIORITY)
1044 1043 return (renderer_priority, extension_priority)
1045 1044
1046 1045 def _sort_according_to_priority(self, matches):
1047 1046
1048 1047 def priority_and_path(match):
1049 1048 return (match.priority, match.path)
1050 1049
1051 1050 return sorted(matches, key=priority_and_path)
1052 1051
1053 1052 def _sort_paths_according_to_priority(self, paths):
1054 1053
1055 1054 def priority_and_path(path):
1056 1055 return (self.path_priority.get(path, self.FALLBACK_PRIORITY), path)
1057 1056
1058 1057 return sorted(paths, key=priority_and_path)
1059 1058
1060 1059
1061 1060 class ReadmeMatch:
1062 1061
1063 1062 def __init__(self, node, match, priority):
1064 1063 self.node = node
1065 1064 self._match = match
1066 1065 self.priority = priority
1067 1066
1068 1067 @property
1069 1068 def path(self):
1070 1069 return self.node.path
1071 1070
1072 1071 def __repr__(self):
1073 1072 return '<ReadmeMatch {} priority={}'.format(self.path, self.priority)
@@ -1,375 +1,376 b''
1 1
2 2 /******************************************************************************
3 3 * *
4 4 * DO NOT CHANGE THIS FILE MANUALLY *
5 5 * *
6 6 * *
7 7 * This file is automatically generated when the app starts up with *
8 8 * generate_js_files = true *
9 9 * *
10 10 * To add a route here pass jsroute=True to the route definition in the app *
11 11 * *
12 12 ******************************************************************************/
13 13 function registerRCRoutes() {
14 14 // routes registration
15 15 pyroutes.register('favicon', '/favicon.ico', []);
16 16 pyroutes.register('robots', '/robots.txt', []);
17 17 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
18 18 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
19 19 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
20 20 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
21 21 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
22 22 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
23 23 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
24 24 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
25 25 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
26 26 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
27 27 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
28 28 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
29 29 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
30 30 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
31 31 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
32 32 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
33 33 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
34 34 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
35 35 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
36 36 pyroutes.register('ops_ping_legacy', '/_admin/ping', []);
37 37 pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []);
38 38 pyroutes.register('admin_home', '/_admin', []);
39 39 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
40 40 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
41 41 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
42 42 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
43 43 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
44 44 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
45 45 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
46 46 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
47 47 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
48 48 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
49 49 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions/delete', []);
50 50 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
51 51 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
52 52 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
53 53 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
54 54 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
55 55 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
56 56 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
57 57 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
58 58 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
59 59 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
60 60 pyroutes.register('admin_settings', '/_admin/settings', []);
61 61 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
62 62 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
63 63 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
64 64 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
65 65 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
66 66 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
67 67 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
68 68 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
69 69 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
70 70 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
71 71 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
72 72 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
73 73 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
74 74 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
75 75 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
76 76 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
77 77 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
78 78 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
79 79 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
80 80 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
81 81 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
82 82 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
83 83 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
84 84 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
85 85 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
86 86 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
87 87 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
88 88 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
89 89 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
90 90 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
91 91 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
92 92 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
93 93 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
94 94 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
95 95 pyroutes.register('users', '/_admin/users', []);
96 96 pyroutes.register('users_data', '/_admin/users_data', []);
97 97 pyroutes.register('users_create', '/_admin/users/create', []);
98 98 pyroutes.register('users_new', '/_admin/users/new', []);
99 99 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
100 100 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
101 101 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
102 102 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
103 103 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
104 104 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
105 105 pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']);
106 106 pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']);
107 107 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
108 108 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
109 109 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
110 110 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
111 111 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
112 112 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
113 113 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
114 114 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
115 115 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
116 116 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
117 117 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
118 118 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
119 119 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
120 120 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
121 121 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
122 122 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
123 123 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
124 124 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
125 125 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
126 126 pyroutes.register('user_groups', '/_admin/user_groups', []);
127 127 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
128 128 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
129 129 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
130 130 pyroutes.register('repos', '/_admin/repos', []);
131 131 pyroutes.register('repo_new', '/_admin/repos/new', []);
132 132 pyroutes.register('repo_create', '/_admin/repos/create', []);
133 133 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
134 134 pyroutes.register('repo_groups_data', '/_admin/repo_groups_data', []);
135 135 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
136 136 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
137 137 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
138 138 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
139 139 pyroutes.register('channelstream_proxy', '/_channelstream', []);
140 140 pyroutes.register('upload_file', '/_file_store/upload', []);
141 141 pyroutes.register('download_file', '/_file_store/download/%(fid)s', ['fid']);
142 142 pyroutes.register('logout', '/_admin/logout', []);
143 143 pyroutes.register('reset_password', '/_admin/password_reset', []);
144 144 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
145 145 pyroutes.register('home', '/', []);
146 146 pyroutes.register('user_autocomplete_data', '/_users', []);
147 147 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
148 148 pyroutes.register('repo_list_data', '/_repos', []);
149 149 pyroutes.register('repo_group_list_data', '/_repo_groups', []);
150 150 pyroutes.register('goto_switcher_data', '/_goto_data', []);
151 151 pyroutes.register('markup_preview', '/_markup_preview', []);
152 152 pyroutes.register('file_preview', '/_file_preview', []);
153 153 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
154 154 pyroutes.register('journal', '/_admin/journal', []);
155 155 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
156 156 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
157 157 pyroutes.register('journal_public', '/_admin/public_journal', []);
158 158 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
159 159 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
160 160 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
161 161 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
162 162 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
163 163 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
164 164 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
165 165 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
166 166 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
167 167 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
168 168 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
169 169 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
170 170 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
171 171 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
172 172 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
173 173 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
174 174 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
175 175 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
176 176 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
177 177 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
178 178 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
179 179 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
180 180 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
181 181 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
182 182 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
183 183 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
184 184 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
185 185 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
186 186 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
187 187 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
188 188 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
189 189 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
190 190 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
191 191 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
192 192 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
193 193 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
194 194 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
195 195 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
196 196 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
197 197 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
198 198 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
199 199 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
200 200 pyroutes.register('repo_files_upload_file', '/%(repo_name)s/upload_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
201 201 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
202 202 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
203 203 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
204 204 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
205 205 pyroutes.register('repo_commits', '/%(repo_name)s/commits', ['repo_name']);
206 206 pyroutes.register('repo_commits_file', '/%(repo_name)s/commits/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
207 207 pyroutes.register('repo_commits_elements', '/%(repo_name)s/commits_elements', ['repo_name']);
208 208 pyroutes.register('repo_commits_elements_file', '/%(repo_name)s/commits_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
209 209 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
210 210 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
211 211 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
212 212 pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
213 213 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
214 214 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
215 215 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
216 216 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
217 217 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
218 218 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
219 219 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
220 220 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
221 221 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
222 222 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
223 223 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
224 224 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
225 225 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
226 226 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
227 227 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
228 228 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
229 229 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
230 230 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
231 231 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
232 232 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
233 233 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
234 234 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
235 235 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
236 236 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
237 237 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
238 238 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
239 239 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
240 240 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
241 241 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
242 pyroutes.register('edit_repo_perms_set_private', '/%(repo_name)s/settings/permissions/set_private', ['repo_name']);
242 243 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
243 244 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
244 245 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
245 246 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
246 247 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
247 248 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
248 249 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
249 250 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
250 251 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
251 252 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
252 253 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
253 254 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
254 255 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
255 256 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
256 257 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
257 258 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
258 259 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
259 260 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
260 261 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
261 262 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
262 263 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
263 264 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
264 265 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
265 266 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed/rss', ['repo_name']);
266 267 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed/atom', ['repo_name']);
267 268 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
268 269 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
269 270 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
270 271 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
271 272 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
272 273 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
273 274 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
274 275 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
275 276 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
276 277 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
277 278 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
278 279 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
279 280 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
280 281 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
281 282 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
282 283 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
283 284 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
284 285 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
285 286 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
286 287 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
287 288 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
288 289 pyroutes.register('search', '/_admin/search', []);
289 290 pyroutes.register('search_repo', '/%(repo_name)s/_search', ['repo_name']);
290 291 pyroutes.register('search_repo_alt', '/%(repo_name)s/search', ['repo_name']);
291 292 pyroutes.register('search_repo_group', '/%(repo_group_name)s/_search', ['repo_group_name']);
292 293 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
293 294 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
294 295 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
295 296 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
296 297 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
297 298 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
298 299 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
299 300 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
300 301 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
301 302 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
302 303 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
303 304 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
304 305 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
305 306 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
306 307 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
307 308 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
308 309 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
309 310 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
310 311 pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []);
311 312 pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []);
312 313 pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']);
313 314 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
314 315 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
315 316 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
316 317 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
317 318 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
318 319 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
319 320 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
320 321 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
321 322 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
322 323 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
323 324 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
324 325 pyroutes.register('gists_show', '/_admin/gists', []);
325 326 pyroutes.register('gists_new', '/_admin/gists/new', []);
326 327 pyroutes.register('gists_create', '/_admin/gists/create', []);
327 328 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
328 329 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
329 330 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
330 331 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
331 332 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
332 333 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
333 334 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
334 335 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
335 336 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
336 337 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
337 338 pyroutes.register('apiv2', '/_admin/api', []);
338 339 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
339 340 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
340 341 pyroutes.register('login', '/_admin/login', []);
341 342 pyroutes.register('register', '/_admin/register', []);
342 343 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
343 344 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
344 345 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
345 346 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
346 347 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
347 348 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
348 349 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
349 350 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
350 351 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
351 352 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
352 353 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
353 354 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
354 355 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
355 356 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
356 357 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
357 358 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
358 359 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
359 360 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
360 361 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
361 362 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
362 363 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
363 364 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
364 365 pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']);
365 366 pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']);
366 367 pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']);
367 368 pyroutes.register('repo_artifacts_get', '/%(repo_name)s/artifacts/download/%(uid)s', ['repo_name', 'uid']);
368 369 pyroutes.register('repo_artifacts_store', '/%(repo_name)s/artifacts/store', ['repo_name']);
369 370 pyroutes.register('repo_artifacts_delete', '/%(repo_name)s/artifacts/delete/%(uid)s', ['repo_name', 'uid']);
370 371 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
371 372 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
372 373 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
373 374 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
374 375 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
375 376 }
@@ -1,202 +1,222 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 <div class="panel panel-default">
4 4 <div class="panel-heading">
5 5 <h3 class="panel-title">${_('Repository Permissions')}</h3>
6 6 </div>
7 7 <div class="panel-body">
8 8 ${h.secure_form(h.route_path('edit_repo_perms', repo_name=c.repo_name), request=request)}
9 9 <table id="permissions_manage" class="rctable permissions">
10 10 <tr>
11 11 <th class="td-radio">${_('None')}</th>
12 12 <th class="td-radio">${_('Read')}</th>
13 13 <th class="td-radio">${_('Write')}</th>
14 14 <th class="td-radio">${_('Admin')}</th>
15 15 <th class="td-owner">${_('User/User Group')}</th>
16 16 <th class="td-action"></th>
17 17 <th class="td-action"></th>
18 18 </tr>
19 19 ## USERS
20 20 %for _user in c.rhodecode_db_repo.permissions():
21 21 %if getattr(_user, 'admin_row', None) or getattr(_user, 'owner_row', None):
22 22 <tr class="perm_admin_row">
23 23 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.none', disabled="disabled")}</td>
24 24 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.read', disabled="disabled")}</td>
25 25 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.write', disabled="disabled")}</td>
26 26 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.admin', 'repository.admin', disabled="disabled")}</td>
27 27 <td class="td-user">
28 28 ${base.gravatar(_user.email, 16)}
29 29 ${h.link_to_user(_user.username)}
30 30 %if getattr(_user, 'admin_row', None):
31 31 (${_('super admin')})
32 32 %endif
33 33 %if getattr(_user, 'owner_row', None):
34 34 (${_('owner')})
35 35 %endif
36 36 </td>
37 37 <td></td>
38 38 <td class="quick_repo_menu">
39 39 % if c.rhodecode_user.is_admin:
40 40 <i class="icon-more"></i>
41 41 <div class="menu_items_container" style="display: none;">
42 42 <ul class="menu_items">
43 43 <li>
44 44 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-permissions'))}
45 45 </li>
46 46 </ul>
47 47 </div>
48 48 % endif
49 49 </td>
50 50 </tr>
51 51 %elif _user.username == h.DEFAULT_USER and c.rhodecode_db_repo.private:
52 52 <tr>
53 53 <td colspan="4">
54 54 <span class="private_repo_msg">
55 55 <strong title="${h.tooltip(_user.permission)}">${_('private repository')}</strong>
56 56 </span>
57 57 </td>
58 58 <td class="private_repo_msg">
59 59 ${base.gravatar(h.DEFAULT_USER_EMAIL, 16)}
60 60 ${h.DEFAULT_USER} - ${_('only users/user groups explicitly added here will have access')}</td>
61 61 <td></td>
62 62 <td class="quick_repo_menu">
63 63 % if c.rhodecode_user.is_admin:
64 64 <i class="icon-more"></i>
65 65 <div class="menu_items_container" style="display: none;">
66 66 <ul class="menu_items">
67 67 <li>
68 68 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='repositories-permissions'))}
69 69 </li>
70 70 </ul>
71 71 </div>
72 72 % endif
73 73 </td>
74 74 </tr>
75 75 %else:
76 76 <% used_by_n_rules = len(getattr(_user, 'branch_rules', None) or []) %>
77 77 <tr>
78 78 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.none', checked=_user.permission=='repository.none', disabled="disabled" if (used_by_n_rules and _user.username != h.DEFAULT_USER) else None)}</td>
79 79 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.read', checked=_user.permission=='repository.read', disabled="disabled" if (used_by_n_rules and _user.username != h.DEFAULT_USER) else None)}</td>
80 80 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.write', checked=_user.permission=='repository.write')}</td>
81 81 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.admin', checked=_user.permission=='repository.admin')}</td>
82 82 <td class="td-user">
83 83 ${base.gravatar(_user.email, 16)}
84 84 <span class="user">
85 85 % if _user.username == h.DEFAULT_USER:
86 86 ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
87 87 % else:
88 88 ${h.link_to_user(_user.username)}
89 89 %if getattr(_user, 'duplicate_perm', None):
90 90 (${_('inactive duplicate')})
91 91 %endif
92 92 %if getattr(_user, 'branch_rules', None):
93 93 % if used_by_n_rules == 1:
94 94 (${_('used by {} branch rule, requires write+ permissions').format(used_by_n_rules)})
95 95 % else:
96 96 (${_('used by {} branch rules, requires write+ permissions').format(used_by_n_rules)})
97 97 % endif
98 98 %endif
99 99 % endif
100 100 </span>
101 101 </td>
102 102 <td class="td-action">
103 103 %if _user.username != h.DEFAULT_USER and getattr(_user, 'branch_rules', None) is None:
104 104 <span class="btn btn-link btn-danger revoke_perm"
105 105 member="${_user.user_id}" member_type="user">
106 106 ${_('Remove')}
107 107 </span>
108 %elif _user.username == h.DEFAULT_USER:
109 <span class="tooltip btn btn-link btn-default" onclick="enablePrivateRepo(); return false" title="${_('Private repositories are only visible to people explicitly added as collaborators.')}">
110 ${_('set private mode')}
111 </span>
108 112 %endif
109 113 </td>
110 114 <td class="quick_repo_menu">
111 115 % if c.rhodecode_user.is_admin:
112 116 <i class="icon-more"></i>
113 117 <div class="menu_items_container" style="display: none;">
114 118 <ul class="menu_items">
115 119 <li>
116 120 % if _user.username == h.DEFAULT_USER:
117 121 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='repositories-permissions'))}
118 122 % else:
119 123 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='repositories-permissions'))}
120 124 % endif
121 125 </li>
122 126 </ul>
123 127 </div>
124 128 % endif
125 129 </td>
126 130 </tr>
127 131 %endif
128 132 %endfor
129 133
130 134 ## USER GROUPS
131 135 %for _user_group in c.rhodecode_db_repo.permission_user_groups(with_members=True):
132 136 <tr>
133 137 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.none', checked=_user_group.permission=='repository.none')}</td>
134 138 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.read', checked=_user_group.permission=='repository.read')}</td>
135 139 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.write', checked=_user_group.permission=='repository.write')}</td>
136 140 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.admin', checked=_user_group.permission=='repository.admin')}</td>
137 141 <td class="td-componentname">
138 142 <i class="icon-user-group"></i>
139 143 %if c.is_super_admin:
140 144 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
141 145 ${_user_group.users_group_name}
142 146 </a>
143 147 %else:
144 148 ${h.link_to_group(_user_group.users_group_name)}
145 149 %endif
146 150 (${_('members')}: ${len(_user_group.members)})
147 151 </td>
148 152 <td class="td-action">
149 153 <span class="btn btn-link btn-danger revoke_perm"
150 154 member="${_user_group.users_group_id}" member_type="user_group">
151 155 ${_('Remove')}
152 156 </span>
153 157 </td>
154 158 <td class="quick_repo_menu">
155 159 % if c.rhodecode_user.is_admin:
156 160 <i class="icon-more"></i>
157 161 <div class="menu_items_container" style="display: none;">
158 162 <ul class="menu_items">
159 163 <li>
160 164 ${h.link_to('show permissions', h.route_path('edit_user_group_perms_summary', user_group_id=_user_group.users_group_id, _anchor='repositories-permissions'))}
161 165 </li>
162 166 </ul>
163 167 </div>
164 168 % endif
165 169 </td>
166 170 </tr>
167 171 %endfor
168 172 <tr class="new_members" id="add_perm_input"></tr>
169 173
170 174 <tr>
171 175 <td></td>
172 176 <td></td>
173 177 <td></td>
174 178 <td></td>
175 179 <td></td>
176 180 <td>
177 181 <span id="add_perm" class="link">
178 182 ${_('Add user/user group')}
179 183 </span>
180 184 </td>
181 185 <td></td>
182 186 </tr>
183 187
184 188 </table>
185 189
186 190 <div class="buttons">
187 191 ${h.submit('save',_('Save'),class_="btn btn-primary")}
188 192 ${h.reset('reset',_('Reset'),class_="btn btn-danger")}
189 193 </div>
190 194 ${h.end_form()}
191 195 </div>
192 196 </div>
193 197
194 198 <script type="text/javascript">
195 199 $('#add_perm').on('click', function(e){
196 200 addNewPermInput($(this), 'repository');
197 201 });
198 202 $('.revoke_perm').on('click', function(e){
199 203 markRevokePermInput($(this), 'repository');
200 204 });
201 205 quick_repo_menu();
206
207 var enablePrivateRepo = function () {
208 var postData = {
209 'csrf_token': CSRF_TOKEN
210 };
211
212 var success = function(o) {
213 var defaultUrl = pyroutes.url('edit_repo_perms', {"repo_name": templateContext.repo_name});
214 window.location = o.redirect_url || defaultUrl;
215 };
216
217 ajaxPOST(
218 pyroutes.url('edit_repo_perms_set_private', {"repo_name": templateContext.repo_name}),
219 postData,
220 success);
221 }
202 222 </script>
General Comments 0
You need to be logged in to leave comments. Login now