diff -r b758351d191f -r cc9b7e14412b web/lib/django/contrib/syndication/views.py --- a/web/lib/django/contrib/syndication/views.py Wed May 19 17:43:59 2010 +0200 +++ b/web/lib/django/contrib/syndication/views.py Tue May 25 02:43:45 2010 +0200 @@ -1,9 +1,192 @@ -from django.contrib.syndication import feeds +import datetime +from django.conf import settings +from django.contrib.sites.models import Site, RequestSite +from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist from django.http import HttpResponse, Http404 +from django.template import loader, Template, TemplateDoesNotExist, RequestContext +from django.utils import feedgenerator, tzinfo +from django.utils.encoding import force_unicode, iri_to_uri, smart_unicode +from django.utils.html import escape + +def add_domain(domain, url): + if not (url.startswith('http://') + or url.startswith('https://') + or url.startswith('mailto:')): + # '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): + feed_type = feedgenerator.DefaultFeed + title_template = None + description_template = None + + def __call__(self, request, *args, **kwargs): + try: + obj = self.get_object(request, *args, **kwargs) + except ObjectDoesNotExist: + raise Http404('Feed object does not exist.') + feedgen = self.get_feed(obj, request) + response = HttpResponse(mimetype=feedgen.mime_type) + feedgen.write(response, 'utf-8') + return response + + def item_title(self, item): + # Titles should be double escaped by default (see #6533) + return escape(force_unicode(item)) + + def item_description(self, item): + return force_unicode(item) + + 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, request, *args, **kwargs): + return None + + def get_feed(self, obj, request): + """ + Returns a feedgenerator.DefaultFeed object, fully populated, for + this feed. Raises FeedDoesNotExist for invalid parameters. + """ + if Site._meta.installed: + current_site = Site.objects.get_current() + else: + current_site = RequestSite(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) or request.path), + 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) + ) + + title_tmp = None + if self.title_template is not None: + try: + title_tmp = loader.get_template(self.title_template) + except TemplateDoesNotExist: + pass + + description_tmp = None + if self.description_template is not None: + try: + description_tmp = loader.get_template(self.description_template) + except TemplateDoesNotExist: + pass + + for item in self.__get_dynamic_attr('items', obj): + if title_tmp is not None: + title = title_tmp.render(RequestContext(request, {'obj': item, 'site': current_site})) + else: + title = self.__get_dynamic_attr('item_title', item) + if description_tmp is not None: + description = description_tmp.render(RequestContext(request, {'obj': item, 'site': current_site})) + else: + description = self.__get_dynamic_attr('item_description', item) + 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 and not pubdate.tzinfo: + ltz = tzinfo.LocalTimezone(pubdate) + pubdate = pubdate.replace(tzinfo=ltz) + + feed.add_item( + title = title, + link = link, + description = description, + 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 + def feed(request, url, feed_dict=None): + """Provided for backwards compatibility.""" + import warnings + warnings.warn('The syndication feed() view is deprecated. Please use the ' + 'new class based view API.', + category=PendingDeprecationWarning) + if not feed_dict: - raise Http404, "No feeds are registered." + raise Http404("No feeds are registered.") try: slug, param = url.split('/', 1) @@ -13,13 +196,14 @@ try: f = feed_dict[slug] except KeyError: - raise Http404, "Slug %r isn't registered." % slug + raise Http404("Slug %r isn't registered." % slug) try: feedgen = f(slug, request).get_feed(param) - except feeds.FeedDoesNotExist: - raise Http404, "Invalid feed parameters. Slug %r is valid, but other parameters, or lack thereof, are not." % slug + except FeedDoesNotExist: + raise Http404("Invalid feed parameters. Slug %r is valid, but other parameters, or lack thereof, are not." % slug) response = HttpResponse(mimetype=feedgen.mime_type) feedgen.write(response, 'utf-8') return response +