Merge branch 'julian'
[philo.git] / contrib / penfield / models.py
index c018247..a03bed8 100644 (file)
@@ -1,13 +1,17 @@
 from django.conf import settings
 from django.conf.urls.defaults import url, patterns, include
 from django.conf import settings
 from django.conf.urls.defaults import url, patterns, include
+from django.contrib.sites.models import Site, RequestSite
+from django.contrib.syndication.views import add_domain
 from django.db import models
 from django.db import models
-from django.http import Http404
+from django.http import Http404, HttpResponse
 from django.template import RequestContext, Template as DjangoTemplate
 from django.utils import feedgenerator, tzinfo
 from django.utils.datastructures import SortedDict
 from django.utils.encoding import smart_unicode, force_unicode
 from django.utils.html import escape
 from datetime import date, datetime
 from django.template import RequestContext, Template as DjangoTemplate
 from django.utils import feedgenerator, tzinfo
 from django.utils.datastructures import SortedDict
 from django.utils.encoding import smart_unicode, force_unicode
 from django.utils.html import escape
 from datetime import date, datetime
+from philo.contrib.penfield.exceptions import HttpNotAcceptable
+from philo.contrib.penfield.middleware import http_not_acceptable
 from philo.contrib.penfield.validators import validate_pagination_count
 from philo.exceptions import ViewCanNotProvideSubpath
 from philo.models import Tag, Titled, Entity, MultiView, Page, register_value_model, TemplateField, Template
 from philo.contrib.penfield.validators import validate_pagination_count
 from philo.exceptions import ViewCanNotProvideSubpath
 from philo.models import Tag, Titled, Entity, MultiView, Page, register_value_model, TemplateField, Template
@@ -17,6 +21,7 @@ try:
 except:
        mimeparse = None
 
 except:
        mimeparse = None
 
+
 ATOM = feedgenerator.Atom1Feed.mime_type
 RSS = feedgenerator.Rss201rev2Feed.mime_type
 FEEDS = SortedDict([
 ATOM = feedgenerator.Atom1Feed.mime_type
 RSS = feedgenerator.Rss201rev2Feed.mime_type
 FEEDS = SortedDict([
@@ -41,6 +46,7 @@ class FeedView(MultiView):
        feed_type = models.CharField(max_length=50, choices=FEED_CHOICES, default=ATOM)
        feed_suffix = models.CharField(max_length=255, blank=False, default="feed")
        feeds_enabled = models.BooleanField(default=True)
        feed_type = models.CharField(max_length=50, choices=FEED_CHOICES, default=ATOM)
        feed_suffix = models.CharField(max_length=255, blank=False, default="feed")
        feeds_enabled = models.BooleanField(default=True)
+       feed_length = models.PositiveIntegerField(blank=True, null=True, default=15, help_text="The maximum number of items to return for this feed. All items will be returned if this field is blank.")
        
        item_title_template = models.ForeignKey(Template, blank=True, null=True, related_name="%(app_label)s_%(class)s_title_related")
        item_description_template = models.ForeignKey(Template, blank=True, null=True, related_name="%(app_label)s_%(class)s_description_related")
        
        item_title_template = models.ForeignKey(Template, blank=True, null=True, related_name="%(app_label)s_%(class)s_title_related")
        item_description_template = models.ForeignKey(Template, blank=True, null=True, related_name="%(app_label)s_%(class)s_description_related")
@@ -50,20 +56,23 @@ class FeedView(MultiView):
        
        description = ""
        
        
        description = ""
        
-       def feed_patterns(self, get_items_attr, page_attr, reverse_name):
+       def feed_patterns(self, base, get_items_attr, page_attr, reverse_name):
                """
                Given the name to be used to reverse this view and the names of
                the attributes for the function that fetches the objects, returns
                patterns suitable for inclusion in urlpatterns.
                """
                """
                Given the name to be used to reverse this view and the names of
                the attributes for the function that fetches the objects, returns
                patterns suitable for inclusion in urlpatterns.
                """
-               urlpatterns = patterns('',
-                       url(r'^$', self.page_view(get_items_attr, page_attr), name=reverse_name)
-               )
+               urlpatterns = patterns('')
                if self.feeds_enabled:
                        feed_reverse_name = "%s_feed" % reverse_name
                if self.feeds_enabled:
                        feed_reverse_name = "%s_feed" % reverse_name
+                       feed_view = http_not_acceptable(self.feed_view(get_items_attr, feed_reverse_name))
+                       feed_pattern = r'%s%s%s$' % (base, (base and base[-1] != "^") and "/" or "", self.feed_suffix)
                        urlpatterns += patterns('',
                        urlpatterns += patterns('',
-                               url(r'^%s$' % self.feed_suffix, self.feed_view(get_items_attr, feed_reverse_name), name=feed_reverse_name),
+                               url(feed_pattern, feed_view, name=feed_reverse_name),
                        )
                        )
+               urlpatterns += patterns('',
+                       url(r"%s$" % base, self.page_view(get_items_attr, page_attr), name=reverse_name)
+               )
                return urlpatterns
        
        def get_object(self, request, **kwargs):
                return urlpatterns
        
        def get_object(self, request, **kwargs):
@@ -79,6 +88,7 @@ class FeedView(MultiView):
                        obj = self.get_object(request, *args, **kwargs)
                        feed = self.get_feed(obj, request, reverse_name)
                        items, xxx = get_items(request, extra_context=extra_context, *args, **kwargs)
                        obj = self.get_object(request, *args, **kwargs)
                        feed = self.get_feed(obj, request, reverse_name)
                        items, xxx = get_items(request, extra_context=extra_context, *args, **kwargs)
+                       self.populate_feed(feed, items, request)
                        
                        response = HttpResponse(mimetype=feed.mime_type)
                        feed.write(response, 'utf-8')
                        
                        response = HttpResponse(mimetype=feed.mime_type)
                        feed.write(response, 'utf-8')
@@ -118,6 +128,8 @@ class FeedView(MultiView):
        
        def get_feed_type(self, request):
                feed_type = self.feed_type
        
        def get_feed_type(self, request):
                feed_type = self.feed_type
+               if feed_type not in FEEDS:
+                       feed_type = FEEDS.keys()[0]
                accept = request.META.get('HTTP_ACCEPT')
                if accept and feed_type not in accept and "*/*" not in accept and "%s/*" % feed_type.split("/")[0] not in accept:
                        # Wups! They aren't accepting the chosen format. Is there another format we can use?
                accept = request.META.get('HTTP_ACCEPT')
                if accept and feed_type not in accept and "*/*" not in accept and "%s/*" % feed_type.split("/")[0] not in accept:
                        # Wups! They aren't accepting the chosen format. Is there another format we can use?
@@ -130,14 +142,18 @@ class FeedView(MultiView):
                                else:
                                        feed_type = None
                        if not feed_type:
                                else:
                                        feed_type = None
                        if not feed_type:
-                               # See RFC 2616
-                               return HttpResponse(status=406)
+                               raise HttpNotAcceptable
                return FEEDS[feed_type]
        
        def get_feed(self, obj, request, reverse_name):
                """
                Returns an unpopulated feedgenerator.DefaultFeed object for this object.
                """
                return FEEDS[feed_type]
        
        def get_feed(self, obj, request, reverse_name):
                """
                Returns an unpopulated feedgenerator.DefaultFeed object for this object.
                """
+               try:
+                       current_site = Site.objects.get_current()
+               except Site.DoesNotExist:
+                       current_site = RequestSite(request)
+               
                feed_type = self.get_feed_type(request)
                node = request.node
                link = node.get_absolute_url(with_domain=True, request=request, secure=request.is_secure())
                feed_type = self.get_feed_type(request)
                node = request.node
                link = node.get_absolute_url(with_domain=True, request=request, secure=request.is_secure())
@@ -148,7 +164,11 @@ class FeedView(MultiView):
                        link = link,
                        description = self.__get_dynamic_attr('description', obj),
                        language = settings.LANGUAGE_CODE.decode(),
                        link = link,
                        description = self.__get_dynamic_attr('description', obj),
                        language = settings.LANGUAGE_CODE.decode(),
-                       feed_url = node.construct_url(self.reverse(reverse_name), with_domain=True, request=request, secure=request.is_secure()),
+                       feed_url = add_domain(
+                               current_site.domain,
+                               self.__get_dynamic_attr('feed_url', obj) or node.construct_url(node.subpath, with_domain=True, request=request, secure=request.is_secure()),
+                               request.is_secure()
+                       ),
                        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),
                        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),
@@ -162,15 +182,22 @@ class FeedView(MultiView):
        
        def populate_feed(self, feed, items, request):
                if self.item_title_template:
        
        def populate_feed(self, feed, items, request):
                if self.item_title_template:
-                       title_template = Template(self.item_title_template.code)
+                       title_template = DjangoTemplate(self.item_title_template.code)
                else:
                        title_template = None
                if self.item_description_template:
                else:
                        title_template = None
                if self.item_description_template:
-                       description_template = Template(self.item_description_template.code)
+                       description_template = DjangoTemplate(self.item_description_template.code)
                else:
                        description_template = None
                
                node = request.node
                else:
                        description_template = None
                
                node = request.node
+               try:
+                       current_site = Site.objects.get_current()
+               except Site.DoesNotExist:
+                       current_site = RequestSite(request)
+               
+               if self.feed_length is not None:
+                       items = items[:self.feed_length]
                
                for item in items:
                        if title_template is not None:
                
                for item in items:
                        if title_template is not None:
@@ -188,7 +215,11 @@ class FeedView(MultiView):
                        enc_url = self.__get_dynamic_attr('item_enclosure_url', item)
                        if enc_url:
                                enc = feedgenerator.Enclosure(
                        enc_url = self.__get_dynamic_attr('item_enclosure_url', item)
                        if enc_url:
                                enc = feedgenerator.Enclosure(
-                                       url = smart_unicode(enc_url),
+                                       url = smart_unicode(add_domain(
+                                                       current_site.domain,
+                                                       enc_url,
+                                                       request.is_secure()
+                                       )),
                                        length = smart_unicode(self.__get_dynamic_attr('item_enclosure_length', item)),
                                        mime_type = smart_unicode(self.__get_dynamic_attr('item_enclosure_mime_type', item))
                                )
                                        length = smart_unicode(self.__get_dynamic_attr('item_enclosure_length', item)),
                                        mime_type = smart_unicode(self.__get_dynamic_attr('item_enclosure_mime_type', item))
                                )
@@ -313,6 +344,7 @@ class BlogView(FeedView):
        
        index_page = models.ForeignKey(Page, related_name='blog_index_related')
        entry_page = models.ForeignKey(Page, related_name='blog_entry_related')
        
        index_page = models.ForeignKey(Page, related_name='blog_index_related')
        entry_page = models.ForeignKey(Page, related_name='blog_entry_related')
+       # TODO: entry_archive is misleading. Rename to ymd_page or timespan_page.
        entry_archive_page = models.ForeignKey(Page, related_name='blog_entry_archive_related', null=True, blank=True)
        tag_page = models.ForeignKey(Page, related_name='blog_tag_related')
        tag_archive_page = models.ForeignKey(Page, related_name='blog_tag_archive_related', null=True, blank=True)
        entry_archive_page = models.ForeignKey(Page, related_name='blog_entry_archive_related', null=True, blank=True)
        tag_page = models.ForeignKey(Page, related_name='blog_tag_related')
        tag_archive_page = models.ForeignKey(Page, related_name='blog_tag_archive_related', null=True, blank=True)
@@ -339,7 +371,7 @@ class BlogView(FeedView):
                                                if self.entry_permalink_style == 'D':
                                                        kwargs.update({'day': str(obj.date.day).zfill(2)})
                                return self.entry_view, [], kwargs
                                                if self.entry_permalink_style == 'D':
                                                        kwargs.update({'day': str(obj.date.day).zfill(2)})
                                return self.entry_view, [], kwargs
-               elif isinstance(obj, Tag) or (isinstance(obj, models.QuerySet) and obj.model == Tag and obj):
+               elif isinstance(obj, Tag) or (isinstance(obj, models.query.QuerySet) and obj.model == Tag and obj):
                        if isinstance(obj, Tag):
                                obj = [obj]
                        slugs = [tag.slug for tag in obj if tag in self.get_tag_queryset()]
                        if isinstance(obj, Tag):
                                obj = [obj]
                        slugs = [tag.slug for tag in obj if tag in self.get_tag_queryset()]
@@ -356,16 +388,9 @@ class BlogView(FeedView):
        
        @property
        def urlpatterns(self):
        
        @property
        def urlpatterns(self):
-               urlpatterns = patterns('',
-                       url(r'^', include(self.feed_patterns('get_all_entries', 'index_page', 'index'))),
-               )
-               if self.feeds_enabled:
-                       urlpatterns += patterns('',
-                               url(r'^%s/(?P<tag_slugs>[-\w]+[-+/\w]*)/%s$' % (self.tag_permalink_base, self.feed_suffix), self.feed_view('get_entries_by_tag', 'entries_by_tag_feed'), name='entries_by_tag_feed'),
-                       )
-               urlpatterns += patterns('',
-                       url(r'^%s/(?P<tag_slugs>[-\w]+[-+/\w]*)$' % self.tag_permalink_base, self.page_view('get_entries_by_tag', 'tag_page'), name='entries_by_tag')
-               )
+               urlpatterns = self.feed_patterns(r'^', 'get_all_entries', 'index_page', 'index') +\
+                       self.feed_patterns(r'^%s/(?P<tag_slugs>[-\w]+[-+/\w]*)$' % self.tag_permalink_base, 'get_entries_by_tag', 'tag_page', 'entries_by_tag')
+               
                if self.tag_archive_page:
                        urlpatterns += patterns('',
                                url((r'^%s$' % self.tag_permalink_base), self.tag_archive_view, name='tag_archive')
                if self.tag_archive_page:
                        urlpatterns += patterns('',
                                url((r'^%s$' % self.tag_permalink_base), self.tag_archive_view, name='tag_archive')
@@ -373,17 +398,11 @@ class BlogView(FeedView):
                
                if self.entry_archive_page:
                        if self.entry_permalink_style in 'DMY':
                
                if self.entry_archive_page:
                        if self.entry_permalink_style in 'DMY':
-                               urlpatterns += patterns('',
-                                       url(r'^(?P<year>\d{4})', include(self.feed_patterns('get_entries_by_ymd', 'entry_archive_page', 'entries_by_year')))
-                               )
+                               urlpatterns += self.feed_patterns(r'^(?P<year>\d{4})', 'get_entries_by_ymd', 'entry_archive_page', 'entries_by_year')
                                if self.entry_permalink_style in 'DM':
                                if self.entry_permalink_style in 'DM':
-                                       urlpatterns += patterns('',
-                                               url(r'^(?P<year>\d{4})/(?P<month>\d{2})$', include(self.feed_patterns('get_entries_by_ymd', 'entry_archive_page', 'entries_by_month'))),
-                                       )
+                                       urlpatterns += self.feed_patterns(r'^(?P<year>\d{4})/(?P<month>\d{2})', 'get_entries_by_ymd', 'entry_archive_page', 'entries_by_month')
                                        if self.entry_permalink_style == 'D':
                                        if self.entry_permalink_style == 'D':
-                                               urlpatterns += patterns('',
-                                                       url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})$', include(self.feed_patterns('get_entries_by_ymd', 'entry_archive_page', 'entries_by_day')))
-                                               )
+                                               urlpatterns += self.feed_patterns(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})', 'get_entries_by_ymd', 'entry_archive_page', 'entries_by_day')
                
                if self.entry_permalink_style == 'D':
                        urlpatterns += patterns('',
                
                if self.entry_permalink_style == 'D':
                        urlpatterns += patterns('',
@@ -490,10 +509,11 @@ class BlogView(FeedView):
                        obj = self.get_object(request, *args, **kwargs)
                        feed = self.get_feed(obj, request, reverse_name)
                        items, extra_context = get_items(request, extra_context=extra_context, *args, **kwargs)
                        obj = self.get_object(request, *args, **kwargs)
                        feed = self.get_feed(obj, request, reverse_name)
                        items, extra_context = get_items(request, extra_context=extra_context, *args, **kwargs)
+                       self.populate_feed(feed, items, request)
                        
                        if 'tags' in extra_context:
                                tags = extra_context['tags']
                        
                        if 'tags' in extra_context:
                                tags = extra_context['tags']
-                               feed.feed['link'] = request.node.construct_url(self.reverse(tags), with_domain=True, request=request, secure=request.is_secure())
+                               feed.feed['link'] = request.node.construct_url(self.reverse(obj=tags), with_domain=True, request=request, secure=request.is_secure())
                        else:
                                tags = obj.entry_tags
                        
                        else:
                                tags = obj.entry_tags
                        
@@ -512,7 +532,7 @@ class BlogView(FeedView):
                        item_context = {
                                'paginator': paginator,
                                'paginated_page': paginated_page,
                        item_context = {
                                'paginator': paginator,
                                'paginated_page': paginated_page,
-                               self.item_context_var: objects
+                               self.item_context_var: items
                        }
                else:
                        item_context = {
                        }
                else:
                        item_context = {
@@ -632,9 +652,8 @@ class NewsletterView(FeedView):
        
        @property
        def urlpatterns(self):
        
        @property
        def urlpatterns(self):
-               urlpatterns = patterns('',
-                       url(r'^', include(self.feed_patterns('get_all_articles', 'index_page', 'index'))),
-                       url(r'^%s/(?P<numbering>.+)' % self.issue_permalink_base, include(self.feed_patterns('get_articles_by_issue', 'issue_page', 'issue')))
+               urlpatterns = self.feed_patterns(r'^', 'get_all_articles', 'index_page', 'index') + patterns('',
+                       url(r'^%s/(?P<numbering>.+)$' % self.issue_permalink_base, self.page_view('get_articles_by_issue', 'issue_page'), name='issue')
                )
                if self.issue_archive_page:
                        urlpatterns += patterns('',
                )
                if self.issue_archive_page:
                        urlpatterns += patterns('',
@@ -645,17 +664,11 @@ class NewsletterView(FeedView):
                                url(r'^%s' % self.article_permalink_base, include(self.feed_patterns('get_all_articles', 'article_archive_page', 'articles')))
                        )
                        if self.article_permalink_style in 'DMY':
                                url(r'^%s' % self.article_permalink_base, include(self.feed_patterns('get_all_articles', 'article_archive_page', 'articles')))
                        )
                        if self.article_permalink_style in 'DMY':
-                               urlpatterns += patterns('',
-                                       url(r'^%s/(?P<year>\d{4})' % self.article_permalink_base, include(self.feed_patterns('get_articles_by_ymd', 'article_archive_page', 'articles_by_year')))
-                               )
+                               urlpatterns += self.feed_patterns(r'^%s/(?P<year>\d{4})' % self.article_permalink_base, 'get_articles_by_ymd', 'article_archive_page', 'articles_by_year')
                                if self.article_permalink_style in 'DM':
                                if self.article_permalink_style in 'DM':
-                                       urlpatterns += patterns('',
-                                               url(r'^%s/(?P<year>\d{4})/(?P<month>\d{2})' % self.article_permalink_base, include(self.feed_patterns('get_articles_by_ymd', 'article_archive_page', 'articles_by_month')))
-                                       )
+                                       urlpatterns += self.feed_patterns(r'^%s/(?P<year>\d{4})/(?P<month>\d{2})' % self.article_permalink_base, 'get_articles_by_ymd', 'article_archive_page', 'articles_by_month')
                                        if self.article_permalink_style == 'D':
                                        if self.article_permalink_style == 'D':
-                                               urlpatterns += patterns('',
-                                                       url(r'^%s/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})' % self.article_permalink_base, include(self.feed_patterns('get_articles_by_ymd', 'article_archive_page', 'articles_by_day')))
-                                               )
+                                               urlpatterns += self.feed_patterns(r'^%s/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})' % self.article_permalink_base, 'get_articles_by_ymd', 'article_archive_page', 'articles_by_day')
                
                if self.article_permalink_style == 'Y':
                        urlpatterns += patterns('',
                
                if self.article_permalink_style == 'Y':
                        urlpatterns += patterns('',