changeset 3530:53eafc983b5c beta

Merge
author leonardo
date Mon, 04 Mar 2013 18:42:14 +0100
parents 1c32b72930fa (current diff) 151a83be8ad5 (diff)
children 1c2371dc86bd
files requires.txt rhodecode/lib/helpers.py rhodecode/public/css/style.css rhodecode/public/js/rhodecode.js rhodecode/templates/base/base.html rhodecode/templates/base/root.html rhodecode/templates/branches/branches.html rhodecode/templates/changelog/changelog.html rhodecode/templates/index_base.html rhodecode/templates/tags/tags.html
diffstat 87 files changed, 1143 insertions(+), 1018 deletions(-) [+]
line wrap: on
line diff
--- a/CONTRIBUTORS	Mon Mar 04 18:30:50 2013 +0100
+++ b/CONTRIBUTORS	Mon Mar 04 18:42:14 2013 +0100
@@ -33,3 +33,4 @@
     Philip Jameson <philip.j@hostdime.com>
     Mads Kiilerich <madski@unity3d.com>
     Dan Sheridan <djs@adelard.com>
+    Dennis Brakhane <brakhane@googlemail.com>
--- a/README.rst	Mon Mar 04 18:30:50 2013 +0100
+++ b/README.rst	Mon Mar 04 18:42:14 2013 +0100
@@ -75,7 +75,7 @@
 - Supports http/https, LDAP, AD, proxy-pass authentication.
 - Full permissions (private/read/write/admin) together with IP restrictions for each repository,
   additional explicit forking and repository creation permissions.
-- Users groups for easier permission management
+- User groups for easier permission management
 - Repository groups let you group repos and manage them easier.
 - Users can fork other users repos, and compare them at any time.
 - Integrates easily with other systems, with custom created mappers you can connect it to almost
--- a/docs/api/api.rst	Mon Mar 04 18:30:50 2013 +0100
+++ b/docs/api/api.rst	Mon Mar 04 18:42:14 2013 +0100
@@ -436,7 +436,7 @@
 get_users_group
 ---------------
 
-Gets an existing users group. This command can be executed only using api_key
+Gets an existing user group. This command can be executed only using api_key
 belonging to user with admin rights.
 
 
@@ -446,7 +446,7 @@
     api_key : "<api_key>"
     method :  "get_users_group"
     args :    {
-                "usersgroupid" : "<users group id or name>"
+                "usersgroupid" : "<user group id or name>"
               }
 
 OUTPUT::
@@ -479,7 +479,7 @@
 get_users_groups
 ----------------
 
-Lists all existing users groups. This command can be executed only using
+Lists all existing user groups. This command can be executed only using
 api_key belonging to user with admin rights.
 
 
@@ -507,7 +507,7 @@
 create_users_group
 ------------------
 
-Creates new users group. This command can be executed only using api_key
+Creates new user group. This command can be executed only using api_key
 belonging to user with admin rights
 
 
@@ -525,7 +525,7 @@
 
     id : <id_given_in_input>
     result: {
-              "msg": "created new users group `<groupname>`",
+              "msg": "created new user group `<groupname>`",
               "users_group": {
                      "users_group_id" : "<id>",
                      "group_name" :     "<groupname>",
@@ -538,7 +538,7 @@
 add_user_to_users_group
 -----------------------
 
-Adds a user to a users group. If user exists in that group success will be
+Adds a user to a user group. If user exists in that group success will be
 `false`. This command can be executed only using api_key
 belonging to user with admin rights
 
@@ -549,7 +549,7 @@
     api_key : "<api_key>"
     method :  "add_user_users_group"
     args:     {
-                "usersgroupid" : "<users group id or name>",
+                "usersgroupid" : "<user group id or name>",
                 "userid" : "<user_id or username>",
               }
 
@@ -558,7 +558,7 @@
     id : <id_given_in_input>
     result: {
               "success": True|False # depends on if member is in group
-              "msg": "added member `<username>` to users group `<groupname>` |
+              "msg": "added member `<username>` to user group `<groupname>` |
                       User is already in that group"
             }
     error:  null
@@ -567,7 +567,7 @@
 remove_user_from_users_group
 ----------------------------
 
-Removes a user from a users group. If user is not in given group success will
+Removes a user from a user group. If user is not in given group success will
 be `false`. This command can be executed only
 using api_key belonging to user with admin rights
 
@@ -578,7 +578,7 @@
     api_key : "<api_key>"
     method :  "remove_user_from_users_group"
     args:     {
-                "usersgroupid" : "<users group id or name>",
+                "usersgroupid" : "<user group id or name>",
                 "userid" : "<user_id or username>",
               }
 
@@ -587,7 +587,7 @@
     id : <id_given_in_input>
     result: {
               "success":  True|False,  # depends on if member is in group
-              "msg": "removed member <username> from users group <groupname> |
+              "msg": "removed member <username> from user group <groupname> |
                       User wasn't in group"
             }
     error:  null
@@ -929,7 +929,7 @@
 grant_users_group_permission
 ----------------------------
 
-Grant permission for users group on given repository, or update
+Grant permission for user group on given repository, or update
 existing one if found. This command can be executed only using
 api_key belonging to user with admin rights.
 
@@ -941,7 +941,7 @@
     method :  "grant_users_group_permission"
     args:     {
                 "repoid" : "<reponame or repo_id>"
-                "usersgroupid" : "<users group id or name>"
+                "usersgroupid" : "<user group id or name>"
                 "perm" : "(repository.(none|read|write|admin))",
               }
 
@@ -958,7 +958,7 @@
 revoke_users_group_permission
 -----------------------------
 
-Revoke permission for users group on given repository.This command can be
+Revoke permission for user group on given repository.This command can be
 executed only using api_key belonging to user with admin rights.
 
 INPUT::
@@ -968,7 +968,7 @@
     method  : "revoke_users_group_permission"
     args:     {
                 "repoid" : "<reponame or repo_id>"
-                "usersgroupid" : "<users group id or name>"
+                "usersgroupid" : "<user group id or name>"
               }
 
 OUTPUT::
--- a/docs/changelog.rst	Mon Mar 04 18:30:50 2013 +0100
+++ b/docs/changelog.rst	Mon Mar 04 18:42:14 2013 +0100
@@ -196,7 +196,7 @@
 fixes
 +++++
 
-- fixed #570 explicit users group permissions can overwrite owner permissions
+- fixed #570 explicit user group permissions can overwrite owner permissions
 - fixed #578 set proper PATH with current Python for Git
   hooks to execute within same Python as RhodeCode
 - fixed issue with Git bare repos that ends with .git in name
@@ -385,7 +385,7 @@
 - created rcextensions module with additional mappings (ref #322) and
   post push/pull/create repo hooks callbacks
 - implemented #377 Users view for his own permissions on account page
-- #399 added inheritance of permissions for users group on repos groups
+- #399 added inheritance of permissions for user group on repos groups
 - #401 repository group is automatically pre-selected when adding repos
   inside a repository group
 - added alternative HTTP 403 response when client failed to authenticate. Helps
@@ -520,7 +520,7 @@
   and groups
 - fixes #271 rare JSON serialization problem with statistics
 - fixes #337 missing validation check for conflicting names of a group with a
-  repositories group
+  repository group
 - #340 fixed session problem for mysql and celery tasks
 - fixed #331 RhodeCode mangles repository names if the a repository group
   contains the "full path" to the repositories
@@ -654,7 +654,7 @@
 - implemented #93 customizable changelog on combined revision ranges -
   equivalent of githubs compare view
 - implemented #108 extended and more powerful LDAP configuration
-- implemented #56 users groups
+- implemented #56 user groups
 - major code rewrites optimized codes for speed and memory usage
 - raw and diff downloads are now in git format
 - setup command checks for write access to given path
--- a/docs/installation_win.rst	Mon Mar 04 18:30:50 2013 +0100
+++ b/docs/installation_win.rst	Mon Mar 04 18:42:14 2013 +0100
@@ -47,7 +47,7 @@
    required, you can uncheck them
 
 .. note::
-   
+
    64bit: You also need to install the Microsoft Windows SDK for .NET 3.5 SP1 (.NET 4.0 won't work).
    Download from: http://www.microsoft.com/en-us/download/details.aspx?id=3138
 
@@ -90,7 +90,7 @@
   .. note::
 
      64bit: Download and install the 64bit version.
-     At the time of writing you can find this at: 
+     At the time of writing you can find this at:
      http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win-amd64-py2.7.exe/download
 
 Step4 - Python BIN
--- a/docs/theme/nature/static/pygments.css	Mon Mar 04 18:30:50 2013 +0100
+++ b/docs/theme/nature/static/pygments.css	Mon Mar 04 18:42:14 2013 +0100
@@ -51,4 +51,4 @@
 .vc { color: #ff99ff } /* Name.Variable.Class */
 .vg { color: #ff99ff } /* Name.Variable.Global */
 .vi { color: #ff99ff } /* Name.Variable.Instance */
-.il { color: #009999 } /* Literal.Number.Integer.Long */
\ No newline at end of file
+.il { color: #009999 } /* Literal.Number.Integer.Long */
--- a/docs/usage/performance.rst	Mon Mar 04 18:30:50 2013 +0100
+++ b/docs/usage/performance.rst	Mon Mar 04 18:42:14 2013 +0100
@@ -46,19 +46,17 @@
     large traffic (large amount of users, CI servers etc). RhodeCode can be
     scaled horizontally on one (recommended) or multiple machines. In order
     to scale horizontally you need to do the following:
-    
+
     - each instance needs it's own .ini file and unique `instance_id` set in them
-    - each instance `data` storage needs to be configured to be stored on a 
+    - each instance `data` storage needs to be configured to be stored on a
       shared disk storage, preferably together with repositories. This `data`
       dir contains template caches, sessions, whoosh index and it's used for
       tasks locking (so it's safe across multiple instances). Set the
       `cache_dir`, `index_dir`, `beaker.cache.data_dir`, `beaker.cache.lock_dir`
-      variables in each .ini file to shared location across RhodeCode instances 
+      variables in each .ini file to shared location across RhodeCode instances
     - if celery is used each instance should run separate celery instance, but
       the message broken should be common to all of them (ex one rabbitmq
-      shared server)    
+      shared server)
     - load balance using round robin or ip hash, recommended is writing LB rules
       that will separate regular user traffic from automated processes like CI
       servers or build bots.
-
-
--- a/requires.txt	Mon Mar 04 18:30:50 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-waitress==0.8.1
-webob==1.0.8
-Pylons==1.0.0
-Beaker==1.6.4
-WebHelpers==1.3
-formencode==1.2.4
-SQLAlchemy==0.7.8
-Mako==0.7.2
-pygments>=1.5
-whoosh>=2.4.0,<2.5
-celery>=2.2.5,<2.3
-babel
-python-dateutil>=1.5.0,<2.0.0
-dulwich>=0.8.5,<0.9.0
-markdown==2.1.1
-docutils==0.8.1
-simplejson==2.5.2
-mock
-py-bcrypt
-mercurial==2.3.0
\ No newline at end of file
--- a/rhodecode/config/routing.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/config/routing.py	Mon Mar 04 18:42:14 2013 +0100
@@ -48,7 +48,7 @@
 
     def check_group(environ, match_dict):
         """
-        check for valid repositories group for proper 404 handling
+        check for valid repository group for proper 404 handling
 
         :param environ:
         :param match_dict:
@@ -235,7 +235,7 @@
         m.connect("user_ips_delete", "/users_ips/{id}",
                   action="delete_ip", conditions=dict(method=["DELETE"]))
 
-    #ADMIN USERS GROUPS REST ROUTES
+    #ADMIN USER GROUPS REST ROUTES
     with rmap.submapper(path_prefix=ADMIN_PREFIX,
                         controller='admin/users_groups') as m:
         m.connect("users_groups", "/users_groups",
--- a/rhodecode/controllers/admin/notifications.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/controllers/admin/notifications.py	Mon Mar 04 18:42:14 2013 +0100
@@ -28,7 +28,7 @@
 
 from pylons import request
 from pylons import tmpl_context as c, url
-from pylons.controllers.util import redirect
+from pylons.controllers.util import redirect, abort
 
 from webhelpers.paginate import Page
 
@@ -117,7 +117,7 @@
                     Session().commit()
                     return 'ok'
         except Exception:
-            Session.rollback()
+            Session().rollback()
             log.error(traceback.format_exc())
         return 'fail'
 
@@ -139,7 +139,7 @@
                     Session().commit()
                     return 'ok'
         except Exception:
-            Session.rollback()
+            Session().rollback()
             log.error(traceback.format_exc())
         return 'fail'
 
@@ -149,8 +149,9 @@
         c.user = self.rhodecode_user
         no = Notification.get(notification_id)
 
-        owner = all(un.user.user_id == c.rhodecode_user.user_id
+        owner = any(un.user.user_id == c.rhodecode_user.user_id
                     for un in no.notifications_to_users)
+
         if no and (h.HasPermissionAny('hg.admin', 'repository.admin')() or owner):
             unotification = NotificationModel()\
                             .get_user_notification(c.user.user_id, no)
@@ -165,7 +166,7 @@
 
                 return render('admin/notifications/show_notification.html')
 
-        return redirect(url('notifications'))
+        return abort(403)
 
     def edit(self, notification_id, format='html'):
         """GET /_admin/notifications/id/edit: Form to edit an existing item"""
--- a/rhodecode/controllers/admin/repos.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/controllers/admin/repos.py	Mon Mar 04 18:42:14 2013 +0100
@@ -345,7 +345,7 @@
     @HasRepoPermissionAllDecorator('repository.admin')
     def delete_perm_users_group(self, repo_name):
         """
-        DELETE an existing repository permission users group
+        DELETE an existing repository permission user group
 
         :param repo_name:
         """
@@ -358,7 +358,7 @@
         except Exception:
             log.error(traceback.format_exc())
             h.flash(_('An error occurred during deletion of repository'
-                      ' users groups'),
+                      ' user groups'),
                     category='error')
             raise HTTPInternalServerError()
 
--- a/rhodecode/controllers/admin/repos_groups.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/controllers/admin/repos_groups.py	Mon Mar 04 18:42:14 2013 +0100
@@ -3,7 +3,7 @@
     rhodecode.controllers.admin.repos_groups
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    Repositories groups controller for RhodeCode
+    Repository groups controller for RhodeCode
 
     :created_on: Mar 23, 2010
     :author: marcink
@@ -282,7 +282,7 @@
     @HasReposGroupPermissionAnyDecorator('group.admin')
     def delete_repos_group_user_perm(self, group_name):
         """
-        DELETE an existing repositories group permission user
+        DELETE an existing repository group permission user
 
         :param group_name:
         """
@@ -307,7 +307,7 @@
     @HasReposGroupPermissionAnyDecorator('group.admin')
     def delete_repos_group_users_group_perm(self, group_name):
         """
-        DELETE an existing repositories group permission users group
+        DELETE an existing repository group permission user group
 
         :param group_name:
         """
@@ -322,7 +322,7 @@
         except Exception:
             log.error(traceback.format_exc())
             h.flash(_('An error occurred during deletion of group'
-                      ' users groups'),
+                      ' user groups'),
                     category='error')
             raise HTTPInternalServerError()
 
--- a/rhodecode/controllers/admin/settings.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/controllers/admin/settings.py	Mon Mar 04 18:42:14 2013 +0100
@@ -474,18 +474,23 @@
 
     @NotAnonymous()
     def my_account_my_pullrequests(self):
-        c.my_pull_requests = PullRequest.query()\
+        c.show_closed = request.GET.get('pr_show_closed')
+
+        def _filter(pr):
+            s = sorted(pr, key=lambda o: o.created_on, reverse=True)
+            if not c.show_closed:
+                s = filter(lambda p: p.status != PullRequest.STATUS_CLOSED, s)
+            return s
+
+        c.my_pull_requests = _filter(PullRequest.query()\
                                 .filter(PullRequest.user_id ==
                                         self.rhodecode_user.user_id)\
-                                .order_by(PullRequest.created_on.desc())\
-                                .all()
+                                .all())
 
-        c.participate_in_pull_requests = sorted(
-            [x.pull_request for x in PullRequestReviewers.query()\
-                                    .filter(PullRequestReviewers.user_id ==
-                                            self.rhodecode_user.user_id)\
-                                    .all()],
-                                    key=lambda o: o.created_on, reverse=True)
+        c.participate_in_pull_requests = _filter([
+                    x.pull_request for x in PullRequestReviewers.query()\
+                    .filter(PullRequestReviewers.user_id ==
+                            self.rhodecode_user.user_id).all()])
 
         return render('admin/users/user_edit_my_account_pullrequests.html')
 
--- a/rhodecode/controllers/admin/users_groups.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/controllers/admin/users_groups.py	Mon Mar 04 18:42:14 2013 +0100
@@ -3,7 +3,7 @@
     rhodecode.controllers.admin.users_groups
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    Users Groups crud controller for pylons
+    User Groups crud controller for pylons
 
     :created_on: Jan 25, 2011
     :author: marcink
@@ -33,16 +33,16 @@
 from pylons.i18n.translation import _
 
 from rhodecode.lib import helpers as h
-from rhodecode.lib.exceptions import UsersGroupsAssignedException
+from rhodecode.lib.exceptions import UserGroupsAssignedException
 from rhodecode.lib.utils2 import safe_unicode, str2bool
 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
 from rhodecode.lib.base import BaseController, render
 
-from rhodecode.model.users_group import UsersGroupModel
+from rhodecode.model.users_group import UserGroupModel
 
-from rhodecode.model.db import User, UsersGroup, UsersGroupToPerm,\
-    UsersGroupRepoToPerm, UsersGroupRepoGroupToPerm
-from rhodecode.model.forms import UsersGroupForm
+from rhodecode.model.db import User, UserGroup, UserGroupToPerm,\
+    UserGroupRepoToPerm, UserGroupRepoGroupToPerm
+from rhodecode.model.forms import UserGroupForm
 from rhodecode.model.meta import Session
 from rhodecode.lib.utils import action_logger
 from sqlalchemy.orm import joinedload
@@ -67,23 +67,23 @@
     def index(self, format='html'):
         """GET /users_groups: All items in the collection"""
         # url('users_groups')
-        c.users_groups_list = UsersGroup().query().all()
+        c.users_groups_list = UserGroup().query().all()
         return render('admin/users_groups/users_groups.html')
 
     def create(self):
         """POST /users_groups: Create a new item"""
         # url('users_groups')
 
-        users_group_form = UsersGroupForm()()
+        users_group_form = UserGroupForm()()
         try:
             form_result = users_group_form.to_python(dict(request.POST))
-            UsersGroupModel().create(name=form_result['users_group_name'],
+            UserGroupModel().create(name=form_result['users_group_name'],
                                      active=form_result['users_group_active'])
             gr = form_result['users_group_name']
             action_logger(self.rhodecode_user,
                           'admin_created_users_group:%s' % gr,
                           None, self.ip_addr, self.sa)
-            h.flash(_('created users group %s') % gr, category='success')
+            h.flash(_('created user group %s') % gr, category='success')
             Session().commit()
         except formencode.Invalid, errors:
             return htmlfill.render(
@@ -94,7 +94,7 @@
                 encoding="UTF-8")
         except Exception:
             log.error(traceback.format_exc())
-            h.flash(_('error occurred during creation of users group %s') \
+            h.flash(_('error occurred during creation of user group %s') \
                     % request.POST.get('users_group_name'), category='error')
 
         return redirect(url('users_groups'))
@@ -110,20 +110,20 @@
             'repositories_groups': {}
         }
 
-        ugroup_repo_perms = UsersGroupRepoToPerm.query()\
-            .options(joinedload(UsersGroupRepoToPerm.permission))\
-            .options(joinedload(UsersGroupRepoToPerm.repository))\
-            .filter(UsersGroupRepoToPerm.users_group_id == id)\
+        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 = UsersGroupRepoGroupToPerm.query()\
-            .options(joinedload(UsersGroupRepoGroupToPerm.permission))\
-            .options(joinedload(UsersGroupRepoGroupToPerm.group))\
-            .filter(UsersGroupRepoGroupToPerm.users_group_id == id)\
+        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:
@@ -145,26 +145,26 @@
         #           method='put')
         # url('users_group', id=ID)
 
-        c.users_group = UsersGroup.get_or_404(id)
+        c.users_group = UserGroup.get_or_404(id)
         self._load_data(id)
 
         available_members = [safe_unicode(x[0]) for x in c.available_members]
 
-        users_group_form = UsersGroupForm(edit=True,
+        users_group_form = UserGroupForm(edit=True,
                                           old_data=c.users_group.get_dict(),
                                           available_members=available_members)()
 
         try:
             form_result = users_group_form.to_python(request.POST)
-            UsersGroupModel().update(c.users_group, form_result)
+            UserGroupModel().update(c.users_group, form_result)
             gr = form_result['users_group_name']
             action_logger(self.rhodecode_user,
                           'admin_updated_users_group:%s' % gr,
                           None, self.ip_addr, self.sa)
-            h.flash(_('updated users group %s') % gr, category='success')
+            h.flash(_('updated user group %s') % gr, category='success')
             Session().commit()
         except formencode.Invalid, errors:
-            ug_model = UsersGroupModel()
+            ug_model = UserGroupModel()
             defaults = errors.value
             e = errors.error_dict or {}
             defaults.update({
@@ -183,7 +183,7 @@
                 encoding="UTF-8")
         except Exception:
             log.error(traceback.format_exc())
-            h.flash(_('error occurred during update of users group %s') \
+            h.flash(_('error occurred during update of user group %s') \
                     % request.POST.get('users_group_name'), category='error')
 
         return redirect(url('edit_users_group', id=id))
@@ -196,16 +196,16 @@
         #    h.form(url('users_group', id=ID),
         #           method='delete')
         # url('users_group', id=ID)
-        usr_gr = UsersGroup.get_or_404(id)
+        usr_gr = UserGroup.get_or_404(id)
         try:
-            UsersGroupModel().delete(usr_gr)
+            UserGroupModel().delete(usr_gr)
             Session().commit()
-            h.flash(_('successfully deleted users group'), category='success')
-        except UsersGroupsAssignedException, e:
+            h.flash(_('successfully deleted user group'), category='success')
+        except UserGroupsAssignedException, e:
             h.flash(e, category='error')
         except Exception:
             log.error(traceback.format_exc())
-            h.flash(_('An error occurred during deletion of users group'),
+            h.flash(_('An error occurred during deletion of user group'),
                     category='error')
         return redirect(url('users_groups'))
 
@@ -217,10 +217,10 @@
         """GET /users_groups/id/edit: Form to edit an existing item"""
         # url('edit_users_group', id=ID)
 
-        c.users_group = UsersGroup.get_or_404(id)
+        c.users_group = UserGroup.get_or_404(id)
         self._load_data(id)
 
-        ug_model = UsersGroupModel()
+        ug_model = UserGroupModel()
         defaults = c.users_group.get_dict()
         defaults.update({
             'create_repo_perm': ug_model.has_perm(c.users_group,
@@ -240,37 +240,37 @@
         """PUT /users_perm/id: Update an existing item"""
         # url('users_group_perm', id=ID, method='put')
 
-        users_group = UsersGroup.get_or_404(id)
+        users_group = UserGroup.get_or_404(id)
         grant_create_perm = str2bool(request.POST.get('create_repo_perm'))
         grant_fork_perm = str2bool(request.POST.get('fork_repo_perm'))
         inherit_perms = str2bool(request.POST.get('inherit_default_permissions'))
 
-        usersgroup_model = UsersGroupModel()
+        usergroup_model = UserGroupModel()
 
         try:
             users_group.inherit_default_permissions = inherit_perms
             Session().add(users_group)
 
             if grant_create_perm:
-                usersgroup_model.revoke_perm(id, 'hg.create.none')
-                usersgroup_model.grant_perm(id, 'hg.create.repository')
-                h.flash(_("Granted 'repository create' permission to users group"),
+                usergroup_model.revoke_perm(id, 'hg.create.none')
+                usergroup_model.grant_perm(id, 'hg.create.repository')
+                h.flash(_("Granted 'repository create' permission to user group"),
                         category='success')
             else:
-                usersgroup_model.revoke_perm(id, 'hg.create.repository')
-                usersgroup_model.grant_perm(id, 'hg.create.none')
-                h.flash(_("Revoked 'repository create' permission to users group"),
+                usergroup_model.revoke_perm(id, 'hg.create.repository')
+                usergroup_model.grant_perm(id, 'hg.create.none')
+                h.flash(_("Revoked 'repository create' permission to user group"),
                         category='success')
 
             if grant_fork_perm:
-                usersgroup_model.revoke_perm(id, 'hg.fork.none')
-                usersgroup_model.grant_perm(id, 'hg.fork.repository')
-                h.flash(_("Granted 'repository fork' permission to users group"),
+                usergroup_model.revoke_perm(id, 'hg.fork.none')
+                usergroup_model.grant_perm(id, 'hg.fork.repository')
+                h.flash(_("Granted 'repository fork' permission to user group"),
                         category='success')
             else:
-                usersgroup_model.revoke_perm(id, 'hg.fork.repository')
-                usersgroup_model.grant_perm(id, 'hg.fork.none')
-                h.flash(_("Revoked 'repository fork' permission to users group"),
+                usergroup_model.revoke_perm(id, 'hg.fork.repository')
+                usergroup_model.grant_perm(id, 'hg.fork.none')
+                h.flash(_("Revoked 'repository fork' permission to user group"),
                         category='success')
 
             Session().commit()
--- a/rhodecode/controllers/api/api.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/controllers/api/api.py	Mon Mar 04 18:42:14 2013 +0100
@@ -34,11 +34,12 @@
     HasPermissionAllDecorator, HasPermissionAnyDecorator, \
     HasPermissionAnyApi, HasRepoPermissionAnyApi
 from rhodecode.lib.utils import map_groups, repo2db_mapper
+from rhodecode.lib.utils2 import str2bool
 from rhodecode.model.meta import Session
 from rhodecode.model.scm import ScmModel
 from rhodecode.model.repo import RepoModel
 from rhodecode.model.user import UserModel
-from rhodecode.model.users_group import UsersGroupModel
+from rhodecode.model.users_group import UserGroupModel
 from rhodecode.model.permission import PermissionModel
 from rhodecode.model.db import Repository, RhodeCodeSetting, UserIpMap
 
@@ -121,13 +122,13 @@
 
 def get_users_group_or_error(usersgroupid):
     """
-    Get users group by id or name or return JsonRPCError if not found
+    Get user group by id or name or return JsonRPCError if not found
 
     :param userid:
     """
-    users_group = UsersGroupModel().get_group(usersgroupid)
+    users_group = UserGroupModel().get_group(usersgroupid)
     if users_group is None:
-        raise JSONRPCError('users group `%s` does not exist' % usersgroupid)
+        raise JSONRPCError('user group `%s` does not exist' % usersgroupid)
     return users_group
 
 
@@ -257,7 +258,7 @@
         if isinstance(userid, Optional):
             userid = apiuser.user_id
         user = get_user_or_error(userid)
-        locked = bool(locked)
+        locked = str2bool(locked)
         try:
             if locked:
                 Repository.lock(repo, user.user_id)
@@ -449,7 +450,7 @@
     @HasPermissionAllDecorator('hg.admin')
     def get_users_group(self, apiuser, usersgroupid):
         """"
-        Get users group by name or id
+        Get user group by name or id
 
         :param apiuser:
         :param usersgroupid:
@@ -468,13 +469,13 @@
     @HasPermissionAllDecorator('hg.admin')
     def get_users_groups(self, apiuser):
         """"
-        Get all users groups
+        Get all user groups
 
         :param apiuser:
         """
 
         result = []
-        for users_group in UsersGroupModel().get_all():
+        for users_group in UserGroupModel().get_all():
             result.append(users_group.get_api_data())
         return result
 
@@ -488,15 +489,15 @@
         :param active:
         """
 
-        if UsersGroupModel().get_by_name(group_name):
-            raise JSONRPCError("users group `%s` already exist" % group_name)
+        if UserGroupModel().get_by_name(group_name):
+            raise JSONRPCError("user group `%s` already exist" % group_name)
 
         try:
             active = Optional.extract(active)
-            ug = UsersGroupModel().create(name=group_name, active=active)
+            ug = UserGroupModel().create(name=group_name, active=active)
             Session().commit()
             return dict(
-                msg='created new users group `%s`' % group_name,
+                msg='created new user group `%s`' % group_name,
                 users_group=ug.get_api_data()
             )
         except Exception:
@@ -506,7 +507,7 @@
     @HasPermissionAllDecorator('hg.admin')
     def add_user_to_users_group(self, apiuser, usersgroupid, userid):
         """"
-        Add a user to a users group
+        Add a user to a user group
 
         :param apiuser:
         :param usersgroupid:
@@ -516,9 +517,9 @@
         users_group = get_users_group_or_error(usersgroupid)
 
         try:
-            ugm = UsersGroupModel().add_user_to_group(users_group, user)
+            ugm = UserGroupModel().add_user_to_group(users_group, user)
             success = True if ugm != True else False
-            msg = 'added member `%s` to users group `%s`' % (
+            msg = 'added member `%s` to user group `%s`' % (
                         user.username, users_group.users_group_name
                     )
             msg = msg if success else 'User is already in that group'
@@ -531,7 +532,7 @@
         except Exception:
             log.error(traceback.format_exc())
             raise JSONRPCError(
-                'failed to add member to users group `%s`' % (
+                'failed to add member to user group `%s`' % (
                     users_group.users_group_name
                 )
             )
@@ -549,9 +550,9 @@
         users_group = get_users_group_or_error(usersgroupid)
 
         try:
-            success = UsersGroupModel().remove_user_from_group(users_group,
+            success = UserGroupModel().remove_user_from_group(users_group,
                                                                user)
-            msg = 'removed member `%s` from users group `%s`' % (
+            msg = 'removed member `%s` from user group `%s`' % (
                         user.username, users_group.users_group_name
                     )
             msg = msg if success else "User wasn't in group"
@@ -560,7 +561,7 @@
         except Exception:
             log.error(traceback.format_exc())
             raise JSONRPCError(
-                'failed to remove member from users group `%s`' % (
+                'failed to remove member from user group `%s`' % (
                         users_group.users_group_name
                     )
             )
@@ -890,7 +891,7 @@
     def grant_users_group_permission(self, apiuser, repoid, usersgroupid,
                                      perm):
         """
-        Grant permission for users group on given repository, or update
+        Grant permission for user group on given repository, or update
         existing one if found
 
         :param apiuser:
@@ -909,7 +910,7 @@
 
             Session().commit()
             return dict(
-                msg='Granted perm: `%s` for users group: `%s` in '
+                msg='Granted perm: `%s` for user group: `%s` in '
                     'repo: `%s`' % (
                     perm.permission_name, users_group.users_group_name,
                     repo.repo_name
@@ -919,7 +920,7 @@
         except Exception:
             log.error(traceback.format_exc())
             raise JSONRPCError(
-                'failed to edit permission for users group: `%s` in '
+                'failed to edit permission for user group: `%s` in '
                 'repo: `%s`' % (
                     usersgroupid, repo.repo_name
                 )
@@ -928,7 +929,7 @@
     @HasPermissionAllDecorator('hg.admin')
     def revoke_users_group_permission(self, apiuser, repoid, usersgroupid):
         """
-        Revoke permission for users group on given repository
+        Revoke permission for user group on given repository
 
         :param apiuser:
         :param repoid:
@@ -943,7 +944,7 @@
 
             Session().commit()
             return dict(
-                msg='Revoked perm for users group: `%s` in repo: `%s`' % (
+                msg='Revoked perm for user group: `%s` in repo: `%s`' % (
                     users_group.users_group_name, repo.repo_name
                 ),
                 success=True
@@ -951,7 +952,7 @@
         except Exception:
             log.error(traceback.format_exc())
             raise JSONRPCError(
-                'failed to edit permission for users group: `%s` in '
+                'failed to edit permission for user group: `%s` in '
                 'repo: `%s`' % (
                     users_group.users_group_name, repo.repo_name
                 )
--- a/rhodecode/controllers/changeset.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/controllers/changeset.py	Mon Mar 04 18:42:14 2013 +0100
@@ -329,7 +329,7 @@
             text = text or (_('Status change -> %s')
                             % ChangesetStatus.get_status_lbl(status))
 
-        comm = ChangesetCommentsModel().create(
+        c.co = comm = ChangesetCommentsModel().create(
             text=text,
             repo=c.rhodecode_db_repo.repo_id,
             user=c.rhodecode_user.user_id,
@@ -371,12 +371,11 @@
         if not request.environ.get('HTTP_X_PARTIAL_XHR'):
             return redirect(h.url('changeset_home', repo_name=repo_name,
                                   revision=revision))
-
+        #only ajax below
         data = {
            'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
         }
         if comm:
-            c.co = comm
             data.update(comm.get_dict())
             data.update({'rendered_text':
                          render('changeset/changeset_comment_block.html')})
--- a/rhodecode/controllers/compare.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/controllers/compare.py	Mon Mar 04 18:42:14 2013 +0100
@@ -83,23 +83,28 @@
             raise HTTPBadRequest()
 
     def index(self, org_ref_type, org_ref, other_ref_type, other_ref):
-
+        # org_ref will be evaluated in org_repo
         org_repo = c.rhodecode_db_repo.repo_name
         org_ref = (org_ref_type, org_ref)
+        # other_ref will be evaluated in other_repo
         other_ref = (other_ref_type, other_ref)
         other_repo = request.GET.get('other_repo', org_repo)
-        c.fulldiff = fulldiff = request.GET.get('fulldiff')
+        # fulldiff disables cut_off_limit
+        c.fulldiff = request.GET.get('fulldiff')
+        # only consider this range of changesets
         rev_start = request.GET.get('rev_start')
         rev_end = request.GET.get('rev_end')
-
-        c.swap_url = h.url('compare_url', as_form=request.GET.get('as_form'),
+        # partial uses compare_cs.html template directly
+        partial = request.environ.get('HTTP_X_PARTIAL_XHR')
+        # as_form puts hidden input field with changeset revisions
+        c.as_form = partial and request.GET.get('as_form')
+        # swap url for compare_diff page - never partial and never as_form
+        c.swap_url = h.url('compare_url',
             repo_name=other_repo,
             org_ref_type=other_ref[0], org_ref=other_ref[1],
             other_repo=org_repo,
             other_ref_type=org_ref[0], other_ref=org_ref[1])
 
-        partial = request.environ.get('HTTP_X_PARTIAL_XHR')
-
         org_repo = Repository.get_by_repo_name(org_repo)
         other_repo = Repository.get_by_repo_name(other_repo)
 
@@ -148,8 +153,6 @@
 
         c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
                                                    c.cs_ranges])
-        # defines that we need hidden inputs with changesets
-        c.as_form = request.GET.get('as_form', False)
         if partial:
             return render('compare/compare_cs.html')
 
@@ -163,7 +166,7 @@
             org_ref = ('rev', ancestor)
             org_repo = other_repo
 
-        diff_limit = self.cut_off_limit if not fulldiff else None
+        diff_limit = self.cut_off_limit if not c.fulldiff else None
 
         _diff = diffs.differ(org_repo, org_ref, other_repo, other_ref)
 
--- a/rhodecode/controllers/files.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/controllers/files.py	Mon Mar 04 18:42:14 2013 +0100
@@ -486,6 +486,8 @@
                 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
                 try:
                     node1 = c.changeset_1.get_node(f_path)
+                    if node1.is_dir():
+                        raise NodeError('%s path is a %s not a file' % (node1, type(node1)))
                 except NodeDoesNotExistError:
                     c.changeset_1 = EmptyChangeset(cs=diff1,
                                                    revision=c.changeset_1.revision,
@@ -499,6 +501,7 @@
                 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
                 try:
                     node2 = c.changeset_2.get_node(f_path)
+                    raise NodeError('%s path is a %s not a file' % (node2, type(node2)))
                 except NodeDoesNotExistError:
                     c.changeset_2 = EmptyChangeset(cs=diff2,
                                                    revision=c.changeset_2.revision,
--- a/rhodecode/controllers/home.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/controllers/home.py	Mon Mar 04 18:42:14 2013 +0100
@@ -81,7 +81,7 @@
     def branch_tag_switcher(self, repo_name):
         if request.is_xhr:
             c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
-            c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
-            return render('/switch_to_list.html')
-        else:
-            raise HTTPBadRequest()
+            if c.rhodecode_db_repo:
+                c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
+                return render('/switch_to_list.html')
+        raise HTTPBadRequest()
--- a/rhodecode/controllers/pullrequests.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/controllers/pullrequests.py	Mon Mar 04 18:42:14 2013 +0100
@@ -67,29 +67,33 @@
         c.users_array = repo_model.get_users_js()
         c.users_groups_array = repo_model.get_users_groups_js()
 
-    def _get_repo_refs(self, repo):
-        hist_l = []
-
-        branches_group = ([('branch:%s:%s' % (k, v), k) for
-                         k, v in repo.branches.iteritems()], _("Branches"))
-        bookmarks_group = ([('book:%s:%s' % (k, v), k) for
-                         k, v in repo.bookmarks.iteritems()], _("Bookmarks"))
-        tags_group = ([('tag:%s:%s' % (k, v), k) for
-                         k, v in repo.tags.iteritems()
-                         if k != 'tip'], _("Tags"))
+    def _get_repo_refs(self, repo, rev=None):
+        """return a structure with repo's interesting changesets, suitable for
+        the selectors in pullrequest.html"""
+        branches = [('branch:%s:%s' % (k, v), k)
+                    for k, v in repo.branches.iteritems()]
+        bookmarks = [('book:%s:%s' % (k, v), k)
+                     for k, v in repo.bookmarks.iteritems()]
+        tags = [('tag:%s:%s' % (k, v), k)
+                for k, v in repo.tags.iteritems()
+                if k != 'tip']
 
         tip = repo.tags['tip']
-        tipref = 'tag:tip:%s' % tip
         colontip = ':' + tip
-        tips = [x[1] for x in branches_group[0] + bookmarks_group[0] + tags_group[0]
+        tips = [x[1] for x in branches + bookmarks + tags
                 if x[0].endswith(colontip)]
-        tags_group[0].append((tipref, 'tip (%s)' % ', '.join(tips)))
+        selected = 'tag:tip:%s' % tip
+        special = [(selected, 'tip (%s)' % ', '.join(tips))]
 
-        hist_l.append(bookmarks_group)
-        hist_l.append(branches_group)
-        hist_l.append(tags_group)
+        if rev:
+            selected = 'rev:%s:%s' % (rev, rev)
+            special.append((selected, rev))
 
-        return hist_l, tipref
+        return [(special, _("Special")),
+                (bookmarks, _("Bookmarks")),
+                (branches, _("Branches")),
+                (tags, _("Tags")),
+                ], selected
 
     def _get_is_allowed_change_status(self, pull_request):
         owner = self.rhodecode_user.user_id == pull_request.user_id
@@ -291,8 +295,6 @@
                                   else EmptyChangeset(), 'raw_id'))
 
         c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges])
-        # defines that we need hidden inputs with changesets
-        c.as_form = request.GET.get('as_form', False)
 
         c.org_ref = org_ref[1]
         c.org_ref_type = org_ref[0]
@@ -391,6 +393,7 @@
                                          )
         c.changeset_statuses = ChangesetStatus.STATUSES
 
+        c.as_form = False
         return render('/pullrequests/pullrequest_show.html')
 
     @NotAnonymous()
@@ -403,11 +406,15 @@
         status = request.POST.get('changeset_status')
         change_status = request.POST.get('change_changeset_status')
         text = request.POST.get('text')
+        close_pr = request.POST.get('save_close')
 
         allowed_to_change_status = self._get_is_allowed_change_status(pull_request)
         if status and change_status and allowed_to_change_status:
-            text = text or (_('Status change -> %s')
+            _def = (_('status change -> %s')
                             % ChangesetStatus.get_status_lbl(status))
+            if close_pr:
+                _def = _('Closing with') + ' ' + _def
+            text = text or _def
         comm = ChangesetCommentsModel().create(
             text=text,
             repo=c.rhodecode_db_repo.repo_id,
@@ -416,7 +423,9 @@
             f_path=request.POST.get('f_path'),
             line_no=request.POST.get('line'),
             status_change=(ChangesetStatus.get_status_lbl(status)
-            if status and change_status and allowed_to_change_status else None)
+                           if status and change_status
+                           and allowed_to_change_status else None),
+            closing_pr=close_pr
         )
 
         action_logger(self.rhodecode_user,
@@ -434,7 +443,7 @@
                     pull_request=pull_request_id
                 )
 
-            if request.POST.get('save_close'):
+            if close_pr:
                 if status in ['rejected', 'approved']:
                     PullRequestModel().close_pull_request(pull_request_id)
                     action_logger(self.rhodecode_user,
--- a/rhodecode/lib/auth.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/auth.py	Mon Mar 04 18:42:14 2013 +0100
@@ -411,7 +411,7 @@
     @property
     def groups_admin(self):
         """
-        Returns list of repositories groups you're an admin of
+        Returns list of repository groups you're an admin of
         """
         return [x[0] for x in self.permissions['repositories_groups'].iteritems()
                 if x[1] == 'group.admin']
--- a/rhodecode/lib/celerylib/__init__.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/celerylib/__init__.py	Mon Mar 04 18:42:14 2013 +0100
@@ -68,6 +68,8 @@
         except socket.error, e:
             if isinstance(e, IOError) and e.errno == 111:
                 log.debug('Unable to connect to celeryd. Sync execution')
+                global CELERY_ON
+                CELERY_ON = False
             else:
                 log.error(traceback.format_exc())
         except KeyError, e:
--- a/rhodecode/lib/celerylib/tasks.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/celerylib/tasks.py	Mon Mar 04 18:42:14 2013 +0100
@@ -251,76 +251,10 @@
         log.info('LockHeld')
         return 'Task with key %s already running' % lockkey
 
-@task(ignore_result=True)
-@dbsession
-def send_password_link(user_email):
-    from rhodecode.model.notification import EmailNotificationModel
-
-    log = get_logger(send_password_link)
-    DBS = get_session()
-
-    try:
-        user = User.get_by_email(user_email)
-        if user:
-            log.debug('password reset user found %s' % user)
-            link = url('reset_password_confirmation', key=user.api_key,
-                       qualified=True)
-            reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET
-            body = EmailNotificationModel().get_email_tmpl(reg_type,
-                                                **{'user':user.short_contact,
-                                                   'reset_url':link})
-            log.debug('sending email')
-            run_task(send_email, user_email,
-                     _("password reset link"), body)
-            log.info('send new password mail to %s' % user_email)
-        else:
-            log.debug("password reset email %s not found" % user_email)
-    except:
-        log.error(traceback.format_exc())
-        return False
-
-    return True
 
 @task(ignore_result=True)
 @dbsession
-def reset_user_password(user_email):
-    from rhodecode.lib import auth
-
-    log = get_logger(reset_user_password)
-    DBS = get_session()
-
-    try:
-        try:
-            user = User.get_by_email(user_email)
-            new_passwd = auth.PasswordGenerator().gen_password(8,
-                             auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
-            if user:
-                user.password = auth.get_crypt_password(new_passwd)
-                user.api_key = auth.generate_api_key(user.username)
-                DBS.add(user)
-                DBS.commit()
-                log.info('change password for %s' % user_email)
-            if new_passwd is None:
-                raise Exception('unable to generate new password')
-        except:
-            log.error(traceback.format_exc())
-            DBS.rollback()
-
-        run_task(send_email, user_email,
-                 'Your new password',
-                 'Your new RhodeCode password:%s' % (new_passwd))
-        log.info('send new password mail to %s' % user_email)
-
-    except:
-        log.error('Failed to update user password')
-        log.error(traceback.format_exc())
-
-    return True
-
-
-@task(ignore_result=True)
-@dbsession
-def send_email(recipients, subject, body, html_body=''):
+def send_email(recipients, subject, body='', html_body=''):
     """
     Sends an email with defined parameters from the .ini files.
 
@@ -348,7 +282,7 @@
     mail_port = email_config.get('smtp_port')
     tls = str2bool(email_config.get('smtp_use_tls'))
     ssl = str2bool(email_config.get('smtp_use_ssl'))
-    debug = str2bool(config.get('debug'))
+    debug = str2bool(email_config.get('debug'))
     smtp_auth = email_config.get('smtp_auth')
 
     if not mail_server:
--- a/rhodecode/lib/dbmigrate/schema/db_1_2_0.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/dbmigrate/schema/db_1_2_0.py	Mon Mar 04 18:42:14 2013 +0100
@@ -41,7 +41,7 @@
 
 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
     generate_api_key, safe_unicode
-from rhodecode.lib.exceptions import UsersGroupsAssignedException
+from rhodecode.lib.exceptions import UserGroupsAssignedException
 from rhodecode.lib.compat import json
 
 from rhodecode.model.meta import Base, Session
@@ -282,7 +282,7 @@
     user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
     repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
 
-    group_member = relationship('UsersGroupMember', cascade='all')
+    group_member = relationship('UserGroupMember', cascade='all')
 
     @property
     def full_contact(self):
@@ -361,7 +361,7 @@
     repository = relationship('Repository')
 
 
-class UsersGroup(Base, BaseModel):
+class UserGroup(Base, BaseModel):
     __tablename__ = 'users_groups'
     __table_args__ = {'extend_existing':True}
 
@@ -369,7 +369,7 @@
     users_group_name = Column("users_group_name", String(length=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)
 
-    members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
+    members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
 
     def __repr__(self):
         return '<userGroup(%s)>' % (self.users_group_name)
@@ -425,7 +425,7 @@
                     if v:
                         v = [v] if isinstance(v, basestring) else v
                         for u_id in set(v):
-                            member = UsersGroupMember(users_group_id, u_id)
+                            member = UserGroupMember(users_group_id, u_id)
                             members_list.append(member)
                     setattr(users_group, 'members', members_list)
                 setattr(users_group, k, v)
@@ -442,12 +442,12 @@
         try:
 
             # check if this group is not assigned to repo
-            assigned_groups = UsersGroupRepoToPerm.query()\
-                .filter(UsersGroupRepoToPerm.users_group_id ==
+            assigned_groups = UserGroupRepoToPerm.query()\
+                .filter(UserGroupRepoToPerm.users_group_id ==
                         users_group_id).all()
 
             if assigned_groups:
-                raise UsersGroupsAssignedException('RepoGroup assigned to %s' %
+                raise UserGroupsAssignedException('RepoGroup assigned to %s' %
                                                    assigned_groups)
 
             users_group = cls.get(users_group_id, cache=False)
@@ -458,7 +458,7 @@
             Session.rollback()
             raise
 
-class UsersGroupMember(Base, BaseModel):
+class UserGroupMember(Base, BaseModel):
     __tablename__ = 'users_groups_members'
     __table_args__ = {'extend_existing':True}
 
@@ -467,7 +467,7 @@
     user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
     user = relationship('User', lazy='joined')
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
 
     def __init__(self, gr_id='', u_id=''):
         self.users_group_id = gr_id
@@ -475,7 +475,7 @@
 
     @staticmethod
     def add_user_to_group(group, user):
-        ugm = UsersGroupMember()
+        ugm = UserGroupMember()
         ugm.users_group = group
         ugm.user = user
         Session.add(ugm)
@@ -505,7 +505,7 @@
     fork = relationship('Repository', remote_side=repo_id)
     group = relationship('RepoGroup')
     repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
-    users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
+    users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
     stats = relationship('Statistics', cascade='all', uselist=False)
 
     followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
@@ -909,7 +909,7 @@
         except:
             Session.rollback()
 
-class UsersGroupRepoToPerm(Base, BaseModel):
+class UserGroupRepoToPerm(Base, BaseModel):
     __tablename__ = 'users_group_repo_to_perm'
     __table_args__ = (UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), {'extend_existing':True})
     users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -917,21 +917,21 @@
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
     repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
     repository = relationship('Repository')
 
     def __repr__(self):
         return '<userGroup:%s => %s >' % (self.users_group, self.repository)
 
-class UsersGroupToPerm(Base, BaseModel):
+class UserGroupToPerm(Base, BaseModel):
     __tablename__ = 'users_group_to_perm'
     __table_args__ = {'extend_existing':True}
     users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
     users_group_id = Column("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)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
 
 
--- a/rhodecode/lib/dbmigrate/schema/db_1_3_0.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/dbmigrate/schema/db_1_3_0.py	Mon Mar 04 18:42:14 2013 +0100
@@ -305,7 +305,7 @@
     repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
     repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
 
-    group_member = relationship('UsersGroupMember', cascade='all')
+    group_member = relationship('UserGroupMember', cascade='all')
 
     notifications = relationship('UserNotification', cascade='all')
     # notifications assigned to this user
@@ -423,7 +423,7 @@
     repository = relationship('Repository', cascade='')
 
 
-class UsersGroup(Base, BaseModel):
+class UserGroup(Base, BaseModel):
     __tablename__ = 'users_groups'
     __table_args__ = (
         {'extend_existing': True, 'mysql_engine':'InnoDB',
@@ -434,9 +434,9 @@
     users_group_name = Column("users_group_name", String(length=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)
 
-    members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
-    users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
-    users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
+    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')
 
     def __unicode__(self):
         return u'<userGroup(%s)>' % (self.users_group_name)
@@ -465,7 +465,7 @@
         return users_group.get(users_group_id)
 
 
-class UsersGroupMember(Base, BaseModel):
+class UserGroupMember(Base, BaseModel):
     __tablename__ = 'users_groups_members'
     __table_args__ = (
         {'extend_existing': True, 'mysql_engine':'InnoDB',
@@ -477,7 +477,7 @@
     user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
     user = relationship('User', lazy='joined')
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
 
     def __init__(self, gr_id='', u_id=''):
         self.users_group_id = gr_id
@@ -510,7 +510,7 @@
     fork = relationship('Repository', remote_side=repo_id)
     group = relationship('RepoGroup')
     repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
-    users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
+    users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
     stats = relationship('Statistics', cascade='all', uselist=False)
 
     followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
@@ -749,7 +749,7 @@
     group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
     repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
-    users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
+    users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
 
     parent_group = relationship('RepoGroup', remote_side=group_id)
 
@@ -946,7 +946,7 @@
     permission = relationship('Permission', lazy='joined')
 
 
-class UsersGroupRepoToPerm(Base, BaseModel):
+class UserGroupRepoToPerm(Base, BaseModel):
     __tablename__ = 'users_group_repo_to_perm'
     __table_args__ = (
         UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
@@ -958,7 +958,7 @@
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
     repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
     repository = relationship('Repository')
 
@@ -975,7 +975,7 @@
         return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
 
 
-class UsersGroupToPerm(Base, BaseModel):
+class UserGroupToPerm(Base, BaseModel):
     __tablename__ = 'users_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'permission_id',),
@@ -986,7 +986,7 @@
     users_group_id = Column("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)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
 
 
@@ -1008,7 +1008,7 @@
     permission = relationship('Permission')
 
 
-class UsersGroupRepoGroupToPerm(Base, BaseModel):
+class UserGroupRepoGroupToPerm(Base, BaseModel):
     __tablename__ = 'users_group_repo_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'group_id'),
@@ -1021,7 +1021,7 @@
     group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
     group = relationship('RepoGroup')
 
--- a/rhodecode/lib/dbmigrate/schema/db_1_4_0.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/dbmigrate/schema/db_1_4_0.py	Mon Mar 04 18:42:14 2013 +0100
@@ -322,7 +322,7 @@
     repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
     repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
 
-    group_member = relationship('UsersGroupMember', cascade='all')
+    group_member = relationship('UserGroupMember', cascade='all')
 
     notifications = relationship('UserNotification', cascade='all')
     # notifications assigned to this user
@@ -521,7 +521,7 @@
     repository = relationship('Repository', cascade='')
 
 
-class UsersGroup(Base, BaseModel):
+class UserGroup(Base, BaseModel):
     __tablename__ = 'users_groups'
     __table_args__ = (
         {'extend_existing': True, 'mysql_engine': 'InnoDB',
@@ -533,9 +533,9 @@
     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)
 
-    members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
-    users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
-    users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
+    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')
 
     def __unicode__(self):
         return u'<userGroup(%s)>' % (self.users_group_name)
@@ -575,7 +575,7 @@
         return data
 
 
-class UsersGroupMember(Base, BaseModel):
+class UserGroupMember(Base, BaseModel):
     __tablename__ = 'users_groups_members'
     __table_args__ = (
         {'extend_existing': True, 'mysql_engine': 'InnoDB',
@@ -587,7 +587,7 @@
     user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
     user = relationship('User', lazy='joined')
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
 
     def __init__(self, gr_id='', u_id=''):
         self.users_group_id = gr_id
@@ -625,7 +625,7 @@
     fork = relationship('Repository', remote_side=repo_id)
     group = relationship('RepoGroup')
     repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
-    users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
+    users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
     stats = relationship('Statistics', cascade='all', uselist=False)
 
     followers = relationship('UserFollowing',
@@ -1013,7 +1013,7 @@
     enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
 
     repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
-    users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
+    users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
 
     parent_group = relationship('RepoGroup', remote_side=group_id)
 
@@ -1277,7 +1277,7 @@
     permission = relationship('Permission', lazy='joined')
 
 
-class UsersGroupRepoToPerm(Base, BaseModel):
+class UserGroupRepoToPerm(Base, BaseModel):
     __tablename__ = 'users_group_repo_to_perm'
     __table_args__ = (
         UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
@@ -1289,7 +1289,7 @@
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
     repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
     repository = relationship('Repository')
 
@@ -1306,7 +1306,7 @@
         return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
 
 
-class UsersGroupToPerm(Base, BaseModel):
+class UserGroupToPerm(Base, BaseModel):
     __tablename__ = 'users_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'permission_id',),
@@ -1317,7 +1317,7 @@
     users_group_id = Column("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)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
 
 
@@ -1339,7 +1339,7 @@
     permission = relationship('Permission')
 
 
-class UsersGroupRepoGroupToPerm(Base, BaseModel):
+class UserGroupRepoGroupToPerm(Base, BaseModel):
     __tablename__ = 'users_group_repo_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'group_id'),
@@ -1352,7 +1352,7 @@
     group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
     group = relationship('RepoGroup')
 
--- a/rhodecode/lib/dbmigrate/schema/db_1_5_0.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/dbmigrate/schema/db_1_5_0.py	Mon Mar 04 18:42:14 2013 +0100
@@ -341,7 +341,7 @@
     repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
     repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
 
-    group_member = relationship('UsersGroupMember', cascade='all')
+    group_member = relationship('UserGroupMember', cascade='all')
 
     notifications = relationship('UserNotification', cascade='all')
     # notifications assigned to this user
@@ -541,7 +541,7 @@
     repository = relationship('Repository', cascade='')
 
 
-class UsersGroup(Base, BaseModel):
+class UserGroup(Base, BaseModel):
     __tablename__ = 'users_groups'
     __table_args__ = (
         {'extend_existing': True, 'mysql_engine': 'InnoDB',
@@ -553,9 +553,9 @@
     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)
 
-    members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
-    users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
-    users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
+    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')
 
     def __unicode__(self):
         return u'<userGroup(%s)>' % (self.users_group_name)
@@ -595,7 +595,7 @@
         return data
 
 
-class UsersGroupMember(Base, BaseModel):
+class UserGroupMember(Base, BaseModel):
     __tablename__ = 'users_groups_members'
     __table_args__ = (
         {'extend_existing': True, 'mysql_engine': 'InnoDB',
@@ -607,7 +607,7 @@
     user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
     user = relationship('User', lazy='joined')
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
 
     def __init__(self, gr_id='', u_id=''):
         self.users_group_id = gr_id
@@ -645,7 +645,7 @@
     fork = relationship('Repository', remote_side=repo_id)
     group = relationship('RepoGroup')
     repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
-    users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
+    users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
     stats = relationship('Statistics', cascade='all', uselist=False)
 
     followers = relationship('UserFollowing',
@@ -1033,7 +1033,7 @@
     enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
 
     repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
-    users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
+    users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
 
     parent_group = relationship('RepoGroup', remote_side=group_id)
 
@@ -1297,7 +1297,7 @@
     permission = relationship('Permission', lazy='joined')
 
 
-class UsersGroupRepoToPerm(Base, BaseModel):
+class UserGroupRepoToPerm(Base, BaseModel):
     __tablename__ = 'users_group_repo_to_perm'
     __table_args__ = (
         UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
@@ -1309,7 +1309,7 @@
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
     repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
     repository = relationship('Repository')
 
@@ -1326,7 +1326,7 @@
         return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
 
 
-class UsersGroupToPerm(Base, BaseModel):
+class UserGroupToPerm(Base, BaseModel):
     __tablename__ = 'users_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'permission_id',),
@@ -1337,7 +1337,7 @@
     users_group_id = Column("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)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
 
 
@@ -1359,7 +1359,7 @@
     permission = relationship('Permission')
 
 
-class UsersGroupRepoGroupToPerm(Base, BaseModel):
+class UserGroupRepoGroupToPerm(Base, BaseModel):
     __tablename__ = 'users_group_repo_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'group_id'),
@@ -1372,7 +1372,7 @@
     group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
     group = relationship('RepoGroup')
 
--- a/rhodecode/lib/dbmigrate/schema/db_1_5_2.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/dbmigrate/schema/db_1_5_2.py	Mon Mar 04 18:42:14 2013 +0100
@@ -341,7 +341,7 @@
     repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
     repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
 
-    group_member = relationship('UsersGroupMember', cascade='all')
+    group_member = relationship('UserGroupMember', cascade='all')
 
     notifications = relationship('UserNotification', cascade='all')
     # notifications assigned to this user
@@ -575,7 +575,7 @@
     repository = relationship('Repository', cascade='')
 
 
-class UsersGroup(Base, BaseModel):
+class UserGroup(Base, BaseModel):
     __tablename__ = 'users_groups'
     __table_args__ = (
         {'extend_existing': True, 'mysql_engine': 'InnoDB',
@@ -587,9 +587,9 @@
     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)
 
-    members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
-    users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
-    users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
+    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')
 
     def __unicode__(self):
         return u'<userGroup(%s)>' % (self.users_group_name)
@@ -629,7 +629,7 @@
         return data
 
 
-class UsersGroupMember(Base, BaseModel):
+class UserGroupMember(Base, BaseModel):
     __tablename__ = 'users_groups_members'
     __table_args__ = (
         {'extend_existing': True, 'mysql_engine': 'InnoDB',
@@ -641,7 +641,7 @@
     user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
     user = relationship('User', lazy='joined')
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
 
     def __init__(self, gr_id='', u_id=''):
         self.users_group_id = gr_id
@@ -680,7 +680,7 @@
     fork = relationship('Repository', remote_side=repo_id)
     group = relationship('RepoGroup')
     repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
-    users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
+    users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
     stats = relationship('Statistics', cascade='all', uselist=False)
 
     followers = relationship('UserFollowing',
@@ -1139,7 +1139,7 @@
     enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
 
     repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
-    users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
+    users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
 
     parent_group = relationship('RepoGroup', remote_side=group_id)
 
@@ -1403,7 +1403,7 @@
     permission = relationship('Permission', lazy='joined')
 
 
-class UsersGroupRepoToPerm(Base, BaseModel):
+class UserGroupRepoToPerm(Base, BaseModel):
     __tablename__ = 'users_group_repo_to_perm'
     __table_args__ = (
         UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
@@ -1415,7 +1415,7 @@
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
     repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
     repository = relationship('Repository')
 
@@ -1432,7 +1432,7 @@
         return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
 
 
-class UsersGroupToPerm(Base, BaseModel):
+class UserGroupToPerm(Base, BaseModel):
     __tablename__ = 'users_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'permission_id',),
@@ -1443,7 +1443,7 @@
     users_group_id = Column("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)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
 
 
@@ -1465,7 +1465,7 @@
     permission = relationship('Permission')
 
 
-class UsersGroupRepoGroupToPerm(Base, BaseModel):
+class UserGroupRepoGroupToPerm(Base, BaseModel):
     __tablename__ = 'users_group_repo_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'group_id'),
@@ -1478,7 +1478,7 @@
     group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
     group = relationship('RepoGroup')
 
--- a/rhodecode/lib/dbmigrate/versions/003_version_1_2_0.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/dbmigrate/versions/003_version_1_2_0.py	Mon Mar 04 18:42:14 2013 +0100
@@ -34,26 +34,26 @@
     #==========================================================================
     # Add table `users_groups`
     #==========================================================================
-    from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UsersGroup
-    UsersGroup().__table__.create()
+    from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UserGroup
+    UserGroup().__table__.create()
 
     #==========================================================================
     # Add table `users_groups_members`
     #==========================================================================
-    from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UsersGroupMember
-    UsersGroupMember().__table__.create()
+    from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UserGroupMember
+    UserGroupMember().__table__.create()
 
     #==========================================================================
     # Add table `users_group_repo_to_perm`
     #==========================================================================
-    from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UsersGroupRepoToPerm
-    UsersGroupRepoToPerm().__table__.create()
+    from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UserGroupRepoToPerm
+    UserGroupRepoToPerm().__table__.create()
 
     #==========================================================================
     # Add table `users_group_to_perm`
     #==========================================================================
-    from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UsersGroupToPerm
-    UsersGroupToPerm().__table__.create()
+    from rhodecode.lib.dbmigrate.schema.db_1_2_0 import UserGroupToPerm
+    UserGroupToPerm().__table__.create()
 
     #==========================================================================
     # Upgrade of `users` table
--- a/rhodecode/lib/dbmigrate/versions/004_version_1_3_0.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/dbmigrate/versions/004_version_1_3_0.py	Mon Mar 04 18:42:14 2013 +0100
@@ -21,8 +21,8 @@
     #==========================================================================
     # Add table `users_group_repo_group_to_perm`
     #==========================================================================
-    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UsersGroupRepoGroupToPerm
-    UsersGroupRepoGroupToPerm().__table__.create()
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UserGroupRepoGroupToPerm
+    UserGroupRepoGroupToPerm().__table__.create()
 
     #==========================================================================
     # Add table `changeset_comments`
@@ -45,8 +45,8 @@
     #==========================================================================
     # Add unique to table `users_group_to_perm`
     #==========================================================================
-    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UsersGroupToPerm
-    tbl = UsersGroupToPerm().__table__
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UserGroupToPerm
+    tbl = UserGroupToPerm().__table__
     cons = UniqueConstraint('users_group_id', 'permission_id', table=tbl)
     cons.create()
 
--- a/rhodecode/lib/dbmigrate/versions/006_version_1_4_0.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/dbmigrate/versions/006_version_1_4_0.py	Mon Mar 04 18:42:14 2013 +0100
@@ -74,8 +74,8 @@
     #==========================================================================
     # USERS GROUP TABLE
     #==========================================================================
-    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UsersGroup
-    tbl = UsersGroup.__table__
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UserGroup
+    tbl = UserGroup.__table__
     # add inherit_default_permission column
     gr_inherit_default_permissions = Column(
                                     "users_group_inherit_default_permissions",
--- a/rhodecode/lib/exceptions.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/exceptions.py	Mon Mar 04 18:42:14 2013 +0100
@@ -50,7 +50,7 @@
     pass
 
 
-class UsersGroupsAssignedException(Exception):
+class UserGroupsAssignedException(Exception):
     pass
 
 
--- a/rhodecode/lib/helpers.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/helpers.py	Mon Mar 04 18:42:14 2013 +0100
@@ -684,9 +684,9 @@
                                     get_user_name, 'user_add.png'),
     'admin_updated_user':          (_('[updated] user'),
                                     get_user_name, 'user_edit.png'),
-    'admin_created_users_group':   (_('[created] users group'),
+    'admin_created_users_group':   (_('[created] user group'),
                                     get_users_group, 'group_add.png'),
-    'admin_updated_users_group':   (_('[updated] users group'),
+    'admin_updated_users_group':   (_('[updated] user group'),
                                     get_users_group, 'group_edit.png'),
     'user_commented_revision':     (_('[commented] on revision in repository'),
                                     get_cs_links, 'comment_add.png'),
@@ -977,7 +977,7 @@
     return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
 
 
-def urlify_text(text_):
+def urlify_text(text_, safe=True):
     """
     Extrac urls from text and make html links out of them
 
@@ -990,8 +990,10 @@
     def url_func(match_obj):
         url_full = match_obj.groups()[0]
         return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
-
-    return literal(url_pat.sub(url_func, text_))
+    _newtext = url_pat.sub(url_func, text_)
+    if safe:
+        return literal(_newtext)
+    return _newtext
 
 
 def urlify_changesets(text_, repository):
@@ -1002,21 +1004,16 @@
     :param repository: repo name to build the URL with
     """
     from pylons import url  # doh, we need to re-import url to mock it later
-    URL_PAT = re.compile(r'(?:^|\s)([0-9a-fA-F]{12,40})(?:$|\s)')
+    URL_PAT = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)')
 
     def url_func(match_obj):
-        rev = match_obj.groups()[0]
-        pref = ''
-        suf = ''
-        if match_obj.group().startswith(' '):
-            pref = ' '
-        if match_obj.group().endswith(' '):
-            suf = ' '
+        rev = match_obj.groups()[1]
+        pref = match_obj.groups()[0]
+        suf = match_obj.groups()[2]
+
         tmpl = (
         '%(pref)s<a class="%(cls)s" href="%(url)s">'
-        '%(rev)s'
-        '</a>'
-        '%(suf)s'
+        '%(rev)s</a>%(suf)s'
         )
         return tmpl % {
          'pref': pref,
@@ -1062,7 +1059,7 @@
     newtext = urlify_changesets(escaper(text_), repository)
 
     # extract http/https links and make them real urls
-    newtext = urlify_text(newtext)
+    newtext = urlify_text(newtext, safe=False)
 
     try:
         from rhodecode import CONFIG
--- a/rhodecode/lib/unionrepo.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/unionrepo.py	Mon Mar 04 18:42:14 2013 +0100
@@ -1,17 +1,20 @@
-# unionrepo.py - repository class for viewing union of repositories
+# unionrepo.py - repository class for viewing union of repository changesets
 #
-# Derived from Mercurial 2.5 bundlerepo.py
+# Derived from bundlerepo.py
 # Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
 # Copyright 2013 Unity Technologies, Mads Kiilerich <madski@unity3d.com>
 #
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-"""Repository class for in-memory pull of one local repository to another.
+"""Repository class for "in-memory pull" of one local repository to another,
+allowing operations like diff and log with revsets.
 """
 
+import os
 from mercurial.node import nullid
-from mercurial import util, mdiff
+from mercurial.i18n import _
+from mercurial import util, mdiff, cmdutil, scmutil
 from mercurial import localrepo, changelog, manifest, filelog, revlog
 
 class unionrevlog(revlog.revlog):
@@ -20,15 +23,14 @@
         # To retrieve a revision, we just need to know the node id so we can
         # look it up in revlog2.
         #
-        # basemap is indexed with revisions coming from the second revlog.
-        #
         # To differentiate a rev in the second revlog from a rev in the revlog,
-        # we check revision against basemap.
+        # we check revision against repotiprev.
+        opener = scmutil.readonlyvfs(opener)
         revlog.revlog.__init__(self, opener, indexfile)
         self.revlog2 = revlog2
 
-        self.basemap = {} # mapping rev that is in revlog2 to ... nothing
         n = len(self)
+        self.repotiprev = n - 1
         self.bundlerevs = set() # used by 'bundle()' revset expression
         for rev2 in self.revlog2:
             rev = self.revlog2.index[rev2]
@@ -42,7 +44,7 @@
                 link = linkmapper(linkrev)
 
             if node in self.nodemap:
-                # this happens for for the common revlog revisions
+                # this happens for the common revlog revisions
                 self.bundlerevs.add(self.nodemap[node])
                 continue
 
@@ -51,24 +53,23 @@
 
             e = (None, None, None, None,
                  link, self.rev(p1node), self.rev(p2node), node)
-            self.basemap[n] = None
             self.index.insert(-1, e)
             self.nodemap[node] = n
             self.bundlerevs.add(n)
             n += 1
 
     def _chunk(self, rev):
-        if rev not in self.basemap:
+        if rev <= self.repotiprev:
             return revlog.revlog._chunk(self, rev)
         return self.revlog2._chunk(self.node(rev))
 
     def revdiff(self, rev1, rev2):
         """return or calculate a delta between two revisions"""
-        if rev1 in self.basemap and rev2 in self.basemap:
+        if rev1 > self.repotiprev and rev2 > self.repotiprev:
             return self.revlog2.revdiff(
                 self.revlog2.rev(self.node(rev1)),
                 self.revlog2.rev(self.node(rev2)))
-        elif rev1 not in self.basemap and rev2 not in self.basemap:
+        elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
             return revlog.revlog.revdiff(self, rev1, rev2)
 
         return mdiff.textdiff(self.revision(self.node(rev1)),
@@ -88,7 +89,7 @@
         if node == nullid:
             return ""
 
-        if rev in self.basemap:
+        if rev > self.repotiprev:
             text = self.revlog2.revision(node)
             self._cache = (node, rev, text)
         else:
@@ -144,7 +145,7 @@
                                      util.expandpath(path2))
         self.repo2 = localrepo.localrepository(ui, path2)
 
-    @util.propertycache
+    @localrepo.unfilteredpropertycache
     def changelog(self):
         return unionchangelog(self.sopener, self.repo2.sopener)
 
@@ -153,7 +154,7 @@
         node = self.repo2.changelog.node(rev2)
         return self.changelog.rev(node)
 
-    @util.propertycache
+    @localrepo.unfilteredpropertycache
     def manifest(self):
         return unionmanifest(self.sopener, self.repo2.sopener,
                              self._clrev)
@@ -174,8 +175,34 @@
     def peer(self):
         return unionpeer(self)
 
+    def getcwd(self):
+        return os.getcwd() # always outside the repo
+
 def instance(ui, path, create):
-    u = util.url(path)
-    assert u.scheme == 'union'
-    repopath, repopath2 = u.path.split("+", 1)
+    if create:
+        raise util.Abort(_('cannot create new union repository'))
+    parentpath = ui.config("bundle", "mainreporoot", "")
+    if not parentpath:
+        # try to find the correct path to the working directory repo
+        parentpath = cmdutil.findrepo(os.getcwd())
+        if parentpath is None:
+            parentpath = ''
+    if parentpath:
+        # Try to make the full path relative so we get a nice, short URL.
+        # In particular, we don't want temp dir names in test outputs.
+        cwd = os.getcwd()
+        if parentpath == cwd:
+            parentpath = ''
+        else:
+            cwd = os.path.join(cwd,'')
+            if parentpath.startswith(cwd):
+                parentpath = parentpath[len(cwd):]
+    if path.startswith('union:'):
+        s = path.split(":", 1)[1].split("+", 1)
+        if len(s) == 1:
+            repopath, repopath2 = parentpath, s[0]
+        else:
+            repopath, repopath2 = s
+    else:
+        repopath, repopath2 = parentpath, path
     return unionrepository(ui, repopath, repopath2)
--- a/rhodecode/lib/vcs/utils/lockfiles.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/lib/vcs/utils/lockfiles.py	Mon Mar 04 18:42:14 2013 +0100
@@ -2,71 +2,71 @@
 
 
 class LockFile(object):
-	"""Provides methods to obtain, check for, and release a file based lock which
-	should be used to handle concurrent access to the same file.
+    """Provides methods to obtain, check for, and release a file based lock which
+    should be used to handle concurrent access to the same file.
 
-	As we are a utility class to be derived from, we only use protected methods.
+    As we are a utility class to be derived from, we only use protected methods.
 
-	Locks will automatically be released on destruction"""
-	__slots__ = ("_file_path", "_owns_lock")
+    Locks will automatically be released on destruction"""
+    __slots__ = ("_file_path", "_owns_lock")
 
-	def __init__(self, file_path):
-		self._file_path = file_path
-		self._owns_lock = False
+    def __init__(self, file_path):
+        self._file_path = file_path
+        self._owns_lock = False
 
-	def __del__(self):
-		self._release_lock()
+    def __del__(self):
+        self._release_lock()
 
-	def _lock_file_path(self):
-		""":return: Path to lockfile"""
-		return "%s.lock" % (self._file_path)
+    def _lock_file_path(self):
+        """:return: Path to lockfile"""
+        return "%s.lock" % (self._file_path)
 
-	def _has_lock(self):
-		""":return: True if we have a lock and if the lockfile still exists
-		:raise AssertionError: if our lock-file does not exist"""
-		if not self._owns_lock:
-			return False
+    def _has_lock(self):
+        """:return: True if we have a lock and if the lockfile still exists
+        :raise AssertionError: if our lock-file does not exist"""
+        if not self._owns_lock:
+            return False
 
-		return True
+        return True
 
-	def _obtain_lock_or_raise(self):
-		"""Create a lock file as flag for other instances, mark our instance as lock-holder
+    def _obtain_lock_or_raise(self):
+        """Create a lock file as flag for other instances, mark our instance as lock-holder
 
-		:raise IOError: if a lock was already present or a lock file could not be written"""
-		if self._has_lock():
-			return
-		lock_file = self._lock_file_path()
-		if os.path.isfile(lock_file):
-			raise IOError("Lock for file %r did already exist, delete %r in case the lock is illegal" % (self._file_path, lock_file))
+        :raise IOError: if a lock was already present or a lock file could not be written"""
+        if self._has_lock():
+            return
+        lock_file = self._lock_file_path()
+        if os.path.isfile(lock_file):
+            raise IOError("Lock for file %r did already exist, delete %r in case the lock is illegal" % (self._file_path, lock_file))
 
-		try:
-			fd = os.open(lock_file, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0)
-			os.close(fd)
-		except OSError,e:
-			raise IOError(str(e))
+        try:
+            fd = os.open(lock_file, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0)
+            os.close(fd)
+        except OSError,e:
+            raise IOError(str(e))
 
-		self._owns_lock = True
+        self._owns_lock = True
 
-	def _obtain_lock(self):
-		"""The default implementation will raise if a lock cannot be obtained.
-		Subclasses may override this method to provide a different implementation"""
-		return self._obtain_lock_or_raise()
+    def _obtain_lock(self):
+        """The default implementation will raise if a lock cannot be obtained.
+        Subclasses may override this method to provide a different implementation"""
+        return self._obtain_lock_or_raise()
 
-	def _release_lock(self):
-		"""Release our lock if we have one"""
-		if not self._has_lock():
-			return
+    def _release_lock(self):
+        """Release our lock if we have one"""
+        if not self._has_lock():
+            return
 
-		# if someone removed our file beforhand, lets just flag this issue
-		# instead of failing, to make it more usable.
-		lfp = self._lock_file_path()
-		try:
-			# on bloody windows, the file needs write permissions to be removable.
-			# Why ...
-			if os.name == 'nt':
-				os.chmod(lfp, 0777)
-			# END handle win32
-			os.remove(lfp)
-		except OSError:
-			pass
-		self._owns_lock = False
+        # if someone removed our file beforhand, lets just flag this issue
+        # instead of failing, to make it more usable.
+        lfp = self._lock_file_path()
+        try:
+            # on bloody windows, the file needs write permissions to be removable.
+            # Why ...
+            if os.name == 'nt':
+                os.chmod(lfp, 0777)
+            # END handle win32
+            os.remove(lfp)
+        except OSError:
+            pass
+        self._owns_lock = False
--- a/rhodecode/model/comment.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/model/comment.py	Mon Mar 04 18:42:14 2013 +0100
@@ -35,6 +35,7 @@
 from rhodecode.model.db import ChangesetComment, User, Repository, \
     Notification, PullRequest
 from rhodecode.model.notification import NotificationModel
+from rhodecode.model.meta import Session
 
 log = logging.getLogger(__name__)
 
@@ -57,8 +58,103 @@
                 user_objects.append(user_obj)
         return user_objects
 
+    def _get_notification_data(self, repo, comment, user, comment_text,
+                               line_no=None, revision=None, pull_request=None,
+                               status_change=None, closing_pr=False):
+        """
+        Get notification data
+
+        :param comment_text:
+        :param line:
+        :returns: tuple (subj,body,recipients,notification_type,email_kwargs)
+        """
+        # make notification
+        body = comment_text  # text of the comment
+        line = ''
+        if line_no:
+            line = _('on line %s') % line_no
+
+        #changeset
+        if revision:
+            notification_type = Notification.TYPE_CHANGESET_COMMENT
+            cs = repo.scm_instance.get_changeset(revision)
+            desc = "%s" % (cs.short_id)
+
+            _url = h.url('changeset_home',
+                repo_name=repo.repo_name,
+                revision=revision,
+                anchor='comment-%s' % comment.comment_id,
+                qualified=True,
+            )
+            subj = safe_unicode(
+                h.link_to('Re changeset: %(desc)s %(line)s' % \
+                          {'desc': desc, 'line': line},
+                          _url)
+            )
+            email_subject = 'User %s commented on changeset %s' % \
+                (user.username, h.short_id(revision))
+            # get the current participants of this changeset
+            recipients = ChangesetComment.get_users(revision=revision)
+            # add changeset author if it's in rhodecode system
+            cs_author = User.get_from_cs_author(cs.author)
+            if not cs_author:
+                #use repo owner if we cannot extract the author correctly
+                cs_author = repo.user
+            recipients += [cs_author]
+            email_kwargs = {
+                'status_change': status_change,
+                'cs_comment_user': h.person(user.email),
+                'cs_target_repo': h.url('summary_home', repo_name=repo.repo_name,
+                                        qualified=True),
+                'cs_comment_url': _url,
+                'raw_id': revision,
+                'message': cs.message
+            }
+        #pull request
+        elif pull_request:
+            notification_type = Notification.TYPE_PULL_REQUEST_COMMENT
+            desc = comment.pull_request.title
+            _url = h.url('pullrequest_show',
+                repo_name=pull_request.other_repo.repo_name,
+                pull_request_id=pull_request.pull_request_id,
+                anchor='comment-%s' % comment.comment_id,
+                qualified=True,
+            )
+            subj = safe_unicode(
+                h.link_to('Re pull request #%(pr_id)s: %(desc)s %(line)s' % \
+                          {'desc': desc,
+                           'pr_id': comment.pull_request.pull_request_id,
+                           'line': line},
+                          _url)
+            )
+            email_subject = 'User %s commented on pull request #%s' % \
+                    (user.username, comment.pull_request.pull_request_id)
+            # get the current participants of this pull request
+            recipients = ChangesetComment.get_users(pull_request_id=
+                                                pull_request.pull_request_id)
+            # add pull request author
+            recipients += [pull_request.author]
+
+            # add the reviewers to notification
+            recipients += [x.user for x in pull_request.reviewers]
+
+            #set some variables for email notification
+            email_kwargs = {
+                'pr_id': pull_request.pull_request_id,
+                'status_change': status_change,
+                'closing_pr': closing_pr,
+                'pr_comment_url': _url,
+                'pr_comment_user': h.person(user.email),
+                'pr_target_repo': h.url('summary_home',
+                                   repo_name=pull_request.other_repo.repo_name,
+                                   qualified=True)
+            }
+
+        return subj, body, recipients, notification_type, email_kwargs, email_subject
+
     def create(self, text, repo, user, revision=None, pull_request=None,
-               f_path=None, line_no=None, status_change=None, send_email=True):
+               f_path=None, line_no=None, status_change=None, closing_pr=False,
+               send_email=True):
         """
         Creates new comment for changeset or pull request.
         IF status_change is not none this comment is associated with a
@@ -72,9 +168,11 @@
         :param f_path:
         :param line_no:
         :param status_change:
+        :param closing_pr:
         :param send_email:
         """
         if not text:
+            log.warning('Missing text for comment, skipping...')
             return
 
         repo = self._get_repo(repo)
@@ -87,8 +185,6 @@
         comment.line_no = line_no
 
         if revision:
-            cs = repo.scm_instance.get_changeset(revision)
-            desc = "%s - %s" % (cs.short_id, h.shorter(cs.message, 256))
             comment.revision = revision
         elif pull_request:
             pull_request = self.__get_pull_request(pull_request)
@@ -96,82 +192,24 @@
         else:
             raise Exception('Please specify revision or pull_request_id')
 
-        self.sa.add(comment)
-        self.sa.flush()
-
-        # make notification
-        line = ''
-        body = text
-
-        #changeset
-        if revision:
-            if line_no:
-                line = _('on line %s') % line_no
-            subj = safe_unicode(
-                h.link_to('Re commit: %(desc)s %(line)s' % \
-                          {'desc': desc, 'line': line},
-                          h.url('changeset_home', repo_name=repo.repo_name,
-                                revision=revision,
-                                anchor='comment-%s' % comment.comment_id,
-                                qualified=True,
-                          )
-                )
-            )
-            notification_type = Notification.TYPE_CHANGESET_COMMENT
-            # get the current participants of this changeset
-            recipients = ChangesetComment.get_users(revision=revision)
-            # add changeset author if it's in rhodecode system
-            cs_author = User.get_from_cs_author(cs.author)
-            if not cs_author:
-                #use repo owner if we cannot extract the author correctly
-                cs_author = repo.user
-            recipients += [cs_author]
-            email_kwargs = {
-                'status_change': status_change,
-            }
-        #pull request
-        elif pull_request:
-            _url = h.url('pullrequest_show',
-                repo_name=pull_request.other_repo.repo_name,
-                pull_request_id=pull_request.pull_request_id,
-                anchor='comment-%s' % comment.comment_id,
-                qualified=True,
-            )
-            subj = safe_unicode(
-                h.link_to('Re pull request #%(pr_id)s: %(desc)s %(line)s' % \
-                          {'desc': comment.pull_request.title,
-                           'pr_id': comment.pull_request.pull_request_id,
-                           'line': line},
-                          _url)
-            )
-
-            notification_type = Notification.TYPE_PULL_REQUEST_COMMENT
-            # get the current participants of this pull request
-            recipients = ChangesetComment.get_users(pull_request_id=
-                                                pull_request.pull_request_id)
-            # add pull request author
-            recipients += [pull_request.author]
-
-            # add the reviewers to notification
-            recipients += [x.user for x in pull_request.reviewers]
-
-            #set some variables for email notification
-            email_kwargs = {
-                'pr_id': pull_request.pull_request_id,
-                'status_change': status_change,
-                'pr_comment_url': _url,
-                'pr_comment_user': h.person(user.email),
-                'pr_target_repo': h.url('summary_home',
-                                   repo_name=pull_request.other_repo.repo_name,
-                                   qualified=True)
-            }
+        Session().add(comment)
+        Session().flush()
 
         if send_email:
+            (subj, body, recipients, notification_type,
+             email_kwargs, email_subject) = self._get_notification_data(
+                                repo, comment, user,
+                                comment_text=text,
+                                line_no=line_no,
+                                revision=revision,
+                                pull_request=pull_request,
+                                status_change=status_change,
+                                closing_pr=closing_pr)
             # create notification objects, and emails
             NotificationModel().create(
                 created_by=user, subject=subj, body=body,
                 recipients=recipients, type_=notification_type,
-                email_kwargs=email_kwargs
+                email_kwargs=email_kwargs, email_subject=email_subject
             )
 
             mention_recipients = set(self._extract_mentions(body))\
@@ -195,7 +233,7 @@
         :param comment_id:
         """
         comment = self.__get_changeset_comment(comment)
-        self.sa.delete(comment)
+        Session().delete(comment)
 
         return comment
 
@@ -204,11 +242,8 @@
         Get's main comments based on revision or pull_request_id
 
         :param repo_id:
-        :type repo_id:
         :param revision:
-        :type revision:
         :param pull_request:
-        :type pull_request:
         """
 
         q = ChangesetComment.query()\
@@ -226,7 +261,7 @@
         return q.all()
 
     def get_inline_comments(self, repo_id, revision=None, pull_request=None):
-        q = self.sa.query(ChangesetComment)\
+        q = Session().query(ChangesetComment)\
             .filter(ChangesetComment.repo_id == repo_id)\
             .filter(ChangesetComment.line_no != None)\
             .filter(ChangesetComment.f_path != None)\
--- a/rhodecode/model/db.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/model/db.py	Mon Mar 04 18:42:14 2013 +0100
@@ -44,6 +44,7 @@
 from rhodecode.lib.vcs.utils.helpers import get_scm
 from rhodecode.lib.vcs.exceptions import VCSError
 from rhodecode.lib.vcs.utils.lazy import LazyProperty
+from rhodecode.lib.vcs.backends.base import EmptyChangeset
 
 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
     safe_unicode, remove_suffix, remove_prefix
@@ -341,7 +342,7 @@
     repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
     repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
 
-    group_member = relationship('UsersGroupMember', cascade='all')
+    group_member = relationship('UserGroupMember', cascade='all')
 
     notifications = relationship('UserNotification', cascade='all')
     # notifications assigned to this user
@@ -604,7 +605,7 @@
     repository = relationship('Repository', cascade='')
 
 
-class UsersGroup(Base, BaseModel):
+class UserGroup(Base, BaseModel):
     __tablename__ = 'users_groups'
     __table_args__ = (
         {'extend_existing': True, 'mysql_engine': 'InnoDB',
@@ -616,9 +617,9 @@
     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)
 
-    members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
-    users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
-    users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
+    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')
 
     def __unicode__(self):
         return u'<userGroup(%s)>' % (self.users_group_name)
@@ -658,7 +659,7 @@
         return data
 
 
-class UsersGroupMember(Base, BaseModel):
+class UserGroupMember(Base, BaseModel):
     __tablename__ = 'users_groups_members'
     __table_args__ = (
         {'extend_existing': True, 'mysql_engine': 'InnoDB',
@@ -670,7 +671,7 @@
     user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
     user = relationship('User', lazy='joined')
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
 
     def __init__(self, gr_id='', u_id=''):
         self.users_group_id = gr_id
@@ -747,7 +748,7 @@
     fork = relationship('Repository', remote_side=repo_id)
     group = relationship('RepoGroup')
     repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
-    users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
+    users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
     stats = relationship('Statistics', cascade='all', uselist=False)
 
     followers = relationship('UserFollowing',
@@ -1053,15 +1054,18 @@
         """
         from rhodecode.lib.vcs.backends.base import BaseChangeset
         if cs_cache is None:
-            cs_cache = self.get_changeset()
+            cs_cache = EmptyChangeset()
+            # use no-cache version here
+            scm_repo = self.scm_instance_no_cache
+            if scm_repo:
+                cs_cache = scm_repo.get_changeset()
+
         if isinstance(cs_cache, BaseChangeset):
             cs_cache = cs_cache.__json__()
 
-        if (cs_cache != self.changeset_cache
-            or not self.last_change
-            or not self.changeset_cache):
+        if (cs_cache != self.changeset_cache or not self.changeset_cache):
             _default = datetime.datetime.fromtimestamp(0)
-            last_change = cs_cache.get('date') or self.last_change or _default
+            last_change = cs_cache.get('date') or _default
             log.debug('updated repo %s with new cs cache %s' % (self, cs_cache))
             self.updated_on = last_change
             self.changeset_cache = cs_cache
@@ -1188,7 +1192,8 @@
         repo_full_path = self.repo_full_path
         try:
             alias = get_scm(repo_full_path)[0]
-            log.debug('Creating instance of %s repository' % alias)
+            log.debug('Creating instance of %s repository from %s'
+                      % (alias, repo_full_path))
             backend = get_backend(alias)
         except VCSError:
             log.error(traceback.format_exc())
@@ -1227,7 +1232,7 @@
     enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
 
     repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
-    users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
+    users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
 
     parent_group = relationship('RepoGroup', remote_side=group_id)
 
@@ -1378,10 +1383,10 @@
         ('repository.write', _('Repository write access')),
         ('repository.admin', _('Repository admin access')),
 
-        ('group.none', _('Repositories Group no access')),
-        ('group.read', _('Repositories Group read access')),
-        ('group.write', _('Repositories Group write access')),
-        ('group.admin', _('Repositories Group admin access')),
+        ('group.none', _('Repository group no access')),
+        ('group.read', _('Repository group read access')),
+        ('group.write', _('Repository group write access')),
+        ('group.admin', _('Repository group admin access')),
 
         ('hg.admin', _('RhodeCode Administrator')),
         ('hg.create.none', _('Repository creation disabled')),
@@ -1490,7 +1495,7 @@
     permission = relationship('Permission', lazy='joined')
 
 
-class UsersGroupRepoToPerm(Base, BaseModel):
+class UserGroupRepoToPerm(Base, BaseModel):
     __tablename__ = 'users_group_repo_to_perm'
     __table_args__ = (
         UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
@@ -1502,7 +1507,7 @@
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
     repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
     repository = relationship('Repository')
 
@@ -1519,7 +1524,7 @@
         return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
 
 
-class UsersGroupToPerm(Base, BaseModel):
+class UserGroupToPerm(Base, BaseModel):
     __tablename__ = 'users_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'permission_id',),
@@ -1530,7 +1535,7 @@
     users_group_id = Column("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)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
 
 
@@ -1552,7 +1557,7 @@
     permission = relationship('Permission')
 
 
-class UsersGroupRepoGroupToPerm(Base, BaseModel):
+class UserGroupRepoGroupToPerm(Base, BaseModel):
     __tablename__ = 'users_group_repo_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'group_id'),
@@ -1565,7 +1570,7 @@
     group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
-    users_group = relationship('UsersGroup')
+    users_group = relationship('UserGroup')
     permission = relationship('Permission')
     group = relationship('RepoGroup')
 
--- a/rhodecode/model/forms.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/model/forms.py	Mon Mar 04 18:42:14 2013 +0100
@@ -94,14 +94,14 @@
     return _UserForm
 
 
-def UsersGroupForm(edit=False, old_data={}, available_members=[]):
-    class _UsersGroupForm(formencode.Schema):
+def UserGroupForm(edit=False, old_data={}, available_members=[]):
+    class _UserGroupForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = True
 
         users_group_name = All(
             v.UnicodeString(strip=True, min=1, not_empty=True),
-            v.ValidUsersGroup(edit, old_data)
+            v.ValidUserGroup(edit, old_data)
         )
 
         users_group_active = v.StringBoolean(if_missing=False)
@@ -112,7 +112,7 @@
                 if_missing=None, not_empty=False
             )
 
-    return _UsersGroupForm
+    return _UserGroupForm
 
 
 def ReposGroupForm(edit=False, old_data={}, available_groups=[],
--- a/rhodecode/model/notification.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/model/notification.py	Mon Mar 04 18:42:14 2013 +0100
@@ -28,12 +28,14 @@
 import logging
 import traceback
 
+from pylons import tmpl_context as c
 from pylons.i18n.translation import _
 
 import rhodecode
 from rhodecode.lib import helpers as h
 from rhodecode.model import BaseModel
 from rhodecode.model.db import Notification, User, UserNotification
+from rhodecode.model.meta import Session
 
 log = logging.getLogger(__name__)
 
@@ -54,7 +56,7 @@
 
     def create(self, created_by, subject, body, recipients=None,
                type_=Notification.TYPE_MESSAGE, with_email=True,
-               email_kwargs={}):
+               email_kwargs={}, email_subject=None):
         """
 
         Creates notification of given type
@@ -68,6 +70,7 @@
         :param type_: type of notification
         :param with_email: send email with this notification
         :param email_kwargs: additional dict to pass as args to email template
+        :param email_subject: use given subject as email subject
         """
         from rhodecode.lib.celerylib import tasks, run_task
 
@@ -105,9 +108,11 @@
 
         # send email with notification to all other participants
         for rec in rec_objs:
-            email_subject = NotificationModel().make_description(notif, False)
+            if not email_subject:
+                email_subject = NotificationModel()\
+                                    .make_description(notif, show_age=False)
             type_ = type_
-            email_body = body
+            email_body = None  # we set body to none, we just send HTML emails
             ## this is passed into template
             kwargs = {'subject': subject, 'body': h.rst_w_mentions(body)}
             kwargs.update(email_kwargs)
@@ -130,7 +135,7 @@
                         .filter(UserNotification.notification
                                 == notification)\
                         .one()
-                self.sa.delete(obj)
+                Session().delete(obj)
                 return True
         except Exception:
             log.error(traceback.format_exc())
@@ -141,7 +146,6 @@
         Get mentions for given user, filter them if filter dict is given
 
         :param user:
-        :type user:
         :param filter:
         """
         user = self._get_user(user)
@@ -167,7 +171,7 @@
                                 == notification)\
                         .one()
                 obj.read = True
-                self.sa.add(obj)
+                Session().add(obj)
                 return True
         except Exception:
             log.error(traceback.format_exc())
@@ -187,7 +191,7 @@
         # update on joined tables :(
         for obj in q.all():
             obj.read = True
-            self.sa.add(obj)
+            Session().add(obj)
 
     def get_unread_cnt_for_user(self, user):
         user = self._get_user(user)
@@ -217,7 +221,7 @@
         #alias
         _n = notification
         _map = {
-            _n.TYPE_CHANGESET_COMMENT: _('commented on commit at %(when)s'),
+            _n.TYPE_CHANGESET_COMMENT: _('commented on changeset at %(when)s'),
             _n.TYPE_MESSAGE: _('sent message at %(when)s'),
             _n.TYPE_MENTION: _('mentioned you at %(when)s'),
             _n.TYPE_REGISTRATION: _('registered in RhodeCode at %(when)s'),
@@ -272,7 +276,8 @@
         email_template = self._tmpl_lookup.get_template(base)
         # translator and helpers inject
         _kwargs = {'_': _,
-                   'h': h}
+                   'h': h,
+                   'c': c}
         _kwargs.update(kwargs)
         log.debug('rendering tmpl %s with kwargs %s' % (base, _kwargs))
         return email_template.render(**_kwargs)
--- a/rhodecode/model/pull_request.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/model/pull_request.py	Mon Mar 04 18:42:14 2013 +0100
@@ -75,13 +75,13 @@
         new.title = title
         new.description = description
         new.author = created_by_user
-        self.sa.add(new)
+        Session().add(new)
         Session().flush()
         #members
         for member in set(reviewers):
             _usr = self._get_user(member)
             reviewer = PullRequestReviewers(_usr, new)
-            self.sa.add(reviewer)
+            Session().add(reviewer)
 
         #reset state to under-review
         ChangesetStatusModel().set_status(
@@ -90,7 +90,8 @@
             user=created_by_user,
             pull_request=new
         )
-
+        revision_data = [(x.raw_id, x.message)
+                         for x in map(org_repo.get_changeset, revisions)]
         #notification to reviewers
         notif = NotificationModel()
 
@@ -114,7 +115,7 @@
             'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
                                  qualified=True,),
             'pr_url': pr_url,
-            'pr_revisions': revisions
+            'pr_revisions': revision_data
         }
 
         notif.create(created_by=created_by_user, subject=subject, body=body,
@@ -140,7 +141,7 @@
         for uid in to_add:
             _usr = self._get_user(uid)
             reviewer = PullRequestReviewers(_usr, pull_request)
-            self.sa.add(reviewer)
+            Session().add(reviewer)
 
         for uid in to_remove:
             reviewer = PullRequestReviewers.query()\
@@ -148,7 +149,7 @@
                             PullRequestReviewers.pull_request==pull_request)\
                     .scalar()
             if reviewer:
-                self.sa.delete(reviewer)
+                Session().delete(reviewer)
 
     def delete(self, pull_request):
         pull_request = self.__get_pull_request(pull_request)
@@ -158,7 +159,7 @@
         pull_request = self.__get_pull_request(pull_request)
         pull_request.status = PullRequest.STATUS_CLOSED
         pull_request.updated_on = datetime.datetime.now()
-        self.sa.add(pull_request)
+        Session().add(pull_request)
 
     def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref):
         """
@@ -248,11 +249,7 @@
         if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
             raise Exception('other_ref must be a two element list/tuple')
 
-        org_repo_scm = org_repo.scm_instance
-        other_repo_scm = other_repo.scm_instance
-
-        alias = org_repo.scm_instance.alias
-        cs_ranges, ancestor = self._get_changesets(alias,
-                                                   org_repo_scm, org_ref,
-                                                   other_repo_scm, other_ref)
+        cs_ranges, ancestor = self._get_changesets(org_repo.scm_instance.alias,
+                                                   org_repo.scm_instance, org_ref,
+                                                   other_repo.scm_instance, other_ref)
         return cs_ranges, ancestor
--- a/rhodecode/model/repo.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/model/repo.py	Mon Mar 04 18:42:14 2013 +0100
@@ -38,7 +38,7 @@
 
 from rhodecode.model import BaseModel
 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
-    Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup,\
+    Statistics, UserGroup, UserGroupRepoToPerm, RhodeCodeUi, RepoGroup,\
     RhodeCodeSetting, RepositoryField
 from rhodecode.lib import helpers as h
 from rhodecode.lib.auth import HasRepoPermissionAny
@@ -54,8 +54,8 @@
     URL_SEPARATOR = Repository.url_sep()
 
     def __get_users_group(self, users_group):
-        return self._get_instance(UsersGroup, users_group,
-                                  callback=UsersGroup.get_by_group_name)
+        return self._get_instance(UserGroup, users_group,
+                                  callback=UserGroup.get_by_group_name)
 
     def _get_repos_group(self, repos_group):
         return self._get_instance(RepoGroup, repos_group,
@@ -120,8 +120,8 @@
         )
 
     def get_users_groups_js(self):
-        users_groups = self.sa.query(UsersGroup)\
-            .filter(UsersGroup.users_group_active == True).all()
+        users_groups = self.sa.query(UserGroup)\
+            .filter(UserGroup.users_group_active == True).all()
 
         return json.dumps([
             {
@@ -149,11 +149,7 @@
         if not repositories:
             repositories = Repository.getAll()
         for repo in repositories:
-            scm_repo = repo.scm_instance_no_cache
-            last_cs = EmptyChangeset()
-            if scm_repo:
-                last_cs = scm_repo.get_changeset()
-            repo.update_changeset_cache(last_cs)
+            repo.update_changeset_cache()
 
     def get_repos_as_dict(self, repos_list=None, admin=False, perm_check=True,
                           super_user_actions=False):
@@ -415,15 +411,15 @@
                     repo = fork_of
                     user_perms = UserRepoToPerm.query()\
                         .filter(UserRepoToPerm.repository == repo).all()
-                    group_perms = UsersGroupRepoToPerm.query()\
-                        .filter(UsersGroupRepoToPerm.repository == repo).all()
+                    group_perms = UserGroupRepoToPerm.query()\
+                        .filter(UserGroupRepoToPerm.repository == repo).all()
 
                     for perm in user_perms:
                         UserRepoToPerm.create(perm.user, new_repo,
                                               perm.permission)
 
                     for perm in group_perms:
-                        UsersGroupRepoToPerm.create(perm.users_group, new_repo,
+                        UserGroupRepoToPerm.create(perm.users_group, new_repo,
                                                     perm.permission)
                 else:
                     _create_default_perms()
@@ -549,12 +545,12 @@
 
     def grant_users_group_permission(self, repo, group_name, perm):
         """
-        Grant permission for users group on given repository, or update
+        Grant permission for user group on given repository, or update
         existing one if found
 
         :param repo: Instance of Repository, repository_id, or repository name
         :param group_name: Instance of UserGroup, users_group_id,
-            or users group name
+            or user group name
         :param perm: Instance of Permission, or permission_name
         """
         repo = self._get_repo(repo)
@@ -562,14 +558,14 @@
         permission = self._get_perm(perm)
 
         # check if we have that permission already
-        obj = self.sa.query(UsersGroupRepoToPerm)\
-            .filter(UsersGroupRepoToPerm.users_group == group_name)\
-            .filter(UsersGroupRepoToPerm.repository == repo)\
+        obj = self.sa.query(UserGroupRepoToPerm)\
+            .filter(UserGroupRepoToPerm.users_group == group_name)\
+            .filter(UserGroupRepoToPerm.repository == repo)\
             .scalar()
 
         if obj is None:
             # create new
-            obj = UsersGroupRepoToPerm()
+            obj = UserGroupRepoToPerm()
 
         obj.repository = repo
         obj.users_group = group_name
@@ -579,18 +575,18 @@
 
     def revoke_users_group_permission(self, repo, group_name):
         """
-        Revoke permission for users group on given repository
+        Revoke permission for user group on given repository
 
         :param repo: Instance of Repository, repository_id, or repository name
         :param group_name: Instance of UserGroup, users_group_id,
-            or users group name
+            or user group name
         """
         repo = self._get_repo(repo)
         group_name = self.__get_users_group(group_name)
 
-        obj = self.sa.query(UsersGroupRepoToPerm)\
-            .filter(UsersGroupRepoToPerm.repository == repo)\
-            .filter(UsersGroupRepoToPerm.users_group == group_name)\
+        obj = self.sa.query(UserGroupRepoToPerm)\
+            .filter(UserGroupRepoToPerm.repository == repo)\
+            .filter(UserGroupRepoToPerm.users_group == group_name)\
             .scalar()
         if obj:
             self.sa.delete(obj)
--- a/rhodecode/model/repo_permission.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/model/repo_permission.py	Mon Mar 04 18:42:14 2013 +0100
@@ -26,7 +26,7 @@
 
 import logging
 from rhodecode.model import BaseModel
-from rhodecode.model.db import UserRepoToPerm, UsersGroupRepoToPerm, \
+from rhodecode.model.db import UserRepoToPerm, UserGroupRepoToPerm, \
     Permission
 
 log = logging.getLogger(__name__)
@@ -64,9 +64,9 @@
             self.sa.delete(current)
 
     def get_users_group_permission(self, repository, users_group):
-        return UsersGroupRepoToPerm.query() \
-                .filter(UsersGroupRepoToPerm.users_group == users_group) \
-                .filter(UsersGroupRepoToPerm.repository == repository) \
+        return UserGroupRepoToPerm.query() \
+                .filter(UserGroupRepoToPerm.users_group == users_group) \
+                .filter(UserGroupRepoToPerm.repository == repository) \
                 .scalar()
 
     def update_users_group_permission(self, repository, users_group,
@@ -77,7 +77,7 @@
             if not current.permission is permission:
                 current.permission = permission
         else:
-            p = UsersGroupRepoToPerm()
+            p = UserGroupRepoToPerm()
             p.users_group = users_group
             p.repository = repository
             p.permission = permission
--- a/rhodecode/model/repos_group.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/model/repos_group.py	Mon Mar 04 18:42:14 2013 +0100
@@ -3,7 +3,7 @@
     rhodecode.model.user_group
     ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    users groups model for RhodeCode
+    repo group model for RhodeCode
 
     :created_on: Jan 25, 2011
     :author: marcink
@@ -33,7 +33,7 @@
 
 from rhodecode.model import BaseModel
 from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
-    User, Permission, UsersGroupRepoGroupToPerm, UsersGroup, Repository
+    User, Permission, UserGroupRepoGroupToPerm, UserGroup, Repository
 
 log = logging.getLogger(__name__)
 
@@ -43,8 +43,8 @@
     cls = RepoGroup
 
     def __get_users_group(self, users_group):
-        return self._get_instance(UsersGroup, users_group,
-                                  callback=UsersGroup.get_by_group_name)
+        return self._get_instance(UserGroup, users_group,
+                                  callback=UserGroup.get_by_group_name)
 
     def _get_repos_group(self, repos_group):
         return self._get_instance(RepoGroup, repos_group,
@@ -79,7 +79,7 @@
 
     def __create_group(self, group_name):
         """
-        makes repositories group on filesystem
+        makes repository group on filesystem
 
         :param repo_name:
         :param parent_id:
@@ -218,7 +218,7 @@
                 if member_type == 'user':
                     # this updates also current one if found
                     _set_perm_user(obj, user=member, perm=perm)
-                ## set for users group
+                ## set for user group
                 else:
                     _set_perm_group(obj, users_group=member, perm=perm)
             # set new permissions
@@ -289,11 +289,11 @@
     def delete_permission(self, repos_group, obj, obj_type, recursive):
         """
         Revokes permission for repos_group for given obj(user or users_group),
-        obj_type can be user or users group
+        obj_type can be user or user group
 
         :param repos_group:
-        :param obj: user or users group id
-        :param obj_type: user or users group type
+        :param obj: user or user group id
+        :param obj_type: user or user group type
         :param recursive: recurse to all children of group
         """
         from rhodecode.model.repo import RepoModel
@@ -327,7 +327,7 @@
 
     def grant_user_permission(self, repos_group, user, perm):
         """
-        Grant permission for user on given repositories group, or update
+        Grant permission for user on given repository group, or update
         existing one if found
 
         :param repos_group: Instance of ReposGroup, repositories_group_id,
@@ -356,7 +356,7 @@
 
     def revoke_user_permission(self, repos_group, user):
         """
-        Revoke permission for user on given repositories group
+        Revoke permission for user on given repository group
 
         :param repos_group: Instance of ReposGroup, repositories_group_id,
             or repositories_group name
@@ -376,13 +376,13 @@
 
     def grant_users_group_permission(self, repos_group, group_name, perm):
         """
-        Grant permission for users group on given repositories group, or update
+        Grant permission for user group on given repository group, or update
         existing one if found
 
         :param repos_group: Instance of ReposGroup, repositories_group_id,
             or repositories_group name
         :param group_name: Instance of UserGroup, users_group_id,
-            or users group name
+            or user group name
         :param perm: Instance of Permission, or permission_name
         """
         repos_group = self._get_repos_group(repos_group)
@@ -390,14 +390,14 @@
         permission = self._get_perm(perm)
 
         # check if we have that permission already
-        obj = self.sa.query(UsersGroupRepoGroupToPerm)\
-            .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
-            .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
+        obj = self.sa.query(UserGroupRepoGroupToPerm)\
+            .filter(UserGroupRepoGroupToPerm.group == repos_group)\
+            .filter(UserGroupRepoGroupToPerm.users_group == group_name)\
             .scalar()
 
         if obj is None:
             # create new
-            obj = UsersGroupRepoGroupToPerm()
+            obj = UserGroupRepoGroupToPerm()
 
         obj.group = repos_group
         obj.users_group = group_name
@@ -407,19 +407,19 @@
 
     def revoke_users_group_permission(self, repos_group, group_name):
         """
-        Revoke permission for users group on given repositories group
+        Revoke permission for user group on given repository group
 
         :param repos_group: Instance of ReposGroup, repositories_group_id,
             or repositories_group name
         :param group_name: Instance of UserGroup, users_group_id,
-            or users group name
+            or user group name
         """
         repos_group = self._get_repos_group(repos_group)
         group_name = self.__get_users_group(group_name)
 
-        obj = self.sa.query(UsersGroupRepoGroupToPerm)\
-            .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
-            .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
+        obj = self.sa.query(UserGroupRepoGroupToPerm)\
+            .filter(UserGroupRepoGroupToPerm.group == repos_group)\
+            .filter(UserGroupRepoGroupToPerm.users_group == group_name)\
             .scalar()
         if obj:
             self.sa.delete(obj)
--- a/rhodecode/model/scm.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/model/scm.py	Mon Mar 04 18:42:14 2013 +0100
@@ -291,9 +291,7 @@
         if all_groups is None:
             all_groups = RepoGroup.query()\
                 .filter(RepoGroup.group_parent_id == None).all()
-        group_iter = GroupList(all_groups)
-
-        return group_iter
+        return [x for x in GroupList(all_groups)]
 
     def mark_for_invalidation(self, repo_name):
         """
--- a/rhodecode/model/user.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/model/user.py	Mon Mar 04 18:42:14 2013 +0100
@@ -37,11 +37,12 @@
 from rhodecode.lib.caching_query import FromCache
 from rhodecode.model import BaseModel
 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
-    UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
-    Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \
+    UserToPerm, UserGroupRepoToPerm, UserGroupToPerm, UserGroupMember, \
+    Notification, RepoGroup, UserRepoGroupToPerm, UserGroupRepoGroupToPerm, \
     UserEmailMap, UserIpMap
 from rhodecode.lib.exceptions import DefaultUserException, \
     UserOwnsReposException
+from rhodecode.model.meta import Session
 
 
 log = logging.getLogger(__name__)
@@ -316,11 +317,61 @@
 
     def reset_password_link(self, data):
         from rhodecode.lib.celerylib import tasks, run_task
-        run_task(tasks.send_password_link, data['email'])
+        from rhodecode.model.notification import EmailNotificationModel
+        user_email = data['email']
+        try:
+            user = User.get_by_email(user_email)
+            if user:
+                log.debug('password reset user found %s' % user)
+                link = url('reset_password_confirmation', key=user.api_key,
+                           qualified=True)
+                reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET
+                body = EmailNotificationModel().get_email_tmpl(reg_type,
+                                                    **{'user': user.short_contact,
+                                                       'reset_url': link})
+                log.debug('sending email')
+                run_task(tasks.send_email, user_email,
+                         _("password reset link"), body, body)
+                log.info('send new password mail to %s' % user_email)
+            else:
+                log.debug("password reset email %s not found" % user_email)
+        except:
+            log.error(traceback.format_exc())
+            return False
+
+        return True
 
     def reset_password(self, data):
         from rhodecode.lib.celerylib import tasks, run_task
-        run_task(tasks.reset_user_password, data['email'])
+        from rhodecode.lib import auth
+        user_email = data['email']
+        try:
+            try:
+                user = User.get_by_email(user_email)
+                new_passwd = auth.PasswordGenerator().gen_password(8,
+                                 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
+                if user:
+                    user.password = auth.get_crypt_password(new_passwd)
+                    user.api_key = auth.generate_api_key(user.username)
+                    Session().add(user)
+                    Session().commit()
+                    log.info('change password for %s' % user_email)
+                if new_passwd is None:
+                    raise Exception('unable to generate new password')
+            except:
+                log.error(traceback.format_exc())
+                Session().rollback()
+
+            run_task(tasks.send_email, user_email,
+                     _('Your new password'),
+                     _('Your new RhodeCode password:%s') % (new_passwd))
+            log.info('send new password mail to %s' % user_email)
+
+        except:
+            log.error('Failed to update user password')
+            log.error(traceback.format_exc())
+
+        return True
 
     def fill_data(self, auth_user, user_id=None, api_key=None):
         """
@@ -413,7 +464,7 @@
                 p = 'repository.admin'
                 user.permissions[RK][r_k] = p
 
-            # repositories groups
+            # repository groups
             for perm in default_repo_groups_perms:
                 rg_k = perm.UserRepoGroupToPerm.group.group_name
                 p = 'group.admin'
@@ -446,7 +497,7 @@
 
             user.permissions[RK][r_k] = p
 
-        # defaults for repositories groups taken from default user permission
+        # defaults for repository groups taken from default user permission
         # on given group
         for perm in default_repo_groups_perms:
             rg_k = perm.UserRepoGroupToPerm.group.group_name
@@ -461,13 +512,13 @@
                              'hg.create.none', 'hg.create.repository'])
 
         # USER GROUPS comes first
-        # users group global permissions
-        user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
-            .options(joinedload(UsersGroupToPerm.permission))\
-            .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
-                   UsersGroupMember.users_group_id))\
-            .filter(UsersGroupMember.user_id == uid)\
-            .order_by(UsersGroupToPerm.users_group_id)\
+        # user group global permissions
+        user_perms_from_users_groups = self.sa.query(UserGroupToPerm)\
+            .options(joinedload(UserGroupToPerm.permission))\
+            .join((UserGroupMember, UserGroupToPerm.users_group_id ==
+                   UserGroupMember.users_group_id))\
+            .filter(UserGroupMember.user_id == uid)\
+            .order_by(UserGroupToPerm.users_group_id)\
             .all()
         #need to group here by groups since user can be in more than one group
         _grouped = [[x, list(y)] for x, y in
@@ -508,21 +559,21 @@
         # permission should be selected based on selected method
         #======================================================================
 
-        # users group for repositories permissions
+        # user group for repositories permissions
         user_repo_perms_from_users_groups = \
-         self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
-            .join((Repository, UsersGroupRepoToPerm.repository_id ==
+         self.sa.query(UserGroupRepoToPerm, Permission, Repository,)\
+            .join((Repository, UserGroupRepoToPerm.repository_id ==
                    Repository.repo_id))\
-            .join((Permission, UsersGroupRepoToPerm.permission_id ==
+            .join((Permission, UserGroupRepoToPerm.permission_id ==
                    Permission.permission_id))\
-            .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
-                   UsersGroupMember.users_group_id))\
-            .filter(UsersGroupMember.user_id == uid)\
+            .join((UserGroupMember, UserGroupRepoToPerm.users_group_id ==
+                   UserGroupMember.users_group_id))\
+            .filter(UserGroupMember.user_id == uid)\
             .all()
 
         multiple_counter = collections.defaultdict(int)
         for perm in user_repo_perms_from_users_groups:
-            r_k = perm.UsersGroupRepoToPerm.repository.repo_name
+            r_k = perm.UserGroupRepoToPerm.repository.repo_name
             multiple_counter[r_k] += 1
             p = perm.Permission.permission_name
             cur_perm = user.permissions[RK][r_k]
@@ -559,27 +610,27 @@
             user.permissions[RK][r_k] = p
 
         #======================================================================
-        # !! PERMISSIONS FOR REPOSITORIES GROUPS !!
+        # !! PERMISSIONS FOR REPOSITORY GROUPS !!
         #======================================================================
         #======================================================================
         # check if user is part of user groups for this repository groups and
         # fill in his permission from it. _choose_perm decides of which
         # permission should be selected based on selected method
         #======================================================================
-        # users group for repo groups permissions
+        # user group for repo groups permissions
         user_repo_group_perms_from_users_groups = \
-         self.sa.query(UsersGroupRepoGroupToPerm, Permission, RepoGroup)\
-         .join((RepoGroup, UsersGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((Permission, UsersGroupRepoGroupToPerm.permission_id
+         self.sa.query(UserGroupRepoGroupToPerm, Permission, RepoGroup)\
+         .join((RepoGroup, UserGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
+         .join((Permission, UserGroupRepoGroupToPerm.permission_id
                 == Permission.permission_id))\
-         .join((UsersGroupMember, UsersGroupRepoGroupToPerm.users_group_id
-                == UsersGroupMember.users_group_id))\
-         .filter(UsersGroupMember.user_id == uid)\
+         .join((UserGroupMember, UserGroupRepoGroupToPerm.users_group_id
+                == UserGroupMember.users_group_id))\
+         .filter(UserGroupMember.user_id == uid)\
          .all()
 
         multiple_counter = collections.defaultdict(int)
         for perm in user_repo_group_perms_from_users_groups:
-            g_k = perm.UsersGroupRepoGroupToPerm.group.group_name
+            g_k = perm.UserGroupRepoGroupToPerm.group.group_name
             multiple_counter[g_k] += 1
             p = perm.Permission.permission_name
             cur_perm = user.permissions[GK][g_k]
--- a/rhodecode/model/users_group.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/model/users_group.py	Mon Mar 04 18:42:14 2013 +0100
@@ -3,7 +3,7 @@
     rhodecode.model.users_group
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    users group model for RhodeCode
+    user group model for RhodeCode
 
     :created_on: Oct 1, 2011
     :author: nvinot
@@ -28,33 +28,33 @@
 import traceback
 
 from rhodecode.model import BaseModel
-from rhodecode.model.db import UsersGroupMember, UsersGroup,\
-    UsersGroupRepoToPerm, Permission, UsersGroupToPerm, User
-from rhodecode.lib.exceptions import UsersGroupsAssignedException
+from rhodecode.model.db import UserGroupMember, UserGroup,\
+    UserGroupRepoToPerm, Permission, UserGroupToPerm, User
+from rhodecode.lib.exceptions import UserGroupsAssignedException
 
 log = logging.getLogger(__name__)
 
 
-class UsersGroupModel(BaseModel):
+class UserGroupModel(BaseModel):
 
-    cls = UsersGroup
+    cls = UserGroup
 
     def __get_users_group(self, users_group):
-        return self._get_instance(UsersGroup, users_group,
-                                  callback=UsersGroup.get_by_group_name)
+        return self._get_instance(UserGroup, users_group,
+                                  callback=UserGroup.get_by_group_name)
 
     def get(self, users_group_id, cache=False):
-        return UsersGroup.get(users_group_id)
+        return UserGroup.get(users_group_id)
 
     def get_group(self, users_group):
         return self.__get_users_group(users_group)
 
     def get_by_name(self, name, cache=False, case_insensitive=False):
-        return UsersGroup.get_by_group_name(name, cache, case_insensitive)
+        return UserGroup.get_by_group_name(name, cache, case_insensitive)
 
     def create(self, name, active=True):
         try:
-            new = UsersGroup()
+            new = UserGroup()
             new.users_group_name = name
             new.users_group_active = active
             self.sa.add(new)
@@ -76,7 +76,7 @@
                     if v:
                         v = [v] if isinstance(v, basestring) else v
                         for u_id in set(v):
-                            member = UsersGroupMember(users_group.users_group_id, u_id)
+                            member = UserGroupMember(users_group.users_group_id, u_id)
                             members_list.append(member)
                     setattr(users_group, 'members', members_list)
                 setattr(users_group, k, v)
@@ -99,11 +99,11 @@
             users_group = self.__get_users_group(users_group)
 
             # check if this group is not assigned to repo
-            assigned_groups = UsersGroupRepoToPerm.query()\
-                .filter(UsersGroupRepoToPerm.users_group == users_group).all()
+            assigned_groups = UserGroupRepoToPerm.query()\
+                .filter(UserGroupRepoToPerm.users_group == users_group).all()
 
             if assigned_groups and force is False:
-                raise UsersGroupsAssignedException('RepoGroup assigned to %s' %
+                raise UserGroupsAssignedException('RepoGroup assigned to %s' %
                                                    assigned_groups)
 
             self.sa.delete(users_group)
@@ -121,7 +121,7 @@
                 return True
 
         try:
-            users_group_member = UsersGroupMember()
+            users_group_member = UserGroupMember()
             users_group_member.user = user
             users_group_member.users_group = users_group
 
@@ -160,23 +160,23 @@
         users_group = self.__get_users_group(users_group)
         perm = self._get_perm(perm)
 
-        return UsersGroupToPerm.query()\
-            .filter(UsersGroupToPerm.users_group == users_group)\
-            .filter(UsersGroupToPerm.permission == perm).scalar() is not None
+        return UserGroupToPerm.query()\
+            .filter(UserGroupToPerm.users_group == users_group)\
+            .filter(UserGroupToPerm.permission == perm).scalar() is not None
 
     def grant_perm(self, users_group, perm):
         users_group = self.__get_users_group(users_group)
         perm = self._get_perm(perm)
 
         # if this permission is already granted skip it
-        _perm = UsersGroupToPerm.query()\
-            .filter(UsersGroupToPerm.users_group == users_group)\
-            .filter(UsersGroupToPerm.permission == perm)\
+        _perm = UserGroupToPerm.query()\
+            .filter(UserGroupToPerm.users_group == users_group)\
+            .filter(UserGroupToPerm.permission == perm)\
             .scalar()
         if _perm:
             return
 
-        new = UsersGroupToPerm()
+        new = UserGroupToPerm()
         new.users_group = users_group
         new.permission = perm
         self.sa.add(new)
@@ -185,8 +185,8 @@
         users_group = self.__get_users_group(users_group)
         perm = self._get_perm(perm)
 
-        obj = UsersGroupToPerm.query()\
-            .filter(UsersGroupToPerm.users_group == users_group)\
-            .filter(UsersGroupToPerm.permission == perm).scalar()
+        obj = UserGroupToPerm.query()\
+            .filter(UserGroupToPerm.users_group == users_group)\
+            .filter(UserGroupToPerm.permission == perm).scalar()
         if obj:
             self.sa.delete(obj)
--- a/rhodecode/model/validators.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/model/validators.py	Mon Mar 04 18:42:14 2013 +0100
@@ -16,7 +16,7 @@
 from rhodecode.lib.compat import OrderedSet
 from rhodecode.lib import ipaddr
 from rhodecode.lib.utils import repo_name_slug
-from rhodecode.model.db import RepoGroup, Repository, UsersGroup, User,\
+from rhodecode.model.db import RepoGroup, Repository, UserGroup, User,\
     ChangesetStatus
 from rhodecode.lib.exceptions import LdapImportError
 from rhodecode.config.routing import ADMIN_PREFIX
@@ -129,13 +129,13 @@
     return _validator
 
 
-def ValidUsersGroup(edit=False, old_data={}):
+def ValidUserGroup(edit=False, old_data={}):
     class _validator(formencode.validators.FancyValidator):
         messages = {
-            'invalid_group': _(u'Invalid users group name'),
-            'group_exist': _(u'Users group "%(usersgroup)s" already exists'),
-            'invalid_usersgroup_name':
-                _(u'users group name may only contain  alphanumeric '
+            'invalid_group': _(u'Invalid user group name'),
+            'group_exist': _(u'User group "%(usergroup)s" already exists'),
+            'invalid_usergroup_name':
+                _(u'user group name may only contain alphanumeric '
                   'characters underscores, periods or dashes and must begin '
                   'with alphanumeric character')
         }
@@ -150,19 +150,19 @@
             old_ugname = None
             if edit:
                 old_id = old_data.get('users_group_id')
-                old_ugname = UsersGroup.get(old_id).users_group_name
+                old_ugname = UserGroup.get(old_id).users_group_name
 
             if old_ugname != value or not edit:
-                is_existing_group = UsersGroup.get_by_group_name(value,
+                is_existing_group = UserGroup.get_by_group_name(value,
                                                         case_insensitive=True)
                 if is_existing_group:
-                    msg = M(self, 'group_exist', state, usersgroup=value)
+                    msg = M(self, 'group_exist', state, usergroup=value)
                     raise formencode.Invalid(msg, value, state,
                         error_dict=dict(users_group_name=msg)
                     )
 
             if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
-                msg = M(self, 'invalid_usersgroup_name', state)
+                msg = M(self, 'invalid_usergroup_name', state)
                 raise formencode.Invalid(msg, value, state,
                     error_dict=dict(users_group_name=msg)
                 )
@@ -317,7 +317,7 @@
                 _(u'Repository named %(repo)s already exists'),
             'repository_in_group_exists': _(u'Repository "%(repo)s" already '
                                             'exists in group "%(group)s"'),
-            'same_group_exists': _(u'Repositories group with name "%(repo)s" '
+            'same_group_exists': _(u'Repository group with name "%(repo)s" '
                                    'already exists')
         }
 
@@ -547,7 +547,7 @@
     class _validator(formencode.validators.FancyValidator):
         messages = {
             'perm_new_member_name':
-                _(u'This username or users group name is not valid')
+                _(u'This username or user group name is not valid')
         }
 
         def to_python(self, value, state):
@@ -604,9 +604,9 @@
                             .filter(User.active == True)\
                             .filter(User.username == k).one()
                     if t is 'users_group':
-                        self.user_db = UsersGroup.query()\
-                            .filter(UsersGroup.users_group_active == True)\
-                            .filter(UsersGroup.users_group_name == k).one()
+                        self.user_db = UserGroup.query()\
+                            .filter(UserGroup.users_group_active == True)\
+                            .filter(UserGroup.users_group_name == k).one()
 
                 except Exception:
                     log.exception('Updated permission failed')
--- a/rhodecode/public/css/style.css	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/public/css/style.css	Mon Mar 04 18:42:14 2013 +0100
@@ -160,56 +160,48 @@
 .top-left-rounded-corner {
     -webkit-border-top-left-radius: 8px;
     -khtml-border-radius-topleft: 8px;
-    -moz-border-radius-topleft: 8px;
     border-top-left-radius: 8px;
 }
 
 .top-right-rounded-corner {
     -webkit-border-top-right-radius: 8px;
     -khtml-border-radius-topright: 8px;
-    -moz-border-radius-topright: 8px;
     border-top-right-radius: 8px;
 }
 
 .bottom-left-rounded-corner {
     -webkit-border-bottom-left-radius: 8px;
     -khtml-border-radius-bottomleft: 8px;
-    -moz-border-radius-bottomleft: 8px;
     border-bottom-left-radius: 8px;
 }
 
 .bottom-right-rounded-corner {
     -webkit-border-bottom-right-radius: 8px;
     -khtml-border-radius-bottomright: 8px;
-    -moz-border-radius-bottomright: 8px;
     border-bottom-right-radius: 8px;
 }
 
 .top-left-rounded-corner-mid {
     -webkit-border-top-left-radius: 4px;
     -khtml-border-radius-topleft: 4px;
-    -moz-border-radius-topleft: 4px;
     border-top-left-radius: 4px;
 }
 
 .top-right-rounded-corner-mid {
     -webkit-border-top-right-radius: 4px;
     -khtml-border-radius-topright: 4px;
-    -moz-border-radius-topright: 4px;
     border-top-right-radius: 4px;
 }
 
 .bottom-left-rounded-corner-mid {
     -webkit-border-bottom-left-radius: 4px;
     -khtml-border-radius-bottomleft: 4px;
-    -moz-border-radius-bottomleft: 4px;
     border-bottom-left-radius: 4px;
 }
 
 .bottom-right-rounded-corner-mid {
     -webkit-border-bottom-right-radius: 4px;
     -khtml-border-radius-bottomright: 4px;
-    -moz-border-radius-bottomright: 4px;
     border-bottom-right-radius: 4px;
 }
 
@@ -244,12 +236,10 @@
 
 #header {
 }
-
 #header ul#logged-user {
     margin-bottom: 5px !important;
     -webkit-border-radius: 0px 0px 8px 8px;
     -khtml-border-radius: 0px 0px 8px 8px;
-    -moz-border-radius: 0px 0px 8px 8px;
     border-radius: 0px 0px 8px 8px;
     height: 37px;
     background-color: #003B76;
@@ -260,7 +250,7 @@
     background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
     background-image: -webkit-linear-gradient(top, #003b76, #00376e);
     background-image: -o-linear-gradient(top, #003b76, #00376e);
-    background-image: linear-gradient(top, #003b76, #00376e);
+    background-image: linear-gradient(to bottom, #003b76, #00376e);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
     box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 }
@@ -314,19 +304,18 @@
     background-color: #003B76;
     opacity: 0.01;
     cursor: pointer;
-    min-height: 10px;	
+    min-height: 10px;
     width: 100% !important;
     -webkit-border-radius: 0px 0px 4px 4px;
     -khtml-border-radius: 0px 0px 4px 4px;
-    -moz-border-radius: 0px 0px 4px 4px;
     border-radius: 0px 0px 4px 4px;
 }
 
 #header-dd:hover{
-	opacity: 0.2;
+    opacity: 0.2;
     -webkit-transition: opacity 0.5s ease-in-out;
     -moz-transition: opacity 0.5s ease-in-out;
-    transition: opacity 0.5s ease-in-out;	
+    transition: opacity 0.5s ease-in-out;
 }
 
 #header #header-inner {
@@ -341,7 +330,7 @@
     background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76),color-stop(100%, #00376e) );
     background-image: -webkit-linear-gradient(top, #003b76, #00376e);
     background-image: -o-linear-gradient(top, #003b76, #00376e);
-    background-image: linear-gradient(top, #003b76, #00376e);
+    background-image: linear-gradient(to bottom, #003b76, #00376e);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
     margin: 0;
     padding: 0;
@@ -349,17 +338,15 @@
     box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
     -webkit-border-radius: 0px 0px 4px 4px;
     -khtml-border-radius: 0px 0px 4px 4px;
-    -moz-border-radius: 0px 0px 4px 4px;
     border-radius: 0px 0px 4px 4px;
 }
 #header #header-inner.hover {
     width: 100% !important;
     -webkit-border-radius: 0px 0px 0px 0px;
     -khtml-border-radius: 0px 0px 0px 0px;
-    -moz-border-radius: 0px 0px 0px 0px;
     border-radius: 0px 0px 0px 0px;
     position: fixed !important;
-    z-index: 10000;    
+    z-index: 10000;
 }
 
 .ie7 #header #header-inner.hover,
@@ -439,7 +426,6 @@
     padding: 0;
     -webkit-border-radius: 4px 4px 4px 4px;
     -khtml-border-radius: 4px 4px 4px 4px;
-    -moz-border-radius: 4px 4px 4px 4px;
     border-radius: 4px 4px 4px 4px;
 }
 
@@ -1096,7 +1082,6 @@
     padding: 0 0 10px;
     -webkit-border-radius: 4px 4px 4px 4px;
     -khtml-border-radius: 4px 4px 4px 4px;
-    -moz-border-radius: 4px 4px 4px 4px;
     border-radius: 4px 4px 4px 4px;
     box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 }
@@ -1126,7 +1111,7 @@
     background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
     background-image: -webkit-linear-gradient(top, #003b76, #00376e);
     background-image: -o-linear-gradient(top, #003b76, #00376e);
-    background-image: linear-gradient(top, #003b76, #00376e);
+    background-image: linear-gradient(to bottom, #003b76, #00376e);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
     margin: 0 0 20px;
     padding: 0;
@@ -1267,7 +1252,7 @@
     background:-moz-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
     background:-o-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
     background:-ms-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
-    background:linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
+    background:linear-gradient(to bottom,rgba(255,255,255,0),rgba(64,96,128,0.1));
 
     display: none;
 }
@@ -1623,7 +1608,6 @@
     padding: 0;
     border: 1px solid #eee;
     -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
     border-radius: 4px;
 }
 
@@ -1949,7 +1933,6 @@
     margin-right: 1px;
     -webkit-border-radius: 4px 4px 4px 4px;
     -khtml-border-radius: 4px 4px 4px 4px;
-    -moz-border-radius: 4px 4px 4px 4px;
     border-radius: 4px 4px 4px 4px;
 
     border: solid 1px #9CF;
@@ -2027,12 +2010,11 @@
     background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
     background-image : -webkit-linear-gradient( top, #003b76, #00376e));
     background-image : -o-linear-gradient( top, #003b76, #00376e));
-    background-image : linear-gradient( top, #003b76, #00376e);
+    background-image : linear-gradient(to bottom, #003b76, #00376e);
     filter :progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
     box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
     -webkit-border-radius: 4px 4px 4px 4px;
     -khtml-border-radius: 4px 4px 4px 4px;
-    -moz-border-radius: 4px 4px 4px 4px;
     border-radius: 4px 4px 4px 4px;
 }
 
@@ -2063,7 +2045,7 @@
     background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
     background-image : -webkit-linear-gradient( top, #003b76, #00376e));
     background-image : -o-linear-gradient( top, #003b76, #00376e));
-    background-image : linear-gradient( top, #003b76, #00376e);
+    background-image : linear-gradient(to bottom, #003b76, #00376e);
     filter : progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
     margin: 0 auto;
     padding: 0;
@@ -2147,13 +2129,12 @@
     background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
     background-image: -webkit-linear-gradient(top, #003b76, #00376e);
     background-image: -o-linear-gradient(top, #003b76, #00376e);
-    background-image: linear-gradient(top, #003b76, #00376e);
+    background-image: linear-gradient(to bottom, #003b76, #00376e);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
 
     z-index: 999;
     -webkit-border-radius: 0px 0px 4px 4px;
     -khtml-border-radius: 0px 0px 4px 4px;
-    -moz-border-radius: 0px 0px 4px 4px;
     border-radius: 0px 0px 4px 4px;
     box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 }
@@ -2213,7 +2194,7 @@
 #quick_login .unread a {
     color: #FFFFFF;
     display: block;
-    padding: 2px;    
+    padding: 2px;
 }
 #quick_login .notifications a:hover,
 #quick_login .unread a:hover {
@@ -2304,7 +2285,7 @@
     background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
     background-image: -webkit-linear-gradient(top, #003b76, #00376e);
     background-image: -o-linear-gradient(top, #003b76, #00376e);
-    background-image: linear-gradient(top, #003b76, #00376e);
+    background-image: linear-gradient(to bottom, #003b76, #00376e);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',
         endColorstr='#00376e', GradientType=0 );
     margin: 0 auto;
@@ -2780,7 +2761,6 @@
     color: #444444;
     background: #FEA;
     -webkit-border-radius: 0px 0px 0px 6px;
-    -moz-border-radius: 0px 0px 0px 6px;
     border-radius: 0px 0px 0px 6px;
     padding: 1px;
 }
@@ -2815,7 +2795,6 @@
     text-transform: uppercase;
     white-space: nowrap;
     -webkit-border-radius: 3px;
-    -moz-border-radius: 3px;
     border-radius: 3px;
     margin-right: 2px;
 }
@@ -2841,7 +2820,6 @@
     color: #ffffff;
     white-space: nowrap;
     -webkit-border-radius: 3px;
-    -moz-border-radius: 3px;
     border-radius: 3px;
 }
 .right .logtags .branchtag a:hover, .logtags .branchtag a {
@@ -2859,7 +2837,6 @@
     color: #ffffff;
     white-space: nowrap;
     -webkit-border-radius: 3px;
-    -moz-border-radius: 3px;
     border-radius: 3px;
 }
 .right .logtags .tagtag a:hover, .logtags .tagtag a {
@@ -2878,7 +2855,6 @@
     text-transform: uppercase;
     white-space: nowrap;
     -webkit-border-radius: 3px;
-    -moz-border-radius: 3px;
     border-radius: 3px;
 }
 .right .logbooks .bookbook, .logbooks .bookbook a, .right .logtags .bookbook, .logtags .bookbook a {
@@ -2896,7 +2872,6 @@
     line-height: 125%;
     padding: 0;
     -webkit-border-radius: 6px 6px 0px 0px;
-    -moz-border-radius: 6px 6px 0px 0px;
     border-radius: 6px 6px 0px 0px;
 }
 
@@ -3109,16 +3084,14 @@
     border: 2px solid #003367;
     font: 100% sans-serif;
     width: auto;
-    opacity: 1px;
+    opacity: 1;
     padding: 8px;
 
     white-space: pre-wrap;
     -webkit-border-radius: 8px 8px 8px 8px;
     -khtml-border-radius: 8px 8px 8px 8px;
-    -moz-border-radius: 8px 8px 8px 8px;
     border-radius: 8px 8px 8px 8px;
     box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
-    -moz-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
     -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 }
 
@@ -3130,12 +3103,11 @@
     border: 2px solid #003367;
     font: 100% sans-serif;
     width: auto;
-    opacity: 1px;
+    opacity: 1;
     padding: 8px;
     white-space: pre-wrap;
     -webkit-border-radius: 8px 8px 8px 8px;
     -khtml-border-radius: 8px 8px 8px 8px;
-    -moz-border-radius: 8px 8px 8px 8px;
     border-radius: 8px 8px 8px 8px;
     box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 }
@@ -3182,7 +3154,6 @@
     position: absolute;
     width: 100%;
     background: #000;
-    -moz-opacity: 0.1px;
     opacity: .10;
     filter: alpha(opacity = 10);
     z-index: 9049;
@@ -3428,7 +3399,7 @@
     background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35) );
     background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
     background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
-    background-image: linear-gradient(top, #ee5f5b, #c43c35);
+    background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35', GradientType=0 );
     border-color: #c43c35 #c43c35 #882a25;
 }
@@ -3443,7 +3414,7 @@
     background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94) );
     background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
     background-image: -o-linear-gradient(top, #fceec1, #eedc94);
-    background-image: linear-gradient(top, #fceec1, #eedc94);
+    background-image: linear-gradient(to bottom, #fceec1, #eedc94);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0 );
     border-color: #eedc94 #eedc94 #e4c652;
 }
@@ -3457,7 +3428,7 @@
     background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957) );
     background-image: -webkit-linear-gradient(top, #62c462, #57a957);
     background-image: -o-linear-gradient(top, #62c462, #57a957);
-    background-image: linear-gradient(top, #62c462, #57a957);
+    background-image: linear-gradient(to bottom, #62c462, #57a957);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0 );
     border-color: #57a957 #57a957 #3d773d;
 }
@@ -3471,7 +3442,7 @@
     background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9) );
     background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
     background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
-    background-image: linear-gradient(top, #5bc0de, #339bb9);
+    background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0 );
     border-color: #339bb9 #339bb9 #22697d;
 }
@@ -3492,10 +3463,8 @@
     border-width: 1px;
     border-style: solid;
     -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
     border-radius: 4px;
     -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
-    -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
     box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
 }
 
@@ -3524,7 +3493,7 @@
 
 table#permissions_manage span.private_repo_msg {
     font-size: 0.8em;
-    opacity: 0.6px;
+    opacity: 0.6;
 }
 
 table#permissions_manage td.private_repo_msg {
@@ -3543,14 +3512,12 @@
     line-height:0;
     -webkit-border-radius: 3px;
     -khtml-border-radius: 3px;
-    -moz-border-radius: 3px;
     border-radius: 3px;
 }
 
 div.gravatar img {
     -webkit-border-radius: 2px;
     -khtml-border-radius: 2px;
-    -moz-border-radius: 2px;
     border-radius: 2px;
 }
 
@@ -3586,7 +3553,7 @@
     background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F4F4F4),color-stop(100%, #DADADA) );
     background-image: -webkit-linear-gradient(top, #F4F4F4, #DADADA) );
     background-image: -o-linear-gradient(top, #F4F4F4, #DADADA) );
-    background-image: linear-gradient(top, #F4F4F4, #DADADA);
+    background-image: linear-gradient(to bottom, #F4F4F4, #DADADA);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F4F4F4', endColorstr='#DADADA', GradientType=0);
 
     border-top: 1px solid #DDD;
@@ -3598,7 +3565,6 @@
     margin: 0px 3px 3px 0px;
     -webkit-border-radius: 4px 4px 4px 4px !important;
     -khtml-border-radius: 4px 4px 4px 4px !important;
-    -moz-border-radius: 4px 4px 4px 4px !important;
     border-radius: 4px 4px 4px 4px !important;
     cursor: pointer !important;
     padding: 3px 3px 3px 3px;
@@ -3623,7 +3589,6 @@
     margin: 0px 0px 3px -4px;
     -webkit-border-radius: 0px 4px 4px 0px !important;
     -khtml-border-radius: 0px 4px 4px 0px !important;
-    -moz-border-radius: 0px 4px 4px 0px !important;
     border-radius: 0px 4px 4px 0px !important;
     width: 100px;
     text-align: center;
@@ -3642,7 +3607,7 @@
 }
 
 .ui-btn.disabled:hover {
-    background-position:none;
+    background-position: 0;
     color: #999;
     text-decoration: none;
     box-shadow: none !important;
@@ -3658,7 +3623,7 @@
     background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));
     background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
     background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
-    background-image: linear-gradient(top, #ee5f5b, #c43c35);
+    background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
     border-color: #c43c35 #c43c35 #882a25;
     border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
@@ -3675,7 +3640,7 @@
     background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));
     background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
     background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
-    background-image: linear-gradient(top, #5bc0de, #339bb9);
+    background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
     border-color: #339bb9 #339bb9 #22697d;
     border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
@@ -3690,7 +3655,7 @@
     background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));
     background-image: -webkit-linear-gradient(top, #62c462, #57a957);
     background-image: -o-linear-gradient(top, #62c462, #57a957);
-    background-image: linear-gradient(top, #62c462, #57a957);
+    background-image: linear-gradient(to bottom, #62c462, #57a957);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
     border-color: #57a957 #57a957 #3d773d;
     border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
@@ -3864,7 +3829,6 @@
     padding: 6px 12px;
     -webkit-border-radius: 4px 4px 4px 4px;
     -khtml-border-radius: 4px 4px 4px 4px;
-    -moz-border-radius: 4px 4px 4px 4px;
     border-radius: 4px 4px 4px 4px;
     box-shadow: 0 1px 0 #ececec;
     cursor: pointer;
@@ -3996,6 +3960,10 @@
     padding: 0;
 }
 
+#login div.form div.fields div.field div.input input.large {
+    width: 250px;
+}
+
 #login div.form div.fields div.field div.checkbox, #register div.form div.fields div.field div.checkbox {
     margin: 0 0 0 184px;
     padding: 0;
@@ -4038,7 +4006,6 @@
 .q_filter_box {
     -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
     -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
     border-radius: 4px;
     border: 0 none;
     color: #AAAAAA;
@@ -4188,7 +4155,6 @@
     overflow: auto;
     -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
     -webkit-border-radius: 3px;
-    -moz-border-radius: 3px;
     border-radius: 3px;
 }
 
@@ -4290,7 +4256,6 @@
     overflow: auto;
     -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
     -webkit-border-radius: 3px;
-    -moz-border-radius: 3px;
     border-radius: 3px;
 }
 
@@ -4304,7 +4269,6 @@
     border: 1px solid #ddd;
     margin-top: 10px;
     -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
     border-radius: 4px;
 }
 
@@ -4354,7 +4318,6 @@
 .comment-form .clearfix {
     background: #EEE;
     -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
     border-radius: 4px;
     padding: 10px;
 }
@@ -4440,7 +4403,6 @@
 .comment-inline-form .clearfix {
     background: #EEE;
     -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
     border-radius: 4px;
     padding: 5px;
 }
@@ -4517,7 +4479,6 @@
 .inline-comments .comment {
     border: 1px solid #ddd;
     -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
     border-radius: 4px;
     margin: 3px 3px 5px 5px;
     background-color: #FAFAFA;
@@ -4584,7 +4545,6 @@
     background-color: #DEDEDE !important;
     border-radius: 4px !important;
     -webkit-border-radius: 4px !important;
-    -moz-border-radius: 4px !important;
 }
 
 .notification-header {
@@ -4609,7 +4569,6 @@
 .notification-table {
     border: 1px solid #ccc;
     -webkit-border-radius: 6px 6px 6px 6px;
-    -moz-border-radius: 6px 6px 6px 6px;
     border-radius: 6px 6px 6px 6px;
     clear: both;
     margin: 0px 20px 0px 20px;
@@ -4660,7 +4619,6 @@
     text-transform: uppercase;
     white-space: nowrap;
     -webkit-border-radius: 3px;
-    -moz-border-radius: 3px;
     border-radius: 3px;
 }
 
@@ -4698,6 +4656,24 @@
 /*****************************************************************************
                                   DIFFS CSS
 ******************************************************************************/
+.diff-collapse{
+    text-align: center;
+    margin-bottom: -15px;
+}
+.diff-collapse-button{
+    cursor: pointer;
+    color: #666;
+    font-size: 16px;
+}
+.diff-container {
+
+}
+
+.diff-container.hidden{
+    display: none;
+    overflow: hidden;
+}
+
 
 div.diffblock {
     overflow: auto;
@@ -4709,7 +4685,6 @@
     /* new */
     line-height: 125%;
     -webkit-border-radius: 6px 6px 0px 0px;
-    -moz-border-radius: 6px 6px 0px 0px;
     border-radius: 6px 6px 0px 0px;
 }
 div.diffblock.margined {
@@ -4787,12 +4762,13 @@
 table.code-difftable {
     border-collapse: collapse;
     width: 99%;
+    border-radius: 0px !important;
 }
 table.code-difftable td {
     padding: 0 !important;
     background: none !important;
     border:0 !important;
-    vertical-align: none !important;
+    vertical-align: baseline !important
 }
 table.code-difftable .context {
     background:none repeat scroll 0 0 #DDE7EF;
@@ -4887,3 +4863,8 @@
 div.comment:target>.comment-wrapp {
     border: solid 2px #ee0 !important;
 }
+
+.lineno:target a {
+    border: solid 2px #ee0 !important;
+    margin: -2px;
+}
--- a/rhodecode/public/js/rhodecode.js	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/public/js/rhodecode.js	Mon Mar 04 18:42:14 2013 +0100
@@ -302,12 +302,25 @@
             }
             if (matchlist.hasOwnProperty(route_name)) {
                 var route = matchlist[route_name];
+                // param substitution
                 for(var i=0; i < route[1].length; i++) {
 
                    if (!params.hasOwnProperty(route[1][i]))
                         throw new Error(route[1][i] + ' missing in "' + route_name + '" route generation');
                 }
                 result = sprintf(route[0], params);
+                
+                var ret = [];
+                //extra params => GET
+                for(param in params){
+                	if (route[1].indexOf(param) == -1){
+                		ret.push(encodeURIComponent(param) + "=" + encodeURIComponent(params[param]));	
+                	}
+                }
+                var _parts = ret.join("&");
+                if(_parts){
+                	result = result +'?'+ _parts
+                }
             }
 
             return result;
@@ -1289,7 +1302,7 @@
             return matches;
         };
 
-    // Define a custom search function for the DataSource of usersGroups
+    // Define a custom search function for the DataSource of userGroups
     var matchGroups = function (sQuery) {
             // Case insensitive matching
             var query = sQuery.toLowerCase();
@@ -1707,7 +1720,7 @@
             return matches;
         };
 
-    // Define a custom search function for the DataSource of usersGroups
+    // Define a custom search function for the DataSource of userGroups
     var matchGroups = function (sQuery) {
             // Case insensitive matching
             var query = sQuery.toLowerCase();
@@ -2149,3 +2162,26 @@
 		});
 	}
 }
+
+
+// global hooks after DOM is loaded
+
+YUE.onDOMReady(function(){
+	YUE.on(YUQ('.diff-collapse-button'), 'click', function(e){
+		var button = e.currentTarget;
+		var t = YUD.get(button).getAttribute('target');
+	    console.log(t);
+		if(YUD.hasClass(t, 'hidden')){
+			YUD.removeClass(t, 'hidden');
+			YUD.get(button).innerHTML = "&uarr; {0} &uarr;".format(_TM['collapse diff']);
+		}
+		else if(!YUD.hasClass(t, 'hidden')){
+			YUD.addClass(t, 'hidden');
+			YUD.get(button).innerHTML = "&darr; {0} &darr;".format(_TM['expand diff']);
+		}
+	});
+	
+	
+	
+});
+
--- a/rhodecode/templates/admin/notifications/show_notification.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/admin/notifications/show_notification.html	Mon Mar 04 18:42:14 2013 +0100
@@ -39,7 +39,12 @@
             <span id="${c.notification.notification_id}" class="delete-notification delete_icon action"></span>
           </div>
         </div>
-        <div class="notification-body">${h.rst_w_mentions(c.notification.body)}</div>
+        <div class="notification-body">
+        <div class="notification-subject">${h.literal(c.notification.subject)}</div>
+        %if c.notification.body:
+            ${h.rst_w_mentions(c.notification.body)}
+        %endif
+        </div>
       </div>
     </div>
 </div>
--- a/rhodecode/templates/admin/permissions/permissions.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/admin/permissions/permissions.html	Mon Mar 04 18:42:14 2013 +0100
@@ -59,7 +59,7 @@
                     ${h.checkbox('overwrite_default_group','true')}
                     <label for="overwrite_default_group">
                     <span class="tooltip"
-                    title="${h.tooltip(_('All default permissions on each repository group will be reset to choosen permission, note that all custom default permission on repositories group will be lost'))}">
+                    title="${h.tooltip(_('All default permissions on each repository group will be reset to choosen permission, note that all custom default permission on repository groups will be lost'))}">
                     ${_('overwrite existing settings')}</span> </label>
 
                 </div>
--- a/rhodecode/templates/admin/repos/repo_edit_perms.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/admin/repos/repo_edit_perms.html	Mon Mar 04 18:42:14 2013 +0100
@@ -38,7 +38,7 @@
         %endif
     %endfor
 
-    ## USERS GROUPS
+    ## USER GROUPS
     %for g2p in c.repo_info.users_group_to_perm:
         <tr id="id${id(g2p.users_group.users_group_name)}">
             <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'repository.none')}</td>
@@ -54,7 +54,7 @@
                 %endif
             </td>
             <td>
-                <span class="delete_icon action_button" onclick="ajaxActionUsersGroup(${g2p.users_group.users_group_id},'${'id%s'%id(g2p.users_group.users_group_name)}')">
+                <span class="delete_icon action_button" onclick="ajaxActionUserGroup(${g2p.users_group.users_group_id},'${'id%s'%id(g2p.users_group.users_group_name)}')">
                 ${_('revoke')}
                 </span>
             </td>
@@ -101,7 +101,7 @@
     var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
 };
 
-function ajaxActionUsersGroup(users_group_id,field_id){
+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){
@@ -109,7 +109,7 @@
             tr.parentNode.removeChild(tr);
         },
         failure:function(o){
-            alert("${_('Failed to remove users group')}");
+            alert("${_('Failed to remove user group')}");
         },
     };
     var postData = '_method=delete&users_group_id='+users_group_id;
--- a/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html	Mon Mar 04 18:42:14 2013 +0100
@@ -40,7 +40,7 @@
         </tr>
     %endfor
 
-    ## USERS GROUPS
+    ## USER GROUPS
     %for g2p in c.repos_group.users_group_to_perm:
         <tr id="id${id(g2p.users_group.users_group_name)}">
             <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.none')}</td>
@@ -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="ajaxActionUsersGroup(${g2p.users_group.users_group_id},'${'id%s'%id(g2p.users_group.users_group_name)}')">
+                <span class="delete_icon action_button" onclick="ajaxActionUserGroup(${g2p.users_group.users_group_id},'${'id%s'%id(g2p.users_group.users_group_name)}')">
                 ${_('revoke')}
                 </span>
             </td>
@@ -105,7 +105,7 @@
     var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
 };
 
-function ajaxActionUsersGroup(users_group_id,field_id){
+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){
@@ -113,7 +113,7 @@
             tr.parentNode.removeChild(tr);
         },
         failure:function(o){
-            alert("${_('Failed to remove users group')}");
+            alert("${_('Failed to remove user group')}");
         },
     };
     var recursive = YUD.get('recursive').checked;
--- a/rhodecode/templates/admin/repos_groups/repos_groups_show.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/admin/repos_groups/repos_groups_show.html	Mon Mar 04 18:42:14 2013 +0100
@@ -2,14 +2,14 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${_('Repositories groups administration')} - ${c.rhodecode_name}
+    ${_('Repository groups administration')} - ${c.rhodecode_name}
 </%def>
 
 
 <%def name="breadcrumbs_links()">
     ${h.link_to(_('Admin'),h.url('admin_home'))}
     &raquo;
-    ${_('repositories groups')}
+    ${_('repository groups')}
 </%def>
 <%def name="page_nav()">
     ${self.menu('admin')}
@@ -48,7 +48,7 @@
                   <tr>
                       <td>
                           <div style="white-space: nowrap">
-                          <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/>
+                          <img class="icon" alt="${_('Repository group')}" src="${h.url('/images/icons/database_link.png')}"/>
                           ${h.link_to(h.literal(' &raquo; '.join(map(h.safe_unicode,[g.name for g in gr.parents+[gr]]))), url('repos_group_home',group_name=gr.group_name))}
                           </div>
                       </td>
@@ -69,7 +69,7 @@
 
             </table>
             % else:
-                ${_('There are no repositories groups yet')}
+                ${_('There are no repository groups yet')}
             % endif
 
     </div>
--- a/rhodecode/templates/admin/settings/settings.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/admin/settings/settings.html	Mon Mar 04 18:42:14 2013 +0100
@@ -64,7 +64,7 @@
                 <div class="checkboxes">
                     <div class="checkbox">
                         ${h.checkbox('full_index',True)}
-                        <label for="full_index">${_('build from scratch')}</label>
+                        <label for="full_index">${_('Build from scratch')}</label>
                     </div>
                 </div>
             </div>
@@ -85,7 +85,7 @@
 
              <div class="field">
                 <div class="label">
-                    <label for="rhodecode_title">${_('Application name')}:</label>
+                    <label for="rhodecode_title">${_('Site branding')}:</label>
                 </div>
                 <div class="input">
                     ${h.text('rhodecode_title',size=30)}
@@ -94,7 +94,7 @@
 
             <div class="field">
                 <div class="label">
-                    <label for="rhodecode_realm">${_('Realm text')}:</label>
+                    <label for="rhodecode_realm">${_('HTTP authentication realm')}:</label>
                 </div>
                 <div class="input">
                     ${h.text('rhodecode_realm',size=30)}
@@ -103,7 +103,7 @@
 
             <div class="field">
                 <div class="label">
-                    <label for="rhodecode_ga_code">${_('GA code')}:</label>
+                    <label for="rhodecode_ga_code">${_('Google Analytics code')}:</label>
                 </div>
                 <div class="input">
                     ${h.text('rhodecode_ga_code',size=30)}
--- a/rhodecode/templates/admin/users/user_edit.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/admin/users/user_edit.html	Mon Mar 04 18:42:14 2013 +0100
@@ -40,12 +40,12 @@
         </div>
         <div class="field">
             <div class="label">
-                <label>${_('API key')}</label> ${c.user.api_key}
+                <label>${_('API key')}:</label> ${c.user.api_key}
             </div>
         </div>
         <div class="field">
             <div class="label">
-                <label>${_('Your IP')}</label> ${c.perm_user.ip_addr or "?"}
+                <label>${_('Current IP')}:</label> ${c.perm_user.ip_addr or "?"}
             </div>
         </div>
         <div class="fields">
--- a/rhodecode/templates/admin/users/user_edit_my_account.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/admin/users/user_edit_my_account.html	Mon Mar 04 18:42:14 2013 +0100
@@ -102,6 +102,7 @@
 </div>
 
 <script type="text/javascript">
+pyroutes.register('admin_settings_my_pullrequests', "${url('admin_settings_my_pullrequests')}", []);
 
 var show_perms = function(e){
     YUD.addClass('show_perms', 'current');
@@ -145,8 +146,15 @@
     YUD.setStyle('pullrequests_container','display','');
     YUD.setStyle('q_filter','display','none');
 
-    var url = "${h.url('admin_settings_my_pullrequests')}";
-    ypjax(url, 'pullrequests_container');
+    var url = pyroutes.url('admin_settings_my_pullrequests');
+    if(YUD.get('show_closed') && YUD.get('show_closed').checked) {
+        var url = pyroutes.url('admin_settings_my_pullrequests', {'pr_show_closed': '1'});
+    }
+    ypjax(url, 'pullrequests_container', function(){
+        YUE.on('show_closed','change',function (e) {
+            show_pullrequests(e);
+        });
+    });
 }
 YUE.on('show_pullrequests','click',function(e){
     show_pullrequests(e)
@@ -270,6 +278,7 @@
           clearTimeout(filterTimeout);
           filterTimeout = setTimeout(updateFilter,600);
       });
+
     }
 </script>
 </%def>
--- a/rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html	Mon Mar 04 18:42:14 2013 +0100
@@ -1,4 +1,8 @@
-
+%if c.show_closed:
+  ${h.checkbox('show_closed',checked="checked", label=_('Show closed pull requests'))}
+%else:
+  ${h.checkbox('show_closed',label=_('Show closed pull requests'))}
+%endif
 <div class="pullrequests_section_head">${_('Opened by me')}</div>
 <ul>
     %if c.my_pull_requests:
--- a/rhodecode/templates/admin/users_groups/users_group_add.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/admin/users_groups/users_group_add.html	Mon Mar 04 18:42:14 2013 +0100
@@ -2,14 +2,14 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${_('Add users group')} - ${c.rhodecode_name}
+    ${_('Add user group')} - ${c.rhodecode_name}
 </%def>
 <%def name="breadcrumbs_links()">
     ${h.link_to(_('Admin'),h.url('admin_home'))}
     &raquo;
-    ${h.link_to(_('Users groups'),h.url('users_groups'))}
+    ${h.link_to(_('User groups'),h.url('users_groups'))}
     &raquo;
-    ${_('add new users group')}
+    ${_('add new user group')}
 </%def>
 
 <%def name="page_nav()">
--- a/rhodecode/templates/admin/users_groups/users_group_edit.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/admin/users_groups/users_group_edit.html	Mon Mar 04 18:42:14 2013 +0100
@@ -2,13 +2,13 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${_('Edit users group')} ${c.users_group.users_group_name} - ${c.rhodecode_name}
+    ${_('Edit user group')} ${c.users_group.users_group_name} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
     ${h.link_to(_('Admin'),h.url('admin_home'))}
     &raquo;
-    ${h.link_to(_('UsersGroups'),h.url('users_groups'))}
+    ${h.link_to(_('UserGroups'),h.url('users_groups'))}
     &raquo;
     ${_('edit')} "${c.users_group.users_group_name}"
 </%def>
--- a/rhodecode/templates/admin/users_groups/users_groups.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/admin/users_groups/users_groups.html	Mon Mar 04 18:42:14 2013 +0100
@@ -2,13 +2,13 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${_('Users groups administration')} - ${c.rhodecode_name}
+    ${_('User groups administration')} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
     ${h.link_to(_('Admin'),h.url('admin_home'))}
     &raquo;
-    ${_('users groups')}
+    ${_('user groups')}
 </%def>
 
 <%def name="page_nav()">
@@ -44,7 +44,7 @@
                     <td>
                         ${h.form(url('users_group', id=u_group.users_group_id),method='delete')}
                             ${h.submit('remove_',_('delete'),id="remove_group_%s" % u_group.users_group_id,
-                            class_="delete_icon action_button",onclick="return  confirm('"+_('Confirm to delete this users group: %s') % u_group.users_group_name+"');")}
+                            class_="delete_icon action_button",onclick="return  confirm('"+_('Confirm to delete this user group: %s') % u_group.users_group_name+"');")}
                         ${h.end_form()}
                     </td>
                 </tr>
--- a/rhodecode/templates/base/base.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/base/base.html	Mon Mar 04 18:42:14 2013 +0100
@@ -71,9 +71,9 @@
   <ul class="admin_menu">
       <li>${h.link_to(_('admin journal'),h.url('admin_home'),class_='journal')}</li>
       <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
-      <li>${h.link_to(_('repositories groups'),h.url('repos_groups'),class_='repos_groups')}</li>
+      <li>${h.link_to(_('repository groups'),h.url('repos_groups'),class_='repos_groups')}</li>
       <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
-      <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
+      <li>${h.link_to(_('user groups'),h.url('users_groups'),class_='groups')}</li>
       <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
       <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
       <li>${h.link_to(_('defaults'),h.url('defaults'),class_='defaults')}</li>
@@ -233,7 +233,7 @@
                             <label for="username">${_('Username')}:</label>
                         </div>
                         <div class="input">
-                            ${h.text('username',class_='focus',size=40)}
+                            ${h.text('username',class_='focus')}
                         </div>
 
                     </div>
@@ -242,7 +242,7 @@
                             <label for="password">${_('Password')}:</label>
                         </div>
                         <div class="input">
-                            ${h.password('password',class_='focus',size=40)}
+                            ${h.password('password',class_='focus')}
                         </div>
 
                     </div>
--- a/rhodecode/templates/base/root.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/base/root.html	Mon Mar 04 18:42:14 2013 +0100
@@ -52,7 +52,10 @@
                 'Open new pull request': "${_('Open new pull request')}",
                 'Open new pull request for selected changesets':  "${_('Open new pull request for selected changesets')}",
                 'Show selected changes __S -> __E': "${_('Show selected changes __S -> __E')}",
+                'Show selected change __S': "${_('Show selected change __S')}",
                 'Selection link': "${_('Selection link')}",
+                'collapse diff': "${_('collapse diff')}",
+                'expand diff': "${_('expand diff')}",
             };
             var _TM = TRANSLATION_MAP;
 
--- a/rhodecode/templates/branches/branches.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/branches/branches.html	Mon Mar 04 18:42:14 2013 +0100
@@ -27,7 +27,7 @@
     </div>
     <!-- end box / title -->
     %if c.repo_branches:
-    <div class="info_box" id="compare_branches" style="clear: both;padding: 10px 19px;vertical-align: right;text-align: right;"><a href="#" class="ui-btn small">${_('Compare branches')}</a></div>
+    <div class="info_box" id="compare_branches" style="clear: both;padding: 10px 19px;text-align: right;"><a href="#" class="ui-btn small">${_('Compare branches')}</a></div>
     %endif
     <div class="table">
         <%include file='branches_data.html'/>
--- a/rhodecode/templates/changelog/changelog.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/changelog/changelog.html	Mon Mar 04 18:42:14 2013 +0100
@@ -33,15 +33,15 @@
                     <canvas id="graph_canvas"></canvas>
                 </div>
                 <div id="graph_content">
-                    <div class="info_box" style="clear: both;padding: 10px 6px;vertical-align: right;text-align: right;">
+                    <div class="info_box" style="clear: both;padding: 10px 6px;text-align: right;">
                     <a href="#" class="ui-btn small" id="rev_range_container" style="display:none"></a>
                     <a href="#" class="ui-btn small" id="rev_range_clear" style="display:none">${_('Clear selection')}</a>
 
                     %if c.rhodecode_db_repo.fork:
-                        <a title="${_('compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,org_ref_type='branch',org_ref='default',other_repo=c.repo_name,other_ref_type='branch',other_ref=request.GET.get('branch') or 'default')}" class="ui-btn small">${_('Compare fork with parent')}</a>
+                        <a title="${_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,org_ref_type='branch',org_ref='default',other_repo=c.repo_name,other_ref_type='branch',other_ref=request.GET.get('branch') or 'default')}" class="ui-btn small">${_('Compare fork with parent')}</a>
                     %endif
                     %if h.is_hg(c.rhodecode_repo):
-                    <a id="open_new_pr" href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="ui-btn small">${_('open new pull request')}</a>
+                    <a id="open_new_pr" href="${h.url('pullrequest_form',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a>
                     %endif
                     </div>
                     <div class="container_header">
@@ -72,7 +72,7 @@
                         </div>
                         <div class="mid">
                             <div class="message">${h.urlify_commit(cs.message, c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
-                            <div class="expand"><span class="expandtext">&darr; ${_('show more')} &darr;</span></div>
+                            <div class="expand"><span class="expandtext">&darr; ${_('Show more')} &darr;</span></div>
                         </div>
                         <div class="right">
                                     <div class="changes">
@@ -163,7 +163,6 @@
                           if(checked_checkboxes.length>0){
                             // modify open pull request to show we have selected cs
                             YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets'];
-
                           }else{
                             YUD.get('open_new_pr').innerHTML = _TM['Open new pull request'];
                           }
@@ -172,32 +171,13 @@
                         if(checked_checkboxes.length>0){
                             var rev_end = checked_checkboxes[0].name;
                             var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
-
-                            // now select all checkboxes in the middle.
-                            var checked = false;
-                            for (var i=0; i<checkboxes.length; i++){
-                                var cb = checkboxes[i];
-                                var rev = cb.name;
-
-                                if (rev == rev_end){
-                                    checked = true;
-                                }
-                                if (checked){
-                                    cb.checked = true;
-                                }
-                                else{
-                                    cb.checked = false;
-                                }
-                                if (rev == rev_start){
-                                    checked = false;
-                                }
-
-                            }
-
                             var url = url_tmpl.replace('__REVRANGE__',
                                     rev_start+'...'+rev_end);
 
-                            var link = _TM['Show selected changes __S -> __E'];
+                            var link = (rev_start == rev_end)
+                                ? _TM['Show selected change __S']
+                                : _TM['Show selected changes __S -> __E'];
+
                             link = link.replace('__S',rev_start.substr(0,6));
                             link = link.replace('__E',rev_end.substr(0,6));
                             YUD.get('rev_range_container').href = url;
--- a/rhodecode/templates/changeset/diff_block.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/changeset/diff_block.html	Mon Mar 04 18:42:14 2013 +0100
@@ -4,7 +4,10 @@
 ## ${diff_block.diff_block(change)}
 ##
 <%def name="diff_block(change)">
-
+<div class="diff-collapse">
+    <span target="${'diff-container-%s' % (id(change))}" class="diff-collapse-button">&uarr; ${_('collapse diff')} &uarr;</span>
+</div>
+<div class="diff-container" id="${'diff-container-%s' % (id(change))}">
 %for FID,(cs1, cs2, change, path, diff, stats) in change.iteritems():
     ##%if op !='removed':
     <div id="${FID}_target" style="clear:both;margin-top:25px"></div>
@@ -37,7 +40,7 @@
     </div>
     ##%endif
 %endfor
-
+</div>
 </%def>
 
 <%def name="diff_block_simple(change)">
@@ -49,8 +52,8 @@
           <div class="changeset_header">
               <div class="changeset_file">
                   ${h.safe_unicode(filenode_path)} |
-                  <a class="spantag" href="${h.url('files_home', repo_name=c.repo_name, f_path=filenode_path, revision=c.org_ref)}">${c.org_ref_type}@${c.org_ref}</a> -&gt;
-                  <a class="spantag" href="${h.url('files_home', repo_name=c.repo_name, f_path=filenode_path, revision=c.other_ref)}">${c.other_ref_type}@${c.other_ref}</a>
+                  <a class="spantag" href="${h.url('files_home', repo_name=c.repo_name, f_path=filenode_path, revision=c.org_ref)}" title="${_('show file at latest version in this repo')}">${c.org_ref_type}@${h.short_id(c.org_ref) if c.org_ref_type=='rev' else c.org_ref}</a> -&gt;
+                  <a class="spantag" href="${h.url('files_home', repo_name=c.repo_name, f_path=filenode_path, revision=c.other_ref)}" title="${_('show file at initial version in this repo')}">${c.other_ref_type}@${h.short_id(c.other_ref) if c.other_ref_type=='rev' else c.other_ref}</a>
               </div>
           </div>
       </div>
--- a/rhodecode/templates/email_templates/changeset_comment.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/email_templates/changeset_comment.html	Mon Mar 04 18:42:14 2013 +0100
@@ -1,12 +1,17 @@
 ## -*- coding: utf-8 -*-
 <%inherit file="main.html"/>
-
-<h4>${subject}</h4>
-
+##message from user goes here
+<p>
+${cs_comment_user}: <br/>
 ${body}
+</p>
+%if status_change:
+    <span>${_('New status')} -&gt; ${status_change}</span>
+%endif
+<div>${_('View this comment here')}: ${cs_comment_url}</div>
 
-% if status_change is not None:
-<div>
-    ${_('New status')} -&gt; ${status_change}
-</div>
-% endif
+<pre>
+${_('Repo')}: ${cs_target_repo}
+${_('Changeset')}: ${h.short_id(raw_id)}
+${_('desc')}: ${h.shorter(message, 256)}
+</pre>
--- a/rhodecode/templates/email_templates/password_reset.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/email_templates/password_reset.html	Mon Mar 04 18:42:14 2013 +0100
@@ -1,12 +1,11 @@
 ## -*- coding: utf-8 -*-
 <%inherit file="main.html"/>
 
-${_('Hello')} ${user}
-
-${_('We received a request to create a new password for your account.')}
-
-${_('You can generate it by clicking following URL')}:
-
+<h4>${_('Hello %s') % user}</h4>
+<div>${_('We received a request to create a new password for your account.')}</div>
+<div>${_('You can generate it by clicking following URL')}:</div>
+<pre>
 ${reset_url}
-
-${_("If you didn't request new password please ignore this email.")}
+</pre>
+<br/>
+${_("If you did not request new password please ignore this email.")}
--- a/rhodecode/templates/email_templates/pull_request.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/email_templates/pull_request.html	Mon Mar 04 18:42:14 2013 +0100
@@ -10,8 +10,10 @@
 </p>
 
 <div>${_('revisions for reviewing')}</div>
-<ul>
-%for r in pr_revisions:
-    <li>${r}</li>
+<pre>
+%for r,r_msg in pr_revisions:
+${h.short_id(r)}:
+    ${h.shorter(r_msg, 256)}
+
 %endfor
-</ul>
+</pre>
--- a/rhodecode/templates/email_templates/pull_request_comment.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/email_templates/pull_request_comment.html	Mon Mar 04 18:42:14 2013 +0100
@@ -1,13 +1,18 @@
 ## -*- coding: utf-8 -*-
 <%inherit file="main.html"/>
-
-${_('User %s commented on pull request #%s for repository %s') % ('<b>%s</b>' % pr_comment_user, pr_id, pr_target_repo) |n}
+${_('Pull request #%s for repository %s') % (pr_id, pr_target_repo) |n}
+##message from user goes here
+<p>
+${pr_comment_user}: <br/>
+${body}
+</p>
 <div>${_('View this comment here')}: ${pr_comment_url}</div>
 
-<p>
-${body}
-
 %if status_change:
-    <span>${_('New status')} -&gt; ${status_change}</span>
+    %if closing_pr:
+       <span>${_('Closing pull request with status')} -&gt; ${status_change}</span>
+    %else:
+       <span>${_('New status')} -&gt; ${status_change}</span>
+    %endif
 %endif
 </p>
--- a/rhodecode/templates/files/files_source.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/files/files_source.html	Mon Mar 04 18:42:14 2013 +0100
@@ -86,8 +86,11 @@
                 h_lines.push(parseInt(highlight_ranges[pos]));
             }
       }
-    highlight_lines(h_lines);
-
+	  highlight_lines(h_lines);
+	  var _first_line= YUD.get('L'+h_lines[0]);
+	  if(_first_line){
+		  _first_line.scrollIntoView()
+	  }
     }
 
     // select code link event
--- a/rhodecode/templates/index_base.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/index_base.html	Mon Mar 04 18:42:14 2013 +0100
@@ -48,7 +48,7 @@
                     <tr>
                         <td>
                             <div style="white-space: nowrap">
-                            <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/>
+                            <img class="icon" alt="${_('Repository group')}" src="${h.url('/images/icons/database_link.png')}"/>
                             ${h.link_to(gr.name,url('repos_group_home',group_name=gr.group_name))}
                             </div>
                         </td>
--- a/rhodecode/templates/login.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/login.html	Mon Mar 04 18:42:14 2013 +0100
@@ -31,7 +31,7 @@
                         <label for="username">${_('Username')}:</label>
                     </div>
                     <div class="input">
-                        ${h.text('username',class_='focus',size=40)}
+                        ${h.text('username',class_='focus large')}
                     </div>
 
                 </div>
@@ -40,7 +40,7 @@
                         <label for="password">${_('Password')}:</label>
                     </div>
                     <div class="input">
-                        ${h.password('password',class_='focus',size=40)}
+                        ${h.password('password',class_='focus large')}
                     </div>
 
                 </div>
--- a/rhodecode/templates/pullrequests/pullrequest.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/pullrequests/pullrequest.html	Mon Mar 04 18:42:14 2013 +0100
@@ -30,7 +30,7 @@
                 <span style="font-size: 20px">
                 ${h.select('org_repo','',c.org_repos,class_='refs')}:${h.select('org_ref',c.default_org_ref,c.org_refs,class_='refs')}
                 </span>
-                 <div style="padding:5px 3px 3px 42px;">${c.rhodecode_db_repo.description}</div>
+                 <div style="padding:5px 3px 3px 20px;">${c.rhodecode_db_repo.description}</div>
             </div>
             <div style="clear:both;padding-top: 10px"></div>
         </div>
@@ -44,7 +44,7 @@
                 <span style="font-size: 20px">
                 ${h.select('other_repo',c.default_other_repo,c.other_repos,class_='refs')}:${h.select('other_ref',c.default_other_ref,c.default_other_refs,class_='refs')}
                 </span>
-                 <div id="other_repo_desc" style="padding:5px 3px 3px 42px;"></div>
+                 <div id="other_repo_desc" style="padding:5px 3px 3px 20px;"></div>
             </div>
             <div style="clear:both;padding-top: 10px"></div>
         </div>
@@ -146,24 +146,25 @@
 
       var select_refs = YUQ('#pull_request_form select.refs')
       var rev_data = {
-    	  'org_repo': org_repo,
-    	  'org_ref': org_ref[1],
-    	  'org_ref_type': org_ref[0],
-    	  'other_repo': other_repo,
-          'other_ref': other_ref[1],
-          'other_ref_type': other_ref[0],
+          'org_repo': org_repo,
+          'org_ref': org_ref[2],
+          'org_ref_type': 'rev',
+          'other_repo': other_repo,
+          'other_ref': other_ref[2],
+          'other_ref_type': 'rev',
       }; // gather the org/other ref and repo here
 
       for (k in rev_data){
-    	  url = url.replace('__'+k+'__',rev_data[k]);
+          url = url.replace('__'+k+'__',rev_data[k]);
       }
 
+      YUD.get('pull_request_overview').innerHTML = "${_('Loading ...')}";
+      YUD.get('pull_request_overview_url').href = url; // shouldn't have as_form ... but ...
+      YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','');
       ypjax(url,'pull_request_overview', function(data){
           var sel_box = YUQ('#pull_request_form #other_repo')[0];
           var repo_name = sel_box.options[sel_box.selectedIndex].value;
           var _data = other_repos_info[repo_name];
-          YUD.get('pull_request_overview_url').href = url;
-          YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','');
           YUD.get('other_repo_desc').innerHTML = other_repos_info[repo_name]['description'];
           YUD.get('other_ref').innerHTML = other_repos_info[repo_name]['revs'];
           // select back the revision that was just compared
@@ -171,8 +172,8 @@
           // reset && add the reviewer based on selected repo
           YUD.get('review_members').innerHTML = '';
           addReviewMember(_data.user.user_id, _data.user.firstname,
-        		          _data.user.lastname, _data.user.username,
-        		          _data.user.gravatar_link);
+                          _data.user.lastname, _data.user.username,
+                          _data.user.gravatar_link);
       })
   }
 
--- a/rhodecode/templates/pullrequests/pullrequest_show.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/pullrequests/pullrequest_show.html	Mon Mar 04 18:42:14 2013 +0100
@@ -7,7 +7,7 @@
 <%def name="breadcrumbs_links()">
     ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
-    ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))}
+    ${h.repo_link(c.rhodecode_db_repo.groups_and_repo)}
     &raquo;
     ${_('Pull request #%s') % c.pull_request.pull_request_id}
 </%def>
@@ -22,7 +22,12 @@
         %if c.pull_request.is_closed():
         <div style="padding:10px; font-size:22px;width:100%;text-align: center; color:#88D882">${_('Closed %s') % (h.age(c.pull_request.updated_on))} ${_('with status %s') % h.changeset_status_lbl(c.current_changeset_status)}</div>
         %endif
-    <h3>${_('Title')}: ${c.pull_request.title}</h3>
+    <h3>
+    %if c.pull_request.is_closed():
+        <img src="${h.url('/images/icons/lock_go.png')}" title="${_('Closed')}"/>
+    %endif
+    <img src="${h.url('/images/icons/flag_status_%s.png' % str(c.pull_request.last_review_status))}" />
+    ${_('Title')}: ${c.pull_request.title}</h3>
 
     <div class="form">
       <div id="summary" class="fields">
--- a/rhodecode/templates/switch_to_list.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/switch_to_list.html	Mon Mar 04 18:42:14 2013 +0100
@@ -4,7 +4,7 @@
     <ul>
     %if c.rhodecode_repo.branches.values():
         %for cnt,branch in enumerate(c.rhodecode_repo.branches.items()):
-            <li><div><pre>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[0]))}</pre></div></li>
+            <li><div><pre>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=(branch[0] if '/' not in branch[0] else branch[1]), at=branch[0]))}</pre></div></li>
         %endfor
     %else:
         <li>${h.link_to(_('There are no branches yet'),'#')}</li>
@@ -16,7 +16,7 @@
     <ul>
     %if c.rhodecode_repo.tags.values():
         %for cnt,tag in enumerate(c.rhodecode_repo.tags.items()):
-         <li><div><pre>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[0]))}</pre></div></li>
+         <li><div><pre>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=(tag[0] if '/' not in tag[0] else tag[1]), at=tag[0]))}</pre></div></li>
         %endfor
     %else:
         <li>${h.link_to(_('There are no tags yet'),'#')}</li>
@@ -29,7 +29,7 @@
     <ul>
     %if c.rhodecode_repo.bookmarks.values():
         %for cnt,book in enumerate(c.rhodecode_repo.bookmarks.items()):
-         <li><div><pre>${h.link_to('%s - %s' % (book[0],h.short_id(book[1])),h.url('files_home',repo_name=c.repo_name,revision=book[1]))}</pre></div></li>
+         <li><div><pre>${h.link_to('%s - %s' % (book[0],h.short_id(book[1])),h.url('files_home',repo_name=c.repo_name,revision=(book[0] if '/' not in book[0] else book[1]), at=book[0]))}</pre></div></li>
         %endfor
     %else:
         <li>${h.link_to(_('There are no bookmarks yet'),'#')}</li>
--- a/rhodecode/templates/tags/tags.html	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/templates/tags/tags.html	Mon Mar 04 18:42:14 2013 +0100
@@ -27,7 +27,7 @@
     </div>
     <!-- end box / title -->
     %if c.repo_tags:
-    <div class="info_box" id="compare_tags" style="clear: both;padding: 10px 19px;vertical-align: right;text-align: right;"><a href="#" class="ui-btn small">${_('Compare tags')}</a></div>
+    <div class="info_box" id="compare_tags" style="clear: both;padding: 10px 19px;text-align: right;"><a href="#" class="ui-btn small">${_('Compare tags')}</a></div>
     %endif
     <div class="table">
         <%include file='tags_data.html'/>
--- a/rhodecode/tests/api/api_base.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/tests/api/api_base.py	Mon Mar 04 18:42:14 2013 +0100
@@ -6,7 +6,7 @@
 from rhodecode.lib.compat import json
 from rhodecode.lib.auth import AuthUser
 from rhodecode.model.user import UserModel
-from rhodecode.model.users_group import UsersGroupModel
+from rhodecode.model.users_group import UserGroupModel
 from rhodecode.model.repo import RepoModel
 from rhodecode.model.meta import Session
 from rhodecode.model.scm import ScmModel
@@ -43,19 +43,19 @@
     return response
 
 
-TEST_USERS_GROUP = 'test_users_group'
+TEST_USER_GROUP = 'test_users_group'
 
 
-def make_users_group(name=TEST_USERS_GROUP):
-    gr = UsersGroupModel().create(name=name)
-    UsersGroupModel().add_user_to_group(users_group=gr,
+def make_users_group(name=TEST_USER_GROUP):
+    gr = UserGroupModel().create(name=name)
+    UserGroupModel().add_user_to_group(users_group=gr,
                                         user=TEST_USER_ADMIN_LOGIN)
     Session().commit()
     return gr
 
 
-def destroy_users_group(name=TEST_USERS_GROUP):
-    UsersGroupModel().delete(users_group=name, force=True)
+def destroy_users_group(name=TEST_USER_GROUP):
+    UserGroupModel().delete(users_group=name, force=True)
     Session().commit()
 
 
@@ -999,10 +999,10 @@
 
     def test_api_get_users_group(self):
         id_, params = _build_data(self.apikey, 'get_users_group',
-                                  usersgroupid=TEST_USERS_GROUP)
+                                  usersgroupid=TEST_USER_GROUP)
         response = api_call(self, params)
 
-        users_group = UsersGroupModel().get_group(TEST_USERS_GROUP)
+        users_group = UserGroupModel().get_group(TEST_USER_GROUP)
         members = []
         for user in users_group.members:
             user = user.user
@@ -1021,13 +1021,13 @@
         response = api_call(self, params)
 
         expected = []
-        for gr_name in [TEST_USERS_GROUP, 'test_users_group2']:
-            users_group = UsersGroupModel().get_group(gr_name)
+        for gr_name in [TEST_USER_GROUP, 'test_users_group2']:
+            users_group = UserGroupModel().get_group(gr_name)
             ret = users_group.get_api_data()
             expected.append(ret)
         self._compare_ok(id_, expected, given=response.body)
 
-        UsersGroupModel().delete(users_group='test_users_group2')
+        UserGroupModel().delete(users_group='test_users_group2')
         Session().commit()
 
     def test_api_create_users_group(self):
@@ -1037,8 +1037,8 @@
         response = api_call(self, params)
 
         ret = {
-            'msg': 'created new users group `%s`' % group_name,
-            'users_group': jsonify(UsersGroupModel()\
+            'msg': 'created new user group `%s`' % group_name,
+            'users_group': jsonify(UserGroupModel()\
                                    .get_by_name(group_name)\
                                    .get_api_data())
         }
@@ -1049,13 +1049,13 @@
 
     def test_api_get_users_group_that_exist(self):
         id_, params = _build_data(self.apikey, 'create_users_group',
-                                  group_name=TEST_USERS_GROUP)
+                                  group_name=TEST_USER_GROUP)
         response = api_call(self, params)
 
-        expected = "users group `%s` already exist" % TEST_USERS_GROUP
+        expected = "user group `%s` already exist" % TEST_USER_GROUP
         self._compare_error(id_, expected, given=response.body)
 
-    @mock.patch.object(UsersGroupModel, 'create', crash)
+    @mock.patch.object(UserGroupModel, 'create', crash)
     def test_api_get_users_group_exception_occurred(self):
         group_name = 'exception_happens'
         id_, params = _build_data(self.apikey, 'create_users_group',
@@ -1067,7 +1067,7 @@
 
     def test_api_add_user_to_users_group(self):
         gr_name = 'test_group'
-        UsersGroupModel().create(gr_name)
+        UserGroupModel().create(gr_name)
         Session().commit()
         id_, params = _build_data(self.apikey, 'add_user_to_users_group',
                                   usersgroupid=gr_name,
@@ -1075,13 +1075,13 @@
         response = api_call(self, params)
 
         expected = {
-                    'msg': 'added member `%s` to users group `%s`' % (
+                    'msg': 'added member `%s` to user group `%s`' % (
                                 TEST_USER_ADMIN_LOGIN, gr_name
                             ),
                     'success': True}
         self._compare_ok(id_, expected, given=response.body)
 
-        UsersGroupModel().delete(users_group=gr_name)
+        UserGroupModel().delete(users_group=gr_name)
         Session().commit()
 
     def test_api_add_user_to_users_group_that_doesnt_exist(self):
@@ -1090,29 +1090,29 @@
                                   userid=TEST_USER_ADMIN_LOGIN)
         response = api_call(self, params)
 
-        expected = 'users group `%s` does not exist' % 'false-group'
+        expected = 'user group `%s` does not exist' % 'false-group'
         self._compare_error(id_, expected, given=response.body)
 
-    @mock.patch.object(UsersGroupModel, 'add_user_to_group', crash)
+    @mock.patch.object(UserGroupModel, 'add_user_to_group', crash)
     def test_api_add_user_to_users_group_exception_occurred(self):
         gr_name = 'test_group'
-        UsersGroupModel().create(gr_name)
+        UserGroupModel().create(gr_name)
         Session().commit()
         id_, params = _build_data(self.apikey, 'add_user_to_users_group',
                                   usersgroupid=gr_name,
                                   userid=TEST_USER_ADMIN_LOGIN)
         response = api_call(self, params)
 
-        expected = 'failed to add member to users group `%s`' % gr_name
+        expected = 'failed to add member to user group `%s`' % gr_name
         self._compare_error(id_, expected, given=response.body)
 
-        UsersGroupModel().delete(users_group=gr_name)
+        UserGroupModel().delete(users_group=gr_name)
         Session().commit()
 
     def test_api_remove_user_from_users_group(self):
         gr_name = 'test_group_3'
-        gr = UsersGroupModel().create(gr_name)
-        UsersGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
+        gr = UserGroupModel().create(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',
                                   usersgroupid=gr_name,
@@ -1120,30 +1120,30 @@
         response = api_call(self, params)
 
         expected = {
-                    'msg': 'removed member `%s` from users group `%s`' % (
+                    'msg': 'removed member `%s` from user group `%s`' % (
                                 TEST_USER_ADMIN_LOGIN, gr_name
                             ),
                     'success': True}
         self._compare_ok(id_, expected, given=response.body)
 
-        UsersGroupModel().delete(users_group=gr_name)
+        UserGroupModel().delete(users_group=gr_name)
         Session().commit()
 
-    @mock.patch.object(UsersGroupModel, 'remove_user_from_group', crash)
+    @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 = UsersGroupModel().create(gr_name)
-        UsersGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
+        gr = UserGroupModel().create(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',
                                   usersgroupid=gr_name,
                                   userid=TEST_USER_ADMIN_LOGIN)
         response = api_call(self, params)
 
-        expected = 'failed to remove member from users group `%s`' % gr_name
+        expected = 'failed to remove member from user group `%s`' % gr_name
         self._compare_error(id_, expected, given=response.body)
 
-        UsersGroupModel().delete(users_group=gr_name)
+        UserGroupModel().delete(users_group=gr_name)
         Session().commit()
 
     @parameterized.expand([('none', 'repository.none'),
@@ -1224,13 +1224,13 @@
     def test_api_grant_users_group_permission(self, name, perm):
         id_, params = _build_data(self.apikey, 'grant_users_group_permission',
                                   repoid=self.REPO,
-                                  usersgroupid=TEST_USERS_GROUP,
+                                  usersgroupid=TEST_USER_GROUP,
                                   perm=perm)
         response = api_call(self, params)
 
         ret = {
-            'msg': 'Granted perm: `%s` for users group: `%s` in repo: `%s`' % (
-                perm, TEST_USERS_GROUP, self.REPO
+            'msg': 'Granted perm: `%s` for user group: `%s` in repo: `%s`' % (
+                perm, TEST_USER_GROUP, self.REPO
             ),
             'success': True
         }
@@ -1241,7 +1241,7 @@
         perm = 'haha.no.permission'
         id_, params = _build_data(self.apikey, 'grant_users_group_permission',
                                   repoid=self.REPO,
-                                  usersgroupid=TEST_USERS_GROUP,
+                                  usersgroupid=TEST_USER_GROUP,
                                   perm=perm)
         response = api_call(self, params)
 
@@ -1253,28 +1253,28 @@
         perm = 'repository.read'
         id_, params = _build_data(self.apikey, 'grant_users_group_permission',
                                   repoid=self.REPO,
-                                  usersgroupid=TEST_USERS_GROUP,
+                                  usersgroupid=TEST_USER_GROUP,
                                   perm=perm)
         response = api_call(self, params)
 
-        expected = 'failed to edit permission for users group: `%s` in repo: `%s`' % (
-                    TEST_USERS_GROUP, self.REPO
+        expected = 'failed to edit permission for user group: `%s` in repo: `%s`' % (
+                    TEST_USER_GROUP, self.REPO
                 )
         self._compare_error(id_, expected, given=response.body)
 
     def test_api_revoke_users_group_permission(self):
         RepoModel().grant_users_group_permission(repo=self.REPO,
-                                                 group_name=TEST_USERS_GROUP,
+                                                 group_name=TEST_USER_GROUP,
                                                  perm='repository.read')
         Session().commit()
         id_, params = _build_data(self.apikey, 'revoke_users_group_permission',
                                   repoid=self.REPO,
-                                  usersgroupid=TEST_USERS_GROUP,)
+                                  usersgroupid=TEST_USER_GROUP,)
         response = api_call(self, params)
 
         expected = {
-            'msg': 'Revoked perm for users group: `%s` in repo: `%s`' % (
-                TEST_USERS_GROUP, self.REPO
+            'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
+                TEST_USER_GROUP, self.REPO
             ),
             'success': True
         }
@@ -1285,10 +1285,10 @@
 
         id_, params = _build_data(self.apikey, 'revoke_users_group_permission',
                                   repoid=self.REPO,
-                                  usersgroupid=TEST_USERS_GROUP,)
+                                  usersgroupid=TEST_USER_GROUP,)
         response = api_call(self, params)
 
-        expected = 'failed to edit permission for users group: `%s` in repo: `%s`' % (
-                    TEST_USERS_GROUP, self.REPO
+        expected = 'failed to edit permission for user group: `%s` in repo: `%s`' % (
+                    TEST_USER_GROUP, self.REPO
                 )
         self._compare_error(id_, expected, given=response.body)
--- a/rhodecode/tests/functional/test_admin_users_groups.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/tests/functional/test_admin_users_groups.py	Mon Mar 04 18:42:14 2013 +0100
@@ -1,7 +1,7 @@
 from rhodecode.tests import *
-from rhodecode.model.db import UsersGroup, UsersGroupToPerm, Permission
+from rhodecode.model.db import UserGroup, UserGroupToPerm, Permission
 
-TEST_USERS_GROUP = 'admins_test'
+TEST_USER_GROUP = 'admins_test'
 
 
 class TestAdminUsersGroupsController(TestController):
@@ -15,14 +15,14 @@
 
     def test_create(self):
         self.log_user()
-        users_group_name = TEST_USERS_GROUP
+        users_group_name = TEST_USER_GROUP
         response = self.app.post(url('users_groups'),
                                  {'users_group_name': users_group_name,
                                   'active':True})
         response.follow()
 
         self.checkSessionFlash(response,
-                               'created users group %s' % TEST_USERS_GROUP)
+                               'created user group %s' % TEST_USER_GROUP)
 
     def test_new(self):
         response = self.app.get(url('new_users_group'))
@@ -39,50 +39,50 @@
 
     def test_delete(self):
         self.log_user()
-        users_group_name = TEST_USERS_GROUP + 'another'
+        users_group_name = TEST_USER_GROUP + 'another'
         response = self.app.post(url('users_groups'),
                                  {'users_group_name':users_group_name,
                                   'active':True})
         response.follow()
 
         self.checkSessionFlash(response,
-                               'created users group %s' % users_group_name)
+                               'created user group %s' % users_group_name)
 
-        gr = self.Session.query(UsersGroup)\
-                           .filter(UsersGroup.users_group_name ==
+        gr = self.Session.query(UserGroup)\
+                           .filter(UserGroup.users_group_name ==
                                    users_group_name).one()
 
         response = self.app.delete(url('users_group', id=gr.users_group_id))
 
-        gr = self.Session.query(UsersGroup)\
-                           .filter(UsersGroup.users_group_name ==
+        gr = self.Session.query(UserGroup)\
+                           .filter(UserGroup.users_group_name ==
                                    users_group_name).scalar()
 
         self.assertEqual(gr, None)
 
     def test_enable_repository_read_on_group(self):
         self.log_user()
-        users_group_name = TEST_USERS_GROUP + 'another2'
+        users_group_name = TEST_USER_GROUP + 'another2'
         response = self.app.post(url('users_groups'),
                                  {'users_group_name': users_group_name,
                                   'active': True})
         response.follow()
 
-        ug = UsersGroup.get_by_group_name(users_group_name)
+        ug = UserGroup.get_by_group_name(users_group_name)
         self.checkSessionFlash(response,
-                               'created users group %s' % users_group_name)
+                               'created user group %s' % users_group_name)
         ## ENABLE REPO CREATE ON A GROUP
         response = self.app.put(url('users_group_perm', id=ug.users_group_id),
                                  {'create_repo_perm': True})
 
         response.follow()
-        ug = UsersGroup.get_by_group_name(users_group_name)
+        ug = UserGroup.get_by_group_name(users_group_name)
         p = Permission.get_by_key('hg.create.repository')
         p2 = Permission.get_by_key('hg.fork.none')
         # check if user has this perms, they should be here since
         # defaults are on
-        perms = UsersGroupToPerm.query()\
-            .filter(UsersGroupToPerm.users_group == ug).all()
+        perms = UserGroupToPerm.query()\
+            .filter(UserGroupToPerm.users_group == ug).all()
 
         self.assertEqual(
             [[x.users_group_id, x.permission_id, ] for x in perms],
@@ -95,13 +95,13 @@
                                     {})
 
         response.follow()
-        ug = UsersGroup.get_by_group_name(users_group_name)
+        ug = UserGroup.get_by_group_name(users_group_name)
         p = Permission.get_by_key('hg.create.none')
         p2 = Permission.get_by_key('hg.fork.none')
         # check if user has this perms, they should be here since
         # defaults are on
-        perms = UsersGroupToPerm.query()\
-            .filter(UsersGroupToPerm.users_group == ug).all()
+        perms = UserGroupToPerm.query()\
+            .filter(UserGroupToPerm.users_group == ug).all()
 
         self.assertEqual(
             sorted([[x.users_group_id, x.permission_id, ] for x in perms]),
@@ -110,18 +110,18 @@
         )
 
         # DELETE !
-        ug = UsersGroup.get_by_group_name(users_group_name)
+        ug = UserGroup.get_by_group_name(users_group_name)
         ugid = ug.users_group_id
         response = self.app.delete(url('users_group', id=ug.users_group_id))
         response = response.follow()
-        gr = self.Session.query(UsersGroup)\
-                           .filter(UsersGroup.users_group_name ==
+        gr = self.Session.query(UserGroup)\
+                           .filter(UserGroup.users_group_name ==
                                    users_group_name).scalar()
 
         self.assertEqual(gr, None)
         p = Permission.get_by_key('hg.create.repository')
-        perms = UsersGroupToPerm.query()\
-            .filter(UsersGroupToPerm.users_group_id == ugid).all()
+        perms = UserGroupToPerm.query()\
+            .filter(UserGroupToPerm.users_group_id == ugid).all()
         perms = [[x.users_group_id,
                   x.permission_id, ] for x in perms]
         self.assertEqual(
@@ -131,27 +131,27 @@
 
     def test_enable_repository_fork_on_group(self):
         self.log_user()
-        users_group_name = TEST_USERS_GROUP + 'another2'
+        users_group_name = TEST_USER_GROUP + 'another2'
         response = self.app.post(url('users_groups'),
                                  {'users_group_name': users_group_name,
                                   'active': True})
         response.follow()
 
-        ug = UsersGroup.get_by_group_name(users_group_name)
+        ug = UserGroup.get_by_group_name(users_group_name)
         self.checkSessionFlash(response,
-                               'created users group %s' % users_group_name)
+                               'created user group %s' % users_group_name)
         ## ENABLE REPO CREATE ON A GROUP
         response = self.app.put(url('users_group_perm', id=ug.users_group_id),
                                  {'fork_repo_perm': True})
 
         response.follow()
-        ug = UsersGroup.get_by_group_name(users_group_name)
+        ug = UserGroup.get_by_group_name(users_group_name)
         p = Permission.get_by_key('hg.create.none')
         p2 = Permission.get_by_key('hg.fork.repository')
         # check if user has this perms, they should be here since
         # defaults are on
-        perms = UsersGroupToPerm.query()\
-            .filter(UsersGroupToPerm.users_group == ug).all()
+        perms = UserGroupToPerm.query()\
+            .filter(UserGroupToPerm.users_group == ug).all()
 
         self.assertEqual(
             [[x.users_group_id, x.permission_id, ] for x in perms],
@@ -164,13 +164,13 @@
                                     {})
 
         response.follow()
-        ug = UsersGroup.get_by_group_name(users_group_name)
+        ug = UserGroup.get_by_group_name(users_group_name)
         p = Permission.get_by_key('hg.create.none')
         p2 = Permission.get_by_key('hg.fork.none')
         # check if user has this perms, they should be here since
         # defaults are on
-        perms = UsersGroupToPerm.query()\
-            .filter(UsersGroupToPerm.users_group == ug).all()
+        perms = UserGroupToPerm.query()\
+            .filter(UserGroupToPerm.users_group == ug).all()
 
         self.assertEqual(
             [[x.users_group_id, x.permission_id, ] for x in perms],
@@ -179,18 +179,18 @@
         )
 
         # DELETE !
-        ug = UsersGroup.get_by_group_name(users_group_name)
+        ug = UserGroup.get_by_group_name(users_group_name)
         ugid = ug.users_group_id
         response = self.app.delete(url('users_group', id=ug.users_group_id))
         response = response.follow()
-        gr = self.Session.query(UsersGroup)\
-                           .filter(UsersGroup.users_group_name ==
+        gr = self.Session.query(UserGroup)\
+                           .filter(UserGroup.users_group_name ==
                                    users_group_name).scalar()
 
         self.assertEqual(gr, None)
         p = Permission.get_by_key('hg.fork.repository')
-        perms = UsersGroupToPerm.query()\
-            .filter(UsersGroupToPerm.users_group_id == ugid).all()
+        perms = UserGroupToPerm.query()\
+            .filter(UserGroupToPerm.users_group_id == ugid).all()
         perms = [[x.users_group_id,
                   x.permission_id, ] for x in perms]
         self.assertEqual(
--- a/rhodecode/tests/functional/test_compare.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/tests/functional/test_compare.py	Mon Mar 04 18:42:14 2013 +0100
@@ -120,7 +120,7 @@
         ## files
         response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s#C--826e8142e6ba">file1</a>""" % (repo1.repo_name, rev2, rev1, repo2.repo_name))
         #swap
-        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?as_form=None&amp;other_repo=%s">[swap]</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
+        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s">[swap]</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
 
     def test_compare_forks_on_branch_extra_commits_origin_has_incomming_hg(self):
         self.log_user()
@@ -173,7 +173,7 @@
         ## files
         response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s#C--826e8142e6ba">file1</a>""" % (repo1.repo_name, rev2, rev1, repo2.repo_name))
         #swap
-        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?as_form=None&amp;other_repo=%s">[swap]</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
+        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s">[swap]</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
 
     def test_compare_cherry_pick_changesets_from_bottom(self):
 
--- a/rhodecode/tests/functional/test_repos_groups.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/tests/functional/test_repos_groups.py	Mon Mar 04 18:42:14 2013 +0100
@@ -6,7 +6,7 @@
     def test_index(self):
         self.log_user()
         response = self.app.get(url('repos_groups'))
-        response.mustcontain('There are no repositories groups yet')
+        response.mustcontain('There are no repository groups yet')
 
 #    def test_index_as_xml(self):
 #        response = self.app.get(url('formatted_repos_groups', format='xml'))
--- a/rhodecode/tests/models/test_permissions.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/tests/models/test_permissions.py	Mon Mar 04 18:42:14 2013 +0100
@@ -4,11 +4,11 @@
 from rhodecode.tests.models.common import _make_group
 from rhodecode.model.repos_group import ReposGroupModel
 from rhodecode.model.repo import RepoModel
-from rhodecode.model.db import RepoGroup, User, UsersGroupRepoGroupToPerm
+from rhodecode.model.db import RepoGroup, User, UserGroupRepoGroupToPerm
 from rhodecode.model.user import UserModel
 
 from rhodecode.model.meta import Session
-from rhodecode.model.users_group import UsersGroupModel
+from rhodecode.model.users_group import UserGroupModel
 from rhodecode.lib.auth import AuthUser
 from rhodecode.tests.api.api_base import create_repo
 
@@ -51,7 +51,7 @@
             ReposGroupModel().delete(self.g2.group_id)
 
         if hasattr(self, 'ug1'):
-            UsersGroupModel().delete(self.ug1, force=True)
+            UserGroupModel().delete(self.ug1, force=True)
 
         Session().commit()
 
@@ -124,10 +124,10 @@
 
     def test_propagated_permission_from_users_group_by_explicit_perms_exist(self):
         # make group
-        self.ug1 = UsersGroupModel().create('G1')
+        self.ug1 = UserGroupModel().create('G1')
         # add user to group
 
-        UsersGroupModel().add_user_to_group(self.ug1, self.u1)
+        UserGroupModel().add_user_to_group(self.ug1, self.u1)
 
         # set permission to lower
         new_perm = 'repository.none'
@@ -158,10 +158,10 @@
 
     def test_propagated_permission_from_users_group(self):
         # make group
-        self.ug1 = UsersGroupModel().create('G1')
+        self.ug1 = UserGroupModel().create('G1')
         # add user to group
 
-        UsersGroupModel().add_user_to_group(self.ug1, self.u3)
+        UserGroupModel().add_user_to_group(self.ug1, self.u3)
 
         # grant perm for group this should override default permission from user
         new_perm_gr = 'repository.write'
@@ -183,9 +183,9 @@
 
     def test_propagated_permission_from_users_group_lower_weight(self):
         # make group
-        self.ug1 = UsersGroupModel().create('G1')
+        self.ug1 = UserGroupModel().create('G1')
         # add user to group
-        UsersGroupModel().add_user_to_group(self.ug1, self.u1)
+        UserGroupModel().add_user_to_group(self.ug1, self.u1)
 
         # set permission to lower
         new_perm_h = 'repository.write'
@@ -299,13 +299,13 @@
                                                 user=self.anon,
                                                 perm='group.none')
         # make group
-        self.ug1 = UsersGroupModel().create('G1')
+        self.ug1 = UserGroupModel().create('G1')
         # add user to group
-        UsersGroupModel().add_user_to_group(self.ug1, self.u1)
+        UserGroupModel().add_user_to_group(self.ug1, self.u1)
         Session().commit()
 
         # check if user is in the group
-        membrs = [x.user_id for x in UsersGroupModel().get(self.ug1.users_group_id).members]
+        membrs = [x.user_id for x in UserGroupModel().get(self.ug1.users_group_id).members]
         self.assertEqual(membrs, [self.u1.user_id])
         # add some user to that group
 
@@ -324,9 +324,9 @@
                                                        perm='group.read')
         Session().commit()
         # check if the
-        obj = Session().query(UsersGroupRepoGroupToPerm)\
-            .filter(UsersGroupRepoGroupToPerm.group == self.g1)\
-            .filter(UsersGroupRepoGroupToPerm.users_group == self.ug1)\
+        obj = Session().query(UserGroupRepoGroupToPerm)\
+            .filter(UserGroupRepoGroupToPerm.group == self.g1)\
+            .filter(UserGroupRepoGroupToPerm.users_group == self.ug1)\
             .scalar()
         self.assertEqual(obj.permission.permission_name, 'group.read')
 
@@ -439,10 +439,10 @@
         u1_auth = AuthUser(user_id=self.u1.user_id)
         self.assertEqual(u1_auth.permissions['repositories']['myownrepo'],
                          'repository.admin')
-        #set his permission as users group, he should still be admin
-        self.ug1 = UsersGroupModel().create('G1')
+        #set his permission as user group, he should still be admin
+        self.ug1 = UserGroupModel().create('G1')
         # add user to group
-        UsersGroupModel().add_user_to_group(self.ug1, self.u1)
+        UserGroupModel().add_user_to_group(self.ug1, self.u1)
         RepoModel().grant_users_group_permission(repo, group_name=self.ug1,
                                                  perm='repository.none')
 
--- a/rhodecode/tests/models/test_users.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/tests/models/test_users.py	Mon Mar 04 18:42:14 2013 +0100
@@ -1,12 +1,12 @@
 import unittest
 from rhodecode.tests import *
 
-from rhodecode.model.db import User, UsersGroup, UsersGroupMember, UserEmailMap,\
+from rhodecode.model.db import User, UserGroup, UserGroupMember, UserEmailMap,\
     Permission
 from rhodecode.model.user import UserModel
 
 from rhodecode.model.meta import Session
-from rhodecode.model.users_group import UsersGroupModel
+from rhodecode.model.users_group import UserGroupModel
 
 
 class TestUser(unittest.TestCase):
@@ -22,19 +22,19 @@
         Session().commit()
         self.assertEqual(User.get_by_username(u'test_user'), usr)
 
-        # make users group
-        users_group = UsersGroupModel().create('some_example_group')
+        # make user group
+        users_group = UserGroupModel().create('some_example_group')
         Session().commit()
 
-        UsersGroupModel().add_user_to_group(users_group, usr)
+        UserGroupModel().add_user_to_group(users_group, usr)
         Session().commit()
 
-        self.assertEqual(UsersGroup.get(users_group.users_group_id), users_group)
-        self.assertEqual(UsersGroupMember.query().count(), 1)
+        self.assertEqual(UserGroup.get(users_group.users_group_id), users_group)
+        self.assertEqual(UserGroupMember.query().count(), 1)
         UserModel().delete(usr.user_id)
         Session().commit()
 
-        self.assertEqual(UsersGroupMember.query().all(), [])
+        self.assertEqual(UserGroupMember.query().all(), [])
 
     def test_additonal_email_as_main(self):
         usr = UserModel().create_or_update(username=u'test_user',
--- a/rhodecode/tests/models/test_users_group_permissions_on_groups.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/tests/models/test_users_group_permissions_on_groups.py	Mon Mar 04 18:42:14 2013 +0100
@@ -10,7 +10,7 @@
 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 UsersGroupModel
+from rhodecode.model.users_group import UserGroupModel
 from rhodecode.model.repo import RepoModel
 
 
@@ -40,10 +40,10 @@
     Session().commit()
     test_u2_id = test_u2.user_id
 
-    gr1 = UsersGroupModel().create(name='perms_group_1')
+    gr1 = UserGroupModel().create(name='perms_group_1')
     Session().commit()
     test_u2_gr_id = gr1.users_group_id
-    UsersGroupModel().add_user_to_group(gr1, user=test_u2_id)
+    UserGroupModel().add_user_to_group(gr1, user=test_u2_id)
     Session().commit()
 
     _get_repo_perms = functools.partial(_get_perms, key='repositories',
--- a/rhodecode/tests/test_libs.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/tests/test_libs.py	Mon Mar 04 18:42:14 2013 +0100
@@ -209,6 +209,21 @@
                 grav = gravatar_url(email_address=em, size=24)
                 assert grav == 'https://server.com/%s/%s' % (_md5(em), 24)
 
+    def _quick_url(self, text, tmpl="""<a class="revision-link" href="%s">%s</a>""", url_=None):
+        """
+        Changes `some text url[foo]` => `some text <a href="/">foo</a>
+
+        :param text:
+        """
+        import re
+        #quickly change expected url[] into a link
+        URL_PAT = re.compile(r'(?:url\[)(.+?)(?:\])')
+
+        def url_func(match_obj):
+            _url = match_obj.groups()[0]
+            return tmpl % (url_ or '/some-url', _url)
+        return URL_PAT.sub(url_func, text)
+
     @parameterized.expand([
       ("",
        ""),
@@ -228,27 +243,48 @@
        "url[ffffffffffff] some text traalaa"),
        ("""Multi line
        123123123123
-       some text 123123123123""",
+       some text 123123123123
+       sometimes !
+       """,
        """Multi line
        url[123123123123]
-       some text url[123123123123]""")
+       some text url[123123123123]
+       sometimes !
+       """)
     ])
     def test_urlify_changesets(self, sample, expected):
-        import re
-
         def fake_url(self, *args, **kwargs):
             return '/some-url'
 
-        #quickly change expected url[] into a link
-        URL_PAT = re.compile(r'(?:url\[)(.+?)(?:\])')
-
-        def url_func(match_obj):
-            _url = match_obj.groups()[0]
-            tmpl = """<a class="revision-link" href="/some-url">%s</a>"""
-            return tmpl % _url
-
-        expected = URL_PAT.sub(url_func, expected)
+        expected = self._quick_url(expected)
 
         with mock.patch('pylons.url', fake_url):
             from rhodecode.lib.helpers import urlify_changesets
             self.assertEqual(urlify_changesets(sample, 'repo_name'), expected)
+
+    @parameterized.expand([
+      ("",
+       "",
+       ""),
+      ("https://svn.apache.org/repos",
+       "url[https://svn.apache.org/repos]",
+       "https://svn.apache.org/repos"),
+      ("http://svn.apache.org/repos",
+       "url[http://svn.apache.org/repos]",
+       "http://svn.apache.org/repos"),
+      ("from rev a also rev http://google.com",
+       "from rev a also rev url[http://google.com]",
+       "http://google.com"),
+       ("""Multi line
+       https://foo.bar.com
+       some text lalala""",
+       """Multi line
+       url[https://foo.bar.com]
+       some text lalala""",
+       "https://foo.bar.com")
+    ])
+    def test_urlify_test(self, sample, expected, url_):
+        from rhodecode.lib.helpers import urlify_text
+        expected = self._quick_url(expected,
+                                   tmpl="""<a href="%s">%s</a>""", url_=url_)
+        self.assertEqual(urlify_text(sample), expected)
--- a/rhodecode/tests/test_validators.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/rhodecode/tests/test_validators.py	Mon Mar 04 18:42:14 2013 +0100
@@ -5,7 +5,7 @@
 from rhodecode.tests import *
 
 from rhodecode.model import validators as v
-from rhodecode.model.users_group import UsersGroupModel
+from rhodecode.model.users_group import UserGroupModel
 
 from rhodecode.model.meta import Session
 from rhodecode.model.repos_group import ReposGroupModel
@@ -51,25 +51,25 @@
         self.assertEqual(TEST_USER_ADMIN_LOGIN,
                          validator.to_python(TEST_USER_ADMIN_LOGIN))
 
-    def test_ValidUsersGroup(self):
-        validator = v.ValidUsersGroup()
+    def test_ValidUserGroup(self):
+        validator = v.ValidUserGroup()
         self.assertRaises(formencode.Invalid, validator.to_python, 'default')
         self.assertRaises(formencode.Invalid, validator.to_python, '.,')
 
-        gr = UsersGroupModel().create('test')
-        gr2 = UsersGroupModel().create('tes2')
+        gr = UserGroupModel().create('test')
+        gr2 = UserGroupModel().create('tes2')
         Session.commit()
         self.assertRaises(formencode.Invalid, validator.to_python, 'test')
         assert gr.users_group_id != None
-        validator = v.ValidUsersGroup(edit=True,
+        validator = v.ValidUserGroup(edit=True,
                                     old_data={'users_group_id':
                                               gr2.users_group_id})
 
         self.assertRaises(formencode.Invalid, validator.to_python, 'test')
         self.assertRaises(formencode.Invalid, validator.to_python, 'TesT')
         self.assertRaises(formencode.Invalid, validator.to_python, 'TEST')
-        UsersGroupModel().delete(gr)
-        UsersGroupModel().delete(gr2)
+        UserGroupModel().delete(gr)
+        UserGroupModel().delete(gr2)
         Session.commit()
 
     def test_ValidReposGroup(self):
--- a/setup.py	Mon Mar 04 18:30:50 2013 +0100
+++ b/setup.py	Mon Mar 04 18:42:14 2013 +0100
@@ -35,11 +35,12 @@
 requirements = [
     "waitress==0.8.2",
     "webob==1.0.8",
+    "webtest==1.4.3",
     "Pylons==1.0.0",
     "Beaker==1.6.4",
     "WebHelpers==1.3",
     "formencode==1.2.4",
-    "SQLAlchemy==0.7.9",
+    "SQLAlchemy==0.7.10",
     "Mako==0.7.3",
     "pygments>=1.5",
     "whoosh>=2.4.0,<2.5",