Skip to content
Permalink
Browse files
Atom feeds for archive indexes
* Autodiscoverable feeds for archive and tag index pages
* Generate paginated and properly archived feeds for archive indexes
  • Loading branch information
da2x committed May 4, 2015
1 parent 9910276 commit 728dd3720f56b5be7bd79eee4f1c6ae398b90d92
@@ -7,7 +7,7 @@ Features
* Substitutions for RSS_LINKS_APPEND_QUERY for identifying
the source feed (feedRelUri) and the kind of feed (feedFormat).
* New option GENERATE_ATOM, off by default
* Current and archive Atom feeds for indexes and category/tag indexes (RFC-4287 and RFC-5005)
* Current and archive Atom feeds for indexes; category, tag, and archive indexes (RFC-4287 and RFC-5005)
* Atom feed auto-discovery in HTML indexes and category/tag indexes
* .atom included in the sitemap index
* New post metadata "updated", inherits "date" if unset
@@ -1,2 +1,13 @@
## -*- coding: utf-8 -*-
<%inherit file="index.tmpl"/>

<%block name="extra_head">
${parent.extra_head()}
%if len(translations) > 1 and generate_atom:
%for language in translations:
<link rel="alternate" type="application/atom+xml" title="Atom for the ${archive_name} section (${language})" href="${_link("archive_atom", archive_name, language)}">
%endfor
%elif generate_atom:
<link rel="alternate" type="application/atom+xml" title="Atom for the ${archive_name} archive" href="${_link("archive_atom", archive_name)}">
%endif
</%block>
@@ -1,2 +1,13 @@
## -*- coding: utf-8 -*-
<%inherit file="index.tmpl"/>

<%block name="extra_head">
${parent.extra_head()}
%if len(translations) > 1 and generate_atom:
%for language in translations:
<link rel="alternate" type="application/atom+xml" title="Atom for the ${tag} section (${language})" href="${_link(kind + "_atom", tag, language)}">
%endfor
%elif generate_atom:
<link rel="alternate" type="application/atom+xml" title="Atom for the ${tag} section" href="${_link("tag" + "_atom", tag)}">
%endif
</%block>
@@ -1571,8 +1571,8 @@ def generic_post_list_renderer(self, lang, posts, output_name,

def atom_feed_renderer(self, lang, posts, output_path, filters,
extra_context):
"""Renders Atom feeds and archives with lists of posts."""
"""Feeds become archives when no longer expected to change"""
"""Renders Atom feeds and archives with lists of posts. Feeds are
considered archives when no future updates to them are expected"""

def atom_link(link_rel, link_type, link_href):
link = lxml.etree.Element("link")
@@ -1593,6 +1593,7 @@ def atom_link(link_rel, link_type, link_href):
context["lang"] = lang
context["prevlink"] = None
context["nextlink"] = None
context["is_feed_stale"] = None
context.update(extra_context)
deps_context = copy(context)
deps_context["posts"] = [(p.meta[lang]['title'], p.permalink(lang)) for p in
@@ -1605,7 +1606,7 @@ def atom_link(link_rel, link_type, link_href):
deps_context['navigation_links'] = deps_context['global']['navigation_links'](lang)

nslist = {}
if not context["feedpagenum"] == context["feedpagecount"] - 1 and not context["feedpagenum"] == 0:
if context["is_feed_stale"] or (not context["feedpagenum"] == context["feedpagecount"] - 1 and not context["feedpagenum"] == 0):
nslist["fh"] = "http://purl.org/syndication/history/1.0"
if not self.config["RSS_TEASERS"]:
nslist["xh"] = "http://www.w3.org/1999/xhtml"
@@ -1634,17 +1635,17 @@ def atom_link(link_rel, link_type, link_href):
if "prevfeedlink" in context:
feed_root.append(atom_link("previous", "application/atom+xml",
self.abs_link(context["prevfeedlink"])))
if not context["feedpagenum"] == 0:
if context["is_feed_stale"] or not context["feedpagenum"] == 0:
feed_root.append(atom_link("current", "application/atom+xml",
self.abs_link(context["currentfeedlink"])))
# Older is "prev-archive" and newer is "next-archive" in archived feeds (opposite of paginated)
if "prevfeedlink" in context and not context["feedpagenum"] == context["feedpagecount"] - 1:
if "prevfeedlink" in context and (context["is_feed_stale"] or not context["feedpagenum"] == context["feedpagecount"] - 1):
feed_root.append(atom_link("next-archive", "application/atom+xml",
self.abs_link(context["prevfeedlink"])))
if "nextfeedlink" in context:
feed_root.append(atom_link("prev-archive", "application/atom+xml",
self.abs_link(context["nextfeedlink"])))
if not context["feedpagenum"] == context["feedpagecount"] - 1:
if context["is_feed_stale"] or not context["feedpagenum"] == context["feedpagecount"] - 1:
lxml.etree.SubElement(feed_root, "{http://purl.org/syndication/history/1.0}archive")
feed_root.append(atom_link("alternate", "text/html",
self.abs_link(context["permalink"])))
@@ -28,6 +28,7 @@

# for tearDown with _reload we cannot use 'import from' to access LocaleBorg
import nikola.utils
import datetime
from nikola.plugin_categories import Task
from nikola.utils import config_changed, adjust_name_for_index_path, adjust_name_for_index_link

@@ -39,6 +40,7 @@ class Archive(Task):

def set_site(self, site):
site.register_path_handler('archive', self.archive_path)
site.register_path_handler('archive_atom', self.archive_atom_path)
return super(Archive, self).set_site(site)

def _prepare_task(self, kw, name, lang, posts, items, template_name,
@@ -81,6 +83,16 @@ def _generate_posts_task(self, kw, name, lang, posts, title, deps_translatable=N
posts = sorted(posts, key=lambda a: a.date)
posts.reverse()
if kw['archives_are_indexes']:
def page_link(i, displayed_i, num_pages, force_addition, extension=None):
feed = "_atom" if extension == ".atom" else ""
return adjust_name_for_index_link(self.site.link("archive" + feed, name, lang), i, displayed_i,
lang, self.site, force_addition, extension)

def page_path(i, displayed_i, num_pages, force_addition, extension=None):
feed = "_atom" if extension == ".atom" else ""
return adjust_name_for_index_path(self.site.path("archive" + feed, name, lang), i, displayed_i,
lang, self.site, force_addition, extension)

uptodate = []
if deps_translatable is not None:
uptodate += [config_changed(deps_translatable, 'nikola.plugins.task.archive')]
@@ -89,11 +101,12 @@ def _generate_posts_task(self, kw, name, lang, posts, title, deps_translatable=N
posts,
title,
"archiveindex.tmpl",
{},
{"archive_name": name,
"is_feed_stale": kw["is_feed_stale"]},
kw,
str(self.name),
lambda i, displayed_i, num_pages, force_addition: adjust_name_for_index_link(self.site.link("archive", name, lang), i, displayed_i, lang, self.site, force_addition),
lambda i, displayed_i, num_pages, force_addition: adjust_name_for_index_path(self.site.path("archive", name, lang), i, displayed_i, lang, self.site, force_addition),
page_link,
page_path,
uptodate)
else:
yield self._prepare_task(kw, name, lang, posts, None, "list_post.tmpl", title, deps_translatable)
@@ -113,6 +126,7 @@ def gen_tasks(self):
"pretty_urls": self.site.config['PRETTY_URLS'],
"strip_indexes": self.site.config['STRIP_INDEXES'],
"index_file": self.site.config['INDEX_FILE'],
"generate_atom": self.site.config["GENERATE_ATOM"],
}
self.site.scan_posts()
yield self.group_task()
@@ -138,8 +152,10 @@ def gen_tasks(self):
# Add archive per year or total archive
if year:
title = kw["messages"][lang]["Posts for year %s"] % year
kw["is_feed_stale"] = (datetime.datetime.utcnow().strftime("%Y") != year)
else:
title = kw["messages"][lang]["Archive"]
kw["is_feed_stale"] = False
deps_translatable = {}
for k in self.site._GLOBAL_CONTEXT_TRANSLATABLE:
deps_translatable[k] = self.site.GLOBAL_CONTEXT[k](lang)
@@ -158,6 +174,8 @@ def gen_tasks(self):
# Add archive per month
year, month = yearmonth.split('/')

kw["is_feed_stale"] = (datetime.datetime.utcnow().strftime("%Y/%m") != yearmonth)

# Filter untranslated posts (via Issue #1360)
if not kw["show_untranslated_posts"]:
posts = [p for p in posts if lang in p.translated_to]
@@ -189,12 +207,22 @@ def gen_tasks(self):
items = [(y, self.site.link("archive", y, lang)) for y in years]
yield self._prepare_task(kw, None, lang, None, items, "list.tmpl", kw["messages"][lang]["Archive"])

def archive_path(self, name, lang):
def archive_path(self, name, lang, is_feed=False):
if is_feed:
extension = ".atom"
archive_file = os.path.splitext(self.site.config['ARCHIVE_FILENAME'])[0] + extension
index_file = os.path.splitext(self.site.config['INDEX_FILE'])[0] + extension
else:
archive_file = self.site.config['ARCHIVE_FILENAME']
index_file = self.site.config['INDEX_FILE']
if name:
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
self.site.config['ARCHIVE_PATH'], name,
self.site.config['INDEX_FILE']] if _f]
index_file] if _f]
else:
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
self.site.config['ARCHIVE_PATH'],
self.site.config['ARCHIVE_FILENAME']] if _f]
archive_file] if _f]

def archive_atom_path(self, name, lang):
return self.archive_path(name, lang, is_feed=True)

0 comments on commit 728dd37

Please sign in to comment.