From aa373f798ff22844692341c60c605bf627744cd7 Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Thu, 2 Jun 2016 22:01:49 +0200 Subject: [PATCH 01/11] + apidoc.json The apidoc.json file configures the ApiDoc tools. It generates AJAX API documentation out of comments in the source code. --- apidoc.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 apidoc.json diff --git a/apidoc.json b/apidoc.json new file mode 100644 index 0000000..760e429 --- /dev/null +++ b/apidoc.json @@ -0,0 +1,6 @@ +{ + "name": "isso", + "description": "a Disqus alternative", + "title": "isso API" +} + From 5ca5d680fa0eb9496bbab22e2331ad59c8658e6b Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Thu, 2 Jun 2016 22:02:06 +0200 Subject: [PATCH 02/11] apidoc for fetch --- isso/views/comments.py | 84 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/isso/views/comments.py b/isso/views/comments.py index 0272fa3..baa720a 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -347,6 +347,90 @@ class API(object): return Response("Yo", 200) + + """ + @api {get} / get comments + @apiGroup Thread + @apiDescription Queries the comments of a thread. + + @apiParam {string} uri + The URI of thread to get the comments from. + @apiParam {number} [parent] + Return only comments that are children of the comment with the provided ID. + @apiParam {number=0,1} [plain] + Iff set to `1`, the plain text entered by the user will be returned in the comments’ `text` attribute (instead of the rendered markdown). + @apiParam {number} [limit] + The maximum number of returned top-level comments. Omit for unlimited results. + @apiParam {number} [nested_limit] + The maximum number of returned nested comments per commint. Omit for unlimited results. + @apiParam {number} [after] + Includes only comments were added after the provided UNIX timestamp. + + @apiSuccess {number} total_replies + The number of replies if the `limit` parameter was not set. If `after` is set to `X`, this is the number of comments that were created after `X`. So setting `after` may change this value! + @apiSuccess {Object[]} replies + The list of comments. Each comment also has the `total_replies`, `replies`, `id` and `hidden_replies` properties to represent nested comments. + @apiSuccess {number} id + Id of the comment `replies` is the list of replies of. `null` for the list of toplevel comments. + @apiSuccess {number} hidden_replies + The number of comments that were ommited from the results because of the `limit` request parameter. Usually, this will be `total_replies` - `limit`. + + @apiExample {curl} Get 2 comments with 5 responses: + curl 'https://comments.example.com/?uri=/thread/&limit=2&nested_limit=5' + @apiSuccessExample Example reponse: + { + "total_replies": 14, + "replies": [ + { + "website": null, + "author": null, + "parent": null, + "created": 1464818460.732863, + "text": "<p>Hello, World!</p>", + "total_replies": 1, + "hidden_replies": 0, + "dislikes": 2, + "modified": null, + "mode": 1, + "replies": [ + { + "website": null, + "author": null, + "parent": 1, + "created": 1464818460.769638, + "text": "<p>Hi, now some Markdown: <em>Italic</em>, <strong>bold</strong>, <code>monospace</code>.</p>", + "dislikes": 0, + "modified": null, + "mode": 1, + "hash": "2af4e1a6c96a", + "id": 2, + "likes": 2 + } + ], + "hash": "1cb6cc0309a2", + "id": 1, + "likes": 2 + }, + { + "website": null, + "author": null, + "parent": null, + "created": 1464818460.80574, + "text": "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium at commodi cum deserunt dolore, error fugiat harum incidunt, ipsa ipsum mollitia nam provident rerum sapiente suscipit tempora vitae? Est, qui?</p>", + "total_replies": 0, + "hidden_replies": 0, + "dislikes": 0, + "modified": null, + "mode": 1, + "replies": [], + "hash": "1cb6cc0309a2", + "id": 3, + "likes": 0 + }, + "id": null, + "hidden_replies": 12 + } + """ @requires(str, 'uri') def fetch(self, environ, request, uri): From b2d9c80b5f17fb86b797ff86da6acb9dd2805bd0 Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Fri, 3 Jun 2016 10:13:13 +0200 Subject: [PATCH 03/11] apidoc for "new comment" --- isso/views/comments.py | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/isso/views/comments.py b/isso/views/comments.py index baa720a..8cf0cab 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -60,6 +60,12 @@ def xhr(func): not forged (XHR is restricted by CORS separately). """ + + """ + @apiDefine csrf + @apiHeader {string="application/json"} Content-Type + The content type must be set to `application/json` to prevent CSRF attacks. + """ def dec(self, env, req, *args, **kwargs): if req.content_type and not req.content_type.startswith("application/json"): @@ -140,6 +146,64 @@ class API(object): return True, "" + """ + @api {post} /new create new + @apiGroup Comment + @apiUse csrf + + @apiParam {string} uri + The uri of the thread to create the comment on. + @apiParam {string} text + The comment’s raw text. + @apiParam {string} [author] + The comment’s author’s name. + @apiParam {string} [email] + The comment’s author’s email address. + @apiParam {string} [website] + The comment’s author’s website’s url. + @apiParam {number} [parent] + The parent comment’s id iff the new comment is a response to an existing comment. + + @apiExample {curl} Create a reply to comment with id 15: + curl 'https://comments.example.com/new?uri=/thread/' -d '{"text": "Stop saying that! *isso*!", "author": "Max Rant", "email": "rant@example.com", "parent": 15}' -H 'Content-Type: application/json' + + @apiSuccess {number} id + The comment’s id (assigned by the server). + @apiSuccess {number} parent + Id of the comment this comment is a reply to. `null` if this is a top-level-comment. + @apiSuccess {number=1,2,4} mode + The comment’s mode: + value | explanation + --- | --- + `1` | accepted: The comment was accepted by the server and is published. + `2` | in moderation queue: The comment was accepted by the server but awaits moderation. + `4` | deleted, but referenced: The comment was deleted on the server but is still referenced by replies. + @apiSuccess {string} author + The comments’s author’s name or `null`. + @apiSuccess {string} website + The comment’s author’s website or `null`. + @apiSuccess {string} hash + A hash uniquely identifying the comment’s author. + @apiSuccess {number} created + UNIX timestamp of the time the comment was created (on the server). + @apiSuccess {number} modified + UNIX timestamp of the time the comment was last modified (on the server). `null` if the comment was not yet modified. + + @apiSuccessExample Success after the above request: + { + "website": null, + "author": "Max Rant", + "parent": 15, + "created": 1464940838.254393, + "text": "<p>Stop saying that! <em>isso</em>!</p>", + "dislikes": 0, + "modified": null, + "mode": 1, + "hash": "e644f6ee43c0", + "id": 10, + "likes": 0 + } + """ @xhr @requires(str, 'uri') def new(self, environ, request, uri): From 1f804bcf8e2fb40cfc2f7b79e2837d3abee7296e Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Fri, 3 Jun 2016 10:28:51 +0200 Subject: [PATCH 04/11] apidoc for "view comment" --- isso/views/comments.py | 84 ++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 23 deletions(-) diff --git a/isso/views/comments.py b/isso/views/comments.py index 8cf0cab..68ed6df 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -146,26 +146,14 @@ class API(object): return True, "" - """ - @api {post} /new create new - @apiGroup Comment - @apiUse csrf - - @apiParam {string} uri - The uri of the thread to create the comment on. - @apiParam {string} text - The comment’s raw text. - @apiParam {string} [author] - The comment’s author’s name. - @apiParam {string} [email] - The comment’s author’s email address. - @apiParam {string} [website] - The comment’s author’s website’s url. - @apiParam {number} [parent] - The parent comment’s id iff the new comment is a response to an existing comment. - - @apiExample {curl} Create a reply to comment with id 15: - curl 'https://comments.example.com/new?uri=/thread/' -d '{"text": "Stop saying that! *isso*!", "author": "Max Rant", "email": "rant@example.com", "parent": 15}' -H 'Content-Type: application/json' + # Common definitions for apidoc follow: + """ + @apiDefine plainParam + @apiParam {number=0,1} [plain] + Iff set to `1`, the plain text entered by the user will be returned in the comments’ `text` attribute (instead of the rendered markdown). + """ + """ + @apiDefine commentResponse @apiSuccess {number} id The comment’s id (assigned by the server). @@ -188,6 +176,30 @@ class API(object): UNIX timestamp of the time the comment was created (on the server). @apiSuccess {number} modified UNIX timestamp of the time the comment was last modified (on the server). `null` if the comment was not yet modified. + """ + + """ + @api {post} /new create new + @apiGroup Comment + @apiUse csrf + + @apiParam {string} uri + The uri of the thread to create the comment on. + @apiParam {string} text + The comment’s raw text. + @apiParam {string} [author] + The comment’s author’s name. + @apiParam {string} [email] + The comment’s author’s email address. + @apiParam {string} [website] + The comment’s author’s website’s url. + @apiParam {number} [parent] + The parent comment’s id iff the new comment is a response to an existing comment. + + @apiExample {curl} Create a reply to comment with id 15: + curl 'https://comments.example.com/new?uri=/thread/' -d '{"text": "Stop saying that! *isso*!", "author": "Max Rant", "email": "rant@example.com", "parent": 15}' -H 'Content-Type: application/json' + + @apiUse commentResponse @apiSuccessExample Success after the above request: { @@ -200,7 +212,7 @@ class API(object): "modified": null, "mode": 1, "hash": "e644f6ee43c0", - "id": 10, + "id": 23, "likes": 0 } """ @@ -277,6 +289,33 @@ class API(object): resp.headers.add("X-Set-Cookie", cookie("isso-%i" % rv["id"])) return resp + """ + @api {get} /id/:id view + @apiGroup Comment + + @apiParam {number} id + The id of the comment to view. + @apiUse plainParam + + @apiExample {curl} View the comment with id 4: + curl 'https://comments.example.com/id/4' + + @apiUse commentResponse + + @apiSuccessExample Example result: + { + "website": null, + "author": null, + "parent": null, + "created": 1464914341.312426, + "text": " <p>I want to use MySQL</p>", + "dislikes": 0, + "modified": null, + "mode": 1, + "id": 4, + "likes": 1 + } + """ def view(self, environ, request, id): rv = self.comments.get(id) @@ -421,8 +460,7 @@ class API(object): The URI of thread to get the comments from. @apiParam {number} [parent] Return only comments that are children of the comment with the provided ID. - @apiParam {number=0,1} [plain] - Iff set to `1`, the plain text entered by the user will be returned in the comments’ `text` attribute (instead of the rendered markdown). + @apiUse plainParam @apiParam {number} [limit] The maximum number of returned top-level comments. Omit for unlimited results. @apiParam {number} [nested_limit] From 9b79a98851939355faa58bd2594a698a9b45bc05 Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Fri, 3 Jun 2016 10:50:57 +0200 Subject: [PATCH 05/11] apidoc for "edit comment" --- isso/views/comments.py | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/isso/views/comments.py b/isso/views/comments.py index 68ed6df..24e01fe 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -181,6 +181,8 @@ class API(object): """ @api {post} /new create new @apiGroup Comment + @apiDescription + Creates a new comment. The response will set a cookie on the requestor to enable them to later edit the comment. @apiUse csrf @apiParam {string} uri @@ -197,7 +199,7 @@ class API(object): The parent comment’s id iff the new comment is a response to an existing comment. @apiExample {curl} Create a reply to comment with id 15: - curl 'https://comments.example.com/new?uri=/thread/' -d '{"text": "Stop saying that! *isso*!", "author": "Max Rant", "email": "rant@example.com", "parent": 15}' -H 'Content-Type: application/json' + curl 'https://comments.example.com/new?uri=/thread/' -d '{"text": "Stop saying that! *isso*!", "author": "Max Rant", "email": "rant@example.com", "parent": 15}' -H 'Content-Type: application/json' -c cookie.txt @apiUse commentResponse @@ -330,6 +332,41 @@ class API(object): return JSON(rv, 200) + """ + @api {put} /id/:id edit + @apiGroup Comment + @apiDescription + Edit an existing comment. Editing a comment is only possible for a short period of time after it was created and only if the requestor has a valid cookie for it. See the [isso server documentation](https://posativ.org/isso/docs/configuration/server) for details. Editing a comment will set a new edit cookie in the response. + @apiUse csrf + + @apiParam {number} id + The id of the comment to edit. + @apiParam {string} text + A new (raw) text for the comment. + @apiParam {string} [author] + The modified comment’s author’s name. + @apiParam {string} [webiste] + The modified comment’s author’s website. + + @apiExample {curl} Edit comment with id 23: + curl -X PUT 'https://comments.example.com/id/23' -d {"text": "I see your point. However, I still disagree.", "website": "maxrant.important.com"} -H 'Content-Type: application/json' -b cookie.txt + + @apiUse commentResponse + + @apiSuccessExample Example response: + { + "website": "maxrant.important.com", + "author": "Max Rant", + "parent": 15, + "created": 1464940838.254393, + "text": "<p>I see your point. However, I still disagree.</p>", + "dislikes": 0, + "modified": 1464943439.073961, + "mode": 1, + "id": 23, + "likes": 0 + } + """ @xhr def edit(self, environ, request, id): From c3439e5c79081f7c450db0fcc99cea59b4945f5b Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Fri, 3 Jun 2016 11:06:46 +0200 Subject: [PATCH 06/11] apidoc for "delete comment" --- isso/views/comments.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/isso/views/comments.py b/isso/views/comments.py index 24e01fe..5f2bac7 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -411,6 +411,21 @@ class API(object): resp.headers.add("X-Set-Cookie", cookie("isso-%i" % rv["id"])) return resp + """ + @api {delete} '/id/:id' delete + @apiGroup Comment + @apiDescription + Delte an existing comment. Deleting a comment is only possible for a short period of time after it was created and only if the requestor has a valid cookie for it. See the [isso server documentation](https://posativ.org/isso/docs/configuration/server) for details. + + @apiParam {number} id + Id of the comment to delete. + + @apiExample {curl} Delete comment with id 14: + curl -X DELETE 'https://comments.example.com/id/14' -b cookie.txt + + @apiSuccessExample Successful deletion returns null: + null + """ @xhr def delete(self, environ, request, id, key=None): From ded4927ae40ceb49ef9b994737d796da43487fcd Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Fri, 3 Jun 2016 14:08:57 +0200 Subject: [PATCH 07/11] apidoc for moderate --- isso/views/comments.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/isso/views/comments.py b/isso/views/comments.py index 5f2bac7..2ad90e2 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -463,6 +463,40 @@ class API(object): resp.headers.add("X-Set-Cookie", cookie("isso-%i" % id)) return resp + """ + @api {post} /id/:id/:action/key moderate + @apiGroup Comment + @apiDescription + Publish or delete a comment that is in the moderation queue (mode `2`). In order to use this endpoint, the requestor needs a `key` that is usually obtained from an email sent out by isso. + + This endpoint can also be used with a `GET` request. In that case, a html page is returned that asks the user whether they are sure to perform the selected action. If they select “yes”, the query is repeated using `POST`. + + @apiParam {number} id + The id of the comment to moderate. + @apiParam {string=activate,delete} action + `activate` to publish the comment (change its mode to `1`). + `delete` to delete the comment + @apiParam {string} key + The moderation key to authenticate the moderation. + + @apiExample {curl} delete comment with id 13: + curl -X POST 'https://comments.example.com/id/13/delete/MTM.CjL6Fg.REIdVXa-whJS_x8ojQL4RrXnuF4' + + @apiSuccessExample {html} Using GET: + <!DOCTYPE html> + <html> + <head> + <script> + if (confirm('Delete: Are you sure?')) { + xhr = new XMLHttpRequest; + xhr.open('POST', window.location.href); + xhr.send(null); + } + </script> + + @apiSuccessExample Using POST: + Yo + """ def moderate(self, environ, request, id, action, key): try: From afd4107ac32637d0050e1505c5f616aed9ae9d18 Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Fri, 3 Jun 2016 14:09:16 +0200 Subject: [PATCH 08/11] apidoc for like & dislike --- isso/views/comments.py | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/isso/views/comments.py b/isso/views/comments.py index 2ad90e2..3096ab8 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -716,12 +716,60 @@ class API(object): return fetched_list + """ + @apiDefine likeResponse + @apiSuccess {number} likes + The (new) number of likes on the comment. + @apiSuccess {number} dislikes + The (new) number of dislikes on the comment. + """ + + """ + @api {post} /id/:id/like like + @apiGroup Comment + @apiDescription + Puts a “like” on a comment. The author of a comment cannot like its own comment. + + @apiParam {number} id + The id of the comment to like. + + @apiExample {curl} Like comment with id 23: + curl -X POST 'https://comments.example.com/id/23/like' + + @apiUse likeResponse + + @apiSuccessExample Example response + { + "likes": 5, + "dislikes": 2 + } + """ @xhr def like(self, environ, request, id): nv = self.comments.vote(True, id, utils.anonymize(str(request.remote_addr))) return JSON(nv, 200) + """ + @api {post} /id/:id/dislike dislike + @apiGroup Comment + @apiDescription + Puts a “dislike” on a comment. The author of a comment cannot dislike its own comment. + + @apiParam {number} id + The id of the comment to dislike. + + @apiExample {curl} Dislike comment with id 23: + curl -X POST 'https://comments.example.com/id/23/dislike' + + @apiUse likeResponse + + @apiSuccessExample Example response + { + "likes": 4, + "dislikes": 3 + } + """ @xhr def dislike(self, environ, request, id): From 8a9fe29bce19957b5c94ce4ce6c2ebfc45fc1896 Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Fri, 3 Jun 2016 14:20:36 +0200 Subject: [PATCH 09/11] apidoc for count --- isso/views/comments.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/isso/views/comments.py b/isso/views/comments.py index 3096ab8..868dbfe 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -787,6 +787,18 @@ class API(object): return JSON(rv, 200) + """ + @api {post} /count count comments + @apiGroup Thread + @apiDescription + Counts the number of comments on multiple threads. The requestor provides a list of thread uris. The number of comments on each thread is returned as a list, in the same order as the threads were requested. The counts include comments that are reponses to comments. + + @apiExample {curl} get the count of 5 threads: + curl 'https://comments.example.com/count' -d '["/blog/firstPost.html", "/blog/controversalPost.html", "/blog/howToCode.html", "/blog/boringPost.html", "/blog/isso.html"] + + @apiSuccessExample Counts of 5 threads: + [2, 18, 4, 0, 3] + """ def counts(self, environ, request): data = request.get_json() From 084f6e5cf050222c35ace7c4f8c95556d0d19c1e Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Fri, 3 Jun 2016 14:39:22 +0200 Subject: [PATCH 10/11] apidoc settings --- apidoc.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apidoc.json b/apidoc.json index 760e429..a960a32 100644 --- a/apidoc.json +++ b/apidoc.json @@ -1,6 +1,11 @@ { "name": "isso", "description": "a Disqus alternative", - "title": "isso API" + "title": "isso API", + "order": ["Thread", "Comment"], + "template": { + "withCompare": false + } + } From 2a11c000d49d1749c1091cc55102909b78ebedcb Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Fri, 3 Jun 2016 20:04:58 +0200 Subject: [PATCH 11/11] convert bad tabs to spaces --- isso/views/comments.py | 404 ++++++++++++++++++++--------------------- 1 file changed, 202 insertions(+), 202 deletions(-) diff --git a/isso/views/comments.py b/isso/views/comments.py index 868dbfe..6a7aef1 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -61,11 +61,11 @@ def xhr(func): """ - """ - @apiDefine csrf - @apiHeader {string="application/json"} Content-Type - The content type must be set to `application/json` to prevent CSRF attacks. - """ + """ + @apiDefine csrf + @apiHeader {string="application/json"} Content-Type + The content type must be set to `application/json` to prevent CSRF attacks. + """ def dec(self, env, req, *args, **kwargs): if req.content_type and not req.content_type.startswith("application/json"): @@ -146,44 +146,44 @@ class API(object): return True, "" - # Common definitions for apidoc follow: - """ - @apiDefine plainParam - @apiParam {number=0,1} [plain] - Iff set to `1`, the plain text entered by the user will be returned in the comments’ `text` attribute (instead of the rendered markdown). - """ - """ - @apiDefine commentResponse + # Common definitions for apidoc follow: + """ + @apiDefine plainParam + @apiParam {number=0,1} [plain] + Iff set to `1`, the plain text entered by the user will be returned in the comments’ `text` attribute (instead of the rendered markdown). + """ + """ + @apiDefine commentResponse - @apiSuccess {number} id - The comment’s id (assigned by the server). - @apiSuccess {number} parent - Id of the comment this comment is a reply to. `null` if this is a top-level-comment. - @apiSuccess {number=1,2,4} mode - The comment’s mode: - value | explanation - --- | --- - `1` | accepted: The comment was accepted by the server and is published. - `2` | in moderation queue: The comment was accepted by the server but awaits moderation. - `4` | deleted, but referenced: The comment was deleted on the server but is still referenced by replies. - @apiSuccess {string} author - The comments’s author’s name or `null`. - @apiSuccess {string} website - The comment’s author’s website or `null`. - @apiSuccess {string} hash - A hash uniquely identifying the comment’s author. - @apiSuccess {number} created - UNIX timestamp of the time the comment was created (on the server). - @apiSuccess {number} modified - UNIX timestamp of the time the comment was last modified (on the server). `null` if the comment was not yet modified. - """ + @apiSuccess {number} id + The comment’s id (assigned by the server). + @apiSuccess {number} parent + Id of the comment this comment is a reply to. `null` if this is a top-level-comment. + @apiSuccess {number=1,2,4} mode + The comment’s mode: + value | explanation + --- | --- + `1` | accepted: The comment was accepted by the server and is published. + `2` | in moderation queue: The comment was accepted by the server but awaits moderation. + `4` | deleted, but referenced: The comment was deleted on the server but is still referenced by replies. + @apiSuccess {string} author + The comments’s author’s name or `null`. + @apiSuccess {string} website + The comment’s author’s website or `null`. + @apiSuccess {string} hash + A hash uniquely identifying the comment’s author. + @apiSuccess {number} created + UNIX timestamp of the time the comment was created (on the server). + @apiSuccess {number} modified + UNIX timestamp of the time the comment was last modified (on the server). `null` if the comment was not yet modified. + """ """ @api {post} /new create new @apiGroup Comment - @apiDescription - Creates a new comment. The response will set a cookie on the requestor to enable them to later edit the comment. - @apiUse csrf + @apiDescription + Creates a new comment. The response will set a cookie on the requestor to enable them to later edit the comment. + @apiUse csrf @apiParam {string} uri The uri of the thread to create the comment on. @@ -198,25 +198,25 @@ class API(object): @apiParam {number} [parent] The parent comment’s id iff the new comment is a response to an existing comment. - @apiExample {curl} Create a reply to comment with id 15: - curl 'https://comments.example.com/new?uri=/thread/' -d '{"text": "Stop saying that! *isso*!", "author": "Max Rant", "email": "rant@example.com", "parent": 15}' -H 'Content-Type: application/json' -c cookie.txt + @apiExample {curl} Create a reply to comment with id 15: + curl 'https://comments.example.com/new?uri=/thread/' -d '{"text": "Stop saying that! *isso*!", "author": "Max Rant", "email": "rant@example.com", "parent": 15}' -H 'Content-Type: application/json' -c cookie.txt - @apiUse commentResponse + @apiUse commentResponse - @apiSuccessExample Success after the above request: - { - "website": null, - "author": "Max Rant", - "parent": 15, - "created": 1464940838.254393, - "text": "<p>Stop saying that! <em>isso</em>!</p>", - "dislikes": 0, - "modified": null, - "mode": 1, - "hash": "e644f6ee43c0", - "id": 23, - "likes": 0 - } + @apiSuccessExample Success after the above request: + { + "website": null, + "author": "Max Rant", + "parent": 15, + "created": 1464940838.254393, + "text": "<p>Stop saying that! <em>isso</em>!</p>", + "dislikes": 0, + "modified": null, + "mode": 1, + "hash": "e644f6ee43c0", + "id": 23, + "likes": 0 + } """ @xhr @requires(str, 'uri') @@ -292,32 +292,32 @@ class API(object): return resp """ - @api {get} /id/:id view - @apiGroup Comment + @api {get} /id/:id view + @apiGroup Comment - @apiParam {number} id - The id of the comment to view. - @apiUse plainParam + @apiParam {number} id + The id of the comment to view. + @apiUse plainParam - @apiExample {curl} View the comment with id 4: - curl 'https://comments.example.com/id/4' + @apiExample {curl} View the comment with id 4: + curl 'https://comments.example.com/id/4' - @apiUse commentResponse + @apiUse commentResponse - @apiSuccessExample Example result: - { - "website": null, - "author": null, - "parent": null, - "created": 1464914341.312426, - "text": " <p>I want to use MySQL</p>", - "dislikes": 0, - "modified": null, - "mode": 1, - "id": 4, - "likes": 1 - } - """ + @apiSuccessExample Example result: + { + "website": null, + "author": null, + "parent": null, + "created": 1464914341.312426, + "text": " <p>I want to use MySQL</p>", + "dislikes": 0, + "modified": null, + "mode": 1, + "id": 4, + "likes": 1 + } + """ def view(self, environ, request, id): rv = self.comments.get(id) @@ -332,41 +332,41 @@ class API(object): return JSON(rv, 200) - """ - @api {put} /id/:id edit - @apiGroup Comment + """ + @api {put} /id/:id edit + @apiGroup Comment @apiDescription - Edit an existing comment. Editing a comment is only possible for a short period of time after it was created and only if the requestor has a valid cookie for it. See the [isso server documentation](https://posativ.org/isso/docs/configuration/server) for details. Editing a comment will set a new edit cookie in the response. - @apiUse csrf + Edit an existing comment. Editing a comment is only possible for a short period of time after it was created and only if the requestor has a valid cookie for it. See the [isso server documentation](https://posativ.org/isso/docs/configuration/server) for details. Editing a comment will set a new edit cookie in the response. + @apiUse csrf - @apiParam {number} id - The id of the comment to edit. - @apiParam {string} text - A new (raw) text for the comment. - @apiParam {string} [author] - The modified comment’s author’s name. - @apiParam {string} [webiste] - The modified comment’s author’s website. + @apiParam {number} id + The id of the comment to edit. + @apiParam {string} text + A new (raw) text for the comment. + @apiParam {string} [author] + The modified comment’s author’s name. + @apiParam {string} [webiste] + The modified comment’s author’s website. - @apiExample {curl} Edit comment with id 23: - curl -X PUT 'https://comments.example.com/id/23' -d {"text": "I see your point. However, I still disagree.", "website": "maxrant.important.com"} -H 'Content-Type: application/json' -b cookie.txt + @apiExample {curl} Edit comment with id 23: + curl -X PUT 'https://comments.example.com/id/23' -d {"text": "I see your point. However, I still disagree.", "website": "maxrant.important.com"} -H 'Content-Type: application/json' -b cookie.txt - @apiUse commentResponse + @apiUse commentResponse - @apiSuccessExample Example response: - { - "website": "maxrant.important.com", - "author": "Max Rant", - "parent": 15, - "created": 1464940838.254393, - "text": "<p>I see your point. However, I still disagree.</p>", - "dislikes": 0, - "modified": 1464943439.073961, - "mode": 1, - "id": 23, - "likes": 0 - } - """ + @apiSuccessExample Example response: + { + "website": "maxrant.important.com", + "author": "Max Rant", + "parent": 15, + "created": 1464940838.254393, + "text": "<p>I see your point. However, I still disagree.</p>", + "dislikes": 0, + "modified": 1464943439.073961, + "mode": 1, + "id": 23, + "likes": 0 + } + """ @xhr def edit(self, environ, request, id): @@ -411,21 +411,21 @@ class API(object): resp.headers.add("X-Set-Cookie", cookie("isso-%i" % rv["id"])) return resp - """ - @api {delete} '/id/:id' delete - @apiGroup Comment - @apiDescription - Delte an existing comment. Deleting a comment is only possible for a short period of time after it was created and only if the requestor has a valid cookie for it. See the [isso server documentation](https://posativ.org/isso/docs/configuration/server) for details. + """ + @api {delete} '/id/:id' delete + @apiGroup Comment + @apiDescription + Delte an existing comment. Deleting a comment is only possible for a short period of time after it was created and only if the requestor has a valid cookie for it. See the [isso server documentation](https://posativ.org/isso/docs/configuration/server) for details. - @apiParam {number} id - Id of the comment to delete. + @apiParam {number} id + Id of the comment to delete. - @apiExample {curl} Delete comment with id 14: - curl -X DELETE 'https://comments.example.com/id/14' -b cookie.txt + @apiExample {curl} Delete comment with id 14: + curl -X DELETE 'https://comments.example.com/id/14' -b cookie.txt - @apiSuccessExample Successful deletion returns null: - null - """ + @apiSuccessExample Successful deletion returns null: + null + """ @xhr def delete(self, environ, request, id, key=None): @@ -463,40 +463,40 @@ class API(object): resp.headers.add("X-Set-Cookie", cookie("isso-%i" % id)) return resp - """ - @api {post} /id/:id/:action/key moderate - @apiGroup Comment - @apiDescription - Publish or delete a comment that is in the moderation queue (mode `2`). In order to use this endpoint, the requestor needs a `key` that is usually obtained from an email sent out by isso. + """ + @api {post} /id/:id/:action/key moderate + @apiGroup Comment + @apiDescription + Publish or delete a comment that is in the moderation queue (mode `2`). In order to use this endpoint, the requestor needs a `key` that is usually obtained from an email sent out by isso. - This endpoint can also be used with a `GET` request. In that case, a html page is returned that asks the user whether they are sure to perform the selected action. If they select “yes”, the query is repeated using `POST`. + This endpoint can also be used with a `GET` request. In that case, a html page is returned that asks the user whether they are sure to perform the selected action. If they select “yes”, the query is repeated using `POST`. - @apiParam {number} id - The id of the comment to moderate. - @apiParam {string=activate,delete} action - `activate` to publish the comment (change its mode to `1`). - `delete` to delete the comment - @apiParam {string} key - The moderation key to authenticate the moderation. + @apiParam {number} id + The id of the comment to moderate. + @apiParam {string=activate,delete} action + `activate` to publish the comment (change its mode to `1`). + `delete` to delete the comment + @apiParam {string} key + The moderation key to authenticate the moderation. - @apiExample {curl} delete comment with id 13: - curl -X POST 'https://comments.example.com/id/13/delete/MTM.CjL6Fg.REIdVXa-whJS_x8ojQL4RrXnuF4' + @apiExample {curl} delete comment with id 13: + curl -X POST 'https://comments.example.com/id/13/delete/MTM.CjL6Fg.REIdVXa-whJS_x8ojQL4RrXnuF4' - @apiSuccessExample {html} Using GET: - <!DOCTYPE html> - <html> - <head> - <script> - if (confirm('Delete: Are you sure?')) { - xhr = new XMLHttpRequest; - xhr.open('POST', window.location.href); - xhr.send(null); - } - </script> + @apiSuccessExample {html} Using GET: + <!DOCTYPE html> + <html> + <head> + <script> + if (confirm('Delete: Are you sure?')) { + xhr = new XMLHttpRequest; + xhr.open('POST', window.location.href); + xhr.send(null); + } + </script> - @apiSuccessExample Using POST: - Yo - """ + @apiSuccessExample Using POST: + Yo + """ def moderate(self, environ, request, id, action, key): try: @@ -546,7 +546,7 @@ class API(object): The URI of thread to get the comments from. @apiParam {number} [parent] Return only comments that are children of the comment with the provided ID. - @apiUse plainParam + @apiUse plainParam @apiParam {number} [limit] The maximum number of returned top-level comments. Omit for unlimited results. @apiParam {number} [nested_limit] @@ -555,13 +555,13 @@ class API(object): Includes only comments were added after the provided UNIX timestamp. @apiSuccess {number} total_replies - The number of replies if the `limit` parameter was not set. If `after` is set to `X`, this is the number of comments that were created after `X`. So setting `after` may change this value! + The number of replies if the `limit` parameter was not set. If `after` is set to `X`, this is the number of comments that were created after `X`. So setting `after` may change this value! @apiSuccess {Object[]} replies - The list of comments. Each comment also has the `total_replies`, `replies`, `id` and `hidden_replies` properties to represent nested comments. + The list of comments. Each comment also has the `total_replies`, `replies`, `id` and `hidden_replies` properties to represent nested comments. @apiSuccess {number} id - Id of the comment `replies` is the list of replies of. `null` for the list of toplevel comments. + Id of the comment `replies` is the list of replies of. `null` for the list of toplevel comments. @apiSuccess {number} hidden_replies - The number of comments that were ommited from the results because of the `limit` request parameter. Usually, this will be `total_replies` - `limit`. + The number of comments that were ommited from the results because of the `limit` request parameter. Usually, this will be `total_replies` - `limit`. @apiExample {curl} Get 2 comments with 5 responses: curl 'https://comments.example.com/?uri=/thread/&limit=2&nested_limit=5' @@ -716,60 +716,60 @@ class API(object): return fetched_list - """ - @apiDefine likeResponse - @apiSuccess {number} likes - The (new) number of likes on the comment. - @apiSuccess {number} dislikes - The (new) number of dislikes on the comment. - """ + """ + @apiDefine likeResponse + @apiSuccess {number} likes + The (new) number of likes on the comment. + @apiSuccess {number} dislikes + The (new) number of dislikes on the comment. + """ - """ - @api {post} /id/:id/like like - @apiGroup Comment - @apiDescription - Puts a “like” on a comment. The author of a comment cannot like its own comment. + """ + @api {post} /id/:id/like like + @apiGroup Comment + @apiDescription + Puts a “like” on a comment. The author of a comment cannot like its own comment. - @apiParam {number} id - The id of the comment to like. + @apiParam {number} id + The id of the comment to like. - @apiExample {curl} Like comment with id 23: - curl -X POST 'https://comments.example.com/id/23/like' + @apiExample {curl} Like comment with id 23: + curl -X POST 'https://comments.example.com/id/23/like' - @apiUse likeResponse + @apiUse likeResponse - @apiSuccessExample Example response - { - "likes": 5, - "dislikes": 2 - } - """ + @apiSuccessExample Example response + { + "likes": 5, + "dislikes": 2 + } + """ @xhr def like(self, environ, request, id): nv = self.comments.vote(True, id, utils.anonymize(str(request.remote_addr))) return JSON(nv, 200) - """ - @api {post} /id/:id/dislike dislike - @apiGroup Comment - @apiDescription - Puts a “dislike” on a comment. The author of a comment cannot dislike its own comment. + """ + @api {post} /id/:id/dislike dislike + @apiGroup Comment + @apiDescription + Puts a “dislike” on a comment. The author of a comment cannot dislike its own comment. - @apiParam {number} id - The id of the comment to dislike. + @apiParam {number} id + The id of the comment to dislike. - @apiExample {curl} Dislike comment with id 23: - curl -X POST 'https://comments.example.com/id/23/dislike' + @apiExample {curl} Dislike comment with id 23: + curl -X POST 'https://comments.example.com/id/23/dislike' - @apiUse likeResponse + @apiUse likeResponse - @apiSuccessExample Example response - { - "likes": 4, - "dislikes": 3 - } - """ + @apiSuccessExample Example response + { + "likes": 4, + "dislikes": 3 + } + """ @xhr def dislike(self, environ, request, id): @@ -787,18 +787,18 @@ class API(object): return JSON(rv, 200) - """ - @api {post} /count count comments - @apiGroup Thread - @apiDescription - Counts the number of comments on multiple threads. The requestor provides a list of thread uris. The number of comments on each thread is returned as a list, in the same order as the threads were requested. The counts include comments that are reponses to comments. + """ + @api {post} /count count comments + @apiGroup Thread + @apiDescription + Counts the number of comments on multiple threads. The requestor provides a list of thread uris. The number of comments on each thread is returned as a list, in the same order as the threads were requested. The counts include comments that are reponses to comments. - @apiExample {curl} get the count of 5 threads: - curl 'https://comments.example.com/count' -d '["/blog/firstPost.html", "/blog/controversalPost.html", "/blog/howToCode.html", "/blog/boringPost.html", "/blog/isso.html"] + @apiExample {curl} get the count of 5 threads: + curl 'https://comments.example.com/count' -d '["/blog/firstPost.html", "/blog/controversalPost.html", "/blog/howToCode.html", "/blog/boringPost.html", "/blog/isso.html"] - @apiSuccessExample Counts of 5 threads: - [2, 18, 4, 0, 3] - """ + @apiSuccessExample Counts of 5 threads: + [2, 18, 4, 0, 3] + """ def counts(self, environ, request): data = request.get_json()