aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xREADME.rst4
-rw-r--r--docs/api/api.rst110
-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
-rw-r--r--test.ini4
28 files changed, 1467 insertions, 398 deletions
diff --git a/README.rst b/README.rst
index 99f75e40..70ff375c 100755
--- a/README.rst
+++ b/README.rst
@@ -3,9 +3,9 @@ RhodeCode documentation!
========================
``RhodeCode`` is a fast and powerful management tool for Mercurial_ and GIT_
-with a built in push/pull server and full text search.
+with a built in push/pull server and full text search and code-review.
It works on http/https and has a built in permission/authentication system with
-the ability to authenticate via LDAP or ActiveDirectory. RhodeCode also supports
+the ability to authenticate via LDAP or ActiveDirectory. RhodeCode also provides
simple API so it's easy integrable with existing external systems.
RhodeCode is similar in some respects to github or bitbucket_,
diff --git a/docs/api/api.rst b/docs/api/api.rst
index ade45e6a..814c3215 100644
--- a/docs/api/api.rst
+++ b/docs/api/api.rst
@@ -91,6 +91,7 @@ Get's an user by username, Returns empty result if user is not found.
This command can be executed only using api_key belonging to user with admin
rights.
+
INPUT::
api_key : "<api_key>"
@@ -122,6 +123,7 @@ get_users
Lists all existing users. This command can be executed only using api_key
belonging to user with admin rights.
+
INPUT::
api_key : "<api_key>"
@@ -145,12 +147,14 @@ OUTPUT::
]
error: null
+
create_user
-----------
Creates new user or updates current one if such user exists. This command can
be executed only using api_key belonging to user with admin rights.
+
INPUT::
api_key : "<api_key>"
@@ -174,12 +178,14 @@ OUTPUT::
}
error: null
+
get_users_group
---------------
Gets an existing users group. This command can be executed only using api_key
belonging to user with admin rights.
+
INPUT::
api_key : "<api_key>"
@@ -210,12 +216,14 @@ OUTPUT::
}
error : null
+
get_users_groups
----------------
Lists all existing users groups. This command can be executed only using
api_key belonging to user with admin rights.
+
INPUT::
api_key : "<api_key>"
@@ -253,6 +261,7 @@ create_users_group
Creates new users group. This command can be executed only using api_key
belonging to user with admin rights
+
INPUT::
api_key : "<api_key>"
@@ -270,12 +279,14 @@ OUTPUT::
}
error: null
+
add_user_to_users_group
-----------------------
Adds a user to a users group. This command can be executed only using api_key
belonging to user with admin rights
+
INPUT::
api_key : "<api_key>"
@@ -293,12 +304,14 @@ OUTPUT::
}
error: null
+
get_repo
--------
Gets an existing repository. This command can be executed only using api_key
belonging to user with admin rights
+
INPUT::
api_key : "<api_key>"
@@ -338,12 +351,14 @@ OUTPUT::
}
error: null
+
get_repos
---------
Lists all existing repositories. This command can be executed only using api_key
belonging to user with admin rights
+
INPUT::
api_key : "<api_key>"
@@ -372,6 +387,7 @@ at given revision. It's possible to specify ret_type to show only `files` or
`dirs`. This command can be executed only using api_key belonging to user
with admin rights
+
INPUT::
api_key : "<api_key>"
@@ -395,7 +411,6 @@ OUTPUT::
error: null
-
create_repo
-----------
@@ -405,6 +420,7 @@ If repository name contains "/", all needed repository groups will be created.
For example "foo/bar/baz" will create groups "foo", "bar" (with "foo" as parent),
and create "baz" repository with "bar" as group.
+
INPUT::
api_key : "<api_key>"
@@ -420,54 +436,106 @@ INPUT::
OUTPUT::
result: {
- "id": "<newrepoid>",
- "msg": "Created new repository <reponame>",
+ "id": "<newrepoid>",
+ "msg": "Created new repository <reponame>",
}
error: null
-add_user_to_repo
-----------------
-Add a user to a repository. This command can be executed only using api_key
-belonging to user with admin rights.
-If "perm" is None, user will be removed from the repository.
+grant_user_permission
+---------------------
+
+Grant permission for user on given repository, or update existing one
+if found. This command can be executed only using api_key belonging to user
+with admin rights.
+
INPUT::
api_key : "<api_key>"
- method : "add_user_to_repo"
+ method : "grant_user_permission"
args: {
"repo_name" : "<reponame>",
"username" : "<username>",
- "perm" : "(None|repository.(read|write|admin))",
+ "perm" : "(repository.(none|read|write|admin))",
}
OUTPUT::
result: {
- "msg" : "Added perm: <perm> for <username> in repo: <reponame>"
+ "msg" : "Granted perm: <perm> for user: <username> in repo: <reponame>"
}
error: null
-add_users_group_to_repo
------------------------
-Add a users group to a repository. This command can be executed only using
-api_key belonging to user with admin rights. If "perm" is None, group will
-be removed from the repository.
+revoke_user_permission
+----------------------
+
+Revoke permission for user on given repository. This command can be executed
+only using api_key belonging to user with admin rights.
+
INPUT::
api_key : "<api_key>"
- method : "add_users_group_to_repo"
+ method : "revoke_user_permission"
args: {
"repo_name" : "<reponame>",
- "group_name" : "<groupname>",
- "perm" : "(None|repository.(read|write|admin))",
+ "username" : "<username>",
}
+
OUTPUT::
-
+
+ result: {
+ "msg" : "Revoked perm for user: <suername> in repo: <reponame>"
+ }
+ error: null
+
+
+grant_users_group_permission
+----------------------------
+
+Grant permission for users group on given repository, or update
+existing one if found. This command can be executed only using
+api_key belonging to user with admin rights.
+
+
+INPUT::
+
+ api_key : "<api_key>"
+ method : "grant_users_group_permission"
+ args: {
+ "repo_name" : "<reponame>",
+ "group_name" : "<usersgroupname>",
+ "perm" : "(repository.(none|read|write|admin))",
+ }
+
+OUTPUT::
+
result: {
- "msg" : Added perm: <perm> for <groupname> in repo: <reponame>"
+ "msg" : "Granted perm: <perm> for group: <usersgroupname> in repo: <reponame>"
}
+ error: null
+
+
+revoke_users_group_permission
+-----------------------------
+
+Revoke permission for users group on given repository.This command can be
+executed only using api_key belonging to user with admin rights.
+INPUT::
+
+ api_key : "<api_key>"
+ method : "revoke_users_group_permission"
+ args: {
+ "repo_name" : "<reponame>",
+ "users_group" : "<usersgroupname>",
+ }
+
+OUTPUT::
+
+ result: {
+ "msg" : "Revoked perm for group: <usersgroupname> in repo: <reponame>"
+ }
+ error: null \ No newline at end of file
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'])
diff --git a/test.ini b/test.ini
index cb8885e5..d17b4fe3 100644
--- a/test.ini
+++ b/test.ini
@@ -89,7 +89,7 @@ beaker.cache.lock_dir=/tmp/data/cache/lock
beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
beaker.cache.super_short_term.type=memory
-beaker.cache.super_short_term.expire=10
+beaker.cache.super_short_term.expire=1
beaker.cache.super_short_term.key_length = 256
beaker.cache.short_term.type=memory
@@ -101,7 +101,7 @@ beaker.cache.long_term.expire=36000
beaker.cache.long_term.key_length = 256
beaker.cache.sql_cache_short.type=memory
-beaker.cache.sql_cache_short.expire=10
+beaker.cache.sql_cache_short.expire=1
beaker.cache.sql_cache_short.key_length = 256
beaker.cache.sql_cache_med.type=memory