Merge branch 'master' into joar-skip_transcoding
[mediagoblin.git] / mediagoblin / db / migrations.py
CommitLineData
70b44584 1# GNU MediaGoblin -- federated, autonomous media hosting
b781c3c9 2# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
70b44584
CAW
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU Affero General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Affero General Public License for more details.
13#
14# You should have received a copy of the GNU Affero General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
29fdd3bb
AW
17import datetime
18
88a9662b 19from sqlalchemy import (MetaData, Table, Column, Boolean, SmallInteger,
316e1dfd 20 Integer, Unicode, UnicodeText, DateTime,
0f14c362
E
21 ForeignKey)
22from sqlalchemy.exc import ProgrammingError
316e1dfd 23from sqlalchemy.ext.declarative import declarative_base
ab1f65e6 24from sqlalchemy.sql import and_
0f14c362 25from migrate.changeset.constraint import UniqueConstraint
b781c3c9 26
c130e3ee 27from mediagoblin.db.migration_tools import RegisterMigration, inspect_table
b0c8328e 28from mediagoblin.db.models import MediaEntry, Collection, User
b781c3c9 29
3ea1cf36 30MIGRATIONS = {}
b781c3c9
JK
31
32
33@RegisterMigration(1, MIGRATIONS)
34def ogg_to_webm_audio(db_conn):
35 metadata = MetaData(bind=db_conn.bind)
36
37 file_keynames = Table('core__file_keynames', metadata, autoload=True,
38 autoload_with=db_conn.bind)
39
40 db_conn.execute(
38c6d441 41 file_keynames.update().where(file_keynames.c.name == 'ogg').
b781c3c9
JK
42 values(name='webm_audio')
43 )
b1055401 44 db_conn.commit()
38c6d441
JW
45
46
47@RegisterMigration(2, MIGRATIONS)
48def add_wants_notification_column(db_conn):
49 metadata = MetaData(bind=db_conn.bind)
50
51 users = Table('core__users', metadata, autoload=True,
52 autoload_with=db_conn.bind)
53
54 col = Column('wants_comment_notification', Boolean,
c4869eff 55 default=True, nullable=True)
38c6d441 56 col.create(users, populate_defaults=True)
b1055401 57 db_conn.commit()
64712915
JW
58
59
60@RegisterMigration(3, MIGRATIONS)
61def add_transcoding_progress(db_conn):
62 metadata = MetaData(bind=db_conn.bind)
63
c4466cb4 64 media_entry = inspect_table(metadata, 'core__media_entries')
64712915
JW
65
66 col = Column('transcoding_progress', SmallInteger)
67 col.create(media_entry)
68 db_conn.commit()
be5be115 69
88a9662b 70
316e1dfd
E
71class Collection_v0(declarative_base()):
72 __tablename__ = "core__collections"
73
74 id = Column(Integer, primary_key=True)
75 title = Column(Unicode, nullable=False)
76 slug = Column(Unicode)
77 created = Column(DateTime, nullable=False, default=datetime.datetime.now,
78 index=True)
79 description = Column(UnicodeText)
80 creator = Column(Integer, ForeignKey(User.id), nullable=False)
81 items = Column(Integer, default=0)
82
83class CollectionItem_v0(declarative_base()):
84 __tablename__ = "core__collection_items"
85
86 id = Column(Integer, primary_key=True)
87 media_entry = Column(
88 Integer, ForeignKey(MediaEntry.id), nullable=False, index=True)
89 collection = Column(Integer, ForeignKey(Collection.id), nullable=False)
90 note = Column(UnicodeText, nullable=True)
91 added = Column(DateTime, nullable=False, default=datetime.datetime.now)
92 position = Column(Integer)
93
94 ## This should be activated, normally.
95 ## But this would change the way the next migration used to work.
96 ## So it's commented for now.
0f14c362
E
97 __table_args__ = (
98 UniqueConstraint('collection', 'media_entry'),
99 {})
100
101collectionitem_unique_constraint_done = False
316e1dfd 102
be5be115 103@RegisterMigration(4, MIGRATIONS)
29fdd3bb 104def add_collection_tables(db_conn):
316e1dfd
E
105 Collection_v0.__table__.create(db_conn.bind)
106 CollectionItem_v0.__table__.create(db_conn.bind)
29fdd3bb 107
0f14c362
E
108 global collectionitem_unique_constraint_done
109 collectionitem_unique_constraint_done = True
110
29fdd3bb
AW
111 db_conn.commit()
112
88a9662b 113
29fdd3bb 114@RegisterMigration(5, MIGRATIONS)
59fb87c9 115def add_mediaentry_collected(db_conn):
be5be115
AW
116 metadata = MetaData(bind=db_conn.bind)
117
c4466cb4 118 media_entry = inspect_table(metadata, 'core__media_entries')
be5be115 119
d8984df8 120 col = Column('collected', Integer, default=0)
be5be115
AW
121 col.create(media_entry)
122 db_conn.commit()
5354f954
JW
123
124
316e1dfd
E
125class ProcessingMetaData_v0(declarative_base()):
126 __tablename__ = 'core__processing_metadata'
939d57a0 127
316e1dfd
E
128 id = Column(Integer, primary_key=True)
129 media_entry_id = Column(Integer, ForeignKey(MediaEntry.id), nullable=False,
130 index=True)
131 callback_url = Column(Unicode)
939d57a0 132
316e1dfd
E
133@RegisterMigration(6, MIGRATIONS)
134def create_processing_metadata_table(db):
135 ProcessingMetaData_v0.__table__.create(db.bind)
5354f954 136 db.commit()
0f14c362 137
ea91c183
E
138
139# Okay, problem being:
140# Migration #4 forgot to add the uniqueconstraint for the
141# new tables. While creating the tables from scratch had
142# the constraint enabled.
143#
a64abbb1 144# So we have four situations that should end up at the same
ea91c183
E
145# db layout:
146#
147# 1. Fresh install.
148# Well, easy. Just uses the tables in models.py
149# 2. Fresh install using a git version just before this migration
150# The tables are all there, the unique constraint is also there.
151# This migration should do nothing.
152# But as we can't detect the uniqueconstraint easily,
153# this migration just adds the constraint again.
154# And possibly fails very loud. But ignores the failure.
155# 3. old install, not using git, just releases.
156# This one will get the new tables in #4 (now with constraint!)
157# And this migration is just skipped silently.
158# 4. old install, always on latest git.
159# This one has the tables, but lacks the constraint.
a64abbb1 160# So this migration adds the constraint.
0f14c362
E
161@RegisterMigration(7, MIGRATIONS)
162def fix_CollectionItem_v0_constraint(db_conn):
163 """Add the forgotten Constraint on CollectionItem"""
164
165 global collectionitem_unique_constraint_done
166 if collectionitem_unique_constraint_done:
0f14c362
E
167 # Reset it. Maybe the whole thing gets run again
168 # For a different db?
169 collectionitem_unique_constraint_done = False
170 return
171
172 metadata = MetaData(bind=db_conn.bind)
173
c4466cb4 174 CollectionItem_table = inspect_table(metadata, 'core__collection_items')
0f14c362
E
175
176 constraint = UniqueConstraint('collection', 'media_entry',
177 name='core__collection_items_collection_media_entry_key',
178 table=CollectionItem_table)
179
180 try:
181 constraint.create()
78fd5581
CAW
182 except ProgrammingError:
183 # User probably has an install that was run since the
184 # collection tables were added, so we don't need to run this migration.
185 pass
186
0f14c362 187 db_conn.commit()
dc4dfbde
MH
188
189
190@RegisterMigration(8, MIGRATIONS)
191def add_license_preference(db):
192 metadata = MetaData(bind=db.bind)
193
0c871f81 194 user_table = inspect_table(metadata, 'core__users')
dc4dfbde 195
0c871f81 196 col = Column('license_preference', Unicode)
dc4dfbde
MH
197 col.create(user_table)
198 db.commit()
e66431f4
CAW
199
200
201@RegisterMigration(9, MIGRATIONS)
202def mediaentry_new_slug_era(db):
203 """
204 Update for the new era for media type slugs.
205
206 Entries without slugs now display differently in the url like:
207 /u/cwebber/m/id=251/
208
209 ... because of this, we should back-convert:
210 - entries without slugs should be converted to use the id, if possible, to
211 make old urls still work
212 - slugs with = (or also : which is now also not allowed) to have those
213 stripped out (small possibility of breakage here sadly)
214 """
215 import uuid
216
217 def slug_and_user_combo_exists(slug, uploader):
e66431f4
CAW
218 return db.execute(
219 media_table.select(
ab1f65e6 220 and_(media_table.c.uploader==uploader,
aecd65b7 221 media_table.c.slug==slug))).first() is not None
e66431f4
CAW
222
223 def append_garbage_till_unique(row, new_slug):
224 """
225 Attach junk to this row until it's unique, then save it
226 """
227 if slug_and_user_combo_exists(new_slug, row.uploader):
228 # okay, still no success;
229 # let's whack junk on there till it's unique.
230 new_slug += '-' + uuid.uuid4().hex[:4]
231 # keep going if necessary!
232 while slug_and_user_combo_exists(new_slug, row.uploader):
233 new_slug += uuid.uuid4().hex[:4]
234
235 db.execute(
236 media_table.update(). \
237 where(media_table.c.id==row.id). \
238 values(slug=new_slug))
239
240 metadata = MetaData(bind=db.bind)
241
242 media_table = inspect_table(metadata, 'core__media_entries')
0b7cdb6f 243
e66431f4
CAW
244 for row in db.execute(media_table.select()):
245 # no slug, try setting to an id
246 if not row.slug:
247 append_garbage_till_unique(row, unicode(row.id))
248 # has "=" or ":" in it... we're getting rid of those
249 elif u"=" in row.slug or u":" in row.slug:
250 append_garbage_till_unique(
251 row, row.slug.replace(u"=", u"-").replace(u":", u"-"))
0b7cdb6f
CAW
252
253 db.commit()