##// END OF EJS Templates
branch permissions: added logic to define in UI branch permissions....
marcink -
r2975:2d612d18 default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -0,0 +1,45 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2011-2018 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 from pyramid.view import view_config
24
25 from rhodecode.apps._base import RepoAppView
26 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
27
28 log = logging.getLogger(__name__)
29
30
31 class RepoSettingsBranchPermissionsView(RepoAppView):
32
33 def load_default_context(self):
34 c = self._get_local_tmpl_context()
35 return c
36
37 @LoginRequired()
38 @HasRepoPermissionAnyDecorator('repository.admin')
39 @view_config(
40 route_name='edit_repo_perms_branch', request_method='GET',
41 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
42 def branch_permissions(self):
43 c = self.load_default_context()
44 c.active = 'permissions_branch'
45 return self._get_template_context(c)
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -0,0 +1,46 b''
1 import logging
2
3 from sqlalchemy import *
4 from sqlalchemy.engine import reflection
5 from sqlalchemy.dialects.mysql import LONGTEXT
6
7 from alembic.migration import MigrationContext
8 from alembic.operations import Operations
9
10 from rhodecode.lib.dbmigrate.utils import create_default_permissions, \
11 create_default_object_permission
12 from rhodecode.model import meta
13 from rhodecode.lib.dbmigrate.versions import _reset_base, notify
14
15 log = logging.getLogger(__name__)
16
17
18 def upgrade(migrate_engine):
19 """
20 Upgrade operations go here.
21 Don't create your own engine; bind migrate_engine to your metadata
22 """
23 _reset_base(migrate_engine)
24 from rhodecode.lib.dbmigrate.schema import db_4_13_0_0 as db
25
26 # issue fixups
27 fixups(db, meta.Session)
28
29
30 def downgrade(migrate_engine):
31 meta = MetaData()
32 meta.bind = migrate_engine
33
34
35 def fixups(models, _SESSION):
36 # create default permissions
37 create_default_permissions(_SESSION, models)
38 log.info('created default global permissions definitions')
39 _SESSION().commit()
40
41 # # fix default object permissions
42 # create_default_object_permission(_SESSION, models)
43
44 log.info('created default permission')
45 _SESSION().commit()
46
@@ -0,0 +1,39 b''
1 import logging
2
3 from sqlalchemy import *
4 from sqlalchemy.engine import reflection
5 from sqlalchemy.dialects.mysql import LONGTEXT
6
7 from alembic.migration import MigrationContext
8 from alembic.operations import Operations
9
10 from rhodecode.model import meta
11 from rhodecode.lib.dbmigrate.versions import _reset_base, notify
12
13 log = logging.getLogger(__name__)
14
15
16 def upgrade(migrate_engine):
17 """
18 Upgrade operations go here.
19 Don't create your own engine; bind migrate_engine to your metadata
20 """
21 _reset_base(migrate_engine)
22 from rhodecode.lib.dbmigrate.schema import db_4_13_0_0 as db
23
24 db.UserToRepoBranchPermission.__table__.create()
25 db.UserGroupToRepoBranchPermission.__table__.create()
26
27 # issue fixups
28 fixups(db, meta.Session)
29
30
31 def downgrade(migrate_engine):
32 meta = MetaData()
33 meta.bind = migrate_engine
34
35
36 def fixups(models, _SESSION):
37 pass
38
39
@@ -0,0 +1,43 b''
1 import logging
2
3 from sqlalchemy import *
4
5 from rhodecode.lib.dbmigrate.utils import (
6 create_default_object_permission, create_default_permissions)
7
8 from rhodecode.model import meta
9 from rhodecode.lib.dbmigrate.versions import _reset_base, notify
10
11 log = logging.getLogger(__name__)
12
13
14 def upgrade(migrate_engine):
15 """
16 Upgrade operations go here.
17 Don't create your own engine; bind migrate_engine to your metadata
18 """
19 _reset_base(migrate_engine)
20 from rhodecode.lib.dbmigrate.schema import db_4_13_0_0 as db
21
22 # issue fixups
23 fixups(db, meta.Session)
24
25
26 def downgrade(migrate_engine):
27 meta = MetaData()
28 meta.bind = migrate_engine
29
30
31 def fixups(models, _SESSION):
32 # create default permissions
33 create_default_permissions(_SESSION, models)
34 log.info('created default global permissions definitions')
35 _SESSION().commit()
36
37 # fix default object permissions
38 create_default_object_permission(_SESSION, models)
39
40 log.info('created default permission')
41 _SESSION().commit()
42
43
@@ -0,0 +1,9 b''
1 <div class="panel panel-default">
2 <div class="panel-heading">
3 <h3 class="panel-title">${_('Default Permissions for Branches.')}</h3>
4 </div>
5 <div class="panel-body">
6 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
7 <img style="width: 100%; height: 100%" src="${h.asset('images/ee_features/admin_branch_permissions.png')}"/>
8 </div>
9 </div>
@@ -0,0 +1,9 b''
1 <div class="panel panel-default">
2 <div class="panel-heading">
3 <h3 class="panel-title">${_('Repository Branch Permissions.')}</h3>
4 </div>
5 <div class="panel-body">
6 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
7 <img style="width: 100%; height: 100%" src="${h.asset('images/ee_features/repo_branch_permissions.png')}"/>
8 </div>
9 </div>
@@ -51,7 +51,7 b' PYRAMID_SETTINGS = {}'
51 EXTENSIONS = {}
51 EXTENSIONS = {}
52
52
53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
54 __dbversion__ = 87 # defines current db version for migrations
54 __dbversion__ = 90 # defines current db version for migrations
55 __platform__ = platform.system()
55 __platform__ = platform.system()
56 __license__ = 'AGPLv3, and Commercial License'
56 __license__ = 'AGPLv3, and Commercial License'
57 __author__ = 'RhodeCode GmbH'
57 __author__ = 'RhodeCode GmbH'
@@ -210,6 +210,11 b' def admin_routes(config):'
210 name='admin_permissions_object_update',
210 name='admin_permissions_object_update',
211 pattern='/permissions/object/update')
211 pattern='/permissions/object/update')
212
212
213 # Branch perms EE feature
214 config.add_route(
215 name='admin_permissions_branch',
216 pattern='/permissions/branch')
217
213 config.add_route(
218 config.add_route(
214 name='admin_permissions_ips',
219 name='admin_permissions_ips',
215 pattern='/permissions/ips')
220 pattern='/permissions/ips')
@@ -182,7 +182,8 b' class AdminPermissionsView(BaseAppView, '
182 self.request.translate,
182 self.request.translate,
183 [x[0] for x in c.repo_perms_choices],
183 [x[0] for x in c.repo_perms_choices],
184 [x[0] for x in c.group_perms_choices],
184 [x[0] for x in c.group_perms_choices],
185 [x[0] for x in c.user_group_perms_choices])()
185 [x[0] for x in c.user_group_perms_choices],
186 )()
186
187
187 try:
188 try:
188 form_result = _form.to_python(dict(self.request.POST))
189 form_result = _form.to_python(dict(self.request.POST))
@@ -218,6 +219,30 b' class AdminPermissionsView(BaseAppView, '
218 @LoginRequired()
219 @LoginRequired()
219 @HasPermissionAllDecorator('hg.admin')
220 @HasPermissionAllDecorator('hg.admin')
220 @view_config(
221 @view_config(
222 route_name='admin_permissions_branch', request_method='GET',
223 renderer='rhodecode:templates/admin/permissions/permissions.mako')
224 def permissions_branch(self):
225 c = self.load_default_context()
226 c.active = 'branch'
227
228 c.user = User.get_default_user(refresh=True)
229 defaults = {}
230 defaults.update(c.user.get_default_perms())
231
232 data = render(
233 'rhodecode:templates/admin/permissions/permissions.mako',
234 self._get_template_context(c), self.request)
235 html = formencode.htmlfill.render(
236 data,
237 defaults=defaults,
238 encoding="UTF-8",
239 force_defaults=False
240 )
241 return Response(html)
242
243 @LoginRequired()
244 @HasPermissionAllDecorator('hg.admin')
245 @view_config(
221 route_name='admin_permissions_global', request_method='GET',
246 route_name='admin_permissions_global', request_method='GET',
222 renderer='rhodecode:templates/admin/permissions/permissions.mako')
247 renderer='rhodecode:templates/admin/permissions/permissions.mako')
223 def permissions_global(self):
248 def permissions_global(self):
@@ -345,6 +345,15 b' def includeme(config):'
345 name='edit_repo_perms',
345 name='edit_repo_perms',
346 pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True)
346 pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True)
347
347
348 # Permissions Branch (EE feature)
349 config.add_route(
350 name='edit_repo_perms_branch',
351 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions', repo_route=True)
352 config.add_route(
353 name='edit_repo_perms_branch_delete',
354 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions/{rule_id}/delete',
355 repo_route=True)
356
348 # Maintenance
357 # Maintenance
349 config.add_route(
358 config.add_route(
350 name='edit_repo_maintenance',
359 name='edit_repo_maintenance',
@@ -367,10 +367,38 b' class PermOriginDict(dict):'
367 self.perm_origin_stack = collections.OrderedDict()
367 self.perm_origin_stack = collections.OrderedDict()
368
368
369 def __setitem__(self, key, (perm, origin)):
369 def __setitem__(self, key, (perm, origin)):
370 self.perm_origin_stack.setdefault(key, []).append((perm, origin))
370 self.perm_origin_stack.setdefault(key, []).append(
371 (perm, origin))
371 dict.__setitem__(self, key, perm)
372 dict.__setitem__(self, key, perm)
372
373
373
374
375 class BranchPermOriginDict(PermOriginDict):
376 """
377 Dedicated branch permissions dict, with tracking of patterns and origins.
378
379 >>> perms = BranchPermOriginDict()
380 >>> perms['resource'] = '*pattern', 'read', 'default'
381 >>> perms['resource']
382 {'*pattern': 'read'}
383 >>> perms['resource'] = '*pattern', 'write', 'admin'
384 >>> perms['resource']
385 {'*pattern': 'write'}
386 >>> perms.perm_origin_stack
387 {'resource': {'*pattern': [('read', 'default'), ('write', 'admin')]}}
388 """
389 def __setitem__(self, key, (pattern, perm, origin)):
390
391 self.perm_origin_stack.setdefault(key, {}) \
392 .setdefault(pattern, []).append((perm, origin))
393
394 if key in self:
395 self[key].__setitem__(pattern, perm)
396 else:
397 patterns = collections.OrderedDict()
398 patterns[pattern] = perm
399 dict.__setitem__(self, key, patterns)
400
401
374 class PermissionCalculator(object):
402 class PermissionCalculator(object):
375
403
376 def __init__(
404 def __init__(
@@ -395,6 +423,7 b' class PermissionCalculator(object):'
395 self.permissions_repositories = PermOriginDict()
423 self.permissions_repositories = PermOriginDict()
396 self.permissions_repository_groups = PermOriginDict()
424 self.permissions_repository_groups = PermOriginDict()
397 self.permissions_user_groups = PermOriginDict()
425 self.permissions_user_groups = PermOriginDict()
426 self.permissions_repository_branches = BranchPermOriginDict()
398 self.permissions_global = set()
427 self.permissions_global = set()
399
428
400 self.default_repo_perms = Permission.get_default_repo_perms(
429 self.default_repo_perms = Permission.get_default_repo_perms(
@@ -405,6 +434,11 b' class PermissionCalculator(object):'
405 Permission.get_default_user_group_perms(
434 Permission.get_default_user_group_perms(
406 self.default_user_id, self.scope_user_group_id)
435 self.default_user_id, self.scope_user_group_id)
407
436
437 # default branch perms
438 self.default_branch_repo_perms = \
439 Permission.get_default_repo_branch_perms(
440 self.default_user_id, self.scope_repo_id)
441
408 def calculate(self):
442 def calculate(self):
409 if self.user_is_admin and not self.calculate_super_admin:
443 if self.user_is_admin and not self.calculate_super_admin:
410 return self._admin_permissions()
444 return self._admin_permissions()
@@ -413,6 +447,7 b' class PermissionCalculator(object):'
413 self._calculate_global_permissions()
447 self._calculate_global_permissions()
414 self._calculate_default_permissions()
448 self._calculate_default_permissions()
415 self._calculate_repository_permissions()
449 self._calculate_repository_permissions()
450 self._calculate_repository_branch_permissions()
416 self._calculate_repository_group_permissions()
451 self._calculate_repository_group_permissions()
417 self._calculate_user_group_permissions()
452 self._calculate_user_group_permissions()
418 return self._permission_structure()
453 return self._permission_structure()
@@ -443,6 +478,15 b' class PermissionCalculator(object):'
443 p = 'usergroup.admin'
478 p = 'usergroup.admin'
444 self.permissions_user_groups[u_k] = p, PermOrigin.SUPER_ADMIN
479 self.permissions_user_groups[u_k] = p, PermOrigin.SUPER_ADMIN
445
480
481 # branch permissions
482 # TODO(marcink): validate this, especially
483 # how this should work using multiple patterns specified ??
484 # looks ok, but still needs double check !!
485 for perm in self.default_branch_repo_perms:
486 r_k = perm.UserRepoToPerm.repository.repo_name
487 p = 'branch.push_force'
488 self.permissions_repository_branches[r_k] = '*', p, PermOrigin.SUPER_ADMIN
489
446 return self._permission_structure()
490 return self._permission_structure()
447
491
448 def _calculate_global_default_permissions(self):
492 def _calculate_global_default_permissions(self):
@@ -472,18 +516,14 b' class PermissionCalculator(object):'
472 # now we read the defined permissions and overwrite what we have set
516 # now we read the defined permissions and overwrite what we have set
473 # before those can be configured from groups or users explicitly.
517 # before those can be configured from groups or users explicitly.
474
518
475 # TODO: johbo: This seems to be out of sync, find out the reason
519 # In case we want to extend this list we should make sure
476 # for the comment below and update it.
520 # this is in sync with User.DEFAULT_USER_PERMISSIONS definitions
477
478 # In case we want to extend this list we should be always in sync with
479 # User.DEFAULT_USER_PERMISSIONS definitions
480 _configurable = frozenset([
521 _configurable = frozenset([
481 'hg.fork.none', 'hg.fork.repository',
522 'hg.fork.none', 'hg.fork.repository',
482 'hg.create.none', 'hg.create.repository',
523 'hg.create.none', 'hg.create.repository',
483 'hg.usergroup.create.false', 'hg.usergroup.create.true',
524 'hg.usergroup.create.false', 'hg.usergroup.create.true',
484 'hg.repogroup.create.false', 'hg.repogroup.create.true',
525 'hg.repogroup.create.false', 'hg.repogroup.create.true',
485 'hg.create.write_on_repogroup.false',
526 'hg.create.write_on_repogroup.false', 'hg.create.write_on_repogroup.true',
486 'hg.create.write_on_repogroup.true',
487 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
527 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
488 ])
528 ])
489
529
@@ -506,7 +546,7 b' class PermissionCalculator(object):'
506 for gr, perms in _explicit_grouped_perms:
546 for gr, perms in _explicit_grouped_perms:
507 # since user can be in multiple groups iterate over them and
547 # since user can be in multiple groups iterate over them and
508 # select the lowest permissions first (more explicit)
548 # select the lowest permissions first (more explicit)
509 # TODO: marcink: do this^^
549 # TODO(marcink): do this^^
510
550
511 # group doesn't inherit default permissions so we actually set them
551 # group doesn't inherit default permissions so we actually set them
512 if not gr.inherit_default_permissions:
552 if not gr.inherit_default_permissions:
@@ -533,8 +573,8 b' class PermissionCalculator(object):'
533
573
534 def _calculate_default_permissions(self):
574 def _calculate_default_permissions(self):
535 """
575 """
536 Set default user permissions for repositories, repository groups
576 Set default user permissions for repositories, repository branches,
537 taken from the default user.
577 repository groups, user groups taken from the default user.
538
578
539 Calculate inheritance of object permissions based on what we have now
579 Calculate inheritance of object permissions based on what we have now
540 in GLOBAL permissions. We check if .false is in GLOBAL since this is
580 in GLOBAL permissions. We check if .false is in GLOBAL since this is
@@ -551,8 +591,7 b' class PermissionCalculator(object):'
551 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
591 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
552 in self.permissions_global)
592 in self.permissions_global)
553
593
554 # defaults for repositories, taken from `default` user permissions
594 # default permissions for repositories, taken from `default` user permissions
555 # on given repo
556 for perm in self.default_repo_perms:
595 for perm in self.default_repo_perms:
557 r_k = perm.UserRepoToPerm.repository.repo_name
596 r_k = perm.UserRepoToPerm.repository.repo_name
558 p = perm.Permission.permission_name
597 p = perm.Permission.permission_name
@@ -585,8 +624,24 b' class PermissionCalculator(object):'
585 o = PermOrigin.SUPER_ADMIN
624 o = PermOrigin.SUPER_ADMIN
586 self.permissions_repositories[r_k] = p, o
625 self.permissions_repositories[r_k] = p, o
587
626
588 # defaults for repository groups taken from `default` user permission
627 # default permissions branch for repositories, taken from `default` user permissions
589 # on given group
628 for perm in self.default_branch_repo_perms:
629
630 r_k = perm.UserRepoToPerm.repository.repo_name
631 p = perm.Permission.permission_name
632 pattern = perm.UserToRepoBranchPermission.branch_pattern
633 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
634
635 if not self.explicit:
636 # TODO(marcink): fix this for multiple entries
637 cur_perm = self.permissions_repository_branches.get(r_k) or 'branch.none'
638 p = self._choose_permission(p, cur_perm)
639
640 # NOTE(marcink): register all pattern/perm instances in this
641 # special dict that aggregates entries
642 self.permissions_repository_branches[r_k] = pattern, p, o
643
644 # default permissions for repository groups taken from `default` user permission
590 for perm in self.default_repo_groups_perms:
645 for perm in self.default_repo_groups_perms:
591 rg_k = perm.UserRepoGroupToPerm.group.group_name
646 rg_k = perm.UserRepoGroupToPerm.group.group_name
592 p = perm.Permission.permission_name
647 p = perm.Permission.permission_name
@@ -611,8 +666,7 b' class PermissionCalculator(object):'
611 o = PermOrigin.SUPER_ADMIN
666 o = PermOrigin.SUPER_ADMIN
612 self.permissions_repository_groups[rg_k] = p, o
667 self.permissions_repository_groups[rg_k] = p, o
613
668
614 # defaults for user groups taken from `default` user permission
669 # default permissions for user groups taken from `default` user permission
615 # on given user group
616 for perm in self.default_user_group_perms:
670 for perm in self.default_user_group_perms:
617 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
671 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
618 p = perm.Permission.permission_name
672 p = perm.Permission.permission_name
@@ -703,6 +757,49 b' class PermissionCalculator(object):'
703 o = PermOrigin.SUPER_ADMIN
757 o = PermOrigin.SUPER_ADMIN
704 self.permissions_repositories[r_k] = p, o
758 self.permissions_repositories[r_k] = p, o
705
759
760 def _calculate_repository_branch_permissions(self):
761 # user group for repositories permissions
762 user_repo_branch_perms_from_user_group = Permission\
763 .get_default_repo_branch_perms_from_user_group(
764 self.user_id, self.scope_repo_id)
765
766 multiple_counter = collections.defaultdict(int)
767 for perm in user_repo_branch_perms_from_user_group:
768 r_k = perm.UserGroupRepoToPerm.repository.repo_name
769 p = perm.Permission.permission_name
770 pattern = perm.UserGroupToRepoBranchPermission.branch_pattern
771 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
772 .users_group.users_group_name
773
774 multiple_counter[r_k] += 1
775 if multiple_counter[r_k] > 1:
776 # TODO(marcink): fix this for multi branch support, and multiple entries
777 cur_perm = self.permissions_repository_branches[r_k]
778 p = self._choose_permission(p, cur_perm)
779
780 self.permissions_repository_branches[r_k] = pattern, p, o
781
782 # user explicit branch permissions for repositories, overrides
783 # any specified by the group permission
784 user_repo_branch_perms = Permission.get_default_repo_branch_perms(
785 self.user_id, self.scope_repo_id)
786 for perm in user_repo_branch_perms:
787
788 r_k = perm.UserRepoToPerm.repository.repo_name
789 p = perm.Permission.permission_name
790 pattern = perm.UserToRepoBranchPermission.branch_pattern
791 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
792
793 if not self.explicit:
794 # TODO(marcink): fix this for multiple entries
795 cur_perm = self.permissions_repository_branches.get(r_k) or 'branch.none'
796 p = self._choose_permission(p, cur_perm)
797
798 # NOTE(marcink): register all pattern/perm instances in this
799 # special dict that aggregates entries
800 self.permissions_repository_branches[r_k] = pattern, p, o
801
802
706 def _calculate_repository_group_permissions(self):
803 def _calculate_repository_group_permissions(self):
707 """
804 """
708 Repository group permissions for the current user.
805 Repository group permissions for the current user.
@@ -845,6 +942,7 b' class PermissionCalculator(object):'
845 return {
942 return {
846 'global': self.permissions_global,
943 'global': self.permissions_global,
847 'repositories': self.permissions_repositories,
944 'repositories': self.permissions_repositories,
945 'repository_branches': self.permissions_repository_branches,
848 'repositories_groups': self.permissions_repository_groups,
946 'repositories_groups': self.permissions_repository_groups,
849 'user_groups': self.permissions_user_groups,
947 'user_groups': self.permissions_user_groups,
850 }
948 }
@@ -956,6 +1054,9 b' class AuthUser(object):'
956 perms['user_groups'] = {
1054 perms['user_groups'] = {
957 k: v for k, v in perms['user_groups'].items()
1055 k: v for k, v in perms['user_groups'].items()
958 if v != 'usergroup.none'}
1056 if v != 'usergroup.none'}
1057 perms['repository_branches'] = {
1058 k: v for k, v in perms['repository_branches'].iteritems()
1059 if v != 'branch.none'}
959 return perms
1060 return perms
960
1061
961 @LazyProperty
1062 @LazyProperty
@@ -1800,7 +1901,6 b' class PermsFunction(object):'
1800 def __call__(self, check_location='', user=None):
1901 def __call__(self, check_location='', user=None):
1801 if not user:
1902 if not user:
1802 log.debug('Using user attribute from global request')
1903 log.debug('Using user attribute from global request')
1803 # TODO: remove this someday,put as user as attribute here
1804 request = self._get_request()
1904 request = self._get_request()
1805 user = request.user
1905 user = request.user
1806
1906
@@ -751,6 +751,13 b' class AttributeDict(AttributeDictBase):'
751
751
752
752
753
753
754 class OrderedDefaultDict(collections.OrderedDict, collections.defaultdict):
755 def __init__(self, default_factory=None, *args, **kwargs):
756 # in python3 you can omit the args to super
757 super(OrderedDefaultDict, self).__init__(*args, **kwargs)
758 self.default_factory = default_factory
759
760
754 def fix_PATH(os_=None):
761 def fix_PATH(os_=None):
755 """
762 """
756 Get current active python path, and append it to PATH variable to fix
763 Get current active python path, and append it to PATH variable to fix
@@ -1913,6 +1913,7 b' class Repository(Base, BaseModel):'
1913 for _usr in q.all():
1913 for _usr in q.all():
1914 usr = AttributeDict(_usr.user.get_dict())
1914 usr = AttributeDict(_usr.user.get_dict())
1915 usr.permission = _usr.permission.permission_name
1915 usr.permission = _usr.permission.permission_name
1916 usr.permission_id = _usr.repo_to_perm_id
1916 perm_rows.append(usr)
1917 perm_rows.append(usr)
1917
1918
1918 # filter the perm rows by 'default' first and then sort them by
1919 # filter the perm rows by 'default' first and then sort them by
@@ -1926,6 +1927,7 b' class Repository(Base, BaseModel):'
1926 usr = AttributeDict(self.user.get_dict())
1927 usr = AttributeDict(self.user.get_dict())
1927 usr.owner_row = True
1928 usr.owner_row = True
1928 usr.permission = _admin_perm
1929 usr.permission = _admin_perm
1930 usr.permission_id = None
1929 owner_row.append(usr)
1931 owner_row.append(usr)
1930
1932
1931 super_admin_rows = []
1933 super_admin_rows = []
@@ -1938,6 +1940,7 b' class Repository(Base, BaseModel):'
1938 usr = AttributeDict(usr.get_dict())
1940 usr = AttributeDict(usr.get_dict())
1939 usr.admin_row = True
1941 usr.admin_row = True
1940 usr.permission = _admin_perm
1942 usr.permission = _admin_perm
1943 usr.permission_id = None
1941 super_admin_rows.append(usr)
1944 super_admin_rows.append(usr)
1942
1945
1943 return super_admin_rows + owner_row + perm_rows
1946 return super_admin_rows + owner_row + perm_rows
@@ -2694,6 +2697,11 b' class Permission(Base, BaseModel):'
2694 ('usergroup.write', _('User group write access')),
2697 ('usergroup.write', _('User group write access')),
2695 ('usergroup.admin', _('User group admin access')),
2698 ('usergroup.admin', _('User group admin access')),
2696
2699
2700 ('branch.none', _('Branch no permissions')),
2701 ('branch.merge', _('Branch access by web merge')),
2702 ('branch.push', _('Branch access by push')),
2703 ('branch.push_force', _('Branch access by push with force')),
2704
2697 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
2705 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
2698 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
2706 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
2699
2707
@@ -2723,11 +2731,16 b' class Permission(Base, BaseModel):'
2723 ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')),
2731 ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')),
2724 ]
2732 ]
2725
2733
2726 # definition of system default permissions for DEFAULT user
2734 # definition of system default permissions for DEFAULT user, created on
2735 # system setup
2727 DEFAULT_USER_PERMISSIONS = [
2736 DEFAULT_USER_PERMISSIONS = [
2737 # object perms
2728 'repository.read',
2738 'repository.read',
2729 'group.read',
2739 'group.read',
2730 'usergroup.read',
2740 'usergroup.read',
2741 # branch, for backward compat we need same value as before so forced pushed
2742 'branch.push_force',
2743 # global
2731 'hg.create.repository',
2744 'hg.create.repository',
2732 'hg.repogroup.create.false',
2745 'hg.repogroup.create.false',
2733 'hg.usergroup.create.false',
2746 'hg.usergroup.create.false',
@@ -2758,6 +2771,11 b' class Permission(Base, BaseModel):'
2758 'usergroup.write': 3,
2771 'usergroup.write': 3,
2759 'usergroup.admin': 4,
2772 'usergroup.admin': 4,
2760
2773
2774 'branch.none': 0,
2775 'branch.merge': 1,
2776 'branch.push': 3,
2777 'branch.push_force': 4,
2778
2761 'hg.repogroup.create.false': 0,
2779 'hg.repogroup.create.false': 0,
2762 'hg.repogroup.create.true': 1,
2780 'hg.repogroup.create.true': 1,
2763
2781
@@ -2794,6 +2812,21 b' class Permission(Base, BaseModel):'
2794 return q.all()
2812 return q.all()
2795
2813
2796 @classmethod
2814 @classmethod
2815 def get_default_repo_branch_perms(cls, user_id, repo_id=None):
2816 q = Session().query(UserToRepoBranchPermission, UserRepoToPerm, Permission) \
2817 .join(
2818 Permission,
2819 UserToRepoBranchPermission.permission_id == Permission.permission_id) \
2820 .join(
2821 UserRepoToPerm,
2822 UserToRepoBranchPermission.rule_to_perm_id == UserRepoToPerm.repo_to_perm_id) \
2823 .filter(UserRepoToPerm.user_id == user_id)
2824
2825 if repo_id:
2826 q = q.filter(UserToRepoBranchPermission.repository_id == repo_id)
2827 return q.order_by(UserToRepoBranchPermission.rule_order).all()
2828
2829 @classmethod
2797 def get_default_repo_perms_from_user_group(cls, user_id, repo_id=None):
2830 def get_default_repo_perms_from_user_group(cls, user_id, repo_id=None):
2798 q = Session().query(UserGroupRepoToPerm, Repository, Permission)\
2831 q = Session().query(UserGroupRepoToPerm, Repository, Permission)\
2799 .join(
2832 .join(
@@ -2818,10 +2851,37 b' class Permission(Base, BaseModel):'
2818 return q.all()
2851 return q.all()
2819
2852
2820 @classmethod
2853 @classmethod
2854 def get_default_repo_branch_perms_from_user_group(cls, user_id, repo_id=None):
2855 q = Session().query(UserGroupToRepoBranchPermission, UserGroupRepoToPerm, Permission) \
2856 .join(
2857 Permission,
2858 UserGroupToRepoBranchPermission.permission_id == Permission.permission_id) \
2859 .join(
2860 UserGroupRepoToPerm,
2861 UserGroupToRepoBranchPermission.rule_to_perm_id == UserGroupRepoToPerm.users_group_to_perm_id) \
2862 .join(
2863 UserGroup,
2864 UserGroupRepoToPerm.users_group_id == UserGroup.users_group_id) \
2865 .join(
2866 UserGroupMember,
2867 UserGroupRepoToPerm.users_group_id == UserGroupMember.users_group_id) \
2868 .filter(
2869 UserGroupMember.user_id == user_id,
2870 UserGroup.users_group_active == true())
2871
2872 if repo_id:
2873 q = q.filter(UserGroupToRepoBranchPermission.repository_id == repo_id)
2874 return q.order_by(UserGroupToRepoBranchPermission.rule_order).all()
2875
2876 @classmethod
2821 def get_default_group_perms(cls, user_id, repo_group_id=None):
2877 def get_default_group_perms(cls, user_id, repo_group_id=None):
2822 q = Session().query(UserRepoGroupToPerm, RepoGroup, Permission)\
2878 q = Session().query(UserRepoGroupToPerm, RepoGroup, Permission)\
2823 .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\
2879 .join(
2824 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
2880 Permission,
2881 UserRepoGroupToPerm.permission_id == Permission.permission_id)\
2882 .join(
2883 RepoGroup,
2884 UserRepoGroupToPerm.group_id == RepoGroup.group_id)\
2825 .filter(UserRepoGroupToPerm.user_id == user_id)
2885 .filter(UserRepoGroupToPerm.user_id == user_id)
2826 if repo_group_id:
2886 if repo_group_id:
2827 q = q.filter(UserRepoGroupToPerm.group_id == repo_group_id)
2887 q = q.filter(UserRepoGroupToPerm.group_id == repo_group_id)
@@ -2910,6 +2970,8 b' class UserRepoToPerm(Base, BaseModel):'
2910 repository = relationship('Repository')
2970 repository = relationship('Repository')
2911 permission = relationship('Permission')
2971 permission = relationship('Permission')
2912
2972
2973 branch_perm_entry = relationship('UserToRepoBranchPermission', cascade="all, delete, delete-orphan", lazy='joined')
2974
2913 @classmethod
2975 @classmethod
2914 def create(cls, user, repository, permission):
2976 def create(cls, user, repository, permission):
2915 n = cls()
2977 n = cls()
@@ -4470,6 +4532,100 b' def set_task_uid(mapper, connection, tar'
4470 target.task_uid = ScheduleEntry.get_uid(target)
4532 target.task_uid = ScheduleEntry.get_uid(target)
4471
4533
4472
4534
4535 class _BaseBranchPerms(BaseModel):
4536 @classmethod
4537 def compute_hash(cls, value):
4538 return sha1_safe(value)
4539
4540 @hybrid_property
4541 def branch_pattern(self):
4542 return self._branch_pattern or '*'
4543
4544 @hybrid_property
4545 def branch_hash(self):
4546 return self._branch_hash
4547
4548 def _validate_glob(self, value):
4549 re.compile('^' + glob2re(value) + '$')
4550
4551 @branch_pattern.setter
4552 def branch_pattern(self, value):
4553 self._validate_glob(value)
4554 self._branch_pattern = value or '*'
4555 # set the Hash when setting the branch pattern
4556 self._branch_hash = self.compute_hash(self._branch_pattern)
4557
4558 def matches(self, branch):
4559 """
4560 Check if this the branch matches entry
4561
4562 :param branch: branch name for the commit
4563 """
4564
4565 branch = branch or ''
4566
4567 branch_matches = True
4568 if branch:
4569 branch_regex = re.compile('^' + glob2re(self.branch_pattern) + '$')
4570 branch_matches = bool(branch_regex.search(branch))
4571
4572 return branch_matches
4573
4574
4575 class UserToRepoBranchPermission(Base, _BaseBranchPerms):
4576 __tablename__ = 'user_to_repo_branch_permissions'
4577 __table_args__ = (
4578 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4579 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
4580 )
4581
4582 branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
4583
4584 repository_id = Column('repository_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
4585 repo = relationship('Repository', backref='user_branch_perms')
4586
4587 permission_id = Column('permission_id', Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
4588 permission = relationship('Permission')
4589
4590 rule_to_perm_id = Column('rule_to_perm_id', Integer(), ForeignKey('repo_to_perm.repo_to_perm_id'), nullable=False, unique=None, default=None)
4591 user_repo_to_perm = relationship('UserRepoToPerm')
4592
4593 rule_order = Column('rule_order', Integer(), nullable=False)
4594 _branch_pattern = Column('branch_pattern', UnicodeText().with_variant(UnicodeText(2048), 'mysql'), default=u'*') # glob
4595 _branch_hash = Column('branch_hash', UnicodeText().with_variant(UnicodeText(2048), 'mysql'))
4596
4597 def __unicode__(self):
4598 return u'<UserBranchPermission(%s => %r)>' % (
4599 self.user_repo_to_perm, self.branch_pattern)
4600
4601
4602 class UserGroupToRepoBranchPermission(Base, _BaseBranchPerms):
4603 __tablename__ = 'user_group_to_repo_branch_permissions'
4604 __table_args__ = (
4605 {'extend_existing': True, 'mysql_engine': 'InnoDB',
4606 'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
4607 )
4608
4609 branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
4610
4611 repository_id = Column('repository_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
4612 repo = relationship('Repository', backref='user_group_branch_perms')
4613
4614 permission_id = Column('permission_id', Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
4615 permission = relationship('Permission')
4616
4617 rule_to_perm_id = Column('rule_to_perm_id', Integer(), ForeignKey('users_group_repo_to_perm.users_group_to_perm_id'), nullable=False, unique=None, default=None)
4618 user_group_repo_to_perm = relationship('UserGroupRepoToPerm')
4619
4620 rule_order = Column('rule_order', Integer(), nullable=False)
4621 _branch_pattern = Column('branch_pattern', UnicodeText().with_variant(UnicodeText(2048), 'mysql'), default=u'*') # glob
4622 _branch_hash = Column('branch_hash', UnicodeText().with_variant(UnicodeText(2048), 'mysql'))
4623
4624 def __unicode__(self):
4625 return u'<UserBranchPermission(%s => %r)>' % (
4626 self.user_group_repo_to_perm, self.branch_pattern)
4627
4628
4473 class DbMigrateVersion(Base, BaseModel):
4629 class DbMigrateVersion(Base, BaseModel):
4474 __tablename__ = 'db_migrate_version'
4630 __tablename__ = 'db_migrate_version'
4475 __table_args__ = (
4631 __table_args__ = (
@@ -504,12 +504,26 b' def ObjectPermissionsForm(localizer, rep'
504 overwrite_default_repo = v.StringBoolean(if_missing=False)
504 overwrite_default_repo = v.StringBoolean(if_missing=False)
505 overwrite_default_group = v.StringBoolean(if_missing=False)
505 overwrite_default_group = v.StringBoolean(if_missing=False)
506 overwrite_default_user_group = v.StringBoolean(if_missing=False)
506 overwrite_default_user_group = v.StringBoolean(if_missing=False)
507
507 default_repo_perm = v.OneOf(repo_perms_choices)
508 default_repo_perm = v.OneOf(repo_perms_choices)
508 default_group_perm = v.OneOf(group_perms_choices)
509 default_group_perm = v.OneOf(group_perms_choices)
509 default_user_group_perm = v.OneOf(user_group_perms_choices)
510 default_user_group_perm = v.OneOf(user_group_perms_choices)
511
510 return _ObjectPermissionsForm
512 return _ObjectPermissionsForm
511
513
512
514
515 def BranchPermissionsForm(localizer, branch_perms_choices):
516 _ = localizer
517
518 class _BranchPermissionsForm(formencode.Schema):
519 allow_extra_fields = True
520 filter_extra_fields = True
521 overwrite_default_branch = v.StringBoolean(if_missing=False)
522 default_branch_perm = v.OneOf(branch_perms_choices)
523
524 return _BranchPermissionsForm
525
526
513 def UserPermissionsForm(localizer, create_choices, create_on_write_choices,
527 def UserPermissionsForm(localizer, create_choices, create_on_write_choices,
514 repo_group_create_choices, user_group_create_choices,
528 repo_group_create_choices, user_group_create_choices,
515 fork_choices, inherit_default_permissions_choices):
529 fork_choices, inherit_default_permissions_choices):
@@ -31,7 +31,7 b' from sqlalchemy.exc import DatabaseError'
31 from rhodecode.model import BaseModel
31 from rhodecode.model import BaseModel
32 from rhodecode.model.db import (
32 from rhodecode.model.db import (
33 User, Permission, UserToPerm, UserRepoToPerm, UserRepoGroupToPerm,
33 User, Permission, UserToPerm, UserRepoToPerm, UserRepoGroupToPerm,
34 UserUserGroupToPerm, UserGroup, UserGroupToPerm)
34 UserUserGroupToPerm, UserGroup, UserGroupToPerm, UserToRepoBranchPermission)
35 from rhodecode.lib.utils2 import str2bool, safe_int
35 from rhodecode.lib.utils2 import str2bool, safe_int
36
36
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
@@ -59,6 +59,9 b' class PermissionModel(BaseModel):'
59 'default_repo_perm': None,
59 'default_repo_perm': None,
60 'default_group_perm': None,
60 'default_group_perm': None,
61 'default_user_group_perm': None,
61 'default_user_group_perm': None,
62
63 # branch
64 'default_branch_perm': None,
62 }
65 }
63
66
64 def set_global_permission_choices(self, c_obj, gettext_translator):
67 def set_global_permission_choices(self, c_obj, gettext_translator):
@@ -82,6 +85,12 b' class PermissionModel(BaseModel):'
82 ('usergroup.write', _('Write'),),
85 ('usergroup.write', _('Write'),),
83 ('usergroup.admin', _('Admin'),)]
86 ('usergroup.admin', _('Admin'),)]
84
87
88 c_obj.branch_perms_choices = [
89 ('branch.none', _('Protected/No Access'),),
90 ('branch.merge', _('Web merge'),),
91 ('branch.push', _('Push'),),
92 ('branch.push_force', _('Force Push'),)]
93
85 c_obj.register_choices = [
94 c_obj.register_choices = [
86 ('hg.register.none', _('Disabled')),
95 ('hg.register.none', _('Disabled')),
87 ('hg.register.manual_activate', _('Allowed with manual account activation')),
96 ('hg.register.manual_activate', _('Allowed with manual account activation')),
@@ -133,6 +142,10 b' class PermissionModel(BaseModel):'
133 if perm.permission.permission_name.startswith('usergroup.'):
142 if perm.permission.permission_name.startswith('usergroup.'):
134 defaults['default_user_group_perm' + suffix] = perm.permission.permission_name
143 defaults['default_user_group_perm' + suffix] = perm.permission.permission_name
135
144
145 # branch
146 if perm.permission.permission_name.startswith('branch.'):
147 defaults['default_branch_perm' + suffix] = perm.permission.permission_name
148
136 # creation of objects
149 # creation of objects
137 if perm.permission.permission_name.startswith('hg.create.write_on_repogroup'):
150 if perm.permission.permission_name.startswith('hg.create.write_on_repogroup'):
138 defaults['default_repo_create_on_write' + suffix] = perm.permission.permission_name
151 defaults['default_repo_create_on_write' + suffix] = perm.permission.permission_name
@@ -199,6 +212,9 b' class PermissionModel(BaseModel):'
199 'default_repo_perm': 'repository.',
212 'default_repo_perm': 'repository.',
200 'default_group_perm': 'group.',
213 'default_group_perm': 'group.',
201 'default_user_group_perm': 'usergroup.',
214 'default_user_group_perm': 'usergroup.',
215 # branch
216 'default_branch_perm': 'branch.',
217
202 }[field_name]
218 }[field_name]
203 for field in keep_fields:
219 for field in keep_fields:
204 pat = get_pat(field)
220 pat = get_pat(field)
@@ -236,8 +252,12 b' class PermissionModel(BaseModel):'
236 _global_perms = self.global_perms.copy()
252 _global_perms = self.global_perms.copy()
237 if obj_type not in ['user', 'user_group']:
253 if obj_type not in ['user', 'user_group']:
238 raise ValueError("obj_type must be on of 'user' or 'user_group'")
254 raise ValueError("obj_type must be on of 'user' or 'user_group'")
239 if len(_global_perms) != len(Permission.DEFAULT_USER_PERMISSIONS):
255 global_perms = len(_global_perms)
240 raise Exception('Inconsistent permissions definition')
256 default_user_perms = len(Permission.DEFAULT_USER_PERMISSIONS)
257 if global_perms != default_user_perms:
258 raise Exception(
259 'Inconsistent permissions definition. Got {} vs {}'.format(
260 global_perms, default_user_perms))
241
261
242 if obj_type == 'user':
262 if obj_type == 'user':
243 self._clear_user_perms(object.user_id, preserve)
263 self._clear_user_perms(object.user_id, preserve)
@@ -337,8 +357,8 b' class PermissionModel(BaseModel):'
337
357
338 def create_default_user_group_permissions(self, user_group, force=False):
358 def create_default_user_group_permissions(self, user_group, force=False):
339 """
359 """
340 Creates only missing default permissions for user group, if force is set it
360 Creates only missing default permissions for user group, if force is
341 resets the default permissions for that user group
361 set it resets the default permissions for that user group
342
362
343 :param user_group:
363 :param user_group:
344 :param force:
364 :param force:
@@ -366,6 +386,7 b' class PermissionModel(BaseModel):'
366 'default_repo_perm',
386 'default_repo_perm',
367 'default_group_perm',
387 'default_group_perm',
368 'default_user_group_perm',
388 'default_user_group_perm',
389 'default_branch_perm',
369
390
370 'default_repo_group_create',
391 'default_repo_group_create',
371 'default_user_group_create',
392 'default_user_group_create',
@@ -392,6 +413,7 b' class PermissionModel(BaseModel):'
392 'default_repo_perm',
413 'default_repo_perm',
393 'default_group_perm',
414 'default_group_perm',
394 'default_user_group_perm',
415 'default_user_group_perm',
416 'default_branch_perm',
395
417
396 'default_register',
418 'default_register',
397 'default_password_reset',
419 'default_password_reset',
@@ -414,6 +436,7 b' class PermissionModel(BaseModel):'
414 'default_repo_perm',
436 'default_repo_perm',
415 'default_group_perm',
437 'default_group_perm',
416 'default_user_group_perm',
438 'default_user_group_perm',
439 'default_branch_perm',
417
440
418 'default_register',
441 'default_register',
419 'default_password_reset',
442 'default_password_reset',
@@ -440,6 +463,7 b' class PermissionModel(BaseModel):'
440 'default_repo_create',
463 'default_repo_create',
441 'default_fork_create',
464 'default_fork_create',
442 'default_inherit_default_permissions',
465 'default_inherit_default_permissions',
466 'default_branch_perm',
443
467
444 'default_register',
468 'default_register',
445 'default_password_reset',
469 'default_password_reset',
@@ -477,8 +501,57 b' class PermissionModel(BaseModel):'
477 .all():
501 .all():
478 g2p.permission = _def
502 g2p.permission = _def
479 self.sa.add(g2p)
503 self.sa.add(g2p)
504
505 # COMMIT
480 self.sa.commit()
506 self.sa.commit()
481 except (DatabaseError,):
507 except (DatabaseError,):
482 log.exception('Failed to set default object permissions')
508 log.exception('Failed to set default object permissions')
483 self.sa.rollback()
509 self.sa.rollback()
484 raise
510 raise
511
512 def update_branch_permissions(self, form_result):
513 if 'perm_user_id' in form_result:
514 perm_user = User.get(safe_int(form_result['perm_user_id']))
515 else:
516 # used mostly to do lookup for default user
517 perm_user = User.get_by_username(form_result['perm_user_name'])
518 try:
519
520 # stage 2 reset defaults and set them from form data
521 self._set_new_user_perms(perm_user, form_result, preserve=[
522 'default_repo_perm',
523 'default_group_perm',
524 'default_user_group_perm',
525
526 'default_repo_group_create',
527 'default_user_group_create',
528 'default_repo_create_on_write',
529 'default_repo_create',
530 'default_fork_create',
531 'default_inherit_default_permissions',
532
533 'default_register',
534 'default_password_reset',
535 'default_extern_activate'])
536
537 # overwrite default branch permissions
538 if form_result['overwrite_default_branch']:
539 _def_name = \
540 form_result['default_branch_perm'].split('branch.')[-1]
541
542 _def = Permission.get_by_key('branch.' + _def_name)
543
544 # TODO(marcink): those are bind to repo, perms, we need to unfold user somehow from this
545 for g2p in self.sa.query(UserToRepoBranchPermission) \
546 .filter(UserToRepoBranchPermission.user == perm_user) \
547 .all():
548 g2p.permission = _def
549 self.sa.add(g2p)
550
551 # COMMIT
552 self.sa.commit()
553 except (DatabaseError,):
554 log.exception('Failed to set default branch permissions')
555 self.sa.rollback()
556 raise
557
@@ -116,6 +116,11 b''
116 .label;
116 .label;
117 padding-top: 5px;
117 padding-top: 5px;
118 }
118 }
119 .label-branch-perm {
120 .label;
121 width: 20px;
122 }
123
119 // Used to position content on the right side of a .label
124 // Used to position content on the right side of a .label
120 .content,
125 .content,
121 .side-by-side-selector {
126 .side-by-side-selector {
@@ -135,6 +140,15 b''
135 }
140 }
136 }
141 }
137
142
143 .input-branch-perm {
144 .input;
145 margin-left: 90px;
146 }
147
148 .input-branch-perm-order {
149 width: 40px;
150 }
151
138 .checkboxes,
152 .checkboxes,
139 .input,
153 .input,
140 .select {
154 .select {
@@ -169,6 +183,9 b''
169 }
183 }
170
184
171 .input {
185 .input {
186 .branch-perm {
187 width: 80px;
188 }
172 .medium {
189 .medium {
173 width: @fields-input-m;
190 width: @fields-input-m;
174 }
191 }
@@ -462,7 +462,7 b' ul.auth_plugins {'
462
462
463 .radios {
463 .radios {
464 position: relative;
464 position: relative;
465 width: 405px;
465 width: 505px;
466 }
466 }
467 }
467 }
468
468
@@ -159,3 +159,9 b''
159 &:extend(.icon-svn-transparent:before);
159 &:extend(.icon-svn-transparent:before);
160 }
160 }
161 }
161 }
162
163 .icon-user-group:before {
164 &:extend(.icon-group:before);
165 margin: 0;
166 font-size: 16px;
167 }
@@ -109,13 +109,21 b''
109 &.read {
109 &.read {
110 &:extend(.tag1);
110 &:extend(.tag1);
111 }
111 }
112
113 &.write {
112 &.write {
114 &:extend(.tag4);
113 &:extend(.tag4);
115 }
114 }
116 &.admin {
115 &.admin {
117 &:extend(.tag5);
116 &:extend(.tag5);
118 }
117 }
118 &.merge {
119 &:extend(.tag1);
120 }
121 &.push {
122 &:extend(.tag4);
123 }
124 &.push_force {
125 &:extend(.tag5);
126 }
119 }
127 }
120
128
121 .phase-draft {
129 .phase-draft {
@@ -87,6 +87,7 b' function registerRCRoutes() {'
87 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
87 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
88 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
88 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
89 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
89 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
90 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
90 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
91 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
91 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
92 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
92 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
93 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
@@ -233,6 +234,8 b' function registerRCRoutes() {'
233 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
234 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
234 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
235 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
235 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
236 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
237 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
238 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
236 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
239 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
237 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
240 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
238 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
241 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
@@ -38,7 +38,7 b' var api;'
38 { data: {"_": "group_name",
38 { data: {"_": "group_name",
39 "sort": "group_name"}, title: "${_('Name')}", className: "td-componentname," ,
39 "sort": "group_name"}, title: "${_('Name')}", className: "td-componentname," ,
40 render: function (data,type,full,meta)
40 render: function (data,type,full,meta)
41 {return '<div><i class="icon-group" title="User group">'+data+'</i></div>'}},
41 {return '<div><i class="icon-user-group" title="User group">'+data+'</i></div>'}},
42
42
43 { data: {"_": "group_description",
43 { data: {"_": "group_description",
44 "sort": "group_description"}, title: "${_('Description')}", className: "td-description" },
44 "sort": "group_description"}, title: "${_('Description')}", className: "td-description" },
@@ -38,6 +38,9 b''
38 <li class="${'active' if c.active=='objects' else ''}">
38 <li class="${'active' if c.active=='objects' else ''}">
39 <a href="${h.route_path('admin_permissions_object')}">${_('Object')}</a>
39 <a href="${h.route_path('admin_permissions_object')}">${_('Object')}</a>
40 </li>
40 </li>
41 <li class="${'active' if c.active=='branch' else ''}">
42 <a href="${h.route_path('admin_permissions_branch')}">${_('Branch')}</a>
43 </li>
41 <li class="${'active' if c.active=='ips' else ''}">
44 <li class="${'active' if c.active=='ips' else ''}">
42 <a href="${h.route_path('admin_permissions_ips')}">${_('IP Whitelist')}</a>
45 <a href="${h.route_path('admin_permissions_ips')}">${_('IP Whitelist')}</a>
43 </li>
46 </li>
@@ -3,7 +3,10 b''
3 <h3 class="panel-title">${_('Default Permissions for Repositories, User Groups and Repository Groups.')}</h3>
3 <h3 class="panel-title">${_('Default Permissions for Repositories, User Groups and Repository Groups.')}</h3>
4 </div>
4 </div>
5 <div class="panel-body">
5 <div class="panel-body">
6 <p>${_('Default system permissions. Each permissions management entity will be created with the following default settings. Check the overwrite checkbox to force any permission changes on already existing settings.')}
6 <p>
7 ${_('Default access permissions. This defines permissions for the `default` user from which other users inherit permissions.')}
8 <br/>
9 ${_('Check the overwrite checkbox to force change all previously defined permissions for `default` user to the new selected value.')}
7 </p>
10 </p>
8 ${h.secure_form(h.route_path('admin_permissions_object_update'), request=request)}
11 ${h.secure_form(h.route_path('admin_permissions_object_update'), request=request)}
9 <div class="form">
12 <div class="form">
@@ -45,7 +48,7 b''
45 ${h.select('default_user_group_perm','',c.user_group_perms_choices)}
48 ${h.select('default_user_group_perm','',c.user_group_perms_choices)}
46 ${h.checkbox('overwrite_default_user_group','true')}
49 ${h.checkbox('overwrite_default_user_group','true')}
47 <label for="overwrite_default_user_group">
50 <label for="overwrite_default_user_group">
48 <span class="tooltip" title="${h.tooltip(_('All default permissions on each user group will be reset to chosen permission, note that all custom default permission on repository groups will be lost'))}">
51 <span class="tooltip" title="${h.tooltip(_('All default permissions on each user group will be reset to chosen permission, note that all custom default permission on user groups will be lost'))}">
49 ${_('Overwrite Existing Settings')}
52 ${_('Overwrite Existing Settings')}
50 </span>
53 </span>
51 </label>
54 </label>
@@ -57,7 +57,7 b''
57 %if _user.username != h.DEFAULT_USER:
57 %if _user.username != h.DEFAULT_USER:
58 <span class="btn btn-link btn-danger revoke_perm"
58 <span class="btn btn-link btn-danger revoke_perm"
59 member="${_user.user_id}" member_type="user">
59 member="${_user.user_id}" member_type="user">
60 <i class="icon-remove"></i> ${_('Revoke')}
60 ${_('Revoke')}
61 </span>
61 </span>
62 %endif
62 %endif
63 </td>
63 </td>
@@ -92,7 +92,7 b''
92 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.write', checked=_user_group.permission=='group.write')}</td>
92 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.write', checked=_user_group.permission=='group.write')}</td>
93 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.admin', checked=_user_group.permission=='group.admin')}</td>
93 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'group.admin', checked=_user_group.permission=='group.admin')}</td>
94 <td class="td-componentname">
94 <td class="td-componentname">
95 <i class="icon-group" ></i>
95 <i class="icon-user-group"></i>
96 %if h.HasPermissionAny('hg.admin')():
96 %if h.HasPermissionAny('hg.admin')():
97 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
97 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
98 ${_user_group.users_group_name}
98 ${_user_group.users_group_name}
@@ -104,17 +104,27 b''
104 <td class="td-action">
104 <td class="td-action">
105 <span class="btn btn-link btn-danger revoke_perm"
105 <span class="btn btn-link btn-danger revoke_perm"
106 member="${_user_group.users_group_id}" member_type="user_group">
106 member="${_user_group.users_group_id}" member_type="user_group">
107 <i class="icon-remove"></i> ${_('Revoke')}
107 ${_('Revoke')}
108 </span>
108 </span>
109 </td>
109 </td>
110 </tr>
110 </tr>
111 %endfor
111 %endfor
112
112
113 <tr class="new_members" id="add_perm_input"></tr>
113 <tr class="new_members" id="add_perm_input"></tr>
114 <tr>
115 <td></td>
116 <td></td>
117 <td></td>
118 <td></td>
119 <td></td>
120 <td>
121 <span id="add_perm" class="link">
122 ${_('Add user/user group')}
123 </span>
124 </td>
125 </tr>
114 </table>
126 </table>
115 <div id="add_perm" class="link">
127
116 ${_('Add new')}
117 </div>
118 <div class="fields">
128 <div class="fields">
119 <div class="field">
129 <div class="field">
120 <div class="label label-radio">
130 <div class="label label-radio">
@@ -48,6 +48,9 b''
48 <li class="${'active' if c.active=='permissions' else ''}">
48 <li class="${'active' if c.active=='permissions' else ''}">
49 <a href="${h.route_path('edit_repo_perms', repo_name=c.repo_name)}">${_('Permissions')}</a>
49 <a href="${h.route_path('edit_repo_perms', repo_name=c.repo_name)}">${_('Permissions')}</a>
50 </li>
50 </li>
51 <li class="${'active' if c.active=='permissions_branch' else ''}">
52 <a href="${h.route_path('edit_repo_perms_branch', repo_name=c.repo_name)}">${_('Branch Permissions')}</a>
53 </li>
51 <li class="${'active' if c.active=='advanced' else ''}">
54 <li class="${'active' if c.active=='advanced' else ''}">
52 <a href="${h.route_path('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a>
55 <a href="${h.route_path('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a>
53 </li>
56 </li>
@@ -67,7 +67,7 b''
67 %if _user.username != h.DEFAULT_USER:
67 %if _user.username != h.DEFAULT_USER:
68 <span class="btn btn-link btn-danger revoke_perm"
68 <span class="btn btn-link btn-danger revoke_perm"
69 member="${_user.user_id}" member_type="user">
69 member="${_user.user_id}" member_type="user">
70 <i class="icon-remove"></i> ${_('Revoke')}
70 ${_('Revoke')}
71 </span>
71 </span>
72 %endif
72 %endif
73 </td>
73 </td>
@@ -83,7 +83,7 b''
83 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.write', checked=_user_group.permission=='repository.write')}</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>
84 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'repository.admin', checked=_user_group.permission=='repository.admin')}</td>
85 <td class="td-componentname">
85 <td class="td-componentname">
86 <i class="icon-group" ></i>
86 <i class="icon-user-group"></i>
87 %if h.HasPermissionAny('hg.admin')():
87 %if h.HasPermissionAny('hg.admin')():
88 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
88 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
89 ${_user_group.users_group_name}
89 ${_user_group.users_group_name}
@@ -95,16 +95,28 b''
95 <td class="td-action">
95 <td class="td-action">
96 <span class="btn btn-link btn-danger revoke_perm"
96 <span class="btn btn-link btn-danger revoke_perm"
97 member="${_user_group.users_group_id}" member_type="user_group">
97 member="${_user_group.users_group_id}" member_type="user_group">
98 <i class="icon-remove"></i> ${_('Revoke')}
98 ${_('Revoke')}
99 </span>
99 </span>
100 </td>
100 </td>
101 </tr>
101 </tr>
102 %endfor
102 %endfor
103 <tr class="new_members" id="add_perm_input"></tr>
103 <tr class="new_members" id="add_perm_input"></tr>
104
105 <tr>
106 <td></td>
107 <td></td>
108 <td></td>
109 <td></td>
110 <td></td>
111 <td>
112 <span id="add_perm" class="link">
113 ${_('Add user/user group')}
114 </span>
115 </td>
116 </tr>
117
104 </table>
118 </table>
105 <div id="add_perm" class="link">
119
106 ${_('Add new')}
107 </div>
108 <div class="buttons">
120 <div class="buttons">
109 ${h.submit('save',_('Save'),class_="btn btn-primary")}
121 ${h.submit('save',_('Save'),class_="btn btn-primary")}
110 ${h.reset('reset',_('Reset'),class_="btn btn-danger")}
122 ${h.reset('reset',_('Reset'),class_="btn btn-danger")}
@@ -59,7 +59,7 b''
59 %if _user.username != h.DEFAULT_USER:
59 %if _user.username != h.DEFAULT_USER:
60 <span class="btn btn-link btn-danger revoke_perm"
60 <span class="btn btn-link btn-danger revoke_perm"
61 member="${_user.user_id}" member_type="user">
61 member="${_user.user_id}" member_type="user">
62 <i class="icon-remove"></i> ${_('revoke')}
62 ${_('Revoke')}
63 </span>
63 </span>
64 %endif
64 %endif
65 </td>
65 </td>
@@ -94,7 +94,7 b''
94 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.write')}</td>
94 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.write')}</td>
95 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.admin')}</td>
95 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.admin')}</td>
96 <td class="td-user">
96 <td class="td-user">
97 <i class="icon-group" ></i>
97 <i class="icon-user-group"></i>
98 %if h.HasPermissionAny('hg.admin')():
98 %if h.HasPermissionAny('hg.admin')():
99 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
99 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
100 ${_user_group.users_group_name}
100 ${_user_group.users_group_name}
@@ -106,16 +106,26 b''
106 <td class="td-action">
106 <td class="td-action">
107 <span class="btn btn-link btn-danger revoke_perm"
107 <span class="btn btn-link btn-danger revoke_perm"
108 member="${_user_group.users_group_id}" member_type="user_group">
108 member="${_user_group.users_group_id}" member_type="user_group">
109 <i class="icon-remove"></i> ${_('revoke')}
109 ${_('Revoke')}
110 </span>
110 </span>
111 </td>
111 </td>
112 </tr>
112 </tr>
113 %endfor
113 %endfor
114 <tr class="new_members" id="add_perm_input"></tr>
114 <tr class="new_members" id="add_perm_input"></tr>
115 <tr>
116 <td></td>
117 <td></td>
118 <td></td>
119 <td></td>
120 <td></td>
121 <td>
122 <span id="add_perm" class="link">
123 ${_('Add user/user group')}
124 </span>
125 </td>
126 </tr>
115 </table>
127 </table>
116 <div id="add_perm" class="link">
128
117 ${_('Add new')}
118 </div>
119 <div class="buttons">
129 <div class="buttons">
120 ${h.submit('save',_('Save'),class_="btn btn-primary")}
130 ${h.submit('save',_('Save'),class_="btn btn-primary")}
121 ${h.reset('reset',_('Reset'),class_="btn btn-danger")}
131 ${h.reset('reset',_('Reset'),class_="btn btn-danger")}
@@ -53,7 +53,7 b' var api;'
53 { data: {"_": "group_name",
53 { data: {"_": "group_name",
54 "sort": "group_name"}, title: "${_('Name')}", className: "td-componentname," ,
54 "sort": "group_name"}, title: "${_('Name')}", className: "td-componentname," ,
55 render: function (data,type,full,meta)
55 render: function (data,type,full,meta)
56 {return '<div><i class="icon-group" title="User group">'+data+'</i></div>'}},
56 {return '<div><i class="icon-user-group" title="User group">'+data+'</i></div>'}},
57
57
58 { data: {"_": "group_description",
58 { data: {"_": "group_description",
59 "sort": "group_description"}, title: "${_('Description')}", className: "td-description" },
59 "sort": "group_description"}, title: "${_('Description')}", className: "td-description" },
@@ -4,11 +4,20 b''
4 ## ${p.perms_summary(c.perm_user.permissions)}
4 ## ${p.perms_summary(c.perm_user.permissions)}
5
5
6 <%def name="perms_summary(permissions, show_all=False, actions=True, side_link=None)">
6 <%def name="perms_summary(permissions, show_all=False, actions=True, side_link=None)">
7 <% section_to_label = {
8 'global': 'Global Permissions',
9 'repository_branches': 'Repository Branch Rules',
10 'repositories': 'Repository Permissions',
11 'user_groups': 'User Group Permissions',
12 'repositories_groups': 'Repository Group Permissions',
13 } %>
7 <div id="perms" class="table fields">
14 <div id="perms" class="table fields">
8 %for section in sorted(permissions.keys()):
15 %for section in sorted(permissions.keys(), key=lambda item: {'global': 0, 'repository_branches': 1}.get(item, 1000)):
9 <div class="panel panel-default">
16 <div class="panel panel-default">
10 <div class="panel-heading">
17 <div class="panel-heading" id="${section.replace("_","-")}-permissions">
11 <h3 class="panel-title">${section.replace("_"," ").capitalize()}</h3>
18 <h3 class="panel-title">${section_to_label.get(section, section)} - ${len(permissions[section])}
19 <a class="permalink" href="#${section.replace("_","-")}-permissions"> ΒΆ</a>
20 </h3>
12 % if side_link:
21 % if side_link:
13 <div class="pull-right">
22 <div class="pull-right">
14 <a href="${side_link}">${_('in JSON format')}</a>
23 <a href="${side_link}">${_('in JSON format')}</a>
@@ -18,15 +27,24 b''
18 <div class="panel-body">
27 <div class="panel-body">
19 <div class="perms_section_head field">
28 <div class="perms_section_head field">
20 <div class="radios">
29 <div class="radios">
21 %if section != 'global':
30 % if section == 'repository_branches':
22 <span class="permissions_boxes">
31 <span class="permissions_boxes">
23 <span class="desc">${_('show')}: </span>
32 <span class="desc">${_('show')}: </span>
24 ${h.checkbox('perms_filter_none_%s' % section, 'none', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='none')} <label for="${'perms_filter_none_%s' % section}"><span class="perm_tag none">${_('none')}</span></label>
33 ${h.checkbox('perms_filter_none_%s' % section, 'none', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='none')} <label for="${'perms_filter_none_{}'.format(section)}"><span class="perm_tag none">${_('none')}</span></label>
25 ${h.checkbox('perms_filter_read_%s' % section, 'read', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='read')} <label for="${'perms_filter_read_%s' % section}"><span class="perm_tag read">${_('read')}</span></label>
34 ${h.checkbox('perms_filter_merge_%s' % section, 'merge', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='merge')} <label for="${'perms_filter_merge_{}'.format(section)}"><span class="perm_tag merge">${_('merge')}</span></label>
26 ${h.checkbox('perms_filter_write_%s' % section, 'write', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='write')} <label for="${'perms_filter_write_%s' % section}"> <span class="perm_tag write">${_('write')}</span></label>
35 ${h.checkbox('perms_filter_push_%s' % section, 'push', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='push')} <label for="${'perms_filter_push_{}'.format(section)}"> <span class="perm_tag push">${_('push')}</span></label>
27 ${h.checkbox('perms_filter_admin_%s' % section, 'admin', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='admin')} <label for="${'perms_filter_admin_%s' % section}"><span class="perm_tag admin">${_('admin')}</span></label>
36 ${h.checkbox('perms_filter_push_force_%s' % section, 'push_force', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='push_force')} <label for="${'perms_filter_push_force_{}'.format(section)}"><span class="perm_tag push_force">${_('push force')}</span></label>
28 </span>
37 </span>
29 %endif
38 % elif section != 'global':
39 <span class="permissions_boxes">
40 <span class="desc">${_('show')}: </span>
41 ${h.checkbox('perms_filter_none_%s' % section, 'none', '', class_='perm_filter filter_%s' % section, section=section, perm_type='none')} <label for="${'perms_filter_none_{}'.format(section)}"><span class="perm_tag none">${_('none')}</span></label>
42 ${h.checkbox('perms_filter_read_%s' % section, 'read', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='read')} <label for="${'perms_filter_read_{}'.format(section)}"><span class="perm_tag read">${_('read')}</span></label>
43 ${h.checkbox('perms_filter_write_%s' % section, 'write', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='write')} <label for="${'perms_filter_write_{}'.format(section)}"> <span class="perm_tag write">${_('write')}</span></label>
44 ${h.checkbox('perms_filter_admin_%s' % section, 'admin', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='admin')} <label for="${'perms_filter_admin_{}'.format(section)}"><span class="perm_tag admin">${_('admin')}</span></label>
45 </span>
46 % endif
47
30 </div>
48 </div>
31 </div>
49 </div>
32 <div class="field">
50 <div class="field">
@@ -72,12 +90,10 b''
72 %endif
90 %endif
73 %else:
91 %else:
74 %if not val_lbl:
92 %if not val_lbl:
75 ${
93 ${{'false': False,
76 {'false': False,
77 'true': True,
94 'true': True,
78 'none': False,
95 'none': False,
79 'repository': True}.get(val[1][0] if 0 < len(val[1]) else 'false')
96 'repository': True}.get(val[1][0] if 0 < len(val[1]) else 'false')}
80 }
81 %else:
97 %else:
82 <span class="perm_tag ${val[1][0]}">${val_lbl}.${val[1][0]}</span>
98 <span class="perm_tag ${val[1][0]}">${val_lbl}.${val[1][0]}</span>
83 %endif
99 %endif
@@ -142,7 +158,72 b''
142 edit_url=h.route_path('user_edit_global_perms', user_id=c.user.user_id), edit_global_url=h.route_path('admin_permissions_object'))}
158 edit_url=h.route_path('user_edit_global_perms', user_id=c.user.user_id), edit_global_url=h.route_path('admin_permissions_object'))}
143
159
144 </tbody>
160 </tbody>
161 ## Branch perms
162 %elif section == 'repository_branches':
163 <thead>
164 <tr>
165 <th>${_('Name')}</th>
166 <th>${_('Pattern')}</th>
167 <th>${_('Permission')}</th>
168 %if actions:
169 <th>${_('Edit Branch Permission')}</th>
170 %endif
171 </thead>
172 <tbody class="section_${section}">
173 <%
174 def name_sorter(permissions):
175 def custom_sorter(item):
176 return item[0]
177 return sorted(permissions, key=custom_sorter)
178
179 def branch_sorter(permissions):
180 def custom_sorter(item):
181 ## none, merge, push, push_force
182 section = item[1].split('.')[-1]
183 section_importance = {'none': u'0',
184 'merge': u'1',
185 'push': u'2',
186 'push_force': u'3'}.get(section)
187 ## sort by importance + name
188 return section_importance + item[0]
189 return sorted(permissions, key=custom_sorter)
190 %>
191 %for k, section_perms in name_sorter(permissions[section].items()):
192 % for pattern, perm in branch_sorter(section_perms.items()):
193 <tr class="perm_row ${'{}_{}'.format(section, perm.split('.')[-1])}">
194 <td class="td-name">
195 <a href="${h.route_path('repo_summary',repo_name=k)}">${k}</a>
196 </td>
197 <td>${pattern}</td>
198 <td class="td-tags">
199 ## TODO: calculate origin somehow
200 ## % for i, ((_pat, perm), origin) in enumerate((permissions[section].perm_origin_stack[k])):
201
202 <div>
203 <% i = 0 %>
204 <% origin = 'unknown' %>
205 <% _css_class = i > 0 and 'perm_overriden' or '' %>
206
207 <span class="${_css_class} perm_tag ${perm.split('.')[-1]}">
208 ${perm}
209 ##(${origin})
210 </span>
211 </div>
212 ## % endfor
213 </td>
214 %if actions:
215 <td class="td-action">
216 <a href="${h.route_path('edit_repo_perms_branch',repo_name=k)}">${_('edit')}</a>
217 </td>
218 %endif
219 </tr>
220 % endfor
221 %endfor
222 </tbody>
223
224 ## Repos/Repo Groups/users groups perms
145 %else:
225 %else:
226
146 ## none/read/write/admin permissions on groups/repos etc
227 ## none/read/write/admin permissions on groups/repos etc
147 <thead>
228 <thead>
148 <tr>
229 <tr>
@@ -167,8 +248,11 b''
167 return sorted(permissions, key=custom_sorter)
248 return sorted(permissions, key=custom_sorter)
168 %>
249 %>
169 %for k, section_perm in sorter(permissions[section].items()):
250 %for k, section_perm in sorter(permissions[section].items()):
170 %if section_perm.split('.')[-1] != 'none' or show_all:
251 <% perm_value = section_perm.split('.')[-1] %>
171 <tr class="perm_row ${'%s_%s' % (section, section_perm.split('.')[-1])}">
252 <% _css_class = 'display:none' if perm_value in ['none'] else '' %>
253
254 %if perm_value != 'none' or show_all:
255 <tr class="perm_row ${'{}_{}'.format(section, section_perm.split('.')[-1])}" style="${_css_class}">
172 <td class="td-name">
256 <td class="td-name">
173 %if section == 'repositories':
257 %if section == 'repositories':
174 <a href="${h.route_path('repo_summary',repo_name=k)}">${k}</a>
258 <a href="${h.route_path('repo_summary',repo_name=k)}">${k}</a>
@@ -183,7 +267,7 b''
183 %if hasattr(permissions[section], 'perm_origin_stack'):
267 %if hasattr(permissions[section], 'perm_origin_stack'):
184 <div>
268 <div>
185 %for i, (perm, origin) in enumerate(reversed(permissions[section].perm_origin_stack[k])):
269 %for i, (perm, origin) in enumerate(reversed(permissions[section].perm_origin_stack[k])):
186
270 <% _css_class = i > 0 and 'perm_overriden' or '' %>
187 % if i > 0:
271 % if i > 0:
188 <div style="color: #979797">
272 <div style="color: #979797">
189 <i class="icon-arrow_up"></i>
273 <i class="icon-arrow_up"></i>
@@ -193,7 +277,7 b''
193 % endif
277 % endif
194
278
195 <div>
279 <div>
196 <span class="${i > 0 and 'perm_overriden' or ''} perm_tag ${perm.split('.')[-1]}">
280 <span class="${_css_class} perm_tag ${perm.split('.')[-1]}">
197 ${perm} (${origin})
281 ${perm} (${origin})
198 </span>
282 </span>
199 </div>
283 </div>
@@ -220,7 +304,7 b''
220 %endfor
304 %endfor
221
305
222 <tr id="empty_${section}" class="noborder" style="display:none;">
306 <tr id="empty_${section}" class="noborder" style="display:none;">
223 <td colspan="6">${_('No permission defined')}</td>
307 <td colspan="6">${_('No matching permission defined')}</td>
224 </tr>
308 </tr>
225
309
226 </tbody>
310 </tbody>
@@ -236,15 +320,16 b''
236
320
237 <script>
321 <script>
238 $(document).ready(function(){
322 $(document).ready(function(){
239 var show_empty = function(section){
323 var showEmpty = function(section){
240 var visible = $('.section_{0} tr.perm_row:visible'.format(section)).length;
324 var visible = $('.section_{0} tr.perm_row:visible'.format(section)).length;
241 if(visible == 0){
325 if(visible === 0){
242 $('#empty_{0}'.format(section)).show();
326 $('#empty_{0}'.format(section)).show();
243 }
327 }
244 else{
328 else{
245 $('#empty_{0}'.format(section)).hide();
329 $('#empty_{0}'.format(section)).hide();
246 }
330 }
247 };
331 };
332
248 $('.perm_filter').on('change', function(e){
333 $('.perm_filter').on('change', function(e){
249 var self = this;
334 var self = this;
250 var section = $(this).attr('section');
335 var section = $(this).attr('section');
@@ -261,7 +346,7 b''
261 $('.'+section+'_'+perm_type).hide();
346 $('.'+section+'_'+perm_type).hide();
262 }
347 }
263 });
348 });
264 show_empty(section);
349 showEmpty(section);
265 })
350 })
266 })
351 })
267 </script>
352 </script>
@@ -284,7 +284,7 b''
284
284
285 <%def name="user_group_name(user_group_name)">
285 <%def name="user_group_name(user_group_name)">
286 <div>
286 <div>
287 <i class="icon-group" title="${_('User group')}"></i>
287 <i class="icon-user-group" title="${_('User group')}"></i>
288 ${h.link_to_group(user_group_name)}
288 ${h.link_to_group(user_group_name)}
289 </div>
289 </div>
290 </%def>
290 </%def>
@@ -534,7 +534,7 b''
534 </tbody>
534 </tbody>
535 </table>
535 </table>
536 <div class="link" id="add_perm">
536 <div class="link" id="add_perm">
537 Add new
537 Add user/user group
538 </div>
538 </div>
539
539
540
540
@@ -8,12 +8,11 b''
8 <div class="panel-heading">${title}</div>
8 <div class="panel-heading">${title}</div>
9 <div class="panel-body">
9 <div class="panel-body">
10
10
11 <div tal:condition="errormsg"
11 <div tal:condition="errormsg" class="clearfix alert alert-error">
12 class="clearfix alert alert-danger">
12 <span i18n:translate="">
13 <p i18n:translate="">
14 There was a problem with this section
13 There was a problem with this section
15 </p>
14 </span>
16 <p>${errormsg}</p>
15 <div>${errormsg}</div>
17 </div>
16 </div>
18
17
19 <div tal:condition="description">
18 <div tal:condition="description">
@@ -140,6 +140,10 b' class TestPermissions(object):'
140 assert repo_perms(user)[repo.repo_name] == 'repository.admin'
140 assert repo_perms(user)[repo.repo_name] == 'repository.admin'
141 repo.user = org_owner
141 repo.user = org_owner
142
142
143 def test_default_owner_branch_perms(self, user_util, test_user_group):
144 user = user_util.create_user()
145 assert branch_perms(user) == {}
146
143 def test_default_owner_repo_group_perms(self, user_util, test_repo_group):
147 def test_default_owner_repo_group_perms(self, user_util, test_repo_group):
144 user = user_util.create_user()
148 user = user_util.create_user()
145 org_owner = test_repo_group.user
149 org_owner = test_repo_group.user
@@ -360,13 +364,15 b' class TestPermissions(object):'
360 user_model.revoke_perm(self.u1, 'hg.fork.repository')
364 user_model.revoke_perm(self.u1, 'hg.fork.repository')
361 user_model.grant_perm(self.u1, 'hg.fork.none')
365 user_model.grant_perm(self.u1, 'hg.fork.none')
362
366
367 # TODO(marcink): check branch permissions now ?
368
363 # make sure inherit flag is turned off
369 # make sure inherit flag is turned off
364 self.u1.inherit_default_permissions = False
370 self.u1.inherit_default_permissions = False
365 Session().commit()
371 Session().commit()
366
372
367 # this user will have non inherited permissions from he's
373 # this user will have non inherited permissions from he's
368 # explicitly set permissions
374 # explicitly set permissions
369 assert global_perms(self.u1) == set([
375 assert global_perms(self.u1) == {
370 'hg.create.none',
376 'hg.create.none',
371 'hg.fork.none',
377 'hg.fork.none',
372 'hg.register.manual_activate',
378 'hg.register.manual_activate',
@@ -375,7 +381,8 b' class TestPermissions(object):'
375 'repository.read',
381 'repository.read',
376 'group.read',
382 'group.read',
377 'usergroup.read',
383 'usergroup.read',
378 ])
384 'branch.push_force',
385 }
379
386
380 def test_non_inherited_permissions_from_default_on_user_disabled(self):
387 def test_non_inherited_permissions_from_default_on_user_disabled(self):
381 user_model = UserModel()
388 user_model = UserModel()
@@ -396,9 +403,11 b' class TestPermissions(object):'
396 self.u1.inherit_default_permissions = False
403 self.u1.inherit_default_permissions = False
397 Session().commit()
404 Session().commit()
398
405
406 # TODO(marcink): check branch perms
407
399 # this user will have non inherited permissions from he's
408 # this user will have non inherited permissions from he's
400 # explicitly set permissions
409 # explicitly set permissions
401 assert global_perms(self.u1) == set([
410 assert global_perms(self.u1) == {
402 'hg.create.repository',
411 'hg.create.repository',
403 'hg.fork.repository',
412 'hg.fork.repository',
404 'hg.register.manual_activate',
413 'hg.register.manual_activate',
@@ -407,7 +416,8 b' class TestPermissions(object):'
407 'repository.read',
416 'repository.read',
408 'group.read',
417 'group.read',
409 'usergroup.read',
418 'usergroup.read',
410 ])
419 'branch.push_force',
420 }
411
421
412 @pytest.mark.parametrize('perm, expected_perm', [
422 @pytest.mark.parametrize('perm, expected_perm', [
413 ('hg.inherit_default_perms.false', 'repository.none', ),
423 ('hg.inherit_default_perms.false', 'repository.none', ),
@@ -425,8 +435,10 b' class TestPermissions(object):'
425 self.u1.inherit_default_permissions = True
435 self.u1.inherit_default_permissions = True
426 Session().commit()
436 Session().commit()
427
437
438 # TODO(marcink): check branch perms
439
428 # this user will have inherited permissions from default user
440 # this user will have inherited permissions from default user
429 assert global_perms(self.u1) == set([
441 assert global_perms(self.u1) == {
430 'hg.create.none',
442 'hg.create.none',
431 'hg.fork.none',
443 'hg.fork.none',
432 'hg.register.manual_activate',
444 'hg.register.manual_activate',
@@ -435,11 +447,12 b' class TestPermissions(object):'
435 'repository.read',
447 'repository.read',
436 'group.read',
448 'group.read',
437 'usergroup.read',
449 'usergroup.read',
450 'branch.push_force',
438 'hg.create.write_on_repogroup.true',
451 'hg.create.write_on_repogroup.true',
439 'hg.usergroup.create.false',
452 'hg.usergroup.create.false',
440 'hg.repogroup.create.false',
453 'hg.repogroup.create.false',
441 perm,
454 perm
442 ])
455 }
443
456
444 assert set(repo_perms(self.u1).values()) == set([expected_perm])
457 assert set(repo_perms(self.u1).values()) == set([expected_perm])
445
458
@@ -693,6 +706,11 b' def repo_perms(user):'
693 return auth_user.permissions['repositories']
706 return auth_user.permissions['repositories']
694
707
695
708
709 def branch_perms(user):
710 auth_user = AuthUser(user_id=user.user_id)
711 return auth_user.permissions['repository_branches']
712
713
696 def group_perms(user):
714 def group_perms(user):
697 auth_user = AuthUser(user_id=user.user_id)
715 auth_user = AuthUser(user_id=user.user_id)
698 return auth_user.permissions['repositories_groups']
716 return auth_user.permissions['repositories_groups']
@@ -66,5 +66,5 b' class TestTags(BackendTestMixin):'
66 def test_name_with_slash(self):
66 def test_name_with_slash(self):
67 self.repo.tag('19/10/11', 'joe')
67 self.repo.tag('19/10/11', 'joe')
68 assert '19/10/11' in self.repo.tags
68 assert '19/10/11' in self.repo.tags
69 self.repo.tag('11', 'joe')
69 self.repo.tag('rel.11', 'joe')
70 assert '11' in self.repo.tags
70 assert 'rel.11' in self.repo.tags
General Comments 0
You need to be logged in to leave comments. Login now