##// END OF EJS Templates
repository-groups: improved detection of repository groups parent....
marcink -
r1188:8732a902 default
parent child Browse files
Show More
@@ -1,878 +1,888 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2013-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 """
23 23 Repositories controller for RhodeCode
24 24 """
25 25
26 26 import logging
27 27 import traceback
28 28
29 29 import formencode
30 30 from formencode import htmlfill
31 31 from pylons import request, tmpl_context as c, url
32 32 from pylons.controllers.util import redirect
33 33 from pylons.i18n.translation import _
34 34 from webob.exc import HTTPForbidden, HTTPNotFound, HTTPBadRequest
35 35
36 36 import rhodecode
37 37 from rhodecode.lib import auth, helpers as h
38 38 from rhodecode.lib.auth import (
39 39 LoginRequired, HasPermissionAllDecorator,
40 40 HasRepoPermissionAllDecorator, NotAnonymous, HasPermissionAny,
41 41 HasRepoGroupPermissionAny, HasRepoPermissionAnyDecorator)
42 42 from rhodecode.lib.base import BaseRepoController, render
43 43 from rhodecode.lib.ext_json import json
44 44 from rhodecode.lib.exceptions import AttachedForksError
45 45 from rhodecode.lib.utils import action_logger, repo_name_slug, jsonify
46 46 from rhodecode.lib.utils2 import safe_int, str2bool
47 47 from rhodecode.lib.vcs import RepositoryError
48 48 from rhodecode.model.db import (
49 49 User, Repository, UserFollowing, RepoGroup, RepositoryField)
50 50 from rhodecode.model.forms import (
51 51 RepoForm, RepoFieldForm, RepoPermsForm, RepoVcsSettingsForm,
52 52 IssueTrackerPatternsForm)
53 53 from rhodecode.model.meta import Session
54 54 from rhodecode.model.repo import RepoModel
55 55 from rhodecode.model.scm import ScmModel, RepoGroupList, RepoList
56 56 from rhodecode.model.settings import (
57 57 SettingsModel, IssueTrackerSettingsModel, VcsSettingsModel,
58 58 SettingNotFound)
59 59
60 60 log = logging.getLogger(__name__)
61 61
62 62
63 63 class ReposController(BaseRepoController):
64 64 """
65 65 REST Controller styled on the Atom Publishing Protocol"""
66 66 # To properly map this controller, ensure your config/routing.py
67 67 # file has a resource setup:
68 68 # map.resource('repo', 'repos')
69 69
70 70 @LoginRequired()
71 71 def __before__(self):
72 72 super(ReposController, self).__before__()
73 73
74 74 def _load_repo(self, repo_name):
75 75 repo_obj = Repository.get_by_repo_name(repo_name)
76 76
77 77 if repo_obj is None:
78 78 h.not_mapped_error(repo_name)
79 79 return redirect(url('repos'))
80 80
81 81 return repo_obj
82 82
83 83 def __load_defaults(self, repo=None):
84 84 acl_groups = RepoGroupList(RepoGroup.query().all(),
85 85 perm_set=['group.write', 'group.admin'])
86 86 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
87 87 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
88 88
89 89 # in case someone no longer have a group.write access to a repository
90 90 # pre fill the list with this entry, we don't care if this is the same
91 91 # but it will allow saving repo data properly.
92 92
93 93 repo_group = None
94 94 if repo:
95 95 repo_group = repo.group
96 96 if repo_group and unicode(repo_group.group_id) not in c.repo_groups_choices:
97 97 c.repo_groups_choices.append(unicode(repo_group.group_id))
98 98 c.repo_groups.append(RepoGroup._generate_choice(repo_group))
99 99
100 100 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
101 101 c.landing_revs_choices = choices
102 102
103 103 def __load_data(self, repo_name=None):
104 104 """
105 105 Load defaults settings for edit, and update
106 106
107 107 :param repo_name:
108 108 """
109 109 c.repo_info = self._load_repo(repo_name)
110 110 self.__load_defaults(c.repo_info)
111 111
112 112 # override defaults for exact repo info here git/hg etc
113 113 if not c.repository_requirements_missing:
114 114 choices, c.landing_revs = ScmModel().get_repo_landing_revs(
115 115 c.repo_info)
116 116 c.landing_revs_choices = choices
117 117 defaults = RepoModel()._get_defaults(repo_name)
118 118
119 119 return defaults
120 120
121 121 def _log_creation_exception(self, e, repo_name):
122 122 reason = None
123 123 if len(e.args) == 2:
124 124 reason = e.args[1]
125 125
126 126 if reason == 'INVALID_CERTIFICATE':
127 127 log.exception(
128 128 'Exception creating a repository: invalid certificate')
129 129 msg = (_('Error creating repository %s: invalid certificate')
130 130 % repo_name)
131 131 else:
132 132 log.exception("Exception creating a repository")
133 133 msg = (_('Error creating repository %s')
134 134 % repo_name)
135 135
136 136 return msg
137 137
138 138 @NotAnonymous()
139 139 def index(self, format='html'):
140 140 """GET /repos: All items in the collection"""
141 141 # url('repos')
142 142
143 143 repo_list = Repository.get_all_repos()
144 144 c.repo_list = RepoList(repo_list, perm_set=['repository.admin'])
145 145 repos_data = RepoModel().get_repos_as_dict(
146 146 repo_list=c.repo_list, admin=True, super_user_actions=True)
147 147 # json used to render the grid
148 148 c.data = json.dumps(repos_data)
149 149
150 150 return render('admin/repos/repos.html')
151 151
152 152 # perms check inside
153 153 @NotAnonymous()
154 154 @auth.CSRFRequired()
155 155 def create(self):
156 156 """
157 157 POST /repos: Create a new item"""
158 158 # url('repos')
159 159
160 160 self.__load_defaults()
161 161 form_result = {}
162 162 task_id = None
163 163 c.personal_repo_group = c.rhodecode_user.personal_repo_group
164 164 try:
165 165 # CanWriteToGroup validators checks permissions of this POST
166 166 form_result = RepoForm(repo_groups=c.repo_groups_choices,
167 167 landing_revs=c.landing_revs_choices)()\
168 168 .to_python(dict(request.POST))
169 169
170 170 # create is done sometimes async on celery, db transaction
171 171 # management is handled there.
172 172 task = RepoModel().create(form_result, c.rhodecode_user.user_id)
173 173 from celery.result import BaseAsyncResult
174 174 if isinstance(task, BaseAsyncResult):
175 175 task_id = task.task_id
176 176 except formencode.Invalid as errors:
177 177 return htmlfill.render(
178 178 render('admin/repos/repo_add.html'),
179 179 defaults=errors.value,
180 180 errors=errors.error_dict or {},
181 181 prefix_error=False,
182 182 encoding="UTF-8",
183 183 force_defaults=False)
184 184
185 185 except Exception as e:
186 186 msg = self._log_creation_exception(e, form_result.get('repo_name'))
187 187 h.flash(msg, category='error')
188 188 return redirect(url('home'))
189 189
190 190 return redirect(h.url('repo_creating_home',
191 191 repo_name=form_result['repo_name_full'],
192 192 task_id=task_id))
193 193
194 194 # perms check inside
195 195 @NotAnonymous()
196 196 def create_repository(self):
197 197 """GET /_admin/create_repository: Form to create a new item"""
198 198 new_repo = request.GET.get('repo', '')
199 parent_group = request.GET.get('parent_group')
199 parent_group = safe_int(request.GET.get('parent_group'))
200 _gr = RepoGroup.get(parent_group)
201
200 202 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
201 203 # you're not super admin nor have global create permissions,
202 204 # but maybe you have at least write permission to a parent group ?
203 _gr = RepoGroup.get(parent_group)
205
204 206 gr_name = _gr.group_name if _gr else None
205 207 # create repositories with write permission on group is set to true
206 208 create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')()
207 209 group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name)
208 210 group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name)
209 211 if not (group_admin or (group_write and create_on_write)):
210 212 raise HTTPForbidden
211 213
212 214 acl_groups = RepoGroupList(RepoGroup.query().all(),
213 215 perm_set=['group.write', 'group.admin'])
214 216 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
215 217 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
216 218 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
217 219 c.personal_repo_group = c.rhodecode_user.personal_repo_group
218 220 c.new_repo = repo_name_slug(new_repo)
219 221
220 ## apply the defaults from defaults page
222 # apply the defaults from defaults page
221 223 defaults = SettingsModel().get_default_repo_settings(strip_prefix=True)
222 224 # set checkbox to autochecked
223 225 defaults['repo_copy_permissions'] = True
224 if parent_group:
225 defaults.update({'repo_group': parent_group})
226
227 parent_group_choice = '-1'
228 if not c.rhodecode_user.is_admin and c.rhodecode_user.personal_repo_group:
229 parent_group_choice = c.rhodecode_user.personal_repo_group
230
231 if parent_group and _gr:
232 if parent_group in [x[0] for x in c.repo_groups]:
233 parent_group_choice = unicode(parent_group)
234
235 defaults.update({'repo_group': parent_group_choice})
226 236
227 237 return htmlfill.render(
228 238 render('admin/repos/repo_add.html'),
229 239 defaults=defaults,
230 240 errors={},
231 241 prefix_error=False,
232 242 encoding="UTF-8",
233 243 force_defaults=False
234 244 )
235 245
236 246 @NotAnonymous()
237 247 def repo_creating(self, repo_name):
238 248 c.repo = repo_name
239 249 c.task_id = request.GET.get('task_id')
240 250 if not c.repo:
241 251 raise HTTPNotFound()
242 252 return render('admin/repos/repo_creating.html')
243 253
244 254 @NotAnonymous()
245 255 @jsonify
246 256 def repo_check(self, repo_name):
247 257 c.repo = repo_name
248 258 task_id = request.GET.get('task_id')
249 259
250 260 if task_id and task_id not in ['None']:
251 261 import rhodecode
252 262 from celery.result import AsyncResult
253 263 if rhodecode.CELERY_ENABLED:
254 264 task = AsyncResult(task_id)
255 265 if task.failed():
256 266 msg = self._log_creation_exception(task.result, c.repo)
257 267 h.flash(msg, category='error')
258 268 return redirect(url('home'), code=501)
259 269
260 270 repo = Repository.get_by_repo_name(repo_name)
261 271 if repo and repo.repo_state == Repository.STATE_CREATED:
262 272 if repo.clone_uri:
263 273 clone_uri = repo.clone_uri_hidden
264 274 h.flash(_('Created repository %s from %s')
265 275 % (repo.repo_name, clone_uri), category='success')
266 276 else:
267 277 repo_url = h.link_to(repo.repo_name,
268 278 h.url('summary_home',
269 279 repo_name=repo.repo_name))
270 280 fork = repo.fork
271 281 if fork:
272 282 fork_name = fork.repo_name
273 283 h.flash(h.literal(_('Forked repository %s as %s')
274 284 % (fork_name, repo_url)), category='success')
275 285 else:
276 286 h.flash(h.literal(_('Created repository %s') % repo_url),
277 287 category='success')
278 288 return {'result': True}
279 289 return {'result': False}
280 290
281 291 @HasRepoPermissionAllDecorator('repository.admin')
282 292 @auth.CSRFRequired()
283 293 def update(self, repo_name):
284 294 """
285 295 PUT /repos/repo_name: Update an existing item"""
286 296 # Forms posted to this method should contain a hidden field:
287 297 # <input type="hidden" name="_method" value="PUT" />
288 298 # Or using helpers:
289 299 # h.form(url('repo', repo_name=ID),
290 300 # method='put')
291 301 # url('repo', repo_name=ID)
292 302
293 303 self.__load_data(repo_name)
294 304 c.active = 'settings'
295 305 c.repo_fields = RepositoryField.query()\
296 306 .filter(RepositoryField.repository == c.repo_info).all()
297 307
298 308 repo_model = RepoModel()
299 309 changed_name = repo_name
300 310
301 311 c.personal_repo_group = c.rhodecode_user.personal_repo_group
302 312 # override the choices with extracted revisions !
303 313 repo = Repository.get_by_repo_name(repo_name)
304 314 old_data = {
305 315 'repo_name': repo_name,
306 316 'repo_group': repo.group.get_dict() if repo.group else {},
307 317 'repo_type': repo.repo_type,
308 318 }
309 319 _form = RepoForm(
310 320 edit=True, old_data=old_data, repo_groups=c.repo_groups_choices,
311 321 landing_revs=c.landing_revs_choices, allow_disabled=True)()
312 322
313 323 try:
314 324 form_result = _form.to_python(dict(request.POST))
315 325 repo = repo_model.update(repo_name, **form_result)
316 326 ScmModel().mark_for_invalidation(repo_name)
317 327 h.flash(_('Repository %s updated successfully') % repo_name,
318 328 category='success')
319 329 changed_name = repo.repo_name
320 330 action_logger(c.rhodecode_user, 'admin_updated_repo',
321 331 changed_name, self.ip_addr, self.sa)
322 332 Session().commit()
323 333 except formencode.Invalid as errors:
324 334 defaults = self.__load_data(repo_name)
325 335 defaults.update(errors.value)
326 336 return htmlfill.render(
327 337 render('admin/repos/repo_edit.html'),
328 338 defaults=defaults,
329 339 errors=errors.error_dict or {},
330 340 prefix_error=False,
331 341 encoding="UTF-8",
332 342 force_defaults=False)
333 343
334 344 except Exception:
335 345 log.exception("Exception during update of repository")
336 346 h.flash(_('Error occurred during update of repository %s') \
337 347 % repo_name, category='error')
338 348 return redirect(url('edit_repo', repo_name=changed_name))
339 349
340 350 @HasRepoPermissionAllDecorator('repository.admin')
341 351 @auth.CSRFRequired()
342 352 def delete(self, repo_name):
343 353 """
344 354 DELETE /repos/repo_name: Delete an existing item"""
345 355 # Forms posted to this method should contain a hidden field:
346 356 # <input type="hidden" name="_method" value="DELETE" />
347 357 # Or using helpers:
348 358 # h.form(url('repo', repo_name=ID),
349 359 # method='delete')
350 360 # url('repo', repo_name=ID)
351 361
352 362 repo_model = RepoModel()
353 363 repo = repo_model.get_by_repo_name(repo_name)
354 364 if not repo:
355 365 h.not_mapped_error(repo_name)
356 366 return redirect(url('repos'))
357 367 try:
358 368 _forks = repo.forks.count()
359 369 handle_forks = None
360 370 if _forks and request.POST.get('forks'):
361 371 do = request.POST['forks']
362 372 if do == 'detach_forks':
363 373 handle_forks = 'detach'
364 374 h.flash(_('Detached %s forks') % _forks, category='success')
365 375 elif do == 'delete_forks':
366 376 handle_forks = 'delete'
367 377 h.flash(_('Deleted %s forks') % _forks, category='success')
368 378 repo_model.delete(repo, forks=handle_forks)
369 379 action_logger(c.rhodecode_user, 'admin_deleted_repo',
370 380 repo_name, self.ip_addr, self.sa)
371 381 ScmModel().mark_for_invalidation(repo_name)
372 382 h.flash(_('Deleted repository %s') % repo_name, category='success')
373 383 Session().commit()
374 384 except AttachedForksError:
375 385 h.flash(_('Cannot delete %s it still contains attached forks')
376 386 % repo_name, category='warning')
377 387
378 388 except Exception:
379 389 log.exception("Exception during deletion of repository")
380 390 h.flash(_('An error occurred during deletion of %s') % repo_name,
381 391 category='error')
382 392
383 393 return redirect(url('repos'))
384 394
385 395 @HasPermissionAllDecorator('hg.admin')
386 396 def show(self, repo_name, format='html'):
387 397 """GET /repos/repo_name: Show a specific item"""
388 398 # url('repo', repo_name=ID)
389 399
390 400 @HasRepoPermissionAllDecorator('repository.admin')
391 401 def edit(self, repo_name):
392 402 """GET /repo_name/settings: Form to edit an existing item"""
393 403 # url('edit_repo', repo_name=ID)
394 404 defaults = self.__load_data(repo_name)
395 405 if 'clone_uri' in defaults:
396 406 del defaults['clone_uri']
397 407
398 408 c.repo_fields = RepositoryField.query()\
399 409 .filter(RepositoryField.repository == c.repo_info).all()
400 410 c.personal_repo_group = c.rhodecode_user.personal_repo_group
401 411 c.active = 'settings'
402 412 return htmlfill.render(
403 413 render('admin/repos/repo_edit.html'),
404 414 defaults=defaults,
405 415 encoding="UTF-8",
406 416 force_defaults=False)
407 417
408 418 @HasRepoPermissionAllDecorator('repository.admin')
409 419 def edit_permissions(self, repo_name):
410 420 """GET /repo_name/settings: Form to edit an existing item"""
411 421 # url('edit_repo', repo_name=ID)
412 422 c.repo_info = self._load_repo(repo_name)
413 423 c.active = 'permissions'
414 424 defaults = RepoModel()._get_defaults(repo_name)
415 425
416 426 return htmlfill.render(
417 427 render('admin/repos/repo_edit.html'),
418 428 defaults=defaults,
419 429 encoding="UTF-8",
420 430 force_defaults=False)
421 431
422 432 @HasRepoPermissionAllDecorator('repository.admin')
423 433 @auth.CSRFRequired()
424 434 def edit_permissions_update(self, repo_name):
425 435 form = RepoPermsForm()().to_python(request.POST)
426 436 RepoModel().update_permissions(repo_name,
427 437 form['perm_additions'], form['perm_updates'], form['perm_deletions'])
428 438
429 439 #TODO: implement this
430 440 #action_logger(c.rhodecode_user, 'admin_changed_repo_permissions',
431 441 # repo_name, self.ip_addr, self.sa)
432 442 Session().commit()
433 443 h.flash(_('Repository permissions updated'), category='success')
434 444 return redirect(url('edit_repo_perms', repo_name=repo_name))
435 445
436 446 @HasRepoPermissionAllDecorator('repository.admin')
437 447 def edit_fields(self, repo_name):
438 448 """GET /repo_name/settings: Form to edit an existing item"""
439 449 # url('edit_repo', repo_name=ID)
440 450 c.repo_info = self._load_repo(repo_name)
441 451 c.repo_fields = RepositoryField.query()\
442 452 .filter(RepositoryField.repository == c.repo_info).all()
443 453 c.active = 'fields'
444 454 if request.POST:
445 455
446 456 return redirect(url('repo_edit_fields'))
447 457 return render('admin/repos/repo_edit.html')
448 458
449 459 @HasRepoPermissionAllDecorator('repository.admin')
450 460 @auth.CSRFRequired()
451 461 def create_repo_field(self, repo_name):
452 462 try:
453 463 form_result = RepoFieldForm()().to_python(dict(request.POST))
454 464 RepoModel().add_repo_field(
455 465 repo_name, form_result['new_field_key'],
456 466 field_type=form_result['new_field_type'],
457 467 field_value=form_result['new_field_value'],
458 468 field_label=form_result['new_field_label'],
459 469 field_desc=form_result['new_field_desc'])
460 470
461 471 Session().commit()
462 472 except Exception as e:
463 473 log.exception("Exception creating field")
464 474 msg = _('An error occurred during creation of field')
465 475 if isinstance(e, formencode.Invalid):
466 476 msg += ". " + e.msg
467 477 h.flash(msg, category='error')
468 478 return redirect(url('edit_repo_fields', repo_name=repo_name))
469 479
470 480 @HasRepoPermissionAllDecorator('repository.admin')
471 481 @auth.CSRFRequired()
472 482 def delete_repo_field(self, repo_name, field_id):
473 483 field = RepositoryField.get_or_404(field_id)
474 484 try:
475 485 RepoModel().delete_repo_field(repo_name, field.field_key)
476 486 Session().commit()
477 487 except Exception as e:
478 488 log.exception("Exception during removal of field")
479 489 msg = _('An error occurred during removal of field')
480 490 h.flash(msg, category='error')
481 491 return redirect(url('edit_repo_fields', repo_name=repo_name))
482 492
483 493 @HasRepoPermissionAllDecorator('repository.admin')
484 494 def edit_advanced(self, repo_name):
485 495 """GET /repo_name/settings: Form to edit an existing item"""
486 496 # url('edit_repo', repo_name=ID)
487 497 c.repo_info = self._load_repo(repo_name)
488 498 c.default_user_id = User.get_default_user().user_id
489 499 c.in_public_journal = UserFollowing.query()\
490 500 .filter(UserFollowing.user_id == c.default_user_id)\
491 501 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
492 502
493 503 c.active = 'advanced'
494 504 c.has_origin_repo_read_perm = False
495 505 if c.repo_info.fork:
496 506 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
497 507 'repository.write', 'repository.read', 'repository.admin')(
498 508 c.repo_info.fork.repo_name, 'repo set as fork page')
499 509
500 510 if request.POST:
501 511 return redirect(url('repo_edit_advanced'))
502 512 return render('admin/repos/repo_edit.html')
503 513
504 514 @HasRepoPermissionAllDecorator('repository.admin')
505 515 @auth.CSRFRequired()
506 516 def edit_advanced_journal(self, repo_name):
507 517 """
508 518 Set's this repository to be visible in public journal,
509 519 in other words assing default user to follow this repo
510 520
511 521 :param repo_name:
512 522 """
513 523
514 524 try:
515 525 repo_id = Repository.get_by_repo_name(repo_name).repo_id
516 526 user_id = User.get_default_user().user_id
517 527 self.scm_model.toggle_following_repo(repo_id, user_id)
518 528 h.flash(_('Updated repository visibility in public journal'),
519 529 category='success')
520 530 Session().commit()
521 531 except Exception:
522 532 h.flash(_('An error occurred during setting this'
523 533 ' repository in public journal'),
524 534 category='error')
525 535
526 536 return redirect(url('edit_repo_advanced', repo_name=repo_name))
527 537
528 538 @HasRepoPermissionAllDecorator('repository.admin')
529 539 @auth.CSRFRequired()
530 540 def edit_advanced_fork(self, repo_name):
531 541 """
532 542 Mark given repository as a fork of another
533 543
534 544 :param repo_name:
535 545 """
536 546
537 547 new_fork_id = request.POST.get('id_fork_of')
538 548 try:
539 549
540 550 if new_fork_id and not new_fork_id.isdigit():
541 551 log.error('Given fork id %s is not an INT', new_fork_id)
542 552
543 553 fork_id = safe_int(new_fork_id)
544 554 repo = ScmModel().mark_as_fork(repo_name, fork_id,
545 555 c.rhodecode_user.username)
546 556 fork = repo.fork.repo_name if repo.fork else _('Nothing')
547 557 Session().commit()
548 558 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
549 559 category='success')
550 560 except RepositoryError as e:
551 561 log.exception("Repository Error occurred")
552 562 h.flash(str(e), category='error')
553 563 except Exception as e:
554 564 log.exception("Exception while editing fork")
555 565 h.flash(_('An error occurred during this operation'),
556 566 category='error')
557 567
558 568 return redirect(url('edit_repo_advanced', repo_name=repo_name))
559 569
560 570 @HasRepoPermissionAllDecorator('repository.admin')
561 571 @auth.CSRFRequired()
562 572 def edit_advanced_locking(self, repo_name):
563 573 """
564 574 Unlock repository when it is locked !
565 575
566 576 :param repo_name:
567 577 """
568 578 try:
569 579 repo = Repository.get_by_repo_name(repo_name)
570 580 if request.POST.get('set_lock'):
571 581 Repository.lock(repo, c.rhodecode_user.user_id,
572 582 lock_reason=Repository.LOCK_WEB)
573 583 h.flash(_('Locked repository'), category='success')
574 584 elif request.POST.get('set_unlock'):
575 585 Repository.unlock(repo)
576 586 h.flash(_('Unlocked repository'), category='success')
577 587 except Exception as e:
578 588 log.exception("Exception during unlocking")
579 589 h.flash(_('An error occurred during unlocking'),
580 590 category='error')
581 591 return redirect(url('edit_repo_advanced', repo_name=repo_name))
582 592
583 593 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
584 594 @auth.CSRFRequired()
585 595 def toggle_locking(self, repo_name):
586 596 """
587 597 Toggle locking of repository by simple GET call to url
588 598
589 599 :param repo_name:
590 600 """
591 601
592 602 try:
593 603 repo = Repository.get_by_repo_name(repo_name)
594 604
595 605 if repo.enable_locking:
596 606 if repo.locked[0]:
597 607 Repository.unlock(repo)
598 608 action = _('Unlocked')
599 609 else:
600 610 Repository.lock(repo, c.rhodecode_user.user_id,
601 611 lock_reason=Repository.LOCK_WEB)
602 612 action = _('Locked')
603 613
604 614 h.flash(_('Repository has been %s') % action,
605 615 category='success')
606 616 except Exception:
607 617 log.exception("Exception during unlocking")
608 618 h.flash(_('An error occurred during unlocking'),
609 619 category='error')
610 620 return redirect(url('summary_home', repo_name=repo_name))
611 621
612 622 @HasRepoPermissionAllDecorator('repository.admin')
613 623 @auth.CSRFRequired()
614 624 def edit_caches(self, repo_name):
615 625 """PUT /{repo_name}/settings/caches: invalidate the repo caches."""
616 626 try:
617 627 ScmModel().mark_for_invalidation(repo_name, delete=True)
618 628 Session().commit()
619 629 h.flash(_('Cache invalidation successful'),
620 630 category='success')
621 631 except Exception:
622 632 log.exception("Exception during cache invalidation")
623 633 h.flash(_('An error occurred during cache invalidation'),
624 634 category='error')
625 635
626 636 return redirect(url('edit_repo_caches', repo_name=c.repo_name))
627 637
628 638 @HasRepoPermissionAllDecorator('repository.admin')
629 639 def edit_caches_form(self, repo_name):
630 640 """GET /repo_name/settings: Form to edit an existing item"""
631 641 # url('edit_repo', repo_name=ID)
632 642 c.repo_info = self._load_repo(repo_name)
633 643 c.active = 'caches'
634 644
635 645 return render('admin/repos/repo_edit.html')
636 646
637 647 @HasRepoPermissionAllDecorator('repository.admin')
638 648 @auth.CSRFRequired()
639 649 def edit_remote(self, repo_name):
640 650 """PUT /{repo_name}/settings/remote: edit the repo remote."""
641 651 try:
642 652 ScmModel().pull_changes(repo_name, c.rhodecode_user.username)
643 653 h.flash(_('Pulled from remote location'), category='success')
644 654 except Exception:
645 655 log.exception("Exception during pull from remote")
646 656 h.flash(_('An error occurred during pull from remote location'),
647 657 category='error')
648 658 return redirect(url('edit_repo_remote', repo_name=c.repo_name))
649 659
650 660 @HasRepoPermissionAllDecorator('repository.admin')
651 661 def edit_remote_form(self, repo_name):
652 662 """GET /repo_name/settings: Form to edit an existing item"""
653 663 # url('edit_repo', repo_name=ID)
654 664 c.repo_info = self._load_repo(repo_name)
655 665 c.active = 'remote'
656 666
657 667 return render('admin/repos/repo_edit.html')
658 668
659 669 @HasRepoPermissionAllDecorator('repository.admin')
660 670 @auth.CSRFRequired()
661 671 def edit_statistics(self, repo_name):
662 672 """PUT /{repo_name}/settings/statistics: reset the repo statistics."""
663 673 try:
664 674 RepoModel().delete_stats(repo_name)
665 675 Session().commit()
666 676 except Exception as e:
667 677 log.error(traceback.format_exc())
668 678 h.flash(_('An error occurred during deletion of repository stats'),
669 679 category='error')
670 680 return redirect(url('edit_repo_statistics', repo_name=c.repo_name))
671 681
672 682 @HasRepoPermissionAllDecorator('repository.admin')
673 683 def edit_statistics_form(self, repo_name):
674 684 """GET /repo_name/settings: Form to edit an existing item"""
675 685 # url('edit_repo', repo_name=ID)
676 686 c.repo_info = self._load_repo(repo_name)
677 687 repo = c.repo_info.scm_instance()
678 688
679 689 if c.repo_info.stats:
680 690 # this is on what revision we ended up so we add +1 for count
681 691 last_rev = c.repo_info.stats.stat_on_revision + 1
682 692 else:
683 693 last_rev = 0
684 694 c.stats_revision = last_rev
685 695
686 696 c.repo_last_rev = repo.count()
687 697
688 698 if last_rev == 0 or c.repo_last_rev == 0:
689 699 c.stats_percentage = 0
690 700 else:
691 701 c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100)
692 702
693 703 c.active = 'statistics'
694 704
695 705 return render('admin/repos/repo_edit.html')
696 706
697 707 @HasRepoPermissionAllDecorator('repository.admin')
698 708 @auth.CSRFRequired()
699 709 def repo_issuetracker_test(self, repo_name):
700 710 if request.is_xhr:
701 711 return h.urlify_commit_message(
702 712 request.POST.get('test_text', ''),
703 713 repo_name)
704 714 else:
705 715 raise HTTPBadRequest()
706 716
707 717 @HasRepoPermissionAllDecorator('repository.admin')
708 718 @auth.CSRFRequired()
709 719 def repo_issuetracker_delete(self, repo_name):
710 720 uid = request.POST.get('uid')
711 721 repo_settings = IssueTrackerSettingsModel(repo=repo_name)
712 722 try:
713 723 repo_settings.delete_entries(uid)
714 724 except Exception:
715 725 h.flash(_('Error occurred during deleting issue tracker entry'),
716 726 category='error')
717 727 else:
718 728 h.flash(_('Removed issue tracker entry'), category='success')
719 729 return redirect(url('repo_settings_issuetracker',
720 730 repo_name=repo_name))
721 731
722 732 def _update_patterns(self, form, repo_settings):
723 733 for uid in form['delete_patterns']:
724 734 repo_settings.delete_entries(uid)
725 735
726 736 for pattern in form['patterns']:
727 737 for setting, value, type_ in pattern:
728 738 sett = repo_settings.create_or_update_setting(
729 739 setting, value, type_)
730 740 Session().add(sett)
731 741
732 742 Session().commit()
733 743
734 744 @HasRepoPermissionAllDecorator('repository.admin')
735 745 @auth.CSRFRequired()
736 746 def repo_issuetracker_save(self, repo_name):
737 747 # Save inheritance
738 748 repo_settings = IssueTrackerSettingsModel(repo=repo_name)
739 749 inherited = (request.POST.get('inherit_global_issuetracker')
740 750 == "inherited")
741 751 repo_settings.inherit_global_settings = inherited
742 752 Session().commit()
743 753
744 754 form = IssueTrackerPatternsForm()().to_python(request.POST)
745 755 if form:
746 756 self._update_patterns(form, repo_settings)
747 757
748 758 h.flash(_('Updated issue tracker entries'), category='success')
749 759 return redirect(url('repo_settings_issuetracker',
750 760 repo_name=repo_name))
751 761
752 762 @HasRepoPermissionAllDecorator('repository.admin')
753 763 def repo_issuetracker(self, repo_name):
754 764 """GET /admin/settings/issue-tracker: All items in the collection"""
755 765 c.active = 'issuetracker'
756 766 c.data = 'data'
757 767 c.repo_info = self._load_repo(repo_name)
758 768
759 769 repo = Repository.get_by_repo_name(repo_name)
760 770 c.settings_model = IssueTrackerSettingsModel(repo=repo)
761 771 c.global_patterns = c.settings_model.get_global_settings()
762 772 c.repo_patterns = c.settings_model.get_repo_settings()
763 773
764 774 return render('admin/repos/repo_edit.html')
765 775
766 776 @HasRepoPermissionAllDecorator('repository.admin')
767 777 def repo_settings_vcs(self, repo_name):
768 778 """GET /{repo_name}/settings/vcs/: All items in the collection"""
769 779
770 780 model = VcsSettingsModel(repo=repo_name)
771 781
772 782 c.active = 'vcs'
773 783 c.global_svn_branch_patterns = model.get_global_svn_branch_patterns()
774 784 c.global_svn_tag_patterns = model.get_global_svn_tag_patterns()
775 785 c.svn_branch_patterns = model.get_repo_svn_branch_patterns()
776 786 c.svn_tag_patterns = model.get_repo_svn_tag_patterns()
777 787 c.repo_info = self._load_repo(repo_name)
778 788 defaults = self._vcs_form_defaults(repo_name)
779 789 c.inherit_global_settings = defaults['inherit_global_settings']
780 790 c.labs_active = str2bool(
781 791 rhodecode.CONFIG.get('labs_settings_active', 'true'))
782 792
783 793 return htmlfill.render(
784 794 render('admin/repos/repo_edit.html'),
785 795 defaults=defaults,
786 796 encoding="UTF-8",
787 797 force_defaults=False)
788 798
789 799 @HasRepoPermissionAllDecorator('repository.admin')
790 800 @auth.CSRFRequired()
791 801 def repo_settings_vcs_update(self, repo_name):
792 802 """POST /{repo_name}/settings/vcs/: All items in the collection"""
793 803 c.active = 'vcs'
794 804
795 805 model = VcsSettingsModel(repo=repo_name)
796 806 c.global_svn_branch_patterns = model.get_global_svn_branch_patterns()
797 807 c.global_svn_tag_patterns = model.get_global_svn_tag_patterns()
798 808 c.svn_branch_patterns = model.get_repo_svn_branch_patterns()
799 809 c.svn_tag_patterns = model.get_repo_svn_tag_patterns()
800 810 c.repo_info = self._load_repo(repo_name)
801 811 defaults = self._vcs_form_defaults(repo_name)
802 812 c.inherit_global_settings = defaults['inherit_global_settings']
803 813
804 814 application_form = RepoVcsSettingsForm(repo_name)()
805 815 try:
806 816 form_result = application_form.to_python(dict(request.POST))
807 817 except formencode.Invalid as errors:
808 818 h.flash(
809 819 _("Some form inputs contain invalid data."),
810 820 category='error')
811 821 return htmlfill.render(
812 822 render('admin/repos/repo_edit.html'),
813 823 defaults=errors.value,
814 824 errors=errors.error_dict or {},
815 825 prefix_error=False,
816 826 encoding="UTF-8",
817 827 force_defaults=False
818 828 )
819 829
820 830 try:
821 831 inherit_global_settings = form_result['inherit_global_settings']
822 832 model.create_or_update_repo_settings(
823 833 form_result, inherit_global_settings=inherit_global_settings)
824 834 except Exception:
825 835 log.exception("Exception while updating settings")
826 836 h.flash(
827 837 _('Error occurred during updating repository VCS settings'),
828 838 category='error')
829 839 else:
830 840 Session().commit()
831 841 h.flash(_('Updated VCS settings'), category='success')
832 842 return redirect(url('repo_vcs_settings', repo_name=repo_name))
833 843
834 844 return htmlfill.render(
835 845 render('admin/repos/repo_edit.html'),
836 846 defaults=self._vcs_form_defaults(repo_name),
837 847 encoding="UTF-8",
838 848 force_defaults=False)
839 849
840 850 @HasRepoPermissionAllDecorator('repository.admin')
841 851 @auth.CSRFRequired()
842 852 @jsonify
843 853 def repo_delete_svn_pattern(self, repo_name):
844 854 if not request.is_xhr:
845 855 return False
846 856
847 857 delete_pattern_id = request.POST.get('delete_svn_pattern')
848 858 model = VcsSettingsModel(repo=repo_name)
849 859 try:
850 860 model.delete_repo_svn_pattern(delete_pattern_id)
851 861 except SettingNotFound:
852 862 raise HTTPBadRequest()
853 863
854 864 Session().commit()
855 865 return True
856 866
857 867 def _vcs_form_defaults(self, repo_name):
858 868 model = VcsSettingsModel(repo=repo_name)
859 869 global_defaults = model.get_global_settings()
860 870
861 871 repo_defaults = {}
862 872 repo_defaults.update(global_defaults)
863 873 repo_defaults.update(model.get_repo_settings())
864 874
865 875 global_defaults = {
866 876 '{}_inherited'.format(k): global_defaults[k]
867 877 for k in global_defaults}
868 878
869 879 defaults = {
870 880 'inherit_global_settings': model.inherit_global_settings
871 881 }
872 882 defaults.update(global_defaults)
873 883 defaults.update(repo_defaults)
874 884 defaults.update({
875 885 'new_svn_branch': '',
876 886 'new_svn_tag': '',
877 887 })
878 888 return defaults
General Comments 0
You need to be logged in to leave comments. Login now