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 = {}, )
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)
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)
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
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)
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
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
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
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)
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
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
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
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)
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
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();
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