diff --git a/djangocms_blog/feeds.py b/djangocms_blog/feeds.py index 7583018..95635f6 100644 --- a/djangocms_blog/feeds.py +++ b/djangocms_blog/feeds.py @@ -1,19 +1,27 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, print_function, unicode_literals +from django.core.cache import cache +from django.utils.encoding import force_text +from django.utils.feedgenerator import Rss201rev2Feed, rfc2822_date + from aldryn_apphooks_config.utils import get_app_instance from django.contrib.sites.models import Site from django.contrib.syndication.views import Feed from django.core.urlresolvers import reverse -from django.utils.translation import ugettext as _ +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext as _, get_language_from_request +from djangocms_blog.settings import get_setting +from djangocms_blog.views import PostDetailView from .models import Post -from .settings import get_setting class LatestEntriesFeed(Feed): + feed_type = Rss201rev2Feed def __call__(self, request, *args, **kwargs): + self.request = request self.namespace, self.config = get_app_instance(request) return super(LatestEntriesFeed, self).__call__(request, *args, **kwargs) @@ -30,7 +38,7 @@ class LatestEntriesFeed(Feed): return item.safe_translation_getter('title') def item_description(self, item): - if get_setting('USE_ABSTRACT'): + if item.app_config.use_abstract: return item.safe_translation_getter('abstract') return item.safe_translation_getter('post_text') @@ -42,3 +50,55 @@ class TagFeed(LatestEntriesFeed): def items(self, obj=None): return Post.objects.published().filter(tags__slug=obj)[:10] + + +class FBInstantFeed(Rss201rev2Feed): + + def rss_attributes(self): + return { + 'version': self._version, + 'xmlns:content': 'http://purl.org/rss/1.0/modules/content/' + } + + def add_root_elements(self, handler): + handler.addQuickElement("title", self.feed['title']) + handler.addQuickElement("link", self.feed['link']) + handler.addQuickElement("description", self.feed['description']) + if self.feed['language'] is not None: + handler.addQuickElement("language", self.feed['language']) + for cat in self.feed['categories']: + handler.addQuickElement("category", cat) + if self.feed['feed_copyright'] is not None: + handler.addQuickElement("copyright", self.feed['feed_copyright']) + handler.addQuickElement("lastBuildDate", rfc2822_date(self.latest_post_date())) + if self.feed['ttl'] is not None: + handler.addQuickElement("ttl", self.feed['ttl']) + + def add_item_elements(self, handler, item): + super(FBInstantFeed, self).add_item_elements(handler, item) + handler.startElement('content:encoded', {}) + handler._write('') + handler.endElement('content:encoded') + + +class FBInstantArticles(LatestEntriesFeed): + feed_type = FBInstantFeed + + def item_extra_kwargs(self, item): + if not item: + return {} + language = get_language_from_request(self.request, check_path=True) + key = item.get_cache_key(language, 'feed') + content = cache.get(key) + if not content: + view = PostDetailView.as_view(instant_article=True) + response = view(self.request, slug=item.safe_translation_getter('slug')) + response.render() + content = mark_safe(response.content) + cache.set(key, content, timeout=get_setting('FEED_CACHE_TIMEOUT')) + return { + 'content': content, + 'slug': item.safe_translation_getter('slug'), + } diff --git a/djangocms_blog/models.py b/djangocms_blog/models.py index 350fe45..0e5a3ea 100644 --- a/djangocms_blog/models.py +++ b/djangocms_blog/models.py @@ -1,13 +1,18 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, print_function, unicode_literals +import hashlib + from aldryn_apphooks_config.fields import AppHookConfigField from aldryn_apphooks_config.managers.parler import AppHookConfigTranslatableManager from cms.models import CMSPlugin, PlaceholderField from django.conf import settings as dj_settings from django.contrib.auth import get_user_model +from django.core.cache import cache from django.core.urlresolvers import reverse from django.db import models +from django.db.models.signals import post_save, pre_delete +from django.dispatch import receiver from django.utils import timezone from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.html import escape, strip_tags @@ -196,6 +201,12 @@ class Post(KnockerModel, ModelMeta, TranslatableModel): def __str__(self): return self.safe_translation_getter('title') + @property + def guid(self, language=None): + if not language: + language = self.get_current_language() + return hashlib.sha256(self.get_absolute_url(language)).hexdigest() + def save(self, *args, **kwargs): """ Handle some auto configuration during save @@ -329,6 +340,9 @@ class Post(KnockerModel, ModelMeta, TranslatableModel): updated = self.app_config.send_knock_update and self.is_published return new or updated + def get_cache_key(self, language, prefix): + return 'djangocms-blog:{2}:{0}:{1}'.format(language, self.guid, prefix) + class BasePostPlugin(CMSPlugin): app_config = AppHookConfigField( @@ -422,3 +436,17 @@ class GenericBlogPlugin(BasePostPlugin): def __str__(self): return force_text(_('generic blog plugin')) + + +@receiver(pre_delete, sender=Post) +def cleanup_post(sender, instance, **kwargs): + for language in instance.get_available_languages(): + key = instance.get_cache_key(language, 'feed') + cache.delete(key) + + +@receiver(post_save, sender=Post) +def cleanup_pagemeta(sender, instance, **kwargs): + for language in instance.get_available_languages(): + key = instance.get_cache_key(language, 'feed') + cache.delete(key) diff --git a/djangocms_blog/settings.py b/djangocms_blog/settings.py index 80ee1a8..3e0c203 100644 --- a/djangocms_blog/settings.py +++ b/djangocms_blog/settings.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, print_function, unicode_literals +from django.utils.safestring import mark_safe + MENU_TYPE_COMPLETE = 'complete' MENU_TYPE_CATEGORIES = 'categories' MENU_TYPE_POSTS = 'posts' @@ -121,6 +123,8 @@ def get_setting(name): settings, 'BLOG_CATEGORY_PLUGIN_NAME', _('Categories')), 'BLOG_ARCHIVE_PLUGIN_NAME': getattr( settings, 'BLOG_ARCHIVE_PLUGIN_NAME', _('Archive')), + 'BLOG_FEED_CACHE_TIMEOUT': getattr( + settings, 'BLOG_FEED_CACHE_TIMEOUT', 3600), } return default['BLOG_%s' % name] diff --git a/djangocms_blog/templates/djangocms_blog/includes/blog_meta.html b/djangocms_blog/templates/djangocms_blog/includes/blog_meta.html index 37eb62a..0705dc2 100644 --- a/djangocms_blog/templates/djangocms_blog/includes/blog_meta.html +++ b/djangocms_blog/templates/djangocms_blog/includes/blog_meta.html @@ -23,4 +23,4 @@