# Copyright (c) 2011, 2012 Free Software Foundation # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # This project incorporates work covered by the following copyright and permission notice: # Copyright (c) 2009, Julien Fache # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # * Neither the name of the author nor the names of other # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. # Copyright (c) 2011, 2012 Free Software Foundation # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . """Feed to Gstudio command module""" import sys from datetime import datetime from optparse import make_option from django.utils.html import strip_tags from django.db.utils import IntegrityError from django.utils.encoding import smart_str from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.utils.text import truncate_words from django.template.defaultfilters import slugify from django.core.management.base import CommandError from django.core.management.base import LabelCommand from gstudio import __version__ from gstudio.models import Nodetype from gstudio.models import Metatype from gstudio.managers import PUBLISHED from gstudio.signals import disconnect_gstudio_signals class Command(LabelCommand): """Command object for importing a RSS or Atom feed into Gstudio.""" help = 'Import a RSS or Atom feed into Gstudio.' label = 'feed url' args = 'url' option_list = LabelCommand.option_list + ( make_option('--noautoexcerpt', action='store_false', dest='auto_excerpt', default=True, help='Do NOT generate an excerpt if not present.'), make_option('--author', dest='author', default='', help='All imported nodetypes belong to specified author'), make_option('--metatype-is-tag', action='store_true', dest='metatype-tag', default=False, help='Store metatypes as tags'), ) SITE = Site.objects.get_current() def __init__(self): """Init the Command and add custom styles""" super(Command, self).__init__() self.style.TITLE = self.style.SQL_FIELD self.style.STEP = self.style.SQL_COLTYPE self.style.ITEM = self.style.HTTP_INFO disconnect_gstudio_signals() def write_out(self, message, verbosity_level=1): """Convenient method for outputing""" if self.verbosity and self.verbosity >= verbosity_level: sys.stdout.write(smart_str(message)) sys.stdout.flush() def handle_label(self, url, **options): try: import feedparser except ImportError: raise CommandError('You need to install the feedparser ' \ 'module to run this command.') self.verbosity = int(options.get('verbosity', 1)) self.auto_excerpt = options.get('auto_excerpt', True) self.default_author = options.get('author') self.metatype_tag = options.get('metatype-tag', False) if self.default_author: try: self.default_author = User.objects.get( username=self.default_author) except User.DoesNotExist: raise CommandError('Invalid username for default author') self.write_out(self.style.TITLE( 'Starting importation of %s to Gstudio %s:\n' % (url, __version__))) feed = feedparser.parse(url) self.import_nodetypes(feed.nodetypes) def import_nodetypes(self, feed_nodetypes): """Import nodetypes""" for feed_nodetype in feed_nodetypes: self.write_out('> %s... ' % feed_nodetype.title) creation_date = datetime(*feed_nodetype.date_parsed[:6]) slug = slugify(feed_nodetype.title)[:255] if Nodetype.objects.filter(creation_date__year=creation_date.year, creation_date__month=creation_date.month, creation_date__day=creation_date.day, slug=slug): self.write_out(self.style.NOTICE( 'SKIPPED (already imported)\n')) continue metatypes = self.import_metatypes(feed_nodetype) nodetype_dict = {'title': feed_nodetype.title[:255], 'content': feed_nodetype.description, 'excerpt': feed_nodetype.get('summary'), 'status': PUBLISHED, 'creation_date': creation_date, 'start_publication': creation_date, 'last_update': datetime.now(), 'slug': slug} if not nodetype_dict['excerpt'] and self.auto_excerpt: nodetype_dict['excerpt'] = truncate_words( strip_tags(feed_nodetype.description), 50) if self.metatype_tag: nodetype_dict['tags'] = self.import_tags(metatypes) nodetype = Nodetype(**nodetype_dict) nodetype.save() nodetype.metatypes.add(*metatypes) nodetype.sites.add(self.SITE) if self.default_author: nodetype.authors.add(self.default_author) elif feed_nodetype.get('author_detail'): try: user = User.objects.create_user( slugify(feed_nodetype.author_detail.get('name')), feed_nodetype.author_detail.get('email', '')) except IntegrityError: user = User.objects.get( username=slugify(feed_nodetype.author_detail.get('name'))) nodetype.authors.add(user) self.write_out(self.style.ITEM('OK\n')) def import_metatypes(self, feed_nodetype): metatypes = [] for cat in feed_nodetype.get('tags', ''): metatype, created = Metatype.objects.get_or_create( slug=slugify(cat.term), defaults={'title': cat.term}) metatypes.append(metatype) return metatypes def import_tags(self, metatypes): tags = [] for cat in metatypes: if len(cat.title.split()) > 1: tags.append('"%s"' % slugify(cat.title).replace('-', ' ')) else: tags.append(slugify(cat.title).replace('-', ' ')) return ', '.join(tags)