Skip to content

Commit

Permalink
merged master
Browse files Browse the repository at this point in the history
  • Loading branch information
ralsina committed Jul 18, 2016
2 parents 7c4d214 + f47705f commit d566ee3
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 5 deletions.
4 changes: 3 additions & 1 deletion CHANGES.txt
Expand Up @@ -5,9 +5,11 @@ Features
--------

* New EXIF_WHITELIST option to filter EXIF data.
* Support ``date`` filtering in the post list directive
(Issue #1889)
* Support ``doc`` shortcode (equivalent to reST ``doc`` role — part of
Issue #2170)
* Albanian translation by Vango Stavro
* Added Albanian translation by Vango Stavro
* Added ``post-(type)`` class to ``story.tmpl`` (uses the ``type``
meta field, defaults to ``post-text`` — same behavior as posts)
* New ``compiled`` signal after post is compiled (Issue #2369)
Expand Down
9 changes: 9 additions & 0 deletions docs/manual.txt
Expand Up @@ -1972,6 +1972,15 @@ The following options are recognized:
Sort post list by one of each post's attributes, usually ``title`` or a
custom ``priority``. Defaults to None (chronological sorting).

* ``date``: string
Show posts that match date range specified by this option. Format:

* comma-separated clauses (AND)
* clause: attribute comparison_operator value (spaces optional)
* attribute: year, month, day, hour, month, second, weekday, isoweekday; or empty for full datetime
* comparison_operator: == != <= >= < >
* value: integer or dateutil-compatible date input

* ``tags`` : string [, string...]
Filter posts to show only posts having at least one of the ``tags``.
Defaults to None.
Expand Down
2 changes: 2 additions & 0 deletions nikola/packages/README.md
Expand Up @@ -3,3 +3,5 @@ We ship some third-party things with Nikola. They live here, along with their l
Packages:

* tzlocal by Lennart Regebro, CC0 license (modified)
* datecond by Chris Warrick (Nikola contributor), 3-clause BSD license
(modified)
30 changes: 30 additions & 0 deletions nikola/packages/datecond/LICENSE
@@ -0,0 +1,30 @@
Copyright © 2016, Chris Warrick.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution.

3. Neither the name of the author of this software nor the names of
contributors to this software may be used to endorse or promote
products derived from this software without specific prior written
consent.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
85 changes: 85 additions & 0 deletions nikola/packages/datecond/__init__.py
@@ -0,0 +1,85 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Date Conditionals (datecond)
# Version 0.1.2
# Copyright © 2015-2016, Chris Warrick.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the author of this software nor the names of
# contributors to this software may be used to endorse or promote
# products derived from this software without specific prior written
# consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""Date range parser."""

from __future__ import print_function, unicode_literals
import dateutil.parser
import re
import operator


__all__ = ('date_in_range',)
CLAUSE = re.compile('(year|month|day|hour|minute|second|weekday|isoweekday)?'
' ?(==|!=|<=|>=|<|>) ?(.*)')
OPERATORS = {
'==': operator.eq,
'!=': operator.ne,
'<=': operator.le,
'>=': operator.ge,
'<': operator.lt,
'>': operator.gt,
}


def date_in_range(date_range, date, debug=True):
"""Check if date is in the range specified.
Format:
* comma-separated clauses (AND)
* clause: attribute comparison_operator value (spaces optional)
* attribute: year, month, day, hour, month, second, weekday, isoweekday
or empty for full datetime
* comparison_operator: == != <= >= < >
* value: integer or dateutil-compatible date input
"""
out = True

for item in date_range.split(','):
attribute, comparison_operator, value = CLAUSE.match(
item.strip()).groups()
if attribute in ('weekday', 'isoweekday'):
left = getattr(date, attribute)()
right = int(value)
elif attribute:
left = getattr(date, attribute)
right = int(value)
else:
left = date
right = dateutil.parser.parse(value)
if debug: # pragma: no cover
print(" <{0} {1} {2}>".format(left, comparison_operator, right))
out = out and OPERATORS[comparison_operator](left, right)
return out
26 changes: 22 additions & 4 deletions nikola/plugins/compile/rest/post_list.py
Expand Up @@ -37,6 +37,7 @@

from nikola import utils
from nikola.plugin_categories import RestExtension
from nikola.packages.datecond import date_in_range

# WARNING: the directive name is post-list
# (with a DASH instead of an UNDERSCORE)
Expand Down Expand Up @@ -86,10 +87,19 @@ class PostList(Directive):
Reverse the order of the post-list.
Defaults is to not reverse the order of posts.
``sort``: string
``sort`` : string
Sort post list by one of each post's attributes, usually ``title`` or a
custom ``priority``. Defaults to None (chronological sorting).
``date`` : string
Show posts that match date range specified by this option. Format:
* comma-separated clauses (AND)
* clause: attribute comparison_operator value (spaces optional)
* attribute: year, month, day, hour, month, second, weekday, isoweekday; or empty for full datetime
* comparison_operator: == != <= >= < >
* value: integer or dateutil-compatible date input
``tags`` : string [, string...]
Filter posts to show only posts having at least one of the ``tags``.
Defaults to None.
Expand Down Expand Up @@ -136,6 +146,7 @@ class PostList(Directive):
'lang': directives.unchanged,
'template': directives.path,
'id': directives.unchanged,
'date': directives.unchanged,
}

def run(self):
Expand All @@ -154,17 +165,21 @@ def run(self):
lang = self.options.get('lang', utils.LocaleBorg().current_lang)
template = self.options.get('template', 'post_list_directive.tmpl')
sort = self.options.get('sort')
date = self.options.get('date')

output = _do_post_list(start, stop, reverse, tags, categories, slugs, post_type,
show_all, lang, template, sort, state=self.state, site=self.site)
show_all, lang, template, sort, state=self.state, site=self.site, date=date)
self.state.document.settings.record_dependencies.add("####MAGIC####TIMELINE")
return [nodes.raw('', output, format='html')]
if output:
return [nodes.raw('', output, format='html')]
else:
return []


def _do_post_list(start=None, stop=None, reverse=False, tags=None, categories=None,
slugs=None, post_type='post', show_all=False, lang=None,
template='post_list_directive.tmpl', sort=None, id=None,
data=None, state=None, site=None):
data=None, state=None, site=None, date=None):
if lang is None:
lang = utils.LocaleBorg().current_lang
if site.invariant: # for testing purposes
Expand Down Expand Up @@ -213,6 +228,9 @@ def _do_post_list(start=None, stop=None, reverse=False, tags=None, categories=No
if sort:
filtered_timeline = natsort.natsorted(filtered_timeline, key=lambda post: post.meta[lang][sort], alg=natsort.ns.F | natsort.ns.IC)

if date:
filtered_timeline = [p for p in filtered_timeline if date_in_range(date, p.date)]

for post in filtered_timeline[start:stop:step]:
if slugs:
cont = True
Expand Down

0 comments on commit d566ee3

Please sign in to comment.