changeset 1616:bbe3f2ba52ca beta

Merge with upstream
author Liad Shani <liadff@gmail.com>
date Tue, 25 Oct 2011 21:17:29 +0200
parents 51bd5404529c (current diff) 019026a8cf67 (diff)
children cf128ced8c85
files rhodecode/config/deployment.ini_tmpl rhodecode/lib/middleware/simplehg.py
diffstat 31 files changed, 1053 insertions(+), 291 deletions(-) [+]
line wrap: on
line diff
--- a/development.ini	Mon Oct 17 20:08:59 2011 +0200
+++ b/development.ini	Tue Oct 25 21:17:29 2011 +0200
@@ -24,6 +24,8 @@
 #smtp_port = 
 #smtp_use_tls = false
 #smtp_use_ssl = true
+# Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
+#smtp_auth = 
 
 [server:main]
 ##nr of threads to spawn
--- a/docs/api/api.rst	Mon Oct 17 20:08:59 2011 +0200
+++ b/docs/api/api.rst	Tue Oct 25 21:17:29 2011 +0200
@@ -7,7 +7,7 @@
 
 Starting from RhodeCode version 1.2 a simple API was implemented.
 There's a single schema for calling all api methods. API is implemented
-with JSON protocol both ways. An url to send API request in RhodeCode is 
+with JSON protocol both ways. An url to send API request in RhodeCode is
 <your_server>/_admin/api
 
 
@@ -22,90 +22,341 @@
 Example call for autopulling remotes repos using curl::
     curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"api_key":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull","args":{"repo":"CPython"}}'
 
-Simply provide 
+Simply provide
  - *api_key* for access and permission validation.
  - *method* is name of method to call
  - *args* is an key:value list of arguments to pass to method
-    
+
 .. note::
-    
-    api_key can be found in your user account page    
-    
-    
+
+    api_key can be found in your user account page
+
+
 RhodeCode API will return always a JSON formatted answer::
-    
+
     {
-        "result": "<result>", 
+        "result": "<result>",
         "error": null
     }
 
 All responses from API will be `HTTP/1.0 200 OK`, if there's an error while
-calling api *error* key from response will contain failure description 
+calling api *error* key from response will contain failure description
 and result will be null.
 
 API METHODS
 +++++++++++
 
-    
+
 pull
 ----
 
-Pulls given repo from remote location. Can be used to automatically keep 
-remote repos up to date. This command can be executed only using api_key 
-belonging to user with admin rights
-
-INPUT::
-
-    api_key:"<api_key>"
-    method: "pull"
-    args: {"repo":<repo_name>}
-
-OUTPUT::
-
-    result:"Pulled from <repo_name>"
-    error:null
-
-    
-create_user
------------
-
-Creates new user in RhodeCode. This command can be executed only using api_key 
+Pulls given repo from remote location. Can be used to automatically keep
+remote repos up to date. This command can be executed only using api_key
 belonging to user with admin rights
 
 INPUT::
 
-    api_key:"<api_key>"
-    method: "create_user"
-    args: {"username": "<username>", 
-           "password": "<password>", 
-           "active":   "<bool>", 
-           "admin":    "<bool>", 
-           "name":     "<firstname>", 
-           "lastname": "<lastname>", 
-           "email":    "<useremail>"}
+    api_key : "<api_key>"
+    method :  "pull"
+    args :    {
+                "repo" : "<repo_name>"
+              }
+
+OUTPUT::
+
+    result : "Pulled from <repo_name>"
+    error :  null
+
+
+get_users
+---------
+
+Lists all existing users. This command can be executed only using api_key
+belonging to user with admin rights.
+
+INPUT::
+
+    api_key : "<api_key>"
+    method :  "get_users"
+    args :    { }
+
+OUTPUT::
+
+    result: [
+              {
+                "id" :       "<id>",
+                "username" : "<username>",
+                "firstname": "<firstname>",
+                "lastname" : "<lastname>",
+                "email" :    "<email>",
+                "active" :   "<bool>",
+                "admin" :    "<bool>",
+                "ldap" :     "<ldap_dn>"
+              },
+    	      …
+            ]
+    error:  null
+
+create_user
+-----------
+
+Creates new user in RhodeCode. This command can be executed only using api_key
+belonging to user with admin rights.
+
+INPUT::
+
+    api_key : "<api_key>"
+    method :  "create_user"
+    args :    {
+                "username" :  "<username>",
+                "password" :  "<password>",
+                "firstname" : "<firstname>",
+                "lastname" :  "<lastname>",
+                "email" :     "<useremail>"
+                "active" :    "<bool> = True",
+                "admin" :     "<bool> = False",
+                "ldap_dn" :   "<ldap_dn> = None"
+              }
 
 OUTPUT::
 
-    result:{"id": <newuserid>,
-            "msg":"created new user <username>"}
-    error:null
-    
-    
+    result: {
+              "msg" : "created new user <username>"
+            }
+    error:  null
+
+get_users_groups
+----------------
+
+Lists all existing users groups. This command can be executed only using api_key
+belonging to user with admin rights.
+
+INPUT::
+
+    api_key : "<api_key>"
+    method :  "get_users_groups"
+    args :    { }
+
+OUTPUT::
+
+    result : [
+               {
+                 "id" :       "<id>",
+                 "name" :     "<name>",
+                 "active":    "<bool>",
+                 "members" :  [
+	    	                    {
+	    	                      "id" :       "<userid>",
+	                              "username" : "<username>",
+	                              "firstname": "<firstname>",
+	                              "lastname" : "<lastname>",
+	                              "email" :    "<email>",
+	                              "active" :   "<bool>",
+	                              "admin" :    "<bool>",
+	                              "ldap" :     "<ldap_dn>"
+	                            },
+	    	                    …
+	                          ]
+	            }
+              ]
+    error : null
+
+get_users_group
+---------------
+
+Gets an existing users group. This command can be executed only using api_key
+belonging to user with admin rights.
+
+INPUT::
+
+    api_key : "<api_key>"
+    method :  "get_users_group"
+    args :    {
+                "group_name" : "<name>"
+              }
+
+OUTPUT::
+
+    result : None if group not exist
+             {
+               "id" :       "<id>",
+               "name" :     "<name>",
+               "active":    "<bool>",
+               "members" :  [
+	    	                  { "id" :       "<userid>",
+	                            "username" : "<username>",
+	                            "firstname": "<firstname>",
+	                            "lastname" : "<lastname>",
+	                            "email" :    "<email>",
+	                            "active" :   "<bool>",
+	                            "admin" :    "<bool>",
+	                            "ldap" :     "<ldap_dn>"
+	                          },
+	    	                  …
+	                        ]
+             }
+    error : null
+
 create_users_group
 ------------------
 
-creates new users group. This command can be executed only using api_key 
+Creates new users group. This command can be executed only using api_key
 belonging to user with admin rights
 
 INPUT::
 
-    api_key:"<api_key>"
-    method: "create_user"
-    args: {"name":  "<groupname>", 
-           "active":"<bool>"}
+    api_key : "<api_key>"
+    method :  "create_users_group"
+    args:     {
+                "name":  "<name>",
+                "active":"<bool> = True"
+              }
+
+OUTPUT::
+
+    result: {
+              "id":  "<newusersgroupid>",
+              "msg": "created new users group <name>"
+            }
+    error:  null
+
+add_user_to_users_groups
+------------------------
+
+Adds a user to a users group. This command can be executed only using api_key
+belonging to user with admin rights
+
+INPUT::
+
+    api_key : "<api_key>"
+    method :  "add_user_users_group"
+    args:     {
+                "group_name" :  "<groupname>",
+                "user_name" :   "<username>"
+              }
+
+OUTPUT::
+
+    result: {
+              "id":  "<newusersgroupmemberid>",
+              "msg": "created new users group member"
+            }
+    error:  null
+
+get_repos
+---------
+
+Lists all existing repositories. This command can be executed only using api_key
+belonging to user with admin rights
+
+INPUT::
+
+    api_key : "<api_key>"
+    method :  "get_repos"
+    args:     { }
 
 OUTPUT::
 
-    result:{"id": <newusersgroupid>,
-            "msg":"created new users group <groupname>"}
-    error:null    
+    result: [
+              {
+                "id" :          "<id>",
+                "name" :        "<name>"
+                "type" :        "<type>",
+                "description" : "<description>"
+              },
+              …
+            ]
+    error:  null
+
+get_repo
+--------
+
+Gets an existing repository. This command can be executed only using api_key
+belonging to user with admin rights
+
+INPUT::
+
+    api_key : "<api_key>"
+    method :  "get_repo"
+    args:     {
+                "name" : "<name>"
+              }
+
+OUTPUT::
+
+    result: None if repository not exist
+            {
+                "id" :          "<id>",
+                "name" :        "<name>"
+                "type" :        "<type>",
+                "description" : "<description>",
+                "members" :     [
+                                  { "id" :         "<userid>",
+	                                "username" :   "<username>",
+	                                "firstname":   "<firstname>",
+	                                "lastname" :   "<lastname>",
+	                                "email" :      "<email>",
+	                                "active" :     "<bool>",
+	                                "admin" :      "<bool>",
+	                                "ldap" :       "<ldap_dn>",
+	                                "permission" : "repository_(read|write|admin)"
+	                              },
+                                  …
+                                  {
+                                    "id" :       "<usersgroupid>",
+                                    "name" :     "<usersgroupname>",
+                                    "active":    "<bool>",
+                                    "permission" : "repository_(read|write|admin)"
+                                  },
+                                  …
+                                ]
+            }
+    error:  null
+
+create_repo
+-----------
+
+Creates a repository. This command can be executed only using api_key
+belonging to user with admin rights.
+If repository name contains "/", all needed repository groups will be created.
+For example "foo/bar/baz" will create groups "foo", "bar" (with "foo" as parent),
+and create "baz" repository with "bar" as group.
+
+INPUT::
+
+    api_key : "<api_key>"
+    method :  "create_repo"
+    args:     {
+                "name" :        "<name>",
+                "owner_name" :  "<ownername>",
+                "description" : "<description> = ''",
+                "repo_type" :   "<type> = 'hg'",
+                "private" :     "<bool> = False"
+              }
+
+OUTPUT::
+
+    result: None
+    error:  null
+
+add_user_to_repo
+----------------
+
+Add a user to a repository. This command can be executed only using api_key
+belonging to user with admin rights.
+If "perm" is None, user will be removed from the repository.
+
+INPUT::
+
+    api_key : "<api_key>"
+    method :  "add_user_to_repo"
+    args:     {
+                "repo_name" :  "<reponame>",
+                "user_name" :  "<username>",
+                "perm" :       "(None|repository_(read|write|admin))",
+              }
+
+OUTPUT::
+
+    result: None
+    error:  null
--- a/production.ini	Mon Oct 17 20:08:59 2011 +0200
+++ b/production.ini	Tue Oct 25 21:17:29 2011 +0200
@@ -24,6 +24,8 @@
 #smtp_port = 
 #smtp_use_tls = false
 #smtp_use_ssl = true
+# Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
+#smtp_auth = 
 
 [server:main]
 ##nr of threads to spawn
--- a/rhodecode/config/deployment.ini_tmpl	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/config/deployment.ini_tmpl	Tue Oct 25 21:17:29 2011 +0200
@@ -24,6 +24,8 @@
 #smtp_port = 
 #smtp_use_tls = false
 #smtp_use_ssl = true
+# Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
+#smtp_auth = 
 
 [server:main]
 ##nr of threads to spawn
@@ -147,7 +149,7 @@
 # SQLITE [default]
 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
  
-# POSTGRES
+# POSTGRESQL
 # sqlalchemy.db1.url = postgresql://user:pass@localhost/rhodecode
 
 # MySQL
--- a/rhodecode/controllers/admin/repos.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/controllers/admin/repos.py	Tue Oct 25 21:17:29 2011 +0200
@@ -26,7 +26,6 @@
 import logging
 import traceback
 import formencode
-from operator import itemgetter
 from formencode import htmlfill
 
 from paste.httpexceptions import HTTPInternalServerError
@@ -92,7 +91,7 @@
             return redirect(url('repos'))
 
         c.default_user_id = User.get_by_username('default').user_id
-        c.in_public_journal = self.sa.query(UserFollowing)\
+        c.in_public_journal = UserFollowing.query()\
             .filter(UserFollowing.user_id == c.default_user_id)\
             .filter(UserFollowing.follows_repository == c.repo_info).scalar()
 
@@ -110,30 +109,7 @@
             c.stats_percentage = '%.2f' % ((float((last_rev)) /
                                             c.repo_last_rev) * 100)
 
-        defaults = c.repo_info.get_dict()
-        group, repo_name = c.repo_info.groups_and_repo
-        defaults['repo_name'] = repo_name
-        defaults['repo_group'] = getattr(group[-1] if group else None,
-                                         'group_id', None)
-
-        #fill owner
-        if c.repo_info.user:
-            defaults.update({'user': c.repo_info.user.username})
-        else:
-            replacement_user = self.sa.query(User)\
-            .filter(User.admin == True).first().username
-            defaults.update({'user': replacement_user})
-
-        #fill repository users
-        for p in c.repo_info.repo_to_perm:
-            defaults.update({'u_perm_%s' % p.user.username:
-                             p.permission.permission_name})
-
-        #fill repository groups
-        for p in c.repo_info.users_group_to_perm:
-            defaults.update({'g_perm_%s' % p.users_group.users_group_name:
-                             p.permission.permission_name})
-
+        defaults = RepoModel()._get_defaults(repo_name)
         return defaults
 
     @HasPermissionAllDecorator('hg.admin')
--- a/rhodecode/controllers/api/api.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/controllers/api/api.py	Tue Oct 25 21:17:29 2011 +0200
@@ -2,10 +2,18 @@
 import logging
 
 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
-from rhodecode.lib.auth import HasPermissionAllDecorator
+from rhodecode.lib.auth import HasPermissionAllDecorator, \
+    HasPermissionAnyDecorator
 from rhodecode.model.scm import ScmModel
 
-from rhodecode.model.db import User, UsersGroup, Repository
+from rhodecode.model.db import User, UsersGroup, Group, Repository
+from rhodecode.model.repo import RepoModel
+from rhodecode.model.user import UserModel
+from rhodecode.model.repo_permission import RepositoryPermissionModel
+from rhodecode.model.users_group import UsersGroupModel
+from rhodecode.model import users_group
+from rhodecode.model.repos_group import ReposGroupModel
+from sqlalchemy.orm.exc import NoResultFound
 
 log = logging.getLogger(__name__)
 
@@ -13,86 +21,354 @@
 class ApiController(JSONRPCController):
     """
     API Controller
-    
-    
+
+
     Each method needs to have USER as argument this is then based on given
     API_KEY propagated as instance of user object
-    
+
     Preferably this should be first argument also
-    
-    
-    Each function should also **raise** JSONRPCError for any 
+
+
+    Each function should also **raise** JSONRPCError for any
     errors that happens
-    
+
     """
 
     @HasPermissionAllDecorator('hg.admin')
     def pull(self, apiuser, repo):
         """
         Dispatch pull action on given repo
-        
-        
+
+
         :param user:
         :param repo:
         """
 
         if Repository.is_valid(repo) is False:
             raise JSONRPCError('Unknown repo "%s"' % repo)
-        
+
         try:
             ScmModel().pull_changes(repo, self.rhodecode_user.username)
             return 'Pulled from %s' % repo
         except Exception:
             raise JSONRPCError('Unable to pull changes from "%s"' % repo)
 
+    @HasPermissionAllDecorator('hg.admin')
+    def get_user(self, apiuser, username):
+        """"
+        Get a user by username
+
+        :param apiuser
+        :param username
+        """
+
+        user = User.get_by_username(username)
+        if not user:
+            return None
+
+        return dict(id=user.user_id,
+                        username=user.username,
+                        firstname=user.name,
+                        lastname=user.lastname,
+                        email=user.email,
+                        active=user.active,
+                        admin=user.admin,
+                        ldap=user.ldap_dn)
 
     @HasPermissionAllDecorator('hg.admin')
-    def create_user(self, apiuser, username, password, active, admin, name, 
-                    lastname, email):
+    def get_users(self, apiuser):
+        """"
+        Get all users
+
+        :param apiuser
         """
-        Creates new user
-        
+
+        result = []
+        for user in User.getAll():
+            result.append(dict(id=user.user_id,
+                                username=user.username,
+                                firstname=user.name,
+                                lastname=user.lastname,
+                                email=user.email,
+                                active=user.active,
+                                admin=user.admin,
+                                ldap=user.ldap_dn))
+        return result
+
+    @HasPermissionAllDecorator('hg.admin')
+    def create_user(self, apiuser, username, password, firstname,
+                    lastname, email, active=True, admin=False, ldap_dn=None):
+        """
+        Create new user
+
         :param apiuser:
         :param username:
         :param password:
-        :param active:
-        :param admin:
         :param name:
         :param lastname:
         :param email:
+        :param active:
+        :param admin:
+        :param ldap_dn:
         """
-        
-        form_data = dict(username=username,
-                         password=password,
-                         active=active,
-                         admin=admin,
-                         name=name,
-                         lastname=lastname,
-                         email=email)
+
+        if self.get_user(apiuser, username):
+            raise JSONRPCError("user %s already exist" % username)
+
         try:
-            u = User.create(form_data)
-            return {'id':u.user_id,
-                    'msg':'created new user %s' % name}
+            form_data = dict(username=username,
+                             password=password,
+                             active=active,
+                             admin=admin,
+                             name=firstname,
+                             lastname=lastname,
+                             email=email,
+                             ldap_dn=ldap_dn)
+            UserModel().create_ldap(username, password, ldap_dn, form_data)
+            return dict(msg='created new user %s' % username)
         except Exception:
             log.error(traceback.format_exc())
-            raise JSONRPCError('failed to create user %s' % name)
+            raise JSONRPCError('failed to create user %s' % username)
+
+    @HasPermissionAllDecorator('hg.admin')
+    def get_users_group(self, apiuser, group_name):
+        """"
+        Get users group by name
+
+        :param apiuser
+        :param group_name
+        """
+
+        users_group = UsersGroup.get_by_group_name(group_name)
+        if not users_group:
+            return None
 
+        members = []
+        for user in users_group.members:
+            user = user.user
+            members.append(dict(id=user.user_id,
+                            username=user.username,
+                            firstname=user.name,
+                            lastname=user.lastname,
+                            email=user.email,
+                            active=user.active,
+                            admin=user.admin,
+                            ldap=user.ldap_dn))
+
+        return dict(id=users_group.users_group_id,
+                    name=users_group.users_group_name,
+                    active=users_group.users_group_active,
+                    members=members)
 
     @HasPermissionAllDecorator('hg.admin')
-    def create_users_group(self, apiuser, name, active):
+    def get_users_groups(self, apiuser):
+        """"
+        Get all users groups
+
+        :param apiuser
+        """
+
+        result = []
+        for users_group in UsersGroup.getAll():
+            members = []
+            for user in users_group.members:
+                user = user.user
+                members.append(dict(id=user.user_id,
+                                username=user.username,
+                                firstname=user.name,
+                                lastname=user.lastname,
+                                email=user.email,
+                                active=user.active,
+                                admin=user.admin,
+                                ldap=user.ldap_dn))
+
+            result.append(dict(id=users_group.users_group_id,
+                                name=users_group.users_group_name,
+                                active=users_group.users_group_active,
+                                members=members))
+        return result
+
+    @HasPermissionAllDecorator('hg.admin')
+    def create_users_group(self, apiuser, name, active=True):
         """
         Creates an new usergroup
-        
+
         :param name:
         :param active:
         """
-        form_data = {'users_group_name':name,
-                     'users_group_active':active}
+
+        if self.get_users_group(apiuser, name):
+            raise JSONRPCError("users group %s already exist" % name)
+
         try:
+            form_data = dict(users_group_name=name,
+                             users_group_active=active)
             ug = UsersGroup.create(form_data)
-            return {'id':ug.users_group_id,
-                    'msg':'created new users group %s' % name}
+            return dict(id=ug.users_group_id,
+                        msg='created new users group %s' % name)
         except Exception:
             log.error(traceback.format_exc())
             raise JSONRPCError('failed to create group %s' % name)
-        
\ No newline at end of file
+
+    @HasPermissionAllDecorator('hg.admin')
+    def add_user_to_users_group(self, apiuser, group_name, user_name):
+        """"
+        Add a user to a group
+
+        :param apiuser
+        :param group_name
+        :param user_name
+        """
+
+        try:
+            users_group = UsersGroup.get_by_group_name(group_name)
+            if not users_group:
+                raise JSONRPCError('unknown users group %s' % group_name)
+
+            try:
+                user = User.get_by_username(user_name)
+            except NoResultFound:
+                raise JSONRPCError('unknown user %s' % user_name)
+
+            ugm = UsersGroupModel().add_user_to_group(users_group, user)
+
+            return dict(id=ugm.users_group_member_id,
+                        msg='created new users group member')
+        except Exception:
+            log.error(traceback.format_exc())
+            raise JSONRPCError('failed to create users group member')
+
+    @HasPermissionAnyDecorator('hg.admin')
+    def get_repo(self, apiuser, repo_name):
+        """"
+        Get repository by name
+
+        :param apiuser
+        :param repo_name
+        """
+
+        try:
+            repo = Repository.get_by_repo_name(repo_name)
+        except NoResultFound:
+            return None
+
+        members = []
+        for user in repo.repo_to_perm:
+            perm = user.permission.permission_name
+            user = user.user
+            members.append(dict(type_="user",
+                                    id=user.user_id,
+                                    username=user.username,
+                                    firstname=user.name,
+                                    lastname=user.lastname,
+                                    email=user.email,
+                                    active=user.active,
+                                    admin=user.admin,
+                                    ldap=user.ldap_dn,
+                                    permission=perm))
+        for users_group in repo.users_group_to_perm:
+            perm = users_group.permission.permission_name
+            users_group = users_group.users_group
+            members.append(dict(type_="users_group",
+                                    id=users_group.users_group_id,
+                                    name=users_group.users_group_name,
+                                    active=users_group.users_group_active,
+                                    permission=perm))
+
+        return dict(id=repo.repo_id,
+                    name=repo.repo_name,
+                    type=repo.repo_type,
+                    description=repo.description,
+                    members=members)
+
+    @HasPermissionAnyDecorator('hg.admin')
+    def get_repos(self, apiuser):
+        """"
+        Get all repositories
+
+        :param apiuser
+        """
+
+        result = []
+        for repository in Repository.getAll():
+            result.append(dict(id=repository.repo_id,
+                                name=repository.repo_name,
+                                type=repository.repo_type,
+                                description=repository.description))
+        return result
+
+    @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
+    def create_repo(self, apiuser, name, owner_name, description='', 
+                    repo_type='hg', private=False):
+        """
+        Create a repository
+
+        :param apiuser
+        :param name
+        :param description
+        :param type
+        :param private
+        :param owner_name
+        """
+
+        try:
+            try:
+                owner = User.get_by_username(owner_name)
+            except NoResultFound:
+                raise JSONRPCError('unknown user %s' % owner)
+
+            if self.get_repo(apiuser, name):
+                raise JSONRPCError("repo %s already exist" % name)
+
+            groups = name.split('/')
+            real_name = groups[-1]
+            groups = groups[:-1]
+            parent_id = None
+            for g in groups:
+                group = Group.get_by_group_name(g)
+                if not group:
+                    group = ReposGroupModel().create(dict(group_name=g,
+                                                  group_description='',
+                                                  group_parent_id=parent_id))
+                parent_id = group.group_id
+
+            RepoModel().create(dict(repo_name=real_name,
+                                     repo_name_full=name,
+                                     description=description,
+                                     private=private,
+                                     repo_type=repo_type,
+                                     repo_group=parent_id,
+                                     clone_uri=None), owner)
+        except Exception:
+            log.error(traceback.format_exc())
+            raise JSONRPCError('failed to create repository %s' % name)
+
+    @HasPermissionAnyDecorator('hg.admin')
+    def add_user_to_repo(self, apiuser, repo_name, user_name, perm):
+        """
+        Add permission for a user to a repository
+
+        :param apiuser
+        :param repo_name
+        :param user_name
+        :param perm
+        """
+
+        try:
+            try:
+                repo = Repository.get_by_repo_name(repo_name)
+            except NoResultFound:
+                raise JSONRPCError('unknown repository %s' % repo)
+
+            try:
+                user = User.get_by_username(user_name)
+            except NoResultFound:
+                raise JSONRPCError('unknown user %s' % user)
+
+            RepositoryPermissionModel()\
+                .update_or_delete_user_permission(repo, user, perm)
+        except Exception:
+            log.error(traceback.format_exc())
+            raise JSONRPCError('failed to edit permission %(repo)s for %(user)s'
+                            % dict(user=user_name, repo=repo_name))
+
--- a/rhodecode/controllers/settings.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/controllers/settings.py	Tue Oct 25 21:17:29 2011 +0200
@@ -42,7 +42,7 @@
 
 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
 from rhodecode.model.repo import RepoModel
-from rhodecode.model.db import User
+from rhodecode.model.db import Group
 
 log = logging.getLogger(__name__)
 
@@ -52,7 +52,15 @@
     @LoginRequired()
     def __before__(self):
         super(SettingsController, self).__before__()
-
+    
+    def __load_defaults(self):
+        c.repo_groups = Group.groups_choices()
+        c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
+        
+        repo_model = RepoModel()
+        c.users_array = repo_model.get_users_js()
+        c.users_groups_array = repo_model.get_users_groups_js()
+        
     @HasRepoPermissionAllDecorator('repository.admin')
     def index(self, repo_name):
         repo_model = RepoModel()
@@ -66,28 +74,9 @@
 
             return redirect(url('home'))
 
-        c.users_array = repo_model.get_users_js()
-        c.users_groups_array = repo_model.get_users_groups_js()
-
-        defaults = c.repo_info.get_dict()
+        self.__load_defaults()
 
-        #fill owner
-        if c.repo_info.user:
-            defaults.update({'user': c.repo_info.user.username})
-        else:
-            replacement_user = self.sa.query(User)\
-            .filter(User.admin == True).first().username
-            defaults.update({'user': replacement_user})
-
-        #fill repository users
-        for p in c.repo_info.repo_to_perm:
-            defaults.update({'u_perm_%s' % p.user.username:
-                             p.permission.permission_name})
-
-        #fill repository groups
-        for p in c.repo_info.users_group_to_perm:
-            defaults.update({'g_perm_%s' % p.users_group.users_group_name:
-                             p.permission.permission_name})
+        defaults = RepoModel()._get_defaults(repo_name)
 
         return htmlfill.render(
             render('settings/repo_settings.html'),
@@ -100,17 +89,22 @@
     def update(self, repo_name):
         repo_model = RepoModel()
         changed_name = repo_name
+        
+        self.__load_defaults()
+        
         _form = RepoSettingsForm(edit=True,
-                                 old_data={'repo_name': repo_name})()
+                                 old_data={'repo_name': repo_name},
+                                 repo_groups=c.repo_groups_choices)()
         try:
             form_result = _form.to_python(dict(request.POST))
+            
             repo_model.update(repo_name, form_result)
             invalidate_cache('get_repo_cached_%s' % repo_name)
             h.flash(_('Repository %s updated successfully' % repo_name),
                     category='success')
-            changed_name = form_result['repo_name']
+            changed_name = form_result['repo_name_full']
             action_logger(self.rhodecode_user, 'user_updated_repo',
-                              changed_name, '', self.sa)
+                          changed_name, '', self.sa)
         except formencode.Invalid, errors:
             c.repo_info = repo_model.get_by_repo_name(repo_name)
             c.users_array = repo_model.get_users_js()
--- a/rhodecode/lib/__init__.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/lib/__init__.py	Tue Oct 25 21:17:29 2011 +0200
@@ -394,13 +394,12 @@
     try:
         from vcs import get_repo
         from vcs.utils.helpers import get_scm
-        from vcs.exceptions import RepositoryError, VCSError
         repopath = os.path.join(os.path.dirname(__file__), '..', '..')
         scm = get_scm(repopath)[0]
         repo = get_repo(path=repopath, alias=scm)
         tip = repo.get_changeset()
         return (tip.revision, tip.short_id)
-    except (ImportError, RepositoryError, VCSError), err:
+    except Exception, err:
         if not quiet:
             print ("Cannot retrieve rhodecode's revision. Original error "
                    "was: %s" % err)
--- a/rhodecode/lib/auth_ldap.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/lib/auth_ldap.py	Tue Oct 25 21:17:29 2011 +0200
@@ -53,8 +53,10 @@
         if self.TLS_KIND == 'LDAPS':
             port = port or 689
             ldap_server_type = ldap_server_type + 's'
-
-        self.TLS_REQCERT = ldap.__dict__['OPT_X_TLS_' + tls_reqcert]
+        
+        OPT_X_TLS_DEMAND = 2
+        self.TLS_REQCERT = getattr(ldap, 'OPT_X_TLS_%s' % tls_reqcert, 
+                                   OPT_X_TLS_DEMAND)
         self.LDAP_SERVER_ADDRESS = server
         self.LDAP_SERVER_PORT = port
 
@@ -63,12 +65,12 @@
         self.LDAP_BIND_PASS = bind_pass
 
         self.LDAP_SERVER = "%s://%s:%s" % (ldap_server_type,
-                                               self.LDAP_SERVER_ADDRESS,
-                                               self.LDAP_SERVER_PORT)
+                                           self.LDAP_SERVER_ADDRESS,
+                                           self.LDAP_SERVER_PORT)
 
         self.BASE_DN = base_dn
         self.LDAP_FILTER = ldap_filter
-        self.SEARCH_SCOPE = ldap.__dict__['SCOPE_' + search_scope]
+        self.SEARCH_SCOPE = getattr(ldap, 'SCOPE_%s' % search_scope)
         self.attr_login = attr_login
 
     def authenticate_ldap(self, username, password):
@@ -88,7 +90,9 @@
         if "," in username:
             raise LdapUsernameError("invalid character in username: ,")
         try:
-            ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts')
+            if hasattr(ldap,'OPT_X_TLS_CACERTDIR'):
+                ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, 
+                                '/etc/openldap/cacerts')
             ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF)
             ldap.set_option(ldap.OPT_RESTART, ldap.OPT_ON)
             ldap.set_option(ldap.OPT_TIMEOUT, 20)
--- a/rhodecode/lib/celerylib/tasks.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/lib/celerylib/tasks.py	Tue Oct 25 21:17:29 2011 +0200
@@ -356,9 +356,10 @@
     tls = str2bool(email_config.get('smtp_use_tls'))
     ssl = str2bool(email_config.get('smtp_use_ssl'))
     debug = str2bool(config.get('debug'))
+    smtp_auth = email_config.get('smtp_auth')
 
     try:
-        m = SmtpMailer(mail_from, user, passwd, mail_server,
+        m = SmtpMailer(mail_from, user, passwd, mail_server,smtp_auth,
                        mail_port, ssl, tls, debug=debug)
         m.send(recipients, subject, body)
     except:
--- a/rhodecode/lib/middleware/simplegit.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/lib/middleware/simplegit.py	Tue Oct 25 21:17:29 2011 +0200
@@ -167,6 +167,8 @@
                     username = REMOTE_USER(environ)
                     try:
                         user = self.__get_user(username)
+                        if user is None:
+                            return HTTPForbidden()(environ, start_response)                        
                         username = user.username
                     except:
                         log.error(traceback.format_exc())
--- a/rhodecode/lib/smtp_mailer.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/lib/smtp_mailer.py	Tue Oct 25 21:17:29 2011 +0200
@@ -39,7 +39,7 @@
 class SmtpMailer(object):
     """SMTP mailer class
 
-    mailer = SmtpMailer(mail_from, user, passwd, mail_server,
+    mailer = SmtpMailer(mail_from, user, passwd, mail_server, smtp_auth
                         mail_port, ssl, tls)
     mailer.send(recipients, subject, body, attachment_files)
 
@@ -49,8 +49,8 @@
 
     """
 
-    def __init__(self, mail_from, user, passwd, mail_server,
-                    mail_port=None, ssl=False, tls=False, debug=False):
+    def __init__(self, mail_from, user, passwd, mail_server, smtp_auth=None,
+                 mail_port=None, ssl=False, tls=False, debug=False):
 
         self.mail_from = mail_from
         self.mail_server = mail_server
@@ -60,6 +60,7 @@
         self.ssl = ssl
         self.tls = tls
         self.debug = debug
+        self.auth = smtp_auth
 
     def send(self, recipients=[], subject='', body='', attachment_files=None):
 
@@ -78,9 +79,11 @@
             smtp_serv.set_debuglevel(1)
 
         smtp_serv.ehlo()
+        if self.auth:
+            smtp_serv.esmtp_features["auth"] = self.auth
 
-        #if server requires authorization you must provide login and password
-        #but only if we have them
+        # if server requires authorization you must provide login and password
+        # but only if we have them
         if self.user and self.passwd:
             smtp_serv.login(self.user, self.passwd)
 
@@ -156,6 +159,7 @@
         if isinstance(msg_file, str):
             return open(msg_file, "rb").read()
         else:
-            #just for safe seek to 0
+            # just for safe seek to 0
             msg_file.seek(0)
             return msg_file.read()
+
--- a/rhodecode/model/db.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/model/db.py	Tue Oct 25 21:17:29 2011 +0200
@@ -30,11 +30,8 @@
 from datetime import date
 
 from sqlalchemy import *
-from sqlalchemy.exc import DatabaseError
 from sqlalchemy.ext.hybrid import hybrid_property
-from sqlalchemy.orm import relationship, backref, joinedload, class_mapper, \
-    validates
-from sqlalchemy.orm.interfaces import MapperExtension
+from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
 from beaker.cache import cache_region, region_invalidate
 
 from vcs import get_backend
@@ -60,24 +57,24 @@
 class ModelSerializer(json.JSONEncoder):
     """
     Simple Serializer for JSON,
-    
+
     usage::
-        
+
         to make object customized for serialization implement a __json__
         method that will return a dict for serialization into json
-        
+
     example::
-        
+
         class Task(object):
-        
+
             def __init__(self, name, value):
                 self.name = name
                 self.value = value
-        
+
             def __json__(self):
                 return dict(name=self.name,
-                            value=self.value)     
-        
+                            value=self.value)
+
     """
 
     def default(self, obj):
@@ -129,11 +126,15 @@
     @classmethod
     def get(cls, id_):
         if id_:
-            return Session.query(cls).get(id_)
+            return cls.query().get(id_)
+
+    @classmethod
+    def getAll(cls):
+        return cls.query().all()
 
     @classmethod
     def delete(cls, id_):
-        obj = Session.query(cls).get(id_)
+        obj = cls.query().get(id_)
         Session.delete(obj)
         Session.commit()
 
@@ -160,13 +161,13 @@
         v = self._app_settings_value
         if v == 'ldap_active':
             v = str2bool(v)
-        return v 
+        return v
 
     @app_settings_value.setter
-    def app_settings_value(self,val):
+    def app_settings_value(self, val):
         """
         Setter that will always make sure we use unicode in app_settings_value
-        
+
         :param val:
         """
         self._app_settings_value = safe_unicode(val)
@@ -178,13 +179,13 @@
 
     @classmethod
     def get_by_name(cls, ldap_key):
-        return Session.query(cls)\
+        return cls.query()\
             .filter(cls.app_settings_name == ldap_key).scalar()
 
     @classmethod
     def get_app_settings(cls, cache=False):
 
-        ret = Session.query(cls)
+        ret = cls.query()
 
         if cache:
             ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
@@ -200,7 +201,7 @@
 
     @classmethod
     def get_ldap_settings(cls, cache=False):
-        ret = Session.query(cls)\
+        ret = cls.query()\
                 .filter(cls.app_settings_name.startswith('ldap_')).all()
         fd = {}
         for row in ret:
@@ -227,7 +228,7 @@
 
     @classmethod
     def get_by_key(cls, key):
-        return Session.query(cls).filter(cls.ui_key == key)
+        return cls.query().filter(cls.ui_key == key)
 
 
     @classmethod
@@ -311,7 +312,7 @@
 
     @classmethod
     def get_by_api_key(cls, api_key):
-        return Session.query(cls).filter(cls.api_key == api_key).one()
+        return cls.query().filter(cls.api_key == api_key).one()
 
     def update_lastlogin(self):
         """Update user lastlogin"""
@@ -376,11 +377,11 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = Session.query(cls)\
-            .filter(cls.users_group_name.ilike(group_name))
+            gr = cls.query()\
+                .filter(cls.users_group_name.ilike(group_name))
         else:
-            gr = Session.query(UsersGroup)\
-                .filter(UsersGroup.users_group_name == group_name)
+            gr = cls.query()\
+                .filter(cls.users_group_name == group_name)
         if cache:
             gr = gr.options(FromCache("sql_cache_short",
                                           "get_user_%s" % group_name))
@@ -389,7 +390,7 @@
 
     @classmethod
     def get(cls, users_group_id, cache=False):
-        users_group = Session.query(cls)
+        users_group = cls.query()
         if cache:
             users_group = users_group.options(FromCache("sql_cache_short",
                                     "get_users_group_%s" % users_group_id))
@@ -422,10 +423,10 @@
                     Session.flush()
                     members_list = []
                     if v:
+                        v = [v] if isinstance(v, basestring) else v
                         for u_id in set(v):
-                            members_list.append(UsersGroupMember(
-                                                            users_group_id,
-                                                            u_id))
+                            member = UsersGroupMember(users_group_id, u_id)
+                            members_list.append(member)
                     setattr(users_group, 'members', members_list)
                 setattr(users_group, k, v)
 
@@ -457,7 +458,6 @@
             Session.rollback()
             raise
 
-
 class UsersGroupMember(Base, BaseModel):
     __tablename__ = 'users_groups_members'
     __table_args__ = {'extend_existing':True}
@@ -473,6 +473,15 @@
         self.users_group_id = gr_id
         self.user_id = u_id
 
+    @staticmethod
+    def add_user_to_group(group, user):
+        ugm = UsersGroupMember()
+        ugm.users_group = group
+        ugm.user = user
+        Session.add(ugm)
+        Session.commit()
+        return ugm
+
 class Repository(Base, BaseModel):
     __tablename__ = 'repositories'
     __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},)
@@ -510,29 +519,27 @@
     @classmethod
     def url_sep(cls):
         return '/'
-    
+
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session.query(cls).filter(cls.repo_name == repo_name)
-
         q = q.options(joinedload(Repository.fork))\
                 .options(joinedload(Repository.user))\
-                .options(joinedload(Repository.group))\
-
+                .options(joinedload(Repository.group))
         return q.one()
 
     @classmethod
     def get_repo_forks(cls, repo_id):
-        return Session.query(cls).filter(Repository.fork_id == repo_id)
+        return cls.query().filter(Repository.fork_id == repo_id)
 
     @classmethod
     def base_path(cls):
         """
         Returns base path when all repos are stored
-        
+
         :param cls:
         """
-        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == 
+        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
                                               cls.url_sep())
         q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -568,7 +575,7 @@
         Returns base full path for that repository means where it actually
         exists on a filesystem
         """
-        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == 
+        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
                                               Repository.url_sep())
         q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -585,7 +592,7 @@
     def get_new_name(self, repo_name):
         """
         returns new full repository name based on assigned group and new new
-        
+
         :param group_name:
         """
         path_prefix = self.group.full_path_splitted if self.group else []
@@ -606,7 +613,7 @@
         baseui._tcfg = config.config()
 
 
-        ret = Session.query(RhodeCodeUi)\
+        ret = RhodeCodeUi.query()\
             .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
 
         hg_ui = ret
@@ -622,7 +629,7 @@
     def is_valid(cls, repo_name):
         """
         returns True if given repo name is a valid filesystem repository
-         
+
         @param cls:
         @param repo_name:
         """
@@ -661,7 +668,7 @@
         None otherwise. `cache_active = False` means that this cache
         state is not valid and needs to be invalidated
         """
-        return Session.query(CacheInvalidation)\
+        return CacheInvalidation.query()\
             .filter(CacheInvalidation.cache_key == self.repo_name)\
             .filter(CacheInvalidation.cache_active == False)\
             .scalar()
@@ -670,7 +677,7 @@
         """
         set a cache for invalidation for this instance
         """
-        inv = Session.query(CacheInvalidation)\
+        inv = CacheInvalidation.query()\
             .filter(CacheInvalidation.cache_key == self.repo_name)\
             .scalar()
 
@@ -763,17 +770,26 @@
 
         repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
                               for x in cls.query().all()])
-        
-        repo_groups = sorted(repo_groups,key=lambda t: t[1].split(sep)[0])        
+
+        repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
         return repo_groups
-    
+
     @classmethod
     def url_sep(cls):
         return '/'
 
     @classmethod
-    def get_by_group_name(cls, group_name):
-        return cls.query().filter(cls.group_name == group_name).scalar()
+    def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
+        if case_insensitive:
+            gr = cls.query()\
+                .filter(cls.group_name.ilike(group_name))
+        else:
+            gr = cls.query()\
+                .filter(cls.group_name == group_name)
+        if cache:
+            gr = gr.options(FromCache("sql_cache_short",
+                                          "get_group_%s" % group_name))
+        return gr.scalar()
 
     @property
     def parents(self):
@@ -801,7 +817,7 @@
 
     @property
     def children(self):
-        return Session.query(Group).filter(Group.parent_group == self)
+        return Group.query().filter(Group.parent_group == self)
 
     @property
     def name(self):
@@ -817,7 +833,7 @@
 
     @property
     def repositories(self):
-        return Session.query(Repository).filter(Repository.group == self)
+        return Repository.query().filter(Repository.group == self)
 
     @property
     def repositories_recursive_count(self):
@@ -836,10 +852,11 @@
     def get_new_name(self, group_name):
         """
         returns new full group name based on parent and new name
-        
+
         :param group_name:
         """
-        path_prefix = self.parent_group.full_path_splitted if self.parent_group else []
+        path_prefix = (self.parent_group.full_path_splitted if 
+                       self.parent_group else [])
         return Group.url_sep().join(path_prefix + [group_name])
 
 
@@ -856,7 +873,7 @@
 
     @classmethod
     def get_by_key(cls, key):
-        return Session.query(cls).filter(cls.permission_name == key).scalar()
+        return cls.query().filter(cls.permission_name == key).scalar()
 
 class RepoToPerm(Base, BaseModel):
     __tablename__ = 'repo_to_perm'
@@ -885,7 +902,7 @@
         if not isinstance(perm, Permission):
             raise Exception('perm needs to be an instance of Permission class')
 
-        return Session.query(cls).filter(cls.user_id == user_id)\
+        return cls.query().filter(cls.user_id == user_id)\
             .filter(cls.permission == perm).scalar() is not None
 
     @classmethod
@@ -909,7 +926,7 @@
             raise Exception('perm needs to be an instance of Permission class')
 
         try:
-            Session.query(cls).filter(cls.user_id == user_id)\
+            cls.query().filter(cls.user_id == user_id)\
                 .filter(cls.permission == perm).delete()
             Session.commit()
         except:
@@ -945,7 +962,7 @@
         if not isinstance(perm, Permission):
             raise Exception('perm needs to be an instance of Permission class')
 
-        return Session.query(cls).filter(cls.users_group_id ==
+        return cls.query().filter(cls.users_group_id ==
                                          users_group_id)\
                                          .filter(cls.permission == perm)\
                                          .scalar() is not None
@@ -971,7 +988,7 @@
             raise Exception('perm needs to be an instance of Permission class')
 
         try:
-            Session.query(cls).filter(cls.users_group_id == users_group_id)\
+            cls.query().filter(cls.users_group_id == users_group_id)\
                 .filter(cls.permission == perm).delete()
             Session.commit()
         except:
@@ -1023,7 +1040,7 @@
 
     @classmethod
     def get_repo_followers(cls, repo_id):
-        return Session.query(cls).filter(cls.follows_repo_id == repo_id)
+        return cls.query().filter(cls.follows_repo_id == repo_id)
 
 class CacheInvalidation(Base, BaseModel):
     __tablename__ = 'cache_invalidation'
@@ -1049,3 +1066,4 @@
     repository_id = Column('repository_id', String(250), primary_key=True)
     repository_path = Column('repository_path', Text)
     version = Column('version', Integer)
+
--- a/rhodecode/model/forms.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/model/forms.py	Tue Oct 25 21:17:29 2011 +0200
@@ -185,20 +185,21 @@
 class ValidPasswordsMatch(formencode.validators.FancyValidator):
 
     def validate_python(self, value, state):
-
-        if value['password'] != value['password_confirmation']:
+        
+        pass_val = value.get('password') or value.get('new_password')
+        if pass_val != value['password_confirmation']:
             e_dict = {'password_confirmation':
                    _('Passwords do not match')}
             raise formencode.Invalid('', value, state, error_dict=e_dict)
 
 class ValidAuth(formencode.validators.FancyValidator):
     messages = {
-            'invalid_password':_('invalid password'),
-            'invalid_login':_('invalid user name'),
-            'disabled_account':_('Your account is disabled')
-
-            }
-    #error mapping
+        'invalid_password':_('invalid password'),
+        'invalid_login':_('invalid user name'),
+        'disabled_account':_('Your account is disabled')
+    }
+    
+    # error mapping
     e_dict = {'username':messages['invalid_login'],
               'password':messages['invalid_password']}
     e_dict_disable = {'username':messages['disabled_account']}
@@ -253,6 +254,7 @@
                 # db key This is an actual just the name to store in the
                 # database
                 repo_name_full = group_path + Group.url_sep() + repo_name
+                
             else:
                 group_path = ''
                 repo_name_full = repo_name
@@ -496,8 +498,6 @@
                                 'tooShort':_('Enter %(min)i characters or more')}
                                 )
 
-
-    #chained validators have access to all data
     chained_validators = [ValidAuth]
 
 def UserForm(edit=False, old_data={}):
@@ -508,15 +508,18 @@
                        ValidUsername(edit, old_data))
         if edit:
             new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
+            password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
             admin = StringBoolean(if_missing=False)
         else:
             password = All(UnicodeString(strip=True, min=6, not_empty=True))
+            password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
+            
         active = StringBoolean(if_missing=False)
         name = UnicodeString(strip=True, min=1, not_empty=True)
         lastname = UnicodeString(strip=True, min=1, not_empty=True)
         email = All(Email(not_empty=True), UniqSystemEmail(old_data))
 
-        chained_validators = [ValidPassword]
+        chained_validators = [ValidPasswordsMatch, ValidPassword]
 
     return _UserForm
 
@@ -616,16 +619,19 @@
 
     return _RepoForkForm
 
-def RepoSettingsForm(edit=False, old_data={}):
+def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
+                     repo_groups=[]):
     class _RepoForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = False
         repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
                         SlugifyName())
         description = UnicodeString(strip=True, min=1, not_empty=True)
+        repo_group = OneOf(repo_groups, hideList=True)
         private = StringBoolean(if_missing=False)
 
-        chained_validators = [ValidRepoName(edit, old_data), ValidPerms, ValidSettings]
+        chained_validators = [ValidRepoName(edit, old_data), ValidPerms, 
+                              ValidSettings]
     return _RepoForm
 
 
--- a/rhodecode/model/repo.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/model/repo.py	Tue Oct 25 21:17:29 2011 +0200
@@ -94,6 +94,46 @@
                                         for gr in users_groups])
         return users_groups_array
 
+    def _get_defaults(self, repo_name):
+        """
+        Get's information about repository, and returns a dict for 
+        usage in forms
+        
+        :param repo_name:
+        """
+
+        repo_info = Repository.get_by_repo_name(repo_name)
+
+        if repo_info is None:
+            return None
+
+        defaults = repo_info.get_dict()
+        group, repo_name = repo_info.groups_and_repo
+        defaults['repo_name'] = repo_name
+        defaults['repo_group'] = getattr(group[-1] if group else None,
+                                         'group_id', None)
+
+        # fill owner
+        if repo_info.user:
+            defaults.update({'user': repo_info.user.username})
+        else:
+            replacement_user = User.query().filter(User.admin ==
+                                                   True).first().username
+            defaults.update({'user': replacement_user})
+
+        # fill repository users
+        for p in repo_info.repo_to_perm:
+            defaults.update({'u_perm_%s' % p.user.username:
+                             p.permission.permission_name})
+
+        # fill repository groups
+        for p in repo_info.users_group_to_perm:
+            defaults.update({'g_perm_%s' % p.users_group.users_group_name:
+                             p.permission.permission_name})
+
+        return defaults
+
+
     def update(self, repo_name, form_data):
         try:
             cur_repo = self.get_by_repo_name(repo_name, cache=False)
@@ -151,7 +191,7 @@
                 elif k == 'repo_name':
                     pass
                 elif k == 'repo_group':
-                    cur_repo.group_id = v
+                    cur_repo.group = Group.get(v)
 
                 else:
                     setattr(cur_repo, k, v)
@@ -305,7 +345,7 @@
         :param parent_id:
         :param clone_uri:
         """
-        from rhodecode.lib.utils import is_valid_repo,is_valid_repos_group
+        from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
 
         if new_parent_id:
             paths = Group.get(new_parent_id).full_path.split(Group.url_sep())
@@ -316,7 +356,7 @@
         repo_path = os.path.join(*map(lambda x:safe_str(x),
                                 [self.repos_path, new_parent_path, repo_name]))
 
-        
+
         # check if this path is not a repository
         if is_valid_repo(repo_path, self.repos_path):
             raise Exception('This path %s is a valid repository' % repo_path)
@@ -324,7 +364,7 @@
         # check if this path is a group
         if is_valid_repos_group(repo_path, self.repos_path):
             raise Exception('This path %s is a valid group' % repo_path)
-                
+
         log.info('creating repo %s in %s @ %s', repo_name, repo_path,
                  clone_uri)
         backend = get_backend(alias)
@@ -368,3 +408,4 @@
                                           % (datetime.today()\
                                              .strftime('%Y%m%d_%H%M%S_%f'),
                                             repo.repo_name)))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/model/repo_permission.py	Tue Oct 25 21:17:29 2011 +0200
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.model.users_group
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    repository permission model for RhodeCode
+
+    :created_on: Oct 1, 2011
+    :author: nvinot
+    :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+from rhodecode.model.db import BaseModel, RepoToPerm, Permission
+from rhodecode.model.meta import Session
+
+log = logging.getLogger(__name__)
+
+class RepositoryPermissionModel(BaseModel):
+    def get_user_permission(self, repository, user):
+        return RepoToPerm.query() \
+                .filter(RepoToPerm.user == user) \
+                .filter(RepoToPerm.repository == repository) \
+                .scalar()
+
+    def update_user_permission(self, repository, user, permission):
+        permission = Permission.get_by_key(permission)
+        current = self.get_user_permission(repository, user)
+        if current:
+            if not current.permission is permission:
+                current.permission = permission
+        else:
+            p = RepoToPerm()
+            p.user = user
+            p.repository = repository
+            p.permission = permission
+            Session.add(p)
+        Session.commit()
+
+    def delete_user_permission(self, repository, user):
+        current = self.get_user_permission(repository, user)
+        if current:
+            Session.delete(current)
+            Session.commit()
+
+    def update_or_delete_user_permission(self, repository, user, permission):
+        if permission:
+            self.update_user_permission(repository, user, permission)
+        else:
+            self.delete_user_permission(repository, user)
--- a/rhodecode/model/repos_group.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/model/repos_group.py	Tue Oct 25 21:17:29 2011 +0200
@@ -127,8 +127,8 @@
         try:
             repos_group = Group.get(repos_group_id)
             old_path = repos_group.full_path
-
-            #change properties
+                
+            # change properties
             repos_group.group_description = form_data['group_description']
             repos_group.parent_group = Group.get(form_data['group_parent_id'])
             repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
--- a/rhodecode/model/user.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/model/user.py	Tue Oct 25 21:17:29 2011 +0200
@@ -49,7 +49,6 @@
 
 
 class UserModel(BaseModel):
-
     def get(self, user_id, cache=False):
         user = self.sa.query(User)
         if cache:
@@ -87,6 +86,7 @@
             new_user.api_key = generate_api_key(form_data['username'])
             self.sa.add(new_user)
             self.sa.commit()
+            return new_user
         except:
             log.error(traceback.format_exc())
             self.sa.rollback()
@@ -96,6 +96,7 @@
         """
         Checks if user is in database, if not creates this user marked
         as ldap user
+        
         :param username:
         :param password:
         :param user_dn:
@@ -386,3 +387,4 @@
                                                      repository.repo_name] = p
 
         return user
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/model/users_group.py	Tue Oct 25 21:17:29 2011 +0200
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.model.users_group
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    users group model for RhodeCode
+
+    :created_on: Oct 1, 2011
+    :author: nvinot
+    :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+import traceback
+
+from rhodecode.model import BaseModel
+from rhodecode.model.caching_query import FromCache
+from rhodecode.model.db import UsersGroupMember, UsersGroup
+
+log = logging.getLogger(__name__)
+
+class UsersGroupModel(BaseModel):
+
+    def get(self, users_group_id, cache = False):
+        users_group = UsersGroup.query()
+        if cache:
+            users_group = users_group.options(FromCache("sql_cache_short",
+                                          "get_users_group_%s" % users_group_id))
+        return users_group.get(users_group_id)
+
+    def get_by_name(self, name, cache = False, case_insensitive = False):
+        users_group = UsersGroup.query()
+        if case_insensitive:
+            users_group = users_group.filter(UsersGroup.users_group_name.ilike(name))
+        else:
+            users_group = users_group.filter(UsersGroup.users_group_name == name)
+        if cache:
+            users_group = users_group.options(FromCache("sql_cache_short",
+                                          "get_users_group_%s" % name))
+        return users_group.scalar()
+
+    def create(self, form_data):
+        try:
+            new_users_group = UsersGroup()
+            for k, v in form_data.items():
+                setattr(new_users_group, k, v)
+
+            self.sa.add(new_users_group)
+            self.sa.commit()
+            return new_users_group
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
+
+    def add_user_to_group(self, users_group, user):
+        for m in users_group.members:
+            u = m.user
+            if u.user_id == user.user_id:
+                return m
+
+        try:
+            users_group_member = UsersGroupMember()
+            users_group_member.user = user
+            users_group_member.users_group = users_group
+
+            users_group.members.append(users_group_member)
+            user.group_member.append(users_group_member)
+
+            self.sa.add(users_group_member)
+            self.sa.commit()
+            return users_group_member
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
--- a/rhodecode/templates/admin/repos_groups/repos_groups_add.html	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/templates/admin/repos_groups/repos_groups_add.html	Tue Oct 25 21:17:29 2011 +0200
@@ -29,7 +29,7 @@
         <div class="fields">
              <div class="field">
                 <div class="label">
-                    <label for="users_group_name">${_('Group name')}:</label>
+                    <label for="group_name">${_('Group name')}:</label>
                 </div>
                 <div class="input">
                     ${h.text('group_name',class_='medium')}
@@ -38,7 +38,7 @@
              
             <div class="field">
                 <div class="label label-textarea">
-                    <label for="description">${_('Description')}:</label>
+                    <label for="group_description">${_('Description')}:</label>
                 </div>
                 <div class="textarea text-area editor">
                     ${h.textarea('group_description',cols=23,rows=5,class_="medium")}
@@ -47,7 +47,7 @@
              
              <div class="field">
                  <div class="label">
-                     <label for="repo_group">${_('Group parent')}:</label>
+                     <label for="group_parent_id">${_('Group parent')}:</label>
                  </div>
                  <div class="input">
                      ${h.select('group_parent_id','',c.repo_groups,class_="medium")}
--- a/rhodecode/templates/admin/repos_groups/repos_groups_edit.html	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/templates/admin/repos_groups/repos_groups_edit.html	Tue Oct 25 21:17:29 2011 +0200
@@ -29,7 +29,7 @@
         <div class="fields">
              <div class="field">
                 <div class="label">
-                    <label for="users_group_name">${_('Group name')}:</label>
+                    <label for="group_name">${_('Group name')}:</label>
                 </div>
                 <div class="input">
                     ${h.text('group_name',class_='medium')}
@@ -38,7 +38,7 @@
              
 	        <div class="field">
 	            <div class="label label-textarea">
-	                <label for="description">${_('Description')}:</label>
+	                <label for="group_description">${_('Description')}:</label>
 	            </div>
 	            <div class="textarea text-area editor">
 	                ${h.textarea('group_description',cols=23,rows=5,class_="medium")}
@@ -47,7 +47,7 @@
              
 	         <div class="field">
 	             <div class="label">
-	                 <label for="repo_group">${_('Group parent')}:</label>
+	                 <label for="group_parent_id">${_('Group parent')}:</label>
 	             </div>
 	             <div class="input">
 	                 ${h.select('group_parent_id','',c.repo_groups,class_="medium")}
--- a/rhodecode/templates/admin/settings/settings.html	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/templates/admin/settings/settings.html	Tue Oct 25 21:17:29 2011 +0200
@@ -34,7 +34,7 @@
 		        <div class="checkboxes">
 		            <div class="checkbox">
 		                ${h.checkbox('destroy',True)}
-		                <label for="checkbox-1">
+		                <label for="destroy">
 		                <span class="tooltip" title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
 		                ${_('destroy old data')}</span> </label>
 		            </div>
@@ -56,12 +56,12 @@
         <div class="fields">
             <div class="field">
                 <div class="label label-checkbox">
-                    <label for="destroy">${_('index build option')}:</label>
+                    <label>${_('index build option')}:</label>
                 </div>
                 <div class="checkboxes">
                     <div class="checkbox">
                         ${h.checkbox('full_index',True)}
-                        <label for="checkbox-1">${_('build from scratch')}</label>
+                        <label for="full_index">${_('build from scratch')}</label>
                     </div>
                 </div>
             </div>
@@ -100,7 +100,7 @@
             
             <div class="field">
                 <div class="label">
-                    <label for="ga_code">${_('GA code')}:</label>
+                    <label for="rhodecode_ga_code">${_('GA code')}:</label>
                 </div>
                 <div class="input">
                     ${h.text('rhodecode_ga_code',size=30)}
@@ -124,7 +124,7 @@
              
              <div class="field">
                 <div class="label label-checkbox">
-                    <label for="web_push_ssl">${_('Web')}:</label>
+                    <label>${_('Web')}:</label>
                 </div>
                 <div class="checkboxes">
 					<div class="checkbox">
@@ -136,7 +136,7 @@
 
              <div class="field">
                 <div class="label label-checkbox">
-                    <label for="web_push_ssl">${_('Hooks')}:</label>
+                    <label>${_('Hooks')}:</label>
                 </div>
                 <div class="input">
                     ${h.link_to(_('advanced setup'),url('admin_edit_setting',setting_id='hooks'))}
--- a/rhodecode/templates/admin/users/user_add.html	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/templates/admin/users/user_add.html	Tue Oct 25 21:17:29 2011 +0200
@@ -44,7 +44,16 @@
                     ${h.password('password',class_='small')}
                 </div>
              </div>
-            
+             
+             <div class="field">
+                <div class="label">
+                    <label for="password_confirmation">${_('Password confirmation')}:</label>
+                </div>
+                <div class="input">
+                    ${h.password('password_confirmation',class_="small",autocomplete="off")}
+                </div>
+             </div>    
+                         
              <div class="field">
                 <div class="label">
                     <label for="name">${_('First Name')}:</label>
--- a/rhodecode/templates/admin/users/user_edit.html	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/templates/admin/users/user_edit.html	Tue Oct 25 21:17:29 2011 +0200
@@ -68,7 +68,16 @@
                     ${h.password('new_password',class_='medium',autocomplete="off")}
                 </div>
              </div>
-            
+             
+             <div class="field">
+                <div class="label">
+                    <label for="password_confirmation">${_('New password confirmation')}:</label>
+                </div>
+                <div class="input">
+                    ${h.password('password_confirmation',class_="medium",autocomplete="off")}
+                </div>
+             </div>
+                         
              <div class="field">
                 <div class="label">
                     <label for="name">${_('First Name')}:</label>
@@ -132,7 +141,7 @@
         <div class="fields">
              <div class="field">
                 <div class="label label-checkbox">
-                    <label for="">${_('Create repositories')}:</label>
+                    <label for="create_repo_perm">${_('Create repositories')}:</label>
                 </div>
                 <div class="checkboxes">
                     ${h.checkbox('create_repo_perm',value=True)}
--- a/rhodecode/templates/admin/users/user_edit_my_account.html	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/templates/admin/users/user_edit_my_account.html	Tue Oct 25 21:17:29 2011 +0200
@@ -57,7 +57,16 @@
 	                    ${h.password('new_password',class_="medium",autocomplete="off")}
 	                </div>
 	             </div>
-	            
+                 
+                 <div class="field">
+                    <div class="label">
+                        <label for="password_confirmation">${_('New password confirmation')}:</label>
+                    </div>
+                    <div class="input">
+                        ${h.password('password_confirmation',class_="medium",autocomplete="off")}
+                    </div>
+                 </div>
+                 	            
 	             <div class="field">
 	                <div class="label">
 	                    <label for="name">${_('First Name')}:</label>
@@ -154,10 +163,12 @@
 		        </tr>
 		     %endfor
 	     %else:
+            <div style="padding:5px 0px 10px 0px;">
 	     	${_('No repositories yet')} 
 	     	%if h.HasPermissionAny('hg.admin','hg.create.repository')():
-	     		${h.link_to(_('create one now'),h.url('admin_settings_create_repository'))}
+	     		${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-button-small")}
 	     	%endif
+            </div>
 	     %endif
 	     </tbody>
 	     </table>
--- a/rhodecode/templates/admin/users_groups/users_group_edit.html	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/templates/admin/users_groups/users_group_edit.html	Tue Oct 25 21:17:29 2011 +0200
@@ -253,7 +253,7 @@
         <div class="fields">
              <div class="field">
                 <div class="label label-checkbox">
-                    <label for="">${_('Create repositories')}:</label>
+                    <label for="create_repo_perm">${_('Create repositories')}:</label>
                 </div>
                 <div class="checkboxes">
                     ${h.checkbox('create_repo_perm',value=True)}
--- a/rhodecode/templates/settings/repo_settings.html	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/templates/settings/repo_settings.html	Tue Oct 25 21:17:29 2011 +0200
@@ -34,7 +34,14 @@
                     ${h.text('repo_name',class_="small")}
                 </div>
              </div>
-             
+            <div class="field">
+                <div class="label">
+                    <label for="repo_group">${_('Repository group')}:</label>
+                </div>
+                <div class="input">
+                    ${h.select('repo_group','',c.repo_groups,class_="medium")}
+                </div>
+            </div>             
             <div class="field">
                 <div class="label label-textarea">
                     <label for="description">${_('Description')}:</label>
--- a/rhodecode/tests/__init__.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/tests/__init__.py	Tue Oct 25 21:17:29 2011 +0200
@@ -77,8 +77,6 @@
         self.assertEqual(response.session['rhodecode_user'].username, username)
         return response.follow()
 
-
-
     def checkSessionFlash(self, response, msg):
         self.assertTrue('flash' in response.session)
         self.assertTrue(msg in response.session['flash'][0][1])
--- a/rhodecode/tests/functional/test_admin_settings.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/tests/functional/test_admin_settings.py	Tue Oct 25 21:17:29 2011 +0200
@@ -137,6 +137,7 @@
                                  params=dict(_method='put',
                                              username='test_admin',
                                              new_password=new_password,
+                                             password_confirmation = new_password,
                                              password='',
                                              name=new_name,
                                              lastname=new_lastname,
@@ -160,6 +161,7 @@
                                                             _method='put',
                                                             username='test_admin',
                                                             new_password=old_password,
+                                                            password_confirmation = old_password,
                                                             password='',
                                                             name=old_name,
                                                             lastname=old_lastname,
@@ -186,6 +188,7 @@
                                                             _method='put',
                                                             username='test_admin',
                                                             new_password='test12',
+                                                            password_confirmation = 'test122',
                                                             name='NewName',
                                                             lastname='NewLastname',
                                                             email=new_email,))
@@ -201,6 +204,7 @@
                                                             _method='put',
                                                             username='test_admin',
                                                             new_password='test12',
+                                                            password_confirmation = 'test122',
                                                             name='NewName',
                                                             lastname='NewLastname',
                                                             email=new_email,))
--- a/rhodecode/tests/functional/test_admin_users.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/tests/functional/test_admin_users.py	Tue Oct 25 21:17:29 2011 +0200
@@ -16,12 +16,14 @@
         self.log_user()
         username = 'newtestuser'
         password = 'test12'
+        password_confirmation = password
         name = 'name'
         lastname = 'lastname'
         email = 'mail@mail.com'
 
         response = self.app.post(url('users'), {'username':username,
                                                'password':password,
+                                               'password_confirmation':password_confirmation,
                                                'name':name,
                                                'active':True,
                                                'lastname':lastname,
@@ -90,6 +92,7 @@
 
         response = self.app.post(url('users'), {'username':username,
                                                'password':password,
+                                               'password_confirmation':password,
                                                'name':name,
                                                'active':True,
                                                'lastname':lastname,
--- a/rhodecode/tests/test_hg_operations.py	Mon Oct 17 20:08:59 2011 +0200
+++ b/rhodecode/tests/test_hg_operations.py	Tue Oct 25 21:17:29 2011 +0200
@@ -48,7 +48,8 @@
 from rhodecode.config.environment import load_environment
 
 rel_path = dn(dn(dn(os.path.abspath(__file__))))
-conf = appconfig('config:development.ini', relative_to=rel_path)
+
+conf = appconfig('config:%s' % sys.argv[1], relative_to=rel_path)
 load_environment(conf.global_conf, conf.local_conf)
 
 add_cache(conf)
@@ -56,10 +57,13 @@
 USER = 'test_admin'
 PASS = 'test12'
 HOST = '127.0.0.1:5000'
-DEBUG = True if sys.argv[1:] else False
+DEBUG = False
 print 'DEBUG:', DEBUG
 log = logging.getLogger(__name__)
 
+engine = engine_from_config(conf, 'sqlalchemy.db1.')
+init_model(engine)
+sa = meta.Session
 
 class Command(object):
 
@@ -96,22 +100,15 @@
         return res
     return __wrapp
 
-def get_session():
-    engine = engine_from_config(conf, 'sqlalchemy.db1.')
-    init_model(engine)
-    sa = meta.Session
-    return sa
-
 
 def create_test_user(force=True):
     print '\tcreating test user'
-    sa = get_session()
 
-    user = sa.query(User).filter(User.username == USER).scalar()
+    user = User.get_by_username(USER)
 
     if force and user is not None:
         print '\tremoving current user'
-        for repo in sa.query(Repository).filter(Repository.user == user).all():
+        for repo in Repository.query().filter(Repository.user == user).all():
             sa.delete(repo)
         sa.delete(user)
         sa.commit()
@@ -134,9 +131,8 @@
 
 def create_test_repo(force=True):
     from rhodecode.model.repo import RepoModel
-    sa = get_session()
 
-    user = sa.query(User).filter(User.username == USER).scalar()
+    user = User.get_by_username(USER)
     if user is None:
         raise Exception('user not found')
 
@@ -156,22 +152,17 @@
 
 
 def set_anonymous_access(enable=True):
-    sa = get_session()
-    user = sa.query(User).filter(User.username == 'default').one()
-    sa.expire(user)
+    user = User.get_by_username('default')
     user.active = enable
     sa.add(user)
     sa.commit()
-    sa.remove()
-    import time;time.sleep(3)
     print '\tanonymous access is now:', enable
-
+    if enable != User.get_by_username('default').active:
+        raise Exception('Cannot set anonymous access')
 
 def get_anonymous_access():
-    sa = get_session()
-    obj1 = sa.query(User).filter(User.username == 'default').one()
-    sa.expire(obj1)
-    return obj1.active
+    user = User.get_by_username('default')
+    return user.active
 
 
 #==============================================================================
@@ -378,16 +369,15 @@
 
 @test_wrapp
 def get_logs():
-    sa = get_session()
-    return len(sa.query(UserLog).all())
+    return UserLog.query().all()
 
 @test_wrapp
 def test_logs(initial):
-    sa = get_session()
-    logs = sa.query(UserLog).all()
-    operations = 7
-    if initial + operations != len(logs):
-        raise Exception("missing number of logs %s vs %s" % (initial, len(logs)))
+    logs = UserLog.query().all()
+    operations = 4
+    if len(initial) + operations != len(logs):
+        raise Exception("missing number of logs initial:%s vs current:%s" % \
+                            (len(initial), len(logs)))
 
 
 if __name__ == '__main__':
@@ -395,18 +385,17 @@
     create_test_repo()
 
     initial_logs = get_logs()
+    print 'initial activity logs: %s' % len(initial_logs)
 
-#    test_push_modify_file()
+    #test_push_modify_file()
     test_clone_with_credentials()
     test_clone_wrong_credentials()
 
-
     test_push_new_file(commits=2, with_clone=True)
 
     test_clone_anonymous()
     test_push_wrong_path()
 
-
     test_push_wrong_credentials()
 
     test_logs(initial_logs)