Exemple #1
0
    def upload(self, **kwargs):
        """Display the upload form.

        :rtype: Dict
        :returns:
            legal_wording
                XHTML legal wording for rendering
            support_email
                An help contact address
            upload_form
                The :class:`~mediacore.forms.media.UploadForm` instance
            form_values
                ``dict`` form values, if any

        """
        support_emails = helpers.fetch_setting('email_support_requests')
        support_emails = email.parse_email_string(support_emails)
        support_email = support_emails and support_emails[0] or None

        return dict(
            legal_wording = helpers.fetch_setting('wording_user_uploads'),
            support_email = support_email,
            upload_form = upload_form,
            form_values = {},
        )
Exemple #2
0
def send_support_request(email, url, description, get_vars, post_vars):
    send_to = fetch_setting("email_support_requests")
    if not send_to:
        return

    subject = "New Support Request: %s" % email
    body = """A user has asked for support

Email: %s

URL: %s

Description: %s

GET_VARS:
%s


POST_VARS:
%s
""" % (
        email,
        url,
        description,
        "\n\n  ".join([x + " :  " + get_vars[x] for x in get_vars]),
        "\n\n  ".join([x + " :  " + post_vars[x] for x in post_vars]),
    )

    send(send_to, fetch_setting("email_send_from"), subject, body)
Exemple #3
0
def send_media_notification(media_obj):
    send_to = fetch_setting("email_media_uploaded")
    if not send_to:
        # media notification emails are disabled!
        return

    edit_url = (url_for(controller="mediaadmin", action="edit", id=media_obj.id, qualified=True),)

    clean_description = strip_xhtml(line_break_xhtml(line_break_xhtml(media_obj.description)))

    subject = "New %s: %s" % (media_obj.type, media_obj.title)
    body = """A new %s file has been uploaded!

Title: %s

Author: %s (%s)

Admin URL: %s

Description: %s
""" % (
        media_obj.type,
        media_obj.title,
        media_obj.author.name,
        media_obj.author.email,
        edit_url,
        clean_description,
    )

    send(send_to, fetch_setting("email_send_from"), subject, body)
Exemple #4
0
def _store_media_file_ftp(file, file_name):
    """Store the file on the defined FTP server.

    Returns the download url for accessing the resource.

    Ensures that the file was stored correctly and is accessible
    via the download url.

    Raises an exception on failure (FTP connection errors, I/O errors,
    integrity errors)
    """
    stor_cmd = 'STOR ' + file_name
    file_url = fetch_setting('ftp_download_url') + file_name

    # Put the file into our FTP storage
    FTPSession = ftplib.FTP(fetch_setting('ftp_server'),
                            fetch_setting('ftp_username'),
                            fetch_setting('ftp_password'))

    try:
        FTPSession.cwd(fetch_setting('ftp_upload_directory'))
        FTPSession.storbinary(stor_cmd, file)
        _verify_ftp_upload_integrity(file, file_url)
    except Exception, e:
        FTPSession.quit()
        raise e
Exemple #5
0
    def comment(self, slug, **values):
        """Post a comment from :class:`~mediacore.forms.comments.PostCommentForm`.

        :param slug: The media :attr:`~mediacore.model.media.Media.slug`
        :returns: Redirect to :meth:`view` page for media.

        """
        akismet_key = helpers.fetch_setting('akismet_key')
        akismet_url = helpers.fetch_setting('akismet_url')
        if akismet_key:
            akismet = Akismet(agent='MediaCore/%s' % MEDIACORE_VERSION)
            akismet.key = akismet_key
            akismet.blog_url = akismet_url or url_for('/', qualified=True)
            akismet.verify_key()
            data = {'comment_author': values['name'].encode('utf-8'),
                    'user_ip': request.environ.get('REMOTE_ADDR'),
                    'user_agent': request.environ.get('HTTP_USER_AGENT'),
                    'referrer': request.environ.get('HTTP_REFERER',  'unknown'),
                    'HTTP_ACCEPT': request.environ.get('HTTP_ACCEPT')}

            if akismet.comment_check(values['body'].encode('utf-8'), data):
                title = "Comment Rejected"
                text = "Your comment appears to be spam and has been rejected."
                add_transient_message('comment_posted', title, text)
                redirect(action='view', anchor='top')

        media = fetch_row(Media, slug=slug)

        c = Comment()
        c.author = AuthorWithIP(
            values['name'], values['email'], request.environ['REMOTE_ADDR']
        )
        c.subject = 'Re: %s' % media.title
        c.body = values['body']

        require_review = asbool(helpers.fetch_setting('req_comment_approval'))
        if not require_review:
            c.reviewed = True
            c.publishable = True

        media.comments.append(c)
        DBSession.add(media)
        email.send_comment_notification(media, c)

        if require_review:
            title = "Thanks for your comment!"
            text = "We will post it just as soon as a moderator approves it."
            add_transient_message('comment_posted', title, text)
            redirect(action='view', anchor='top')
        else:
            redirect(action='view', anchor='comment-%s' % c.id)
Exemple #6
0
def _verify_ftp_upload_integrity(file, file_url):
    """Download the file, and make sure that it matches the original.

    Returns True on success, and raises an Exception on failure.

    FIXME: Ideally we wouldn't have to download the whole file, we'd have
           some better way of verifying the integrity of the upload.
    """
    file.seek(0)
    old_hash = sha.new(file.read()).hexdigest()
    tries = 0

    # Try to download the file. Increase the number of retries, or the
    # timeout duration, if the server is particularly slow.
    # eg: Akamai usually takes 3-15 seconds to make an uploaded file
    #     available over HTTP.
    while tries < int(fetch_setting('ftp_upload_integrity_retries')):
        time.sleep(3)
        tries += 1
        try:
            temp_file = urllib2.urlopen(file_url)
            new_hash = sha.new(temp_file.read()).hexdigest()
            temp_file.close()

            # If the downloaded file matches, success! Otherwise, we can
            # be pretty sure that it got corrupted during FTP transfer.
            if old_hash == new_hash:
                return True
            else:
                raise FTPUploadException(
                    'Uploaded File and Downloaded File did not match')
        except urllib2.HTTPError, e:
            pass
Exemple #7
0
    def update_popularity(self):
        # FIXME: The current algorithm assumes that the earliest publication
        #        date is January 1, 2000.

        # In our ranking algorithm, being base_life_hours newer is equivalent
        # to having log_base times more votes.
        log_base = int(helpers.fetch_setting('popularity_decay_exponent'))
        base_life_hours = int(helpers.fetch_setting('popularity_decay_lifetime'))

        if self.is_published:
            base_life = base_life_hours * 3600
            delta = self.publish_on - datetime(2000, 1, 1) # since January 1, 2000
            t = delta.days * 86400 + delta.seconds
            popularity = math.log(self.likes+1, log_base) + t/base_life
            self.popularity_points = max(int(popularity), 0)
        else:
            self.popularity_points = 0
Exemple #8
0
def pick_media_file_player(files):
    """Return the best choice of files to play and which player to use.

    XXX: This method uses the very unsophisticated technique of assuming
         that if the client is capable of playing the container format, then
         the client should be able to play the tracks within the container,
         regardless of the codecs actually used. As such, admins would be
         well advised to use the lowest-common-denominator for their targeted
         clients when using files for consumption in an HTML5 player, and
         to use the standard codecs when encoding for Flash player use.

    :param files: :class:`~mediacore.model.media.MediaFile` instances.
    :type files: list
    :rtype: tuple
    :returns: A :class:`~mediacore.model.media.MediaFile` and a player name.

    """
    from mediacore.lib.helpers import fetch_setting
    player_type = fetch_setting('player_type')

    # Only proceed if this file is a playable type
    files = [file for file in files if file.type in ('audio', 'video')]

    # First, check if it's an embedded video from another site.
    for file in files:
        if file.container in external_embedded_containers:
            return file, 'embed'

    # If possible, return an applicable file and html5 player
    # Note that this is currently based only on the container type
    if player_type in ['best', 'html5']:
        for container, codecs in supported_html5_types():
            for file in files:
                if file.container == container:
                    return file, fetch_setting('html5_player')

    # If possible, return an applicable file and flash player
    if player_type in ['best', 'flash']:
        for file in files:
            if file.container in flash_supported_containers:
                return file, fetch_setting('flash_player')

    # No acceptable file/player combination could be found.
    return None, None
Exemple #9
0
def send_comment_notification(media, comment):
    send_to = fetch_setting("email_comment_posted")
    if not send_to:
        # Comment notification emails are disabled!
        return

    subject = "New Comment: %s" % comment.subject
    body = """A new comment has been posted!

Author: %s
Post: %s

Body: %s
""" % (
        comment.author.name,
        url_for(controller="media", action="view", slug=media.slug, qualified=True),
        strip_xhtml(line_break_xhtml(line_break_xhtml(comment.body))),
    )

    send(send_to, fetch_setting("email_send_from"), subject, body)
Exemple #10
0
def _store_media_file(file, file_name):
    """Copy the file to its permanent location and return its URI"""
    if asbool(fetch_setting('ftp_storage')):
        # Put the file into our FTP storage, return its URL
        return _store_media_file_ftp(file, file_name)
    else:
        # Store the file locally, return its path relative to the media dir
        file_path = os.path.join(config['media_dir'], file_name)
        permanent_file = open(file_path, 'w')
        shutil.copyfileobj(file, permanent_file)
        file.close()
        permanent_file.close()
        return file_name
Exemple #11
0
    def _save_media_obj(self, name, email, title, description, tags, file, url):
        # create our media object as a status-less placeholder initially
        media_obj = Media()
        media_obj.author = Author(name, email)
        media_obj.title = title
        media_obj.slug = get_available_slug(Media, title)
        media_obj.description = description
        media_obj.notes = fetch_setting('wording_additional_notes')
        media_obj.set_tags(tags)

        # Create a media object, add it to the media_obj, and store the file permanently.
        if file is not None:
            media_file = _add_new_media_file(media_obj, file.filename, file.file)
        else:
            media_file = MediaFile()
            url = unicode(url)
            embed = parse_embed_url(url)
            if embed:
                media_file.type = embed['type']
                media_file.container = embed['container']
                media_file.embed = embed['id']
                media_file.display_name = '%s ID: %s' % \
                    (embed['container'].capitalize(), media_file.embed)
            else:
                # Check for types we can play ourselves
                ext = os.path.splitext(url)[1].lower()[1:]
                container = guess_container_format(ext)
                if container in accepted_extensions():
                    media_file.type = guess_media_type(container)
                    media_file.container = container
                    media_file.url = url
                    media_file.display_name = os.path.basename(url)
                else:
                    # Trigger a validation error on the whole form.
                    raise formencode.Invalid('Please specify a URL or upload a file below.', None, None)
            media_obj.files.append(media_file)

        # Add the final changes.
        media_obj.update_status()
        DBSession.add(media_obj)
        DBSession.flush()

        create_default_thumbs_for(media_obj)

        return media_obj
Exemple #12
0
    def _save_media_obj(self, name, email, title, description, tags, file, url):
        # create our media object as a status-less placeholder initially
        media_obj = Media()
        media_obj.author = Author(name, email)
        media_obj.title = title
        media_obj.slug = get_available_slug(Media, title)
        media_obj.description = description
        media_obj.notes = fetch_setting('wording_additional_notes')
        media_obj.set_tags(tags)

        # Create a media object, add it to the media_obj, and store the file permanently.
        if file is not None:
            media_file = _add_new_media_file(media_obj, file.filename, file.file)
        else:
            # FIXME: For some reason the media.type isn't ever set to video
            #        during this request. On subsequent requests, when
            #        media_obj.update_type() is called, it is set properly.
            #        This isn't too serious an issue right now because
            #        it is called the first time a moderator goes to review
            #        the new media_obj.
            media_file = MediaFile()
            url = unicode(url)
            for type, info in external_embedded_containers.iteritems():
                match = info['pattern'].match(url)
                if match:
                    media_file.type = guess_media_type(type)
                    media_file.container = type
                    media_file.embed = match.group('id')
                    media_file.display_name = type.capitalize() + ' ID: ' + media_file.embed
                    break
            else:
                # Trigger a validation error on the whole form.
                raise formencode.Invalid('Please specify a URL or upload a file below.', None, None)
            media_obj.files.append(media_file)

        # Add the final changes.
        media_obj.update_type()
        media_obj.update_status()
        DBSession.add(media_obj)
        DBSession.flush()

        create_default_thumbs_for(media_obj)

        return media_obj
Exemple #13
0
    def __init__(self, *args, **kwargs):
        """Initialize the controller and hook in the external template, if any.

        These settings used are pulled from your INI config file:

            external_template
                Flag to enable or disable use of the external template
            external_template_name
                The name to load/save the external template as
            external_template_url
                The URL to pull the external template from
            external_template_timeout
                The number of seconds before the template should be refreshed

        See also :meth:`update_external_template` for more information.
        """
        tmpl_context.layout_template = config['layout_template']
        tmpl_context.external_template = None

        # Load Google Analytics settings into template context:
        try:
            tmpl_context.google_analytics_uacct = \
                helpers.fetch_setting('google_analytics_uacct')
        except:
            tmpl_context.google_analytics_uacct = None


        if asbool(config['external_template']):
            tmpl_name = config['external_template_name']
            tmpl_url = config['external_template_url']
            timeout = config['external_template_timeout']
            tmpl_context.external_template = tmpl_name

            try:
                self.update_external_template(tmpl_url, tmpl_name, timeout)
            except:
                # Catch the error because the external template is noncritical.
                # TODO: Add error reporting here.
                pass

        super(BaseController, self).__init__(*args, **kwargs)
Exemple #14
0
    def _save_media_obj(self, name, email, title, description, tags, file):
        # cope with anonymous posters
        if name is None:
            name = 'Anonymous'

        # create our media object as a status-less placeholder initially
        media_obj = Media()
        media_obj.author = Author(name, email)
        media_obj.title = title
        media_obj.slug = get_available_slug(Media, title)
        media_obj.description = helpers.clean_xhtml(description)
        media_obj.status = 'draft,unencoded,unreviewed'
        media_obj.notes = helpers.fetch_setting('wording_additional_notes')
        media_obj.set_tags(tags)

        # Create a media object, add it to the media_obj, and store the file permanently.
        media_file = _add_new_media_file(media_obj, file.filename, file.file)

        # Add the final changes.
        media_obj.update_type()
        media_obj.update_status()
        DBSession.add(media_obj)

        return media_obj
Exemple #15
0
    The default validator converts any HTML entities into Unicode in the
    submitted text.
    """
    validator = XHTMLEntityValidator

    def __init__(self, *args, **kwargs):
        """Initialize the widget.

        If no validator is specified at instantiation time, instantiates
        the default validator.
        """
        tw_TA.__init__(self, *args, **kwargs)
        if 'validator' not in kwargs:
            self.validator = self.validator()

tiny_mce_condition = lambda: fetch_setting('rich_text_editor') == 'tinymce'

class XHTMLTextArea(TextArea):
    validator = XHTMLValidator
    javascript = [
        ConditionalJSLink(
            link = url_for("/scripts/third-party/tiny_mce/tiny_mce.js"),
            condition = tiny_mce_condition,
        ),
        ConditionalJSSource("""window.addEvent('domready', function(){
tinyMCE.onAddEditor.add(function(t, ed){
	// Add an event for ajax form managers to call when dealing with these
	// elements, because they will often override the form's submit action
	ed.onInit.add(function(editor){
		ed.formElement.addEvent('beforeAjax', function(ev) {
			ed.save();
Exemple #16
0
def pick_media_file_player(files, browser=None, version=None, user_agent=None):
    """Return the best choice of files to play and which player to use.

    XXX: This method uses the very unsophisticated technique of assuming
         that if the client is capable of playing the container format, then
         the client should be able to play the tracks within the container,
         regardless of the codecs actually used. As such, admins would be
         well advised to use the lowest-common-denominator for their targeted
         clients when using files for consumption in an HTML5 player, and
         to use the standard codecs when encoding for Flash player use.

    :param files: :class:`~mediacore.model.media.MediaFile` instances.
    :type files: list
    :param browser: Optional browser name to bypass user agents altogether.
        See :attr:`native_browser_supported_containers` for possible values.
    :type browser: str or None
    :param version: Optional version number, used when a browser arg is given.
    :type version: float or None
    :param user_agent: Optional User-Agent header to use. Defaults to
        that of the current request.
    :type user_agent: str or None
    :returns: A :class:`~mediacore.model.media.MediaFile` and a player name.
    :rtype: tuple

    """
    from mediacore.lib.helpers import fetch_setting
    player_type = fetch_setting('player_type')

    if browser is None:
        browser, version = parse_user_agent_version(user_agent)

    support_html5 = player_type in ('best', 'html5')
    support_flash = player_type in ('best', 'flash') and \
        browser in flash_supported_browsers

    # Only proceed if this file is a playable type
    files = [file for file in files if file.type in (AUDIO, VIDEO)]

    # First, check if it's an embedded video from another site.
    if support_flash:
        for file in files:
            if file.container in external_embedded_containers:
                # TODO: Support vimeo and youtube in our jwplayer/etc
                return file, 'embed'

    # If possible, return an applicable file and html5 player
    # Note that this is currently based only on the container type
    if support_html5:
        for container, codecs in native_supported_types(browser, version):
            for file in files:
                if file.container == container:
                    return file, fetch_setting('html5_player')

    # If possible, return an applicable file and flash player
    if support_flash:
        for file in files:
            if file.container in flash_supported_containers:
                return file, fetch_setting('flash_player')

    # No acceptable file/player combination could be found.
    return None, None