aboutsummaryrefslogtreecommitdiff
path: root/rhodecode
diff options
context:
space:
mode:
authorMarcin Kuzminski <marcin@python-works.com>2012-01-28 01:06:29 +0200
committerMarcin Kuzminski <marcin@python-works.com>2012-01-28 01:06:29 +0200
commitd4e540f70af3cf79b8a13cbcdb6a74b6c6d75af9 (patch)
treed7d612464c0748a61654cfb0574de87c27808e27 /rhodecode
parentc6b3ec29e04bc5494ffdcb58840fc532080d697f (diff)
#227 Initial version of repository groups permissions system
- implemented none/read/write/admin permissions for groups - wrote more tests for permissions, and new permissions groups - a lot of code garden, splitted logic into proper models - permissions on groups doesn't propagate yet to repositories - deprecated some methods on api for managing permissions on repositories for users, and users groups --HG-- branch : beta
Diffstat (limited to 'rhodecode')
-rw-r--r--rhodecode/config/middleware.py3
-rw-r--r--rhodecode/config/routing.py30
-rw-r--r--rhodecode/controllers/admin/repos.py22
-rw-r--r--rhodecode/controllers/admin/repos_groups.py85
-rw-r--r--rhodecode/controllers/api/api.py121
-rw-r--r--rhodecode/controllers/home.py7
-rw-r--r--rhodecode/lib/__init__.py6
-rw-r--r--rhodecode/lib/auth.py89
-rw-r--r--rhodecode/lib/db_manage.py39
-rw-r--r--rhodecode/lib/hooks.py4
-rw-r--r--rhodecode/lib/utils.py41
-rw-r--r--rhodecode/model/__init__.py14
-rwxr-xr-xrhodecode/model/db.py23
-rw-r--r--rhodecode/model/forms.py117
-rw-r--r--rhodecode/model/notification.py5
-rw-r--r--rhodecode/model/repo.py201
-rw-r--r--rhodecode/model/repo_permission.py17
-rw-r--r--rhodecode/model/repos_group.py174
-rw-r--r--rhodecode/model/scm.py47
-rw-r--r--rhodecode/model/user.py157
-rw-r--r--rhodecode/model/users_group.py27
-rw-r--r--rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html270
-rw-r--r--rhodecode/templates/admin/repos_groups/repos_groups_edit.html11
-rw-r--r--rhodecode/templates/index_base.html4
-rw-r--r--rhodecode/tests/test_models.py233
25 files changed, 1374 insertions, 373 deletions
diff --git a/rhodecode/config/middleware.py b/rhodecode/config/middleware.py
index 84b5e88d..3ef59fd7 100644
--- a/rhodecode/config/middleware.py
+++ b/rhodecode/config/middleware.py
@@ -51,8 +51,8 @@ def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
from rhodecode.lib.profiler import ProfilingMiddleware
app = ProfilingMiddleware(app)
-
if asbool(full_stack):
+
# Handle Python exceptions
app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
@@ -80,7 +80,6 @@ def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
app = Cascade([static_app, app])
app = make_gzip_middleware(app, global_conf, compress_level=1)
-
app.config = config
return app
diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py
index 28d2faf1..f0ffaccc 100644
--- a/rhodecode/config/routing.py
+++ b/rhodecode/config/routing.py
@@ -113,8 +113,9 @@ def make_map(config):
function=check_repo))
#ajax delete repo perm user
m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
- action="delete_perm_user", conditions=dict(method=["DELETE"],
- function=check_repo))
+ action="delete_perm_user",
+ conditions=dict(method=["DELETE"], function=check_repo))
+
#ajax delete repo perm users_group
m.connect('delete_repo_users_group',
"/repos_delete_users_group/{repo_name:.*}",
@@ -128,7 +129,7 @@ def make_map(config):
m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
action="repo_cache", conditions=dict(method=["DELETE"],
function=check_repo))
- m.connect('repo_public_journal',"/repos_public_journal/{repo_name:.*}",
+ m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*}",
action="repo_public_journal", conditions=dict(method=["PUT"],
function=check_repo))
m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
@@ -169,6 +170,17 @@ def make_map(config):
m.connect("formatted_repos_group", "/repos_groups/{id}.{format}",
action="show", conditions=dict(method=["GET"],
function=check_int))
+ # ajax delete repos group perm user
+ m.connect('delete_repos_group_user_perm',
+ "/delete_repos_group_user_perm/{group_name:.*}",
+ action="delete_repos_group_user_perm",
+ conditions=dict(method=["DELETE"], function=check_group))
+
+ # ajax delete repos group perm users_group
+ m.connect('delete_repos_group_users_group_perm',
+ "/delete_repos_group_users_group_perm/{group_name:.*}",
+ action="delete_repos_group_users_group_perm",
+ conditions=dict(method=["DELETE"], function=check_group))
#ADMIN USER REST ROUTES
with rmap.submapper(path_prefix=ADMIN_PREFIX,
@@ -310,8 +322,6 @@ def make_map(config):
m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
action="show", conditions=dict(method=["GET"]))
-
-
#ADMIN MAIN PAGES
with rmap.submapper(path_prefix=ADMIN_PREFIX,
controller='admin/admin') as m:
@@ -320,13 +330,12 @@ def make_map(config):
action='add_repo')
#==========================================================================
- # API V1
+ # API V2
#==========================================================================
with rmap.submapper(path_prefix=ADMIN_PREFIX,
controller='api/api') as m:
m.connect('api', '/api')
-
#USER JOURNAL
rmap.connect('journal', '%s/journal' % ADMIN_PREFIX, controller='journal')
@@ -388,11 +397,13 @@ def make_map(config):
controller='changeset', revision='tip',
conditions=dict(function=check_repo))
- rmap.connect('changeset_comment', '/{repo_name:.*}/changeset/{revision}/comment',
+ rmap.connect('changeset_comment',
+ '/{repo_name:.*}/changeset/{revision}/comment',
controller='changeset', revision='tip', action='comment',
conditions=dict(function=check_repo))
- rmap.connect('changeset_comment_delete', '/{repo_name:.*}/changeset/comment/{comment_id}/delete',
+ rmap.connect('changeset_comment_delete',
+ '/{repo_name:.*}/changeset/comment/{comment_id}/delete',
controller='changeset', action='delete_comment',
conditions=dict(function=check_repo, method=["DELETE"]))
@@ -493,5 +504,4 @@ def make_map(config):
controller='followers', action='followers',
conditions=dict(function=check_repo))
-
return rmap
diff --git a/rhodecode/controllers/admin/repos.py b/rhodecode/controllers/admin/repos.py
index c2bcc29c..4e9e7b63 100644
--- a/rhodecode/controllers/admin/repos.py
+++ b/rhodecode/controllers/admin/repos.py
@@ -3,7 +3,7 @@
rhodecode.controllers.admin.repos
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Admin controller for RhodeCode
+ Repositories controller for RhodeCode
:created_on: Apr 7, 2010
:author: marcink
@@ -277,7 +277,6 @@ class ReposController(BaseController):
return redirect(url('repos'))
-
@HasRepoPermissionAllDecorator('repository.admin')
def delete_perm_user(self, repo_name):
"""
@@ -287,10 +286,11 @@ class ReposController(BaseController):
"""
try:
- repo_model = RepoModel()
- repo_model.delete_perm_user(request.POST, repo_name)
+ RepoModel().revoke_user_permission(repo=repo_name,
+ user=request.POST['user_id'])
Session.commit()
- except Exception, e:
+ except Exception:
+ log.error(traceback.format_exc())
h.flash(_('An error occurred during deletion of repository user'),
category='error')
raise HTTPInternalServerError()
@@ -302,11 +302,14 @@ class ReposController(BaseController):
:param repo_name:
"""
+
try:
- repo_model = RepoModel()
- repo_model.delete_perm_users_group(request.POST, repo_name)
+ RepoModel().revoke_users_group_permission(
+ repo=repo_name, group_name=request.POST['users_group_id']
+ )
Session.commit()
- except Exception, e:
+ except Exception:
+ log.error(traceback.format_exc())
h.flash(_('An error occurred during deletion of repository'
' users groups'),
category='error')
@@ -321,8 +324,7 @@ class ReposController(BaseController):
"""
try:
- repo_model = RepoModel()
- repo_model.delete_stats(repo_name)
+ RepoModel().delete_stats(repo_name)
Session.commit()
except Exception, e:
h.flash(_('An error occurred during deletion of repository stats'),
diff --git a/rhodecode/controllers/admin/repos_groups.py b/rhodecode/controllers/admin/repos_groups.py
index 38b870de..abfcc330 100644
--- a/rhodecode/controllers/admin/repos_groups.py
+++ b/rhodecode/controllers/admin/repos_groups.py
@@ -3,7 +3,7 @@
rhodecode.controllers.admin.repos_groups
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- repos groups controller for RhodeCode
+ Repositories groups controller for RhodeCode
:created_on: Mar 23, 2010
:author: marcink
@@ -29,19 +29,22 @@ import formencode
from formencode import htmlfill
-from pylons import request, response, session, tmpl_context as c, url
-from pylons.controllers.util import abort, redirect
+from pylons import request, tmpl_context as c, url
+from pylons.controllers.util import redirect
from pylons.i18n.translation import _
from sqlalchemy.exc import IntegrityError
from rhodecode.lib import helpers as h
-from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator
+from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\
+ HasReposGroupPermissionAnyDecorator
from rhodecode.lib.base import BaseController, render
from rhodecode.model.db import RepoGroup
from rhodecode.model.repos_group import ReposGroupModel
from rhodecode.model.forms import ReposGroupForm
from rhodecode.model.meta import Session
+from rhodecode.model.repo import RepoModel
+from webob.exc import HTTPInternalServerError
log = logging.getLogger(__name__)
@@ -60,6 +63,10 @@ class ReposGroupsController(BaseController):
c.repo_groups = RepoGroup.groups_choices()
c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
+ repo_model = RepoModel()
+ c.users_array = repo_model.get_users_js()
+ c.users_groups_array = repo_model.get_users_groups_js()
+
def __load_data(self, group_id):
"""
Load defaults settings for edit, and update
@@ -74,13 +81,22 @@ class ReposGroupsController(BaseController):
data['group_name'] = repo_group.name
+ # fill repository users
+ for p in repo_group.repo_group_to_perm:
+ data.update({'u_perm_%s' % p.user.username:
+ p.permission.permission_name})
+
+ # fill repository groups
+ for p in repo_group.users_group_to_perm:
+ data.update({'g_perm_%s' % p.users_group.users_group_name:
+ p.permission.permission_name})
+
return data
@HasPermissionAnyDecorator('hg.admin')
def index(self, format='html'):
"""GET /repos_groups: All items in the collection"""
# url('repos_groups')
-
sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
c.groups = sorted(RepoGroup.query().all(), key=sk)
return render('admin/repos_groups/repos_groups_show.html')
@@ -94,7 +110,11 @@ class ReposGroupsController(BaseController):
c.repo_groups_choices)()
try:
form_result = repos_group_form.to_python(dict(request.POST))
- ReposGroupModel().create(form_result)
+ ReposGroupModel().create(
+ group_name=form_result['group_name'],
+ group_description=form_result['group_description'],
+ parent=form_result['group_parent_id']
+ )
Session.commit()
h.flash(_('created repos group %s') \
% form_result['group_name'], category='success')
@@ -134,10 +154,11 @@ class ReposGroupsController(BaseController):
self.__load_defaults()
c.repos_group = RepoGroup.get(id)
- repos_group_form = ReposGroupForm(edit=True,
- old_data=c.repos_group.get_dict(),
- available_groups=
- c.repo_groups_choices)()
+ repos_group_form = ReposGroupForm(
+ edit=True,
+ old_data=c.repos_group.get_dict(),
+ available_groups=c.repo_groups_choices
+ )()
try:
form_result = repos_group_form.to_python(dict(request.POST))
ReposGroupModel().update(id, form_result)
@@ -201,10 +222,52 @@ class ReposGroupsController(BaseController):
return redirect(url('repos_groups'))
+ @HasReposGroupPermissionAnyDecorator('group.admin')
+ def delete_repos_group_user_perm(self, group_name):
+ """
+ DELETE an existing repositories group permission user
+
+ :param group_name:
+ """
+
+ try:
+ ReposGroupModel().revoke_user_permission(
+ repos_group=group_name, user=request.POST['user_id']
+ )
+ Session.commit()
+ except Exception:
+ log.error(traceback.format_exc())
+ h.flash(_('An error occurred during deletion of group user'),
+ category='error')
+ raise HTTPInternalServerError()
+
+ @HasReposGroupPermissionAnyDecorator('group.admin')
+ def delete_repos_group_users_group_perm(self, group_name):
+ """
+ DELETE an existing repositories group permission users group
+
+ :param group_name:
+ """
+
+ try:
+ ReposGroupModel().revoke_users_group_permission(
+ repos_group=group_name,
+ group_name=request.POST['users_group_id']
+ )
+ Session.commit()
+ except Exception:
+ log.error(traceback.format_exc())
+ h.flash(_('An error occurred during deletion of group'
+ ' users groups'),
+ category='error')
+ raise HTTPInternalServerError()
+
def show_by_name(self, group_name):
id_ = RepoGroup.get_by_group_name(group_name).group_id
return self.show(id_)
+ @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
+ 'group.admin')
def show(self, id, format='html'):
"""GET /repos_groups/id: Show a specific item"""
# url('repos_group', id=ID)
@@ -240,7 +303,7 @@ class ReposGroupsController(BaseController):
defaults = self.__load_data(id_)
# we need to exclude this group from the group list for editing
- c.repo_groups = filter(lambda x:x[0] != id_, c.repo_groups)
+ c.repo_groups = filter(lambda x: x[0] != id_, c.repo_groups)
return htmlfill.render(
render('admin/repos_groups/repos_groups_edit.html'),
diff --git a/rhodecode/controllers/api/api.py b/rhodecode/controllers/api/api.py
index 31e5dd45..e4669a89 100644
--- a/rhodecode/controllers/api/api.py
+++ b/rhodecode/controllers/api/api.py
@@ -401,13 +401,7 @@ class ApiController(JSONRPCController):
for g in groups:
group = RepoGroup.get_by_group_name(g)
if not group:
- group = ReposGroupModel().create(
- dict(
- group_name=g,
- group_description='',
- group_parent_id=parent_id
- )
- )
+ group = ReposGroupModel().create(g, '', parent_id)
parent_id = group.group_id
repo = RepoModel().create(
@@ -434,11 +428,11 @@ class ApiController(JSONRPCController):
raise JSONRPCError('failed to create repository %s' % repo_name)
@HasPermissionAnyDecorator('hg.admin')
- def add_user_to_repo(self, apiuser, repo_name, username, perm):
+ def grant_user_permission(self, repo_name, username, perm):
"""
- Add permission for a user to a repository
+ Grant permission for user on given repository, or update existing one
+ if found
- :param apiuser:
:param repo_name:
:param username:
:param perm:
@@ -449,17 +443,15 @@ class ApiController(JSONRPCController):
if repo is None:
raise JSONRPCError('unknown repository %s' % repo)
- try:
- user = User.get_by_username(username)
- except NoResultFound:
- raise JSONRPCError('unknown user %s' % user)
+ user = User.get_by_username(username)
+ if user is None:
+ raise JSONRPCError('unknown user %s' % username)
- RepositoryPermissionModel()\
- .update_or_delete_user_permission(repo, user, perm)
- Session.commit()
+ RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
+ Session.commit()
return dict(
- msg='Added perm: %s for %s in repo: %s' % (
+ msg='Granted perm: %s for user: %s in repo: %s' % (
perm, username, repo_name
)
)
@@ -472,11 +464,45 @@ class ApiController(JSONRPCController):
)
@HasPermissionAnyDecorator('hg.admin')
- def add_users_group_to_repo(self, apiuser, repo_name, group_name, perm):
+ def revoke_user_permission(self, repo_name, username):
"""
- Add permission for a users group to a repository
+ Revoke permission for user on given repository
+
+ :param repo_name:
+ :param username:
+ """
+
+ try:
+ repo = Repository.get_by_repo_name(repo_name)
+ if repo is None:
+ raise JSONRPCError('unknown repository %s' % repo)
+
+ user = User.get_by_username(username)
+ if user is None:
+ raise JSONRPCError('unknown user %s' % username)
+
+ RepoModel().revoke_user_permission(repo=repo_name, user=username)
+
+ Session.commit()
+ return dict(
+ msg='Revoked perm for user: %s in repo: %s' % (
+ username, repo_name
+ )
+ )
+ except Exception:
+ log.error(traceback.format_exc())
+ raise JSONRPCError(
+ 'failed to edit permission %(repo)s for %(user)s' % dict(
+ user=username, repo=repo_name
+ )
+ )
+
+ @HasPermissionAnyDecorator('hg.admin')
+ def grant_users_group_permission(self, repo_name, group_name, perm):
+ """
+ Grant permission for users group on given repository, or update
+ existing one if found
- :param apiuser:
:param repo_name:
:param group_name:
:param perm:
@@ -487,24 +513,59 @@ class ApiController(JSONRPCController):
if repo is None:
raise JSONRPCError('unknown repository %s' % repo)
- try:
- user_group = UsersGroup.get_by_group_name(group_name)
- except NoResultFound:
+ user_group = UsersGroup.get_by_group_name(group_name)
+ if user_group is None:
raise JSONRPCError('unknown users group %s' % user_group)
- RepositoryPermissionModel()\
- .update_or_delete_users_group_permission(repo, user_group,
- perm)
+ RepoModel().grant_users_group_permission(repo=repo_name,
+ group_name=group_name,
+ perm=perm)
+
Session.commit()
return dict(
- msg='Added perm: %s for %s in repo: %s' % (
+ msg='Granted perm: %s for group: %s in repo: %s' % (
perm, group_name, repo_name
)
)
except Exception:
log.error(traceback.format_exc())
raise JSONRPCError(
- 'failed to edit permission %(repo)s for %(usergr)s' % dict(
- usergr=group_name, repo=repo_name
+ 'failed to edit permission %(repo)s for %(usersgr)s' % dict(
+ usersgr=group_name, repo=repo_name
+ )
+ )
+
+ @HasPermissionAnyDecorator('hg.admin')
+ def revoke_users_group_permission(self, repo_name, group_name):
+ """
+ Revoke permission for users group on given repository
+
+ :param repo_name:
+ :param group_name:
+ """
+
+ try:
+ repo = Repository.get_by_repo_name(repo_name)
+ if repo is None:
+ raise JSONRPCError('unknown repository %s' % repo)
+
+ user_group = UsersGroup.get_by_group_name(group_name)
+ if user_group is None:
+ raise JSONRPCError('unknown users group %s' % user_group)
+
+ RepoModel().revoke_users_group_permission(repo=repo_name,
+ group_name=group_name)
+
+ Session.commit()
+ return dict(
+ msg='Revoked perm for group: %s in repo: %s' % (
+ group_name, repo_name
+ )
+ )
+ except Exception:
+ log.error(traceback.format_exc())
+ raise JSONRPCError(
+ 'failed to edit permission %(repo)s for %(usersgr)s' % dict(
+ usersgr=group_name, repo=repo_name
)
)
diff --git a/rhodecode/controllers/home.py b/rhodecode/controllers/home.py
index 9129a89c..77ef18eb 100644
--- a/rhodecode/controllers/home.py
+++ b/rhodecode/controllers/home.py
@@ -30,7 +30,7 @@ from paste.httpexceptions import HTTPBadRequest
from rhodecode.lib.auth import LoginRequired
from rhodecode.lib.base import BaseController, render
-from rhodecode.model.db import RepoGroup, Repository
+from rhodecode.model.db import Repository
log = logging.getLogger(__name__)
@@ -42,11 +42,8 @@ class HomeController(BaseController):
super(HomeController, self).__before__()
def index(self):
-
c.repos_list = self.scm_model.get_repos()
-
- c.groups = RepoGroup.query()\
- .filter(RepoGroup.group_parent_id == None).all()
+ c.groups = self.scm_model.get_repos_groups()
return render('/index.html')
diff --git a/rhodecode/lib/__init__.py b/rhodecode/lib/__init__.py
index 9a194782..2e2b05c5 100644
--- a/rhodecode/lib/__init__.py
+++ b/rhodecode/lib/__init__.py
@@ -25,6 +25,8 @@
import os
import re
+from vcs.utils.lazy import LazyProperty
+
def __get_lem():
from pygments import lexers
@@ -213,6 +215,7 @@ def safe_unicode(str_, from_encoding='utf8'):
except (ImportError, UnicodeDecodeError, Exception):
return unicode(str_, from_encoding, 'replace')
+
def safe_str(unicode_, to_encoding='utf8'):
"""
safe str function. Does few trick to turn unicode_ into string
@@ -250,7 +253,6 @@ def safe_str(unicode_, to_encoding='utf8'):
return safe_str
-
def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
"""
Custom engine_from_config functions that makes sure we use NullPool for
@@ -393,6 +395,7 @@ def credentials_filter(uri):
return ''.join(uri)
+
def get_changeset_safe(repo, rev):
"""
Safe version of get_changeset if this changeset doesn't exists for a
@@ -437,6 +440,7 @@ def get_current_revision(quiet=False):
"was: %s" % err)
return None
+
def extract_mentioned_users(s):
"""
Returns unique usernames from given string s that have @mention
diff --git a/rhodecode/lib/auth.py b/rhodecode/lib/auth.py
index 21b457b2..7cd402c9 100644
--- a/rhodecode/lib/auth.py
+++ b/rhodecode/lib/auth.py
@@ -31,7 +31,7 @@ import hashlib
from tempfile import _RandomNameSequence
from decorator import decorator
-from pylons import config, session, url, request
+from pylons import config, url, request
from pylons.controllers.util import abort, redirect
from pylons.i18n.translation import _
@@ -45,7 +45,7 @@ if __platform__ in PLATFORM_OTHERS:
from rhodecode.lib import str2bool, safe_unicode
from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
-from rhodecode.lib.utils import get_repo_slug
+from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug
from rhodecode.lib.auth_ldap import AuthLdap
from rhodecode.model import meta
@@ -80,8 +80,8 @@ class PasswordGenerator(object):
def __init__(self, passwd=''):
self.passwd = passwd
- def gen_password(self, len, type):
- self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
+ def gen_password(self, length, type_):
+ self.passwd = ''.join([random.choice(type_) for _ in xrange(length)])
return self.passwd
@@ -575,6 +575,41 @@ class HasRepoPermissionAnyDecorator(PermsDecorator):
return False
+class HasReposGroupPermissionAllDecorator(PermsDecorator):
+ """
+ Checks for access permission for all given predicates for specific
+ repository. All of them have to be meet in order to fulfill the request
+ """
+
+ def check_permissions(self):
+ group_name = get_repos_group_slug(request)
+ try:
+ user_perms = set([self.user_perms['repositories_groups'][group_name]])
+ except KeyError:
+ return False
+ if self.required_perms.issubset(user_perms):
+ return True
+ return False
+
+
+class HasReposGroupPermissionAnyDecorator(PermsDecorator):
+ """
+ Checks for access permission for any of given predicates for specific
+ repository. In order to fulfill the request any of predicates must be meet
+ """
+
+ def check_permissions(self):
+ group_name = get_repos_group_slug(request)
+
+ try:
+ user_perms = set([self.user_perms['repositories_groups'][group_name]])
+ except KeyError:
+ return False
+ if self.required_perms.intersection(user_perms):
+ return True
+ return False
+
+
#==============================================================================
# CHECK FUNCTIONS
#==============================================================================
@@ -641,8 +676,9 @@ class HasRepoPermissionAll(PermsFunction):
self.repo_name = get_repo_slug(request)
try:
- self.user_perms = set([self.user_perms['reposit'
- 'ories'][self.repo_name]])
+ self.user_perms = set(
+ [self.user_perms['repositories'][self.repo_name]]
+ )
except KeyError:
return False
self.granted_for = self.repo_name
@@ -662,8 +698,9 @@ class HasRepoPermissionAny(PermsFunction):
self.repo_name = get_repo_slug(request)
try:
- self.user_perms = set([self.user_perms['reposi'
- 'tories'][self.repo_name]])
+ self.user_perms = set(
+ [self.user_perms['repositories'][self.repo_name]]
+ )
except KeyError:
return False
self.granted_for = self.repo_name
@@ -672,6 +709,42 @@ class HasRepoPermissionAny(PermsFunction):
return False
+class HasReposGroupPermissionAny(PermsFunction):
+ def __call__(self, group_name=None, check_Location=''):
+ self.group_name = group_name
+ return super(HasReposGroupPermissionAny, self).__call__(check_Location)
+
+ def check_permissions(self):
+ try:
+ self.user_perms = set(
+ [self.user_perms['repositories_groups'][self.group_name]]
+ )
+ except KeyError:
+ return False
+ self.granted_for = self.repo_name
+ if self.required_perms.intersection(self.user_perms):
+ return True
+ return False
+
+
+class HasReposGroupPermissionAll(PermsFunction):
+ def __call__(self, group_name=None, check_Location=''):
+ self.group_name = group_name
+ return super(HasReposGroupPermissionAny, self).__call__(check_Location)
+
+ def check_permissions(self):
+ try:
+ self.user_perms = set(
+ [self.user_perms['repositories_groups'][self.group_name]]
+ )
+ except KeyError:
+ return False
+ self.granted_for = self.repo_name
+ if self.required_perms.issubset(self.user_perms):
+ return True
+ return False
+
+
#==============================================================================
# SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
#==============================================================================
diff --git a/rhodecode/lib/db_manage.py b/rhodecode/lib/db_manage.py
index 4dbd390b..fc4ed3c5 100644
--- a/rhodecode/lib/db_manage.py
+++ b/rhodecode/lib/db_manage.py
@@ -442,23 +442,28 @@ class DbManage(object):
def create_permissions(self):
# module.(access|create|change|delete)_[name]
- # module.(read|write|owner)
- perms = [('repository.none', 'Repository no access'),
- ('repository.read', 'Repository read access'),
- ('repository.write', 'Repository write access'),
- ('repository.admin', 'Repository admin access'),
- ('hg.admin', 'Hg Administrator'),
- ('hg.create.repository', 'Repository create'),
- ('hg.create.none', 'Repository creation disabled'),
- ('hg.register.none', 'Register disabled'),
- ('hg.register.manual_activate', 'Register new user with '
- 'RhodeCode without manual'
- 'activation'),
-
- ('hg.register.auto_activate', 'Register new user with '
- 'RhodeCode without auto '
- 'activation'),
- ]
+ # module.(none|read|write|admin)
+ perms = [
+ ('repository.none', 'Repository no access'),
+ ('repository.read', 'Repository read access'),
+ ('repository.write', 'Repository write access'),
+ ('repository.admin', 'Repository admin access'),
+
+ ('group.none', 'Repositories Group no access'),
+ ('group.read', 'Repositories Group read access'),
+ ('group.write', 'Repositories Group write access'),
+ ('group.admin', 'Repositories Group admin access'),
+
+ ('hg.admin', 'Hg Administrator'),
+ ('hg.create.repository', 'Repository create'),
+ ('hg.create.none', 'Repository creation disabled'),
+ ('hg.register.none', 'Register disabled'),
+ ('hg.register.manual_activate', 'Register new user with RhodeCode '
+ 'without manual activation'),
+
+ ('hg.register.auto_activate', 'Register new user with RhodeCode '
+ 'without auto activation'),
+ ]
for p in perms:
new_perm = Permission()
diff --git a/rhodecode/lib/hooks.py b/rhodecode/lib/hooks.py
index ed327c0c..04126d24 100644
--- a/rhodecode/lib/hooks.py
+++ b/rhodecode/lib/hooks.py
@@ -130,7 +130,7 @@ def log_create_repository(repository_dict, created_by, **kwargs):
Post create repository Hook. This is a dummy function for admins to re-use
if needed
- :param repository: dict dump of repository object
+ :param repository: dict dump of repository object
:param created_by: username who created repository
:param created_date: date of creation
@@ -152,4 +152,4 @@ def log_create_repository(repository_dict, created_by, **kwargs):
"""
- return 0 \ No newline at end of file
+ return 0
diff --git a/rhodecode/lib/utils.py b/rhodecode/lib/utils.py
index aeb3b49b..468a2786 100644
--- a/rhodecode/lib/utils.py
+++ b/rhodecode/lib/utils.py
@@ -52,6 +52,7 @@ from rhodecode.model import meta
from rhodecode.model.db import Repository, User, RhodeCodeUi, \
UserLog, RepoGroup, RhodeCodeSetting
from rhodecode.model.meta import Session
+from rhodecode.model.repos_group import ReposGroupModel
log = logging.getLogger(__name__)
@@ -94,6 +95,10 @@ def get_repo_slug(request):
return request.environ['pylons.routes_dict'].get('repo_name')
+def get_repos_group_slug(request):
+ return request.environ['pylons.routes_dict'].get('group_name')
+
+
def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
"""
Action logger for various actions made by users
@@ -197,6 +202,7 @@ def is_valid_repo(repo_name, base_path):
except VCSError:
return False
+
def is_valid_repos_group(repos_group_name, base_path):
"""
Returns True if given path is a repos group False otherwise
@@ -216,6 +222,7 @@ def is_valid_repos_group(repos_group_name, base_path):
return False
+
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
while True:
ok = raw_input(prompt)
@@ -317,7 +324,8 @@ class EmptyChangeset(BaseChangeset):
an EmptyChangeset
"""
- def __init__(self, cs='0' * 40, repo=None, requested_revision=None, alias=None):
+ def __init__(self, cs='0' * 40, repo=None, requested_revision=None,
+ alias=None):
self._empty_cs = cs
self.revision = -1
self.message = ''
@@ -368,14 +376,23 @@ def map_groups(groups):
# last element is repo in nested groups structure
groups = groups[:-1]
-
+ rgm = ReposGroupModel(sa)
for lvl, group_name in enumerate(groups):
+ log.debug('creating group level: %s group_name: %s' % (lvl, group_name))
group_name = '/'.join(groups[:lvl] + [group_name])
- group = sa.query(RepoGroup).filter(RepoGroup.group_name == group_name).scalar()
+ group = RepoGroup.get_by_group_name(group_name)
+ desc = '%s group' % group_name
+
+# # WTF that doesn't work !?
+# if group is None:
+# group = rgm.create(group_name, desc, parent, just_db=True)
+# sa.commit()
if group is None:
group = RepoGroup(group_name, parent)
+ group.group_description = desc
sa.add(group)
+ rgm._create_default_perms(group)
sa.commit()
parent = group
return group
@@ -404,15 +421,14 @@ def repo2db_mapper(initial_repo_list, remove_obsolete=False):
log.info('repository %s not found creating default' % name)
added.append(name)
form_data = {
- 'repo_name': name,
- 'repo_name_full': name,
- 'repo_type': repo.alias,
- 'description': repo.description \
- if repo.description != 'unknown' else \
- '%s repository' % name,
- 'private': False,
- 'group_id': getattr(group, 'group_id', None)
- }
+ 'repo_name': name,
+ 'repo_name_full': name,
+ 'repo_type': repo.alias,
+ 'description': repo.description \
+ if repo.description != 'unknown' else '%s repository' % name,
+ 'private': False,
+ 'group_id': getattr(group, 'group_id', None)
+ }
rm.create(form_data, user, just_db=True)
sa.commit()
removed = []
@@ -426,6 +442,7 @@ def repo2db_mapper(initial_repo_list, remove_obsolete=False):
return added, removed
+
# set cache regions for beaker so celery can utilise it
def add_cache(settings):
cache_settings = {'regions': None}
diff --git a/rhodecode/model/__init__.py b/rhodecode/model/__init__.py
index 5c435a2b..b11325d2 100644
--- a/rhodecode/model/__init__.py
+++ b/rhodecode/model/__init__.py
@@ -74,12 +74,13 @@ class BaseModel(object):
else:
self.sa = meta.Session
- def _get_instance(self, cls, instance):
+ def _get_instance(self, cls, instance, callback=None):
"""
- Get's instance of given cls using some simple lookup mechanism
+ Get's instance of given cls using some simple lookup mechanism.
:param cls: class to fetch
:param instance: int or Instance
+ :param callback: callback to call if all lookups failed
"""
if isinstance(instance, cls):
@@ -88,5 +89,10 @@ class BaseModel(object):
return cls.get(instance)
else:
if instance:
- raise Exception('given object must be int or Instance'
- ' of %s got %s' % (type(cls), type(instance)))
+ if callback is None:
+ raise Exception(
+ 'given object must be int or Instance of %s got %s, '
+ 'no callback provided' % (cls, type(instance))
+ )
+ else:
+ return callback(instance)
diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py
index d5165d45..31829f45 100755
--- a/rhodecode/model/db.py
+++ b/rhodecode/model/db.py
@@ -717,6 +717,9 @@ class RepoGroup(Base, BaseModel):
group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+ repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
+ users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
+
parent_group = relationship('RepoGroup', remote_side=group_id)
def __init__(self, group_name='', parent_group=None):
@@ -833,8 +836,9 @@ class Permission(Base, BaseModel):
permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
def __repr__(self):
- return "<%s('%s:%s')>" % (self.__class__.__name__,
- self.permission_id, self.permission_name)
+ return "<%s('%s:%s')>" % (
+ self.__class__.__name__, self.permission_id, self.permission_name
+ )
@classmethod
def get_by_key(cls, key):
@@ -843,9 +847,18 @@ class Permission(Base, BaseModel):
@classmethod
def get_default_perms(cls, default_user_id):
q = Session.query(UserRepoToPerm, Repository, cls)\
- .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
- .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
- .filter(UserRepoToPerm.user_id == default_user_id)
+ .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
+ .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+ .filter(UserRepoToPerm.user_id == default_user_id)
+
+ return q.all()
+
+ @classmethod
+ def get_default_group_perms(cls, default_user_id):
+ q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
+ .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
+ .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+ .filter(UserRepoGroupToPerm.user_id == default_user_id)
return q.all()
diff --git a/rhodecode/model/forms.py b/rhodecode/model/forms.py
index 528936fe..b2379e6a 100644
--- a/rhodecode/model/forms.py
+++ b/rhodecode/model/forms.py
@@ -388,57 +388,66 @@ def ValidForkType(old_data):
return _ValidForkType
-class ValidPerms(formencode.validators.FancyValidator):
- messages = {'perm_new_member_name': _('This username or users group name'
- ' is not valid')}
+def ValidPerms(type_='repo'):
+ if type_ == 'group':
+ EMPTY_PERM = 'group.none'
+ elif type_ == 'repo':
+ EMPTY_PERM = 'repository.none'
+
+ class _ValidPerms(formencode.validators.FancyValidator):
+ messages = {
+ 'perm_new_member_name':
+ _('This username or users group name is not valid')
+ }
- def to_python(self, value, state):
- perms_update = []
- perms_new = []
- #build a list of permission to update and new permission to create
- for k, v in value.items():
- #means new added member to permissions
- if k.startswith('perm_new_member'):
- new_perm = value.get('perm_new_member', False)
- new_member = value.get('perm_new_member_name', False)
- new_type = value.get('perm_new_member_type')
-
- if new_member and new_perm:
- if (new_member, new_perm, new_type) not in perms_new:
- perms_new.append((new_member, new_perm, new_type))
- elif k.startswith('u_perm_') or k.startswith('g_perm_'):
- member = k[7:]
- t = {'u': 'user',
- 'g': 'users_group'
- }[k[0]]
- if member == 'default':
- if value['private']:
- #set none for default when updating to private repo
- v = 'repository.none'
- perms_update.append((member, v, t))
-
- value['perms_updates'] = perms_update
- value['perms_new'] = perms_new
-
- #update permissions
- for k, v, t in perms_new:
- try:
- if t is 'user':
- self.user_db = User.query()\
- .filter(User.active == True)\
- .filter(User.username == k).one()
- if t is 'users_group':
- self.user_db = UsersGroup.query()\
- .filter(UsersGroup.users_group_active == True)\
- .filter(UsersGroup.users_group_name == k).one()
-
- except Exception:
- msg = self.message('perm_new_member_name',
- state=State_obj)
- raise formencode.Invalid(
- msg, value, state, error_dict={'perm_new_member_name': msg}
- )
- return value
+ def to_python(self, value, state):
+ perms_update = []
+ perms_new = []
+ # build a list of permission to update and new permission to create
+ for k, v in value.items():
+ # means new added member to permissions
+ if k.startswith('perm_new_member'):
+ new_perm = value.get('perm_new_member', False)
+ new_member = value.get('perm_new_member_name', False)
+ new_type = value.get('perm_new_member_type')
+
+ if new_member and new_perm:
+ if (new_member, new_perm, new_type) not in perms_new:
+ perms_new.append((new_member, new_perm, new_type))
+ elif k.startswith('u_perm_') or k.startswith('g_perm_'):
+ member = k[7:]
+ t = {'u': 'user',
+ 'g': 'users_group'
+ }[k[0]]
+ if member == 'default':
+ if value.get('private'):
+ # set none for default when updating to private repo
+ v = EMPTY_PERM
+ perms_update.append((member, v, t))
+
+ value['perms_updates'] = perms_update
+ value['perms_new'] = perms_new
+
+ # update permissions
+ for k, v, t in perms_new:
+ try:
+ if t is 'user':
+ self.user_db = User.query()\
+ .filter(User.active == True)\
+ .filter(User.username == k).one()
+ if t is 'users_group':
+ self.user_db = UsersGroup.query()\
+ .filter(UsersGroup.users_group_active == True)\
+ .filter(UsersGroup.users_group_name == k).one()
+
+ except Exception:
+ msg = self.message('perm_new_member_name',
+ state=State_obj)
+ raise formencode.Invalid(
+ msg, value, state, error_dict={'perm_new_member_name': msg}
+ )
+ return value
+ return _ValidPerms
class ValidSettings(formencode.validators.FancyValidator):
@@ -588,7 +597,7 @@ def UsersGroupForm(edit=False, old_data={}, available_members=[]):
def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
class _ReposGroupForm(formencode.Schema):
allow_extra_fields = True
- filter_extra_fields = True
+ filter_extra_fields = False
group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
SlugifyName())
@@ -598,7 +607,7 @@ def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
testValueList=True,
if_missing=None, not_empty=False)
- chained_validators = [ValidReposGroup(edit, old_data)]
+ chained_validators = [ValidReposGroup(edit, old_data), ValidPerms('group')]
return _ReposGroupForm
@@ -649,7 +658,7 @@ def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
#this is repo owner
user = All(UnicodeString(not_empty=True), ValidRepoUser)
- chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
+ chained_validators = [ValidRepoName(edit, old_data), ValidPerms()]
return _RepoForm
@@ -683,7 +692,7 @@ def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()
repo_group = OneOf(repo_groups, hideList=True)
private = StringBoolean(if_missing=False)
- chained_validators = [ValidRepoName(edit, old_data), ValidPerms,
+ chained_validators = [ValidRepoName(edit, old_data), ValidPerms(),
ValidSettings]
return _RepoForm
diff --git a/rhodecode/model/notification.py b/rhodecode/model/notification.py
index bb2f950a..dc5617e3 100644
--- a/rhodecode/model/notification.py
+++ b/rhodecode/model/notification.py
@@ -42,10 +42,7 @@ log = logging.getLogger(__name__)
class NotificationModel(BaseModel):
def __get_user(self, user):
- if isinstance(user, basestring):
- return User.get_by_username(username=user)
- else:
- return self._get_instance(User, user)
+ return self._get_instance(User, user, callback=User.get_by_username)
def __get_notification(self, notification):
if isinstance(notification, Notification):
diff --git a/rhodecode/model/repo.py b/rhodecode/model/repo.py
index 6650de01..99ac4788 100644
--- a/rhodecode/model/repo.py
+++ b/rhodecode/model/repo.py
@@ -28,9 +28,9 @@ import logging
import traceback
from datetime import datetime
-from vcs.utils.lazy import LazyProperty
from vcs.backends import get_backend
+from rhodecode.lib import LazyProperty
from rhodecode.lib import safe_str, safe_unicode
from rhodecode.lib.caching_query import FromCache
from rhodecode.lib.hooks import log_create_repository
@@ -39,11 +39,31 @@ from rhodecode.model import BaseModel
from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
+
log = logging.getLogger(__name__)
class RepoModel(BaseModel):
+ def __get_user(self, user):
+ return self._get_instance(User, user, callback=User.get_by_username)
+
+ def __get_users_group(self, users_group):
+ return self._get_instance(UsersGroup, users_group,
+ callback=UsersGroup.get_by_group_name)
+
+ def __get_repos_group(self, repos_group):
+ return self._get_instance(RepoGroup, repos_group,
+ callback=RepoGroup.get_by_group_name)
+
+ def __get_repo(self, repository):
+ return self._get_instance(Repository, repository,
+ callback=Repository.get_by_repo_name)
+
+ def __get_perm(self, permission):
+ return self._get_instance(Permission, permission,
+ callback=Permission.get_by_key)
+
@LazyProperty
def repos_path(self):
"""
@@ -138,49 +158,24 @@ class RepoModel(BaseModel):
# update permissions
for member, perm, member_type in form_data['perms_updates']:
if member_type == 'user':
- _member = User.get_by_username(member)
- r2p = self.sa.query(UserRepoToPerm)\
- .filter(UserRepoToPerm.user == _member)\
- .filter(UserRepoToPerm.repository == cur_repo)\
- .one()
-
- r2p.permission = self.sa.query(Permission)\
- .filter(Permission.permission_name ==
- perm).scalar()
- self.sa.add(r2p)
+ # this updates existing one
+ RepoModel().grant_user_permission(
+ repo=cur_repo, user=member, perm=perm
+ )
else:
- g2p = self.sa.query(UsersGroupRepoToPerm)\
- .filter(UsersGroupRepoToPerm.users_group ==
- UsersGroup.get_by_group_name(member))\
- .filter(UsersGroupRepoToPerm.repository ==
- cur_repo).one()
-
- g2p.permission = self.sa.query(Permission)\
- .filter(Permission.permission_name ==
- perm).scalar()
- self.sa.add(g2p)
-
+ RepoModel().grant_users_group_permission(
+ repo=cur_repo, group_name=member, perm=perm
+ )
# set new permissions
for member, perm, member_type in form_data['perms_new']:
if member_type == 'user':
- r2p = UserRepoToPerm()
- r2p.repository = cur_repo
- r2p.user = User.get_by_username(member)
-
- r2p.permission = self.sa.query(Permission)\
- .filter(Permission.
- permission_name == perm)\
- .scalar()
- self.sa.add(r2p)
+ RepoModel().grant_user_permission(
+ repo=cur_repo, user=member, perm=perm
+ )
else:
- g2p = UsersGroupRepoToPerm()
- g2p.repository = cur_repo
- g2p.users_group = UsersGroup.get_by_group_name(member)
- g2p.permission = self.sa.query(Permission)\
- .filter(Permission.
- permission_name == perm)\
- .scalar()
- self.sa.add(g2p)
+ RepoModel().grant_users_group_permission(
+ repo=cur_repo, group_name=member, perm=perm
+ )
# update current repo
for k, v in form_data.items():
@@ -314,28 +309,93 @@ class RepoModel(BaseModel):
log.error(traceback.format_exc())
raise
- def delete_perm_user(self, form_data, repo_name):
- try:
- obj = self.sa.query(UserRepoToPerm)\
- .filter(UserRepoToPerm.repository \
- == self.get_by_repo_name(repo_name))\
- .filter(UserRepoToPerm.user_id == form_data['user_id']).one()
- self.sa.delete(obj)
- except:
- log.error(traceback.format_exc())
- raise
+ def grant_user_permission(self, repo, user, perm):
+ """
+ Grant permission for user on given repository, or update existing one
+ if found
- def delete_perm_users_group(self, form_data, repo_name):
- try:
- obj = self.sa.query(UsersGroupRepoToPerm)\
- .filter(UsersGroupRepoToPerm.repository \
- == self.get_by_repo_name(repo_name))\
- .filter(UsersGroupRepoToPerm.users_group_id
- == form_data['users_group_id']).one()
- self.sa.delete(obj)
- except:
- log.error(traceback.format_exc())
- raise
+ :param repo: Instance of Repository, repository_id, or repository name
+ :param user: Instance of User, user_id or username
+ :param perm: Instance of Permission, or permission_name
+ """
+ user = self.__get_user(user)
+ repo = self.__get_repo(repo)
+ permission = self.__get_perm(perm)
+
+ # check if we have that permission already
+ obj = self.sa.query(UserRepoToPerm)\
+ .filter(UserRepoToPerm.user == user)\
+ .filter(UserRepoToPerm.repository == repo)\
+ .scalar()
+ if obj is None:
+ # create new !
+ obj = UserRepoToPerm()
+ obj.repository = repo
+ obj.user = user
+ obj.permission = permission
+ self.sa.add(obj)
+
+ def revoke_user_permission(self, repo, user):
+ """
+ Revoke permission for user on given repository
+
+ :param repo: Instance of Repository, repository_id, or repository name
+ :param user: Instance of User, user_id or username
+ """
+ user = self.__get_user(user)
+ repo = self.__get_repo(repo)
+
+ obj = self.sa.query(UserRepoToPerm)\
+ .filter(UserRepoToPerm.repository == repo)\
+ .filter(UserRepoToPerm.user == user)\
+ .one()
+ self.sa.delete(obj)
+
+ def grant_users_group_permission(self, repo, group_name, perm):
+ """
+ Grant permission for users group on given repository, or update
+ existing one if found
+
+ :param repo: Instance of Repository, repository_id, or repository name
+ :param group_name: Instance of UserGroup, users_group_id,
+ or users group name
+ :param perm: Instance of Permission, or permission_name
+ """
+ repo = self.__get_repo(repo)
+ group_name = self.__get_users_group(group_name)
+ permission = self.__get_perm(perm)
+
+ # check if we have that permission already
+ obj = self.sa.query(UsersGroupRepoToPerm)\
+ .filter(UsersGroupRepoToPerm.users_group == group_name)\
+ .filter(UsersGroupRepoToPerm.repository == repo)\
+ .scalar()
+
+ if obj is None:
+ # create new
+ obj = UsersGroupRepoToPerm()
+
+ obj.repository = repo
+ obj.users_group = group_name
+ obj.permission = permission
+ self.sa.add(obj)
+
+ def revoke_users_group_permission(self, repo, group_name):
+ """
+ Revoke permission for users group on given repository
+
+ :param repo: Instance of Repository, repository_id, or repository name
+ :param group_name: Instance of UserGroup, users_group_id,
+ or users group name
+ """
+ repo = self.__get_repo(repo)
+ group_name = self.__get_users_group(group_name)
+
+ obj = self.sa.query(UsersGroupRepoToPerm)\
+ .filter(UsersGroupRepoToPerm.repository == repo)\
+ .filter(UsersGroupRepoToPerm.users_group == group_name)\
+ .one()
+ self.sa.delete(obj)
def delete_stats(self, repo_name):
"""
@@ -345,8 +405,9 @@ class RepoModel(BaseModel):
"""
try:
obj = self.sa.query(Statistics)\
- .filter(Statistics.repository == \
- self.get_by_repo_name(repo_name)).one()
+ .filter(Statistics.repository ==
+ self.get_by_repo_name(repo_name))\
+ .one()
self.sa.delete(obj)
except:
log.error(traceback.format_exc())
@@ -373,10 +434,9 @@ class RepoModel(BaseModel):
new_parent_path = ''
# we need to make it str for mercurial
- repo_path = os.path.join(*map(lambda x:safe_str(x),
+ repo_path = os.path.join(*map(lambda x: safe_str(x),
[self.repos_path, new_parent_path, repo_name]))
-
# check if this path is not a repository
if is_valid_repo(repo_path, self.repos_path):
raise Exception('This path %s is a valid repository' % repo_path)
@@ -393,7 +453,6 @@ class RepoModel(BaseModel):
backend(repo_path, create=True, src_url=clone_uri)
-
def __rename_repo(self, old, new):
"""
renames repository on filesystem
@@ -406,8 +465,9 @@ class RepoModel(BaseModel):
old_path = os.path.join(self.repos_path, old)
new_path = os.path.join(self.repos_path, new)
if os.path.isdir(new_path):
- raise Exception('Was trying to rename to already existing dir %s' \
- % new_path)
+ raise Exception(
+ 'Was trying to rename to already existing dir %s' % new_path
+ )
shutil.move(old_path, new_path)
def __delete_repo(self, repo):
@@ -426,7 +486,6 @@ class RepoModel(BaseModel):
shutil.move(os.path.join(rm_path, '.%s' % alias),
os.path.join(rm_path, 'rm__.%s' % alias))
# disable repo
- shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \
- % (datetime.today()\
- .strftime('%Y%m%d_%H%M%S_%f'),
- repo.repo_name)))
+ _d = 'rm__%s__%s' % (datetime.now().strftime('%Y%m%d_%H%M%S_%f'),
+ repo.repo_name)
+ shutil.move(rm_path, os.path.join(self.repos_path, _d))
diff --git a/rhodecode/model/repo_permission.py b/rhodecode/model/repo_permission.py
index 7a9cc8e2..0f19ef56 100644
--- a/rhodecode/model/repo_permission.py
+++ b/rhodecode/model/repo_permission.py
@@ -26,14 +26,29 @@
import logging
from rhodecode.model import BaseModel
-from rhodecode.model.db import UserRepoToPerm, UsersGroupRepoToPerm, Permission
+from rhodecode.model.db import UserRepoToPerm, UsersGroupRepoToPerm, Permission,\
+ User, Repository
log = logging.getLogger(__name__)
class RepositoryPermissionModel(BaseModel):
+ def __get_user(self, user):
+ return self._get_instance(User, user, callback=User.get_by_username)
+
+ def __get_repo(self, repository):
+ return self._get_instance(Repository, repository,
+ callback=Repository.get_by_repo_name)
+
+ def __get_perm(self, permission):
+ return self._get_instance(Permission, permission,
+ callback=Permission.get_by_key)
+
def get_user_permission(self, repository, user):
+ repository = self.__get_repo(repository)
+ user = self.__get_user(user)
+
return UserRepoToPerm.query() \
.filter(UserRepoToPerm.user == user) \
.filter(UserRepoToPerm.repository == repository) \
diff --git a/rhodecode/model/repos_group.py b/rhodecode/model/repos_group.py
index e0de7076..94590ccb 100644
--- a/rhodecode/model/repos_group.py
+++ b/rhodecode/model/repos_group.py
@@ -28,18 +28,32 @@ import logging
import traceback
import shutil
-from pylons.i18n.translation import _
-
-from vcs.utils.lazy import LazyProperty
+from rhodecode.lib import LazyProperty
from rhodecode.model import BaseModel
-from rhodecode.model.db import RepoGroup, RhodeCodeUi
+from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
+ User, Permission, UsersGroupRepoGroupToPerm, UsersGroup
log = logging.getLogger(__name__)
class ReposGroupModel(BaseModel):
+ def __get_user(self, user):
+ return self._get_instance(User, user, callback=User.get_by_username)
+
+ def __get_users_group(self, users_group):
+ return self._get_instance(UsersGroup, users_group,
+ callback=UsersGroup.get_by_group_name)
+
+ def __get_repos_group(self, repos_group):
+ return self._get_instance(RepoGroup, repos_group,
+ callback=RepoGroup.get_by_group_name)
+
+ def __get_perm(self, permission):
+ return self._get_instance(Permission, permission,
+ callback=Permission.get_by_key)
+
@LazyProperty
def repos_path(self):
"""
@@ -49,6 +63,24 @@ class ReposGroupModel(BaseModel):
q = RhodeCodeUi.get_by_key('/').one()
return q.ui_value
+ def _create_default_perms(self, new_group):
+ # create default permission
+ repo_group_to_perm = UserRepoGroupToPerm()
+ default_perm = 'group.read'
+ for p in User.get_by_username('default').user_perms:
+ if p.permission.permission_name.startswith('group.'):
+ default_perm = p.permission.permission_name
+ break
+
+ repo_group_to_perm.permission_id = self.sa.query(Permission)\
+ .filter(Permission.permission_name == default_perm)\
+ .one().permission_id
+
+ repo_group_to_perm.group = new_group
+ repo_group_to_perm.user_id = User.get_by_username('default').user_id
+
+ self.sa.add(repo_group_to_perm)
+
def __create_group(self, group_name):
"""
makes repositories group on filesystem
@@ -102,16 +134,21 @@ class ReposGroupModel(BaseModel):
# delete only if that path really exists
os.rmdir(rm_path)
- def create(self, form_data):
+ def create(self, group_name, group_description, parent, just_db=False):
try:
new_repos_group = RepoGroup()
- new_repos_group.group_description = form_data['group_description']
- new_repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
- new_repos_group.group_name = new_repos_group.get_new_name(form_data['group_name'])
+ new_repos_group.group_description = group_description
+ new_repos_group.parent_group = self.__get_repos_group(parent)
+ new_repos_group.group_name = new_repos_group.get_new_name(group_name)
self.sa.add(new_repos_group)
- self.sa.flush()
- self.__create_group(new_repos_group.group_name)
+ self._create_default_perms(new_repos_group)
+
+ if not just_db:
+ # we need to flush here, in order to check if database won't
+ # throw any exceptions, create filesystem dirs at the very end
+ self.sa.flush()
+ self.__create_group(new_repos_group.group_name)
return new_repos_group
except:
@@ -122,6 +159,29 @@ class ReposGroupModel(BaseModel):
try:
repos_group = RepoGroup.get(repos_group_id)
+
+ # update permissions
+ for member, perm, member_type in form_data['perms_updates']:
+ if member_type == 'user':
+ # this updates also current one if found
+ ReposGroupModel().grant_user_permission(
+ repos_group=repos_group, user=member, perm=perm
+ )
+ else:
+ ReposGroupModel().grant_users_group_permission(
+ repos_group=repos_group, group_name=member, perm=perm
+ )
+ # set new permissions
+ for member, perm, member_type in form_data['perms_new']:
+ if member_type == 'user':
+ ReposGroupModel().grant_user_permission(
+ repos_group=repos_group, user=member, perm=perm
+ )
+ else:
+ ReposGroupModel().grant_users_group_permission(
+ repos_group=repos_group, group_name=member, perm=perm
+ )
+
old_path = repos_group.full_path
# change properties
@@ -154,3 +214,97 @@ class ReposGroupModel(BaseModel):
except:
log.error(traceback.format_exc())
raise
+
+ def grant_user_permission(self, repos_group, user, perm):
+ """
+ Grant permission for user on given repositories group, or update
+ existing one if found
+
+ :param repos_group: Instance of ReposGroup, repositories_group_id,
+ or repositories_group name
+ :param user: Instance of User, user_id or username
+ :param perm: Instance of Permission, or permission_name
+ """
+
+ repos_group = self.__get_repos_group(repos_group)
+ user = self.__get_user(user)
+ permission = self.__get_perm(perm)
+
+ # check if we have that permission already
+ obj = self.sa.query(UserRepoGroupToPerm)\
+ .filter(UserRepoGroupToPerm.user == user)\
+ .filter(UserRepoGroupToPerm.group == repos_group)\
+ .scalar()
+ if obj is None:
+ # create new !
+ obj = UserRepoGroupToPerm()
+ obj.group = repos_group
+ obj.user = user
+ obj.permission = permission
+ self.sa.add(obj)
+
+ def revoke_user_permission(self, repos_group, user):
+ """
+ Revoke permission for user on given repositories group
+
+ :param repos_group: Instance of ReposGroup, repositories_group_id,
+ or repositories_group name
+ :param user: Instance of User, user_id or username
+ """
+
+ repos_group = self.__get_repos_group(repos_group)
+ user = self.__get_user(user)
+
+ obj = self.sa.query(UserRepoGroupToPerm)\
+ .filter(UserRepoGroupToPerm.user == user)\
+ .filter(UserRepoGroupToPerm.group == repos_group)\
+ .one()
+ self.sa.delete(obj)
+
+ def grant_users_group_permission(self, repos_group, group_name, perm):
+ """
+ Grant permission for users group on given repositories group, or update
+ existing one if found
+
+ :param repos_group: Instance of ReposGroup, repositories_group_id,
+ or repositories_group name
+ :param group_name: Instance of UserGroup, users_group_id,
+ or users group name
+ :param perm: Instance of Permission, or permission_name
+ """
+ repos_group = self.__get_repos_group(repos_group)
+ group_name = self.__get_users_group(group_name)
+ permission = self.__get_perm(perm)
+
+ # check if we have that permission already
+ obj = self.sa.query(UsersGroupRepoGroupToPerm)\
+ .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
+ .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
+ .scalar()
+
+ if obj is None:
+ # create new
+ obj = UsersGroupRepoGroupToPerm()
+
+ obj.group = repos_group
+ obj.users_group = group_name
+ obj.permission = permission
+ self.sa.add(obj)
+
+ def revoke_users_group_permission(self, repos_group, group_name):
+ """
+ Revoke permission for users group on given repositories group
+
+ :param repos_group: Instance of ReposGroup, repositories_group_id,
+ or repositories_group name
+ :param group_name: Instance of UserGroup, users_group_id,
+ or users group name
+ """
+ repos_group = self.__get_repos_group(repos_group)
+ group_name = self.__get_users_group(group_name)
+
+ obj = self.sa.query(UsersGroupRepoGroupToPerm)\
+ .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
+ .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
+ .one()
+ self.sa.delete(obj)
diff --git a/rhodecode/model/scm.py b/rhodecode/model/scm.py
index 668804f8..5542ab3b 100644
--- a/rhodecode/model/scm.py
+++ b/rhodecode/model/scm.py
@@ -36,12 +36,12 @@ from vcs.nodes import FileNode
from rhodecode import BACKENDS
from rhodecode.lib import helpers as h
from rhodecode.lib import safe_str
-from rhodecode.lib.auth import HasRepoPermissionAny
+from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny
from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
action_logger, EmptyChangeset
from rhodecode.model import BaseModel
from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
- UserFollowing, UserLog, User
+ UserFollowing, UserLog, User, RepoGroup
log = logging.getLogger(__name__)
@@ -80,15 +80,16 @@ class CachedRepoList(object):
for dbr in self.db_repo_list:
scmr = dbr.scm_instance_cached
# check permission at this level
- if not HasRepoPermissionAny('repository.read', 'repository.write',
- 'repository.admin')(dbr.repo_name,
- 'get repo check'):
+ if not HasRepoPermissionAny(
+ 'repository.read', 'repository.write', 'repository.admin'
+ )(dbr.repo_name, 'get repo check'):
continue
if scmr is None:
- log.error('%s this repository is present in database but it '
- 'cannot be created as an scm instance',
- dbr.repo_name)
+ log.error(
+ '%s this repository is present in database but it '
+ 'cannot be created as an scm instance' % dbr.repo_name
+ )
continue
last_change = scmr.last_change
@@ -115,6 +116,28 @@ class CachedRepoList(object):
yield tmp_d
+class GroupList(object):
+
+ def __init__(self, db_repo_group_list):
+ self.db_repo_group_list = db_repo_group_list
+
+ def __len__(self):
+ return len(self.db_repo_group_list)
+
+ def __repr__(self):
+ return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
+
+ def __iter__(self):
+ for dbgr in self.db_repo_group_list:
+ # check permission at this level
+ if not HasReposGroupPermissionAny(
+ 'group.read', 'group.write', 'group.admin'
+ )(dbgr.group_name, 'get group repo check'):
+ continue
+
+ yield dbgr
+
+
class ScmModel(BaseModel):
"""
Generic Scm Model
@@ -200,6 +223,14 @@ class ScmModel(BaseModel):
return repo_iter
+ def get_repos_groups(self, all_groups=None):
+ if all_groups is None:
+ all_groups = RepoGroup.query()\
+ .filter(RepoGroup.group_parent_id == None).all()
+ group_iter = GroupList(all_groups)
+
+ return group_iter
+
def mark_for_invalidation(self, repo_name):
"""Puts cache invalidation task into db for
further global cache invalidation
diff --git a/rhodecode/model/user.py b/rhodecode/model/user.py
index 59dbc871..cedce660 100644
--- a/rhodecode/model/user.py
+++ b/rhodecode/model/user.py
@@ -35,7 +35,7 @@ from rhodecode.lib.caching_query import FromCache
from rhodecode.model import BaseModel
from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
- Notification
+ Notification, RepoGroup, UserRepoGroupToPerm, UsersGroup
from rhodecode.lib.exceptions import DefaultUserException, \
UserOwnsReposException
@@ -46,16 +46,26 @@ from sqlalchemy.orm import joinedload
log = logging.getLogger(__name__)
-PERM_WEIGHTS = {'repository.none': 0,
- 'repository.read': 1,
- 'repository.write': 3,
- 'repository.admin': 3}
+PERM_WEIGHTS = {
+ 'repository.none': 0,
+ 'repository.read': 1,
+ 'repository.write': 3,
+ 'repository.admin': 4,
+ 'group.none': 0,
+ 'group.read': 1,
+ 'group.write': 3,
+ 'group.admin': 4,
+}
class UserModel(BaseModel):
def __get_user(self, user):
- return self._get_instance(User, user)
+ return self._get_instance(User, user, callback=User.get_by_username)
+
+ def __get_perm(self, permission):
+ return self._get_instance(Permission, permission,
+ callback=Permission.get_by_key)
def get(self, user_id, cache=False):
user = self.sa.query(User)
@@ -348,9 +358,12 @@ class UserModel(BaseModel):
:param user: user instance to fill his perms
"""
-
- user.permissions['repositories'] = {}
- user.permissions['global'] = set()
+ RK = 'repositories'
+ GK = 'repositories_groups'
+ GLOBAL = 'global'
+ user.permissions[RK] = {}
+ user.permissions[GK] = {}
+ user.permissions[GLOBAL] = set()
#======================================================================
# fetch default permissions
@@ -358,36 +371,45 @@ class UserModel(BaseModel):
default_user = User.get_by_username('default', cache=True)
default_user_id = default_user.user_id
- default_perms = Permission.get_default_perms(default_user_id)
+ default_repo_perms = Permission.get_default_perms(default_user_id)
+ default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
if user.is_admin:
#==================================================================
- # #admin have all default rights set to admin
+ # admin user have all default rights for repositories
+ # and groups set to admin
#==================================================================
- user.permissions['global'].add('hg.admin')
+ user.permissions[GLOBAL].add('hg.admin')
- for perm in default_perms:
+ # repositories
+ for perm in default_repo_perms:
+ r_k = perm.UserRepoToPerm.repository.repo_name
p = 'repository.admin'
- user.permissions['repositories'][perm.UserRepoToPerm.
- repository.repo_name] = p
+ user.permissions[RK][r_k] = p
+
+ # repositories groups
+ for perm in default_repo_groups_perms:
+ rg_k = perm.UserRepoGroupToPerm.group.group_name
+ p = 'group.admin'
+ user.permissions[GK][rg_k] = p
else:
#==================================================================
- # set default permissions
+ # set default permissions first for repositories and groups
#==================================================================
uid = user.user_id
- # default global
+ # default global permissions
default_global_perms = self.sa.query(UserToPerm)\
.filter(UserToPerm.user_id == default_user_id)
for perm in default_global_perms:
- user.permissions['global'].add(perm.permission.permission_name)
+ user.permissions[GLOBAL].add(perm.permission.permission_name)
# default for repositories
- for perm in default_perms:
- if perm.Repository.private and not (perm.Repository.user_id ==
- uid):
+ for perm in default_repo_perms:
+ r_k = perm.UserRepoToPerm.repository.repo_name
+ if perm.Repository.private and not (perm.Repository.user_id == uid):
# disable defaults for private repos,
p = 'repository.none'
elif perm.Repository.user_id == uid:
@@ -396,8 +418,13 @@ class UserModel(BaseModel):
else:
p = perm.Permission.permission_name
- user.permissions['repositories'][perm.UserRepoToPerm.
- repository.repo_name] = p
+ user.permissions[RK][r_k] = p
+
+ # default for repositories groups
+ for perm in default_repo_groups_perms:
+ rg_k = perm.UserRepoGroupToPerm.group.group_name
+ p = perm.Permission.permission_name
+ user.permissions[GK][rg_k] = p
#==================================================================
# overwrite default with user permissions if any
@@ -409,25 +436,24 @@ class UserModel(BaseModel):
.filter(UserToPerm.user_id == uid).all()
for perm in user_perms:
- user.permissions['global'].add(perm.permission.permission_name)
+ user.permissions[GLOBAL].add(perm.permission.permission_name)
# user repositories
- user_repo_perms = self.sa.query(UserRepoToPerm, Permission,
- Repository)\
- .join((Repository, UserRepoToPerm.repository_id ==
- Repository.repo_id))\
- .join((Permission, UserRepoToPerm.permission_id ==
- Permission.permission_id))\
- .filter(UserRepoToPerm.user_id == uid).all()
+ user_repo_perms = \
+ self.sa.query(UserRepoToPerm, Permission, Repository)\
+ .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
+ .join((Permission, UserRepoToPerm.permission_id == Permission.permission_id))\
+ .filter(UserRepoToPerm.user_id == uid)\
+ .all()
for perm in user_repo_perms:
# set admin if owner
+ r_k = perm.UserRepoToPerm.repository.repo_name
if perm.Repository.user_id == uid:
p = 'repository.admin'
else:
p = perm.Permission.permission_name
- user.permissions['repositories'][perm.UserRepoToPerm.
- repository.repo_name] = p
+ user.permissions[RK][r_k] = p
#==================================================================
# check if user is part of groups for this repository and fill in
@@ -442,30 +468,44 @@ class UserModel(BaseModel):
.filter(UsersGroupMember.user_id == uid).all()
for perm in user_perms_from_users_groups:
- user.permissions['global'].add(perm.permission.permission_name)
+ user.permissions[GLOBAL].add(perm.permission.permission_name)
# users group repositories
- user_repo_perms_from_users_groups = self.sa.query(
- UsersGroupRepoToPerm,
- Permission, Repository,)\
- .join((Repository, UsersGroupRepoToPerm.repository_id ==
- Repository.repo_id))\
- .join((Permission, UsersGroupRepoToPerm.permission_id ==
- Permission.permission_id))\
- .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
- UsersGroupMember.users_group_id))\
- .filter(UsersGroupMember.user_id == uid).all()
+ user_repo_perms_from_users_groups = \
+ self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
+ .join((Repository, UsersGroupRepoToPerm.repository_id == Repository.repo_id))\
+ .join((Permission, UsersGroupRepoToPerm.permission_id == Permission.permission_id))\
+ .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id == UsersGroupMember.users_group_id))\
+ .filter(UsersGroupMember.user_id == uid)\
+ .all()
for perm in user_repo_perms_from_users_groups:
+ r_k = perm.UsersGroupRepoToPerm.repository.repo_name
p = perm.Permission.permission_name
- cur_perm = user.permissions['repositories'][perm.
- UsersGroupRepoToPerm.
- repository.repo_name]
+ cur_perm = user.permissions[RK][r_k]
# overwrite permission only if it's greater than permission
# given from other sources
if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
- user.permissions['repositories'][perm.UsersGroupRepoToPerm.
- repository.repo_name] = p
+ user.permissions[RK][r_k] = p
+
+ #==================================================================
+ # get access for this user for repos group and override defaults
+ #==================================================================
+
+ # user repositories groups
+ user_repo_groups_perms = \
+ self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\
+ .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
+ .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\
+ .filter(UserRepoToPerm.user_id == uid)\
+ .all()
+
+ for perm in user_repo_groups_perms:
+ rg_k = perm.UserRepoGroupToPerm.group.group_name
+ p = perm.Permission.permission_name
+ cur_perm = user.permissions[GK][rg_k]
+ if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
+ user.permissions[GK][rg_k] = p
return user
@@ -480,23 +520,28 @@ class UserModel(BaseModel):
.filter(UserToPerm.permission == perm).scalar() is not None
def grant_perm(self, user, perm):
- if not isinstance(perm, Permission):
- raise Exception('perm needs to be an instance of Permission class '
- 'got %s instead' % type(perm))
+ """
+ Grant user global permissions
+ :param user:
+ :param perm:
+ """
user = self.__get_user(user)
-
+ perm = self.__get_perm(perm)
new = UserToPerm()
new.user = user
new.permission = perm
self.sa.add(new)
def revoke_perm(self, user, perm):
- if not isinstance(perm, Permission):
- raise Exception('perm needs to be an instance of Permission class '
- 'got %s instead' % type(perm))
+ """
+ Revoke users global permissions
+ :param user:
+ :param perm:
+ """
user = self.__get_user(user)
+ perm = self.__get_perm(perm)
obj = UserToPerm.query().filter(UserToPerm.user == user)\
.filter(UserToPerm.permission == perm).scalar()
diff --git a/rhodecode/model/users_group.py b/rhodecode/model/users_group.py
index 738e6aaa..b07958b0 100644
--- a/rhodecode/model/users_group.py
+++ b/rhodecode/model/users_group.py
@@ -38,7 +38,12 @@ log = logging.getLogger(__name__)
class UsersGroupModel(BaseModel):
def __get_users_group(self, users_group):
- return self._get_instance(UsersGroup, users_group)
+ return self._get_instance(UsersGroup, users_group,
+ callback=UsersGroup.get_by_group_name)
+
+ def __get_perm(self, permission):
+ return self._get_instance(Permission, permission,
+ callback=Permission.get_by_key)
def get(self, users_group_id, cache=False):
return UsersGroup.get(users_group_id)
@@ -80,7 +85,15 @@ class UsersGroupModel(BaseModel):
log.error(traceback.format_exc())
raise
- def delete(self, users_group):
+ def delete(self, users_group, force=False):
+ """
+ Deletes repos group, unless force flag is used
+ raises exception if there are members in that group, else deletes
+ group and users
+
+ :param users_group:
+ :param force:
+ """
try:
users_group = self.__get_users_group(users_group)
@@ -88,7 +101,7 @@ class UsersGroupModel(BaseModel):
assigned_groups = UsersGroupRepoToPerm.query()\
.filter(UsersGroupRepoToPerm.users_group == users_group).all()
- if assigned_groups:
+ if assigned_groups and force is False:
raise UsersGroupsAssignedException('RepoGroup assigned to %s' %
assigned_groups)
@@ -118,10 +131,8 @@ class UsersGroupModel(BaseModel):
raise
def has_perm(self, users_group, perm):
- if not isinstance(perm, Permission):
- raise Exception('perm needs to be an instance of Permission class')
-
users_group = self.__get_users_group(users_group)
+ perm = self.__get_perm(perm)
return UsersGroupToPerm.query()\
.filter(UsersGroupToPerm.users_group == users_group)\
@@ -139,10 +150,8 @@ class UsersGroupModel(BaseModel):
self.sa.add(new)
def revoke_perm(self, users_group, perm):
- if not isinstance(perm, Permission):
- raise Exception('perm needs to be an instance of Permission class')
-
users_group = self.__get_users_group(users_group)
+ perm = self.__get_perm(perm)
obj = UsersGroupToPerm.query()\
.filter(UsersGroupToPerm.users_group == users_group)\
diff --git a/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html b/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html
new file mode 100644
index 00000000..533ce17b
--- /dev/null
+++ b/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html
@@ -0,0 +1,270 @@
+<table id="permissions_manage" class="noborder">
+ <tr>
+ <td>${_('none')}</td>
+ <td>${_('read')}</td>
+ <td>${_('write')}</td>
+ <td>${_('admin')}</td>
+ <td>${_('member')}</td>
+ <td></td>
+ </tr>
+ ## USERS
+ %for r2p in c.repos_group.repo_group_to_perm:
+ <tr id="id${id(r2p.user.username)}">
+ <td>${h.radio('u_perm_%s' % r2p.user.username,'group.none')}</td>
+ <td>${h.radio('u_perm_%s' % r2p.user.username,'group.read')}</td>
+ <td>${h.radio('u_perm_%s' % r2p.user.username,'group.write')}</td>
+ <td>${h.radio('u_perm_%s' % r2p.user.username,'group.admin')}</td>
+ <td style="white-space: nowrap;">
+ <img style="vertical-align:bottom" src="${h.url('/images/icons/user.png')}"/>${r2p.user.username}
+ </td>
+ <td>
+ %if r2p.user.username !='default':
+ <span class="delete_icon action_button" onclick="ajaxActionUser(${r2p.user.user_id},'${'id%s'%id(r2p.user.username)}')">
+ ${_('revoke')}
+ </span>
+ %endif
+ </td>
+ </tr>
+ %endfor
+
+ ## USERS GROUPS
+ %for g2p in c.repos_group.users_group_to_perm:
+ <tr id="id${id(g2p.users_group.users_group_name)}">
+ <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.none')}</td>
+ <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.read')}</td>
+ <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.write')}</td>
+ <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.admin')}</td>
+ <td style="white-space: nowrap;">
+ <img style="vertical-align:bottom" src="${h.url('/images/icons/group.png')}"/>${g2p.users_group.users_group_name}
+ </td>
+ <td>
+ <span class="delete_icon action_button" onclick="ajaxActionUsersGroup(${g2p.users_group.users_group_id},'${'id%s'%id(g2p.users_group.users_group_name)}')">
+ ${_('revoke')}
+ </span>
+ </td>
+ </tr>
+ %endfor
+ <tr id="add_perm_input">
+ <td>${h.radio('perm_new_member','group.none')}</td>
+ <td>${h.radio('perm_new_member','group.read')}</td>
+ <td>${h.radio('perm_new_member','group.write')}</td>
+ <td>${h.radio('perm_new_member','group.admin')}</td>
+ <td class='ac'>
+ <div class="perm_ac" id="perm_ac">
+ ${h.text('perm_new_member_name',class_='yui-ac-input')}
+ ${h.hidden('perm_new_member_type')}
+ <div id="perm_container"></div>
+ </div>
+ </td>
+ <td></td>
+ </tr>
+ <tr>
+ <td colspan="6">
+ <span id="add_perm" class="add_icon" style="cursor: pointer;">
+ ${_('Add another member')}
+ </span>
+ </td>
+ </tr>
+</table>
+<script type="text/javascript">
+function ajaxActionUser(user_id, field_id) {
+ var sUrl = "${h.url('delete_repos_group_user_perm',group_name=c.repos_group.name)}";
+ var callback = {
+ success: function (o) {
+ var tr = YUD.get(String(field_id));
+ tr.parentNode.removeChild(tr);
+ },
+ failure: function (o) {
+ alert("${_('Failed to remove user')}");
+ },
+ };
+ var postData = '_method=delete&user_id=' + user_id;
+ var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
+};
+
+function ajaxActionUsersGroup(users_group_id,field_id){
+ var sUrl = "${h.url('delete_repos_group_users_group_perm',group_name=c.repos_group.name)}";
+ var callback = {
+ success:function(o){
+ var tr = YUD.get(String(field_id));
+ tr.parentNode.removeChild(tr);
+ },
+ failure:function(o){
+ alert("${_('Failed to remove users group')}");
+ },
+ };
+ var postData = '_method=delete&users_group_id='+users_group_id;
+ var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
+};
+
+YUE.onDOMReady(function () {
+ if (!YUD.hasClass('perm_new_member_name', 'error')) {
+ YUD.setStyle('add_perm_input', 'display', 'none');
+ }
+ YAHOO.util.Event.addListener('add_perm', 'click', function () {
+ YUD.setStyle('add_perm_input', 'display', '');
+ YUD.setStyle('add_perm', 'opacity', '0.6');
+ YUD.setStyle('add_perm', 'cursor', 'default');
+ });
+});
+
+YAHOO.example.FnMultipleFields = function () {
+ var myUsers = ${c.users_array|n};
+ var myGroups = ${c.users_groups_array|n};
+
+ // Define a custom search function for the DataSource of users
+ var matchUsers = function (sQuery) {
+ // Case insensitive matching
+ var query = sQuery.toLowerCase();
+ var i = 0;
+ var l = myUsers.length;
+ var matches = [];
+
+ // Match against each name of each contact
+ for (; i < l; i++) {
+ contact = myUsers[i];
+ if ((contact.fname.toLowerCase().indexOf(query) > -1) || (contact.lname.toLowerCase().indexOf(query) > -1) || (contact.nname && (contact.nname.toLowerCase().indexOf(query) > -1))) {
+ matches[matches.length] = contact;
+ }
+ }
+ return matches;
+ };
+
+ // Define a custom search function for the DataSource of usersGroups
+ var matchGroups = function (sQuery) {
+ // Case insensitive matching
+ var query = sQuery.toLowerCase();
+ var i = 0;
+ var l = myGroups.length;
+ var matches = [];
+
+ // Match against each name of each contact
+ for (; i < l; i++) {
+ matched_group = myGroups[i];
+ if (matched_group.grname.toLowerCase().indexOf(query) > -1) {
+ matches[matches.length] = matched_group;
+ }
+ }
+ return matches;
+ };
+
+ //match all
+ var matchAll = function (sQuery) {
+ u = matchUsers(sQuery);
+ g = matchGroups(sQuery);
+ return u.concat(g);
+ };
+
+ // DataScheme for members
+ var memberDS = new YAHOO.util.FunctionDataSource(matchAll);
+ memberDS.responseSchema = {
+ fields: ["id", "fname", "lname", "nname", "grname", "grmembers"]
+ };
+
+ // DataScheme for owner
+ var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
+ ownerDS.responseSchema = {
+ fields: ["id", "fname", "lname", "nname"]
+ };
+
+ // Instantiate AutoComplete for perms
+ var membersAC = new YAHOO.widget.AutoComplete("perm_new_member_name", "perm_container", memberDS);
+ membersAC.useShadow = false;
+ membersAC.resultTypeList = false;
+
+ // Instantiate AutoComplete for owner
+ var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS);
+ ownerAC.useShadow = false;
+ ownerAC.resultTypeList = false;
+
+
+ // Helper highlight function for the formatter
+ var highlightMatch = function (full, snippet, matchindex) {
+ return full.substring(0, matchindex) + "<span class='match'>" + full.substr(matchindex, snippet.length) + "</span>" + full.substring(matchindex + snippet.length);
+ };
+
+ // Custom formatter to highlight the matching letters
+ var custom_formatter = function (oResultData, sQuery, sResultMatch) {
+ var query = sQuery.toLowerCase();
+
+ if (oResultData.grname != undefined) {
+ var grname = oResultData.grname;
+ var grmembers = oResultData.grmembers;
+ var grnameMatchIndex = grname.toLowerCase().indexOf(query);
+ var grprefix = "${_('Group')}: ";
+ var grsuffix = " (" + grmembers + " ${_('members')})";
+
+ if (grnameMatchIndex > -1) {
+ return grprefix + highlightMatch(grname, query, grnameMatchIndex) + grsuffix;
+ }
+
+ return grprefix + oResultData.grname + grsuffix;
+ } else if (oResultData.fname != undefined) {
+
+ var fname = oResultData.fname,
+ lname = oResultData.lname,
+ nname = oResultData.nname || "",
+ // Guard against null value
+ fnameMatchIndex = fname.toLowerCase().indexOf(query),
+ lnameMatchIndex = lname.toLowerCase().indexOf(query),
+ nnameMatchIndex = nname.toLowerCase().indexOf(query),
+ displayfname, displaylname, displaynname;
+
+ if (fnameMatchIndex > -1) {
+ displayfname = highlightMatch(fname, query, fnameMatchIndex);
+ } else {
+ displayfname = fname;
+ }
+
+ if (lnameMatchIndex > -1) {
+ displaylname = highlightMatch(lname, query, lnameMatchIndex);
+ } else {
+ displaylname = lname;
+ }
+
+ if (nnameMatchIndex > -1) {
+ displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
+ } else {
+ displaynname = nname ? "(" + nname + ")" : "";
+ }
+
+ return displayfname + " " + displaylname + " " + displaynname;
+ } else {
+ return '';
+ }
+ };
+ membersAC.formatResult = custom_formatter;
+ ownerAC.formatResult = custom_formatter;
+
+ var myHandler = function (sType, aArgs) {
+
+ var myAC = aArgs[0]; // reference back to the AC instance
+ var elLI = aArgs[1]; // reference to the selected LI element
+ var oData = aArgs[2]; // object literal of selected item's result data
+ //fill the autocomplete with value
+ if (oData.nname != undefined) {
+ //users
+ myAC.getInputEl().value = oData.nname;
+ YUD.get('perm_new_member_type').value = 'user';
+ } else {
+ //groups
+ myAC.getInputEl().value = oData.grname;
+ YUD.get('perm_new_member_type').value = 'users_group';
+ }
+
+ };
+
+ membersAC.itemSelectEvent.subscribe(myHandler);
+ if(ownerAC.itemSelectEvent){
+ ownerAC.itemSelectEvent.subscribe(myHandler);
+ }
+
+ return {
+ memberDS: memberDS,
+ ownerDS: ownerDS,
+ membersAC: membersAC,
+ ownerAC: ownerAC,
+ };
+}();
+
+</script>
diff --git a/rhodecode/templates/admin/repos_groups/repos_groups_edit.html b/rhodecode/templates/admin/repos_groups/repos_groups_edit.html
index 89bca5f7..b3681099 100644
--- a/rhodecode/templates/admin/repos_groups/repos_groups_edit.html
+++ b/rhodecode/templates/admin/repos_groups/repos_groups_edit.html
@@ -53,9 +53,18 @@
${h.select('group_parent_id','',c.repo_groups,class_="medium")}
</div>
</div>
+ <div class="field">
+ <div class="label">
+ <label for="input">${_('Permissions')}:</label>
+ </div>
+ <div class="input">
+ <%include file="repos_group_edit_perms.html"/>
+ </div>
+ </div>
<div class="buttons">
- ${h.submit('save',_('save'),class_="ui-button")}
+ ${h.submit('save',_('Save'),class_="ui-button")}
+ ${h.reset('reset',_('Reset'),class_="ui-button")}
</div>
</div>
</div>
diff --git a/rhodecode/templates/index_base.html b/rhodecode/templates/index_base.html
index e5684dbb..0aaba7da 100644
--- a/rhodecode/templates/index_base.html
+++ b/rhodecode/templates/index_base.html
@@ -38,7 +38,9 @@
</div>
</td>
<td>${gr.group_description}</td>
- ##<td><b>${gr.repositories.count()}</b></td>
+ ## this is commented out since for multi nested repos can be HEAVY!
+ ## in number of executed queries during traversing uncomment at will
+ ##<td><b>${gr.repositories_recursive_count}</b></td>
</tr>
% endfor
diff --git a/rhodecode/tests/test_models.py b/rhodecode/tests/test_models.py
index 434071cb..b0fd6e48 100644
--- a/rhodecode/tests/test_models.py
+++ b/rhodecode/tests/test_models.py
@@ -12,13 +12,27 @@ from rhodecode.model.user import UserModel
from rhodecode.model.meta import Session
from rhodecode.model.notification import NotificationModel
from rhodecode.model.users_group import UsersGroupModel
+from rhodecode.lib.auth import AuthUser
+
+
+def _make_group(path, desc='desc', parent_id=None,
+ skip_if_exists=False):
+
+ gr = RepoGroup.get_by_group_name(path)
+ if gr and skip_if_exists:
+ return gr
+
+ gr = ReposGroupModel().create(path, desc, parent_id)
+ Session.commit()
+ return gr
+
class TestReposGroups(unittest.TestCase):
def setUp(self):
- self.g1 = self.__make_group('test1', skip_if_exists=True)
- self.g2 = self.__make_group('test2', skip_if_exists=True)
- self.g3 = self.__make_group('test3', skip_if_exists=True)
+ self.g1 = _make_group('test1', skip_if_exists=True)
+ self.g2 = _make_group('test2', skip_if_exists=True)
+ self.g3 = _make_group('test3', skip_if_exists=True)
def tearDown(self):
print 'out'
@@ -31,102 +45,81 @@ class TestReposGroups(unittest.TestCase):
def _check_folders(self):
print os.listdir(TESTS_TMP_PATH)
- def __make_group(self, path, desc='desc', parent_id=None,
- skip_if_exists=False):
-
- gr = RepoGroup.get_by_group_name(path)
- if gr and skip_if_exists:
- return gr
-
- form_data = dict(group_name=path,
- group_description=desc,
- group_parent_id=parent_id)
- gr = ReposGroupModel().create(form_data)
- Session.commit()
- return gr
-
def __delete_group(self, id_):
ReposGroupModel().delete(id_)
-
def __update_group(self, id_, path, desc='desc', parent_id=None):
form_data = dict(group_name=path,
group_description=desc,
- group_parent_id=parent_id)
+ group_parent_id=parent_id,
+ perms_updates=[],
+ perms_new=[])
gr = ReposGroupModel().update(id_, form_data)
return gr
def test_create_group(self):
- g = self.__make_group('newGroup')
+ g = _make_group('newGroup')
self.assertEqual(g.full_path, 'newGroup')
self.assertTrue(self.__check_path('newGroup'))
-
def test_create_same_name_group(self):
- self.assertRaises(IntegrityError, lambda:self.__make_group('newGroup'))
+ self.assertRaises(IntegrityError, lambda:_make_group('newGroup'))
Session.rollback()
def test_same_subgroup(self):
- sg1 = self.__make_group('sub1', parent_id=self.g1.group_id)
+ sg1 = _make_group('sub1', parent_id=self.g1.group_id)
self.assertEqual(sg1.parent_group, self.g1)
self.assertEqual(sg1.full_path, 'test1/sub1')
self.assertTrue(self.__check_path('test1', 'sub1'))
- ssg1 = self.__make_group('subsub1', parent_id=sg1.group_id)
+ ssg1 = _make_group('subsub1', parent_id=sg1.group_id)
self.assertEqual(ssg1.parent_group, sg1)
self.assertEqual(ssg1.full_path, 'test1/sub1/subsub1')
self.assertTrue(self.__check_path('test1', 'sub1', 'subsub1'))
-
def test_remove_group(self):
- sg1 = self.__make_group('deleteme')
+ sg1 = _make_group('deleteme')
self.__delete_group(sg1.group_id)
self.assertEqual(RepoGroup.get(sg1.group_id), None)
self.assertFalse(self.__check_path('deteteme'))
- sg1 = self.__make_group('deleteme', parent_id=self.g1.group_id)
+ sg1 = _make_group('deleteme', parent_id=self.g1.group_id)
self.__delete_group(sg1.group_id)
self.assertEqual(RepoGroup.get(sg1.group_id), None)
self.assertFalse(self.__check_path('test1', 'deteteme'))
-
def test_rename_single_group(self):
- sg1 = self.__make_group('initial')
+ sg1 = _make_group('initial')
new_sg1 = self.__update_group(sg1.group_id, 'after')
self.assertTrue(self.__check_path('after'))
self.assertEqual(RepoGroup.get_by_group_name('initial'), None)
-
def test_update_group_parent(self):
- sg1 = self.__make_group('initial', parent_id=self.g1.group_id)
+ sg1 = _make_group('initial', parent_id=self.g1.group_id)
new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
self.assertTrue(self.__check_path('test1', 'after'))
self.assertEqual(RepoGroup.get_by_group_name('test1/initial'), None)
-
new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
self.assertTrue(self.__check_path('test3', 'after'))
self.assertEqual(RepoGroup.get_by_group_name('test3/initial'), None)
-
new_sg1 = self.__update_group(sg1.group_id, 'hello')
self.assertTrue(self.__check_path('hello'))
self.assertEqual(RepoGroup.get_by_group_name('hello'), new_sg1)
-
-
def test_subgrouping_with_repo(self):
- g1 = self.__make_group('g1')
- g2 = self.__make_group('g2')
+ g1 = _make_group('g1')
+ g2 = _make_group('g2')
# create new repo
form_data = dict(repo_name='john',
@@ -150,13 +143,13 @@ class TestReposGroups(unittest.TestCase):
RepoModel().update(r.repo_name, form_data)
self.assertEqual(r.repo_name, 'g1/john')
-
self.__update_group(g1.group_id, 'g1', parent_id=g2.group_id)
self.assertTrue(self.__check_path('g2', 'g1'))
# test repo
self.assertEqual(r.repo_name, os.path.join('g2', 'g1', r.just_name))
+
class TestUser(unittest.TestCase):
def __init__(self, methodName='runTest'):
Session.remove()
@@ -245,7 +238,6 @@ class TestNotifications(unittest.TestCase):
self.assertEqual(len(unotification), len(usrs))
self.assertEqual([x.user.user_id for x in unotification], usrs)
-
def test_user_notifications(self):
self.assertEqual([], Notification.query().all())
self.assertEqual([], UserNotification.query().all())
@@ -284,7 +276,6 @@ class TestNotifications(unittest.TestCase):
== notification).all()
self.assertEqual(un, [])
-
def test_delete_association(self):
self.assertEqual([], Notification.query().all())
@@ -361,6 +352,7 @@ class TestNotifications(unittest.TestCase):
self.assertEqual(NotificationModel()
.get_unread_cnt_for_user(self.u3), 2)
+
class TestUsers(unittest.TestCase):
def __init__(self, methodName='runTest'):
@@ -401,4 +393,163 @@ class TestUsers(unittest.TestCase):
#revoke
UserModel().revoke_perm(self.u1, perm)
Session.commit()
- self.assertEqual(UserModel().has_perm(self.u1, perm),False)
+ self.assertEqual(UserModel().has_perm(self.u1, perm), False)
+
+
+class TestPermissions(unittest.TestCase):
+ def __init__(self, methodName='runTest'):
+ super(TestPermissions, self).__init__(methodName=methodName)
+
+ def setUp(self):
+ self.u1 = UserModel().create_or_update(
+ username=u'u1', password=u'qweqwe',
+ email=u'u1@rhodecode.org', name=u'u1', lastname=u'u1'
+ )
+ self.a1 = UserModel().create_or_update(
+ username=u'a1', password=u'qweqwe',
+ email=u'a1@rhodecode.org', name=u'a1', lastname=u'a1', admin=True
+ )
+ Session.commit()
+
+ def tearDown(self):
+ UserModel().delete(self.u1)
+ UserModel().delete(self.a1)
+ if hasattr(self, 'g1'):
+ ReposGroupModel().delete(self.g1.group_id)
+ if hasattr(self, 'g2'):
+ ReposGroupModel().delete(self.g2.group_id)
+
+ if hasattr(self, 'ug1'):
+ UsersGroupModel().delete(self.ug1, force=True)
+
+ Session.commit()
+
+ def test_default_perms_set(self):
+ u1_auth = AuthUser(user_id=self.u1.user_id)
+ perms = {
+ 'repositories_groups': {},
+ 'global': set([u'hg.create.repository', u'repository.read',
+ u'hg.register.manual_activate']),
+ 'repositories': {u'vcs_test_hg': u'repository.read'}
+ }
+ self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+ perms['repositories'][HG_REPO])
+ new_perm = 'repository.write'
+ RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm)
+ Session.commit()
+
+ u1_auth = AuthUser(user_id=self.u1.user_id)
+ self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], new_perm)
+
+ def test_default_admin_perms_set(self):
+ a1_auth = AuthUser(user_id=self.a1.user_id)
+ perms = {
+ 'repositories_groups': {},
+ 'global': set([u'hg.admin']),
+ 'repositories': {u'vcs_test_hg': u'repository.admin'}
+ }
+ self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
+ perms['repositories'][HG_REPO])
+ new_perm = 'repository.write'
+ RepoModel().grant_user_permission(repo=HG_REPO, user=self.a1, perm=new_perm)
+ Session.commit()
+ # cannot really downgrade admins permissions !? they still get's set as
+ # admin !
+ u1_auth = AuthUser(user_id=self.a1.user_id)
+ self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+ perms['repositories'][HG_REPO])
+
+ def test_default_group_perms(self):
+ self.g1 = _make_group('test1', skip_if_exists=True)
+ self.g2 = _make_group('test2', skip_if_exists=True)
+ u1_auth = AuthUser(user_id=self.u1.user_id)
+ perms = {
+ 'repositories_groups': {u'test1': 'group.read', u'test2': 'group.read'},
+ 'global': set([u'hg.create.repository', u'repository.read', u'hg.register.manual_activate']),
+ 'repositories': {u'vcs_test_hg': u'repository.read'}
+ }
+ self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+ perms['repositories'][HG_REPO])
+ self.assertEqual(u1_auth.permissions['repositories_groups'],
+ perms['repositories_groups'])
+
+ def test_default_admin_group_perms(self):
+ self.g1 = _make_group('test1', skip_if_exists=True)
+ self.g2 = _make_group('test2', skip_if_exists=True)
+ a1_auth = AuthUser(user_id=self.a1.user_id)
+ perms = {
+ 'repositories_groups': {u'test1': 'group.admin', u'test2': 'group.admin'},
+ 'global': set(['hg.admin']),
+ 'repositories': {u'vcs_test_hg': 'repository.admin'}
+ }
+
+ self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
+ perms['repositories'][HG_REPO])
+ self.assertEqual(a1_auth.permissions['repositories_groups'],
+ perms['repositories_groups'])
+
+ def test_propagated_permission_from_users_group(self):
+ # make group
+ self.ug1 = UsersGroupModel().create('G1')
+ # add user to group
+ UsersGroupModel().add_user_to_group(self.ug1, self.u1)
+
+ # set permission to lower
+ new_perm = 'repository.none'
+ RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm)
+ Session.commit()
+ u1_auth = AuthUser(user_id=self.u1.user_id)
+ self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+ new_perm)
+
+ # grant perm for group this should override permission from user
+ new_perm = 'repository.write'
+ RepoModel().grant_users_group_permission(repo=HG_REPO,
+ group_name=self.ug1,
+ perm=new_perm)
+ # check perms
+ u1_auth = AuthUser(user_id=self.u1.user_id)
+ perms = {
+ 'repositories_groups': {},
+ 'global': set([u'hg.create.repository', u'repository.read',
+ u'hg.register.manual_activate']),
+ 'repositories': {u'vcs_test_hg': u'repository.read'}
+ }
+ self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+ new_perm)
+ self.assertEqual(u1_auth.permissions['repositories_groups'],
+ perms['repositories_groups'])
+
+ def test_propagated_permission_from_users_group_lower_weight(self):
+ # make group
+ self.ug1 = UsersGroupModel().create('G1')
+ # add user to group
+ UsersGroupModel().add_user_to_group(self.ug1, self.u1)
+
+ # set permission to lower
+ new_perm_h = 'repository.write'
+ RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
+ perm=new_perm_h)
+ Session.commit()
+ u1_auth = AuthUser(user_id=self.u1.user_id)
+ self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+ new_perm_h)
+
+ # grant perm for group this should NOT override permission from user
+ # since it's lower than granted
+ new_perm_l = 'repository.read'
+ RepoModel().grant_users_group_permission(repo=HG_REPO,
+ group_name=self.ug1,
+ perm=new_perm_l)
+ # check perms
+ u1_auth = AuthUser(user_id=self.u1.user_id)
+ perms = {
+ 'repositories_groups': {},
+ 'global': set([u'hg.create.repository', u'repository.read',
+ u'hg.register.manual_activate']),
+ 'repositories': {u'vcs_test_hg': u'repository.write'}
+ }
+ self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+ new_perm_h)
+ self.assertEqual(u1_auth.permissions['repositories_groups'],
+ perms['repositories_groups'])