feed: make /feed API call configurable server and client-side

On server-side, this can be enabled by providing a base URL to use to
build the full URL. Limit also becomes configurable. On client-side,
we need to add a switch to know whatever or not the additional link
can be displayed.
This commit is contained in:
Vincent Bernat 2018-04-22 16:55:06 +02:00
parent bceb69518b
commit 45f6b1eda3
7 changed files with 66 additions and 10 deletions

View File

@ -20,7 +20,8 @@ preferably in the script tag which embeds the JS:
data-isso-avatar-bg="#f0f0f0" data-isso-avatar-bg="#f0f0f0"
data-isso-avatar-fg="#9abf88 #5698c4 #e279a3 #9163b6 ..." data-isso-avatar-fg="#9abf88 #5698c4 #e279a3 #9163b6 ..."
data-isso-vote="true" data-isso-vote="true"
data-vote-levels="" data-isso-vote-levels=""
data-isso-feed="false"
src="/prefix/js/embed.js"></script> src="/prefix/js/embed.js"></script>
Furthermore you can override the automatic title detection inside Furthermore you can override the automatic title detection inside
@ -125,3 +126,10 @@ For example, the value `"-5,5"` will cause each `isso-comment` to be given one o
- `isso-vote-level-2` for scores of `5` and greater - `isso-vote-level-2` for scores of `5` and greater
These classes can then be used to customize the appearance of comments (eg. put a star on popular comments) These classes can then be used to customize the appearance of comments (eg. put a star on popular comments)
data-isso-feed
--------------
Enable or disable the addition of a link to the feed for the comment
thread. The link will only be valid if the appropriate setting, in
``[rss]`` section, is also enabled server-side.

View File

@ -308,6 +308,27 @@ algorithm
Arguments have to be in that order, but can be reduced to `pbkdf2:4096` Arguments have to be in that order, but can be reduced to `pbkdf2:4096`
for example to override the iterations only. for example to override the iterations only.
.. _configure-rss:
RSS
---
Isso can provide an Atom feed for each comment thread. Users can use
them to subscribe to comments and be notified of changes. Atom feeds
are enabled as soon as there is a base URL defined in this section.
.. code-block:: ini
[rss]
base =
limit = 100
base
base URL to use to build complete URI to pages (by appending the URI from Isso)
limit
number of most recent comments to return for a thread
Appendum Appendum
-------- --------

View File

@ -15,7 +15,8 @@ define(function() {
"avatar-fg": ["#9abf88", "#5698c4", "#e279a3", "#9163b6", "avatar-fg": ["#9abf88", "#5698c4", "#e279a3", "#9163b6",
"#be5168", "#f19670", "#e4bf80", "#447c69"].join(" "), "#be5168", "#f19670", "#e4bf80", "#447c69"].join(" "),
"vote": true, "vote": true,
"vote-levels": null "vote-levels": null,
"feed": false
}; };
var js = document.getElementsByTagName("script"); var js = document.getElementsByTagName("script");

View File

@ -27,11 +27,13 @@ require(["app/lib/ready", "app/config", "app/i18n", "app/api", "app/isso", "app/
return console.log("abort, #isso-thread is missing"); return console.log("abort, #isso-thread is missing");
} }
var feedLink = $.new('a', i18n.translate('atom-feed')); if (config["feed"]) {
var feedLinkWrapper = $.new('span.isso-feedlink'); var feedLink = $.new('a', i18n.translate('atom-feed'));
feedLink.href = api.feed($("#isso-thread").getAttribute("data-isso-id")); var feedLinkWrapper = $.new('span.isso-feedlink');
feedLinkWrapper.append(feedLink); feedLink.href = api.feed($("#isso-thread").getAttribute("data-isso-id"));
$("#isso-thread").append(feedLinkWrapper); feedLinkWrapper.append(feedLink);
$("#isso-thread").append(feedLinkWrapper);
}
$("#isso-thread").append($.new('h4')); $("#isso-thread").append($.new('h4'));
$("#isso-thread").append(new isso.Postbox(null)); $("#isso-thread").append(new isso.Postbox(null));
$("#isso-thread").append('<div id="isso-root"></div>'); $("#isso-thread").append('<div id="isso-root"></div>');

View File

@ -31,9 +31,9 @@ class TestComments(unittest.TestCase):
fd, self.path = tempfile.mkstemp() fd, self.path = tempfile.mkstemp()
conf = config.load(os.path.join(dist.location, "share", "isso.conf")) conf = config.load(os.path.join(dist.location, "share", "isso.conf"))
conf.set("general", "dbpath", self.path) conf.set("general", "dbpath", self.path)
conf.set("general", "host", "https://example.org")
conf.set("guard", "enabled", "off") conf.set("guard", "enabled", "off")
conf.set("hash", "algorithm", "none") conf.set("hash", "algorithm", "none")
self.conf = conf
class App(Isso, core.Mixin): class App(Isso, core.Mixin):
pass pass
@ -326,7 +326,13 @@ class TestComments(unittest.TestCase):
self.assertListEqual(list(rv.keys()), []) self.assertListEqual(list(rv.keys()), [])
def testNoFeed(self):
rv = self.get('/feed?uri=%2Fpath%2Fnothing')
self.assertEqual(rv.status_code, 404)
def testFeedEmpty(self): def testFeedEmpty(self):
self.conf.set("rss", "base", "https://example.org")
rv = self.get('/feed?uri=%2Fpath%2Fnothing') rv = self.get('/feed?uri=%2Fpath%2Fnothing')
self.assertEqual(rv.status_code, 200) self.assertEqual(rv.status_code, 200)
self.assertEqual(rv.headers['ETag'], '"empty"') self.assertEqual(rv.headers['ETag'], '"empty"')
@ -335,6 +341,8 @@ class TestComments(unittest.TestCase):
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0"><updated>1970-01-01T01:00:00Z</updated><id>tag:example.org,2018:/isso/thread/path/nothing</id><title>Comments for example.org/path/nothing</title></feed>""") <feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0"><updated>1970-01-01T01:00:00Z</updated><id>tag:example.org,2018:/isso/thread/path/nothing</id><title>Comments for example.org/path/nothing</title></feed>""")
def testFeed(self): def testFeed(self):
self.conf.set("rss", "base", "https://example.org")
self.post('/new?uri=%2Fpath%2F', data=json.dumps({'text': 'First'})) self.post('/new?uri=%2Fpath%2F', data=json.dumps({'text': 'First'}))
self.post('/new?uri=%2Fpath%2F', self.post('/new?uri=%2Fpath%2F',
data=json.dumps({'text': 'First', 'parent': 1})) data=json.dumps({'text': 'First', 'parent': 1}))

View File

@ -854,11 +854,15 @@ class API(object):
""" """
@requires(str, 'uri') @requires(str, 'uri')
def feed(self, environ, request, uri): def feed(self, environ, request, uri):
conf = self.isso.conf.section("rss")
if not conf.get('base'):
raise NotFound
args = { args = {
'uri': uri, 'uri': uri,
'order_by': 'id', 'order_by': 'id',
'asc': 0, 'asc': 0,
'limit': 100 'limit': conf.getint('limit')
} }
try: try:
args['limit'] = max(int(request.args.get('limit')), args['limit']) args['limit'] = max(int(request.args.get('limit')), args['limit'])
@ -867,7 +871,7 @@ class API(object):
except ValueError: except ValueError:
return BadRequest("limit should be integer") return BadRequest("limit should be integer")
comments = self.comments.fetch(**args) comments = self.comments.fetch(**args)
base = self.conf.get('host').split()[0] base = conf.get('base')
hostname = urlparse(base).netloc hostname = urlparse(base).netloc
# Let's build an Atom feed. # Let's build an Atom feed.

View File

@ -180,3 +180,15 @@ salt = Eech7co8Ohloopo9Ol6baimi
# strengthening. Arguments have to be in that order, but can be reduced to # strengthening. Arguments have to be in that order, but can be reduced to
# pbkdf2:4096 for example to override the iterations only. # pbkdf2:4096 for example to override the iterations only.
algorithm = pbkdf2 algorithm = pbkdf2
[rss]
# Provide an Atom feed for each comment thread for users to subscribe to.
# The base URL of pages is needed to build the Atom feed. By appending
# the URI, we should get the complete URL to use to access the page
# with the comments. When empty, Atom feeds are disabled.
base =
# Limit the number of elements to return for each thread.
limit = 100