diff options
Diffstat (limited to 'webapp/django/contrib/syndication/feeds.py')
-rw-r--r-- | webapp/django/contrib/syndication/feeds.py | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/webapp/django/contrib/syndication/feeds.py b/webapp/django/contrib/syndication/feeds.py new file mode 100644 index 0000000000..a1f08107f9 --- /dev/null +++ b/webapp/django/contrib/syndication/feeds.py @@ -0,0 +1,178 @@ +from datetime import datetime, timedelta + +from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist +from django.template import loader, Template, TemplateDoesNotExist +from django.contrib.sites.models import Site, RequestSite +from django.utils import feedgenerator +from django.utils.tzinfo import FixedOffset +from django.utils.encoding import smart_unicode, iri_to_uri +from django.conf import settings +from django.template import RequestContext + +def add_domain(domain, url): + if not (url.startswith('http://') or url.startswith('https://')): + # 'url' must already be ASCII and URL-quoted, so no need for encoding + # conversions here. + url = iri_to_uri(u'http://%s%s' % (domain, url)) + return url + +class FeedDoesNotExist(ObjectDoesNotExist): + pass + +class Feed(object): + item_pubdate = None + item_enclosure_url = None + feed_type = feedgenerator.DefaultFeed + title_template = None + description_template = None + + def __init__(self, slug, request): + self.slug = slug + self.request = request + self.feed_url = request.path + self.title_template_name = self.title_template or ('feeds/%s_title.html' % slug) + self.description_template_name = self.description_template or ('feeds/%s_description.html' % slug) + + def item_link(self, item): + try: + return item.get_absolute_url() + except AttributeError: + raise ImproperlyConfigured, "Give your %s class a get_absolute_url() method, or define an item_link() method in your Feed class." % item.__class__.__name__ + + def __get_dynamic_attr(self, attname, obj, default=None): + try: + attr = getattr(self, attname) + except AttributeError: + return default + if callable(attr): + # Check func_code.co_argcount rather than try/excepting the + # function and catching the TypeError, because something inside + # the function may raise the TypeError. This technique is more + # accurate. + if hasattr(attr, 'func_code'): + argcount = attr.func_code.co_argcount + else: + argcount = attr.__call__.func_code.co_argcount + if argcount == 2: # one argument is 'self' + return attr(obj) + else: + return attr() + return attr + + def feed_extra_kwargs(self, obj): + """ + Returns an extra keyword arguments dictionary that is used when + initializing the feed generator. + """ + return {} + + def item_extra_kwargs(self, item): + """ + Returns an extra keyword arguments dictionary that is used with + the `add_item` call of the feed generator. + """ + return {} + + def get_object(self, bits): + return None + + def get_feed(self, url=None): + """ + Returns a feedgenerator.DefaultFeed object, fully populated, for + this feed. Raises FeedDoesNotExist for invalid parameters. + """ + if url: + bits = url.split('/') + else: + bits = [] + + try: + obj = self.get_object(bits) + except ObjectDoesNotExist: + raise FeedDoesNotExist + + if Site._meta.installed: + current_site = Site.objects.get_current() + else: + current_site = RequestSite(self.request) + + link = self.__get_dynamic_attr('link', obj) + link = add_domain(current_site.domain, link) + + feed = self.feed_type( + title = self.__get_dynamic_attr('title', obj), + subtitle = self.__get_dynamic_attr('subtitle', obj), + link = link, + description = self.__get_dynamic_attr('description', obj), + language = settings.LANGUAGE_CODE.decode(), + feed_url = add_domain(current_site.domain, + self.__get_dynamic_attr('feed_url', obj)), + author_name = self.__get_dynamic_attr('author_name', obj), + author_link = self.__get_dynamic_attr('author_link', obj), + author_email = self.__get_dynamic_attr('author_email', obj), + categories = self.__get_dynamic_attr('categories', obj), + feed_copyright = self.__get_dynamic_attr('feed_copyright', obj), + feed_guid = self.__get_dynamic_attr('feed_guid', obj), + ttl = self.__get_dynamic_attr('ttl', obj), + **self.feed_extra_kwargs(obj) + ) + + try: + title_tmp = loader.get_template(self.title_template_name) + except TemplateDoesNotExist: + title_tmp = Template('{{ obj }}') + try: + description_tmp = loader.get_template(self.description_template_name) + except TemplateDoesNotExist: + description_tmp = Template('{{ obj }}') + + for item in self.__get_dynamic_attr('items', obj): + link = add_domain(current_site.domain, self.__get_dynamic_attr('item_link', item)) + enc = None + enc_url = self.__get_dynamic_attr('item_enclosure_url', item) + if enc_url: + enc = feedgenerator.Enclosure( + url = smart_unicode(enc_url), + length = smart_unicode(self.__get_dynamic_attr('item_enclosure_length', item)), + mime_type = smart_unicode(self.__get_dynamic_attr('item_enclosure_mime_type', item)) + ) + author_name = self.__get_dynamic_attr('item_author_name', item) + if author_name is not None: + author_email = self.__get_dynamic_attr('item_author_email', item) + author_link = self.__get_dynamic_attr('item_author_link', item) + else: + author_email = author_link = None + + pubdate = self.__get_dynamic_attr('item_pubdate', item) + if pubdate: + now = datetime.now() + utcnow = datetime.utcnow() + + # Must always subtract smaller time from larger time here. + if utcnow > now: + sign = -1 + tzDifference = (utcnow - now) + else: + sign = 1 + tzDifference = (now - utcnow) + + # Round the timezone offset to the nearest half hour. + tzOffsetMinutes = sign * ((tzDifference.seconds / 60 + 15) / 30) * 30 + tzOffset = timedelta(minutes=tzOffsetMinutes) + pubdate = pubdate.replace(tzinfo=FixedOffset(tzOffset)) + + feed.add_item( + title = title_tmp.render(RequestContext(self.request, {'obj': item, 'site': current_site})), + link = link, + description = description_tmp.render(RequestContext(self.request, {'obj': item, 'site': current_site})), + unique_id = self.__get_dynamic_attr('item_guid', item, link), + enclosure = enc, + pubdate = pubdate, + author_name = author_name, + author_email = author_email, + author_link = author_link, + categories = self.__get_dynamic_attr('item_categories', item), + item_copyright = self.__get_dynamic_attr('item_copyright', item), + **self.item_extra_kwargs(item) + ) + return feed |