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