317 lines
7.8 KiB
Python
317 lines
7.8 KiB
Python
from functools import wraps
|
|
|
|
from django.contrib.syndication import views
|
|
from django.utils import feedgenerator
|
|
from django.utils.timezone import get_fixed_timezone
|
|
|
|
from .models import Article, Entry
|
|
|
|
|
|
def wraps_decorator(f):
|
|
@wraps(f)
|
|
def wrapper(*args, **kwargs):
|
|
value = f(*args, **kwargs)
|
|
return f"{value} -- decorated by @wraps."
|
|
|
|
return wrapper
|
|
|
|
|
|
def common_decorator(f):
|
|
def wrapper(*args, **kwargs):
|
|
value = f(*args, **kwargs)
|
|
return f"{value} -- common decorated."
|
|
|
|
return wrapper
|
|
|
|
|
|
class TestRss2Feed(views.Feed):
|
|
title = "My blog"
|
|
description = "A more thorough description of my blog."
|
|
link = "/blog/"
|
|
feed_guid = "/foo/bar/1234"
|
|
author_name = "Sally Smith"
|
|
author_email = "test@example.com"
|
|
author_link = "http://www.example.com/"
|
|
categories = ("python", "django")
|
|
feed_copyright = "Copyright (c) 2007, Sally Smith"
|
|
ttl = 600
|
|
|
|
def items(self):
|
|
return Entry.objects.all()
|
|
|
|
def item_description(self, item):
|
|
return "Overridden description: %s" % item
|
|
|
|
def item_pubdate(self, item):
|
|
return item.published
|
|
|
|
def item_updateddate(self, item):
|
|
return item.updated
|
|
|
|
def item_comments(self, item):
|
|
return "%scomments" % item.get_absolute_url()
|
|
|
|
item_author_name = "Sally Smith"
|
|
item_author_email = "test@example.com"
|
|
item_author_link = "http://www.example.com/"
|
|
item_categories = ("python", "testing")
|
|
item_copyright = "Copyright (c) 2007, Sally Smith"
|
|
|
|
|
|
class TestRss2FeedWithCallableObject(TestRss2Feed):
|
|
class TimeToLive:
|
|
def __call__(self):
|
|
return 700
|
|
|
|
ttl = TimeToLive()
|
|
|
|
|
|
class TestRss2FeedWithDecoratedMethod(TestRss2Feed):
|
|
class TimeToLive:
|
|
@wraps_decorator
|
|
def __call__(self):
|
|
return 800
|
|
|
|
@staticmethod
|
|
@wraps_decorator
|
|
def feed_copyright():
|
|
return "Copyright (c) 2022, John Doe"
|
|
|
|
ttl = TimeToLive()
|
|
|
|
@staticmethod
|
|
def categories():
|
|
return ("javascript", "vue")
|
|
|
|
@wraps_decorator
|
|
def title(self):
|
|
return "Overridden title"
|
|
|
|
@wraps_decorator
|
|
def item_title(self, item):
|
|
return f"Overridden item title: {item.title}"
|
|
|
|
@wraps_decorator
|
|
def description(self, obj):
|
|
return "Overridden description"
|
|
|
|
@wraps_decorator
|
|
def item_description(self):
|
|
return "Overridden item description"
|
|
|
|
|
|
class TestRss2FeedWithWrongDecoratedMethod(TestRss2Feed):
|
|
@common_decorator
|
|
def item_description(self, item):
|
|
return f"Overridden item description: {item.title}"
|
|
|
|
|
|
class TestRss2FeedWithGuidIsPermaLinkTrue(TestRss2Feed):
|
|
def item_guid_is_permalink(self, item):
|
|
return True
|
|
|
|
|
|
class TestRss2FeedWithGuidIsPermaLinkFalse(TestRss2Feed):
|
|
def item_guid(self, item):
|
|
return str(item.pk)
|
|
|
|
def item_guid_is_permalink(self, item):
|
|
return False
|
|
|
|
|
|
class TestRss091Feed(TestRss2Feed):
|
|
feed_type = feedgenerator.RssUserland091Feed
|
|
|
|
|
|
class TestNoPubdateFeed(views.Feed):
|
|
title = "Test feed"
|
|
link = "/feed/"
|
|
|
|
def items(self):
|
|
return Entry.objects.all()
|
|
|
|
|
|
class TestAtomFeed(TestRss2Feed):
|
|
feed_type = feedgenerator.Atom1Feed
|
|
subtitle = TestRss2Feed.description
|
|
|
|
|
|
class TestLatestFeed(TestRss2Feed):
|
|
"""
|
|
A feed where the latest entry date is an `updated` element.
|
|
"""
|
|
|
|
feed_type = feedgenerator.Atom1Feed
|
|
subtitle = TestRss2Feed.description
|
|
|
|
def items(self):
|
|
return Entry.objects.exclude(title="My last entry")
|
|
|
|
|
|
class ArticlesFeed(TestRss2Feed):
|
|
"""
|
|
A feed to test no link being defined. Articles have no get_absolute_url()
|
|
method, and item_link() is not defined.
|
|
"""
|
|
|
|
def items(self):
|
|
return Article.objects.all()
|
|
|
|
|
|
class TestSingleEnclosureRSSFeed(TestRss2Feed):
|
|
"""
|
|
A feed to test that RSS feeds work with a single enclosure.
|
|
"""
|
|
|
|
def item_enclosure_url(self, item):
|
|
return "http://example.com"
|
|
|
|
def item_enclosure_size(self, item):
|
|
return 0
|
|
|
|
def item_mime_type(self, item):
|
|
return "image/png"
|
|
|
|
|
|
class TestMultipleEnclosureRSSFeed(TestRss2Feed):
|
|
"""
|
|
A feed to test that RSS feeds raise an exception with multiple enclosures.
|
|
"""
|
|
|
|
def item_enclosures(self, item):
|
|
return [
|
|
feedgenerator.Enclosure("http://example.com/hello.png", 0, "image/png"),
|
|
feedgenerator.Enclosure("http://example.com/goodbye.png", 0, "image/png"),
|
|
]
|
|
|
|
|
|
class TemplateFeed(TestRss2Feed):
|
|
"""
|
|
A feed to test defining item titles and descriptions with templates.
|
|
"""
|
|
|
|
title_template = "syndication/title.html"
|
|
description_template = "syndication/description.html"
|
|
|
|
# Defining a template overrides any item_title definition
|
|
def item_title(self):
|
|
return "Not in a template"
|
|
|
|
|
|
class TemplateContextFeed(TestRss2Feed):
|
|
"""
|
|
A feed to test custom context data in templates for title or description.
|
|
"""
|
|
|
|
title_template = "syndication/title_context.html"
|
|
description_template = "syndication/description_context.html"
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context["foo"] = "bar"
|
|
return context
|
|
|
|
|
|
class TestLanguageFeed(TestRss2Feed):
|
|
language = "de"
|
|
|
|
|
|
class TestGetObjectFeed(TestRss2Feed):
|
|
def get_object(self, request, entry_id):
|
|
return Entry.objects.get(pk=entry_id)
|
|
|
|
def items(self, obj):
|
|
return Article.objects.filter(entry=obj)
|
|
|
|
def item_link(self, item):
|
|
return "%sarticle/%s/" % (item.entry.get_absolute_url(), item.pk)
|
|
|
|
def item_comments(self, item):
|
|
return "%scomments" % self.item_link(item)
|
|
|
|
def item_description(self, item):
|
|
return "Article description: %s" % item.title
|
|
|
|
def item_title(self, item):
|
|
return "Title: %s" % item.title
|
|
|
|
|
|
class NaiveDatesFeed(TestAtomFeed):
|
|
"""
|
|
A feed with naive (non-timezone-aware) dates.
|
|
"""
|
|
|
|
def item_pubdate(self, item):
|
|
return item.published
|
|
|
|
|
|
class TZAwareDatesFeed(TestAtomFeed):
|
|
"""
|
|
A feed with timezone-aware dates.
|
|
"""
|
|
|
|
def item_pubdate(self, item):
|
|
# Provide a weird offset so that the test can know it's getting this
|
|
# specific offset and not accidentally getting on from
|
|
# settings.TIME_ZONE.
|
|
return item.published.replace(tzinfo=get_fixed_timezone(42))
|
|
|
|
|
|
class TestFeedUrlFeed(TestAtomFeed):
|
|
feed_url = "http://example.com/customfeedurl/"
|
|
|
|
|
|
class MyCustomAtom1Feed(feedgenerator.Atom1Feed):
|
|
"""
|
|
Test of a custom feed generator class.
|
|
"""
|
|
|
|
def root_attributes(self):
|
|
attrs = super().root_attributes()
|
|
attrs["django"] = "rocks"
|
|
return attrs
|
|
|
|
def add_root_elements(self, handler):
|
|
super().add_root_elements(handler)
|
|
handler.addQuickElement("spam", "eggs")
|
|
|
|
def item_attributes(self, item):
|
|
attrs = super().item_attributes(item)
|
|
attrs["bacon"] = "yum"
|
|
return attrs
|
|
|
|
def add_item_elements(self, handler, item):
|
|
super().add_item_elements(handler, item)
|
|
handler.addQuickElement("ministry", "silly walks")
|
|
|
|
|
|
class TestCustomFeed(TestAtomFeed):
|
|
feed_type = MyCustomAtom1Feed
|
|
|
|
|
|
class TestSingleEnclosureAtomFeed(TestAtomFeed):
|
|
"""
|
|
A feed to test that Atom feeds work with a single enclosure.
|
|
"""
|
|
|
|
def item_enclosure_url(self, item):
|
|
return "http://example.com"
|
|
|
|
def item_enclosure_size(self, item):
|
|
return 0
|
|
|
|
def item_mime_type(self, item):
|
|
return "image/png"
|
|
|
|
|
|
class TestMultipleEnclosureAtomFeed(TestAtomFeed):
|
|
"""
|
|
A feed to test that Atom feeds work with multiple enclosures.
|
|
"""
|
|
|
|
def item_enclosures(self, item):
|
|
return [
|
|
feedgenerator.Enclosure("http://example.com/hello.png", "0", "image/png"),
|
|
feedgenerator.Enclosure("http://example.com/goodbye.png", "0", "image/png"),
|
|
]
|