Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/category feed #538

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 101 additions & 66 deletions djangocms_blog/feeds.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,34 +32,38 @@

class LatestEntriesFeed(Feed):
feed_type = Rss201rev2Feed
feed_items_number = get_setting('FEED_LATEST_ITEMS')
feed_items_number = get_setting("FEED_LATEST_ITEMS")

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)

def link(self):
return reverse('%s:posts-latest' % self.namespace, current_app=self.namespace)
return reverse("%s:posts-latest" % self.namespace, current_app=self.namespace)

def title(self):
return Site.objects.get_current().name

def description(self):
return _('Blog articles on %(site_name)s') % {'site_name': Site.objects.get_current().name}
return _("Blog articles on %(site_name)s") % {
"site_name": Site.objects.get_current().name
}

def items(self, obj=None):
return Post.objects.namespace(
self.namespace
).published().order_by('-date_published')[:self.feed_items_number]
return (
Post.objects.namespace(self.namespace)
.published()
.order_by("-date_published")[: self.feed_items_number]
)

def item_title(self, item):
return mark_safe(item.safe_translation_getter('title'))
return mark_safe(item.safe_translation_getter("title"))

def item_description(self, item):
if item.app_config.use_abstract:
return mark_safe(item.safe_translation_getter('abstract'))
return mark_safe(item.safe_translation_getter('post_text'))
return mark_safe(item.safe_translation_getter("abstract"))
return mark_safe(item.safe_translation_getter("post_text"))

def item_updateddate(self, item):
return item.date_modified
Expand All @@ -78,114 +82,145 @@ def item_author_url(self, item):


class TagFeed(LatestEntriesFeed):
feed_items_number = get_setting('FEED_TAGS_ITEMS')
def get_object(self, request, tag, feed_items_number=None):
if feed_items_number is None:
feed_items_number = get_setting("FEED_TAGS_ITEMS")

return {"tag": tag, "feed_items_number": int(feed_items_number)}

def items(self, obj=None):
return Post.objects.published().filter(tags__slug=obj["tag"])[
: obj["feed_items_number"]
]


def get_object(self, request, tag):
return tag # pragma: no cover
class CategoryFeed(LatestEntriesFeed):
def get_object(self, request, category, feed_items_number=None):
if feed_items_number is None:
feed_items_number = get_setting("FEED_CATEGORY_ITEMS")

return {"category": category, "feed_items_number": int(feed_items_number)}

def items(self, obj=None):
return Post.objects.published().filter(tags__slug=obj)[:self.feed_items_number]
return Post.objects.published().filter(
categories__translations__slug=obj["category"]
)[: obj["feed_items_number"]]


class FBInstantFeed(Rss201rev2Feed):
date_format = '%Y-%m-%dT%H:%M:%S%z'
date_format = "%Y-%m-%dT%H:%M:%S%z"

def rss_attributes(self):
return {
'version': self._version,
'xmlns:content': 'http://purl.org/rss/1.0/modules/content/'
"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("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', self.latest_post_date().strftime(self.date_format)
"lastBuildDate", self.latest_post_date().strftime(self.date_format)
)
if self.feed['ttl'] is not None:
handler.addQuickElement('ttl', self.feed['ttl'])
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)
if item['author']:
handler.addQuickElement('author', item['author'])
if item['date_pub'] is not None:
handler.addQuickElement('pubDate', item['date_pub'].strftime(self.date_format))
if item['date_mod'] is not None:
handler.addQuickElement('modDate', item['date_mod'].strftime(self.date_format))

handler.startElement('description', {})
handler._write('<![CDATA[{0}]]>'.format(
unescape(normalize_newlines(force_text(item['abstract'])).replace('\n', ' ')))
if item["author"]:
handler.addQuickElement("author", item["author"])
if item["date_pub"] is not None:
handler.addQuickElement(
"pubDate", item["date_pub"].strftime(self.date_format)
)
if item["date_mod"] is not None:
handler.addQuickElement(
"modDate", item["date_mod"].strftime(self.date_format)
)

handler.startElement("description", {})
handler._write(
"<![CDATA[{0}]]>".format(
unescape(
normalize_newlines(force_text(item["abstract"])).replace("\n", " ")
)
)
)
handler.endElement('description')
handler.startElement('content:encoded', {})
handler._write('<![CDATA[')
handler._write('<!doctype html>')
handler._write(unescape(force_text(item['content'])))
handler._write(']]>')
handler.endElement('content:encoded')
handler.endElement("description")
handler.startElement("content:encoded", {})
handler._write("<![CDATA[")
handler._write("<!doctype html>")
handler._write(unescape(force_text(item["content"])))
handler._write("]]>")
handler.endElement("content:encoded")


class FBInstantArticles(LatestEntriesFeed):
feed_type = FBInstantFeed
feed_items_number = get_setting('FEED_INSTANT_ITEMS')
feed_items_number = get_setting("FEED_INSTANT_ITEMS")

def items(self, obj=None):
return Post.objects.namespace(
self.namespace
).published().order_by('-date_modified')[:self.feed_items_number]
return (
Post.objects.namespace(self.namespace)
.published()
.order_by("-date_modified")[: self.feed_items_number]
)

def _clean_html(self, content):
body = BytesIO(content)
document = etree.iterparse(body, html=True)
for a, e in document:
if not (e.text and e.text.strip()) and len(e) == 0 and e.tag == 'p':
if not (e.text and e.text.strip()) and len(e) == 0 and e.tag == "p":
e.getparent().remove(e)
if e.tag in ('h3', 'h4', 'h5', 'h6') and 'op-kicker' not in e.attrib.get('class', ''):
e.tag = 'h2'
if e.tag in ("h3", "h4", "h5", "h6") and "op-kicker" not in e.attrib.get(
"class", ""
):
e.tag = "h2"
return etree.tostring(document.root)

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')
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 = view(self.request, slug=item.safe_translation_getter("slug"))
response.render()
content = self._clean_html(response.content)
cache.set(key, content, timeout=get_setting('FEED_CACHE_TIMEOUT'))
cache.set(key, content, timeout=get_setting("FEED_CACHE_TIMEOUT"))
if item.app_config.use_abstract:
abstract = strip_tags(item.safe_translation_getter('abstract'))
abstract = strip_tags(item.safe_translation_getter("abstract"))
else:
abstract = strip_tags(item.safe_translation_getter('post_text'))
abstract = strip_tags(item.safe_translation_getter("post_text"))
return {
'author': item.get_author_name(),
'content': content,
'date': item.date_modified,
'date_pub': item.date_modified,
'date_mod': item.date_modified,
'abstract': abstract
"author": item.get_author_name(),
"content": content,
"date": item.date_modified,
"date_pub": item.date_modified,
"date_mod": item.date_modified,
"abstract": abstract,
}

def item_categories(self, item):
return [category.safe_translation_getter('name') for category in item.categories.all()]
return [
category.safe_translation_getter("name")
for category in item.categories.all()
]

def item_author_name(self, item):
return ''
return ""

def item_author_url(self, item):
return ''
return ""

def item_description(self, item):
return None
Expand Down
3 changes: 3 additions & 0 deletions djangocms_blog/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,10 @@ def get_authors(self):
qs = qs.published(current_site=False)
count = qs.count()
if count:
# total nb of articles
author.count = count
# "the number of author articles to be displayed"
author.posts = qs[:self.latest_posts]
return authors


Expand Down
Loading