From: tilly-Q Date: Thu, 3 Oct 2013 20:13:12 +0000 (-0400) Subject: In this commit, I mostly did work on the migrations. Firstly, I droppped the X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=9519c0a91f6c67883d62b656c971cc10e47ea967;p=mediagoblin.git In this commit, I mostly did work on the migrations. Firstly, I droppped the vestigial columns from the User table (ie. status, email_verified, is_admin). Otherwise, I did a lot of work converting my existing migrations from high- level ORM commands to low-level SQL commands to ensure that the migrating will work regardless of what stage their instance is working in. I also re-integrated my two registered migrations into one. Because the migration became very long, I also added a lot of clarifying documentation. --- diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index 54b4adb4..6e644c3a 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -29,7 +29,7 @@ from migrate.changeset.constraint import UniqueConstraint from mediagoblin.db.extratypes import JSONEncoded from mediagoblin.db.migration_tools import RegisterMigration, inspect_table from mediagoblin.db.models import (MediaEntry, Collection, User, - MediaComment, Privilege, FOUNDATIONS) + MediaComment, Privilege) MIGRATIONS = {} @@ -518,7 +518,7 @@ class Privilege_v0(declarative_base()): class PrivilegeUserAssociation_v0(declarative_base()): __tablename__ = 'core__privileges_users' - group_id = Column( + privilege_id = Column( 'core__privilege_id', Integer, ForeignKey(User.id), @@ -529,8 +529,32 @@ class PrivilegeUserAssociation_v0(declarative_base()): ForeignKey(Privilege.id), primary_key=True) -@RegisterMigration(16, MIGRATIONS) +PRIVILEGE_FOUNDATIONS_v0 = [{'privilege_name':u'admin'}, + {'privilege_name':u'moderator'}, + {'privilege_name':u'uploader'}, + {'privilege_name':u'reporter'}, + {'privilege_name':u'commenter'}, + {'privilege_name':u'active'}] + + +class User_vR1(declarative_base()): + __tablename__ = 'rename__users' + id = Column(Integer, primary_key=True) + username = Column(Unicode, nullable=False, unique=True) + email = Column(Unicode, nullable=False) + pw_hash = Column(Unicode) + created = Column(DateTime, nullable=False, default=datetime.datetime.now) + wants_comment_notification = Column(Boolean, default=True) + wants_notifications = Column(Boolean, default=True) + license_preference = Column(Unicode) + url = Column(Unicode) + bio = Column(UnicodeText) # ?? + +@RegisterMigration(18, MIGRATIONS) def create_moderation_tables(db): + + # First, we will create the new tables in the database. + #-------------------------------------------------------------------------- ReportBase_v0.__table__.create(db.bind) CommentReport_v0.__table__.create(db.bind) MediaReport_v0.__table__.create(db.bind) @@ -540,46 +564,109 @@ def create_moderation_tables(db): db.commit() - for parameters in FOUNDATIONS[Privilege]: - p = Privilege(**parameters) - p.save() - - -@RegisterMigration(17, MIGRATIONS) -def update_user_privilege_columns(db): - # first, create the privileges which would be created by foundations - default_privileges = Privilege.query.filter( - Privilege.privilege_name !=u'admin').filter( - Privilege.privilege_name !=u'moderator').filter( - Privilege.privilege_name !=u'active').all() - admin_privilege = Privilege.query.filter( - Privilege.privilege_name ==u'admin').first() - active_privilege = Privilege.query.filter( - Privilege.privilege_name ==u'active').first() - # then, assign them to the appropriate users - for inactive_user in User.query.filter( - User.status!=u'active').filter( - User.is_admin==False).all(): - - inactive_user.all_privileges = default_privileges - inactive_user.save() - for user in User.query.filter( - User.status==u'active').filter( - User.is_admin==False).all(): - - user.all_privileges = default_privileges + [active_privilege] - user.save() - for admin_user in User.query.filter( - User.is_admin==True).all(): - - admin_user.all_privileges = default_privileges + [ - admin_privilege, active_privilege] - admin_user.save() - - # and then drop the now vestigial status column + # Then initialize the tables that we will later use + #-------------------------------------------------------------------------- metadata = MetaData(bind=db.bind) + privileges_table= inspect_table(metadata, "core__privileges") user_table = inspect_table(metadata, 'core__users') - status = user_table.columns['status'] - status.drop() + user_privilege_assoc = inspect_table( + metadata, 'core__privileges_users') + + # This section initializes the default Privilege foundations, that + # would be created through the FOUNDATIONS system in a new instance + #-------------------------------------------------------------------------- + for parameters in PRIVILEGE_FOUNDATIONS_v0: + db.execute(privileges_table.insert().values(**parameters)) + db.commit() + # This next section takes the information from the old is_admin and status + # columns and converts those to the new privilege system + #-------------------------------------------------------------------------- + admin_users_ids, active_users_ids, inactive_users_ids = ( + db.execute( + user_table.select().where( + user_table.c.is_admin==1)).fetchall(), + db.execute( + user_table.select().where( + user_table.c.is_admin==0).where( + user_table.c.status==u"active")).fetchall(), + db.execute( + user_table.select().where( + user_table.c.is_admin==0).where( + user_table.c.status!=u"active")).fetchall()) + + # Get the ids for each of the privileges so we can reference them ~~~~~~~~~ + (admin_privilege_id, uploader_privilege_id, + reporter_privilege_id, commenter_privilege_id, + active_privilege_id) = [ + db.execute(privileges_table.select().where( + privileges_table.c.privilege_name==privilege_name)).first()['id'] + for privilege_name in + [u"admin",u"uploader",u"reporter",u"commenter",u"active"] + ] + + # Give each user the appopriate privileges depending whether they are an + # admin, an active user or an inactivated user ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + for admin_user in admin_users_ids: + admin_user_id = admin_user['id'] + for privilege_id in [admin_privilege_id, uploader_privilege_id, reporter_privilege_id, commenter_privilege_id, active_privilege_id]: + db.execute(user_privilege_assoc.insert().values( + core__privilege_id=admin_user_id, + core__user_id=privilege_id)) + + for active_user in active_users_ids: + active_user_id = active_user['id'] + for privilege_id in [uploader_privilege_id, reporter_privilege_id, commenter_privilege_id, active_privilege_id]: + db.execute(user_privilege_assoc.insert().values( + core__privilege_id=active_user_id, + core__user_id=privilege_id)) + + for inactive_user in inactive_users_ids: + inactive_user_id = inactive_user['id'] + for privilege_id in [uploader_privilege_id, reporter_privilege_id, commenter_privilege_id]: + db.execute(user_privilege_assoc.insert().values( + core__privilege_id=inactive_user_id, + core__user_id=privilege_id)) + + db.commit() + + # And then, once the information is taken from the is_admin & status columns + # we drop all of the vestigial columns from the User table. + #-------------------------------------------------------------------------- + if db.bind.url.drivername == 'sqlite': + # SQLite has some issues that make it *impossible* to drop boolean + # columns. So, the following code is a very hacky workaround which + # makes it possible. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + User_vR1.__table__.create(db.bind) + db.commit() + new_user_table = inspect_table(metadata, 'rename__users') + for row in db.execute(user_table.select()): + db.execute(new_user_table.insert().values( + username=row.username, + email=row.email, + pw_hash=row.pw_hash, + created=row.created, + wants_comment_notification=row.wants_comment_notification, + wants_notifications=row.wants_notifications, + license_preference=row.license_preference, + url=row.url, + bio=row.bio)) + + db.commit() + user_table.drop() + + db.commit() + new_user_table.rename("core__users") + else: + # If the db is not SQLite, this process is much simpler ~~~~~~~~~~~~~~~ + + status = user_table.columns['status'] + email_verified = user_table.columns['email_verified'] + is_admin = user_table.columns['is_admin'] + status.drop() + email_verified.drop() + is_admin.drop() + + db.commit() diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 466f31b8..5173be9e 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -63,18 +63,12 @@ class User(Base, UserMixin): # point. email = Column(Unicode, nullable=False) pw_hash = Column(Unicode) -#--column email_verified is VESTIGIAL with privileges and should not be used--- -#--should be dropped ASAP though a bug in sqlite3 prevents this atm------------ - email_verified = Column(Boolean, default=False) created = Column(DateTime, nullable=False, default=datetime.datetime.now) # Intented to be nullable=False, but migrations would not work for it # set to nullable=True implicitly. wants_comment_notification = Column(Boolean, default=True) wants_notifications = Column(Boolean, default=True) license_preference = Column(Unicode) -#--column admin is VESTIGIAL with privileges and should not be used------------ -#--should be dropped ASAP though a bug in sqlite3 prevents this atm------------ - is_admin = Column(Boolean, default=False, nullable=False) url = Column(Unicode) bio = Column(UnicodeText) # ??