class MediaFile(Base): """ TODO: Highly consider moving "name" into a new table. TODO: Consider preloading said table in software """ __tablename__ = "core__mediafiles" media_entry = Column( Integer, ForeignKey(MediaEntry.id), 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'), {}) def __repr__(self): return "<MediaFile %s: %r>" % (self.name, self.file_path) name_helper = relationship(FileKeynames, lazy="joined", innerjoin=True) name = association_proxy('name_helper', 'name', creator=FileKeynames.find_or_new )
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()
def add_metadata_column(db): metadata = MetaData(bind=db.bind) media_entry = inspect_table(metadata, 'core__media_entries') col = Column('media_metadata', MutationDict.as_mutable(JSONEncoded), default=MutationDict()) col.create(media_entry) db.commit()
class MediaEntry(Base, MediaEntryMixin): """ TODO: Consider fetching the media_files using join """ __tablename__ = "core__media_entries" id = Column(Integer, primary_key=True) uploader = Column(Integer, ForeignKey(User.id), nullable=False, index=True) title = Column(Unicode, nullable=False) slug = Column(Unicode) created = Column(DateTime, nullable=False, default=datetime.datetime.now, index=True) description = Column(UnicodeText) # ?? media_type = Column(Unicode, nullable=False) state = Column(Unicode, default=u'unprocessed', nullable=False) # or use sqlalchemy.types.Enum? license = Column(Unicode) file_size = Column(Integer, default=0) fail_error = Column(Unicode) fail_metadata = Column(JSONEncoded) transcoding_progress = Column(SmallInteger) queued_media_file = Column(PathTupleWithSlashes) queued_task_id = Column(Unicode) __table_args__ = ( UniqueConstraint('uploader', 'slug'), {}) get_uploader = relationship(User) media_files_helper = relationship("MediaFile", collection_class=attribute_mapped_collection("name"), cascade="all, delete-orphan" ) media_files = association_proxy('media_files_helper', 'file_path', creator=lambda k, v: MediaFile(name=k, file_path=v) ) attachment_files_helper = relationship("MediaAttachmentFile", cascade="all, delete-orphan", order_by="MediaAttachmentFile.created" ) attachment_files = association_proxy("attachment_files_helper", "dict_view", creator=lambda v: MediaAttachmentFile( name=v["name"], filepath=v["filepath"]) ) tags_helper = relationship("MediaTag", cascade="all, delete-orphan" # should be automatically deleted ) tags = association_proxy("tags_helper", "dict_view", creator=lambda v: MediaTag(name=v["name"], slug=v["slug"]) ) collections_helper = relationship("CollectionItem", cascade="all, delete-orphan" ) collections = association_proxy("collections_helper", "in_collection") media_metadata = Column(MutationDict.as_mutable(JSONEncoded), default=MutationDict()) ## TODO # fail_error def get_comments(self, ascending=False): order_col = MediaComment.created if not ascending: order_col = desc(order_col) return self.all_comments.order_by(order_col) def url_to_prev(self, urlgen): """get the next 'newer' entry by this user""" media = MediaEntry.query.filter( (MediaEntry.uploader == self.uploader) & (MediaEntry.state == u'processed') & (MediaEntry.id > self.id)).order_by(MediaEntry.id).first() if media is not None: return media.url_for_self(urlgen) def url_to_next(self, urlgen): """get the next 'older' entry by this user""" media = MediaEntry.query.filter( (MediaEntry.uploader == self.uploader) & (MediaEntry.state == u'processed') & (MediaEntry.id < self.id)).order_by(desc(MediaEntry.id)).first() 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) def media_data_init(self, **kwargs): """ Initialize or update the contents of a media entry's media_data row """ media_data = self.media_data if media_data is None: # Get the correct table: table = import_component(self.media_type + '.models:DATA_MODEL') # No media data, so actually add a new one media_data = table(**kwargs) # Get the relationship set up. media_data.get_media_entry = self else: # Update old media data for field, value in kwargs.iteritems(): setattr(media_data, field, value) @memoized_property def media_data_ref(self): return import_component(self.media_type + '.models:BACKREF_NAME') def __repr__(self): safe_title = self.title.encode('ascii', 'replace') return '<{classname} {id}: {title}>'.format( classname=self.__class__.__name__, id=self.id, title=safe_title) def delete(self, del_orphan_tags=True, **kwargs): """Delete MediaEntry and all related files/attachments/comments This will *not* automatically delete unused collections, which can remain empty... :param del_orphan_tags: True/false if we delete unused Tags too :param commit: True/False if this should end the db transaction""" # User's CollectionItems are automatically deleted via "cascade". # Comments on this Media are deleted by cascade, hopefully. # Delete all related files/attachments try: delete_media_files(self) except OSError, error: # Returns list of files we failed to delete _log.error('No such files from the user "{1}" to delete: ' '{0}'.format(str(error), self.get_uploader)) _log.info('Deleted Media entry id "{0}"'.format(self.id)) # Related MediaTag's are automatically cleaned, but we might # want to clean out unused Tag's too. if del_orphan_tags: # TODO: Import here due to cyclic imports!!! # This cries for refactoring from mediagoblin.db.util import clean_orphan_tags clean_orphan_tags(commit=False) # pass through commit=False/True in kwargs super(MediaEntry, self).delete(**kwargs)
class Location_V0(declarative_base()): __tablename__ = "core__locations" id = Column(Integer, primary_key=True) name = Column(Unicode) position = Column(MutationDict.as_mutable(JSONEncoded)) address = Column(MutationDict.as_mutable(JSONEncoded))