changeset 3714:7e3d89d9d3a2 beta

- Manage User’s Groups: create, delete, rename, add/remove users inside. by user group admin. In this case, a user's group can be owned by several people thru an owner user's group. Some refactoring of naming, permission handling logic. - remove some code duplicity as well as inconsistent naming
author Marcin Kuzminski <marcin@python-works.com>
date Mon, 08 Apr 2013 22:47:35 +0200
parents e45f8cefd7d9
children 25dbbdae3ed9
files docs/api/api.rst rhodecode/__init__.py rhodecode/config/routing.py rhodecode/controllers/admin/repos.py rhodecode/controllers/admin/repos_groups.py rhodecode/controllers/admin/settings.py rhodecode/controllers/admin/users_groups.py rhodecode/controllers/api/api.py rhodecode/controllers/forks.py rhodecode/lib/auth.py rhodecode/lib/db_manage.py rhodecode/lib/dbmigrate/versions/012_version_1_7_0.py rhodecode/lib/utils.py rhodecode/model/db.py rhodecode/model/forms.py rhodecode/model/repo.py rhodecode/model/repos_group.py rhodecode/model/scm.py rhodecode/model/user.py rhodecode/model/users_group.py rhodecode/model/validators.py rhodecode/templates/admin/repos/repo_edit_perms.html rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html rhodecode/templates/admin/repos_groups/repos_groups_edit.html rhodecode/templates/admin/users_groups/user_group_edit_perms.html rhodecode/templates/admin/users_groups/users_group_edit.html rhodecode/templates/base/base.html rhodecode/templates/base/root.html rhodecode/tests/api/api_base.py rhodecode/tests/fixture.py rhodecode/tests/models/test_permissions.py rhodecode/tests/models/test_users.py rhodecode/tests/models/test_users_group_permissions_on_groups.py rhodecode/tests/test_validators.py
diffstat 34 files changed, 1029 insertions(+), 344 deletions(-) [+]
line wrap: on
line diff
--- a/docs/api/api.rst	Mon Apr 08 20:38:37 2013 +0200
+++ b/docs/api/api.rst	Mon Apr 08 22:47:35 2013 +0200
@@ -518,8 +518,9 @@
     api_key : "<api_key>"
     method :  "create_users_group"
     args:     {
-                "group_name":  "<groupname>",
-                "active":"<bool> = Optional(True)"
+                "group_name": "<groupname>",
+                "owner" :     "<onwer_name_or_id = Optional(=apiuser)>",
+                "active":     "<bool> = Optional(True)"
               }
 
 OUTPUT::
--- a/rhodecode/__init__.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/__init__.py	Mon Apr 08 22:47:35 2013 +0200
@@ -38,7 +38,7 @@
 
 __version__ = ('.'.join((str(each) for each in VERSION[:3])) +
                '.'.join(VERSION[3:]))
-__dbversion__ = 11  # defines current db version for migrations
+__dbversion__ = 12  # defines current db version for migrations
 __platform__ = platform.system()
 __license__ = 'GPLv3'
 __py_version__ = sys.version_info
--- a/rhodecode/config/routing.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/config/routing.py	Mon Apr 08 22:47:35 2013 +0200
@@ -200,6 +200,13 @@
         m.connect("formatted_repos_group", "/repos_groups/{group_name:.*?}.{format}",
                   action="show", conditions=dict(method=["GET"],
                                                  function=check_group))
+
+        #add repo perm member
+        m.connect('set_repo_group_perm_member',
+                  "/set_repo_group_perm_member/{group_name:.*?}",
+             action="set_repo_group_perm_member",
+             conditions=dict(method=["POST"], function=check_group))
+
         # ajax delete repository group perm user
         m.connect('delete_repos_group_user_perm',
                   "/delete_repos_group_user_perm/{group_name:.*?}",
@@ -279,9 +286,20 @@
                   action="show", conditions=dict(method=["GET"]))
 
         #EXTRAS USER ROUTES
-        m.connect("users_group_perm", "/users_groups_perm/{id}",
+        # update
+        m.connect("users_group_perm", "/users_groups/{id}/update_global_perm",
                   action="update_perm", conditions=dict(method=["PUT"]))
 
+        #add user group perm member
+        m.connect('set_user_group_perm_member', "/users_groups/{id}/grant_perm",
+             action="set_user_group_perm_member",
+             conditions=dict(method=["POST"]))
+
+        #ajax delete user group perm
+        m.connect('delete_user_group_perm_member', "/users_groups/{id}/revoke_perm",
+             action="delete_user_group_perm_member",
+             conditions=dict(method=["DELETE"]))
+
     #ADMIN GROUP REST ROUTES
     rmap.resource('group', 'groups',
                   controller='admin/groups', path_prefix=ADMIN_PREFIX)
--- a/rhodecode/controllers/admin/repos.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/controllers/admin/repos.py	Mon Apr 08 22:47:35 2013 +0200
@@ -46,7 +46,7 @@
 from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup,\
     RhodeCodeSetting, RepositoryField
 from rhodecode.model.forms import RepoForm, RepoFieldForm, RepoPermsForm
-from rhodecode.model.scm import ScmModel, GroupList
+from rhodecode.model.scm import ScmModel, RepoGroupList
 from rhodecode.model.repo import RepoModel
 from rhodecode.lib.compat import json
 from sqlalchemy.sql.expression import func
@@ -67,7 +67,7 @@
         super(ReposController, self).__before__()
 
     def __load_defaults(self):
-        acl_groups = GroupList(RepoGroup.query().all(),
+        acl_groups = RepoGroupList(RepoGroup.query().all(),
                                perm_set=['group.write', 'group.admin'])
         c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
         c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
@@ -214,7 +214,7 @@
             if not HasReposGroupPermissionAny('group.admin', 'group.write')(group_name=gr_name):
                 raise HTTPForbidden
 
-        acl_groups = GroupList(RepoGroup.query().all(),
+        acl_groups = RepoGroupList(RepoGroup.query().all(),
                                perm_set=['group.write', 'group.admin'])
         c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
         c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
@@ -330,32 +330,8 @@
     @HasRepoPermissionAllDecorator('repository.admin')
     def set_repo_perm_member(self, repo_name):
         form = RepoPermsForm()().to_python(request.POST)
-
-        perms_new = form['perms_new']
-        perms_updates = form['perms_updates']
-        cur_repo = repo_name
-
-        # update permissions
-        for member, perm, member_type in perms_updates:
-            if member_type == 'user':
-                # this updates existing one
-                RepoModel().grant_user_permission(
-                    repo=cur_repo, user=member, perm=perm
-                )
-            else:
-                RepoModel().grant_users_group_permission(
-                    repo=cur_repo, group_name=member, perm=perm
-                )
-        # set new permissions
-        for member, perm, member_type in perms_new:
-            if member_type == 'user':
-                RepoModel().grant_user_permission(
-                    repo=cur_repo, user=member, perm=perm
-                )
-            else:
-                RepoModel().grant_users_group_permission(
-                    repo=cur_repo, group_name=member, perm=perm
-                )
+        RepoModel()._update_permissions(repo_name, form['perms_new'],
+                                        form['perms_updates'])
         #TODO: implement this
         #action_logger(self.rhodecode_user, 'admin_changed_repo_permissions',
         #              repo_name, self.ip_addr, self.sa)
--- a/rhodecode/controllers/admin/repos_groups.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/controllers/admin/repos_groups.py	Mon Apr 08 22:47:35 2013 +0200
@@ -43,14 +43,15 @@
     HasPermissionAll
 from rhodecode.lib.base import BaseController, render
 from rhodecode.model.db import RepoGroup, Repository
+from rhodecode.model.scm import RepoGroupList
 from rhodecode.model.repos_group import ReposGroupModel
-from rhodecode.model.forms import ReposGroupForm
+from rhodecode.model.forms import ReposGroupForm, RepoGroupPermsForm
 from rhodecode.model.meta import Session
 from rhodecode.model.repo import RepoModel
 from webob.exc import HTTPInternalServerError, HTTPNotFound
 from rhodecode.lib.utils2 import str2bool, safe_int
 from sqlalchemy.sql.expression import func
-from rhodecode.model.scm import GroupList
+
 
 log = logging.getLogger(__name__)
 
@@ -72,7 +73,7 @@
 
         #override the choices for this form, we need to filter choices
         #and display only those we have ADMIN right
-        groups_with_admin_rights = GroupList(RepoGroup.query().all(),
+        groups_with_admin_rights = RepoGroupList(RepoGroup.query().all(),
                                              perm_set=['group.admin'])
         c.repo_groups = RepoGroup.groups_choices(groups=groups_with_admin_rights,
                                                  show_empty_group=allow_empty_group)
@@ -94,12 +95,12 @@
         data = repo_group.get_dict()
         data['group_name'] = repo_group.name
 
-        # fill repository users
+        # fill repository group 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
+        # fill repository group 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})
@@ -118,7 +119,8 @@
     def index(self, format='html'):
         """GET /repos_groups: All items in the collection"""
         # url('repos_groups')
-        group_iter = GroupList(RepoGroup.query().all(), perm_set=['group.admin'])
+        group_iter = RepoGroupList(RepoGroup.query().all(),
+                                   perm_set=['group.admin'])
         sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
         c.groups = sorted(group_iter, key=sk)
         return render('admin/repos_groups/repos_groups_show.html')
@@ -190,7 +192,7 @@
         #           method='put')
         # url('repos_group', group_name=GROUP_NAME)
 
-        c.repos_group = ReposGroupModel()._get_repos_group(group_name)
+        c.repos_group = ReposGroupModel()._get_repo_group(group_name)
         if HasPermissionAll('hg.admin')('group edit'):
             #we're global admin, we're ok and we can create TOP level groups
             allow_empty_group = True
@@ -247,7 +249,7 @@
         #           method='delete')
         # url('repos_group', group_name=GROUP_NAME)
 
-        gr = c.repos_group = ReposGroupModel()._get_repos_group(group_name)
+        gr = c.repos_group = ReposGroupModel()._get_repo_group(group_name)
         repos = gr.repositories.all()
         if repos:
             h.flash(_('This group contains %s repositores and cannot be '
@@ -274,6 +276,24 @@
         return redirect(url('repos_groups'))
 
     @HasReposGroupPermissionAnyDecorator('group.admin')
+    def set_repo_group_perm_member(self, group_name):
+        c.repos_group = ReposGroupModel()._get_repo_group(group_name)
+        form = RepoGroupPermsForm()().to_python(request.POST)
+
+        recursive = form['recursive']
+        # iterate over all members(if in recursive mode) of this groups and
+        # set the permissions !
+        # this can be potentially heavy operation
+        ReposGroupModel()._update_permissions(c.repos_group, form['perms_new'],
+                                              form['perms_updates'], recursive)
+        #TODO: implement this
+        #action_logger(self.rhodecode_user, 'admin_changed_repo_permissions',
+        #              repo_name, self.ip_addr, self.sa)
+        Session().commit()
+        h.flash(_('Repository Group permissions updated'), category='success')
+        return redirect(url('edit_repos_group', group_name=group_name))
+
+    @HasReposGroupPermissionAnyDecorator('group.admin')
     def delete_repos_group_user_perm(self, group_name):
         """
         DELETE an existing repository group permission user
@@ -337,7 +357,7 @@
         """GET /repos_groups/group_name: Show a specific item"""
         # url('repos_group', group_name=GROUP_NAME)
 
-        c.group = c.repos_group = ReposGroupModel()._get_repos_group(group_name)
+        c.group = c.repos_group = ReposGroupModel()._get_repo_group(group_name)
         c.group_repos = c.group.repositories.all()
 
         #overwrite our cached list with current filter
@@ -369,7 +389,7 @@
         """GET /repos_groups/group_name/edit: Form to edit an existing item"""
         # url('edit_repos_group', group_name=GROUP_NAME)
 
-        c.repos_group = ReposGroupModel()._get_repos_group(group_name)
+        c.repos_group = ReposGroupModel()._get_repo_group(group_name)
         #we can only allow moving empty group if it's already a top-level
         #group, ie has no parents, or we're admin
         if HasPermissionAll('hg.admin')('group edit'):
--- a/rhodecode/controllers/admin/settings.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/controllers/admin/settings.py	Mon Apr 08 22:47:35 2013 +0200
@@ -47,7 +47,7 @@
     RhodeCodeSetting, PullRequest, PullRequestReviewers
 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
     ApplicationUiSettingsForm, ApplicationVisualisationForm
-from rhodecode.model.scm import ScmModel, GroupList
+from rhodecode.model.scm import ScmModel, RepoGroupList
 from rhodecode.model.user import UserModel
 from rhodecode.model.repo import RepoModel
 from rhodecode.model.db import User
--- a/rhodecode/controllers/admin/users_groups.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/controllers/admin/users_groups.py	Mon Apr 08 22:47:35 2013 +0200
@@ -34,18 +34,20 @@
 
 from rhodecode.lib import helpers as h
 from rhodecode.lib.exceptions import UserGroupsAssignedException
-from rhodecode.lib.utils2 import safe_unicode, str2bool
-from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
+from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
+from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator,\
+    HasUserGroupPermissionAnyDecorator
 from rhodecode.lib.base import BaseController, render
-
+from rhodecode.model.scm import UserGroupList
 from rhodecode.model.users_group import UserGroupModel
-
+from rhodecode.model.repo import RepoModel
 from rhodecode.model.db import User, UserGroup, UserGroupToPerm,\
     UserGroupRepoToPerm, UserGroupRepoGroupToPerm
-from rhodecode.model.forms import UserGroupForm
+from rhodecode.model.forms import UserGroupForm, UserGroupPermsForm
 from rhodecode.model.meta import Session
 from rhodecode.lib.utils import action_logger
 from sqlalchemy.orm import joinedload
+from webob.exc import HTTPInternalServerError
 
 log = logging.getLogger(__name__)
 
@@ -57,17 +59,82 @@
     #     map.resource('users_group', 'users_groups')
 
     @LoginRequired()
-    @HasPermissionAllDecorator('hg.admin')
     def __before__(self):
         super(UsersGroupsController, self).__before__()
         c.available_permissions = config['available_permissions']
 
+    def __load_data(self, user_group_id):
+        ugroup_repo_perms = UserGroupRepoToPerm.query()\
+            .options(joinedload(UserGroupRepoToPerm.permission))\
+            .options(joinedload(UserGroupRepoToPerm.repository))\
+            .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\
+            .all()
+
+        for gr in ugroup_repo_perms:
+            c.users_group.permissions['repositories'][gr.repository.repo_name]  \
+                = gr.permission.permission_name
+
+        ugroup_group_perms = UserGroupRepoGroupToPerm.query()\
+            .options(joinedload(UserGroupRepoGroupToPerm.permission))\
+            .options(joinedload(UserGroupRepoGroupToPerm.group))\
+            .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\
+            .all()
+
+        for gr in ugroup_group_perms:
+            c.users_group.permissions['repositories_groups'][gr.group.group_name] \
+                = gr.permission.permission_name
+
+        c.group_members_obj = sorted((x.user for x in c.users_group.members),
+                                     key=lambda u: u.username.lower())
+
+        c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
+        c.available_members = sorted(((x.user_id, x.username) for x in
+                                      User.query().all()),
+                                     key=lambda u: u[1].lower())
+        repo_model = RepoModel()
+        c.users_array = repo_model.get_users_js()
+
+        # commented out due to not now supporting assignment for user group
+        # on user group
+        c.users_groups_array = "[]"  # repo_model.get_users_groups_js()
+        c.available_permissions = config['available_permissions']
+
+    def __load_defaults(self, user_group_id):
+        """
+        Load defaults settings for edit, and update
+
+        :param user_group_id:
+        """
+        user_group = UserGroup.get_or_404(user_group_id)
+        data = user_group.get_dict()
+
+        ug_model = UserGroupModel()
+
+        data.update({
+            'create_repo_perm': ug_model.has_perm(user_group,
+                                                  'hg.create.repository'),
+            'fork_repo_perm': ug_model.has_perm(user_group,
+                                                'hg.fork.repository'),
+        })
+
+        # fill user group users
+        for p in user_group.user_user_group_to_perm:
+            data.update({'u_perm_%s' % p.user.username:
+                             p.permission.permission_name})
+
+        return data
+
     def index(self, format='html'):
         """GET /users_groups: All items in the collection"""
         # url('users_groups')
-        c.users_groups_list = UserGroup().query().all()
+
+        group_iter = UserGroupList(UserGroup().query().all(),
+                                   perm_set=['usergroup.admin'])
+        sk = lambda g: g.users_group_name
+        c.users_groups_list = sorted(group_iter, key=sk)
         return render('admin/users_groups/users_groups.html')
 
+    @HasPermissionAllDecorator('hg.admin')
     def create(self):
         """POST /users_groups: Create a new item"""
         # url('users_groups')
@@ -76,7 +143,9 @@
         try:
             form_result = users_group_form.to_python(dict(request.POST))
             UserGroupModel().create(name=form_result['users_group_name'],
-                                     active=form_result['users_group_active'])
+                                    owner=self.rhodecode_user.user_id,
+                                    active=form_result['users_group_active'])
+
             gr = form_result['users_group_name']
             action_logger(self.rhodecode_user,
                           'admin_created_users_group:%s' % gr,
@@ -97,45 +166,13 @@
 
         return redirect(url('users_groups'))
 
+    @HasPermissionAllDecorator('hg.admin')
     def new(self, format='html'):
         """GET /users_groups/new: Form to create a new item"""
         # url('new_users_group')
         return render('admin/users_groups/users_group_add.html')
 
-    def _load_data(self, id):
-        c.users_group.permissions = {
-            'repositories': {},
-            'repositories_groups': {}
-        }
-
-        ugroup_repo_perms = UserGroupRepoToPerm.query()\
-            .options(joinedload(UserGroupRepoToPerm.permission))\
-            .options(joinedload(UserGroupRepoToPerm.repository))\
-            .filter(UserGroupRepoToPerm.users_group_id == id)\
-            .all()
-
-        for gr in ugroup_repo_perms:
-            c.users_group.permissions['repositories'][gr.repository.repo_name]  \
-                = gr.permission.permission_name
-
-        ugroup_group_perms = UserGroupRepoGroupToPerm.query()\
-            .options(joinedload(UserGroupRepoGroupToPerm.permission))\
-            .options(joinedload(UserGroupRepoGroupToPerm.group))\
-            .filter(UserGroupRepoGroupToPerm.users_group_id == id)\
-            .all()
-
-        for gr in ugroup_group_perms:
-            c.users_group.permissions['repositories_groups'][gr.group.group_name] \
-                = gr.permission.permission_name
-
-        c.group_members_obj = sorted((x.user for x in c.users_group.members),
-                                     key=lambda u: u.username.lower())
-        c.group_members = [(x.user_id, x.username) for x in
-                           c.group_members_obj]
-        c.available_members = sorted(((x.user_id, x.username) for x in
-                                      User.query().all()),
-                                     key=lambda u: u[1].lower())
-
+    @HasUserGroupPermissionAnyDecorator('usergroup.admin')
     def update(self, id):
         """PUT /users_groups/id: Update an existing item"""
         # Forms posted to this method should contain a hidden field:
@@ -146,7 +183,7 @@
         # url('users_group', id=ID)
 
         c.users_group = UserGroup.get_or_404(id)
-        self._load_data(id)
+        self.__load_data(id)
 
         available_members = [safe_unicode(x[0]) for x in c.available_members]
 
@@ -188,6 +225,7 @@
 
         return redirect(url('edit_users_group', id=id))
 
+    @HasUserGroupPermissionAnyDecorator('usergroup.admin')
     def delete(self, id):
         """DELETE /users_groups/id: Delete an existing item"""
         # Forms posted to this method should contain a hidden field:
@@ -209,25 +247,71 @@
                     category='error')
         return redirect(url('users_groups'))
 
+    @HasUserGroupPermissionAnyDecorator('usergroup.admin')
+    def set_user_group_perm_member(self, id):
+        """
+        grant permission for given usergroup
+
+        :param id:
+        """
+        user_group = UserGroup.get_or_404(id)
+        form = UserGroupPermsForm()().to_python(request.POST)
+
+        # set the permissions !
+        UserGroupModel()._update_permissions(user_group, form['perms_new'],
+                                            form['perms_updates'])
+        #TODO: implement this
+        #action_logger(self.rhodecode_user, 'admin_changed_repo_permissions',
+        #              repo_name, self.ip_addr, self.sa)
+        Session().commit()
+        h.flash(_('User Group permissions updated'), category='success')
+        return redirect(url('edit_users_group', id=id))
+
+    @HasUserGroupPermissionAnyDecorator('usergroup.admin')
+    def delete_user_group_perm_member(self, id):
+        """
+        DELETE an existing repository group permission user
+
+        :param group_name:
+        """
+        try:
+            obj_type = request.POST.get('obj_type')
+            obj_id = None
+            if obj_type == 'user':
+                obj_id = safe_int(request.POST.get('user_id'))
+            elif obj_type == 'user_group':
+                obj_id = safe_int(request.POST.get('user_group_id'))
+
+            if not c.rhodecode_user.is_admin:
+                if obj_type == 'user' and c.rhodecode_user.user_id == obj_id:
+                    msg = _('Cannot revoke permission for yourself as admin')
+                    h.flash(msg, category='warning')
+                    raise Exception('revoke admin permission on self')
+            if obj_type == 'user':
+                UserGroupModel().revoke_user_permission(user_group=id,
+                                                        user=obj_id)
+            elif obj_type == 'user_group':
+                pass
+            Session().commit()
+        except Exception:
+            log.error(traceback.format_exc())
+            h.flash(_('An error occurred during deletion of group user'),
+                    category='error')
+            raise HTTPInternalServerError()
+
     def show(self, id, format='html'):
         """GET /users_groups/id: Show a specific item"""
         # url('users_group', id=ID)
 
+    @HasUserGroupPermissionAnyDecorator('usergroup.admin')
     def edit(self, id, format='html'):
         """GET /users_groups/id/edit: Form to edit an existing item"""
         # url('edit_users_group', id=ID)
 
         c.users_group = UserGroup.get_or_404(id)
-        self._load_data(id)
+        self.__load_data(id)
 
-        ug_model = UserGroupModel()
-        defaults = c.users_group.get_dict()
-        defaults.update({
-            'create_repo_perm': ug_model.has_perm(c.users_group,
-                                                  'hg.create.repository'),
-            'fork_repo_perm': ug_model.has_perm(c.users_group,
-                                                'hg.fork.repository'),
-        })
+        defaults = self.__load_defaults(id)
 
         return htmlfill.render(
             render('admin/users_groups/users_group_edit.html'),
@@ -236,6 +320,7 @@
             force_defaults=False
         )
 
+    @HasUserGroupPermissionAnyDecorator('usergroup.admin')
     def update_perm(self, id):
         """PUT /users_perm/id: Update an existing item"""
         # url('users_group_perm', id=ID, method='put')
--- a/rhodecode/controllers/api/api.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/controllers/api/api.py	Mon Apr 08 22:47:35 2013 +0200
@@ -537,12 +537,15 @@
         return result
 
     @HasPermissionAllDecorator('hg.admin')
-    def create_users_group(self, apiuser, group_name, active=Optional(True)):
+    def create_users_group(self, apiuser, group_name,
+                           owner=Optional(OAttr('apiuser')),
+                           active=Optional(True)):
         """
         Creates an new usergroup
 
         :param apiuser:
         :param group_name:
+        :param owner:
         :param active:
         """
 
@@ -550,8 +553,14 @@
             raise JSONRPCError("user group `%s` already exist" % group_name)
 
         try:
+            if isinstance(owner, Optional):
+                owner = apiuser.user_id
+
+            owner = get_user_or_error(owner)
             active = Optional.extract(active)
-            ug = UserGroupModel().create(name=group_name, active=active)
+            ug = UserGroupModel().create(name=group_name,
+                                         owner=owner,
+                                         active=active)
             Session().commit()
             return dict(
                 msg='created new user group `%s`' % group_name,
--- a/rhodecode/controllers/forks.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/controllers/forks.py	Mon Apr 08 22:47:35 2013 +0200
@@ -42,7 +42,7 @@
     RhodeCodeUi
 from rhodecode.model.repo import RepoModel
 from rhodecode.model.forms import RepoForkForm
-from rhodecode.model.scm import ScmModel, GroupList
+from rhodecode.model.scm import ScmModel, RepoGroupList
 from rhodecode.lib.utils2 import safe_int
 
 log = logging.getLogger(__name__)
@@ -55,7 +55,7 @@
         super(ForksController, self).__before__()
 
     def __load_defaults(self):
-        acl_groups = GroupList(RepoGroup.query().all(),
+        acl_groups = RepoGroupList(RepoGroup.query().all(),
                                perm_set=['group.write', 'group.admin'])
         c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
         c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
--- a/rhodecode/lib/auth.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/lib/auth.py	Mon Apr 08 22:47:35 2013 +0200
@@ -42,7 +42,8 @@
 from rhodecode.lib.utils2 import str2bool, safe_unicode
 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError,\
     LdapImportError
-from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug
+from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug,\
+    get_user_group_slug
 from rhodecode.lib.auth_ldap import AuthLdap
 
 from rhodecode.model import meta
@@ -410,7 +411,7 @@
                 if x[1] == 'repository.admin']
 
     @property
-    def groups_admin(self):
+    def repository_groups_admin(self):
         """
         Returns list of repository groups you're an admin of
         """
@@ -418,6 +419,14 @@
                 if x[1] == 'group.admin']
 
     @property
+    def user_groups_admin(self):
+        """
+        Returns list of user groups you're an admin of
+        """
+        return [x[0] for x in self.permissions['user_groups'].iteritems()
+                if x[1] == 'usergroup.admin']
+
+    @property
     def ip_allowed(self):
         """
         Checks if ip_addr used in constructor is allowed from defined list of
@@ -693,7 +702,7 @@
 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
+    repository group. All of them have to be meet in order to fulfill the request
     """
 
     def check_permissions(self):
@@ -711,7 +720,7 @@
 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
+    repository group. In order to fulfill the request any of predicates must be meet
     """
 
     def check_permissions(self):
@@ -726,6 +735,42 @@
         return False
 
 
+class HasUserGroupPermissionAllDecorator(PermsDecorator):
+    """
+    Checks for access permission for all given predicates for specific
+    user group. All of them have to be meet in order to fulfill the request
+    """
+
+    def check_permissions(self):
+        group_name = get_user_group_slug(request)
+        try:
+            user_perms = set([self.user_perms['user_groups'][group_name]])
+        except KeyError:
+            return False
+
+        if self.required_perms.issubset(user_perms):
+            return True
+        return False
+
+
+class HasUserGroupPermissionAnyDecorator(PermsDecorator):
+    """
+    Checks for access permission for any of given predicates for specific
+    user group. In order to fulfill the request any of predicates must be meet
+    """
+
+    def check_permissions(self):
+        group_name = get_user_group_slug(request)
+        try:
+            user_perms = set([self.user_perms['user_groups'][group_name]])
+        except KeyError:
+            return False
+
+        if self.required_perms.intersection(user_perms):
+            return True
+        return False
+
+
 #==============================================================================
 # CHECK FUNCTIONS
 #==============================================================================
@@ -865,6 +910,39 @@
         return False
 
 
+class HasUserGroupPermissionAny(PermsFunction):
+    def __call__(self, user_group_name=None, check_location=''):
+        self.user_group_name = user_group_name
+        return super(HasUserGroupPermissionAny, self).__call__(check_location)
+
+    def check_permissions(self):
+        try:
+            self._user_perms = set(
+                [self.user_perms['user_groups'][self.user_group_name]]
+            )
+        except KeyError:
+            return False
+        if self.required_perms.intersection(self._user_perms):
+            return True
+        return False
+
+
+class HasUserGroupPermissionAll(PermsFunction):
+    def __call__(self, user_group_name=None, check_location=''):
+        self.user_group_name = user_group_name
+        return super(HasUserGroupPermissionAll, self).__call__(check_location)
+
+    def check_permissions(self):
+        try:
+            self._user_perms = set(
+                [self.user_perms['user_groups'][self.user_group_name]]
+            )
+        except KeyError:
+            return False
+        if self.required_perms.issubset(self._user_perms):
+            return True
+        return False
+
 #==============================================================================
 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
 #==============================================================================
--- a/rhodecode/lib/db_manage.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/lib/db_manage.py	Mon Apr 08 22:47:35 2013 +0200
@@ -89,7 +89,7 @@
         else:
             destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
         if not destroy:
-            sys.exit('Nothing done')
+            sys.exit('Nothing tables created')
         if destroy:
             Base.metadata.drop_all()
 
@@ -127,7 +127,7 @@
                          'sure You backed up your database before. '
                          'Continue ? [y/n]')
         if not upgrade:
-            sys.exit('Nothing done')
+            sys.exit('No upgrade performed')
 
         repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
                              'rhodecode/lib/dbmigrate')
@@ -292,6 +292,10 @@
             def step_11(self):
                 self.klass.update_repo_info()
 
+            def step_12(self):
+                self.klass.create_permissions()
+                self.klass.populate_default_permissions()
+
         upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
 
         # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
@@ -528,7 +532,8 @@
 
             if default is None:
                 log.debug('missing default permission for group %s adding' % g)
-                ReposGroupModel()._create_default_perms(g)
+                perm_obj = ReposGroupModel()._create_default_perms(g)
+                self.sa.add(perm_obj)
 
     def reset_permissions(self, username):
         """
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/versions/012_version_1_7_0.py	Mon Apr 08 22:47:35 2013 +0200
@@ -0,0 +1,62 @@
+import logging
+import datetime
+
+from sqlalchemy import *
+from sqlalchemy.exc import DatabaseError
+from sqlalchemy.orm import relation, backref, class_mapper, joinedload
+from sqlalchemy.orm.session import Session
+from sqlalchemy.ext.declarative import declarative_base
+
+from rhodecode.lib.dbmigrate.migrate import *
+from rhodecode.lib.dbmigrate.migrate.changeset import *
+
+from rhodecode.model.meta import Base
+from rhodecode.model import meta
+from rhodecode.lib.dbmigrate.versions import _reset_base
+
+log = logging.getLogger(__name__)
+
+
+def upgrade(migrate_engine):
+    """
+    Upgrade operations go here.
+    Don't create your own engine; bind migrate_engine to your metadata
+    """
+    _reset_base(migrate_engine)
+
+    #==========================================================================
+    # UserUserGroupToPerm
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_7_0 import UserUserGroupToPerm
+    tbl = UserUserGroupToPerm.__table__
+    tbl.create()
+
+    #==========================================================================
+    # UserGroupUserGroupToPerm
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_7_0 import UserGroupUserGroupToPerm
+    tbl = UserGroupUserGroupToPerm.__table__
+    tbl.create()
+
+    #==========================================================================
+    # UserGroup
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_7_0 import UserGroup
+    tbl = UserGroup.__table__
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=False, default=None)
+    # create username column
+    user_id.create(table=tbl)
+
+    #==========================================================================
+    # UserGroup
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_7_0 import RepoGroup
+    tbl = RepoGroup.__table__
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=False, default=None)
+    # create username column
+    user_id.create(table=tbl)
+
+
+def downgrade(migrate_engine):
+    meta = MetaData()
+    meta.bind = migrate_engine
--- a/rhodecode/lib/utils.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/lib/utils.py	Mon Apr 08 22:47:35 2013 +0200
@@ -53,7 +53,7 @@
 
 from rhodecode.model import meta
 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
-    UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation
+    UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation, UserGroup
 from rhodecode.model.meta import Session
 from rhodecode.model.repos_group import ReposGroupModel
 from rhodecode.lib.utils2 import safe_str, safe_unicode
@@ -114,6 +114,14 @@
     return _group
 
 
+def get_user_group_slug(request):
+    _group = request.environ['pylons.routes_dict'].get('id')
+    _group = UserGroup.get(_group)
+    if _group:
+        _group = _group.users_group_name
+    return _group
+
+
 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
     """
     Action logger for various actions made by users
@@ -372,6 +380,7 @@
     # last element is repo in nested groups structure
     groups = groups[:-1]
     rgm = ReposGroupModel(sa)
+    owner = User.get_first_admin()
     for lvl, group_name in enumerate(groups):
         group_name = '/'.join(groups[:lvl] + [group_name])
         group = RepoGroup.get_by_group_name(group_name)
@@ -382,13 +391,16 @@
             break
 
         if group is None:
-            log.debug('creating group level: %s group_name: %s' % (lvl,
-                                                                   group_name))
+            log.debug('creating group level: %s group_name: %s'
+                      % (lvl, group_name))
             group = RepoGroup(group_name, parent)
             group.group_description = desc
+            group.user = owner
             sa.add(group)
-            rgm._create_default_perms(group)
+            perm_obj = rgm._create_default_perms(group)
+            sa.add(perm_obj)
             sa.flush()
+
         parent = group
     return group
 
@@ -409,9 +421,7 @@
     from rhodecode.model.scm import ScmModel
     sa = meta.Session()
     rm = RepoModel()
-    user = sa.query(User).filter(User.admin == True).first()
-    if user is None:
-        raise Exception('Missing administrative account!')
+    user = User.get_first_admin()
     added = []
 
     ##creation defaults
--- a/rhodecode/model/db.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/model/db.py	Mon Apr 08 22:47:35 2013 +0200
@@ -131,6 +131,11 @@
 
     @classmethod
     def getAll(cls):
+        # deprecated and left for backward compatibility
+        return cls.get_all()
+
+    @classmethod
+    def get_all(cls):
         return cls.query().all()
 
     @classmethod
@@ -490,6 +495,13 @@
         Session().add(self)
         log.debug('updated user %s lastlogin' % self.username)
 
+    @classmethod
+    def get_first_admin(cls):
+        user = User.query().filter(User.admin == True).first()
+        if user is None:
+            raise Exception('Missing administrative account!')
+        return user
+
     def get_api_data(self):
         """
         Common function for generating user related data for API
@@ -616,13 +628,18 @@
     users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
     users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
     inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
 
     members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
     users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
     users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
+    user_user_group_to_perm = relationship('UserUserGroupToPerm ', cascade='all')
+    user = relationship('User')
 
     def __unicode__(self):
-        return u'<userGroup(%s)>' % (self.users_group_name)
+        return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
+                                      self.users_group_id,
+                                      self.users_group_name)
 
     @classmethod
     def get_by_group_name(cls, group_name, cache=False,
@@ -1229,19 +1246,20 @@
     group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
     group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
     enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
 
     repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
     users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
-
     parent_group = relationship('RepoGroup', remote_side=group_id)
+    user = relationship('User')
 
     def __init__(self, group_name='', parent_group=None):
         self.group_name = group_name
         self.parent_group = parent_group
 
     def __unicode__(self):
-        return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
-                                  self.group_name)
+        return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
+                                      self.group_name)
 
     @classmethod
     def groups_choices(cls, groups=None, show_empty_group=True):
@@ -1397,6 +1415,11 @@
         ('group.write', _('Repository group write access')),
         ('group.admin', _('Repository group admin access')),
 
+        ('usergroup.none', _('User group no access')),
+        ('usergroup.read', _('User group read access')),
+        ('usergroup.write', _('User group write access')),
+        ('usergroup.admin', _('User group admin access')),
+
         ('hg.admin', _('RhodeCode Administrator')),
         ('hg.create.none', _('Repository creation disabled')),
         ('hg.create.repository', _('Repository creation enabled')),
@@ -1422,10 +1445,15 @@
         'group.write': 3,
         'group.admin': 4,
 
+        'usergroup.none': 0,
+        'usergroup.read': 1,
+        'usergroup.write': 3,
+        'usergroup.admin': 4,
+
         'hg.fork.none': 0,
         'hg.fork.repository': 1,
         'hg.create.none': 0,
-        'hg.create.repository':1
+        'hg.create.repository': 1
     }
 
     permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -1459,6 +1487,15 @@
 
         return q.all()
 
+    @classmethod
+    def get_default_user_group_perms(cls, default_user_id):
+        q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
+         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
+         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
+         .filter(UserUserGroupToPerm.user_id == default_user_id)
+
+        return q.all()
+
 
 class UserRepoToPerm(Base, BaseModel):
     __tablename__ = 'repo_to_perm'
@@ -1486,7 +1523,36 @@
         return n
 
     def __unicode__(self):
-        return u'<user:%s => %s >' % (self.user, self.repository)
+        return u'<%s => %s >' % (self.user, self.repository)
+
+
+class UserUserGroupToPerm(Base, BaseModel):
+    __tablename__ = 'user_user_group_to_perm'
+    __table_args__ = (
+        UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+    user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
+    user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
+
+    user = relationship('User')
+    user_group = relationship('UserGroup')
+    permission = relationship('Permission')
+
+    @classmethod
+    def create(cls, user, user_group, permission):
+        n = cls()
+        n.user = user
+        n.user_group = user_group
+        n.permission = permission
+        Session().add(n)
+        return n
+
+    def __unicode__(self):
+        return u'<%s => %s >' % (self.user, self.user_group)
 
 
 class UserToPerm(Base, BaseModel):
@@ -1533,6 +1599,36 @@
         return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
 
 
+#TODO; not sure if this will be ever used
+class UserGroupUserGroupToPerm(Base, BaseModel):
+    __tablename__ = 'user_group_user_group_to_perm'
+    __table_args__ = (
+        UniqueConstraint('user_group_id', 'user_group_id', 'permission_id'),
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+    user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    target_user_group_id = Column("target_users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
+    user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
+
+    target_user_group = relationship('UserGroup', remote_side=target_user_group_id, primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
+    user_group = relationship('UserGroup', remote_side=user_group_id, primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
+    permission = relationship('Permission')
+
+    @classmethod
+    def create(cls, target_user_group, user_group, permission):
+        n = cls()
+        n.target_user_group = target_user_group
+        n.user_group = user_group
+        n.permission = permission
+        Session().add(n)
+        return n
+
+    def __unicode__(self):
+        return u'<UserGroup:%s => %s >' % (self.target_user_group, self.user_group)
+
+
 class UserGroupToPerm(Base, BaseModel):
     __tablename__ = 'users_group_to_perm'
     __table_args__ = (
--- a/rhodecode/model/forms.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/model/forms.py	Mon Apr 08 22:47:35 2013 +0200
@@ -134,9 +134,7 @@
                                       testValueList=True,
                                       if_missing=None, not_empty=True))
         enable_locking = v.StringBoolean(if_missing=False)
-        recursive = v.StringBoolean(if_missing=False)
-        chained_validators = [v.ValidReposGroup(edit, old_data),
-                              v.ValidPerms('group')]
+        chained_validators = [v.ValidReposGroup(edit, old_data)]
 
     return _ReposGroupForm
 
@@ -207,10 +205,27 @@
     class _RepoPermsForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = False
-        chained_validators = [v.ValidPerms()]
+        chained_validators = [v.ValidPerms(type_='repo')]
     return _RepoPermsForm
 
 
+def RepoGroupPermsForm():
+    class _RepoGroupPermsForm(formencode.Schema):
+        allow_extra_fields = True
+        filter_extra_fields = False
+        recursive = v.StringBoolean(if_missing=False)
+        chained_validators = [v.ValidPerms(type_='repo_group')]
+    return _RepoGroupPermsForm
+
+
+def UserGroupPermsForm():
+    class _UserPermsForm(formencode.Schema):
+        allow_extra_fields = True
+        filter_extra_fields = False
+        chained_validators = [v.ValidPerms(type_='user_group')]
+    return _UserPermsForm
+
+
 def RepoFieldForm():
     class _RepoFieldForm(formencode.Schema):
         filter_extra_fields = True
--- a/rhodecode/model/repo.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/model/repo.py	Mon Apr 08 22:47:35 2013 +0200
@@ -52,14 +52,33 @@
     cls = Repository
     URL_SEPARATOR = Repository.url_sep()
 
-    def __get_users_group(self, users_group):
+    def _get_user_group(self, users_group):
         return self._get_instance(UserGroup, users_group,
                                   callback=UserGroup.get_by_group_name)
 
-    def _get_repos_group(self, repos_group):
+    def _get_repo_group(self, repos_group):
         return self._get_instance(RepoGroup, repos_group,
                                   callback=RepoGroup.get_by_group_name)
 
+    def _create_default_perms(self, repository, private):
+        # create default permission
+        default = 'repository.read'
+        def_user = User.get_by_username('default')
+        for p in def_user.user_perms:
+            if p.permission.permission_name.startswith('repository.'):
+                default = p.permission.permission_name
+                break
+
+        default_perm = 'repository.none' if private else default
+
+        repo_to_perm = UserRepoToPerm()
+        repo_to_perm.permission = Permission.get_by_key(default_perm)
+
+        repo_to_perm.repository = repository
+        repo_to_perm.user_id = def_user.user_id
+
+        return repo_to_perm
+
     @LazyProperty
     def repos_path(self):
         """
@@ -336,7 +355,7 @@
 
         owner = self._get_user(owner)
         fork_of = self._get_repo(fork_of)
-        repos_group = self._get_repos_group(repos_group)
+        repos_group = self._get_repo_group(repos_group)
         try:
 
             # repo name is just a name of repository
@@ -369,26 +388,6 @@
 
             self.sa.add(new_repo)
 
-            def _create_default_perms():
-                # create default permission
-                repo_to_perm = UserRepoToPerm()
-                default = 'repository.read'
-                for p in User.get_by_username('default').user_perms:
-                    if p.permission.permission_name.startswith('repository.'):
-                        default = p.permission.permission_name
-                        break
-
-                default_perm = 'repository.none' if private else default
-
-                repo_to_perm.permission_id = self.sa.query(Permission)\
-                        .filter(Permission.permission_name == default_perm)\
-                        .one().permission_id
-
-                repo_to_perm.repository = new_repo
-                repo_to_perm.user_id = User.get_by_username('default').user_id
-
-                self.sa.add(repo_to_perm)
-
             if fork_of:
                 if copy_fork_permissions:
                     repo = fork_of
@@ -405,9 +404,11 @@
                         UserGroupRepoToPerm.create(perm.users_group, new_repo,
                                                     perm.permission)
                 else:
-                    _create_default_perms()
+                    perm_obj = self._create_default_perms(new_repo, private)
+                    self.sa.add(perm_obj)
             else:
-                _create_default_perms()
+                perm_obj = self._create_default_perms(new_repo, private)
+                self.sa.add(perm_obj)
 
             if not just_db:
                 self.__create_repo(repo_name, repo_type,
@@ -456,6 +457,35 @@
             enable_statistics, enable_locking, enable_downloads
         )
 
+    def _update_permissions(self, repo, perms_new=None,
+                            perms_updates=None):
+        if not perms_new:
+            perms_new = []
+        if not perms_updates:
+            perms_updates = []
+
+        # update permissions
+        for member, perm, member_type in perms_updates:
+            if member_type == 'user':
+                # this updates existing one
+                self.grant_user_permission(
+                    repo=repo, user=member, perm=perm
+                )
+            else:
+                self.grant_users_group_permission(
+                    repo=repo, group_name=member, perm=perm
+                )
+        # set new permissions
+        for member, perm, member_type in perms_new:
+            if member_type == 'user':
+                self.grant_user_permission(
+                    repo=repo, user=member, perm=perm
+                )
+            else:
+                self.grant_users_group_permission(
+                    repo=repo, group_name=member, perm=perm
+                )
+
     def create_fork(self, form_data, cur_user):
         """
         Simple wrapper into executing celery task for fork creation
@@ -559,7 +589,7 @@
         :param perm: Instance of Permission, or permission_name
         """
         repo = self._get_repo(repo)
-        group_name = self.__get_users_group(group_name)
+        group_name = self._get_user_group(group_name)
         permission = self._get_perm(perm)
 
         # check if we have that permission already
@@ -587,7 +617,7 @@
             or user group name
         """
         repo = self._get_repo(repo)
-        group_name = self.__get_users_group(group_name)
+        group_name = self._get_user_group(group_name)
 
         obj = self.sa.query(UserGroupRepoToPerm)\
             .filter(UserGroupRepoToPerm.repository == repo)\
--- a/rhodecode/model/repos_group.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/model/repos_group.py	Mon Apr 08 22:47:35 2013 +0200
@@ -42,11 +42,11 @@
 
     cls = RepoGroup
 
-    def __get_users_group(self, users_group):
+    def _get_user_group(self, users_group):
         return self._get_instance(UserGroup, users_group,
                                   callback=UserGroup.get_by_group_name)
 
-    def _get_repos_group(self, repos_group):
+    def _get_repo_group(self, repos_group):
         return self._get_instance(RepoGroup, repos_group,
                                   callback=RepoGroup.get_by_group_name)
 
@@ -61,21 +61,19 @@
 
     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:
+        def_user = User.get_by_username('default')
+        for p in def_user.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 = UserRepoGroupToPerm()
+        repo_group_to_perm.permission = Permission.get_by_key(default_perm)
 
         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)
+        repo_group_to_perm.user_id = def_user.user_id
+        return repo_group_to_perm
 
     def __create_group(self, group_name):
         """
@@ -143,12 +141,14 @@
     def create(self, group_name, group_description, owner, parent=None, just_db=False):
         try:
             new_repos_group = RepoGroup()
+            new_repos_group.user = self._get_user(owner)
             new_repos_group.group_description = group_description or group_name
-            new_repos_group.parent_group = self._get_repos_group(parent)
+            new_repos_group.parent_group = self._get_repo_group(parent)
             new_repos_group.group_name = new_repos_group.get_new_name(group_name)
 
             self.sa.add(new_repos_group)
-            self._create_default_perms(new_repos_group)
+            perm_obj = self._create_default_perms(new_repos_group)
+            self.sa.add(perm_obj)
 
             #create an ADMIN permission for owner, later owner should go into
             #the owner field of groups
@@ -176,7 +176,7 @@
 
         def _set_perm_user(obj, user, perm):
             if isinstance(obj, RepoGroup):
-                ReposGroupModel().grant_user_permission(
+                self.grant_user_permission(
                     repos_group=obj, user=user, perm=perm
                 )
             elif isinstance(obj, Repository):
@@ -193,7 +193,7 @@
 
         def _set_perm_group(obj, users_group, perm):
             if isinstance(obj, RepoGroup):
-                ReposGroupModel().grant_users_group_permission(
+                self.grant_users_group_permission(
                     repos_group=obj, group_name=users_group, perm=perm
                 )
             elif isinstance(obj, Repository):
@@ -237,14 +237,7 @@
     def update(self, repos_group, form_data):
 
         try:
-            repos_group = self._get_repos_group(repos_group)
-            recursive = form_data['recursive']
-            # iterate over all members(if in recursive mode) of this groups and
-            # set the permissions !
-            # this can be potentially heavy operation
-            self._update_permissions(repos_group, form_data['perms_new'],
-                                     form_data['perms_updates'], recursive)
-
+            repos_group = self._get_repo_group(repos_group)
             old_path = repos_group.full_path
 
             # change properties
@@ -288,7 +281,7 @@
             raise
 
     def delete(self, repos_group, force_delete=False):
-        repos_group = self._get_repos_group(repos_group)
+        repos_group = self._get_repo_group(repos_group)
         try:
             self.sa.delete(repos_group)
             self.__delete_group(repos_group, force_delete)
@@ -307,7 +300,7 @@
         :param recursive: recurse to all children of group
         """
         from rhodecode.model.repo import RepoModel
-        repos_group = self._get_repos_group(repos_group)
+        repos_group = self._get_repo_group(repos_group)
 
         for el in repos_group.recursive_groups_and_repos():
             if not recursive:
@@ -346,7 +339,7 @@
         :param perm: Instance of Permission, or permission_name
         """
 
-        repos_group = self._get_repos_group(repos_group)
+        repos_group = self._get_repo_group(repos_group)
         user = self._get_user(user)
         permission = self._get_perm(perm)
 
@@ -373,7 +366,7 @@
         :param user: Instance of User, user_id or username
         """
 
-        repos_group = self._get_repos_group(repos_group)
+        repos_group = self._get_repo_group(repos_group)
         user = self._get_user(user)
 
         obj = self.sa.query(UserRepoGroupToPerm)\
@@ -395,8 +388,8 @@
             or user 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)
+        repos_group = self._get_repo_group(repos_group)
+        group_name = self._get_user_group(group_name)
         permission = self._get_perm(perm)
 
         # check if we have that permission already
@@ -424,8 +417,8 @@
         :param group_name: Instance of UserGroup, users_group_id,
             or user group name
         """
-        repos_group = self._get_repos_group(repos_group)
-        group_name = self.__get_users_group(group_name)
+        repos_group = self._get_repo_group(repos_group)
+        group_name = self._get_user_group(group_name)
 
         obj = self.sa.query(UserGroupRepoGroupToPerm)\
             .filter(UserGroupRepoGroupToPerm.group == repos_group)\
--- a/rhodecode/model/scm.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/model/scm.py	Mon Apr 08 22:47:35 2013 +0200
@@ -46,7 +46,8 @@
 from rhodecode.lib import helpers as h
 from rhodecode.lib.utils2 import safe_str, safe_unicode, get_server_url,\
     _set_extras
-from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny
+from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny,\
+    HasUserGroupPermissionAnyDecorator, HasUserGroupPermissionAny
 from rhodecode.lib.utils import get_filesystem_repos, make_ui, \
     action_logger, REMOVED_REPO_PAT
 from rhodecode.model import BaseModel
@@ -165,36 +166,58 @@
             yield tmp_d
 
 
-class GroupList(object):
-
-    def __init__(self, db_repo_group_list, perm_set=None):
+class _PermCheckIterator(object):
+    def __init__(self, obj_list, obj_attr, perm_set, perm_checker):
         """
-        Creates iterator from given list of group objects, additionally
+        Creates iterator from given list of objects, additionally
         checking permission for them from perm_set var
 
-        :param db_repo_group_list:
-        :param perm_set: list of permissons to check
+        :param obj_list: list of db objects
+        :param obj_attr: attribute of object to pass into perm_checker
+        :param perm_set: list of permissions to check
+        :param perm_checker: callable to check permissions against
         """
-        self.db_repo_group_list = db_repo_group_list
-        if not perm_set:
-            perm_set = ['group.read', 'group.write', 'group.admin']
+        self.obj_list = obj_list
+        self.obj_attr = obj_attr
         self.perm_set = perm_set
+        self.perm_checker = perm_checker
 
     def __len__(self):
-        return len(self.db_repo_group_list)
+        return len(self.obj_list)
 
     def __repr__(self):
         return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
 
     def __iter__(self):
-        for dbgr in self.db_repo_group_list:
+        for db_obj in self.obj_list:
             # check permission at this level
-            if not HasReposGroupPermissionAny(
-                *self.perm_set
-            )(dbgr.group_name, 'get group repo check'):
+            name = getattr(db_obj, self.obj_attr, None)
+            if not self.perm_checker(*self.perm_set)(name, self.__class__.__name__):
                 continue
 
-            yield dbgr
+            yield db_obj
+
+
+class RepoGroupList(_PermCheckIterator):
+
+    def __init__(self, db_repo_group_list, perm_set=None):
+        if not perm_set:
+            perm_set = ['group.read', 'group.write', 'group.admin']
+
+        super(RepoGroupList, self).__init__(obj_list=db_repo_group_list,
+                    obj_attr='group_name', perm_set=perm_set,
+                    perm_checker=HasReposGroupPermissionAny)
+
+
+class UserGroupList(_PermCheckIterator):
+
+    def __init__(self, db_user_group_list, perm_set=None):
+        if not perm_set:
+            perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
+
+        super(UserGroupList, self).__init__(obj_list=db_user_group_list,
+                    obj_attr='users_group_name', perm_set=perm_set,
+                    perm_checker=HasUserGroupPermissionAny)
 
 
 class ScmModel(BaseModel):
@@ -293,7 +316,7 @@
         if all_groups is None:
             all_groups = RepoGroup.query()\
                 .filter(RepoGroup.group_parent_id == None).all()
-        return [x for x in GroupList(all_groups)]
+        return [x for x in RepoGroupList(all_groups)]
 
     def mark_for_invalidation(self, repo_name):
         """
--- a/rhodecode/model/user.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/model/user.py	Mon Apr 08 22:47:35 2013 +0200
@@ -425,9 +425,11 @@
         """
         RK = 'repositories'
         GK = 'repositories_groups'
+        UK = 'user_groups'
         GLOBAL = 'global'
         user.permissions[RK] = {}
         user.permissions[GK] = {}
+        user.permissions[UK] = {}
         user.permissions[GLOBAL] = set()
 
         def _choose_perm(new_perm, cur_perm):
@@ -450,6 +452,7 @@
 
         default_repo_perms = Permission.get_default_perms(default_user_id)
         default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
+        default_user_group_perms = Permission.get_default_user_group_perms(default_user_id)
 
         if user.is_admin:
             #==================================================================
@@ -469,6 +472,12 @@
                 rg_k = perm.UserRepoGroupToPerm.group.group_name
                 p = 'group.admin'
                 user.permissions[GK][rg_k] = p
+
+            # user groups
+            for perm in default_user_group_perms:
+                u_k = perm.UserUserGroupToPerm.user_group.users_group_name
+                p = 'usergroup.admin'
+                user.permissions[UK][u_k] = p
             return user
 
         #==================================================================
@@ -504,6 +513,13 @@
             p = perm.Permission.permission_name
             user.permissions[GK][rg_k] = p
 
+        # defaults for user groups taken from default user permission
+        # on given user group
+        for perm in default_user_group_perms:
+            u_k = perm.UserUserGroupToPerm.user_group.users_group_name
+            p = perm.Permission.permission_name
+            user.permissions[UK][u_k] = p
+
         #======================================================================
         # !! OVERRIDE GLOBALS !! with user permissions if any found
         #======================================================================
@@ -588,15 +604,7 @@
 
         # user explicit permissions for repositories, overrides any specified
         # by the group permission
-        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 = Permission.get_default_perms(uid)
         for perm in user_repo_perms:
             r_k = perm.UserRepoToPerm.repository.repo_name
             cur_perm = user.permissions[RK][r_k]
@@ -639,14 +647,7 @@
             user.permissions[GK][g_k] = p
 
         # user explicit permissions for repository 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(UserRepoGroupToPerm.user_id == uid)\
-         .all()
-
+        user_repo_groups_perms = Permission.get_default_group_perms(uid)
         for perm in user_repo_groups_perms:
             rg_k = perm.UserRepoGroupToPerm.group.group_name
             p = perm.Permission.permission_name
@@ -655,6 +656,19 @@
                 p = _choose_perm(p, cur_perm)
             user.permissions[GK][rg_k] = p
 
+        #======================================================================
+        # !! PERMISSIONS FOR USER GROUPS !!
+        #======================================================================
+        #user explicit permission for user groups
+        user_user_groups_perms = Permission.get_default_user_group_perms(uid)
+        for perm in user_user_groups_perms:
+            u_k = perm.UserUserGroupToPerm.user_group.users_group_name
+            p = perm.Permission.permission_name
+            cur_perm = user.permissions[UK][u_k]
+            if not explicit:
+                p = _choose_perm(p, cur_perm)
+            user.permissions[UK][u_k] = p
+
         return user
 
     def has_perm(self, user, perm):
--- a/rhodecode/model/users_group.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/model/users_group.py	Mon Apr 08 22:47:35 2013 +0200
@@ -29,7 +29,7 @@
 
 from rhodecode.model import BaseModel
 from rhodecode.model.db import UserGroupMember, UserGroup,\
-    UserGroupRepoToPerm, Permission, UserGroupToPerm, User
+    UserGroupRepoToPerm, Permission, UserGroupToPerm, User, UserUserGroupToPerm
 from rhodecode.lib.exceptions import UserGroupsAssignedException
 
 log = logging.getLogger(__name__)
@@ -39,26 +39,74 @@
 
     cls = UserGroup
 
-    def __get_users_group(self, users_group):
+    def _get_user_group(self, users_group):
         return self._get_instance(UserGroup, users_group,
                                   callback=UserGroup.get_by_group_name)
 
+    def _create_default_perms(self, user_group):
+        # create default permission
+        default_perm = 'usergroup.read'
+        def_user = User.get_by_username('default')
+        for p in def_user.user_perms:
+            if p.permission.permission_name.startswith('usergroup.'):
+                default_perm = p.permission.permission_name
+                break
+
+        user_group_to_perm = UserUserGroupToPerm()
+        user_group_to_perm.permission = Permission.get_by_key(default_perm)
+
+        user_group_to_perm.user_group = user_group
+        user_group_to_perm.user_id = def_user.user_id
+        return user_group_to_perm
+
+    def _update_permissions(self, user_group, perms_new=None,
+                            perms_updates=None):
+        if not perms_new:
+            perms_new = []
+        if not perms_updates:
+            perms_updates = []
+
+        # update permissions
+        for member, perm, member_type in perms_updates:
+            if member_type == 'user':
+                # this updates existing one
+                self.grant_user_permission(
+                    user_group=user_group, user=member, perm=perm
+                )
+            else:
+                self.grant_users_group_permission(
+                    user_group=user_group, group_name=member, perm=perm
+                )
+        # set new permissions
+        for member, perm, member_type in perms_new:
+            if member_type == 'user':
+                self.grant_user_permission(
+                    user_group=user_group, user=member, perm=perm
+                )
+            else:
+                self.grant_users_group_permission(
+                    user_group=user_group, group_name=member, perm=perm
+                )
+
     def get(self, users_group_id, cache=False):
         return UserGroup.get(users_group_id)
 
     def get_group(self, users_group):
-        return self.__get_users_group(users_group)
+        return self._get_user_group(users_group)
 
     def get_by_name(self, name, cache=False, case_insensitive=False):
         return UserGroup.get_by_group_name(name, cache, case_insensitive)
 
-    def create(self, name, active=True):
+    def create(self, name, owner, active=True):
         try:
-            new = UserGroup()
-            new.users_group_name = name
-            new.users_group_active = active
-            self.sa.add(new)
-            return new
+            new_user_group = UserGroup()
+            new_user_group.user = self._get_user(owner)
+            new_user_group.users_group_name = name
+            new_user_group.users_group_active = active
+            self.sa.add(new_user_group)
+            perm_obj = self._create_default_perms(new_user_group)
+            self.sa.add(perm_obj)
+            return new_user_group
         except Exception:
             log.error(traceback.format_exc())
             raise
@@ -66,7 +114,7 @@
     def update(self, users_group, form_data):
 
         try:
-            users_group = self.__get_users_group(users_group)
+            users_group = self._get_user_group(users_group)
 
             for k, v in form_data.items():
                 if k == 'users_group_members':
@@ -96,7 +144,7 @@
         :param force:
         """
         try:
-            users_group = self.__get_users_group(users_group)
+            users_group = self._get_user_group(users_group)
 
             # check if this group is not assigned to repo
             assigned_groups = UserGroupRepoToPerm.query()\
@@ -112,7 +160,7 @@
             raise
 
     def add_user_to_group(self, users_group, user):
-        users_group = self.__get_users_group(users_group)
+        users_group = self._get_user_group(users_group)
         user = self._get_user(user)
 
         for m in users_group.members:
@@ -135,7 +183,7 @@
             raise
 
     def remove_user_from_group(self, users_group, user):
-        users_group = self.__get_users_group(users_group)
+        users_group = self._get_user_group(users_group)
         user = self._get_user(user)
 
         users_group_member = None
@@ -157,7 +205,7 @@
             return False
 
     def has_perm(self, users_group, perm):
-        users_group = self.__get_users_group(users_group)
+        users_group = self._get_user_group(users_group)
         perm = self._get_perm(perm)
 
         return UserGroupToPerm.query()\
@@ -165,7 +213,7 @@
             .filter(UserGroupToPerm.permission == perm).scalar() is not None
 
     def grant_perm(self, users_group, perm):
-        users_group = self.__get_users_group(users_group)
+        users_group = self._get_user_group(users_group)
         perm = self._get_perm(perm)
 
         # if this permission is already granted skip it
@@ -182,7 +230,7 @@
         self.sa.add(new)
 
     def revoke_perm(self, users_group, perm):
-        users_group = self.__get_users_group(users_group)
+        users_group = self._get_user_group(users_group)
         perm = self._get_perm(perm)
 
         obj = UserGroupToPerm.query()\
@@ -190,3 +238,58 @@
             .filter(UserGroupToPerm.permission == perm).scalar()
         if obj:
             self.sa.delete(obj)
+
+    def grant_user_permission(self, user_group, user, perm):
+        """
+        Grant permission for user on given user group, or update
+        existing one if found
+
+        :param user_group: Instance of UserGroup, users_group_id,
+            or users_group_name
+        :param user: Instance of User, user_id or username
+        :param perm: Instance of Permission, or permission_name
+        """
+
+        user_group = self._get_user_group(user_group)
+        user = self._get_user(user)
+        permission = self._get_perm(perm)
+
+        # check if we have that permission already
+        obj = self.sa.query(UserUserGroupToPerm)\
+            .filter(UserUserGroupToPerm.user == user)\
+            .filter(UserUserGroupToPerm.user_group == user_group)\
+            .scalar()
+        if obj is None:
+            # create new !
+            obj = UserUserGroupToPerm()
+        obj.user_group = user_group
+        obj.user = user
+        obj.permission = permission
+        self.sa.add(obj)
+        log.debug('Granted perm %s to %s on %s' % (perm, user, user_group))
+
+    def revoke_user_permission(self, user_group, user):
+        """
+        Revoke permission for user on given repository group
+
+        :param user_group: Instance of ReposGroup, repositories_group_id,
+            or repositories_group name
+        :param user: Instance of User, user_id or username
+        """
+
+        user_group = self._get_user_group(user_group)
+        user = self._get_user(user)
+
+        obj = self.sa.query(UserUserGroupToPerm)\
+            .filter(UserUserGroupToPerm.user == user)\
+            .filter(UserUserGroupToPerm.user_group == user_group)\
+            .scalar()
+        if obj:
+            self.sa.delete(obj)
+            log.debug('Revoked perm on %s on %s' % (user_group, user))
+
+    def grant_users_group_permission(self, user_group, group_name, perm):
+        raise NotImplementedError()
+
+    def revoke_users_group_permission(self, user_group, group_name):
+        raise NotImplementedError()
--- a/rhodecode/model/validators.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/model/validators.py	Mon Apr 08 22:47:35 2013 +0200
@@ -546,10 +546,12 @@
 
 
 def ValidPerms(type_='repo'):
-    if type_ == 'group':
+    if type_ == 'repo_group':
         EMPTY_PERM = 'group.none'
     elif type_ == 'repo':
         EMPTY_PERM = 'repository.none'
+    elif type_ == 'user_group':
+        EMPTY_PERM = 'usergroup.none'
 
     class _validator(formencode.validators.FancyValidator):
         messages = {
--- a/rhodecode/templates/admin/repos/repo_edit_perms.html	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/templates/admin/repos/repo_edit_perms.html	Mon Apr 08 22:47:35 2013 +0200
@@ -29,7 +29,7 @@
             </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)}')">
+                <span class="delete_icon action_button" onclick="ajaxActionRevoke(${r2p.user.user_id}, 'user', '${'id%s'%id(r2p.user.username)}')">
                 ${_('revoke')}
                 </span>
               %endif
@@ -54,7 +54,7 @@
                 %endif
             </td>
             <td>
-                <span class="delete_icon action_button" onclick="ajaxActionUserGroup(${g2p.users_group.users_group_id},'${'id%s'%id(g2p.users_group.users_group_name)}')">
+                <span class="delete_icon action_button" onclick="ajaxActionRevoke(${g2p.users_group.users_group_id}, 'user_group', '${'id%s'%id(g2p.users_group.users_group_name)}')">
                 ${_('revoke')}
                 </span>
             </td>
@@ -86,35 +86,29 @@
     </tr>
 </table>
 <script type="text/javascript">
-function ajaxActionUser(user_id, field_id) {
-    var sUrl = "${h.url('delete_repo_user',repo_name=c.repo_name)}";
+function ajaxActionRevoke(obj_id, obj_type, field_id) {
     var callback = {
         success: function (o) {
             var tr = YUD.get(String(field_id));
             tr.parentNode.removeChild(tr);
         },
         failure: function (o) {
-            alert("${_('Failed to remove user')}");
+            alert(_TM['Failed to remoke permission'] + ": " + o.status);
         },
     };
-    var postData = '_method=delete&user_id=' + user_id;
+    if (obj_type=='user'){
+        var sUrl = "${h.url('delete_repo_user',repo_name=c.repo_name)}";
+        var postData = '_method=delete&user_id={0}&obj_type=user'.format(obj_id);
+    }
+    else if (obj_type=='user_group'){
+        var sUrl = "${h.url('delete_repo_users_group',repo_name=c.repo_name)}";
+        var postData = '_method=delete&users_group_id={0}&obj_type=user_group'.format(obj_id);
+
+    }
+
     var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
 };
 
-function ajaxActionUserGroup(users_group_id,field_id){
-    var sUrl = "${h.url('delete_repo_users_group',repo_name=c.repo_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 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')) {
--- a/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html	Mon Apr 08 22:47:35 2013 +0200
@@ -21,7 +21,7 @@
             </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)}')">
+                <span class="delete_icon action_button" onclick="ajaxActionRevoke(${r2p.user.user_id}, 'user', '${'id%s'%id(r2p.user.username)}')">
                 ${_('revoke')}
                 </span>
               %endif
@@ -51,7 +51,7 @@
                 <img class="perm-gravatar" src="${h.url('/images/icons/group.png')}"/>${g2p.users_group.users_group_name}
             </td>
             <td>
-                <span class="delete_icon action_button" onclick="ajaxActionUserGroup(${g2p.users_group.users_group_id},'${'id%s'%id(g2p.users_group.users_group_name)}')">
+                <span class="delete_icon action_button" onclick="ajaxActionRevoke(${g2p.users_group.users_group_id}, 'user_group', '${'id%s'%id(g2p.users_group.users_group_name)}')">
                 ${_('revoke')}
                 </span>
             </td>
@@ -89,37 +89,29 @@
     </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.group_name)}";
+function ajaxActionRevoke(obj_id, obj_type, field_id) {
     var callback = {
         success: function (o) {
             var tr = YUD.get(String(field_id));
             tr.parentNode.removeChild(tr);
         },
         failure: function (o) {
-            alert("${_('Failed to remove user')}");
+            alert(_TM['Failed to remoke permission'] + ": " + o.status);
         },
     };
     var recursive = YUD.get('recursive').checked;
-    var postData = '_method=delete&recursive={0}&user_id={1}'.format(recursive,user_id);
+
+    if (obj_type=='user'){
+        var sUrl = "${h.url('delete_repos_group_user_perm',group_name=c.repos_group.group_name)}";
+        var postData = '_method=delete&recursive={0}&user_id={1}&obj_type=user'.format(recursive,obj_id);
+    }
+    else if (obj_type=='user_group'){
+        var sUrl = "${h.url('delete_repos_group_users_group_perm',group_name=c.repos_group.group_name)}";
+        var postData = '_method=delete&recursive={0}&users_group_id={0}&obj_type=user_group'.format(recursive,obj_id);
+    }
     var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
 };
 
-function ajaxActionUserGroup(users_group_id,field_id){
-    var sUrl = "${h.url('delete_repos_group_users_group_perm',group_name=c.repos_group.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 group')}");
-        },
-    };
-    var recursive = YUD.get('recursive').checked;
-    var postData = '_method=delete&recursive={0}&users_group_id={1}'.format(recursive,users_group_id);
-    var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
-};
 
 YUE.onDOMReady(function () {
     if (!YUD.hasClass('perm_new_member_name', 'error')) {
--- a/rhodecode/templates/admin/repos_groups/repos_groups_edit.html	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/templates/admin/repos_groups/repos_groups_edit.html	Mon Apr 08 22:47:35 2013 +0200
@@ -18,7 +18,7 @@
 </%def>
 
 <%def name="main()">
-<div class="box">
+<div class="box box-left">
     <!-- box / title -->
     <div class="title">
         ${self.breadcrumbs()}
@@ -60,14 +60,6 @@
                 </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="field">
                 <div class="label label-checkbox">
                     <label for="enable_locking">${_('Enable locking')}:</label>
                 </div>
@@ -84,4 +76,28 @@
     </div>
     ${h.end_form()}
 </div>
+<div class="box box-right">
+    <div class="title">
+        <h5>${_('Permissions')}</h5>
+    </div>
+    ${h.form(url('set_repo_group_perm_member', group_name=c.repos_group.group_name),method='post')}
+    <div class="form">
+       <div class="fields">
+            <div class="field">
+                <div class="label">
+                    <label for="input">${_('Permissions')}:</label>
+                </div>
+                <div class="input">
+                    ${h.hidden('repo_private')}
+                    <%include file="repos_group_edit_perms.html"/>
+                </div>
+            </div>
+            <div class="buttons">
+              ${h.submit('save',_('Save'),class_="ui-btn large")}
+              ${h.reset('reset',_('Reset'),class_="ui-btn large")}
+            </div>
+       </div>
+    </div>
+    ${h.end_form()}
+</div>
 </%def>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/templates/admin/users_groups/user_group_edit_perms.html	Mon Apr 08 22:47:35 2013 +0200
@@ -0,0 +1,100 @@
+<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.users_group.user_user_group_to_perm:
+        ##forbid revoking permission from yourself
+        <tr id="id${id(r2p.user.username)}">
+            %if c.rhodecode_user.user_id != r2p.user.user_id or c.rhodecode_user.is_admin:
+            <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.none')}</td>
+            <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.read')}</td>
+            <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.write')}</td>
+            <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.admin')}</td>
+            <td style="white-space: nowrap;">
+                <img class="perm-gravatar" src="${h.gravatar_url(r2p.user.email,14)}"/>${r2p.user.username if r2p.user.username != 'default' else _('default')}
+            </td>
+            <td>
+              %if r2p.user.username !='default':
+                <span class="delete_icon action_button" onclick="ajaxActionRevoke(${r2p.user.user_id}, 'user', '${'id%s'%id(r2p.user.username)}')">
+                ${_('revoke')}
+                </span>
+              %endif
+            </td>
+            %else:
+            <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.none', disabled="disabled")}</td>
+            <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.read', disabled="disabled")}</td>
+            <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.write', disabled="disabled")}</td>
+            <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.admin', disabled="disabled")}</td>
+            <td style="white-space: nowrap;">
+                <img class="perm-gravatar" src="${h.gravatar_url(r2p.user.email,14)}"/>${r2p.user.username if r2p.user.username != 'default' else _('default')}
+            </td>
+            <td>
+            </td>
+            %endif
+        </tr>
+    %endfor
+
+    <%
+    _tmpl = h.literal("""' \
+        <td><input type="radio" value="usergroup.none" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
+        <td><input type="radio" value="usergroup.read" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
+        <td><input type="radio" value="usergroup.write" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
+        <td><input type="radio" value="usergroup.admin" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
+        <td class="ac"> \
+            <div class="perm_ac" id="perm_ac_{0}"> \
+                <input class="yui-ac-input" id="perm_new_member_name_{0}" name="perm_new_member_name_{0}" value="" type="text"> \
+                <input id="perm_new_member_type_{0}" name="perm_new_member_type_{0}" value="" type="hidden">  \
+                <div id="perm_container_{0}"></div> \
+            </div> \
+        </td> \
+        <td></td>'""")
+    %>
+    ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl'
+    <tr class="new_members last_new_member" id="add_perm_input"></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 ajaxActionRevoke(obj_id, obj_type, field_id) {
+    var callback = {
+        success: function (o) {
+            var tr = YUD.get(String(field_id));
+            tr.parentNode.removeChild(tr);
+        },
+        failure: function (o) {
+            alert(_TM['Failed to remoke permission'] + ": " + o.status);
+        },
+    };
+    var sUrl = "${h.url('delete_user_group_perm_member', id=c.users_group.users_group_id)}";
+    if (obj_type=='user'){
+        var postData = '_method=delete&user_id={0}&obj_type=user'.format(obj_id);
+    }
+    else if (obj_type=='user_group'){
+        var postData = '_method=delete&user_group_id={0}&obj_type=user_group'.format(obj_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 () {
+        addPermAction(${_tmpl}, ${c.users_array|n}, ${c.users_groups_array|n});
+    });
+});
+
+</script>
--- a/rhodecode/templates/admin/users_groups/users_group_edit.html	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/templates/admin/users_groups/users_group_edit.html	Mon Apr 08 22:47:35 2013 +0200
@@ -18,7 +18,7 @@
 </%def>
 
 <%def name="main()">
-<div class="box box-left">
+<div class="box box-left" style="clear:left">
     <!-- box / title -->
     <div class="title">
         ${self.breadcrumbs()}
@@ -92,12 +92,54 @@
             </div>
     </div>
 ${h.end_form()}
+    <div class="group_members_wrap">
+    % if c.group_members_obj:
+      <ul class="group_members">
+      %for user in c.group_members_obj:
+        <li>
+          <div class="group_member">
+            <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/> </div>
+            <div>${h.link_to(user.username, h.url('edit_user',id=user.user_id))}</div>
+            <div>${user.full_name}</div>
+          </div>
+        </li>
+      %endfor
+      </ul>
+      %else:
+        <span class="empty_data">${_('No members yet')}</span>
+      %endif
+    </div>
+</div>
+
+
+<div class="box box-right">
+    <div class="title">
+        <h5>${_('Permissions')}</h5>
+    </div>
+    ${h.form(url('set_user_group_perm_member', id=c.users_group.users_group_id),method='post')}
+    <div class="form">
+       <div class="fields">
+            <div class="field">
+                <div class="label">
+                    <label for="input">${_('Permissions')}:</label>
+                </div>
+                <div class="input">
+                    <%include file="user_group_edit_perms.html"/>
+                </div>
+            </div>
+            <div class="buttons">
+              ${h.submit('save',_('Save'),class_="ui-btn large")}
+              ${h.reset('reset',_('Reset'),class_="ui-btn large")}
+            </div>
+       </div>
+    </div>
+    ${h.end_form()}
 </div>
 
 <div class="box box-right">
     <!-- box / title -->
     <div class="title">
-        <h5>${_('Permissions')}</h5>
+        <h5>${_('Permissions summary')}</h5>
     </div>
     ${h.form(url('users_group_perm', id=c.users_group.users_group_id), method='put')}
     <div class="form">
@@ -138,35 +180,6 @@
         </div>
     </div>
     ${h.end_form()}
-
-    ## permissions overview
-    <%namespace name="p" file="/base/perms_summary.html"/>
-    ${p.perms_summary(c.users_group.permissions)}
-</div>
-
-<div class="box box-right" style="clear:right">
-    <!-- box / title -->
-    <div class="title">
-        <h5>${_('Group members')}</h5>
-    </div>
-
-    <div class="group_members_wrap">
-    % if c.group_members_obj:
-      <ul class="group_members">
-      %for user in c.group_members_obj:
-        <li>
-          <div class="group_member">
-            <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/> </div>
-            <div>${h.link_to(user.username, h.url('edit_user',id=user.user_id))}</div>
-            <div>${user.full_name}</div>
-          </div>
-        </li>
-      %endfor
-      </ul>
-      %else:
-        <span class="empty_data">${_('No members yet')}</span>
-      %endif
-    </div>
 </div>
 
 <script type="text/javascript">
--- a/rhodecode/templates/base/base.html	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/templates/base/base.html	Mon Apr 08 22:47:35 2013 +0200
@@ -77,9 +77,14 @@
   </ul>
 </%def>
 
-<%def name="admin_menu_simple()">
+<%def name="admin_menu_simple(repository_groups=None, user_groups=None)">
   <ul>
+   %if repository_groups:
       <li>${h.link_to(_('Repository groups'),h.url('repos_groups'),class_='repos_groups')}</li>
+   %endif:
+   %if user_groups:
+      <li>${h.link_to(_('User groups'),h.url('users_groups'),class_='groups')}</li>
+   %endif
   </ul>
 </%def>
 
@@ -294,12 +299,12 @@
               </a>
               ${admin_menu()}
             </li>
-          % elif c.rhodecode_user.groups_admin:
+          % elif c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
           <li ${is_current('admin')}>
               <a class="menu_link admin childs" title="${_('Admin')}">
                 ${_('Admin')}
               </a>
-              ${admin_menu_simple()}
+              ${admin_menu_simple(c.rhodecode_user.repository_groups_admin, c.rhodecode_user.user_groups_admin)}
           </li>
           % endif
           ${usermenu()}
--- a/rhodecode/templates/base/root.html	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/templates/base/root.html	Mon Apr 08 22:47:35 2013 +0200
@@ -54,7 +54,8 @@
                 'Show selected changeset __S': "${_('Show selected changeset __S')}",
                 'Selection link': "${_('Selection link')}",
                 'Collapse diff': "${_('Collapse diff')}",
-                'Expand diff': "${_('Expand diff')}"
+                'Expand diff': "${_('Expand diff')}",
+                'Failed to remoke permission': "${_('Failed to remoke permission')}"
             };
             var _TM = TRANSLATION_MAP;
 
--- a/rhodecode/tests/api/api_base.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/tests/api/api_base.py	Mon Apr 08 22:47:35 2013 +0200
@@ -50,9 +50,9 @@
 
 ## helpers
 def make_users_group(name=TEST_USER_GROUP):
-    gr = UserGroupModel().create(name=name)
+    gr = fixture.create_user_group(name, cur_user=TEST_USER_ADMIN_LOGIN)
     UserGroupModel().add_user_to_group(users_group=gr,
-                                        user=TEST_USER_ADMIN_LOGIN)
+                                       user=TEST_USER_ADMIN_LOGIN)
     Session().commit()
     return gr
 
@@ -1084,8 +1084,7 @@
 
     def test_api_add_user_to_users_group(self):
         gr_name = 'test_group'
-        UserGroupModel().create(gr_name)
-        Session().commit()
+        fixture.create_user_group(gr_name)
         id_, params = _build_data(self.apikey, 'add_user_to_users_group',
                                   usersgroupid=gr_name,
                                   userid=TEST_USER_ADMIN_LOGIN)
@@ -1113,8 +1112,7 @@
     @mock.patch.object(UserGroupModel, 'add_user_to_group', crash)
     def test_api_add_user_to_users_group_exception_occurred(self):
         gr_name = 'test_group'
-        UserGroupModel().create(gr_name)
-        Session().commit()
+        fixture.create_user_group(gr_name)
         id_, params = _build_data(self.apikey, 'add_user_to_users_group',
                                   usersgroupid=gr_name,
                                   userid=TEST_USER_ADMIN_LOGIN)
@@ -1128,7 +1126,7 @@
 
     def test_api_remove_user_from_users_group(self):
         gr_name = 'test_group_3'
-        gr = UserGroupModel().create(gr_name)
+        gr = fixture.create_user_group(gr_name)
         UserGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
         Session().commit()
         id_, params = _build_data(self.apikey, 'remove_user_from_users_group',
@@ -1149,7 +1147,7 @@
     @mock.patch.object(UserGroupModel, 'remove_user_from_group', crash)
     def test_api_remove_user_from_users_group_exception_occurred(self):
         gr_name = 'test_group_3'
-        gr = UserGroupModel().create(gr_name)
+        gr = fixture.create_user_group(gr_name)
         UserGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
         Session().commit()
         id_, params = _build_data(self.apikey, 'remove_user_from_users_group',
--- a/rhodecode/tests/fixture.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/tests/fixture.py	Mon Apr 08 22:47:35 2013 +0200
@@ -2,10 +2,11 @@
 Helpers for fixture generation
 """
 from rhodecode.tests import *
-from rhodecode.model.db import Repository, User, RepoGroup
+from rhodecode.model.db import Repository, User, RepoGroup, UserGroup
 from rhodecode.model.meta import Session
 from rhodecode.model.repo import RepoModel
 from rhodecode.model.repos_group import ReposGroupModel
+from rhodecode.model.users_group import UserGroupModel
 
 
 class Fixture(object):
@@ -43,6 +44,15 @@
 
         return defs
 
+    def _get_user_group_create_params(self, name, **custom):
+        defs = dict(
+            users_group_name=name,
+            users_group_active=True,
+        )
+        defs.update(custom)
+
+        return defs
+
     def create_repo(self, name, **kwargs):
         if 'skip_if_exists' in kwargs:
             del kwargs['skip_if_exists']
@@ -100,3 +110,17 @@
         Session().commit()
         gr = RepoGroup.get_by_group_name(gr.group_name)
         return gr
+
+    def create_user_group(self, name, **kwargs):
+        if 'skip_if_exists' in kwargs:
+            del kwargs['skip_if_exists']
+            gr = UserGroup.get_by_group_name(group_name=name)
+            if gr:
+                return gr
+        form_data = self._get_user_group_create_params(name, **kwargs)
+        owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
+        user_group = UserGroupModel().create(name=form_data['users_group_name'],
+                        owner=owner, active=form_data['users_group_active'])
+        Session().commit()
+        user_group = UserGroup.get_by_group_name(user_group.users_group_name)
+        return user_group
--- a/rhodecode/tests/models/test_permissions.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/tests/models/test_permissions.py	Mon Apr 08 22:47:35 2013 +0200
@@ -126,9 +126,7 @@
 
     def test_propagated_permission_from_users_group_by_explicit_perms_exist(self):
         # make group
-        self.ug1 = UserGroupModel().create('G1')
-        # add user to group
-
+        self.ug1 = fixture.create_user_group('G1')
         UserGroupModel().add_user_to_group(self.ug1, self.u1)
 
         # set permission to lower
@@ -160,9 +158,7 @@
 
     def test_propagated_permission_from_users_group(self):
         # make group
-        self.ug1 = UserGroupModel().create('G1')
-        # add user to group
-
+        self.ug1 = fixture.create_user_group('G1')
         UserGroupModel().add_user_to_group(self.ug1, self.u3)
 
         # grant perm for group this should override default permission from user
@@ -185,7 +181,7 @@
 
     def test_propagated_permission_from_users_group_lower_weight(self):
         # make group
-        self.ug1 = UserGroupModel().create('G1')
+        self.ug1 = fixture.create_user_group('G1')
         # add user to group
         UserGroupModel().add_user_to_group(self.ug1, self.u1)
 
@@ -295,7 +291,7 @@
                                                 user=self.anon,
                                                 perm='group.none')
         # make group
-        self.ug1 = UserGroupModel().create('G1')
+        self.ug1 = fixture.create_user_group('G1')
         # add user to group
         UserGroupModel().add_user_to_group(self.ug1, self.u1)
         Session().commit()
@@ -434,8 +430,7 @@
         self.assertEqual(u1_auth.permissions['repositories']['myownrepo'],
                          'repository.admin')
         #set his permission as user group, he should still be admin
-        self.ug1 = UserGroupModel().create('G1')
-        # add user to group
+        self.ug1 = fixture.create_user_group('G1')
         UserGroupModel().add_user_to_group(self.ug1, self.u1)
         RepoModel().grant_users_group_permission(self.test_repo,
                                                  group_name=self.ug1,
--- a/rhodecode/tests/models/test_users.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/tests/models/test_users.py	Mon Apr 08 22:47:35 2013 +0200
@@ -7,6 +7,9 @@
 
 from rhodecode.model.meta import Session
 from rhodecode.model.users_group import UserGroupModel
+from rhodecode.tests.fixture import Fixture
+
+fixture = Fixture()
 
 
 class TestUser(unittest.TestCase):
@@ -26,7 +29,7 @@
         self.assertEqual(User.get_by_username(u'test_user'), usr)
 
         # make user group
-        users_group = UserGroupModel().create('some_example_group')
+        users_group = fixture.create_user_group('some_example_group')
         Session().commit()
 
         UserGroupModel().add_user_to_group(users_group, usr)
--- a/rhodecode/tests/models/test_users_group_permissions_on_groups.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/tests/models/test_users_group_permissions_on_groups.py	Mon Apr 08 22:47:35 2013 +0200
@@ -4,15 +4,16 @@
 from rhodecode.tests import *
 
 from rhodecode.model.repos_group import ReposGroupModel
-from rhodecode.model.db import RepoGroup, Repository, User
+from rhodecode.model.db import RepoGroup
 
 from rhodecode.model.meta import Session
 from nose.tools import with_setup
 from rhodecode.tests.models.common import _create_project_tree, check_tree_perms, \
     _get_perms, _check_expected_count, expected_count, _destroy_project_tree
 from rhodecode.model.users_group import UserGroupModel
-from rhodecode.model.repo import RepoModel
+from rhodecode.tests.fixture import Fixture
 
+fixture = Fixture()
 
 test_u2_id = None
 test_u2_gr_id = None
@@ -40,7 +41,7 @@
     Session().commit()
     test_u2_id = test_u2.user_id
 
-    gr1 = UserGroupModel().create(name='perms_group_1')
+    gr1 = fixture.create_user_group('perms_group_1')
     Session().commit()
     test_u2_gr_id = gr1.users_group_id
     UserGroupModel().add_user_to_group(gr1, user=test_u2_id)
--- a/rhodecode/tests/test_validators.py	Mon Apr 08 20:38:37 2013 +0200
+++ b/rhodecode/tests/test_validators.py	Mon Apr 08 22:47:35 2013 +0200
@@ -12,6 +12,9 @@
 from rhodecode.config.routing import ADMIN_PREFIX
 from rhodecode.model.db import ChangesetStatus, Repository
 from rhodecode.model.changeset_status import ChangesetStatusModel
+from rhodecode.tests.fixture import Fixture
+
+fixture = Fixture()
 
 
 class TestReposGroups(unittest.TestCase):
@@ -55,9 +58,9 @@
         self.assertRaises(formencode.Invalid, validator.to_python, 'default')
         self.assertRaises(formencode.Invalid, validator.to_python, '.,')
 
-        gr = UserGroupModel().create('test')
-        gr2 = UserGroupModel().create('tes2')
-        Session.commit()
+        gr = fixture.create_user_group('test')
+        gr2 = fixture.create_user_group('tes2')
+        Session().commit()
         self.assertRaises(formencode.Invalid, validator.to_python, 'test')
         assert gr.users_group_id != None
         validator = v.ValidUserGroup(edit=True,
@@ -69,7 +72,7 @@
         self.assertRaises(formencode.Invalid, validator.to_python, 'TEST')
         UserGroupModel().delete(gr)
         UserGroupModel().delete(gr2)
-        Session.commit()
+        Session().commit()
 
     def test_ValidReposGroup(self):
         validator = v.ValidReposGroup()