def _update_settings(self, values): """Modify the settings associated with the given dictionary.""" for name, value in values.iteritems(): setting = tmpl_context.settings[name] if value is None: value = u'' else: value = unicode(value) if setting.value != value: setting.value = value DBSession.add(setting) DBSession.flush() # Clear the settings cache unless there are multiple processes. # We have no way of notifying the other processes that they need # to clear their caches too, so we've just gotta let it play out # until all the caches expire. if not request.environ.get('wsgi.multiprocess', False): app_globals.settings_cache.clear() else: # uWSGI provides an automagically included module # that we can use to call a graceful restart of all # the uwsgi processes. # http://projects.unbit.it/uwsgi/wiki/uWSGIReload try: import uwsgi uwsgi.reload() except ImportError: pass
def insert_settings(defaults): """Insert the given setting if they don't exist yet. XXX: Does not include any support for MultiSetting. This approach won't work for that. We'll need to use sqlalchemy-migrate. :type defaults: list :param defaults: Key and value pairs :rtype: list :returns: Any settings that have just been created. """ inserted = [] existing_settings = set(x[0] for x in DBSession.query(Setting.key) \ .filter(Setting.key \ .in_(key for key, value in defaults))) for key, value in defaults: if key in existing_settings: continue transaction = DBSession.begin_nested() try: s = Setting(key, value) DBSession.add(s) transaction.commit() inserted.append(s) except IntegrityError: transaction.rollback() if inserted: DBSession.commit() return inserted
def save(self, id, display_name, group_name, permissions, delete=None, **kwargs): """Save changes or create a new :class:`~mediacore.model.auth.Group` instance. :param id: Group ID. If ``"new"`` a new group is created. :type id: ``int`` or ``"new"`` :returns: Redirect back to :meth:`index` after successful save. """ group = fetch_row(Group, id) if delete: DBSession.delete(group) redirect(action='index', id=None) group.display_name = display_name group.group_name = group_name if permissions: query = DBSession.query(Permission).filter( Permission.permission_id.in_(permissions)) group.permissions = list(query.all()) else: group.permissions = [] DBSession.add(group) redirect(action='index', id=None)
def _add_new_media_file(media, original_filename, file): # FIXME: I think this will raise a KeyError if the uploaded # file doesn't have an extension. file_ext = os.path.splitext(original_filename)[1].lower()[1:] # set the file paths depending on the file type media_file = MediaFile() media_file.display_name = original_filename media_file.container = guess_container_format(file_ext) media_file.type = guess_media_type(media_file.container) # Small files are stored in memory and do not have a tmp file w/ fileno if hasattr(file, 'fileno'): media_file.size = os.fstat(file.fileno())[6] else: # The file may contain multi-byte characters, so we must seek instead of count chars file.seek(0, os.SEEK_END) media_file.size = file.tell() file.seek(0) # update media relations media.files.append(media_file) # add the media file (and its media, if new) to the database to get IDs DBSession.add(media_file) DBSession.flush() # copy the file to its permanent location file_name = '%d_%d_%s.%s' % (media.id, media_file.id, media.slug, file_ext) file_url = _store_media_file(file, file_name) media_file.file_name = file_name return media_file
def save(self, id, email_address, display_name, login_details, delete=None, **kwargs): """Save changes or create a new :class:`~mediacore.model.auth.User` instance. :param id: User ID. If ``"new"`` a new user is created. :type id: ``int`` or ``"new"`` :returns: Redirect back to :meth:`index` after successful save. """ user = fetch_row(User, id) if delete: DBSession.delete(user) redirect(action='index', id=None) user.display_name = display_name user.email_address = email_address user.user_name = login_details['user_name'] password = login_details['password'] if password is not None and password != '': user.password = password if login_details['group']: group = fetch_row(Group, login_details['group']) user.groups = [group] else: user.groups = [] DBSession.add(user) DBSession.flush() redirect(action='index', id=None)
def attach_and_store_media_file(media, media_file, file): """Given a Media object, a MediaFile object, and a file handle, attaches the MediaFile to the Media object, and saves the file to permanent storage. Adds the MediaFile to the database. """ # Small files are stored in memory and do not have a tmp file w/ fileno if hasattr(file, 'fileno'): media_file.size = os.fstat(file.fileno())[6] else: # The file may contain multi-byte characters, so we must seek instead of count chars file.seek(0, os.SEEK_END) media_file.size = file.tell() file.seek(0) # update media relations media.files.append(media_file) # add the media file (and its media, if new) to the database to get IDs DBSession.add(media_file) DBSession.flush() # copy the file to its permanent location file_name = '%d_%d_%s.%s' % (media.id, media_file.id, media.slug, media_file.container) file_url = store_media_file(file, file_name) if file_url: # The file has been stored remotely media_file.url = file_url else: # The file is stored locally and we just need its name media_file.file_name = file_name
def save(self, id, delete=None, **kwargs): """Save changes or create a category. See :class:`~mediacore.forms.admin.settings.categories.CategoryForm` for POST vars. :param id: Category ID :param delete: If true the category is to be deleted rather than saved. :type delete: bool :rtype: JSON dict :returns: success bool """ if tmpl_context.form_errors: if request.is_xhr: return dict(success=False, errors=tmpl_context.form_errors) else: # TODO: Add error reporting for users with JS disabled? return redirect(action="edit") cat = fetch_row(Category, id) if delete: DBSession.delete(cat) data = dict(success=True, id=cat.id, parent_options=unicode(category_form.c["parent_id"].display())) else: cat.name = kwargs["name"] cat.slug = get_available_slug(Category, kwargs["slug"], cat) if kwargs["parent_id"]: parent = fetch_row(Category, kwargs["parent_id"]) if parent is not cat and cat not in parent.ancestors(): cat.parent = parent else: cat.parent = None DBSession.add(cat) DBSession.flush() data = dict( success=True, id=cat.id, name=cat.name, slug=cat.slug, parent_id=cat.parent_id, parent_options=unicode(category_form.c["parent_id"].display()), depth=cat.depth(), row=unicode( category_row_form.display( action=url_for(id=cat.id), category=cat, depth=cat.depth(), first_child=True ) ), ) if request.is_xhr: return data else: redirect(action="index", id=None)
def podcast_from_feed(d, tags=False, save_files=False): # Assume not explicit explicit = False if 'itunes_explicit' in d['feed']: explicit = bool(d['feed']['itunes_explicit']) image = None if 'image' in d['feed']: image = d['feed']['image']['href'] title = u'' if 'title' in d['feed']: title = d['feed']['title'] description = u'' if 'summary' in d['feed']: description = d['feed']['summary'] subtitle = u'' if 'subtitle' in d['feed']: subtitle = d['feed']['subtitle'] slug = slugify(title) author_name = u"PLACEHOLDER NAME" author_email = u"*****@*****.**" podcast = Podcast() 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.explicit = explicit DBSession.add(podcast) DBSession.flush() # Create thumbs from image, or default thumbs created_images = False if image: temp_imagefile = tempfile.TemporaryFile() imagefile = urllib2.urlopen(image) temp_imagefile.write(imagefile.read()) temp_imagefile.seek(0) filename = urlparse.urlparse(image)[2] create_thumbs_for(podcast, temp_imagefile, filename) created_images = True if not created_images: create_default_thumbs_for(podcast) # Now add all of the entries for entry in d['entries']: media = media_from_entry(entry, tags, save_files) media.podcast = podcast return podcast
def prepareForUpload(self, environ, media_id, content_type, filename, filesize, meta=None, **kwargs): STORAGE_ENGINE = getStorageEngine() log.info("{self}.prepareForUpload({media_id},{content_type},{filename},{filesize})".format(**vars())) if not meta: meta = {} else: try: meta = json.loads(meta) except Exception as e: return {"success": False, "message": "Invalid JSON object given for `meta`"} media = fetch_row(Media, media_id) mediaFile = MediaFile() mediaFile.storage = STORAGE_ENGINE mediaFile.media = media mediaFile.media_id = media_id mediaFile.type = content_type mediaFile.meta = meta media.type = content_type mediaFile.display_name = filename mediaFile.size = filesize media.files.append(mediaFile) DBSession.add(media) DBSession.add(mediaFile) DBSession.flush() # This is to ensure that we don't allow any uploads that haven't been prepared for with prepareForUpload token = "".join(random.choice(string.ascii_uppercase + string.digits) for x in range(13)) upload_tokens[str(mediaFile.id)] = token return { "success": True, "id": mediaFile.id, "upload_url": "http://{host}{path}".format( host=environ["HTTP_HOST"], path=url_for( controller="upload_api/api/uploader", action="uploadFile", media_id=media_id, file_id=mediaFile.id ), ), "upload_headers": { "Content-Type": "application/octet-stream", "Cache-Control": "none", "X-File-Name": filename, "X-Upload-Token": token, }, "postprocess_url": "http://{host}{path}".format( host=environ["HTTP_HOST"], path=url_for( controller="upload_api/api/uploader", action="postprocessFile", media_id=media_id, file_id=mediaFile.id, ), ), }
def import_videos_from_feed(self, feed): for entry in feed.entry: youtube_id = self.id_for_entry(entry) if not self._should_import_video(youtube_id): continue media = self._import_video(entry) self._video_notifcation(youtube_id) if media: DBSession.add(media) DBSession.flush()
def fetch_and_create_multi_setting(key, value): multisettings = MultiSetting.query\ .filter(MultiSetting.key==key)\ .all() for ms in multisettings: if ms.value == value: return ms ms = MultiSetting(key, value) DBSession.add(ms) return ms
def example(cls, **kwargs): defaults = dict( name=u'baz_users', display_name=u'Baz Users', ) defaults.update(kwargs) group = Group(**defaults) DBSession.add(group) DBSession.flush() return group
def example(cls, **kwargs): defaults = dict( name = u'baz_users', display_name = u'Baz Users', ) defaults.update(kwargs) group = Group(**defaults) DBSession.add(group) DBSession.flush() return group
def save_thumb(self, id, thumb, **kwargs): """Save a thumbnail uploaded with :class:`~mediacore.forms.admin.ThumbForm`. :param id: Media ID. If ``"new"`` a new Media stub is created with :func:`~mediacore.model.media.create_media_stub`. :type id: ``int`` or ``"new"`` :param file: The uploaded file :type file: :class:`cgi.FieldStorage` or ``None`` :rtype: JSON dict :returns: success bool message Error message, if unsuccessful id The :attr:`~mediacore.model.media.Media.id` which is important if a new media has just been created. """ if id == 'new': media = create_media_stub() else: media = fetch_row(Media, id) try: # Create thumbs img = Image.open(thumb.file) if id == 'new': DBSession.add(media) DBSession.flush() # TODO: Allow other formats? for key, xy in config['thumb_sizes'][media._thumb_dir].iteritems(): thumb_path = helpers.thumb_path(media, key) thumb_img = helpers.resize_thumb(img, xy) thumb_img.save(thumb_path) # Backup the original image just for kicks backup_type = os.path.splitext(thumb.filename)[1].lower()[1:] backup_path = helpers.thumb_path(media, 'orig', ext=backup_type) backup_file = open(backup_path, 'w+b') thumb.file.seek(0) shutil.copyfileobj(thumb.file, backup_file) thumb.file.close() backup_file.close() success = True message = None except IOError: success = False message = 'Unsupported image type' except Exception, e: success = False message = e.message
def example(cls, **kwargs): defaults = dict( name=u'foo', description=u'foo permission', groups=None, ) defaults.update(kwargs) permission = Permission(**defaults) DBSession.add(permission) DBSession.flush() return permission
def popularity_save(self, **kwargs): """Save :class:`~mediacore.forms.admin.settings.PopularityForm`. Updates the popularity for every media item based on the submitted values. """ self._save(popularity_form, values=kwargs) for m in Media.query: m.update_popularity() DBSession.add(m) redirect(action='popularity')
def _update_settings(self, values): """Modify the settings associated with the given dictionary.""" for name, value in values.iteritems(): if value is None: value = u'' else: value = unicode(value) if self.settings[name].value != value: self.settings[name].value = value DBSession.add(self.settings[name]) DBSession.flush()
def example(cls, **kwargs): defaults = dict( name=u'foo', description = u'foo permission', groups = None, ) defaults.update(kwargs) permission = Permission(**defaults) DBSession.add(permission) DBSession.flush() return permission
def example(cls, **kwargs): media = Media() defaults = dict(title=u"Foo Media", author=Author(u"Joe", u"*****@*****.**"), type=VIDEO) defaults.update(kwargs) defaults.setdefault("slug", get_available_slug(Media, defaults["title"])) for key, value in defaults.items(): assert hasattr(media, key) setattr(media, key, value) DBSession.add(media) DBSession.flush() return media
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: self._delete_media(media) DBSession.commit() 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' and not has_thumbs(media): 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)
def save_display(self, **kwargs): """Save :class:`~mediacore.forms.admin.settings.DisplayForm`.""" player_type = c.settings['player_type'].value self._save(display_form, **kwargs) # If the player_type changes, we must update the Media.encoded flag, # since some things may play now and/or not play anymore with the # new setting. if player_type != c.settings['player_type'].value: for m in Media.query.options(orm.eagerload('files')): m.update_status() DBSession.add(m) redirect(action='display')
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)
def edit_file(self, id, file_id, file_type=None, delete=None, **kwargs): """Save action for the :class:`~mediacore.forms.admin.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) data = dict(success=False) try: file = [file for file in media.files if file.id == int(file_id)][0] except IndexError: data['message'] = 'File no longer exists.' if file_type: file.type = file_type DBSession.add(file) data['success'] = True elif delete: file_path = file.file_path DBSession.delete(file) transaction.commit() if file_path: helpers.delete_files([file_path], 'media') media = fetch_row(Media, id) data['success'] = True else: data['message'] = 'No action to perform.' if data['success']: data['file_type'] = file.type media.update_type() media.update_status() DBSession.add(media) DBSession.flush() # 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
def add_file(self, id, file=None, url=None, **kwargs): """Save action for the :class:`~mediacore.forms.admin.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. :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.admin.media.EditFileForm` for this file. status_form The rendered XHTML :class:`~mediacore.forms.admin.media.UpdateStatusForm` """ if id == 'new': media = Media() user = request.environ['repoze.who.identity']['user'] media.author = Author(user.display_name, user.email_address) # Create a temp stub until we can set it to something meaningful timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') media.title = u'Temporary stub %s' % timestamp media.slug = get_available_slug(Media, '_stub_' + timestamp) DBSession.add(media) DBSession.flush() else: media = fetch_row(Media, id) try: media_file = add_new_media_file(media, file, url) except Invalid, e: DBSession.rollback() data = dict( success = False, message = e.message, )
def example(cls, **kwargs): category = Category() defaults = dict(name=u'Foo', parent_id=0) defaults.update(kwargs) defaults.setdefault('slug', get_available_slug(Category, defaults['name'])) for key, value in defaults.items(): assert hasattr(category, key) setattr(category, key, value) DBSession.add(category) DBSession.flush() return category
def get_videos_from_feed(feed): for entry in feed.entry: # Occasionally, there are issues with a video in a feed # not being available (region restrictions, etc) # If this happens, just move along. if not entry.media.player: log.debug('Video Feed Error: No player URL? %s' % entry) continue video_url = unicode(entry.media.player.url, "utf-8") if video_already_has_media_file(video_url): continue categories = kwargs.get('youtube.categories', None) tags = kwargs.get('youtube.tags', None) media = fetch_row(Media, u'new') user = request.environ['repoze.who.identity']['user'] media.author = Author(user.display_name, user.email_address) media.reviewed = True media.title = unicode(entry.media.title.text, "utf-8") if entry.media.description.text: encoded_description = unicode(entry.media.description.text, "utf-8") media.description = clean_xhtml(encoded_description) media.slug = get_available_slug(Media, media.title, media) if tags: media.set_tags(unicode(tags)) if categories: if not isinstance(categories, list): categories = [categories] media.set_categories(categories) try: media_file = add_new_media_file(media, url=video_url) except StorageError, e: log.debug('Video Feed Error: Error storing video: %s at %s' \ % e.message, video_url) continue if not has_thumbs(media): create_default_thumbs_for(media) media.title = media_file.display_name media.update_status() if auto_publish: media.reviewed = 1 media.encoded = 1 media.publishable = 1 media.created_on = datetime.now() media.modified_on = datetime.now() media.publish_on = datetime.now() DBSession.add(media) DBSession.flush()
def createMediaItem(self, title, author_email=None, author_name=None, slug=None, tags=None, podcast_id=None, category_ids=None, meta=None, **kwargs): mediaItem = Media() log.info("createMediaItem({title})".format(title=title)) if not slug: slug = title elif slug.startswith('_stub_'): slug = slug[len('_stub_'):] if slug != mediaItem.slug: mediaItem.slug = get_available_slug(Media, slug, mediaItem) if podcast_id: podcast_id = int(podcast_id) else: podcast_id = 0 if not meta: meta = {} else: try: meta = json.loads(meta) except Exception as e: return { "success": False, "message": "Invalid JSON object given for `meta`" } mediaItem.title = title mediaItem.author = Author(author_name or "No Author", author_email or "No Email") mediaItem.podcast_id = podcast_id or None mediaItem.set_tags(tags) mediaItem.set_categories(category_ids) mediaItem.update_status() mediaItem.meta = meta DBSession.add(mediaItem) DBSession.flush() return {"success": True, "id": mediaItem.id}
def example(cls, **kwargs): user = User() defaults = dict( user_name = u'joe', email_address = u'*****@*****.**', display_name = u'Joe Smith', created = datetime.now(), ) defaults.update(kwargs) for key, value in defaults.items(): setattr(user, key, value) DBSession.add(user) DBSession.flush() return user
def example(cls, **kwargs): user = User() defaults = dict( user_name=u'joe', email_address=u'*****@*****.**', display_name=u'Joe Smith', created=datetime.now(), ) defaults.update(kwargs) for key, value in defaults.items(): setattr(user, key, value) DBSession.add(user) DBSession.flush() return user
def example(cls, **kwargs): media = Media() defaults = dict( title=u'Foo Media', author=Author(u'Joe', u'*****@*****.**'), type = None, ) defaults.update(kwargs) defaults.setdefault('slug', get_available_slug(Media, defaults['title'])) for key, value in defaults.items(): assert hasattr(media, key) setattr(media, key, value) DBSession.add(media) DBSession.flush() return media
def example(cls, **kwargs): category = Category() defaults = dict( name=u'Foo', parent_id=0 ) defaults.update(kwargs) defaults.setdefault('slug', get_available_slug(Category, defaults['name'])) for key, value in defaults.items(): assert hasattr(category, key) setattr(category, key, value) DBSession.add(category) DBSession.flush() return category
def example(cls, **kwargs): media = Media() defaults = dict( title=u'Foo Media', author=Author(u'Joe', u'*****@*****.**'), type=None, ) defaults.update(kwargs) defaults.setdefault('slug', get_available_slug(Media, defaults['title'])) for key, value in defaults.items(): assert hasattr(media, key) setattr(media, key, value) DBSession.add(media) DBSession.flush() return media
def save_thumb(self, id, thumb, **kwargs): """Save a thumbnail uploaded with :class:`~mediacore.forms.admin.ThumbForm`. :param id: Media ID. If ``"new"`` a new Media stub is created. :type id: ``int`` or ``"new"`` :param file: The uploaded file :type file: :class:`cgi.FieldStorage` or ``None`` :rtype: JSON dict :returns: success bool message Error message, if unsuccessful id The :attr:`~mediacore.model.media.Media.id` which is important if a new media has just been created. """ if id == 'new': media = Media() user = req.perm.user media.author = Author(user.display_name, user.email_address) media.title = os.path.basename(thumb.filename) media.slug = get_available_slug(Media, '_stub_' + media.title) DBSession.add(media) DBSession.flush() else: media = fetch_row(Media, id) try: # Create JPEG thumbs create_thumbs_for(media, thumb.file, thumb.filename) success = True message = None except IOError, e: success = False if id == 'new': DBSession.delete(media) if e.errno == 13: message = _('Permission denied, cannot write file') elif e.message == 'cannot identify image file': message = _('Unsupported image type: %s') \ % os.path.splitext(thumb.filename)[1].lstrip('.') elif e.message == 'cannot read interlaced PNG files': message = _('Interlaced PNGs are not supported.') else: raise
def save_thumb(self, id, thumb, **kwargs): """Save a thumbnail uploaded with :class:`~mediacore.forms.admin.ThumbForm`. :param id: Media ID. If ``"new"`` a new Media stub is created. :type id: ``int`` or ``"new"`` :param file: The uploaded file :type file: :class:`cgi.FieldStorage` or ``None`` :rtype: JSON dict :returns: success bool message Error message, if unsuccessful id The :attr:`~mediacore.model.media.Media.id` which is important if a new media has just been created. """ if id == 'new': media = Media() user = request.environ['repoze.who.identity']['user'] media.author = Author(user.display_name, user.email_address) media.title = os.path.basename(thumb.filename) media.slug = get_available_slug(Media, '_stub_' + media.title) DBSession.add(media) DBSession.flush() else: media = fetch_row(Media, id) try: # Create JPEG thumbs create_thumbs_for(media, thumb.file, thumb.filename) success = True message = None except IOError, e: success = False if id == 'new': DBSession.delete(media) if e.errno == 13: message = _('Permission denied, cannot write file') elif e.message == 'cannot identify image file': message = _('Unsupport image type: %s') \ % os.path.splitext(thumb.filename)[1].lstrip('.') elif e.message == 'cannot read interlaced PNG files': message = _('Interlaced PNGs are not supported.') else: raise
def createMediaItem( self, title, author_email=None, author_name=None, slug=None, tags=None, podcast_id=None, category_ids=None, meta=None, **kwargs ): mediaItem = Media() log.info("createMediaItem({title})".format(title=title)) if not slug: slug = title elif slug.startswith("_stub_"): slug = slug[len("_stub_") :] if slug != mediaItem.slug: mediaItem.slug = get_available_slug(Media, slug, mediaItem) if podcast_id: podcast_id = int(podcast_id) else: podcast_id = 0 if not meta: meta = {} else: try: meta = json.loads(meta) except Exception as e: return {"success": False, "message": "Invalid JSON object given for `meta`"} mediaItem.title = title mediaItem.author = Author(author_name or "No Author", author_email or "No Email") mediaItem.podcast_id = podcast_id or None mediaItem.set_tags(tags) mediaItem.set_categories(category_ids) mediaItem.update_status() mediaItem.meta = meta DBSession.add(mediaItem) DBSession.flush() return {"success": True, "id": mediaItem.id}
def save_edit(self, id, body, **kwargs): """Save an edit from :class:`~mediacore.forms.admin.comments.EditCommentForm`. :param id: Comment ID :type id: ``int`` :rtype: JSON dict :returns: success bool body The edited comment body after validation/filtering """ comment = fetch_row(Comment, id) comment.body = body DBSession.add(comment) return dict(success=True, body=comment.body)
def save(self, id, email_address, display_name, login_details, delete=None, **kwargs): """Save changes or create a new :class:`~mediacore.model.auth.User` instance. :param id: User ID. If ``"new"`` a new user is created. :type id: ``int`` or ``"new"`` :returns: Redirect back to :meth:`index` after successful save. """ user = fetch_row(User, id) if delete: DBSession.delete(user) redirect(action='index', id=None) user.display_name = display_name user.email_address = email_address user.user_name = login_details['user_name'] password = login_details['password'] if password is not None and password != '': user.password = password if login_details['group']: group = fetch_row(Group, login_details['group']) user.groups = [group] else: user.groups = [] DBSession.add(user) # Check if we're changing the logged in user's own password logged_in_user = request.environ['repoze.who.identity']['user'] if user.user_id == logged_in_user.user_id \ and password is not None and password != '': DBSession.commit() # repoze.who sees the Unauthorized response and clears the cookie, # forcing a fresh login with the new password raise webob.exc.HTTPUnauthorized().exception redirect(action='index', id=None)
def save_status(self, id, status, ids=None, **kwargs): """Approve or delete a comment or comments. :param id: A :attr:`~mediacore.model.comments.Comment.id` if we are acting on a single comment, or ``"bulk"`` if we should refer to ``ids``. :type id: ``int`` or ``"bulk"`` :param status: ``"approve"`` or ``"trash"`` depending on what action the user requests. :param ids: An optional string of IDs separated by commas. :type ids: ``unicode`` or ``None`` :rtype: JSON dict :returns: success bool ids A list of :attr:`~mediacore.model.comments.Comment.id` that have changed. """ if id != 'bulk': ids = [id] if not isinstance(ids, list): ids = [ids] if status == 'approve': publishable = True elif status == 'trash': publishable = False else: # XXX: This form should never be submitted without a valid status. raise AssertionError('Unexpected status: %r' % status) comments = Comment.query.filter(Comment.id.in_(ids)).all() for comment in comments: comment.reviewed = True comment.publishable = publishable DBSession.add(comment) DBSession.flush() if request.is_xhr: return dict(success=True, ids=ids) else: redirect(action='index')
def save(self, id, slug, title, author_name, author_email, description, notes, details, 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 = helpers.thumb_paths(media) 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) transaction.commit() helpers.delete_files(file_paths, 'media') redirect(action='index', id=None) 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.duration = details['duration'] # validator converts hh:mm:ss to secs media.podcast_id = podcast media.set_tags(tags) media.set_categories(categories) media.update_status() DBSession.add(media) DBSession.flush() if id == 'new': helpers.create_default_thumbs_for(media) redirect(action='edit', id=media.id)
def popularity_save(self, **kwargs): """Save :class:`~mediacore.forms.admin.settings.PopularityForm`. Updates the popularity for every media item based on the submitted values. """ self._save(popularity_form, values=kwargs) # ".util.calculate_popularity()" uses the popularity settings from # the request.settings which are only updated when a new request # comes in. # update the settings manually so the popularity is actually updated # correctly. for key in ('popularity_decay_exponent', 'popularity_decay_lifetime'): request.settings[key] = kwargs['popularity.'+key] for m in Media.query: m.update_popularity() DBSession.add(m) redirect(action='popularity')
def uploadFile(self, environ, media_id, file_id, **kwargs): log.info("uploadFile({media_id},{file_id})".format(**vars())) media = fetch_row(Media, media_id) mediaFile = fetch_row(MediaFile, file_id) # Requests not carrying a valid X-Upload-Token must be rejected immediately if 'HTTP_X_UPLOAD_TOKEN' not in environ or str( file_id) not in upload_tokens.keys(): raise webob.exc.HTTPForbidden().exception elif not environ['HTTP_X_UPLOAD_TOKEN'] == upload_tokens[str(file_id)]: raise webob.exc.HTTPForbidden().exception STORAGE_ENGINE = getStorageEngine() class FileEntry(object): def __init__(self, file, name=None): self.file = file self.filename = name if name else file.name unique_id = STORAGE_ENGINE.store(media_file=mediaFile, file=FileEntry( environ['wsgi.input'], mediaFile.display_name)) try: STORAGE_ENGINE.transcode(mediaFile) except Exception: log.debug('Engine %r unsuitable for transcoding %r', STORAGE_ENGINE, mediaFile) mediaFile.container = os.path.splitext(mediaFile.display_name)[1][1:] if unique_id: mediaFile.unique_id = unique_id DBSession.add(mediaFile) DBSession.flush() del upload_tokens[str(file_id)] # Ideally we'd determine information about the uploaded media file and return it here. return {}
def save_edit(self, id, body, **kwargs): """Save an edit from :class:`~mediacore.forms.admin.comments.EditCommentForm`. :param id: Comment ID :type id: ``int`` :rtype: JSON dict :returns: success bool body The edited comment body after validation/filtering """ comment = fetch_row(Comment, id) comment.body = body DBSession.add(comment) return dict( success=True, body=comment.body, )
def save(self, id, delete=False, **kwargs): """Save changes or create a tag. See :class:`~mediacore.forms.admin.settings.tags.TagForm` for POST vars. :param id: Tag ID :rtype: JSON dict :returns: success bool """ if tmpl_context.form_errors: if request.is_xhr: return dict(success=False, errors=tmpl_context.form_errors) else: # TODO: Add error reporting for users with JS disabled? return redirect(action='edit') tag = fetch_row(Tag, id) if delete: DBSession.delete(tag) data = dict(success=True, id=tag.id) else: tag.name = kwargs['name'] tag.slug = get_available_slug(Tag, kwargs['slug'], tag) DBSession.add(tag) DBSession.flush() data = dict( success = True, id = tag.id, name = tag.name, slug = tag.slug, row = unicode(tag_row_form.display(tag=tag)), ) if request.is_xhr: return data else: redirect(action='index', id=None)
def insert_settings(defaults): """Insert the given setting if they don't exist yet. XXX: Does not include any support for MultiSetting. This approach won't work for that. We'll need to use sqlalchemy-migrate. :type defaults: list :param defaults: Key and value pairs :rtype: list :returns: Any settings that have just been created. """ inserted = [] try: settings_query = DBSession.query(Setting.key)\ .filter(Setting.key.in_([key for key, value in defaults])) existing_settings = set(x[0] for x in settings_query) except ProgrammingError: # If we are running paster setup-app on a fresh database with a # plugin which tries to use this function every time the # Environment.loaded event fires, the settings table will not # exist and this exception will be thrown, but its safe to ignore. # The settings will be created the next time the event fires, # which will likely be the first time the app server starts up. return inserted for key, value in defaults: if key in existing_settings: continue transaction = DBSession.begin_nested() try: s = Setting(key, value) DBSession.add(s) transaction.commit() inserted.append(s) except IntegrityError: transaction.rollback() if inserted: DBSession.commit() return inserted
def prepareForUpload(self, environ, media_id, content_type, filename, filesize, meta=None, **kwargs): STORAGE_ENGINE = getStorageEngine() log.info( "prepareForUpload({media_id},{content_type},{filename},{filesize})" .format(**vars())) if not meta: meta = {} else: try: meta = json.loads(meta) except Exception as e: return { "success": False, "message": "Invalid JSON object given for `meta`" } media = fetch_row(Media, media_id) mediaFile = MediaFile() mediaFile.storage = STORAGE_ENGINE mediaFile.media = media mediaFile.media_id = media_id mediaFile.type = content_type mediaFile.meta = meta media.type = content_type mediaFile.display_name = filename mediaFile.size = filesize media.files.append(mediaFile) DBSession.add(media) DBSession.add(mediaFile) DBSession.flush() # This is to ensure that we don't allow any uploads that haven't been prepared for with prepareForUpload token = ''.join( random.choice(string.ascii_uppercase + string.digits) for x in range(13)) upload_tokens[str(mediaFile.id)] = token return { "success": True, "id": mediaFile.id, "upload_url": "http://{host}{path}".format( host=environ['HTTP_HOST'], path=url_for(controller='upload_api/api/uploader', action='uploadFile', media_id=media_id, file_id=mediaFile.id)), "upload_headers": { "Content-Type": "application/octet-stream", "Cache-Control": "none", "X-File-Name": filename, "X-Upload-Token": token }, "postprocess_url": "http://{host}{path}".format( host=environ['HTTP_HOST'], path=url_for(controller='upload_api/api/uploader', action='postprocessFile', media_id=media_id, file_id=mediaFile.id)) }
def media_from_entry(e, tags=False, save_files=False): # Get tags as a list of unicode objects. tags = [t['term'] for t in e['tags']] # Assume not explicit. explicit = 0 if 'itunes_explicit' in e: explicit = e['itunes_explicit'] # Find the duration, if it exists duration = u'' if 'itunes_duration' in e: try: duration = e['itunes_duration'] duration = duration_to_seconds(duration) except ValueError: duration = None # Find the first <img> tag in the summary, if there is one image = None m = img_regex.match(e['summary']) if m is not None: image = m.group(1)[1:-1] title = e['title'] slug = slugify(title) author_name = u"PLACEHOLDER NAME" author_email = u"*****@*****.**" if 'author_detail' in e: if 'name' in e['author_detail']: author_name = e['author_detail']['name'] if 'email' in e['author_detail']: author_email = e['author_detail']['email'] year, month, day, hour, minute, second = e['updated_parsed'][:6] updated = datetime(year, month, day, hour, minute, second) media = Media() media.slug = get_available_slug(Media, slug, media) media.title = e['title'] media.author = Author(author_name, author_email) media.description = e['summary'] media.notes = u'' if tags: media.set_tags(tags) else: media.set_categories(tags) media.publish_on = updated media.created_on = updated media.publishable = True media.reviewed = True media.duration = duration DBSession.add(media) DBSession.flush() # Create thumbs from image, or default thumbs created_images = False if image: temp_imagefile = tempfile.TemporaryFile() imagefile = urllib2.urlopen(image) temp_imagefile.write(imagefile.read()) temp_imagefile.seek(0) filename = urlparse.urlparse(image)[2] create_thumbs_for(media, temp_imagefile, filename) created_images = True if not created_images: create_default_thumbs_for(media) print "Loaded episode:", media # now add all of the files. for enc in e['enclosures']: mf = media_file_from_enclosure(enc, media, save_files) print "Loaded media file:", mf media.update_status() return media
def add_file(self, id, file=None, url=None, **kwargs): """Save action for the :class:`~mediacore.forms.admin.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. :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.admin.media.EditFileForm` for this file. status_form The rendered XHTML :class:`~mediacore.forms.admin.media.UpdateStatusForm` """ if id == 'new': media = Media() user = request.environ['repoze.who.identity']['user'] media.author = Author(user.display_name, user.email_address) # Create a temp stub until we can set it to something meaningful timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') media.title = u'Temporary stub %s' % timestamp media.slug = get_available_slug(Media, '_stub_' + timestamp) media.reviewed = True DBSession.add(media) DBSession.flush() else: media = fetch_row(Media, id) media_file = add_new_media_file(media, file, url) if media.slug.startswith('_stub_'): media.title = media_file.display_name media.slug = get_available_slug(Media, '_stub_' + media.title) # The thumbs may have been created already by add_new_media_file if id == 'new' and not has_thumbs(media): create_default_thumbs_for(media) media.update_status() # 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)) data = dict( success = True, media_id = media.id, file_id = media_file.id, file_type = media_file.type, edit_form = edit_form_xhtml, status_form = status_form_xhtml, title = media.title, slug = media.slug, description = media.description, link = url_for(action='edit', id=media.id), duration = helpers.duration_from_seconds(media.duration), ) return data
def save(self, id, delete=None, **kwargs): """Save changes or create a category. See :class:`~mediacore.forms.admin.settings.categories.CategoryForm` for POST vars. :param id: Category ID :param delete: If true the category is to be deleted rather than saved. :type delete: bool :rtype: JSON dict :returns: success bool """ if tmpl_context.form_errors: if request.is_xhr: return dict(success=False, errors=tmpl_context.form_errors) else: # TODO: Add error reporting for users with JS disabled? return redirect(action='edit') cat = fetch_row(Category, id) if delete: DBSession.delete(cat) data = dict( success = True, id = cat.id, parent_options = unicode(category_form.c['parent_id'].display()), ) else: cat.name = kwargs['name'] cat.slug = get_available_slug(Category, kwargs['slug'], cat) if kwargs['parent_id']: parent = fetch_row(Category, kwargs['parent_id']) if parent is not cat and cat not in parent.ancestors(): cat.parent = parent else: cat.parent = None DBSession.add(cat) DBSession.flush() data = dict( success = True, id = cat.id, name = cat.name, slug = cat.slug, parent_id = cat.parent_id, parent_options = unicode(category_form.c['parent_id'].display()), depth = cat.depth(), row = unicode(category_row_form.display( action = url_for(id=cat.id), category = cat, depth = cat.depth(), first_child = True, )), ) if request.is_xhr: return data else: redirect(action='index', id=None)