Merge branch 'pr-83', closes #83
This commit is contained in:
commit
fb182ae93f
@ -10,6 +10,9 @@ preferably in the script tag which embeds the JS:
|
|||||||
data-isso-css="true"
|
data-isso-css="true"
|
||||||
data-isso-lang="ru"
|
data-isso-lang="ru"
|
||||||
data-isso-reply-to-self="false"
|
data-isso-reply-to-self="false"
|
||||||
|
data-isso-max-comments-top="10"
|
||||||
|
data-isso-max-comments-nested="5"
|
||||||
|
data-isso-reveal-on-click="5"
|
||||||
data-avatar-bg="#f0f0f0"
|
data-avatar-bg="#f0f0f0"
|
||||||
data-avatar-fg="#9abf88 #5698c4 #e279a3 #9163b6 ..."
|
data-avatar-fg="#9abf88 #5698c4 #e279a3 #9163b6 ..."
|
||||||
src="/prefix/js/embed.js"></script>
|
src="/prefix/js/embed.js"></script>
|
||||||
@ -53,6 +56,19 @@ data-isso-reply-to-self
|
|||||||
|
|
||||||
Set to `true` when spam guard is configured with `reply-to-self = true`.
|
Set to `true` when spam guard is configured with `reply-to-self = true`.
|
||||||
|
|
||||||
|
data-isso-max-comments-top and data-isso-max-comments-nested
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Number of top level (or nested) comments to show by default. If some
|
||||||
|
comments are not shown, an "X Hidden" link is shown.
|
||||||
|
|
||||||
|
Set to `"inf"` to show all, or `"0"` to hide all.
|
||||||
|
|
||||||
|
data-isso-reveal-on-click
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Number of comments to reveal on clicking the "X Hidden" link.
|
||||||
|
|
||||||
data-isso-avatar-bg
|
data-isso-avatar-bg
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
@ -97,15 +97,31 @@ class Comments:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def fetch(self, uri, mode=5):
|
def fetch(self, uri, mode=5, after=0, parent='any', order_by='id', limit=None):
|
||||||
"""
|
"""
|
||||||
Return comments for :param:`uri` with :param:`mode`.
|
Return comments for :param:`uri` with :param:`mode`.
|
||||||
"""
|
"""
|
||||||
rv = self.db.execute([
|
sql = [ 'SELECT comments.* FROM comments INNER JOIN threads ON',
|
||||||
'SELECT comments.* FROM comments INNER JOIN threads ON',
|
' threads.uri=? AND comments.tid=threads.id AND (? | comments.mode) = ?',
|
||||||
' threads.uri=? AND comments.tid=threads.id AND (? | comments.mode) = ?'
|
' AND comments.created>?']
|
||||||
'ORDER BY id ASC;'], (uri, mode, mode)).fetchall()
|
|
||||||
|
|
||||||
|
sql_args = [uri, mode, mode, after]
|
||||||
|
|
||||||
|
if parent != 'any':
|
||||||
|
if parent is None:
|
||||||
|
sql.append('AND comments.parent IS NULL')
|
||||||
|
else:
|
||||||
|
sql.append('AND comments.parent=?')
|
||||||
|
sql_args.append(parent)
|
||||||
|
|
||||||
|
sql.append('ORDER BY ? ASC')
|
||||||
|
sql_args.append(order_by)
|
||||||
|
|
||||||
|
if limit:
|
||||||
|
sql.append('LIMIT ?')
|
||||||
|
sql_args.append(limit)
|
||||||
|
|
||||||
|
rv = self.db.execute(sql, sql_args).fetchall()
|
||||||
for item in rv:
|
for item in rv:
|
||||||
yield dict(zip(Comments.fields, item))
|
yield dict(zip(Comments.fields, item))
|
||||||
|
|
||||||
@ -181,6 +197,17 @@ class Comments:
|
|||||||
return {'likes': likes + 1, 'dislikes': dislikes}
|
return {'likes': likes + 1, 'dislikes': dislikes}
|
||||||
return {'likes': likes, 'dislikes': dislikes + 1}
|
return {'likes': likes, 'dislikes': dislikes + 1}
|
||||||
|
|
||||||
|
def reply_count(self, url, after=0):
|
||||||
|
"""
|
||||||
|
Return comment count for main thread and all reply threads for one url.
|
||||||
|
"""
|
||||||
|
|
||||||
|
sql = [ 'SELECT comments.parent,count(*) FROM comments INNER JOIN threads ON',
|
||||||
|
' threads.uri=? AND comments.tid=threads.id',
|
||||||
|
' AND comments.mode = 1 AND comments.created>? GROUP BY comments.parent;']
|
||||||
|
|
||||||
|
return dict(self.db.execute(sql, [url, after]).fetchall())
|
||||||
|
|
||||||
def count(self, *urls):
|
def count(self, *urls):
|
||||||
"""
|
"""
|
||||||
Return comment count for one ore more urls..
|
Return comment count for one ore more urls..
|
||||||
|
@ -78,7 +78,8 @@ define(["app/lib/promise", "app/globals"], function(Q, globals) {
|
|||||||
var qs = function(params) {
|
var qs = function(params) {
|
||||||
var rv = "";
|
var rv = "";
|
||||||
for (var key in params) {
|
for (var key in params) {
|
||||||
if (params.hasOwnProperty(key) && params[key]) {
|
if (params.hasOwnProperty(key) &&
|
||||||
|
params[key] !== null && typeof(params[key]) !== "undefined") {
|
||||||
rv += key + "=" + encodeURIComponent(params[key]) + "&";
|
rv += key + "=" + encodeURIComponent(params[key]) + "&";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,17 +129,31 @@ define(["app/lib/promise", "app/globals"], function(Q, globals) {
|
|||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
var fetch = function(tid) {
|
var fetch = function(tid, limit, nested_limit, parent, lastcreated) {
|
||||||
|
if (typeof(limit) === 'undefined') { limit = "inf"; }
|
||||||
|
if (typeof(nested_limit) === 'undefined') { nested_limit = "inf"; }
|
||||||
|
if (typeof(parent) === 'undefined') { parent = null; }
|
||||||
|
|
||||||
|
var query_dict = {uri: tid || location, after: lastcreated, parent: parent};
|
||||||
|
|
||||||
|
if(limit !== "inf") {
|
||||||
|
query_dict['limit'] = limit;
|
||||||
|
}
|
||||||
|
if(nested_limit !== "inf"){
|
||||||
|
query_dict['nested_limit'] = nested_limit;
|
||||||
|
}
|
||||||
|
|
||||||
var deferred = Q.defer();
|
var deferred = Q.defer();
|
||||||
curl("GET", endpoint + "/?" + qs({uri: tid || location}), null, function(rv) {
|
curl("GET", endpoint + "/?" +
|
||||||
if (rv.status === 200) {
|
qs(query_dict), null, function(rv) {
|
||||||
deferred.resolve(JSON.parse(rv.body));
|
if (rv.status === 200) {
|
||||||
} else if (rv.status === 404) {
|
deferred.resolve(JSON.parse(rv.body));
|
||||||
deferred.resolve([]);
|
} else if (rv.status === 404) {
|
||||||
} else {
|
deferred.resolve({total_replies: 0});
|
||||||
deferred.reject(rv.body);
|
} else {
|
||||||
}
|
deferred.reject(rv.body);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,6 +5,9 @@ define(function() {
|
|||||||
"css": true,
|
"css": true,
|
||||||
"lang": (navigator.language || navigator.userLanguage).split("-")[0],
|
"lang": (navigator.language || navigator.userLanguage).split("-")[0],
|
||||||
"reply-to-self": false,
|
"reply-to-self": false,
|
||||||
|
"max-comments-top": 10,
|
||||||
|
"max-comments-nested": 5,
|
||||||
|
"reveal-on-click": 5,
|
||||||
"avatar-bg": "#f0f0f0",
|
"avatar-bg": "#f0f0f0",
|
||||||
"avatar-fg": ["#9abf88", "#5698c4", "#e279a3", "#9163b6",
|
"avatar-fg": ["#9abf88", "#5698c4", "#e279a3", "#9163b6",
|
||||||
"#be5168", "#f19670", "#e4bf80", "#447c69"].join(" ")
|
"#be5168", "#f19670", "#e4bf80", "#447c69"].join(" ")
|
||||||
|
@ -15,6 +15,7 @@ define({
|
|||||||
"comment-deleted": "Kommentar gelöscht.",
|
"comment-deleted": "Kommentar gelöscht.",
|
||||||
"comment-queued": "Kommentar muss noch freigeschaltet werden.",
|
"comment-queued": "Kommentar muss noch freigeschaltet werden.",
|
||||||
"comment-anonymous": "Anonym",
|
"comment-anonymous": "Anonym",
|
||||||
|
"comment-hidden": "{{ hidden_replies }} versteckt",
|
||||||
"date-now": "eben jetzt",
|
"date-now": "eben jetzt",
|
||||||
"date-minute": "vor einer Minute\nvor {{ n }} Minuten",
|
"date-minute": "vor einer Minute\nvor {{ n }} Minuten",
|
||||||
"date-hour": "vor einer Stunde\nvor {{ n }} Stunden",
|
"date-hour": "vor einer Stunde\nvor {{ n }} Stunden",
|
||||||
|
@ -17,6 +17,7 @@ define({
|
|||||||
"comment-deleted": "Comment deleted.",
|
"comment-deleted": "Comment deleted.",
|
||||||
"comment-queued": "Comment in queue for moderation.",
|
"comment-queued": "Comment in queue for moderation.",
|
||||||
"comment-anonymous": "Anonymous",
|
"comment-anonymous": "Anonymous",
|
||||||
|
"comment-hidden": "{{ hidden_replies }} Hidden",
|
||||||
|
|
||||||
"date-now": "right now",
|
"date-now": "right now",
|
||||||
"date-minute": "a minute ago\n{{ n }} minutes ago",
|
"date-minute": "a minute ago\n{{ n }} minutes ago",
|
||||||
|
@ -15,6 +15,7 @@ define({
|
|||||||
"comment-deleted": "Commentaire supprimé.",
|
"comment-deleted": "Commentaire supprimé.",
|
||||||
"comment-queued": "Commentaire en attente de modération.",
|
"comment-queued": "Commentaire en attente de modération.",
|
||||||
"comment-anonymous": "Anonyme",
|
"comment-anonymous": "Anonyme",
|
||||||
|
"comment-hidden": "1 caché\n{{ hidden_replies }} cachés",
|
||||||
"date-now": "À l'instant'",
|
"date-now": "À l'instant'",
|
||||||
"date-minute": "Il y a une minute \n{{ n }} minutes",
|
"date-minute": "Il y a une minute \n{{ n }} minutes",
|
||||||
"date-hour": "Il y a une heure\n{{ n }} heures ",
|
"date-hour": "Il y a une heure\n{{ n }} heures ",
|
||||||
|
@ -84,8 +84,54 @@ define(["app/text/html", "app/dom", "app/utils", "app/config", "app/api", "app/m
|
|||||||
return el;
|
return el;
|
||||||
};
|
};
|
||||||
|
|
||||||
var insert = function(comment, scrollIntoView) {
|
var insert_loader = function(commentWrapper, lastcreated) {
|
||||||
|
var entrypoint;
|
||||||
|
if (commentWrapper.id === null) {
|
||||||
|
entrypoint = $("#isso-root");
|
||||||
|
commentWrapper.name = 'null';
|
||||||
|
} else {
|
||||||
|
entrypoint = $("#isso-" + commentWrapper.id + " > .text-wrapper > .isso-follow-up");
|
||||||
|
commentWrapper.name = commentWrapper.id;
|
||||||
|
}
|
||||||
|
var el = $.htmlify(Mark.up(templates["comment_loader"], commentWrapper));
|
||||||
|
|
||||||
|
entrypoint.append(el);
|
||||||
|
|
||||||
|
$("a.load_hidden", el).toggle("click",
|
||||||
|
function() {
|
||||||
|
el.remove();
|
||||||
|
api.fetch($("#isso-thread").getAttribute("data-isso-id"),
|
||||||
|
config["reveal-on-click"], config["max-comments-nested"],
|
||||||
|
commentWrapper.id,
|
||||||
|
lastcreated).then(
|
||||||
|
function(rv) {
|
||||||
|
if (rv.total_replies === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastcreated = 0;
|
||||||
|
rv.replies.forEach(function(commentObject) {
|
||||||
|
insert(commentObject, false);
|
||||||
|
if(commentObject.created > lastcreated) {
|
||||||
|
lastcreated = commentObject.created;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(rv.hidden_replies > 0) {
|
||||||
|
insert_loader(rv, lastcreated);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.location.hash.length > 0) {
|
||||||
|
$(window.location.hash).scrollIntoView();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(err) {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var insert = function(comment, scrollIntoView) {
|
||||||
var el = $.htmlify(Mark.up(templates["comment"], comment));
|
var el = $.htmlify(Mark.up(templates["comment"], comment));
|
||||||
|
|
||||||
// update datetime every 60 seconds
|
// update datetime every 60 seconds
|
||||||
@ -126,13 +172,13 @@ define(["app/text/html", "app/dom", "app/utils", "app/config", "app/api", "app/m
|
|||||||
$("a.reply", footer).textContent = msgs["comment-close"];
|
$("a.reply", footer).textContent = msgs["comment-close"];
|
||||||
},
|
},
|
||||||
function() {
|
function() {
|
||||||
form.remove()
|
form.remove();
|
||||||
$("a.reply", footer).textContent = msgs["comment-reply"];
|
$("a.reply", footer).textContent = msgs["comment-reply"];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// update vote counter, but hide if votes sum to 0
|
// update vote counter, but hide if votes sum to 0
|
||||||
var votes = function(value) {
|
var votes = function(value) {
|
||||||
var span = $("span.votes", footer);
|
var span = $("span.votes", footer);
|
||||||
if (span === null && value !== 0) {
|
if (span === null && value !== 0) {
|
||||||
footer.prepend($.new("span.votes", value));
|
footer.prepend($.new("span.votes", value));
|
||||||
@ -261,10 +307,27 @@ define(["app/text/html", "app/dom", "app/utils", "app/config", "app/api", "app/m
|
|||||||
if (! config["reply-to-self"] && utils.cookie("isso-" + comment.id)) {
|
if (! config["reply-to-self"] && utils.cookie("isso-" + comment.id)) {
|
||||||
show($("a.reply", footer).detach());
|
show($("a.reply", footer).detach());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(comment.hasOwnProperty('replies')) {
|
||||||
|
var lastcreated = 0;
|
||||||
|
comment.replies.forEach(function(replyObject) {
|
||||||
|
insert(replyObject, false);
|
||||||
|
if(replyObject.created > lastcreated) {
|
||||||
|
lastcreated = replyObject.created;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
if(comment.hidden_replies > 0) {
|
||||||
|
insert_loader(comment, lastcreated);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
insert: insert,
|
insert: insert,
|
||||||
|
insert_loader: insert_loader,
|
||||||
Postbox: Postbox
|
Postbox: Postbox
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
3
isso/js/app/text/comment-loader.html
Normal file
3
isso/js/app/text/comment-loader.html
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<div class="isso-comment-loader" id="isso-loader-{{ name | blank }}">
|
||||||
|
<a class="load_hidden" href="#">{{ i18n-comment-hidden | pluralize : `hidden_replies` }}</a>
|
||||||
|
</div>
|
@ -1,6 +1,7 @@
|
|||||||
define(["text!./postbox.html", "text!./comment.html"], function (postbox, comment) {
|
define(["text!./postbox.html", "text!./comment.html", "text!./comment-loader.html"], function (postbox, comment, comment_loader) {
|
||||||
return {
|
return {
|
||||||
postbox: postbox,
|
postbox: postbox,
|
||||||
comment: comment
|
comment: comment,
|
||||||
|
comment_loader: comment_loader
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -26,16 +26,28 @@ require(["app/lib/ready", "app/config", "app/api", "app/isso", "app/count", "app
|
|||||||
$("#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>');
|
||||||
|
|
||||||
api.fetch($("#isso-thread").getAttribute("data-isso-id")).then(
|
api.fetch($("#isso-thread").getAttribute("data-isso-id"),
|
||||||
|
config["max-comments-top"],
|
||||||
|
config["max-comments-nested"]).then(
|
||||||
function(rv) {
|
function(rv) {
|
||||||
if (! rv.length) {
|
if (rv.total_replies === 0) {
|
||||||
$("#isso-thread > h4").textContent = Mark.up("{{ i18n-no-comments }}");
|
$("#isso-thread > h4").textContent = Mark.up("{{ i18n-no-comments }}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#isso-thread > h4").textContent = Mark.up("{{ i18n-num-comments | pluralize : `n` }}", {n: rv.length});
|
var lastcreated = 0;
|
||||||
for (var i=0; i < rv.length; i++) {
|
var total_count = rv.total_replies;
|
||||||
isso.insert(rv[i], false);
|
rv.replies.forEach(function(commentObject) {
|
||||||
|
isso.insert(commentObject, false);
|
||||||
|
if(commentObject.created > lastcreated) {
|
||||||
|
lastcreated = commentObject.created;
|
||||||
|
}
|
||||||
|
total_count = total_count + commentObject.total_replies;
|
||||||
|
});
|
||||||
|
$("#isso-thread > h4").textContent = Mark.up("{{ i18n-num-comments | pluralize : `n` }}", {n: total_count});
|
||||||
|
|
||||||
|
if(rv.hidden_replies > 0) {
|
||||||
|
isso.insert_loader(rv, lastcreated);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.location.hash.length > 0) {
|
if (window.location.hash.length > 0) {
|
||||||
|
@ -103,7 +103,7 @@ class TestComments(unittest.TestCase):
|
|||||||
self.assertEqual(r.status_code, 200)
|
self.assertEqual(r.status_code, 200)
|
||||||
|
|
||||||
rv = loads(r.data)
|
rv = loads(r.data)
|
||||||
self.assertEqual(len(rv), 20)
|
self.assertEqual(len(rv['replies']), 20)
|
||||||
|
|
||||||
def testCreateInvalidParent(self):
|
def testCreateInvalidParent(self):
|
||||||
|
|
||||||
@ -138,6 +138,40 @@ class TestComments(unittest.TestCase):
|
|||||||
self.assertEqual(self.get('/?uri=%2Fpath%2Fspam%2F&id=123').status_code, 404)
|
self.assertEqual(self.get('/?uri=%2Fpath%2Fspam%2F&id=123').status_code, 404)
|
||||||
self.assertEqual(self.get('/?uri=?uri=%foo%2F').status_code, 404)
|
self.assertEqual(self.get('/?uri=?uri=%foo%2F').status_code, 404)
|
||||||
|
|
||||||
|
def testGetLimited(self):
|
||||||
|
|
||||||
|
for i in range(20):
|
||||||
|
self.post('/new?uri=test', data=json.dumps({'text': '...'}))
|
||||||
|
|
||||||
|
r = self.get('/?uri=test&limit=10')
|
||||||
|
self.assertEqual(r.status_code, 200)
|
||||||
|
|
||||||
|
rv = loads(r.data)
|
||||||
|
self.assertEqual(len(rv['replies']), 10)
|
||||||
|
|
||||||
|
def testGetNested(self):
|
||||||
|
|
||||||
|
self.post('/new?uri=test', data=json.dumps({'text': '...'}))
|
||||||
|
self.post('/new?uri=test', data=json.dumps({'text': '...', 'parent': 1}))
|
||||||
|
|
||||||
|
r = self.get('/?uri=test&parent=1')
|
||||||
|
self.assertEqual(r.status_code, 200)
|
||||||
|
|
||||||
|
rv = loads(r.data)
|
||||||
|
self.assertEqual(len(rv['replies']), 1)
|
||||||
|
|
||||||
|
def testGetLimitedNested(self):
|
||||||
|
|
||||||
|
self.post('/new?uri=test', data=json.dumps({'text': '...'}))
|
||||||
|
for i in range(20):
|
||||||
|
self.post('/new?uri=test', data=json.dumps({'text': '...', 'parent': 1}))
|
||||||
|
|
||||||
|
r = self.get('/?uri=test&parent=1&limit=10')
|
||||||
|
self.assertEqual(r.status_code, 200)
|
||||||
|
|
||||||
|
rv = loads(r.data)
|
||||||
|
self.assertEqual(len(rv['replies']), 10)
|
||||||
|
|
||||||
def testUpdate(self):
|
def testUpdate(self):
|
||||||
|
|
||||||
self.post('/new?uri=%2Fpath%2F', data=json.dumps({'text': 'Lorem ipsum ...'}))
|
self.post('/new?uri=%2Fpath%2F', data=json.dumps({'text': 'Lorem ipsum ...'}))
|
||||||
|
@ -320,11 +320,81 @@ class API(object):
|
|||||||
@requires(str, 'uri')
|
@requires(str, 'uri')
|
||||||
def fetch(self, environ, request, uri):
|
def fetch(self, environ, request, uri):
|
||||||
|
|
||||||
rv = list(self.comments.fetch(uri))
|
args = {
|
||||||
if not rv:
|
'uri': uri,
|
||||||
raise NotFound
|
'after': request.args.get('after', 0)
|
||||||
|
}
|
||||||
|
|
||||||
for item in rv:
|
try:
|
||||||
|
args['limit'] = int(request.args.get('limit'))
|
||||||
|
except TypeError:
|
||||||
|
args['limit'] = None
|
||||||
|
except ValueError:
|
||||||
|
return BadRequest("limit should be integer")
|
||||||
|
|
||||||
|
if request.args.get('parent') is not None:
|
||||||
|
try:
|
||||||
|
args['parent'] = int(request.args.get('parent'))
|
||||||
|
root_id = args['parent']
|
||||||
|
except ValueError:
|
||||||
|
return BadRequest("parent should be integer")
|
||||||
|
else:
|
||||||
|
args['parent'] = None
|
||||||
|
root_id = None
|
||||||
|
|
||||||
|
plain = request.args.get('plain', '0') == '0'
|
||||||
|
|
||||||
|
reply_counts = self.comments.reply_count(uri, args['after'])
|
||||||
|
|
||||||
|
if args['limit'] == 0:
|
||||||
|
root_list = []
|
||||||
|
else:
|
||||||
|
root_list = list(self.comments.fetch(**args))
|
||||||
|
if not root_list:
|
||||||
|
raise NotFound
|
||||||
|
|
||||||
|
if root_id not in reply_counts:
|
||||||
|
reply_counts[root_id] = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
nested_limit = int(request.args.get('nested_limit'))
|
||||||
|
except TypeError:
|
||||||
|
nested_limit = None
|
||||||
|
except ValueError:
|
||||||
|
return BadRequest("nested_limit should be integer")
|
||||||
|
|
||||||
|
rv = {
|
||||||
|
'id' : root_id,
|
||||||
|
'total_replies' : reply_counts[root_id],
|
||||||
|
'hidden_replies' : reply_counts[root_id] - len(root_list),
|
||||||
|
'replies' : self._process_fetched_list(root_list, plain)
|
||||||
|
}
|
||||||
|
# We are only checking for one level deep comments
|
||||||
|
if root_id is None:
|
||||||
|
for comment in rv['replies']:
|
||||||
|
if comment['id'] in reply_counts:
|
||||||
|
comment['total_replies'] = reply_counts[comment['id']]
|
||||||
|
if nested_limit is not None:
|
||||||
|
if nested_limit > 0:
|
||||||
|
args['parent'] = comment['id']
|
||||||
|
args['limit'] = nested_limit
|
||||||
|
replies = list(self.comments.fetch(**args))
|
||||||
|
else:
|
||||||
|
replies = []
|
||||||
|
else:
|
||||||
|
args['parent'] = comment['id']
|
||||||
|
replies = list(self.comments.fetch(**args))
|
||||||
|
else:
|
||||||
|
comment['total_replies'] = 0
|
||||||
|
replies = []
|
||||||
|
|
||||||
|
comment['hidden_replies'] = comment['total_replies'] - len(replies)
|
||||||
|
comment['replies'] = self._process_fetched_list(replies, plain)
|
||||||
|
|
||||||
|
return JSON(rv, 200)
|
||||||
|
|
||||||
|
def _process_fetched_list(self, fetched_list, plain=False):
|
||||||
|
for item in fetched_list:
|
||||||
|
|
||||||
key = item['email'] or item['remote_addr']
|
key = item['email'] or item['remote_addr']
|
||||||
val = self.cache.get('hash', key.encode('utf-8'))
|
val = self.cache.get('hash', key.encode('utf-8'))
|
||||||
@ -338,11 +408,11 @@ class API(object):
|
|||||||
for key in set(item.keys()) - API.FIELDS:
|
for key in set(item.keys()) - API.FIELDS:
|
||||||
item.pop(key)
|
item.pop(key)
|
||||||
|
|
||||||
if request.args.get('plain', '0') == '0':
|
if plain:
|
||||||
for item in rv:
|
for item in fetched_list:
|
||||||
item['text'] = self.isso.render(item['text'])
|
item['text'] = self.isso.render(item['text'])
|
||||||
|
|
||||||
return JSON(rv, 200)
|
return fetched_list
|
||||||
|
|
||||||
@xhr
|
@xhr
|
||||||
def like(self, environ, request, id):
|
def like(self, environ, request, id):
|
||||||
|
Loading…
Reference in New Issue
Block a user