예제 #1
0
def restore_necessary_files():
    # Restore the appropriate media files and thumbnail files
    # for any media currently in the database.
    # Use the python models to do this.
    if not deleted_dir:
        return

    filename_pairs = []
    for media in DBSession.query(Media).all():
        for thumb in thumb_paths(media).values():
            filename_pairs.append((
                thumb.replace(m_img_dir, m_deleted_dir),
                thumb
            ))
        for file in media.files:
            if file.file_path:
                filename_pairs.append((
                    file.file_path.replace(media_dir, m_deleted_dir),
                    file.file_path
                ))
    for podcast in DBSession.query(Podcast).all():
        for thumb in thumb_paths(podcast).values():
            filename_pairs.append((
                thumb.replace(p_img_dir, p_deleted_dir),
                thumb
            ))

    for src, dest in filename_pairs:
        if os.path.exists(src):
            if DEBUG:
                print "Moving %s to %s" % (src, dest)
            shutil.move(src, dest)
예제 #2
0
def backup_files(dump_dir):
    # Backup all files (media files, thumbs) referenced by an object in the DB
    # to the provided dump_dir.

    # TODO: display errors when file operations fail

    if dump_dir == "/":
        return 1, "Dump Files directory should never be the root directory, '/'"

    # normalize dirname
    dump_dir = dump_dir.rstrip(os.sep) + os.sep

    # These are the directories we will write to.
    media_thumb_dir = dump_dir + Media._thumb_dir
    podcast_thumb_dir = dump_dir + Podcast._thumb_dir
    media_files_dir = dump_dir + "media_files"

    # Initialize our default paths to backup
    default_images = ["news.jpg", "newm.jpg", "newl.jpg"]
    media_thumbs = [m_img_dir + os.sep + img for img in default_images]
    podcast_thumbs = [p_img_dir + os.sep + img for img in default_images]
    media_files = []

    # Add the media thumbs and media files
    for media in DBSession.query(Media).all():
        file_paths = [file_path(f) for f in media.files]
        media_files += [fp for fp in file_paths if fp]
        media_thumbs += thumb_paths(media).values()

    # Add the podcast thumbs
    for podcast in DBSession.query(Podcast).all():
        podcast_thumbs += thumb_paths(podcast).values()

    # Ensure the necessary directories exist.
    assert os.path.isdir(dump_dir)
    for subdir in (media_thumb_dir, media_files_dir, podcast_thumb_dir):
        if not os.path.exists(subdir):
            os.mkdir(subdir)
        assert os.path.isdir(subdir)
        empty_dir(subdir)

    # Copy over all of the files:
    sources_dests = (
        (media_thumbs, media_thumb_dir),
        (media_files, media_files_dir),
        (podcast_thumbs, podcast_thumb_dir),
    )
    for sources, dest_dir in sources_dests:
        for src in sources:
            if DEBUG:
                print "Copying %s to %s%s" % (src, dest_dir, os.sep)
            shutil.copy2(src, dest_dir)

    return (
        0,
        "%d thumbnails and %d media files successfully backed up"
        % (len(media_thumbs) + len(podcast_thumbs), len(media_files)),
    )
예제 #3
0
def backup_files(dump_dir):
    # Backup all files (media files, thumbs) referenced by an object in the DB
    # to the provided dump_dir.

    # TODO: display errors when file operations fail

    if dump_dir == '/':
        return 1, "Dump Files directory should never be the root directory, '/'"

    # normalize dirname
    dump_dir = dump_dir.rstrip(os.sep) + os.sep

    # These are the directories we will write to.
    media_thumb_dir = dump_dir + Media._thumb_dir
    podcast_thumb_dir = dump_dir + Podcast._thumb_dir
    media_files_dir = dump_dir + 'media_files'

    # Initialize our default paths to backup
    default_images = ['news.jpg', 'newm.jpg', 'newl.jpg']
    media_thumbs = [m_img_dir+os.sep+img for img in default_images]
    podcast_thumbs = [p_img_dir+os.sep+img for img in default_images]
    media_files = []

    # Add the media thumbs and media files
    for media in DBSession.query(Media).all():
        file_paths = [file_path(f) for f in media.files]
        media_files += [fp for fp in file_paths if fp]
        media_thumbs += thumb_paths(media).values()

    # Add the podcast thumbs
    for podcast in DBSession.query(Podcast).all():
        podcast_thumbs += thumb_paths(podcast).values()

    # Ensure the necessary directories exist.
    assert os.path.isdir(dump_dir)
    for subdir in (media_thumb_dir, media_files_dir, podcast_thumb_dir):
        if not os.path.exists(subdir):
            os.mkdir(subdir)
        assert os.path.isdir(subdir)
        empty_dir(subdir)

    # Copy over all of the files:
    sources_dests = (
        (media_thumbs, media_thumb_dir),
        (media_files, media_files_dir),
        (podcast_thumbs, podcast_thumb_dir),
    )
    for sources, dest_dir in sources_dests:
        for src in sources:
            if DEBUG:
                print "Copying %s to %s%s" % (src, dest_dir, os.sep)
            shutil.copy2(src, dest_dir)

    return 0,'%d thumbnails and %d media files successfully backed up' %\
            (len(media_thumbs) + len(podcast_thumbs), len(media_files))
예제 #4
0
def remove_unnecessary_files():
    # Move all media files and thumbnail files into 'deleted' folder.
    # XXX: don't run if deleted_dir is not set!
    if not deleted_dir:
        return

    for media in DBSession.query(Media).all():
        file_paths = thumb_paths(media).values()
        for f in media.files:
            file_paths.append(f.file_path)
        helpers.delete_files(file_paths, 'media')

    for podcast in DBSession.query(Podcast).all():
        file_paths = thumb_paths(podcast).values()
        helpers.delete_files(file_paths, 'podcasts')
예제 #5
0
    def save(self,
             id,
             slug,
             title,
             subtitle,
             author_name,
             author_email,
             description,
             details,
             feed,
             delete=None,
             **kwargs):
        """Save changes or create a new :class:`~mediacore.model.podcasts.Podcast` instance.

        Form handler the :meth:`edit` action and the
        :class:`~mediacore.forms.admin.podcasts.PodcastForm`.

        Redirects back to :meth:`edit` after successful editing
        and :meth:`index` after successful deletion.

        """
        podcast = fetch_row(Podcast, id)

        if delete:
            file_paths = thumb_paths(podcast).values()
            DBSession.delete(podcast)
            DBSession.commit()
            helpers.delete_files(file_paths, Podcast._thumb_dir)
            redirect(action='index', id=None)

        if not slug:
            slug = title
        if slug != podcast.slug:
            podcast.slug = get_available_slug(Podcast, slug, podcast)
        podcast.title = title
        podcast.subtitle = subtitle
        podcast.author = Author(author_name, author_email)
        podcast.description = description
        podcast.copyright = details['copyright']
        podcast.category = details['category']
        podcast.itunes_url = feed['itunes_url']
        podcast.feedburner_url = feed['feedburner_url']
        podcast.explicit = {
            'yes': True,
            'clean': False
        }.get(details['explicit'], None)

        if id == 'new':
            DBSession.add(podcast)
            DBSession.flush()
            create_default_thumbs_for(podcast)

        redirect(action='edit', id=podcast.id)
예제 #6
0
 def _delete_media(self, media):
     # FIXME: Ensure that if the first file is deleted from the file system,
     #        then the second fails, the first file is deleted from the
     #        and not not linking to a nonexistent file.
     # Delete every file from the storage engine
     for file in media.files:
         file.storage.delete(file.unique_id)
         # Remove this item from the DBSession so that the foreign key
         # ON DELETE CASCADE can take effect.
         DBSession.expunge(file)
     # Delete the media
     DBSession.delete(media)
     DBSession.flush()
     # Cleanup the thumbnails
     thumbs = thumb_paths(media).values()
     helpers.delete_files(thumbs, Media._thumb_dir)
예제 #7
0
def s3_delete_thumbs(item):
    """Delete the thumbnails associated with the given item.

    :param item: A 2-tuple with a subdir name and an ID. If given a
        ORM mapped class with _thumb_dir and id attributes, the info
        can be extracted automatically.
    :type item: ``tuple`` or mapped class instance
    """
    # fallback to normal thumb handling if no S3 engine is enabled.
    storage = get_s3_storage()
    if not storage:
        return None
    bucket = storage.connect_to_bucket()

    for path in thumb_paths(item, exists=True).itervalues():
        bucket.delete_key(path)
        if bucket.get_key(path):
            raise RuntimeError('Delete failed')
    return True
예제 #8
0
    def save(
        self, id, slug, title, subtitle, author_name, author_email, description, details, feed, delete=None, **kwargs
    ):
        """Save changes or create a new :class:`~mediacore.model.podcasts.Podcast` instance.

        Form handler the :meth:`edit` action and the
        :class:`~mediacore.forms.admin.podcasts.PodcastForm`.

        Redirects back to :meth:`edit` after successful editing
        and :meth:`index` after successful deletion.

        """
        podcast = fetch_row(Podcast, id)

        if delete:
            file_paths = thumb_paths(podcast).values()
            DBSession.delete(podcast)
            DBSession.commit()
            helpers.delete_files(file_paths, Podcast._thumb_dir)
            redirect(action="index", id=None)

        if not slug:
            slug = title
        if slug != podcast.slug:
            podcast.slug = get_available_slug(Podcast, slug, podcast)
        podcast.title = title
        podcast.subtitle = subtitle
        podcast.author = Author(author_name, author_email)
        podcast.description = description
        podcast.copyright = details["copyright"]
        podcast.category = details["category"]
        podcast.itunes_url = feed["itunes_url"]
        podcast.feedburner_url = feed["feedburner_url"]
        podcast.explicit = {"yes": True, "clean": False}.get(details["explicit"], None)

        if id == "new":
            DBSession.add(podcast)
            DBSession.flush()
            create_default_thumbs_for(podcast)

        redirect(action="edit", id=podcast.id)
예제 #9
0
    def merge_stubs(self, orig_id, input_id, **kwargs):
        """Merge in a newly created media item.

        This is merges media that has just been created. It must have:
            1. a non-default thumbnail, or
            2. a file, or
            3. a title, description, etc

        :param orig_id: Media ID to copy data to
        :type orig_id: ``int``
        :param input_id: Media ID to source files, thumbs, etc from
        :type input_id: ``int``
        :returns: JSON dict

        """
        orig = fetch_row(Media, orig_id)
        input = fetch_row(Media, input_id)
        merged_files = []

        # Merge in the file(s) from the input stub
        if input.slug.startswith('_stub_') and input.files:
            for file in input.files[:]:
                # XXX: The filename will still use the old ID
                file.media = orig
                merged_files.append(file)
            DBSession.delete(input)

        # The original is a file or thumb stub, copy in the new values
        elif orig.slug.startswith('_stub_') \
        and not input.slug.startswith('_stub_'):
            DBSession.delete(input)
            DBSession.flush()
            orig.podcast = input.podcast
            orig.title = input.title
            orig.subtitle = input.subtitle
            orig.slug = input.slug
            orig.author = input.author
            orig.description = input.description
            orig.notes = input.notes
            orig.duration = input.duration
            orig.views = input.views
            orig.likes = input.likes
            orig.publish_on = input.publish_on
            orig.publish_until = input.publish_until
            orig.categories = input.categories
            orig.tags = input.tags
            orig.update_popularity()

        # Copy the input thumb over the default thumbnail
        elif input.slug.startswith('_stub_') \
        and has_default_thumbs(orig) \
        and not has_default_thumbs(input):
            for key, dst_path in thumb_paths(orig).iteritems():
                src_path = thumb_path(input, key)
                # This will raise an OSError on Windows, but not *nix
                os.rename(src_path, dst_path)
            DBSession.delete(input)

        # Report an error
        else:
            return dict(
                success = False,
                message = u'No merge operation fits.',
            )

        orig.update_status()

        status_form_xhtml = unicode(update_status_form.display(
            action=url_for(action='update_status', id=orig.id),
            media=orig))

        file_xhtml = {}
        for file in merged_files:
            file_xhtml[file.id] = unicode(edit_file_form.display(
                action=url_for(action='edit_file', id=orig.id),
                file=file))

        return dict(
            success = True,
            media_id = orig.id,
            title = orig.title,
            link = url_for(action='edit', id=orig.id),
            status_form = status_form_xhtml,
            file_forms = file_xhtml,
        )
예제 #10
0
    def merge_stubs(self, orig_id, input_id, **kwargs):
        """Merge in a newly created media item.

        This is merges media that has just been created. It must have:
            1. a non-default thumbnail, or
            2. a file, or
            3. a title, description, etc

        :param orig_id: Media ID to copy data to
        :type orig_id: ``int``
        :param input_id: Media ID to source files, thumbs, etc from
        :type input_id: ``int``
        :returns: JSON dict

        """
        orig = fetch_row(Media, orig_id)
        input = fetch_row(Media, input_id)
        merged_files = []

        # Merge in the file(s) from the input stub
        if input.slug.startswith('_stub_') and input.files:
            for file in input.files[:]:
                # XXX: The filename will still use the old ID
                file.media = orig
                merged_files.append(file)
            DBSession.delete(input)

        # The original is a file or thumb stub, copy in the new values
        elif orig.slug.startswith('_stub_') \
        and not input.slug.startswith('_stub_'):
            DBSession.delete(input)
            DBSession.flush()
            orig.podcast = input.podcast
            orig.title = input.title
            orig.subtitle = input.subtitle
            orig.slug = input.slug
            orig.author = input.author
            orig.description = input.description
            orig.notes = input.notes
            orig.duration = input.duration
            orig.views = input.views
            orig.likes = input.likes
            orig.publish_on = input.publish_on
            orig.publish_until = input.publish_until
            orig.categories = input.categories
            orig.tags = input.tags
            orig.update_popularity()

        # Copy the input thumb over the default thumbnail
        elif input.slug.startswith('_stub_') \
        and has_default_thumbs(orig) \
        and not has_default_thumbs(input):
            for key, dst_path in thumb_paths(orig).iteritems():
                src_path = thumb_path(input, key)
                # This will raise an OSError on Windows, but not *nix
                os.rename(src_path, dst_path)
            DBSession.delete(input)

        # Report an error
        else:
            return dict(
                success = False,
                message = u'No merge operation fits.',
            )

        orig.update_status()

        status_form_xhtml = unicode(update_status_form.display(
            action=url_for(action='update_status', id=orig.id),
            media=orig))

        file_xhtml = {}
        for file in merged_files:
            file_xhtml[file.id] = unicode(edit_file_form.display(
                action=url_for(action='edit_file', id=orig.id),
                file=file))

        return dict(
            success = True,
            media_id = orig.id,
            title = orig.title,
            link = url_for(action='edit', id=orig.id),
            status_form = status_form_xhtml,
            file_forms = file_xhtml,
        )
예제 #11
0
    def save(self, id, slug, title, author_name, author_email,
             description, notes, podcast, tags, categories,
             delete=None, **kwargs):
        """Save changes or create a new :class:`~mediacore.model.media.Media` instance.

        Form handler the :meth:`edit` action and the
        :class:`~mediacore.forms.admin.media.MediaForm`.

        Redirects back to :meth:`edit` after successful editing
        and :meth:`index` after successful deletion.

        """
        media = fetch_row(Media, id)

        if delete:
            file_paths = thumb_paths(media).values()
            for f in media.files:
                file_paths.append(f.file_path)
                # Remove the file from the session so that SQLAlchemy doesn't
                # try to issue an UPDATE to set the MediaFile.media_id to None.
                # The database ON DELETE CASCADE handles everything for us.
                DBSession.expunge(f)
            DBSession.delete(media)
            DBSession.commit()
            helpers.delete_files(file_paths, Media._thumb_dir)
            redirect(action='index', id=None)

        if not slug:
            slug = title
        elif slug.startswith('_stub_'):
            slug = slug[len('_stub_'):]
        if slug != media.slug:
            media.slug = get_available_slug(Media, slug, media)
        media.title = title
        media.author = Author(author_name, author_email)
        media.description = description
        media.notes = notes
        media.podcast_id = podcast
        media.set_tags(tags)
        media.set_categories(categories)

        media.update_status()
        DBSession.add(media)
        DBSession.flush()

        if id == 'new':
            create_default_thumbs_for(media)

        if request.is_xhr:
            status_form_xhtml = unicode(update_status_form.display(
                action=url_for(action='update_status', id=media.id),
                media=media))

            return dict(
                media_id = media.id,
                values = {'slug': slug},
                link = url_for(action='edit', id=media.id),
                status_form = status_form_xhtml,
            )
        else:
            redirect(action='edit', id=media.id)