New 'latest' endpoint to serve latest comments.
This commit is contained in:
parent
1de758887a
commit
1633d9261e
@ -110,6 +110,10 @@ gravatar-url
|
||||
Url for gravatar images. The "{}" is where the email hash will be placed.
|
||||
Defaults to "https://www.gravatar.com/avatar/{}?d=identicon"
|
||||
|
||||
latest-enabled
|
||||
If True it will enable the ``/latest`` endpoint. Optional, defaults
|
||||
to False.
|
||||
|
||||
|
||||
|
||||
.. _CORS: https://developer.mozilla.org/en/docs/HTTP/Access_control_CORS
|
||||
|
@ -83,6 +83,19 @@ plain :
|
||||
pass plain=1 to get the raw comment text, defaults to 0.
|
||||
|
||||
|
||||
Get the latest N comments for all threads:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
GET /latest?limit=N
|
||||
|
||||
The N parameter limits how many of the latest comments to retrieve; it's
|
||||
mandatory, and must be an integer greater than 0.
|
||||
|
||||
This endpoint needs to be enabled in the configuration (see the
|
||||
``latest-enabled`` option in the ``general`` section).
|
||||
|
||||
|
||||
Create comment
|
||||
--------------
|
||||
|
||||
|
@ -33,6 +33,7 @@ class TestComments(unittest.TestCase):
|
||||
conf.set("general", "dbpath", self.path)
|
||||
conf.set("guard", "enabled", "off")
|
||||
conf.set("hash", "algorithm", "none")
|
||||
conf.set("general", "latest-enabled", "true")
|
||||
self.conf = conf
|
||||
|
||||
class App(Isso, core.Mixin):
|
||||
@ -451,6 +452,48 @@ class TestComments(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
rv["text"], '<p>This is <strong>mark</strong><em>down</em></p>')
|
||||
|
||||
def testLatestOk(self):
|
||||
# load some comments in a mix of posts
|
||||
saved = []
|
||||
for idx, post_id in enumerate([1, 2, 2, 1, 2, 1, 3, 1, 4, 2, 3, 4, 1, 2]):
|
||||
text = 'text-{}'.format(idx)
|
||||
post_uri = 'test-{}'.format(post_id)
|
||||
self.post('/new?uri=' + post_uri, data=json.dumps({'text': text}))
|
||||
saved.append((post_uri, text))
|
||||
|
||||
response = self.get('/latest?limit=5')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
body = loads(response.data)
|
||||
expected_items = saved[-5:] # latest 5
|
||||
for reply, expected in zip(body, expected_items):
|
||||
expected_uri, expected_text = expected
|
||||
self.assertIn(expected_text, reply['text'])
|
||||
self.assertEqual(expected_uri, reply['uri'])
|
||||
|
||||
def testLatestWithoutLimit(self):
|
||||
response = self.get('/latest')
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
def testLatestBadLimitNaN(self):
|
||||
response = self.get('/latest?limit=WAT')
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
def testLatestBadLimitNegative(self):
|
||||
response = self.get('/latest?limit=-12')
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
def testLatestBadLimitZero(self):
|
||||
response = self.get('/latest?limit=0')
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
def testLatestNotEnabled(self):
|
||||
# disable the endpoint
|
||||
self.conf.set("general", "latest-enabled", "false")
|
||||
|
||||
response = self.get('/latest?limit=5')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
|
||||
class TestModeratedComments(unittest.TestCase):
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import collections
|
||||
import re
|
||||
import time
|
||||
import functools
|
||||
@ -112,6 +113,7 @@ class API(object):
|
||||
('count', ('GET', '/count')),
|
||||
('counts', ('POST', '/count')),
|
||||
('feed', ('GET', '/feed')),
|
||||
('latest', ('GET', '/latest')),
|
||||
('view', ('GET', '/id/<int:id>')),
|
||||
('edit', ('PUT', '/id/<int:id>')),
|
||||
('delete', ('DELETE', '/id/<int:id>')),
|
||||
@ -1136,3 +1138,89 @@ class API(object):
|
||||
counts=comment_mode_count,
|
||||
order_by=order_by, asc=asc,
|
||||
isso_host_script=isso_host_script)
|
||||
"""
|
||||
@api {get} /latest latest
|
||||
@apiGroup Comment
|
||||
@apiDescription
|
||||
Get the latest comments from the system, no matter which thread
|
||||
|
||||
@apiParam {number} limit
|
||||
The quantity of last comments to retrieve
|
||||
|
||||
@apiExample {curl} Get the latest 5 comments
|
||||
curl 'https://comments.example.com/latest?limit=5'
|
||||
|
||||
@apiUse commentResponse
|
||||
|
||||
@apiSuccessExample Example result:
|
||||
[
|
||||
{
|
||||
"website": null,
|
||||
"uri": "/some",
|
||||
"author": null,
|
||||
"parent": null,
|
||||
"created": 1464912312.123416,
|
||||
"text": " <p>I want to use MySQL</p>",
|
||||
"dislikes": 0,
|
||||
"modified": null,
|
||||
"mode": 1,
|
||||
"id": 3,
|
||||
"likes": 1
|
||||
},
|
||||
{
|
||||
"website": null,
|
||||
"uri": "/other",
|
||||
"author": null,
|
||||
"parent": null,
|
||||
"created": 1464914341.312426,
|
||||
"text": " <p>I want to use MySQL</p>",
|
||||
"dislikes": 0,
|
||||
"modified": null,
|
||||
"mode": 1,
|
||||
"id": 4,
|
||||
"likes": 0
|
||||
}
|
||||
]
|
||||
"""
|
||||
|
||||
def latest(self, environ, request):
|
||||
# if the feature is not allowed, don't present the endpoint
|
||||
if not self.conf.getboolean("latest-enabled"):
|
||||
return NotFound()
|
||||
|
||||
# get and check the limit
|
||||
bad_limit_msg = "Query parameter 'limit' is mandatory (integer, >0)"
|
||||
try:
|
||||
limit = int(request.args['limit'])
|
||||
except (KeyError, ValueError):
|
||||
return BadRequest(bad_limit_msg)
|
||||
if limit <= 0:
|
||||
return BadRequest(bad_limit_msg)
|
||||
|
||||
# retrieve the latest N comments from the DB
|
||||
all_comments_gen = self.comments.fetchall(limit=None, order_by='created', mode='1')
|
||||
comments = collections.deque(all_comments_gen, maxlen=limit)
|
||||
|
||||
# prepare a special set of fields (except text which is rendered specifically)
|
||||
fields = {
|
||||
'author',
|
||||
'created',
|
||||
'dislikes',
|
||||
'id',
|
||||
'likes',
|
||||
'mode',
|
||||
'modified',
|
||||
'parent',
|
||||
'text',
|
||||
'uri',
|
||||
'website',
|
||||
}
|
||||
|
||||
# process the retrieved comments and build results
|
||||
result = []
|
||||
for comment in comments:
|
||||
processed = {key: comment[key] for key in fields}
|
||||
processed['text'] = self.isso.render(comment['text'])
|
||||
result.append(processed)
|
||||
|
||||
return JSON(result, 200)
|
||||
|
@ -59,6 +59,10 @@ gravatar = false
|
||||
# default url for gravatar. {} is where the hash will be placed
|
||||
gravatar-url = https://www.gravatar.com/avatar/{}?d=identicon
|
||||
|
||||
# enable the "/latest" endpoint, that serves comment for multiple posts (not
|
||||
# needing to previously know the posts URIs)
|
||||
latest-enabled = false
|
||||
|
||||
[admin]
|
||||
enabled = false
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user