Ejemplo n.º 1
0
    def view(self, slug, podcast_slug=None, **kwargs):
        """Display the media player, info and comments.

        :param slug: The :attr:`~mediacore.models.media.Media.slug` to lookup
        :param podcast_slug: The :attr:`~mediacore.models.podcasts.Podcast.slug`
            for podcast this media belongs to. Although not necessary for
            looking up the media, it tells us that the podcast slug was
            specified in the URL and therefore we reached this action by the
            preferred route.
        :rtype dict:
        :returns:
            media
                The :class:`~mediacore.model.media.Media` instance for display.
            comment_form
                The :class:`~mediacore.forms.comments.PostCommentForm` instance.
            comment_form_action
                ``str`` comment form action
            comment_form_values
                ``dict`` form values
            next_episode
                The next episode in the podcast series, if this media belongs to
                a podcast, another :class:`~mediacore.model.media.Media`
                instance.

        """
        media = fetch_row(Media, slug=slug)
        media.views += 1

        next_episode = None
        if media.podcast_id is not None:
            # Always view podcast media from a URL that shows the context of the podcast
            if url_for() != url_for(podcast_slug=media.podcast.slug):
               redirect(podcast_slug=media.podcast.slug)

            if media.is_published:
                next_episode = DBSession.query(Media)\
                    .filter(Media.podcast_id == media.podcast.id)\
                    .filter(Media.publish_on > media.publish_on)\
                    .filter(Media.publish_on < datetime.now())\
                    .filter(Media.status >= 'publish')\
                    .filter(Media.status.excludes('trash'))\
                    .order_by(Media.publish_on)\
                    .first()

        return dict(
            media = media,
            comment_form = post_comment_form,
            comment_form_action = url_for(action='comment'),
            comment_form_values = kwargs,
            next_episode = next_episode,
        )
Ejemplo n.º 2
0
    def edit(self, id, **kwargs):
        """Display the :class:`~mediacore.forms.users.UserForm` for editing or adding.

        :param id: User ID
        :type id: ``int`` or ``"new"``
        :rtype: dict
        :returns:
            user
                The :class:`~mediacore.model.auth.User` instance we're editing.
            user_form
                The :class:`~mediacore.forms.users.UserForm` instance.
            user_action
                ``str`` form submit url
            user_values
                ``dict`` form values

        """
        user = fetch_row(User, id)

        if tmpl_context.action == "save" or id == "new":
            # Use the values from error_handler or GET for new users
            user_values = kwargs
            user_values["login_details.password"] = None
            user_values["login_details.confirm_password"] = None
        else:
            user_values = dict(
                display_name=user.display_name,
                email_address=user.email_address,
                login_details=dict(group=user.groups[0].group_id if user.groups else None, user_name=user.user_name),
            )

        return dict(user=user, user_form=user_form, user_action=url_for(action="save"), user_values=user_values)
Ejemplo n.º 3
0
    def post_login(self, came_from=url_for(controller="/admin")):
        if not request.identity:
            login_counter = request.environ["repoze.who.logins"] + 1
            redirect(came_from)

        userid = request.identity["repoze.who.userid"]
        flash(_("Welcome back, %s!") % userid)
        redirect(came_from)
Ejemplo n.º 4
0
def podcast_image_url(podcast, size='s'):
    if not podcast:
        return None

    image = 'podcasts/%d%s.jpg' % (podcast.id, size)
    file_name = os.path.join(
        config.image_dir,
        image
    )
    if not os.path.isfile(file_name):
        return None

    file_url = '/images/' + image

    return url_for(file_url)
Ejemplo n.º 5
0
    def _jsonify(self, media):
        im_path = '/images/media/%d%%s.jpg' % media.id

        if media.podcast_id:
            media_url = url_for(controller='/media', action='view', slug=media.slug,
                                podcast_slug=media.podcast.slug)
        else:
            media_url = url_for(controller="/media", action="view", slug=media.slug)

        return dict(
            title = media.title,
            description = media.description,
            description_plain = helpers.strip_xhtml(helpers.line_break_xhtml(\
                helpers.line_break_xhtml(media.description))),
            img_l = url_for(im_path % 'l'),
            img_m = url_for(im_path % 'm'),
            img_s = url_for(im_path % 's'),
            img_ss = url_for(im_path % 'ss'),
            id = media.id,
            slug = media.slug,
            url = media_url,
            podcast = media.podcast and media.podcast.slug or None,
        )
Ejemplo n.º 6
0
    def upload_submit_async(self, **kwargs):
        """Ajax form validation and/or submission.

        This is the save handler for :class:`~mediacore.forms.media.UploadForm`.

        When ajax is enabled this action is called for each field as the user
        fills them in. Although the entire form is validated, the JS only
        provides the value of one field at a time,

        :param validate: A JSON list of field names to check for validation
        :parma \*\*kwargs: One or more form field values.
        :rtype: JSON dict
        :returns:
            :When validating one or more fields:

            valid
                bool
            err
                A dict of error messages keyed by the field names

            :When saving an upload:

            success
                bool
            redirect
                If valid, the redirect url for the upload successful page.

        .. note::

            This method returns incorrect Content-Type headers: Content-Type
            is set to ``text/html`` even though the returned data is really
            of type ``application/json``.

            This is because this method is used from the flash based uploader;
            Swiff.Uploader (which we use) uses Flash's FileReference.upload()
            method, which doesn't allow overriding the HTTP headers.

            On windows, the default headers have an "Accept: text/\*" line.
            This means that it won't accept "application/json".

            TG honours that, and, when returning, will throw an error rather
            than respond with an unacceptable Content-Type.

            It would perhaps be more correct to set Content-Type to
            ``text/plain`` or ``text/x-json``, but there seems to be a bug in
            the current TG 2.0.3 + Pylons 0.9.7 stack w.r.t. overriding the
            Content-Type headers.
        """
        # TODO: look into the bug outlined in the note above.

        if 'validate' in kwargs:
            # we're just validating the fields. no need to worry.
            fields = json.loads(kwargs['validate'])
            err = {}
            for field in fields:
                if field in tmpl_context.form_errors:
                    err[field] = tmpl_context.form_errors[field]

            return json.dumps(dict(
                valid = len(err) == 0,
                err = err
            ))
        else:
            # We're actually supposed to save the fields. Let's do it.
            if len(tmpl_context.form_errors) != 0:
                # if the form wasn't valid, return failure
                return json.dumps(dict(
                    success = False
                ))

            # else actually save it!
            kwargs.setdefault('name')
            kwargs.setdefault('tags')

            media_obj = self._save_media_obj(
                kwargs['name'], kwargs['email'],
                kwargs['title'], kwargs['description'],
                kwargs['tags'], kwargs['file']
            )
            email.send_media_notification(media_obj)

            return json.dumps(dict(
                success = True,
                redirect = url_for(action='upload_success')
            ))
Ejemplo n.º 7
0
from formencode import validators
from paste.deploy.converters import asbool
from paste.util import mimeparse

from mediacore.lib.base import (BaseController, url_for, redirect,
    expose, expose_xhr, validate, paginate)
from mediacore.model import (DBSession, fetch_row, get_available_slug,
    Media, MediaFile, Comment, Tag, Topic, Author, AuthorWithIP, Podcast)
from mediacore.lib import helpers, email
from mediacore.forms.media import UploadForm
from mediacore.forms.comments import PostCommentForm


post_comment_form = PostCommentForm()
upload_form = UploadForm(
    action = url_for(controller='/media', action='upload_submit'),
    async_action = url_for(controller='/media', action='upload_submit_async')
)


class FTPUploadException(Exception):
    pass


class MediaController(BaseController):
    """Media actions -- for both regular and podcast media"""

    def __init__(self, *args, **kwargs):
        """Populate the :obj:`pylons.tmpl_context` with topics.

        Used by :data:`mediacore.templates.helpers` to render the
Ejemplo n.º 8
0
 def post_logout(self, came_from=url_for("/")):
     flash(_("We hope to see you soon!"))
     redirect(came_from)
Ejemplo n.º 9
0
    def login(self, came_from=url_for("/")):
        login_counter = request.environ["repoze.who.logins"]
        if login_counter > 0:
            flash(_("Wrong credentials"), "warning")

        return dict(login_counter=str(login_counter), came_from=came_from)
Ejemplo n.º 10
0
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from tg import config, request, response, tmpl_context
from sqlalchemy import orm, sql
from repoze.what.predicates import has_permission

from mediacore.lib.base import (BaseController, url_for, redirect,
    expose, expose_xhr, validate, paginate)
from mediacore.lib import helpers
from mediacore.model import DBSession, fetch_row, Setting
from mediacore.forms.settings import SettingsForm

settings_form = SettingsForm(action=url_for(controller='/settingadmin',
                                            action='save'))


class SettingadminController(BaseController):
    allow_only = has_permission('admin')

    @expose()
    def index(self, section='topics', **kwargs):
        redirect(controller='categoryadmin', category=section)


    @expose('mediacore.templates.admin.settings.edit')
    def edit(self, **kwargs):
        """Display the :class:`~mediacore.forms.settings.SettingsForm`.

        :rtype: dict
Ejemplo n.º 11
0
    def edit_file(self, id, file_id, player_enabled, feed_enabled,
                  toggle_feed, toggle_player, delete, **kwargs):
        """Save action for the :class:`~mediacore.forms.media.EditFileForm`.

        Changes or delets a :class:`~mediacore.model.media.MediaFile`.

        :param id: Media ID
        :type id: :class:`int`
        :rtype: JSON dict
        :returns:
            success
                bool
            message
                Error message, if unsuccessful
            status_form
                Rendered XHTML for the status form, updated to reflect the
                changes made.

        """
        media = fetch_row(Media, id, incl_trash=True)
        data = {}

#        try:
        try:
            file = [file for file in media.files if file.id == file_id][0]
        except IndexError:
            raise Exception, 'File does not exist.'

        if toggle_player:
            data['field'] = 'player_enabled'
            file.enable_player = data['value'] = not player_enabled
            DBSession.add(file)
        elif toggle_feed:
            data['field'] = 'feed_enabled'
            file.enable_feed = data['value'] = not feed_enabled
            # Raises an exception if it is the only feed enabled file for
            # an already published podcast episode.
            DBSession.add(file)
        elif delete:
            data['field'] = 'delete'
            DBSession.delete(file)
            media.files.remove(file)
        else:
            raise Exception, 'No action to perform.'

        data['success'] = True
        media.update_type()
        media.update_status()
        DBSession.add(media)
#        except Exception, e:
#            data['success'] = False
#            data['message'] = e.message

        if request.is_xhr:
            # Return the rendered widget for injection
            status_form_xhtml = unicode(update_status_form.display(
                action=url_for(action='update_status'), media=media))
            data['status_form'] = status_form_xhtml
            return data
        else:
            DBSession.flush()
            redirect(action='edit')
Ejemplo n.º 12
0
    def add_file(self, id, file=None, url=None, **kwargs):
        """Save action for the :class:`~mediacore.forms.media.AddFileForm`.

        Creates a new :class:`~mediacore.model.media.MediaFile` from the
        uploaded file or the local or remote URL.

        :param id: Media ID. If ``"new"`` a new Media stub is created with
            :func:`~mediacore.model.media.create_media_stub`.
        :type id: :class:`int` or ``"new"``
        :param file: The uploaded file
        :type file: :class:`cgi.FieldStorage` or ``None``
        :param url: A URL to a recognizable audio or video file
        :type url: :class:`unicode` or ``None``
        :rtype: JSON dict
        :returns:
            success
                bool
            message
                Error message, if unsuccessful
            media_id
                The :attr:`~mediacore.model.media.Media.id` which is
                important if new media has just been created.
            file_id
                The :attr:`~mediacore.model.media.MediaFile.id` for the newly
                created file.
            edit_form
                The rendered XHTML :class:`~mediacore.forms.media.EditFileForm`
                for this file.
            status_form
                The rendered XHTML :class:`~mediacore.forms.media.UpdateStatusForm`

        """
        if id == 'new':
            media = create_media_stub()
        else:
            media = fetch_row(Media, id, incl_trash=True)

        try:
            if file is not None:
                # Create a media object, add it to the video, and store the file permanently.
                media_file = _add_new_media_file(media, file.filename, file.file)
            elif url:
                media_file = MediaFile()
                # Parse the URL checking for known embeddables like YouTube
                for type, info in config.embeddable_filetypes.iteritems():
                    match = re.match(info['pattern'], url)
                    if match:
                        media_file.type = type
                        media_file.url = match.group('id')
                        media_file.enable_feed = False
                        break
                else:
                    # Check for types we can play ourselves
                    type = os.path.splitext(url)[1].lower()[1:]
                    for playable_types in config.playable_types.itervalues():
                        if type in playable_types:
                            media_file.type = type
                            media_file.url = url
                            break
                    else:
                        raise Exception, 'Unsupported URL %s' % url
            else:
                raise Exception, 'Given no action to perform.'

            media.files.append(media_file)
            media.update_type()
            media.update_status()
            DBSession.add(media)
            DBSession.flush()

            # Render some widgets so the XHTML can be injected into the page
            edit_form_xhtml = unicode(edit_file_form.display(
                action=url_for(action='edit_file', id=media.id),
                file=media_file))
            status_form_xhtml = unicode(update_status_form.display(
                action=url_for(action='update_status', id=media.id),
                media=media))

            return dict(
                success = True,
                media_id = media.id,
                file_id = media_file.id,
                edit_form = edit_form_xhtml,
                status_form = status_form_xhtml,
            )
        except Exception, e:
            return dict(
                success = False,
                message = e.message,
            )
Ejemplo n.º 13
0
    def edit(self, id, **kwargs):
        """Display the media forms for editing or adding.

        This page serves as the error_handler for every kind of edit action,
        if anything goes wrong with them they'll be redirected here.

        :param id: Media ID
        :type id: ``int`` or ``"new"``
        :param \*\*kwargs: Extra args populate the form for ``"new"`` media
        :returns:
            media
                :class:`~mediacore.model.media.Media` instance
            media_form
                The :class:`~mediacore.forms.media.MediaForm` instance
            media_action
                ``str`` form submit url
            media_values
                ``dict`` form values
            file_add_form
                The :class:`~mediacore.forms.media.AddFileForm` instance
            file_add_action
                ``str`` form submit url
            file_edit_form
                The :class:`~mediacore.forms.media.EditFileForm` instance
            file_edit_action
                ``str`` form submit url
            album_art_form
                The :class:`~mediacore.forms.admin.AlbumArtForm` instance
            album_art_action
                ``str`` form submit url
            update_status_form
                The :class:`~mediacore.forms.media.UpdateStatusForm` instance
            update_status_action
                ``str`` form submit url

        """
        media = fetch_row(Media, id, incl_trash=True)

        if tmpl_context.action == 'save' or id == 'new':
            # Use the values from error_handler or GET for new podcast media
            media_values = kwargs
            user = request.environ['repoze.who.identity']['user']
            media_values.setdefault('author_name', user.display_name)
            media_values.setdefault('author_email', user.email_address)
        else:
            # Pull the defaults from the media item
            media_values = dict(
                podcast = media.podcast_id,
                slug = media.slug,
                title = media.title,
                author_name = media.author.name,
                author_email = media.author.email,
                description = media.description,
                tags = ', '.join((tag.name for tag in media.tags)),
                topics = [topic.id for topic in media.topics],
                notes = media.notes,
                details = dict(duration = helpers.duration_from_seconds(media.duration)),
            )

        # Re-verify the state of our Media object in case the data is nonsensical
        if id != 'new':
            media.update_type()
            media.update_status()
            DBSession.add(media)

        return dict(
            media = media,
            media_form = media_form,
            media_action = url_for(action='save'),
            media_values = media_values,
            file_add_form = add_file_form,
            file_add_action = url_for(action='add_file'),
            file_edit_form = edit_file_form,
            file_edit_action = url_for(action='edit_file'),
            album_art_form = album_art_form,
            album_art_action = url_for(action='save_album_art'),
            update_status_form = update_status_form,
            update_status_action = url_for(action='update_status'),
        )
Ejemplo n.º 14
0
from mediacore.model import (DBSession, fetch_row, get_available_slug,
    Media, MediaFile, Podcast, Tag, Author)
from mediacore.lib import helpers
from mediacore.model.media import create_media_stub
from mediacore.controllers.media import _add_new_media_file
from mediacore.forms.admin import SearchForm, AlbumArtForm
from mediacore.forms.media import (MediaForm, AddFileForm, EditFileForm,
    UpdateStatusForm, PodcastFilterForm)


media_form = MediaForm()
add_file_form = AddFileForm()
edit_file_form = EditFileForm()
album_art_form = AlbumArtForm()
update_status_form = UpdateStatusForm()
search_form = SearchForm(action=url_for(controller='/mediaadmin', action='index'))
podcast_filter_form = PodcastFilterForm(action=url_for(controller='/mediaadmin', action='index'))

class MediaadminController(BaseController):
    allow_only = has_permission('admin')

    @expose_xhr('mediacore.templates.admin.media.index',
                'mediacore.templates.admin.media.index-table')
    @paginate('media', items_per_page=25)
    def index(self, page=1, search=None, podcast_filter=None, **kwargs):
        """List media with pagination and filtering.

        :param page: Page number, defaults to 1.
        :type page: int
        :param search: Optional search term to filter by
        :type search: unicode or None
Ejemplo n.º 15
0
Comment Moderation Controller
"""
from tg import config, request, response, tmpl_context
from repoze.what.predicates import has_permission
from sqlalchemy import orm, sql

from mediacore.lib.base import (BaseController, url_for, redirect,
    expose, expose_xhr, validate, paginate)
from mediacore.model import DBSession, fetch_row, Media, Comment
from mediacore.lib import helpers
from mediacore.forms.admin import SearchForm
from mediacore.forms.comments import EditCommentForm


edit_form = EditCommentForm()
search_form = SearchForm(action=url_for(controller='/commentadmin',
                                        action='index'))

class CommentadminController(BaseController):
    allow_only = has_permission('admin')

    @expose_xhr('mediacore.templates.admin.comments.index',
                'mediacore.templates.admin.comments.index-table')
    @paginate('comments', items_per_page=50)
    def index(self, page=1, search=None, media_filter=None, **kwargs):
        """List comments with pagination and filtering.

        :param page: Page number, defaults to 1.
        :type page: int
        :param search: Optional search term to filter by
        :type search: unicode or None
        :param media_filter: Optional media ID to filter by