diff options
Diffstat (limited to 'mediagoblin/db')
-rw-r--r-- | mediagoblin/db/extratypes.py | 30 | ||||
-rw-r--r-- | mediagoblin/db/migrations.py | 60 | ||||
-rw-r--r-- | mediagoblin/db/models.py | 38 |
3 files changed, 118 insertions, 10 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 6616b657..0356c672 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, MediaComment, User, Privilege) @@ -474,6 +474,43 @@ 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() + +################### +# Moderation tables +################### + class ReportBase_v0(declarative_base()): __tablename__ = 'core__reports' id = Column(Integer, primary_key=True) @@ -487,6 +524,7 @@ class ReportBase_v0(declarative_base()): result = Column(UnicodeText) __mapper_args__ = {'polymorphic_on': discriminator} + class CommentReport_v0(ReportBase_v0): __tablename__ = 'core__reports_on_comments' __mapper_args__ = {'polymorphic_identity': 'comment_report'} @@ -496,7 +534,6 @@ class CommentReport_v0(ReportBase_v0): comment_id = Column(Integer, ForeignKey(MediaComment.id), nullable=True) - class MediaReport_v0(ReportBase_v0): __tablename__ = 'core__reports_on_media' __mapper_args__ = {'polymorphic_identity': 'media_report'} @@ -504,6 +541,7 @@ class MediaReport_v0(ReportBase_v0): id = Column('id',Integer, ForeignKey('core__reports.id'), primary_key=True) media_entry_id = Column(Integer, ForeignKey(MediaEntry.id), nullable=True) + class UserBan_v0(declarative_base()): __tablename__ = 'core__user_bans' user_id = Column(Integer, ForeignKey(User.id), nullable=False, @@ -511,11 +549,13 @@ class UserBan_v0(declarative_base()): expiration_date = Column(Date) reason = Column(UnicodeText, nullable=False) + class Privilege_v0(declarative_base()): __tablename__ = 'core__privileges' id = Column(Integer, nullable=False, primary_key=True, unique=True) privilege_name = Column(Unicode, nullable=False, unique=True) + class PrivilegeUserAssociation_v0(declarative_base()): __tablename__ = 'core__privileges_users' privilege_id = Column( @@ -529,13 +569,18 @@ class PrivilegeUserAssociation_v0(declarative_base()): ForeignKey(Privilege.id), primary_key=True) + 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'}] + {'privilege_name':u'moderator'}, + {'privilege_name':u'uploader'}, + {'privilege_name':u'reporter'}, + {'privilege_name':u'commenter'}, + {'privilege_name':u'active'}] + +# vR1 stands for "version Rename 1". This only exists because we need +# to deal with dropping some booleans and it's otherwise impossible +# with sqlite. class User_vR1(declarative_base()): __tablename__ = 'rename__users' @@ -550,6 +595,7 @@ class User_vR1(declarative_base()): url = Column(Unicode) bio = Column(UnicodeText) # ?? + @RegisterMigration(18, MIGRATIONS) def create_moderation_tables(db): diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 5173be9e..1514a3aa 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 @@ -71,6 +72,8 @@ class User(Base, UserMixin): license_preference = Column(Unicode) url = Column(Unicode) bio = Column(UnicodeText) # ?? + uploaded = Column(Integer, default=0) + upload_limit = Column(Integer) ## TODO # plugin data would be in a separate model @@ -217,6 +220,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) @@ -291,6 +295,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) @@ -387,6 +420,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'), |