-
Notifications
You must be signed in to change notification settings - Fork 458
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
WIP: render author pages #1972
Merged
Merged
WIP: render author pages #1972
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
c0efaef
WIP: render authors pages
124dcc5
Fix style
63fd0ef
Add AUTHOR* variables to config
8d0baae
Fix
ccf0820
Use author description
07f0bb4
Add author related tempaltes to base
8d80677
Add author tempalte to bootstrap3
2dbe15b
Fix tag template
be162a0
Update messages_en.py
a8422d2
Remove pointless code
ad710b1
Fix key error
d58afc6
Remove unused imports
e3e0b04
Fix style
a594801
Fix
083ce3c
pygal v2.0.4
Kwpolska 0b24500
Merge pull request #1981 from getnikola/posts-categories
da2x 14ca39d
WIP: render authors pages
5caf0c3
Fix style
e75341e
Add AUTHOR* variables to config
f4fb9c8
Fix
eb11672
Use author description
7eaa217
Add author related tempaltes to base
e2f9dac
Add author tempalte to bootstrap3
e8b4498
Fix tag template
2a0f5e8
Update messages_en.py
c763177
Remove pointless code
7ed2db0
Fix key error
664a1b8
Remove unused imports
be91d91
Fix style
4de1133
Fix
98d8973
Merge branch 'master' of github.com:jjconti/nikola
1f47671
Restore removed \n
d9f3387
Add ENABLE_AUTHOR_PAGES conf
c0841d4
Only generate author pages if ENABLE_AUTHOR_PAGES is True and there i…
679ed98
Add author_pages_generated to global context to use it in tamplates
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next
Next commit
WIP: render authors pages
- Loading branch information
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[Core] | ||
Name = render_authors | ||
Module = authors | ||
|
||
[Documentation] | ||
Author = Juanjo Conti | ||
Version = 0.1 | ||
Website = http://getnikola.com | ||
Description = Render the author pages and feeds. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,294 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
# Copyright © 2015 Juanjo Conti. | ||
|
||
# Permission is hereby granted, free of charge, to any | ||
# person obtaining a copy of this software and associated | ||
# documentation files (the "Software"), to deal in the | ||
# Software without restriction, including without limitation | ||
# the rights to use, copy, modify, merge, publish, | ||
# distribute, sublicense, and/or sell copies of the | ||
# Software, and to permit persons to whom the Software is | ||
# furnished to do so, subject to the following conditions: | ||
# | ||
# The above copyright notice and this permission notice | ||
# shall be included in all copies or substantial portions of | ||
# the Software. | ||
# | ||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY | ||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | ||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | ||
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS | ||
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
|
||
"""Render the author pages and feeds.""" | ||
|
||
from __future__ import unicode_literals | ||
import json | ||
import os | ||
import sys | ||
import natsort | ||
try: | ||
from urlparse import urljoin | ||
except ImportError: | ||
from urllib.parse import urljoin # NOQA | ||
from collections import defaultdict | ||
|
||
from nikola.plugin_categories import Task | ||
from nikola import utils | ||
|
||
|
||
class RenderAuthors(Task): | ||
|
||
"""Render the author pages and feeds.""" | ||
|
||
name = "render_authors" | ||
posts_per_author = None | ||
|
||
def set_site(self, site): | ||
"""Set Nikola site.""" | ||
site.register_path_handler('author_index', self.author_index_path) | ||
site.register_path_handler('author', self.author_path) | ||
site.register_path_handler('author_atom', self.author_atom_path) | ||
site.register_path_handler('author_rss', self.author_rss_path) | ||
return super(RenderAuthors, self).set_site(site) | ||
|
||
def gen_tasks(self): | ||
"""Render the author pages and feeds.""" | ||
kw = { | ||
"translations": self.site.config["TRANSLATIONS"], | ||
"blog_title": self.site.config["BLOG_TITLE"], | ||
"site_url": self.site.config["SITE_URL"], | ||
"base_url": self.site.config["BASE_URL"], | ||
"messages": self.site.MESSAGES, | ||
"output_folder": self.site.config['OUTPUT_FOLDER'], | ||
"filters": self.site.config['FILTERS'], | ||
'author_path': self.site.config['AUTHOR_PATH'], | ||
"author_pages_are_indexes": self.site.config['AUTHOR_PAGES_ARE_INDEXES'], | ||
"generate_rss": self.site.config['GENERATE_RSS'], | ||
"rss_teasers": self.site.config["RSS_TEASERS"], | ||
"rss_plain": self.site.config["RSS_PLAIN"], | ||
"rss_link_append_query": self.site.config["RSS_LINKS_APPEND_QUERY"], | ||
"show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'], | ||
"feed_length": self.site.config['FEED_LENGTH'], | ||
"tzinfo": self.site.tzinfo, | ||
"pretty_urls": self.site.config['PRETTY_URLS'], | ||
"strip_indexes": self.site.config['STRIP_INDEXES'], | ||
"index_file": self.site.config['INDEX_FILE'], | ||
} | ||
|
||
self.site.scan_posts() | ||
yield self.group_task() | ||
|
||
yield self.list_authors_page(kw) | ||
|
||
if not self._posts_per_author(): # this may be self.site.posts_per_author | ||
return | ||
|
||
author_list = list(self._posts_per_author().items()) | ||
|
||
def render_lists(author, posts): | ||
"""Render author pages as RSS files and lists/indexes.""" | ||
post_list = sorted(posts, key=lambda a: a.date) | ||
post_list.reverse() | ||
for lang in kw["translations"]: | ||
if kw["show_untranslated_posts"]: | ||
filtered_posts = post_list | ||
else: | ||
filtered_posts = [x for x in post_list if x.is_translation_available(lang)] | ||
if kw["generate_rss"]: | ||
yield self.author_rss(author, lang, filtered_posts, kw) | ||
# Render HTML | ||
if kw['author_pages_are_indexes']: | ||
yield self.author_page_as_index(author, lang, filtered_posts, kw) | ||
else: | ||
yield self.author_page_as_list(tag, lang, filtered_posts, kw) | ||
|
||
for author, posts in author_list: | ||
for task in render_lists(author, posts): | ||
yield task | ||
|
||
def _create_authors_page(self, kw): | ||
"""Create a global "all authors" page for each language.""" | ||
template_name = "authors.tmpl" | ||
kw = kw.copy() | ||
for lang in kw["translations"]: | ||
authors = natsort.natsorted([author for author in self._posts_per_author().keys()], | ||
alg=natsort.ns.F | natsort.ns.IC) | ||
has_authors = (authors != []) | ||
kw['authors'] = authors | ||
output_name = os.path.join( | ||
kw['output_folder'], self.site.path('author_index', None, lang)) | ||
output_name = output_name | ||
context = {} | ||
if has_authors: | ||
context["title"] = kw["messages"][lang]["Authors"] | ||
context["items"] = [(author, self.site.link("author", author, lang)) for author | ||
in authors] | ||
else: | ||
context["items"] = None | ||
context["permalink"] = self.site.link("author_index", None, lang) | ||
context["description"] = context["title"] | ||
context["pagekind"] = ["list", "authors_page"] | ||
task = self.site.generic_post_list_renderer( | ||
lang, | ||
[], | ||
output_name, | ||
template_name, | ||
kw['filters'], | ||
context, | ||
) | ||
task['uptodate'] = task['uptodate'] + [utils.config_changed(kw, 'nikola.plugins.task.authors:page')] | ||
task['basename'] = str(self.name) | ||
yield task | ||
|
||
def list_authors_page(self, kw): | ||
"""Create a global "all authors" page for each language.""" | ||
yield self._create_authors_page(kw) | ||
|
||
def _get_title(self, author): | ||
return author | ||
|
||
def _get_description(self, author, lang): | ||
return author | ||
|
||
def author_page_as_index(self, author, lang, post_list, kw): | ||
"""Render a sort of index page collection using only this author's posts.""" | ||
kind = "author" | ||
|
||
def page_link(i, displayed_i, num_pages, force_addition, extension=None): | ||
feed = "_atom" if extension == ".atom" else "" | ||
return utils.adjust_name_for_index_link(self.site.link(kind + feed, author, 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 utils.adjust_name_for_index_path(self.site.path(kind + feed, author, lang), i, displayed_i, lang, self.site, force_addition, extension) | ||
|
||
context_source = {} | ||
title = self._get_title(author) | ||
if kw["generate_rss"]: | ||
# On a author page, the feeds include the author's feeds | ||
rss_link = ("""<link rel="alternate" type="application/rss+xml" """ | ||
"""type="application/rss+xml" title="RSS for author """ | ||
"""{0} ({1})" href="{2}">""".format( | ||
title, lang, self.site.link(kind + "_rss", author, lang))) | ||
context_source['rss_link'] = rss_link | ||
context_source["author"] = title | ||
indexes_title = kw["messages"][lang]["Posts by %s"] % title | ||
context_source["description"] = self._get_description(author, lang) | ||
context_source["pagekind"] = ["index", "author_page"] | ||
template_name = "authorindex.tmpl" | ||
|
||
yield self.site.generic_index_renderer(lang, post_list, indexes_title, template_name, context_source, kw, str(self.name), page_link, page_path) | ||
|
||
def author_page_as_list(self, author, lang, post_list, kw): | ||
"""Render a single flat link list with this author's posts.""" | ||
kind = "author" | ||
template_name = "author.tmpl" | ||
output_name = os.path.join(kw['output_folder'], self.site.path( | ||
kind, author, lang)) | ||
context = {} | ||
context["lang"] = lang | ||
title = self._get_title(author) | ||
context["author"] = title | ||
context["title"] = kw["messages"][lang]["Posts by %s"] % title | ||
context["posts"] = post_list | ||
context["permalink"] = self.site.link(kind, author, lang) | ||
context["kind"] = kind | ||
context["description"] = self._get_description(author, lang) | ||
context["pagekind"] = ["list", "author_page"] | ||
task = self.site.generic_post_list_renderer( | ||
lang, | ||
post_list, | ||
output_name, | ||
template_name, | ||
kw['filters'], | ||
context, | ||
) | ||
task['uptodate'] = task['uptodate'] + [utils.config_changed(kw, 'nikola.plugins.task.authors:list')] | ||
task['basename'] = str(self.name) | ||
yield task | ||
|
||
def author_rss(self, author, lang, posts, kw): | ||
"""Create a RSS feed for a single author in a given language.""" | ||
kind = "author" | ||
# Render RSS | ||
output_name = os.path.normpath( | ||
os.path.join(kw['output_folder'], | ||
self.site.path(kind + "_rss", author, lang))) | ||
feed_url = urljoin(self.site.config['BASE_URL'], self.site.link(kind + "_rss", author, lang).lstrip('/')) | ||
deps = [] | ||
deps_uptodate = [] | ||
post_list = sorted(posts, key=lambda a: a.date) | ||
post_list.reverse() | ||
for post in post_list: | ||
deps += post.deps(lang) | ||
deps_uptodate += post.deps_uptodate(lang) | ||
task = { | ||
'basename': str(self.name), | ||
'name': output_name, | ||
'file_dep': deps, | ||
'targets': [output_name], | ||
'actions': [(utils.generic_rss_renderer, | ||
(lang, "{0} ({1})".format(kw["blog_title"](lang), self._get_title(author)), | ||
kw["site_url"], None, post_list, | ||
output_name, kw["rss_teasers"], kw["rss_plain"], kw['feed_length'], | ||
feed_url, None, kw["rss_link_append_query"]))], | ||
'clean': True, | ||
'uptodate': [utils.config_changed(kw, 'nikola.plugins.task.authors:rss')] + deps_uptodate, | ||
'task_dep': ['render_posts'], | ||
} | ||
return utils.apply_filters(task, kw['filters']) | ||
|
||
def slugify_author_name(self, name): | ||
"""Slugify an author name.""" | ||
if self.site.config['SLUG_AUTHOR_PATH']: | ||
name = utils.slugify(name) | ||
return name | ||
|
||
def author_index_path(self, name, lang): | ||
"""Return path to the author index.""" | ||
return [_f for _f in [self.site.config['TRANSLATIONS'][lang], | ||
self.site.config['AUTHOR_PATH'], | ||
self.site.config['INDEX_FILE']] if _f] | ||
|
||
def author_path(self, name, lang): | ||
"""Return path to an author.""" | ||
if self.site.config['PRETTY_URLS']: | ||
return [_f for _f in [ | ||
self.site.config['TRANSLATIONS'][lang], | ||
self.site.config['AUTHOR_PATH'], | ||
self.slugify_author_name(name), | ||
self.site.config['INDEX_FILE']] if _f] | ||
else: | ||
return [_f for _f in [ | ||
self.site.config['TRANSLATIONS'][lang], | ||
self.site.config['AUTHOR_PATH'], | ||
self.slugify_author_name(name) + ".html"] if _f] | ||
|
||
def author_atom_path(self, name, lang): | ||
"""Return path to an author Atom feed.""" | ||
return [_f for _f in [self.site.config['TRANSLATIONS'][lang], | ||
self.site.config['AUTHOR_PATH'], self.slugify_author_name(name) + ".atom"] if | ||
_f] | ||
|
||
def author_rss_path(self, name, lang): | ||
"""Return path to an author RSS feed.""" | ||
return [_f for _f in [self.site.config['TRANSLATIONS'][lang], | ||
self.site.config['AUTHOR_PATH'], self.slugify_author_name(name) + ".xml"] if | ||
_f] | ||
|
||
def _add_extension(self, path, extension): | ||
path[-1] += extension | ||
return path | ||
|
||
def _posts_per_author(self): | ||
"""Return a dict of posts per author""" | ||
if self.posts_per_author is None: | ||
self.posts_per_author = defaultdict(list) | ||
for post in self.site.timeline: | ||
self.posts_per_author[post.author()].append(post) | ||
return self.posts_per_author |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added documentation for this new pagekind as well as all the other existing ones to
docs/theming.txt
.