diff options
Diffstat (limited to 'mediagoblin/db')
-rw-r--r-- | mediagoblin/db/extratypes.py | 30 | ||||
-rw-r--r-- | mediagoblin/db/migrations.py | 34 | ||||
-rw-r--r-- | mediagoblin/db/models.py | 38 |
3 files changed, 98 insertions, 4 deletions
diff --git a/mediagoblin/db/extratypes.py b/mediagoblin/db/extratypes.py index f2304af0..8e04d58d 100644 --- a/mediagoblin/db/extratypes.py +++ b/mediagoblin/db/extratypes.py @@ -15,6 +15,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. +from sqlalchemy.ext.mutable import Mutable from sqlalchemy.types import TypeDecorator, Unicode, TEXT import json @@ -38,7 +39,7 @@ class PathTupleWithSlashes(TypeDecorator): return value -# The following class and only this one class is in very +# The following two classes and only these two classes is in very # large parts based on example code from sqlalchemy. # # The original copyright notice and license follows: @@ -61,3 +62,30 @@ class JSONEncoded(TypeDecorator): if value is not None: value = json.loads(value) return value + + +class MutationDict(Mutable, dict): + @classmethod + def coerce(cls, key, value): + "Convert plain dictionaries to MutationDict." + + if not isinstance(value, MutationDict): + if isinstance(value, dict): + return MutationDict(value) + + # this call will raise ValueError + return Mutable.coerce(key, value) + else: + return value + + def __setitem__(self, key, value): + "Detect dictionary set events and emit change events." + + dict.__setitem__(self, key, value) + self.changed() + + def __delitem__(self, key): + "Detect dictionary del events and emit change events." + + dict.__delitem__(self, key) + self.changed() diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index 62fb7e8d..423508f6 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -26,7 +26,7 @@ from sqlalchemy.sql import and_ from migrate.changeset.constraint import UniqueConstraint -from mediagoblin.db.extratypes import JSONEncoded +from mediagoblin.db.extratypes import JSONEncoded, MutationDict from mediagoblin.db.migration_tools import RegisterMigration, inspect_table from mediagoblin.db.models import MediaEntry, Collection, User, MediaComment @@ -474,3 +474,35 @@ def wants_notifications(db): col.create(user_table) db.commit() + + +@RegisterMigration(16, MIGRATIONS) +def upload_limits(db): + """Add user upload limit columns""" + metadata = MetaData(bind=db.bind) + + user_table = inspect_table(metadata, 'core__users') + media_entry_table = inspect_table(metadata, 'core__media_entries') + + col = Column('uploaded', Integer, default=0) + col.create(user_table) + + col = Column('upload_limit', Integer) + col.create(user_table) + + col = Column('file_size', Integer, default=0) + col.create(media_entry_table) + + db.commit() + + +@RegisterMigration(17, MIGRATIONS) +def add_file_metadata(db): + """Add file_metadata to MediaFile""" + metadata = MetaData(bind=db.bind) + media_file_table = inspect_table(metadata, "core__mediafiles") + + col = Column('file_metadata', MutationDict.as_mutable(JSONEncoded)) + col.create(media_file_table) + + db.commit() diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 4341e086..68a2faa0 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -30,8 +30,8 @@ from sqlalchemy.sql.expression import desc from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.util import memoized_property - -from mediagoblin.db.extratypes import PathTupleWithSlashes, JSONEncoded +from mediagoblin.db.extratypes import (PathTupleWithSlashes, JSONEncoded, + MutationDict) from mediagoblin.db.base import Base, DictReadAttrProxy from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, \ MediaCommentMixin, CollectionMixin, CollectionItemMixin @@ -48,6 +48,7 @@ from migrate import changeset _log = logging.getLogger(__name__) + class User(Base, UserMixin): """ TODO: We should consider moving some rarely used fields @@ -74,6 +75,8 @@ class User(Base, UserMixin): is_admin = Column(Boolean, default=False, nullable=False) url = Column(Unicode) bio = Column(UnicodeText) # ?? + uploaded = Column(Integer, default=0) + upload_limit = Column(Integer) ## TODO # plugin data would be in a separate model @@ -190,6 +193,7 @@ class MediaEntry(Base, MediaEntryMixin): # or use sqlalchemy.types.Enum? license = Column(Unicode) collected = Column(Integer, default=0) + file_size = Column(Integer, default=0) fail_error = Column(Unicode) fail_metadata = Column(JSONEncoded) @@ -264,6 +268,35 @@ class MediaEntry(Base, MediaEntryMixin): if media is not None: return media.url_for_self(urlgen) + def get_file_metadata(self, file_key, metadata_key=None): + """ + Return the file_metadata dict of a MediaFile. If metadata_key is given, + return the value of the key. + """ + media_file = MediaFile.query.filter_by(media_entry=self.id, + name=unicode(file_key)).first() + + if media_file: + if metadata_key: + return media_file.file_metadata.get(metadata_key, None) + + return media_file.file_metadata + + def set_file_metadata(self, file_key, **kwargs): + """ + Update the file_metadata of a MediaFile. + """ + media_file = MediaFile.query.filter_by(media_entry=self.id, + name=unicode(file_key)).first() + + file_metadata = media_file.file_metadata or {} + + for key, value in kwargs.iteritems(): + file_metadata[key] = value + + media_file.file_metadata = file_metadata + media_file.save() + @property def media_data(self): return getattr(self, self.media_data_ref) @@ -360,6 +393,7 @@ class MediaFile(Base): nullable=False) name_id = Column(SmallInteger, ForeignKey(FileKeynames.id), nullable=False) file_path = Column(PathTupleWithSlashes) + file_metadata = Column(MutationDict.as_mutable(JSONEncoded)) __table_args__ = ( PrimaryKeyConstraint('media_entry', 'name_id'), |