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 | |
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 | 51 | EXTENSIONS = {} |
|
52 | 52 | |
|
53 | 53 | __version__ = ('.'.join((str(each) for each in VERSION[:3]))) |
|
54 |
__dbversion__ = |
|
|
54 | __dbversion__ = 90 # defines current db version for migrations | |
|
55 | 55 | __platform__ = platform.system() |
|
56 | 56 | __license__ = 'AGPLv3, and Commercial License' |
|
57 | 57 | __author__ = 'RhodeCode GmbH' |
@@ -210,6 +210,11 b' def admin_routes(config):' | |||
|
210 | 210 | name='admin_permissions_object_update', |
|
211 | 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 | 218 | config.add_route( |
|
214 | 219 | name='admin_permissions_ips', |
|
215 | 220 | pattern='/permissions/ips') |
@@ -182,7 +182,8 b' class AdminPermissionsView(BaseAppView, ' | |||
|
182 | 182 | self.request.translate, |
|
183 | 183 | [x[0] for x in c.repo_perms_choices], |
|
184 | 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 | 188 | try: |
|
188 | 189 | form_result = _form.to_python(dict(self.request.POST)) |
@@ -218,6 +219,30 b' class AdminPermissionsView(BaseAppView, ' | |||
|
218 | 219 | @LoginRequired() |
|
219 | 220 | @HasPermissionAllDecorator('hg.admin') |
|
220 | 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 | 246 | route_name='admin_permissions_global', request_method='GET', |
|
222 | 247 | renderer='rhodecode:templates/admin/permissions/permissions.mako') |
|
223 | 248 | def permissions_global(self): |
@@ -345,6 +345,15 b' def includeme(config):' | |||
|
345 | 345 | name='edit_repo_perms', |
|
346 | 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 | 357 | # Maintenance |
|
349 | 358 | config.add_route( |
|
350 | 359 | name='edit_repo_maintenance', |
@@ -367,10 +367,38 b' class PermOriginDict(dict):' | |||
|
367 | 367 | self.perm_origin_stack = collections.OrderedDict() |
|
368 | 368 | |
|
369 | 369 | def __setitem__(self, key, (perm, origin)): |
|
370 |
self.perm_origin_stack.setdefault(key, []).append( |
|
|
370 | self.perm_origin_stack.setdefault(key, []).append( | |
|
371 | (perm, origin)) | |
|
371 | 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 | 402 | class PermissionCalculator(object): |
|
375 | 403 | |
|
376 | 404 | def __init__( |
@@ -395,6 +423,7 b' class PermissionCalculator(object):' | |||
|
395 | 423 | self.permissions_repositories = PermOriginDict() |
|
396 | 424 | self.permissions_repository_groups = PermOriginDict() |
|
397 | 425 | self.permissions_user_groups = PermOriginDict() |
|
426 | self.permissions_repository_branches = BranchPermOriginDict() | |
|
398 | 427 | self.permissions_global = set() |
|
399 | 428 | |
|
400 | 429 | self.default_repo_perms = Permission.get_default_repo_perms( |
@@ -405,6 +434,11 b' class PermissionCalculator(object):' | |||
|
405 | 434 | Permission.get_default_user_group_perms( |
|
406 | 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 | 442 | def calculate(self): |
|
409 | 443 | if self.user_is_admin and not self.calculate_super_admin: |
|
410 | 444 | return self._admin_permissions() |
@@ -413,6 +447,7 b' class PermissionCalculator(object):' | |||
|
413 | 447 | self._calculate_global_permissions() |
|
414 | 448 | self._calculate_default_permissions() |
|
415 | 449 | self._calculate_repository_permissions() |
|
450 | self._calculate_repository_branch_permissions() | |
|
416 | 451 | self._calculate_repository_group_permissions() |
|
417 | 452 | self._calculate_user_group_permissions() |
|
418 | 453 | return self._permission_structure() |
@@ -443,6 +478,15 b' class PermissionCalculator(object):' | |||
|
443 | 478 | p = 'usergroup.admin' |
|
444 | 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 | 490 | return self._permission_structure() |
|
447 | 491 | |
|
448 | 492 | def _calculate_global_default_permissions(self): |
@@ -472,18 +516,14 b' class PermissionCalculator(object):' | |||
|
472 | 516 | # now we read the defined permissions and overwrite what we have set |
|
473 | 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 | |
|
476 | # for the comment below and update it. | |
|
477 | ||
|
478 | # In case we want to extend this list we should be always in sync with | |
|
479 | # User.DEFAULT_USER_PERMISSIONS definitions | |
|
519 | # In case we want to extend this list we should make sure | |
|
520 | # this is in sync with User.DEFAULT_USER_PERMISSIONS definitions | |
|
480 | 521 | _configurable = frozenset([ |
|
481 | 522 | 'hg.fork.none', 'hg.fork.repository', |
|
482 | 523 | 'hg.create.none', 'hg.create.repository', |
|
483 | 524 | 'hg.usergroup.create.false', 'hg.usergroup.create.true', |
|
484 | 525 | 'hg.repogroup.create.false', 'hg.repogroup.create.true', |
|
485 | 'hg.create.write_on_repogroup.false', | |
|
486 | 'hg.create.write_on_repogroup.true', | |
|
526 | 'hg.create.write_on_repogroup.false', 'hg.create.write_on_repogroup.true', | |
|
487 | 527 | 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true' |
|
488 | 528 | ]) |
|
489 | 529 | |
@@ -506,7 +546,7 b' class PermissionCalculator(object):' | |||
|
506 | 546 | for gr, perms in _explicit_grouped_perms: |
|
507 | 547 | # since user can be in multiple groups iterate over them and |
|
508 | 548 | # select the lowest permissions first (more explicit) |
|
509 |
# TODO |
|
|
549 | # TODO(marcink): do this^^ | |
|
510 | 550 | |
|
511 | 551 | # group doesn't inherit default permissions so we actually set them |
|
512 | 552 | if not gr.inherit_default_permissions: |
@@ -533,8 +573,8 b' class PermissionCalculator(object):' | |||
|
533 | 573 | |
|
534 | 574 | def _calculate_default_permissions(self): |
|
535 | 575 | """ |
|
536 |
Set default user permissions for repositories, repository |
|
|
537 | taken from the default user. | |
|
576 | Set default user permissions for repositories, repository branches, | |
|
577 | repository groups, user groups taken from the default user. | |
|
538 | 578 | |
|
539 | 579 | Calculate inheritance of object permissions based on what we have now |
|
540 | 580 | in GLOBAL permissions. We check if .false is in GLOBAL since this is |
@@ -551,8 +591,7 b' class PermissionCalculator(object):' | |||
|
551 | 591 | user_inherit_object_permissions = not ('hg.inherit_default_perms.false' |
|
552 | 592 | in self.permissions_global) |
|
553 | 593 | |
|
554 | # defaults for repositories, taken from `default` user permissions | |
|
555 | # on given repo | |
|
594 | # default permissions for repositories, taken from `default` user permissions | |
|
556 | 595 | for perm in self.default_repo_perms: |
|
557 | 596 | r_k = perm.UserRepoToPerm.repository.repo_name |
|
558 | 597 | p = perm.Permission.permission_name |
@@ -585,8 +624,24 b' class PermissionCalculator(object):' | |||
|
585 | 624 | o = PermOrigin.SUPER_ADMIN |
|
586 | 625 | self.permissions_repositories[r_k] = p, o |
|
587 | 626 | |
|
588 |
# defaults for repositor |
|
|
589 | # on given group | |
|
627 | # default permissions branch for repositories, taken from `default` user permissions | |
|
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 | 645 | for perm in self.default_repo_groups_perms: |
|
591 | 646 | rg_k = perm.UserRepoGroupToPerm.group.group_name |
|
592 | 647 | p = perm.Permission.permission_name |
@@ -611,8 +666,7 b' class PermissionCalculator(object):' | |||
|
611 | 666 | o = PermOrigin.SUPER_ADMIN |
|
612 | 667 | self.permissions_repository_groups[rg_k] = p, o |
|
613 | 668 | |
|
614 | # defaults for user groups taken from `default` user permission | |
|
615 | # on given user group | |
|
669 | # default permissions for user groups taken from `default` user permission | |
|
616 | 670 | for perm in self.default_user_group_perms: |
|
617 | 671 | u_k = perm.UserUserGroupToPerm.user_group.users_group_name |
|
618 | 672 | p = perm.Permission.permission_name |
@@ -703,6 +757,49 b' class PermissionCalculator(object):' | |||
|
703 | 757 | o = PermOrigin.SUPER_ADMIN |
|
704 | 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 | 803 | def _calculate_repository_group_permissions(self): |
|
707 | 804 | """ |
|
708 | 805 | Repository group permissions for the current user. |
@@ -845,6 +942,7 b' class PermissionCalculator(object):' | |||
|
845 | 942 | return { |
|
846 | 943 | 'global': self.permissions_global, |
|
847 | 944 | 'repositories': self.permissions_repositories, |
|
945 | 'repository_branches': self.permissions_repository_branches, | |
|
848 | 946 | 'repositories_groups': self.permissions_repository_groups, |
|
849 | 947 | 'user_groups': self.permissions_user_groups, |
|
850 | 948 | } |
@@ -956,6 +1054,9 b' class AuthUser(object):' | |||
|
956 | 1054 | perms['user_groups'] = { |
|
957 | 1055 | k: v for k, v in perms['user_groups'].items() |
|
958 | 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 | 1060 | return perms |
|
960 | 1061 | |
|
961 | 1062 | @LazyProperty |
@@ -1800,7 +1901,6 b' class PermsFunction(object):' | |||
|
1800 | 1901 | def __call__(self, check_location='', user=None): |
|
1801 | 1902 | if not user: |
|
1802 | 1903 | log.debug('Using user attribute from global request') |
|
1803 | # TODO: remove this someday,put as user as attribute here | |
|
1804 | 1904 | request = self._get_request() |
|
1805 | 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 | 761 | def fix_PATH(os_=None): |
|
755 | 762 | """ |
|
756 | 763 | Get current active python path, and append it to PATH variable to fix |
@@ -1913,6 +1913,7 b' class Repository(Base, BaseModel):' | |||
|
1913 | 1913 | for _usr in q.all(): |
|
1914 | 1914 | usr = AttributeDict(_usr.user.get_dict()) |
|
1915 | 1915 | usr.permission = _usr.permission.permission_name |
|
1916 | usr.permission_id = _usr.repo_to_perm_id | |
|
1916 | 1917 | perm_rows.append(usr) |
|
1917 | 1918 | |
|
1918 | 1919 | # filter the perm rows by 'default' first and then sort them by |
@@ -1926,6 +1927,7 b' class Repository(Base, BaseModel):' | |||
|
1926 | 1927 | usr = AttributeDict(self.user.get_dict()) |
|
1927 | 1928 | usr.owner_row = True |
|
1928 | 1929 | usr.permission = _admin_perm |
|
1930 | usr.permission_id = None | |
|
1929 | 1931 | owner_row.append(usr) |
|
1930 | 1932 | |
|
1931 | 1933 | super_admin_rows = [] |
@@ -1938,6 +1940,7 b' class Repository(Base, BaseModel):' | |||
|
1938 | 1940 | usr = AttributeDict(usr.get_dict()) |
|
1939 | 1941 | usr.admin_row = True |
|
1940 | 1942 | usr.permission = _admin_perm |
|
1943 | usr.permission_id = None | |
|
1941 | 1944 | super_admin_rows.append(usr) |
|
1942 | 1945 | |
|
1943 | 1946 | return super_admin_rows + owner_row + perm_rows |
@@ -2694,6 +2697,11 b' class Permission(Base, BaseModel):' | |||
|
2694 | 2697 | ('usergroup.write', _('User group write access')), |
|
2695 | 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 | 2705 | ('hg.repogroup.create.false', _('Repository Group creation disabled')), |
|
2698 | 2706 | ('hg.repogroup.create.true', _('Repository Group creation enabled')), |
|
2699 | 2707 | |
@@ -2723,11 +2731,16 b' class Permission(Base, BaseModel):' | |||
|
2723 | 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 | 2736 | DEFAULT_USER_PERMISSIONS = [ |
|
2737 | # object perms | |
|
2728 | 2738 | 'repository.read', |
|
2729 | 2739 | 'group.read', |
|
2730 | 2740 | 'usergroup.read', |
|
2741 | # branch, for backward compat we need same value as before so forced pushed | |
|
2742 | 'branch.push_force', | |
|
2743 | # global | |
|
2731 | 2744 | 'hg.create.repository', |
|
2732 | 2745 | 'hg.repogroup.create.false', |
|
2733 | 2746 | 'hg.usergroup.create.false', |
@@ -2758,6 +2771,11 b' class Permission(Base, BaseModel):' | |||
|
2758 | 2771 | 'usergroup.write': 3, |
|
2759 | 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 | 2779 | 'hg.repogroup.create.false': 0, |
|
2762 | 2780 | 'hg.repogroup.create.true': 1, |
|
2763 | 2781 | |
@@ -2794,6 +2812,21 b' class Permission(Base, BaseModel):' | |||
|
2794 | 2812 | return q.all() |
|
2795 | 2813 | |
|
2796 | 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 | 2830 | def get_default_repo_perms_from_user_group(cls, user_id, repo_id=None): |
|
2798 | 2831 | q = Session().query(UserGroupRepoToPerm, Repository, Permission)\ |
|
2799 | 2832 | .join( |
@@ -2818,10 +2851,37 b' class Permission(Base, BaseModel):' | |||
|
2818 | 2851 | return q.all() |
|
2819 | 2852 | |
|
2820 | 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 | 2877 | def get_default_group_perms(cls, user_id, repo_group_id=None): |
|
2822 | 2878 | q = Session().query(UserRepoGroupToPerm, RepoGroup, Permission)\ |
|
2823 | .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\ | |
|
2824 | .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\ | |
|
2879 | .join( | |
|
2880 | Permission, | |
|
2881 | UserRepoGroupToPerm.permission_id == Permission.permission_id)\ | |
|
2882 | .join( | |
|
2883 | RepoGroup, | |
|
2884 | UserRepoGroupToPerm.group_id == RepoGroup.group_id)\ | |
|
2825 | 2885 | .filter(UserRepoGroupToPerm.user_id == user_id) |
|
2826 | 2886 | if repo_group_id: |
|
2827 | 2887 | q = q.filter(UserRepoGroupToPerm.group_id == repo_group_id) |
@@ -2910,6 +2970,8 b' class UserRepoToPerm(Base, BaseModel):' | |||
|
2910 | 2970 | repository = relationship('Repository') |
|
2911 | 2971 | permission = relationship('Permission') |
|
2912 | 2972 | |
|
2973 | branch_perm_entry = relationship('UserToRepoBranchPermission', cascade="all, delete, delete-orphan", lazy='joined') | |
|
2974 | ||
|
2913 | 2975 | @classmethod |
|
2914 | 2976 | def create(cls, user, repository, permission): |
|
2915 | 2977 | n = cls() |
@@ -4470,6 +4532,100 b' def set_task_uid(mapper, connection, tar' | |||
|
4470 | 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 | 4629 | class DbMigrateVersion(Base, BaseModel): |
|
4474 | 4630 | __tablename__ = 'db_migrate_version' |
|
4475 | 4631 | __table_args__ = ( |
@@ -504,12 +504,26 b' def ObjectPermissionsForm(localizer, rep' | |||
|
504 | 504 | overwrite_default_repo = v.StringBoolean(if_missing=False) |
|
505 | 505 | overwrite_default_group = v.StringBoolean(if_missing=False) |
|
506 | 506 | overwrite_default_user_group = v.StringBoolean(if_missing=False) |
|
507 | ||
|
507 | 508 | default_repo_perm = v.OneOf(repo_perms_choices) |
|
508 | 509 | default_group_perm = v.OneOf(group_perms_choices) |
|
509 | 510 | default_user_group_perm = v.OneOf(user_group_perms_choices) |
|
511 | ||
|
510 | 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 | 527 | def UserPermissionsForm(localizer, create_choices, create_on_write_choices, |
|
514 | 528 | repo_group_create_choices, user_group_create_choices, |
|
515 | 529 | fork_choices, inherit_default_permissions_choices): |
@@ -31,7 +31,7 b' from sqlalchemy.exc import DatabaseError' | |||
|
31 | 31 | from rhodecode.model import BaseModel |
|
32 | 32 | from rhodecode.model.db import ( |
|
33 | 33 | User, Permission, UserToPerm, UserRepoToPerm, UserRepoGroupToPerm, |
|
34 | UserUserGroupToPerm, UserGroup, UserGroupToPerm) | |
|
34 | UserUserGroupToPerm, UserGroup, UserGroupToPerm, UserToRepoBranchPermission) | |
|
35 | 35 | from rhodecode.lib.utils2 import str2bool, safe_int |
|
36 | 36 | |
|
37 | 37 | log = logging.getLogger(__name__) |
@@ -59,6 +59,9 b' class PermissionModel(BaseModel):' | |||
|
59 | 59 | 'default_repo_perm': None, |
|
60 | 60 | 'default_group_perm': None, |
|
61 | 61 | 'default_user_group_perm': None, |
|
62 | ||
|
63 | # branch | |
|
64 | 'default_branch_perm': None, | |
|
62 | 65 | } |
|
63 | 66 | |
|
64 | 67 | def set_global_permission_choices(self, c_obj, gettext_translator): |
@@ -82,6 +85,12 b' class PermissionModel(BaseModel):' | |||
|
82 | 85 | ('usergroup.write', _('Write'),), |
|
83 | 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 | 94 | c_obj.register_choices = [ |
|
86 | 95 | ('hg.register.none', _('Disabled')), |
|
87 | 96 | ('hg.register.manual_activate', _('Allowed with manual account activation')), |
@@ -133,6 +142,10 b' class PermissionModel(BaseModel):' | |||
|
133 | 142 | if perm.permission.permission_name.startswith('usergroup.'): |
|
134 | 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 | 149 | # creation of objects |
|
137 | 150 | if perm.permission.permission_name.startswith('hg.create.write_on_repogroup'): |
|
138 | 151 | defaults['default_repo_create_on_write' + suffix] = perm.permission.permission_name |
@@ -199,6 +212,9 b' class PermissionModel(BaseModel):' | |||
|
199 | 212 | 'default_repo_perm': 'repository.', |
|
200 | 213 | 'default_group_perm': 'group.', |
|
201 | 214 | 'default_user_group_perm': 'usergroup.', |
|
215 | # branch | |
|
216 | 'default_branch_perm': 'branch.', | |
|
217 | ||
|
202 | 218 | }[field_name] |
|
203 | 219 | for field in keep_fields: |
|
204 | 220 | pat = get_pat(field) |
@@ -236,8 +252,12 b' class PermissionModel(BaseModel):' | |||
|
236 | 252 | _global_perms = self.global_perms.copy() |
|
237 | 253 | if obj_type not in ['user', 'user_group']: |
|
238 | 254 | raise ValueError("obj_type must be on of 'user' or 'user_group'") |
|
239 | if len(_global_perms) != len(Permission.DEFAULT_USER_PERMISSIONS): | |
|
240 | raise Exception('Inconsistent permissions definition') | |
|
255 | global_perms = len(_global_perms) | |
|
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 | 262 | if obj_type == 'user': |
|
243 | 263 | self._clear_user_perms(object.user_id, preserve) |
@@ -337,8 +357,8 b' class PermissionModel(BaseModel):' | |||
|
337 | 357 | |
|
338 | 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 |
|
|
341 | resets the default permissions for that user group | |
|
360 | Creates only missing default permissions for user group, if force is | |
|
361 | set it resets the default permissions for that user group | |
|
342 | 362 | |
|
343 | 363 | :param user_group: |
|
344 | 364 | :param force: |
@@ -366,6 +386,7 b' class PermissionModel(BaseModel):' | |||
|
366 | 386 | 'default_repo_perm', |
|
367 | 387 | 'default_group_perm', |
|
368 | 388 | 'default_user_group_perm', |
|
389 | 'default_branch_perm', | |
|
369 | 390 | |
|
370 | 391 | 'default_repo_group_create', |
|
371 | 392 | 'default_user_group_create', |
@@ -392,6 +413,7 b' class PermissionModel(BaseModel):' | |||
|
392 | 413 | 'default_repo_perm', |
|
393 | 414 | 'default_group_perm', |
|
394 | 415 | 'default_user_group_perm', |
|
416 | 'default_branch_perm', | |
|
395 | 417 | |
|
396 | 418 | 'default_register', |
|
397 | 419 | 'default_password_reset', |
@@ -414,6 +436,7 b' class PermissionModel(BaseModel):' | |||
|
414 | 436 | 'default_repo_perm', |
|
415 | 437 | 'default_group_perm', |
|
416 | 438 | 'default_user_group_perm', |
|
439 | 'default_branch_perm', | |
|
417 | 440 | |
|
418 | 441 | 'default_register', |
|
419 | 442 | 'default_password_reset', |
@@ -440,6 +463,7 b' class PermissionModel(BaseModel):' | |||
|
440 | 463 | 'default_repo_create', |
|
441 | 464 | 'default_fork_create', |
|
442 | 465 | 'default_inherit_default_permissions', |
|
466 | 'default_branch_perm', | |
|
443 | 467 | |
|
444 | 468 | 'default_register', |
|
445 | 469 | 'default_password_reset', |
@@ -477,8 +501,57 b' class PermissionModel(BaseModel):' | |||
|
477 | 501 | .all(): |
|
478 | 502 | g2p.permission = _def |
|
479 | 503 | self.sa.add(g2p) |
|
504 | ||
|
505 | # COMMIT | |
|
480 | 506 | self.sa.commit() |
|
481 | 507 | except (DatabaseError,): |
|
482 | 508 | log.exception('Failed to set default object permissions') |
|
483 | 509 | self.sa.rollback() |
|
484 | 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 | 116 | .label; |
|
117 | 117 | padding-top: 5px; |
|
118 | 118 | } |
|
119 | .label-branch-perm { | |
|
120 | .label; | |
|
121 | width: 20px; | |
|
122 | } | |
|
123 | ||
|
119 | 124 | // Used to position content on the right side of a .label |
|
120 | 125 | .content, |
|
121 | 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 | 152 | .checkboxes, |
|
139 | 153 | .input, |
|
140 | 154 | .select { |
@@ -169,6 +183,9 b'' | |||
|
169 | 183 | } |
|
170 | 184 | |
|
171 | 185 | .input { |
|
186 | .branch-perm { | |
|
187 | width: 80px; | |
|
188 | } | |
|
172 | 189 | .medium { |
|
173 | 190 | width: @fields-input-m; |
|
174 | 191 | } |
@@ -462,7 +462,7 b' ul.auth_plugins {' | |||
|
462 | 462 | |
|
463 | 463 | .radios { |
|
464 | 464 | position: relative; |
|
465 |
width: |
|
|
465 | width: 505px; | |
|
466 | 466 | } |
|
467 | 467 | } |
|
468 | 468 |
@@ -159,3 +159,9 b'' | |||
|
159 | 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 | 109 | &.read { |
|
110 | 110 | &:extend(.tag1); |
|
111 | 111 | } |
|
112 | ||
|
113 | 112 | &.write { |
|
114 | 113 | &:extend(.tag4); |
|
115 | 114 | } |
|
116 | 115 | &.admin { |
|
117 | 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 | 129 | .phase-draft { |
@@ -87,6 +87,7 b' function registerRCRoutes() {' | |||
|
87 | 87 | pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []); |
|
88 | 88 | pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []); |
|
89 | 89 | pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []); |
|
90 | pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []); | |
|
90 | 91 | pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []); |
|
91 | 92 | pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []); |
|
92 | 93 | pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []); |
@@ -233,6 +234,8 b' function registerRCRoutes() {' | |||
|
233 | 234 | pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']); |
|
234 | 235 | pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']); |
|
235 | 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 | 239 | pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']); |
|
237 | 240 | pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']); |
|
238 | 241 | pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']); |
@@ -38,7 +38,7 b' var api;' | |||
|
38 | 38 | { data: {"_": "group_name", |
|
39 | 39 | "sort": "group_name"}, title: "${_('Name')}", className: "td-componentname," , |
|
40 | 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 | 43 | { data: {"_": "group_description", |
|
44 | 44 | "sort": "group_description"}, title: "${_('Description')}", className: "td-description" }, |
@@ -38,6 +38,9 b'' | |||
|
38 | 38 | <li class="${'active' if c.active=='objects' else ''}"> |
|
39 | 39 | <a href="${h.route_path('admin_permissions_object')}">${_('Object')}</a> |
|
40 | 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 | 44 | <li class="${'active' if c.active=='ips' else ''}"> |
|
42 | 45 | <a href="${h.route_path('admin_permissions_ips')}">${_('IP Whitelist')}</a> |
|
43 | 46 | </li> |
@@ -3,7 +3,10 b'' | |||
|
3 | 3 | <h3 class="panel-title">${_('Default Permissions for Repositories, User Groups and Repository Groups.')}</h3> |
|
4 | 4 | </div> |
|
5 | 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 | 10 | </p> |
|
8 | 11 | ${h.secure_form(h.route_path('admin_permissions_object_update'), request=request)} |
|
9 | 12 | <div class="form"> |
@@ -45,7 +48,7 b'' | |||
|
45 | 48 | ${h.select('default_user_group_perm','',c.user_group_perms_choices)} |
|
46 | 49 | ${h.checkbox('overwrite_default_user_group','true')} |
|
47 | 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 |
|
|
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 | 52 | ${_('Overwrite Existing Settings')} |
|
50 | 53 | </span> |
|
51 | 54 | </label> |
@@ -57,7 +57,7 b'' | |||
|
57 | 57 | %if _user.username != h.DEFAULT_USER: |
|
58 | 58 | <span class="btn btn-link btn-danger revoke_perm" |
|
59 | 59 | member="${_user.user_id}" member_type="user"> |
|
60 |
|
|
|
60 | ${_('Revoke')} | |
|
61 | 61 | </span> |
|
62 | 62 | %endif |
|
63 | 63 | </td> |
@@ -92,7 +92,7 b'' | |||
|
92 | 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 | 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 | 94 | <td class="td-componentname"> |
|
95 |
<i class="icon-group" |
|
|
95 | <i class="icon-user-group"></i> | |
|
96 | 96 | %if h.HasPermissionAny('hg.admin')(): |
|
97 | 97 | <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}"> |
|
98 | 98 | ${_user_group.users_group_name} |
@@ -104,17 +104,27 b'' | |||
|
104 | 104 | <td class="td-action"> |
|
105 | 105 | <span class="btn btn-link btn-danger revoke_perm" |
|
106 | 106 | member="${_user_group.users_group_id}" member_type="user_group"> |
|
107 |
|
|
|
107 | ${_('Revoke')} | |
|
108 | 108 | </span> |
|
109 | 109 | </td> |
|
110 | 110 | </tr> |
|
111 | 111 | %endfor |
|
112 | 112 | |
|
113 | 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 | 126 | </table> |
|
115 | <div id="add_perm" class="link"> | |
|
116 | ${_('Add new')} | |
|
117 | </div> | |
|
127 | ||
|
118 | 128 | <div class="fields"> |
|
119 | 129 | <div class="field"> |
|
120 | 130 | <div class="label label-radio"> |
@@ -48,6 +48,9 b'' | |||
|
48 | 48 | <li class="${'active' if c.active=='permissions' else ''}"> |
|
49 | 49 | <a href="${h.route_path('edit_repo_perms', repo_name=c.repo_name)}">${_('Permissions')}</a> |
|
50 | 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 | 54 | <li class="${'active' if c.active=='advanced' else ''}"> |
|
52 | 55 | <a href="${h.route_path('edit_repo_advanced', repo_name=c.repo_name)}">${_('Advanced')}</a> |
|
53 | 56 | </li> |
@@ -67,7 +67,7 b'' | |||
|
67 | 67 | %if _user.username != h.DEFAULT_USER: |
|
68 | 68 | <span class="btn btn-link btn-danger revoke_perm" |
|
69 | 69 | member="${_user.user_id}" member_type="user"> |
|
70 |
|
|
|
70 | ${_('Revoke')} | |
|
71 | 71 | </span> |
|
72 | 72 | %endif |
|
73 | 73 | </td> |
@@ -83,7 +83,7 b'' | |||
|
83 | 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 | 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 | 85 | <td class="td-componentname"> |
|
86 |
<i class="icon-group" |
|
|
86 | <i class="icon-user-group"></i> | |
|
87 | 87 | %if h.HasPermissionAny('hg.admin')(): |
|
88 | 88 | <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}"> |
|
89 | 89 | ${_user_group.users_group_name} |
@@ -95,16 +95,28 b'' | |||
|
95 | 95 | <td class="td-action"> |
|
96 | 96 | <span class="btn btn-link btn-danger revoke_perm" |
|
97 | 97 | member="${_user_group.users_group_id}" member_type="user_group"> |
|
98 |
|
|
|
98 | ${_('Revoke')} | |
|
99 | 99 | </span> |
|
100 | 100 | </td> |
|
101 | 101 | </tr> |
|
102 | 102 | %endfor |
|
103 | 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 | 118 | </table> |
|
105 | <div id="add_perm" class="link"> | |
|
106 | ${_('Add new')} | |
|
107 | </div> | |
|
119 | ||
|
108 | 120 | <div class="buttons"> |
|
109 | 121 | ${h.submit('save',_('Save'),class_="btn btn-primary")} |
|
110 | 122 | ${h.reset('reset',_('Reset'),class_="btn btn-danger")} |
@@ -59,7 +59,7 b'' | |||
|
59 | 59 | %if _user.username != h.DEFAULT_USER: |
|
60 | 60 | <span class="btn btn-link btn-danger revoke_perm" |
|
61 | 61 | member="${_user.user_id}" member_type="user"> |
|
62 |
|
|
|
62 | ${_('Revoke')} | |
|
63 | 63 | </span> |
|
64 | 64 | %endif |
|
65 | 65 | </td> |
@@ -94,7 +94,7 b'' | |||
|
94 | 94 | <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.write')}</td> |
|
95 | 95 | <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.admin')}</td> |
|
96 | 96 | <td class="td-user"> |
|
97 |
<i class="icon-group" |
|
|
97 | <i class="icon-user-group"></i> | |
|
98 | 98 | %if h.HasPermissionAny('hg.admin')(): |
|
99 | 99 | <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}"> |
|
100 | 100 | ${_user_group.users_group_name} |
@@ -106,16 +106,26 b'' | |||
|
106 | 106 | <td class="td-action"> |
|
107 | 107 | <span class="btn btn-link btn-danger revoke_perm" |
|
108 | 108 | member="${_user_group.users_group_id}" member_type="user_group"> |
|
109 |
|
|
|
109 | ${_('Revoke')} | |
|
110 | 110 | </span> |
|
111 | 111 | </td> |
|
112 | 112 | </tr> |
|
113 | 113 | %endfor |
|
114 | 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 | 127 | </table> |
|
116 | <div id="add_perm" class="link"> | |
|
117 | ${_('Add new')} | |
|
118 | </div> | |
|
128 | ||
|
119 | 129 | <div class="buttons"> |
|
120 | 130 | ${h.submit('save',_('Save'),class_="btn btn-primary")} |
|
121 | 131 | ${h.reset('reset',_('Reset'),class_="btn btn-danger")} |
@@ -53,7 +53,7 b' var api;' | |||
|
53 | 53 | { data: {"_": "group_name", |
|
54 | 54 | "sort": "group_name"}, title: "${_('Name')}", className: "td-componentname," , |
|
55 | 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 | 58 | { data: {"_": "group_description", |
|
59 | 59 | "sort": "group_description"}, title: "${_('Description')}", className: "td-description" }, |
@@ -4,11 +4,20 b'' | |||
|
4 | 4 | ## ${p.perms_summary(c.perm_user.permissions)} |
|
5 | 5 | |
|
6 | 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 | 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 | 16 | <div class="panel panel-default"> |
|
10 | <div class="panel-heading"> | |
|
11 | <h3 class="panel-title">${section.replace("_"," ").capitalize()}</h3> | |
|
17 | <div class="panel-heading" id="${section.replace("_","-")}-permissions"> | |
|
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 | 21 | % if side_link: |
|
13 | 22 | <div class="pull-right"> |
|
14 | 23 | <a href="${side_link}">${_('in JSON format')}</a> |
@@ -18,15 +27,24 b'' | |||
|
18 | 27 | <div class="panel-body"> |
|
19 | 28 | <div class="perms_section_head field"> |
|
20 | 29 | <div class="radios"> |
|
21 |
%if section |
|
|
30 | % if section == 'repository_branches': | |
|
22 | 31 | <span class="permissions_boxes"> |
|
23 | 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_ |
|
|
25 |
${h.checkbox('perms_filter_re |
|
|
26 |
${h.checkbox('perms_filter_ |
|
|
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> | |
|
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> | |
|
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> | |
|
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> | |
|
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 | 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 | 48 | </div> |
|
31 | 49 | </div> |
|
32 | 50 | <div class="field"> |
@@ -72,12 +90,10 b'' | |||
|
72 | 90 | %endif |
|
73 | 91 | %else: |
|
74 | 92 | %if not val_lbl: |
|
75 | ${ | |
|
76 | {'false': False, | |
|
93 | ${{'false': False, | |
|
77 | 94 | 'true': True, |
|
78 | 95 | 'none': False, |
|
79 | 'repository': True}.get(val[1][0] if 0 < len(val[1]) else 'false') | |
|
80 | } | |
|
96 | 'repository': True}.get(val[1][0] if 0 < len(val[1]) else 'false')} | |
|
81 | 97 | %else: |
|
82 | 98 | <span class="perm_tag ${val[1][0]}">${val_lbl}.${val[1][0]}</span> |
|
83 | 99 | %endif |
@@ -142,7 +158,72 b'' | |||
|
142 | 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 | 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 | 225 | %else: |
|
226 | ||
|
146 | 227 |
|
|
147 | 228 | <thead> |
|
148 | 229 | <tr> |
@@ -167,8 +248,11 b'' | |||
|
167 | 248 | return sorted(permissions, key=custom_sorter) |
|
168 | 249 | %> |
|
169 | 250 | %for k, section_perm in sorter(permissions[section].items()): |
|
170 |
|
|
|
171 | <tr class="perm_row ${'%s_%s' % (section, section_perm.split('.')[-1])}"> | |
|
251 | <% perm_value = 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 | 256 | <td class="td-name"> |
|
173 | 257 | %if section == 'repositories': |
|
174 | 258 | <a href="${h.route_path('repo_summary',repo_name=k)}">${k}</a> |
@@ -183,7 +267,7 b'' | |||
|
183 | 267 | %if hasattr(permissions[section], 'perm_origin_stack'): |
|
184 | 268 | <div> |
|
185 | 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 | 271 | % if i > 0: |
|
188 | 272 | <div style="color: #979797"> |
|
189 | 273 | <i class="icon-arrow_up"></i> |
@@ -193,7 +277,7 b'' | |||
|
193 | 277 | % endif |
|
194 | 278 | |
|
195 | 279 | <div> |
|
196 |
<span class="${ |
|
|
280 | <span class="${_css_class} perm_tag ${perm.split('.')[-1]}"> | |
|
197 | 281 | ${perm} (${origin}) |
|
198 | 282 | </span> |
|
199 | 283 | </div> |
@@ -220,7 +304,7 b'' | |||
|
220 | 304 | %endfor |
|
221 | 305 | |
|
222 | 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 | 308 | </tr> |
|
225 | 309 | |
|
226 | 310 | </tbody> |
@@ -236,15 +320,16 b'' | |||
|
236 | 320 | |
|
237 | 321 | <script> |
|
238 | 322 | $(document).ready(function(){ |
|
239 |
var show |
|
|
323 | var showEmpty = function(section){ | |
|
240 | 324 | var visible = $('.section_{0} tr.perm_row:visible'.format(section)).length; |
|
241 | if(visible == 0){ | |
|
325 | if(visible === 0){ | |
|
242 | 326 | $('#empty_{0}'.format(section)).show(); |
|
243 | 327 | } |
|
244 | 328 | else{ |
|
245 | 329 | $('#empty_{0}'.format(section)).hide(); |
|
246 | 330 | } |
|
247 | 331 | }; |
|
332 | ||
|
248 | 333 | $('.perm_filter').on('change', function(e){ |
|
249 | 334 | var self = this; |
|
250 | 335 | var section = $(this).attr('section'); |
@@ -261,7 +346,7 b'' | |||
|
261 | 346 | $('.'+section+'_'+perm_type).hide(); |
|
262 | 347 | } |
|
263 | 348 | }); |
|
264 |
show |
|
|
349 | showEmpty(section); | |
|
265 | 350 | }) |
|
266 | 351 | }) |
|
267 | 352 | </script> |
@@ -284,7 +284,7 b'' | |||
|
284 | 284 | |
|
285 | 285 | <%def name="user_group_name(user_group_name)"> |
|
286 | 286 | <div> |
|
287 | <i class="icon-group" title="${_('User group')}"></i> | |
|
287 | <i class="icon-user-group" title="${_('User group')}"></i> | |
|
288 | 288 | ${h.link_to_group(user_group_name)} |
|
289 | 289 | </div> |
|
290 | 290 | </%def> |
@@ -534,7 +534,7 b'' | |||
|
534 | 534 | </tbody> |
|
535 | 535 | </table> |
|
536 | 536 | <div class="link" id="add_perm"> |
|
537 |
Add |
|
|
537 | Add user/user group | |
|
538 | 538 | </div> |
|
539 | 539 | |
|
540 | 540 |
@@ -8,12 +8,11 b'' | |||
|
8 | 8 | <div class="panel-heading">${title}</div> |
|
9 | 9 | <div class="panel-body"> |
|
10 | 10 | |
|
11 | <div tal:condition="errormsg" | |
|
12 | class="clearfix alert alert-danger"> | |
|
13 | <p i18n:translate=""> | |
|
11 | <div tal:condition="errormsg" class="clearfix alert alert-error"> | |
|
12 | <span i18n:translate=""> | |
|
14 | 13 | There was a problem with this section |
|
15 | </p> | |
|
16 |
< |
|
|
14 | </span> | |
|
15 | <div>${errormsg}</div> | |
|
17 | 16 | </div> |
|
18 | 17 | |
|
19 | 18 | <div tal:condition="description"> |
@@ -140,6 +140,10 b' class TestPermissions(object):' | |||
|
140 | 140 | assert repo_perms(user)[repo.repo_name] == 'repository.admin' |
|
141 | 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 | 147 | def test_default_owner_repo_group_perms(self, user_util, test_repo_group): |
|
144 | 148 | user = user_util.create_user() |
|
145 | 149 | org_owner = test_repo_group.user |
@@ -360,13 +364,15 b' class TestPermissions(object):' | |||
|
360 | 364 | user_model.revoke_perm(self.u1, 'hg.fork.repository') |
|
361 | 365 | user_model.grant_perm(self.u1, 'hg.fork.none') |
|
362 | 366 | |
|
367 | # TODO(marcink): check branch permissions now ? | |
|
368 | ||
|
363 | 369 | # make sure inherit flag is turned off |
|
364 | 370 | self.u1.inherit_default_permissions = False |
|
365 | 371 | Session().commit() |
|
366 | 372 | |
|
367 | 373 | # this user will have non inherited permissions from he's |
|
368 | 374 | # explicitly set permissions |
|
369 |
assert global_perms(self.u1) == |
|
|
375 | assert global_perms(self.u1) == { | |
|
370 | 376 | 'hg.create.none', |
|
371 | 377 | 'hg.fork.none', |
|
372 | 378 | 'hg.register.manual_activate', |
@@ -375,7 +381,8 b' class TestPermissions(object):' | |||
|
375 | 381 | 'repository.read', |
|
376 | 382 | 'group.read', |
|
377 | 383 | 'usergroup.read', |
|
378 | ]) | |
|
384 | 'branch.push_force', | |
|
385 | } | |
|
379 | 386 | |
|
380 | 387 | def test_non_inherited_permissions_from_default_on_user_disabled(self): |
|
381 | 388 | user_model = UserModel() |
@@ -396,9 +403,11 b' class TestPermissions(object):' | |||
|
396 | 403 | self.u1.inherit_default_permissions = False |
|
397 | 404 | Session().commit() |
|
398 | 405 | |
|
406 | # TODO(marcink): check branch perms | |
|
407 | ||
|
399 | 408 | # this user will have non inherited permissions from he's |
|
400 | 409 | # explicitly set permissions |
|
401 |
assert global_perms(self.u1) == |
|
|
410 | assert global_perms(self.u1) == { | |
|
402 | 411 | 'hg.create.repository', |
|
403 | 412 | 'hg.fork.repository', |
|
404 | 413 | 'hg.register.manual_activate', |
@@ -407,7 +416,8 b' class TestPermissions(object):' | |||
|
407 | 416 | 'repository.read', |
|
408 | 417 | 'group.read', |
|
409 | 418 | 'usergroup.read', |
|
410 | ]) | |
|
419 | 'branch.push_force', | |
|
420 | } | |
|
411 | 421 | |
|
412 | 422 | @pytest.mark.parametrize('perm, expected_perm', [ |
|
413 | 423 | ('hg.inherit_default_perms.false', 'repository.none', ), |
@@ -425,8 +435,10 b' class TestPermissions(object):' | |||
|
425 | 435 | self.u1.inherit_default_permissions = True |
|
426 | 436 | Session().commit() |
|
427 | 437 | |
|
438 | # TODO(marcink): check branch perms | |
|
439 | ||
|
428 | 440 | # this user will have inherited permissions from default user |
|
429 |
assert global_perms(self.u1) == |
|
|
441 | assert global_perms(self.u1) == { | |
|
430 | 442 | 'hg.create.none', |
|
431 | 443 | 'hg.fork.none', |
|
432 | 444 | 'hg.register.manual_activate', |
@@ -435,11 +447,12 b' class TestPermissions(object):' | |||
|
435 | 447 | 'repository.read', |
|
436 | 448 | 'group.read', |
|
437 | 449 | 'usergroup.read', |
|
450 | 'branch.push_force', | |
|
438 | 451 | 'hg.create.write_on_repogroup.true', |
|
439 | 452 | 'hg.usergroup.create.false', |
|
440 | 453 | 'hg.repogroup.create.false', |
|
441 |
perm |
|
|
442 |
|
|
|
454 | perm | |
|
455 | } | |
|
443 | 456 | |
|
444 | 457 | assert set(repo_perms(self.u1).values()) == set([expected_perm]) |
|
445 | 458 | |
@@ -693,6 +706,11 b' def repo_perms(user):' | |||
|
693 | 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 | 714 | def group_perms(user): |
|
697 | 715 | auth_user = AuthUser(user_id=user.user_id) |
|
698 | 716 | return auth_user.permissions['repositories_groups'] |
@@ -66,5 +66,5 b' class TestTags(BackendTestMixin):' | |||
|
66 | 66 | def test_name_with_slash(self): |
|
67 | 67 | self.repo.tag('19/10/11', 'joe') |
|
68 | 68 | assert '19/10/11' in self.repo.tags |
|
69 | self.repo.tag('11', 'joe') | |
|
70 | assert '11' in self.repo.tags | |
|
69 | self.repo.tag('rel.11', 'joe') | |
|
70 | assert 'rel.11' in self.repo.tags |
General Comments 0
You need to be logged in to leave comments.
Login now