changeset 2000:72c525a7e7ad beta

added migrations from 1.2.X to 1.3
author Marcin Kuzminski <marcin@python-works.com>
date Sun, 19 Feb 2012 17:41:07 +0200
parents 6b474c01ba98
children 93d4e3eb7d84
files rhodecode/__init__.py rhodecode/lib/auth.py rhodecode/lib/db_manage.py rhodecode/lib/dbmigrate/migrate/changeset/ansisql.py rhodecode/lib/dbmigrate/migrate/changeset/constraint.py rhodecode/lib/dbmigrate/migrate/changeset/databases/firebird.py rhodecode/lib/dbmigrate/migrate/changeset/databases/mysql.py rhodecode/lib/dbmigrate/migrate/changeset/databases/postgres.py rhodecode/lib/dbmigrate/migrate/changeset/databases/sqlite.py rhodecode/lib/dbmigrate/migrate/changeset/schema.py rhodecode/lib/dbmigrate/migrate/versioning/schemadiff.py rhodecode/lib/dbmigrate/migrate/versioning/util/__init__.py rhodecode/lib/dbmigrate/schema/db_1_2_0.py rhodecode/lib/dbmigrate/schema/db_1_3_0.py rhodecode/lib/dbmigrate/versions/002_version_1_1_0.py rhodecode/lib/dbmigrate/versions/003_version_1_2_0.py rhodecode/lib/dbmigrate/versions/004_version_1_3_0.py rhodecode/lib/dbmigrate/versions/005_version_1_3_0.py rhodecode/model/db.py
diffstat 19 files changed, 185 insertions(+), 175 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/__init__.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/__init__.py	Sun Feb 19 17:41:07 2012 +0200
@@ -28,7 +28,7 @@
 
 VERSION = (1, 3, 0, 'beta')
 __version__ = '.'.join((str(each) for each in VERSION[:4]))
-__dbversion__ = 4  # defines current db version for migrations
+__dbversion__ = 5  # defines current db version for migrations
 __platform__ = platform.system()
 __license__ = 'GPLv3'
 __py_version__ = sys.version_info
--- a/rhodecode/lib/auth.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/auth.py	Sun Feb 19 17:41:07 2012 +0200
@@ -226,8 +226,8 @@
                  'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
                  'email': get_ldap_attr('ldap_attr_email'),
                 }
-                
-                # don't store LDAP password since we don't need it. Override 
+
+                # don't store LDAP password since we don't need it. Override
                 # with some random generated password
                 _password = PasswordGenerator().gen_password(length=8)
                 # create this user on the fly if it doesn't exist in rhodecode
--- a/rhodecode/lib/db_manage.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/db_manage.py	Sun Feb 19 17:41:07 2012 +0200
@@ -171,10 +171,13 @@
                 self.klass.create_ldap_options(skip_existing=True)
 
             def step_4(self):
-                print ('TODO:')
+                print ('create permissions and fix groups')
                 self.klass.create_permissions()
                 self.klass.fixup_groups()
 
+            def step_5(self):
+                pass
+            
         upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
 
         # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
@@ -182,7 +185,7 @@
             print ('performing upgrade step %s' % step)
             getattr(UpgradeSteps(self), 'step_%s' % step)()
             self.sa.commit()
-            
+
     def fix_repo_paths(self):
         """
         Fixes a old rhodecode version path into new one without a '*'
--- a/rhodecode/lib/dbmigrate/migrate/changeset/ansisql.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/ansisql.py	Sun Feb 19 17:41:07 2012 +0200
@@ -17,23 +17,19 @@
                                Index)
 
 from rhodecode.lib.dbmigrate.migrate import exceptions
-from rhodecode.lib.dbmigrate.migrate.changeset import constraint, SQLA_06
+from rhodecode.lib.dbmigrate.migrate.changeset import constraint
 
-if not SQLA_06:
-    from sqlalchemy.sql.compiler import SchemaGenerator, SchemaDropper
-else:
-    from sqlalchemy.schema import AddConstraint, DropConstraint
-    from sqlalchemy.sql.compiler import DDLCompiler
-    SchemaGenerator = SchemaDropper = DDLCompiler
+from sqlalchemy.schema import AddConstraint, DropConstraint
+from sqlalchemy.sql.compiler import DDLCompiler
+SchemaGenerator = SchemaDropper = DDLCompiler
 
 
 class AlterTableVisitor(SchemaVisitor):
     """Common operations for ``ALTER TABLE`` statements."""
 
-    if SQLA_06:
-        # engine.Compiler looks for .statement
-        # when it spawns off a new compiler
-        statement = ClauseElement()
+    # engine.Compiler looks for .statement
+    # when it spawns off a new compiler
+    statement = ClauseElement()
 
     def append(self, s):
         """Append content to the SchemaIterator's query buffer."""
@@ -123,9 +119,8 @@
                                                    name=column.primary_key_name)
             cons.create()
 
-    if SQLA_06:
-        def add_foreignkey(self, fk):
-            self.connection.execute(AddConstraint(fk))
+    def add_foreignkey(self, fk):
+        self.connection.execute(AddConstraint(fk))
 
 class ANSIColumnDropper(AlterTableVisitor, SchemaDropper):
     """Extends ANSI SQL dropper for column dropping (``ALTER TABLE
@@ -232,10 +227,7 @@
 
     def _visit_column_type(self, table, column, delta):
         type_ = delta['type']
-        if SQLA_06:
-            type_text = str(type_.compile(dialect=self.dialect))
-        else:
-            type_text = type_.dialect_impl(self.dialect).get_col_spec()
+        type_text = str(type_.compile(dialect=self.dialect))
         self.append("TYPE %s" % type_text)
 
     def _visit_column_name(self, table, column, delta):
@@ -279,75 +271,17 @@
     def visit_migrate_unique_constraint(self, *p, **k):
         self._visit_constraint(*p, **k)
 
-if SQLA_06:
-    class ANSIConstraintGenerator(ANSIConstraintCommon, SchemaGenerator):
-        def _visit_constraint(self, constraint):
-            constraint.name = self.get_constraint_name(constraint)
-            self.append(self.process(AddConstraint(constraint)))
-            self.execute()
-
-    class ANSIConstraintDropper(ANSIConstraintCommon, SchemaDropper):
-        def _visit_constraint(self, constraint):
-            constraint.name = self.get_constraint_name(constraint)
-            self.append(self.process(DropConstraint(constraint, cascade=constraint.cascade)))
-            self.execute()
-
-else:
-    class ANSIConstraintGenerator(ANSIConstraintCommon, SchemaGenerator):
-
-        def get_constraint_specification(self, cons, **kwargs):
-            """Constaint SQL generators.
-
-            We cannot use SA visitors because they append comma.
-            """
+class ANSIConstraintGenerator(ANSIConstraintCommon, SchemaGenerator):
+    def _visit_constraint(self, constraint):
+        constraint.name = self.get_constraint_name(constraint)
+        self.append(self.process(AddConstraint(constraint)))
+        self.execute()
 
-            if isinstance(cons, PrimaryKeyConstraint):
-                if cons.name is not None:
-                    self.append("CONSTRAINT %s " % self.preparer.format_constraint(cons))
-                self.append("PRIMARY KEY ")
-                self.append("(%s)" % ', '.join(self.preparer.quote(c.name, c.quote)
-                                               for c in cons))
-                self.define_constraint_deferrability(cons)
-            elif isinstance(cons, ForeignKeyConstraint):
-                self.define_foreign_key(cons)
-            elif isinstance(cons, CheckConstraint):
-                if cons.name is not None:
-                    self.append("CONSTRAINT %s " %
-                                self.preparer.format_constraint(cons))
-                self.append("CHECK (%s)" % cons.sqltext)
-                self.define_constraint_deferrability(cons)
-            elif isinstance(cons, UniqueConstraint):
-                if cons.name is not None:
-                    self.append("CONSTRAINT %s " %
-                                self.preparer.format_constraint(cons))
-                self.append("UNIQUE (%s)" % \
-                    (', '.join(self.preparer.quote(c.name, c.quote) for c in cons)))
-                self.define_constraint_deferrability(cons)
-            else:
-                raise exceptions.InvalidConstraintError(cons)
-
-        def _visit_constraint(self, constraint):
-
-            table = self.start_alter_table(constraint)
-            constraint.name = self.get_constraint_name(constraint)
-            self.append("ADD ")
-            self.get_constraint_specification(constraint)
-            self.execute()
-
-
-    class ANSIConstraintDropper(ANSIConstraintCommon, SchemaDropper):
-
-        def _visit_constraint(self, constraint):
-            self.start_alter_table(constraint)
-            self.append("DROP CONSTRAINT ")
-            constraint.name = self.get_constraint_name(constraint)
-            self.append(self.preparer.format_constraint(constraint))
-            if constraint.cascade:
-                self.cascade_constraint(constraint)
-            self.execute()
-
-        def cascade_constraint(self, constraint):
-            self.append(" CASCADE")
+class ANSIConstraintDropper(ANSIConstraintCommon, SchemaDropper):
+    def _visit_constraint(self, constraint):
+        constraint.name = self.get_constraint_name(constraint)
+        self.append(self.process(DropConstraint(constraint, cascade=constraint.cascade)))
+        self.execute()
 
 
 class ANSIDialect(DefaultDialect):
--- a/rhodecode/lib/dbmigrate/migrate/changeset/constraint.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/constraint.py	Sun Feb 19 17:41:07 2012 +0200
@@ -4,7 +4,7 @@
 from sqlalchemy import schema
 
 from rhodecode.lib.dbmigrate.migrate.exceptions import *
-from rhodecode.lib.dbmigrate.migrate.changeset import SQLA_06
+
 
 class ConstraintChangeset(object):
     """Base class for Constraint classes."""
@@ -85,7 +85,6 @@
         if table is not None:
             self._set_parent(table)
 
-
     def autoname(self):
         """Mimic the database's automatic constraint names"""
         return "%s_pkey" % self.table.name
@@ -111,8 +110,9 @@
         table = kwargs.pop('table', table)
         refcolnames, reftable = self._normalize_columns(refcolumns,
                                                         table_name=True)
-        super(ForeignKeyConstraint, self).__init__(colnames, refcolnames, *args,
-                                                   **kwargs)
+        super(ForeignKeyConstraint, self).__init__(
+            colnames, refcolnames, *args,**kwargs
+        )
         if table is not None:
             self._set_parent(table)
 
@@ -165,8 +165,6 @@
         table = kwargs.pop('table', table)
         schema.CheckConstraint.__init__(self, sqltext, *args, **kwargs)
         if table is not None:
-            if not SQLA_06:
-                self.table = table
             self._set_parent(table)
         self.colnames = colnames
 
@@ -199,4 +197,4 @@
 
     def autoname(self):
         """Mimic the database's automatic constraint names"""
-        return "%s_%s_key" % (self.table.name, self.colnames[0])
+        return "%s_%s_key" % (self.table.name, '_'.join(self.colnames))
--- a/rhodecode/lib/dbmigrate/migrate/changeset/databases/firebird.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/firebird.py	Sun Feb 19 17:41:07 2012 +0200
@@ -4,13 +4,10 @@
 from sqlalchemy.databases import firebird as sa_base
 from sqlalchemy.schema import PrimaryKeyConstraint
 from rhodecode.lib.dbmigrate.migrate import exceptions
-from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
+from rhodecode.lib.dbmigrate.migrate.changeset import ansisql
 
 
-if SQLA_06:
-    FBSchemaGenerator = sa_base.FBDDLCompiler
-else:
-    FBSchemaGenerator = sa_base.FBSchemaGenerator
+FBSchemaGenerator = sa_base.FBDDLCompiler
 
 class FBColumnGenerator(FBSchemaGenerator, ansisql.ANSIColumnGenerator):
     """Firebird column generator implementation."""
@@ -41,10 +38,7 @@
                 # is deleted!
                 continue
 
-            if SQLA_06:
-                should_drop = column.name in cons.columns
-            else:
-                should_drop = cons.contains_column(column) and cons.name
+            should_drop = column.name in cons.columns
             if should_drop:
                 self.start_alter_table(column)
                 self.append("DROP CONSTRAINT ")
--- a/rhodecode/lib/dbmigrate/migrate/changeset/databases/mysql.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/mysql.py	Sun Feb 19 17:41:07 2012 +0200
@@ -6,13 +6,10 @@
 from sqlalchemy import types as sqltypes
 
 from rhodecode.lib.dbmigrate.migrate import exceptions
-from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
+from rhodecode.lib.dbmigrate.migrate.changeset import ansisql
 
 
-if not SQLA_06:
-    MySQLSchemaGenerator = sa_base.MySQLSchemaGenerator
-else:
-    MySQLSchemaGenerator = sa_base.MySQLDDLCompiler
+MySQLSchemaGenerator = sa_base.MySQLDDLCompiler
 
 class MySQLColumnGenerator(MySQLSchemaGenerator, ansisql.ANSIColumnGenerator):
     pass
@@ -53,37 +50,11 @@
 class MySQLConstraintGenerator(ansisql.ANSIConstraintGenerator):
     pass
 
-if SQLA_06:
-    class MySQLConstraintDropper(MySQLSchemaGenerator, ansisql.ANSIConstraintDropper):
-        def visit_migrate_check_constraint(self, *p, **k):
-            raise exceptions.NotSupportedError("MySQL does not support CHECK"
-                " constraints, use triggers instead.")
 
-else:
-    class MySQLConstraintDropper(ansisql.ANSIConstraintDropper):
-
-        def visit_migrate_primary_key_constraint(self, constraint):
-            self.start_alter_table(constraint)
-            self.append("DROP PRIMARY KEY")
-            self.execute()
-
-        def visit_migrate_foreign_key_constraint(self, constraint):
-            self.start_alter_table(constraint)
-            self.append("DROP FOREIGN KEY ")
-            constraint.name = self.get_constraint_name(constraint)
-            self.append(self.preparer.format_constraint(constraint))
-            self.execute()
-
-        def visit_migrate_check_constraint(self, *p, **k):
-            raise exceptions.NotSupportedError("MySQL does not support CHECK"
-                " constraints, use triggers instead.")
-
-        def visit_migrate_unique_constraint(self, constraint, *p, **k):
-            self.start_alter_table(constraint)
-            self.append('DROP INDEX ')
-            constraint.name = self.get_constraint_name(constraint)
-            self.append(self.preparer.format_constraint(constraint))
-            self.execute()
+class MySQLConstraintDropper(MySQLSchemaGenerator, ansisql.ANSIConstraintDropper):
+    def visit_migrate_check_constraint(self, *p, **k):
+        raise exceptions.NotSupportedError("MySQL does not support CHECK"
+            " constraints, use triggers instead.")
 
 
 class MySQLDialect(ansisql.ANSIDialect):
--- a/rhodecode/lib/dbmigrate/migrate/changeset/databases/postgres.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/postgres.py	Sun Feb 19 17:41:07 2012 +0200
@@ -3,14 +3,11 @@
 
    .. _`PostgreSQL`: http://www.postgresql.org/
 """
-from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
+from rhodecode.lib.dbmigrate.migrate.changeset import ansisql
+
 
-if not SQLA_06:
-    from sqlalchemy.databases import postgres as sa_base
-    PGSchemaGenerator = sa_base.PGSchemaGenerator
-else:
-    from sqlalchemy.databases import postgresql as sa_base
-    PGSchemaGenerator = sa_base.PGDDLCompiler
+from sqlalchemy.databases import postgresql as sa_base
+PGSchemaGenerator = sa_base.PGDDLCompiler
 
 
 class PGColumnGenerator(PGSchemaGenerator, ansisql.ANSIColumnGenerator):
--- a/rhodecode/lib/dbmigrate/migrate/changeset/databases/sqlite.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/sqlite.py	Sun Feb 19 17:41:07 2012 +0200
@@ -11,11 +11,8 @@
 from rhodecode.lib.dbmigrate.migrate import exceptions
 from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
 
+SQLiteSchemaGenerator = sa_base.SQLiteDDLCompiler
 
-if not SQLA_06:
-    SQLiteSchemaGenerator = sa_base.SQLiteSchemaGenerator
-else:
-    SQLiteSchemaGenerator = sa_base.SQLiteDDLCompiler
 
 class SQLiteCommon(object):
 
--- a/rhodecode/lib/dbmigrate/migrate/changeset/schema.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/schema.py	Sun Feb 19 17:41:07 2012 +0200
@@ -349,10 +349,7 @@
     def process_column(self, column):
         """Processes default values for column"""
         # XXX: this is a snippet from SA processing of positional parameters
-        if not SQLA_06 and column.args:
-            toinit = list(column.args)
-        else:
-            toinit = list()
+        toinit = list()
 
         if column.server_default is not None:
             if isinstance(column.server_default, sqlalchemy.FetchedValue):
@@ -368,9 +365,6 @@
         if toinit:
             column._init_items(*toinit)
 
-        if not SQLA_06:
-            column.args = []
-
     def _get_table(self):
         return getattr(self, '_table', None)
 
@@ -469,14 +463,18 @@
         self._set_parent(self.metadata)
 
     def _meta_key(self):
+        """Get the meta key for this table."""
         return sqlalchemy.schema._get_table_key(self.name, self.schema)
 
     def deregister(self):
         """Remove this table from its metadata"""
-        key = self._meta_key()
-        meta = self.metadata
-        if key in meta.tables:
-            del meta.tables[key]
+        if SQLA_07:
+            self.metadata._remove_table(self.name, self.schema)
+        else:
+            key = self._meta_key()
+            meta = self.metadata
+            if key in meta.tables:
+                del meta.tables[key]
 
 
 class ChangesetColumn(object):
--- a/rhodecode/lib/dbmigrate/migrate/versioning/schemadiff.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/schemadiff.py	Sun Feb 19 17:41:07 2012 +0200
@@ -39,7 +39,7 @@
     :return: object which will evaluate to :keyword:`True` if there \
       are differences else :keyword:`False`.
     """
-    return SchemaDiff(metadataA, metadataB, excludeTables)
+    return SchemaDiff(metadataA, metadataB, excludeTables=excludeTables)
 
 
 class ColDiff(object):
--- a/rhodecode/lib/dbmigrate/migrate/versioning/util/__init__.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/util/__init__.py	Sun Feb 19 17:41:07 2012 +0200
@@ -158,8 +158,8 @@
         kw['engine'] = engine
         return f(*a, **kw)
     finally:
-        if isinstance(engine, Engine):
-            log.debug('Disposing SQLAlchemy engine %s' % engine)
+        if isinstance(engine, Engine) and engine is not url:
+            log.debug('Disposing SQLAlchemy engine %s', engine)
             engine.dispose()
 
 
--- a/rhodecode/lib/dbmigrate/schema/db_1_2_0.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/schema/db_1_2_0.py	Sun Feb 19 17:41:07 2012 +0200
@@ -927,6 +927,7 @@
 
 class UsersGroupToPerm(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)
--- a/rhodecode/lib/dbmigrate/schema/db_1_3_0.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/schema/db_1_3_0.py	Sun Feb 19 17:41:07 2012 +0200
@@ -22,3 +22,7 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+#TODO: when branch 1.3 is finished replacem with db.py content
+
+from rhodecode.model.db import *
--- a/rhodecode/lib/dbmigrate/versions/002_version_1_1_0.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/versions/002_version_1_1_0.py	Sun Feb 19 17:41:07 2012 +0200
@@ -12,6 +12,7 @@
 
 log = logging.getLogger(__name__)
 
+
 def upgrade(migrate_engine):
     """ Upgrade operations go here.
     Don't create your own engine; bind migrate_engine to your metadata
@@ -44,8 +45,6 @@
                       nullable=True, unique=None, default=None)
     revision.create(tbl)
 
-
-
     #==========================================================================
     # Upgrade of `repositories` table
     #==========================================================================
@@ -80,6 +79,7 @@
 
     return
 
+
 def downgrade(migrate_engine):
     meta = MetaData()
     meta.bind = migrate_engine
--- a/rhodecode/lib/dbmigrate/versions/003_version_1_2_0.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/versions/003_version_1_2_0.py	Sun Feb 19 17:41:07 2012 +0200
@@ -13,6 +13,7 @@
 
 log = logging.getLogger(__name__)
 
+
 def upgrade(migrate_engine):
     """ Upgrade operations go here.
     Don't create your own engine; bind migrate_engine to your metadata
--- a/rhodecode/lib/dbmigrate/versions/004_version_1_3_0.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/lib/dbmigrate/versions/004_version_1_3_0.py	Sun Feb 19 17:41:07 2012 +0200
@@ -13,12 +13,58 @@
 
 log = logging.getLogger(__name__)
 
+
 def upgrade(migrate_engine):
     """ Upgrade operations go here.
     Don't create your own engine; bind migrate_engine to your metadata
     """
+    #==========================================================================
+    # Add table `users_group_repo_group_to_perm`
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UsersGroupRepoGroupToPerm
+    UsersGroupRepoGroupToPerm().__table__.create()
 
+    #==========================================================================
+    # Add table `changeset_comments`
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import  ChangesetComment
+    ChangesetComment().__table__.create()
 
+    #==========================================================================
+    # Add table `notifications`
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import  Notification
+    Notification().__table__.create()
+
+    #==========================================================================
+    # Add table `user_to_notification`
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import  UserNotification
+    UserNotification().__table__.create()
+
+    #==========================================================================
+    # Add unique to table `users_group_to_perm`
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UsersGroupToPerm
+    tbl = UsersGroupToPerm().__table__
+    cons = UniqueConstraint('users_group_id', 'permission_id', table=tbl)
+    cons.create()
+
+    #==========================================================================
+    # Fix unique constrain on table `user_logs`
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UserLog
+    tbl = UserLog().__table__
+    col = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'),
+                 nullable=False, unique=None, default=None)
+    col.alter(nullable=True, table=tbl)
+
+    #==========================================================================
+    # Rename table `group_to_perm` to `user_repo_group_to_perm`
+    #==========================================================================
+    tbl = Table('group_to_perm', MetaData(bind=migrate_engine), autoload=True,
+                    autoload_with=migrate_engine)
+    tbl.rename('user_repo_group_to_perm')
 
     return
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/versions/005_version_1_3_0.py	Sun Feb 19 17:41:07 2012 +0200
@@ -0,0 +1,65 @@
+import logging
+import datetime
+
+from sqlalchemy import *
+from sqlalchemy.exc import DatabaseError
+from sqlalchemy.orm import relation, backref, class_mapper
+from sqlalchemy.orm.session import Session
+
+from rhodecode.lib.dbmigrate.migrate import *
+from rhodecode.lib.dbmigrate.migrate.changeset import *
+
+from rhodecode.model.meta import Base
+
+log = logging.getLogger(__name__)
+
+
+def upgrade(migrate_engine):
+    """ Upgrade operations go here.
+    Don't create your own engine; bind migrate_engine to your metadata
+    """
+
+    #==========================================================================
+    # Change unique constraints of table `repo_to_perm`
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UserRepoToPerm
+    tbl = UserRepoToPerm().__table__
+    new_cons = UniqueConstraint('user_id', 'repository_id', 'permission_id', table=tbl)
+    new_cons.create()
+
+    if migrate_engine.name in ['mysql']:
+        old_cons = UniqueConstraint('user_id', 'repository_id', table=tbl, name="user_id")
+        old_cons.drop()
+    elif migrate_engine.name in ['postgresql']:
+        old_cons = UniqueConstraint('user_id', 'repository_id', table=tbl)
+        old_cons.drop()
+    else:
+        # sqlite doesn't support dropping constraints...
+        print """Please manually drop UniqueConstraint('user_id', 'repository_id')"""
+
+    #==========================================================================
+    # fix uniques of table `user_repo_group_to_perm`
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UserRepoGroupToPerm
+    tbl = UserRepoGroupToPerm().__table__
+    new_cons = UniqueConstraint('group_id', 'permission_id', 'user_id', table=tbl)
+    new_cons.create()
+
+    # fix uniqueConstraints
+    if migrate_engine.name in ['mysql']:
+        #mysql is givinig troubles here...
+        old_cons = UniqueConstraint('group_id', 'permission_id', table=tbl, name="group_id")
+        old_cons.drop()
+    elif migrate_engine.name in ['postgresql']:
+        old_cons = UniqueConstraint('group_id', 'permission_id', table=tbl, name='group_to_perm_group_id_permission_id_key')
+        old_cons.drop()
+    else:
+        # sqlite doesn't support dropping constraints...
+        print """Please manually drop UniqueConstraint('group_id', 'permission_id')"""
+
+    return
+
+
+def downgrade(migrate_engine):
+    meta = MetaData()
+    meta.bind = migrate_engine
--- a/rhodecode/model/db.py	Sun Feb 19 05:15:04 2012 +0200
+++ b/rhodecode/model/db.py	Sun Feb 19 17:41:07 2012 +0200
@@ -40,12 +40,12 @@
 from vcs.utils.lazy import LazyProperty
 
 from rhodecode.lib import str2bool, safe_str, get_changeset_safe, safe_unicode
-from rhodecode.lib.exceptions import UsersGroupsAssignedException
 from rhodecode.lib.compat import json
 from rhodecode.lib.caching_query import FromCache
 
 from rhodecode.model.meta import Base, Session
 
+
 log = logging.getLogger(__name__)
 
 #==============================================================================
@@ -682,6 +682,7 @@
             return
 
         if alias == 'hg':
+
             repo = backend(safe_str(repo_full_path), create=False,
                            baseui=self._ui)
             # skip hidden web repository
@@ -856,7 +857,7 @@
 class UserRepoToPerm(Base, BaseModel):
     __tablename__ = 'repo_to_perm'
     __table_args__ = (
-        UniqueConstraint('user_id', 'repository_id'),
+        UniqueConstraint('user_id', 'repository_id', 'permission_id'),
         {'extend_existing': True}
     )
     repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -865,8 +866,8 @@
     repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 
     user = relationship('User')
+    repository = relationship('Repository')
     permission = relationship('Permission')
-    repository = relationship('Repository')
 
     @classmethod
     def create(cls, user, repository, permission):
@@ -898,7 +899,7 @@
 class UsersGroupRepoToPerm(Base, BaseModel):
     __tablename__ = 'users_group_repo_to_perm'
     __table_args__ = (
-        UniqueConstraint('repository_id', 'users_group_id',),
+        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)
@@ -940,7 +941,7 @@
 class UserRepoGroupToPerm(Base, BaseModel):
     __tablename__ = 'user_repo_group_to_perm'
     __table_args__ = (
-        UniqueConstraint('user_id', 'group_id'),
+        UniqueConstraint('user_id', 'group_id', 'permission_id'),
         {'extend_existing': True}
     )
 
@@ -950,8 +951,8 @@
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
     user = relationship('User')
+    group = relationship('RepoGroup')
     permission = relationship('Permission')
-    group = relationship('RepoGroup')
 
 
 class UsersGroupRepoGroupToPerm(Base, BaseModel):