Show More
@@ -0,0 +1,98 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
3 | # Copyright (C) 2011-2017 RhodeCode GmbH | |
|
4 | # | |
|
5 | # This program is free software: you can redistribute it and/or modify | |
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |
|
7 | # (only), as published by the Free Software Foundation. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU Affero General Public License | |
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
|
16 | # | |
|
17 | # This program is dual-licensed. If you wish to learn more about the | |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
|
20 | ||
|
21 | import logging | |
|
22 | ||
|
23 | import deform | |
|
24 | from pyramid.httpexceptions import HTTPFound | |
|
25 | from pyramid.view import view_config | |
|
26 | ||
|
27 | from rhodecode.apps._base import RepoAppView | |
|
28 | from rhodecode.forms import RcForm | |
|
29 | from rhodecode.lib import helpers as h | |
|
30 | from rhodecode.lib import audit_logger | |
|
31 | from rhodecode.lib.auth import ( | |
|
32 | LoginRequired, HasRepoPermissionAnyDecorator, | |
|
33 | HasRepoPermissionAllDecorator, CSRFRequired) | |
|
34 | from rhodecode.model.db import RepositoryField, RepoGroup | |
|
35 | from rhodecode.model.forms import RepoPermsForm | |
|
36 | from rhodecode.model.meta import Session | |
|
37 | from rhodecode.model.repo import RepoModel | |
|
38 | from rhodecode.model.scm import RepoGroupList, ScmModel | |
|
39 | from rhodecode.model.validation_schema.schemas import repo_schema | |
|
40 | ||
|
41 | log = logging.getLogger(__name__) | |
|
42 | ||
|
43 | ||
|
44 | class RepoSettingsPermissionsView(RepoAppView): | |
|
45 | ||
|
46 | def load_default_context(self): | |
|
47 | c = self._get_local_tmpl_context() | |
|
48 | ||
|
49 | # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead | |
|
50 | c.repo_info = self.db_repo | |
|
51 | ||
|
52 | self._register_global_c(c) | |
|
53 | return c | |
|
54 | ||
|
55 | @LoginRequired() | |
|
56 | @HasRepoPermissionAnyDecorator('repository.admin') | |
|
57 | @view_config( | |
|
58 | route_name='edit_repo_perms', request_method='GET', | |
|
59 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |
|
60 | def edit_permissions(self): | |
|
61 | c = self.load_default_context() | |
|
62 | c.active = 'permissions' | |
|
63 | return self._get_template_context(c) | |
|
64 | ||
|
65 | @LoginRequired() | |
|
66 | @HasRepoPermissionAllDecorator('repository.admin') | |
|
67 | @CSRFRequired() | |
|
68 | @view_config( | |
|
69 | route_name='edit_repo_perms', request_method='POST', | |
|
70 | renderer='rhodecode:templates/admin/repos/repo_edit.mako') | |
|
71 | def edit_permissions_update(self): | |
|
72 | _ = self.request.translate | |
|
73 | c = self.load_default_context() | |
|
74 | c.active = 'permissions' | |
|
75 | data = self.request.POST | |
|
76 | # store private flag outside of HTML to verify if we can modify | |
|
77 | # default user permissions, prevents submition of FAKE post data | |
|
78 | # into the form for private repos | |
|
79 | data['repo_private'] = self.db_repo.private | |
|
80 | form = RepoPermsForm()().to_python(data) | |
|
81 | changes = RepoModel().update_permissions( | |
|
82 | self.db_repo_name, form['perm_additions'], form['perm_updates'], | |
|
83 | form['perm_deletions']) | |
|
84 | ||
|
85 | action_data = { | |
|
86 | 'added': changes['added'], | |
|
87 | 'updated': changes['updated'], | |
|
88 | 'deleted': changes['deleted'], | |
|
89 | } | |
|
90 | audit_logger.store( | |
|
91 | 'repo.edit.permissions', action_data=action_data, | |
|
92 | user=self._rhodecode_user, repo=self.db_repo) | |
|
93 | ||
|
94 | Session().commit() | |
|
95 | h.flash(_('Repository permissions updated'), category='success') | |
|
96 | ||
|
97 | raise HTTPFound( | |
|
98 | self.request.route_path('edit_repo_perms', repo_name=self.db_repo_name)) |
@@ -31,6 +31,11 b' def includeme(config):' | |||
|
31 | 31 | name='edit_repo_caches', |
|
32 | 32 | pattern='/{repo_name:.*?[^/]}/settings/caches', repo_route=True) |
|
33 | 33 | |
|
34 | # Permissions | |
|
35 | config.add_route( | |
|
36 | name='edit_repo_perms', | |
|
37 | pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True) | |
|
38 | ||
|
34 | 39 | # Repo Review Rules |
|
35 | 40 | config.add_route( |
|
36 | 41 | name='repo_reviewers', |
@@ -39,6 +39,7 b' def route_path(name, params=None, **kwar' | |||
|
39 | 39 | base_url = { |
|
40 | 40 | 'edit_repo': '/{repo_name}/settings', |
|
41 | 41 | 'edit_repo_caches': '/{repo_name}/settings/caches', |
|
42 | 'edit_repo_perms': '/{repo_name}/settings/permissions', | |
|
42 | 43 | }[name].format(**kwargs) |
|
43 | 44 | |
|
44 | 45 | if params: |
@@ -59,7 +60,8 b' def _get_permission_for_user(user, repo)' | |||
|
59 | 60 | class TestAdminRepoSettings(object): |
|
60 | 61 | @pytest.mark.parametrize('urlname', [ |
|
61 | 62 | 'edit_repo', |
|
62 | 'edit_repo_caches' | |
|
63 | 'edit_repo_caches', | |
|
64 | 'edit_repo_perms', | |
|
63 | 65 | ]) |
|
64 | 66 | def test_show_page(self, urlname, app, backend): |
|
65 | 67 | app.get(route_path(urlname, repo_name=backend.repo_name), status=200) |
@@ -72,7 +74,6 b' class TestAdminRepoSettings(object):' | |||
|
72 | 74 | self.app.get(route_path('edit_repo', repo_name=backend_hg.repo_name)) |
|
73 | 75 | |
|
74 | 76 | @pytest.mark.parametrize('urlname', [ |
|
75 | 'edit_repo_perms', | |
|
76 | 77 | 'edit_repo_advanced', |
|
77 | 78 | 'repo_vcs_settings', |
|
78 | 79 | 'edit_repo_fields', |
@@ -661,16 +661,6 b' def make_map(config):' | |||
|
661 | 661 | requirements=URL_NAME_REQUIREMENTS) |
|
662 | 662 | |
|
663 | 663 | # repo edit options |
|
664 | rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions', | |
|
665 | jsroute=True, | |
|
666 | controller='admin/repos', action='edit_permissions', | |
|
667 | conditions={'method': ['GET'], 'function': check_repo}, | |
|
668 | requirements=URL_NAME_REQUIREMENTS) | |
|
669 | rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions', | |
|
670 | controller='admin/repos', action='edit_permissions_update', | |
|
671 | conditions={'method': ['PUT'], 'function': check_repo}, | |
|
672 | requirements=URL_NAME_REQUIREMENTS) | |
|
673 | ||
|
674 | 664 | rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields', |
|
675 | 665 | controller='admin/repos', action='edit_fields', |
|
676 | 666 | conditions={'method': ['GET'], 'function': check_repo}, |
@@ -339,33 +339,6 b' class ReposController(BaseRepoController' | |||
|
339 | 339 | # url('repo', repo_name=ID) |
|
340 | 340 | |
|
341 | 341 | @HasRepoPermissionAllDecorator('repository.admin') |
|
342 | def edit_permissions(self, repo_name): | |
|
343 | """GET /repo_name/settings: Form to edit an existing item""" | |
|
344 | c.repo_info = self._load_repo(repo_name) | |
|
345 | c.active = 'permissions' | |
|
346 | defaults = RepoModel()._get_defaults(repo_name) | |
|
347 | ||
|
348 | return htmlfill.render( | |
|
349 | render('admin/repos/repo_edit.mako'), | |
|
350 | defaults=defaults, | |
|
351 | encoding="UTF-8", | |
|
352 | force_defaults=False) | |
|
353 | ||
|
354 | @HasRepoPermissionAllDecorator('repository.admin') | |
|
355 | @auth.CSRFRequired() | |
|
356 | def edit_permissions_update(self, repo_name): | |
|
357 | form = RepoPermsForm()().to_python(request.POST) | |
|
358 | RepoModel().update_permissions(repo_name, | |
|
359 | form['perm_additions'], form['perm_updates'], form['perm_deletions']) | |
|
360 | ||
|
361 | #TODO: implement this | |
|
362 | #action_logger(c.rhodecode_user, 'admin_changed_repo_permissions', | |
|
363 | # repo_name, self.ip_addr, self.sa) | |
|
364 | Session().commit() | |
|
365 | h.flash(_('Repository permissions updated'), category='success') | |
|
366 | return redirect(url('edit_repo_perms', repo_name=repo_name)) | |
|
367 | ||
|
368 | @HasRepoPermissionAllDecorator('repository.admin') | |
|
369 | 342 | def edit_fields(self, repo_name): |
|
370 | 343 | """GET /repo_name/settings: Form to edit an existing item""" |
|
371 | 344 | c.repo_info = self._load_repo(repo_name) |
@@ -36,6 +36,7 b' ACTIONS = {' | |||
|
36 | 36 | |
|
37 | 37 | 'repo.add': {}, |
|
38 | 38 | 'repo.edit': {}, |
|
39 | 'repo.edit.permissions': {}, | |
|
39 | 40 | 'repo.commit.strip': {} |
|
40 | 41 | } |
|
41 | 42 |
@@ -295,16 +295,6 b' class RepoModel(BaseModel):' | |||
|
295 | 295 | replacement_user = User.get_first_super_admin().username |
|
296 | 296 | defaults.update({'user': replacement_user}) |
|
297 | 297 | |
|
298 | # fill repository users | |
|
299 | for p in repo_info.repo_to_perm: | |
|
300 | defaults.update({'u_perm_%s' % p.user.user_id: | |
|
301 | p.permission.permission_name}) | |
|
302 | ||
|
303 | # fill repository groups | |
|
304 | for p in repo_info.users_group_to_perm: | |
|
305 | defaults.update({'g_perm_%s' % p.users_group.users_group_id: | |
|
306 | p.permission.permission_name}) | |
|
307 | ||
|
308 | 298 | return defaults |
|
309 | 299 | |
|
310 | 300 | def update(self, repo, **kwargs): |
@@ -507,10 +497,16 b' class RepoModel(BaseModel):' | |||
|
507 | 497 | |
|
508 | 498 | req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin') |
|
509 | 499 | |
|
500 | changes = { | |
|
501 | 'added': [], | |
|
502 | 'updated': [], | |
|
503 | 'deleted': [] | |
|
504 | } | |
|
510 | 505 | # update permissions |
|
511 | 506 | for member_id, perm, member_type in perm_updates: |
|
512 | 507 | member_id = int(member_id) |
|
513 | 508 | if member_type == 'user': |
|
509 | member_name = User.get(member_id).username | |
|
514 | 510 | # this updates also current one if found |
|
515 | 511 | self.grant_user_permission( |
|
516 | 512 | repo=repo, user=member_id, perm=perm) |
@@ -522,10 +518,14 b' class RepoModel(BaseModel):' | |||
|
522 | 518 | self.grant_user_group_permission( |
|
523 | 519 | repo=repo, group_name=member_id, perm=perm) |
|
524 | 520 | |
|
521 | changes['updated'].append({'type': member_type, 'id': member_id, | |
|
522 | 'name': member_name, 'new_perm': perm}) | |
|
523 | ||
|
525 | 524 | # set new permissions |
|
526 | 525 | for member_id, perm, member_type in perm_additions: |
|
527 | 526 | member_id = int(member_id) |
|
528 | 527 | if member_type == 'user': |
|
528 | member_name = User.get(member_id).username | |
|
529 | 529 | self.grant_user_permission( |
|
530 | 530 | repo=repo, user=member_id, perm=perm) |
|
531 | 531 | else: # set for user group |
@@ -535,11 +535,13 b' class RepoModel(BaseModel):' | |||
|
535 | 535 | *req_perms)(member_name, user=cur_user): |
|
536 | 536 | self.grant_user_group_permission( |
|
537 | 537 | repo=repo, group_name=member_id, perm=perm) |
|
538 | ||
|
538 | changes['added'].append({'type': member_type, 'id': member_id, | |
|
539 | 'name': member_name, 'new_perm': perm}) | |
|
539 | 540 | # delete permissions |
|
540 | 541 | for member_id, perm, member_type in perm_deletions: |
|
541 | 542 | member_id = int(member_id) |
|
542 | 543 | if member_type == 'user': |
|
544 | member_name = User.get(member_id).username | |
|
543 | 545 | self.revoke_user_permission(repo=repo, user=member_id) |
|
544 | 546 | else: # set for user group |
|
545 | 547 | # check if we have permissions to alter this usergroup |
@@ -549,6 +551,10 b' class RepoModel(BaseModel):' | |||
|
549 | 551 | self.revoke_user_group_permission( |
|
550 | 552 | repo=repo, group_name=member_id) |
|
551 | 553 | |
|
554 | changes['deleted'].append({'type': member_type, 'id': member_id, | |
|
555 | 'name': member_name, 'new_perm': perm}) | |
|
556 | return changes | |
|
557 | ||
|
552 | 558 | def create_fork(self, form_data, cur_user): |
|
553 | 559 | """ |
|
554 | 560 | Simple wrapper into executing celery task for fork creation |
@@ -784,7 +784,8 b" def ValidPerms(type_='repo'):" | |||
|
784 | 784 | del_member = perm_dict.get('id') |
|
785 | 785 | del_type = perm_dict.get('type') |
|
786 | 786 | if del_member and del_type: |
|
787 |
perm_deletions.add( |
|
|
787 | perm_deletions.add( | |
|
788 | (del_member, None, del_type)) | |
|
788 | 789 | |
|
789 | 790 | # store additions in order of how they were added in web form |
|
790 | 791 | for k in sorted(new_perms_group.keys()): |
@@ -793,36 +794,48 b" def ValidPerms(type_='repo'):" | |||
|
793 | 794 | new_type = perm_dict.get('type') |
|
794 | 795 | new_perm = perm_dict.get('perm') |
|
795 | 796 | if new_member and new_perm and new_type: |
|
796 |
perm_additions.add( |
|
|
797 | perm_additions.add( | |
|
798 | (new_member, new_perm, new_type)) | |
|
797 | 799 | |
|
798 | 800 | # get updates of permissions |
|
799 | 801 | # (read the existing radio button states) |
|
802 | default_user_id = User.get_default_user().user_id | |
|
800 | 803 | for k, update_value in value.iteritems(): |
|
801 | 804 | if k.startswith('u_perm_') or k.startswith('g_perm_'): |
|
802 | 805 | member = k[7:] |
|
803 | 806 | update_type = {'u': 'user', |
|
804 | 807 | 'g': 'users_group'}[k[0]] |
|
805 | if member == User.DEFAULT_USER: | |
|
808 | ||
|
809 | if safe_int(member) == default_user_id: | |
|
806 | 810 | if str2bool(value.get('repo_private')): |
|
807 |
# |
|
|
808 | # private repo protects agains form manipulation | |
|
811 | # prevent from updating default user permissions | |
|
812 | # when this repository is marked as private | |
|
809 | 813 | update_value = EMPTY_PERM |
|
810 | perm_updates.add((member, update_value, update_type)) | |
|
811 | # check the deletes | |
|
812 | 814 | |
|
813 | value['perm_additions'] = list(perm_additions) | |
|
815 | perm_updates.add( | |
|
816 | (member, update_value, update_type)) | |
|
817 | ||
|
818 | value['perm_additions'] = [] # propagated later | |
|
814 | 819 | value['perm_updates'] = list(perm_updates) |
|
815 | 820 | value['perm_deletions'] = list(perm_deletions) |
|
816 | 821 | |
|
817 | # validate users they exist and they are active ! | |
|
818 | for member_id, _perm, member_type in perm_additions: | |
|
822 | updates_map = dict( | |
|
823 | (x[0], (x[1], x[2])) for x in value['perm_updates']) | |
|
824 | # make sure Additions don't override updates. | |
|
825 | for member_id, perm, member_type in list(perm_additions): | |
|
826 | if member_id in updates_map: | |
|
827 | perm = updates_map[member_id][0] | |
|
828 | value['perm_additions'].append((member_id, perm, member_type)) | |
|
829 | ||
|
830 | # on new entries validate users they exist and they are active ! | |
|
831 | # this leaves feedback to the form | |
|
819 | 832 | try: |
|
820 | 833 | if member_type == 'user': |
|
821 |
|
|
|
834 | User.query()\ | |
|
822 | 835 | .filter(User.active == true())\ |
|
823 | 836 | .filter(User.user_id == member_id).one() |
|
824 | 837 | if member_type == 'users_group': |
|
825 |
|
|
|
838 | UserGroup.query()\ | |
|
826 | 839 | .filter(UserGroup.users_group_active == true())\ |
|
827 | 840 | .filter(UserGroup.users_group_id == member_id)\ |
|
828 | 841 | .one() |
@@ -24,7 +24,6 b' function registerRCRoutes() {' | |||
|
24 | 24 | pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']); |
|
25 | 25 | pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/default-reviewers', ['repo_name']); |
|
26 | 26 | pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']); |
|
27 | pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']); | |
|
28 | 27 | pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']); |
|
29 | 28 | pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']); |
|
30 | 29 | pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']); |
@@ -99,6 +98,7 b' function registerRCRoutes() {' | |||
|
99 | 98 | pyroutes.register('goto_switcher_data', '/_goto_data', []); |
|
100 | 99 | pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); |
|
101 | 100 | pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']); |
|
101 | pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']); | |
|
102 | 102 | pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']); |
|
103 | 103 | pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']); |
|
104 | 104 | pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']); |
@@ -42,7 +42,7 b'' | |||
|
42 | 42 | <a href="${h.route_path('edit_repo', repo_name=c.repo_name)}">${_('Settings')}</a> |
|
43 | 43 | </li> |
|
44 | 44 | <li class="${'active' if c.active=='permissions' else ''}"> |
|
45 |
<a href="${h. |
|
|
45 | <a href="${h.route_path('edit_repo_perms', repo_name=c.repo_name)}">${_('Permissions')}</a> | |
|
46 | 46 | </li> |
|
47 | 47 | <li class="${'active' if c.active=='advanced' else ''}"> |
|
48 | 48 | <a href="${h.url('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a> |
@@ -5,8 +5,7 b'' | |||
|
5 | 5 | <h3 class="panel-title">${_('Repository Permissions')}</h3> |
|
6 | 6 | </div> |
|
7 | 7 | <div class="panel-body"> |
|
8 |
${h.secure_form( |
|
|
9 | ${h.hidden('repo_private')} | |
|
8 | ${h.secure_form(h.route_path('edit_repo_perms', repo_name=c.repo_name), method='POST')} | |
|
10 | 9 | <table id="permissions_manage" class="rctable permissions"> |
|
11 | 10 | <tr> |
|
12 | 11 | <th class="td-radio">${_('None')}</th> |
@@ -40,7 +39,7 b'' | |||
|
40 | 39 | <tr> |
|
41 | 40 | <td colspan="4"> |
|
42 | 41 | <span class="private_repo_msg"> |
|
43 | <strong>${_('private repository')}</strong> | |
|
42 | <strong title="${_user.permission}">${_('private repository')}</strong> | |
|
44 | 43 | </span> |
|
45 | 44 | </td> |
|
46 | 45 | <td class="private_repo_msg"> |
@@ -50,10 +49,10 b'' | |||
|
50 | 49 | </tr> |
|
51 | 50 | %else: |
|
52 | 51 | <tr> |
|
53 | <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.none')}</td> | |
|
54 | <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.read')}</td> | |
|
55 | <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.write')}</td> | |
|
56 | <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.admin')}</td> | |
|
52 | <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.none', checked=_user.permission=='repository.none')}</td> | |
|
53 | <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.read', checked=_user.permission=='repository.read')}</td> | |
|
54 | <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.write', checked=_user.permission=='repository.write')}</td> | |
|
55 | <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'repository.admin', checked=_user.permission=='repository.admin')}</td> | |
|
57 | 56 | <td class="td-user"> |
|
58 | 57 | ${base.gravatar(_user.email, 16)} |
|
59 | 58 | <span class="user"> |
@@ -79,10 +78,10 b'' | |||
|
79 | 78 | ## USER GROUPS |
|
80 | 79 | %for _user_group in c.repo_info.permission_user_groups(): |
|
81 | 80 | <tr> |
|
82 | <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.none')}</td> | |
|
83 | <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.read')}</td> | |
|
84 | <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.write')}</td> | |
|
85 | <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.admin')}</td> | |
|
81 | <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.none', checked=_user_group.permission=='repository.none')}</td> | |
|
82 | <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.read', checked=_user_group.permission=='repository.read')}</td> | |
|
83 | <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.write', checked=_user_group.permission=='repository.write')}</td> | |
|
84 | <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.admin', checked=_user_group.permission=='repository.admin')}</td> | |
|
86 | 85 | <td class="td-componentname"> |
|
87 | 86 | <i class="icon-group" ></i> |
|
88 | 87 | %if h.HasPermissionAny('hg.admin')(): |
@@ -146,7 +146,7 b'' | |||
|
146 | 146 | %if actions: |
|
147 | 147 | <td class="td-action"> |
|
148 | 148 | %if section == 'repositories': |
|
149 |
<a href="${h. |
|
|
149 | <a href="${h.route_path('edit_repo_perms',repo_name=k,anchor='permissions_manage')}">${_('edit')}</a> | |
|
150 | 150 | %elif section == 'repositories_groups': |
|
151 | 151 | <a href="${h.url('edit_repo_group_perms',group_name=k,anchor='permissions_manage')}">${_('edit')}</a> |
|
152 | 152 | %elif section == 'user_groups': |
General Comments 0
You need to be logged in to leave comments.
Login now