diff --git a/isso/db/comments.py b/isso/db/comments.py index 8c97121..9c3bdda 100644 --- a/isso/db/comments.py +++ b/isso/db/comments.py @@ -97,15 +97,31 @@ class Comments: 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`. """ - rv = self.db.execute([ - 'SELECT comments.* FROM comments INNER JOIN threads ON', - ' threads.uri=? AND comments.tid=threads.id AND (? | comments.mode) = ?' - 'ORDER BY id ASC;'], (uri, mode, mode)).fetchall() + sql = [ 'SELECT comments.* FROM comments INNER JOIN threads ON', + ' threads.uri=? AND comments.tid=threads.id AND (? | comments.mode) = ?', + ' AND comments.created>?'] + sql_args = [uri, mode, mode, after] + + if parent != 'any': + if parent is None or parent == 'NULL': + 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 != None and limit != 0: + sql.append('LIMIT ?') + sql_args.append(limit) + + rv = self.db.execute(sql, sql_args).fetchall() for item in rv: yield dict(zip(Comments.fields, item)) @@ -181,6 +197,17 @@ class Comments: return {'likes': likes + 1, 'dislikes': dislikes} return {'likes': likes, 'dislikes': dislikes + 1} + def reply_count(self, url): + """ + 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 group by comments.parent;'] + + return dict(self.db.execute(sql, [url]).fetchall()) + def count(self, *urls): """ Return comment count for one ore more urls.. diff --git a/isso/views/comments.py b/isso/views/comments.py index eac16ff..40958d1 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -320,11 +320,53 @@ class API(object): @requires(str, 'uri') def fetch(self, environ, request, uri): - rv = list(self.comments.fetch(uri)) - if not rv: + fetch_args={'uri': uri} + if request.args.get('after'): + fetch_args['after'] = request.args.get('after') + if request.args.get('limit'): + try: + fetch_args['limit'] = int(request.args.get('limit')) + except ValueError: + return BadRequest("Limit should be integer") + if request.args.get('parent'): + try: + fetch_args['parent'] = int(request.args.get('parent')) + root_id = int(request.args.get('parent')) + except ValueError: + return BadRequest("Parent should be integer") + else: + root_id = None + + if request.args.get('plain', '0') == '0': + plain = True + else: + plain = False + + reply_counts = self.comments.reply_count(uri) + + full_list = list(self.comments.fetch(**fetch_args)) + root_list = [i for i in full_list if i['parent'] == root_id] + if not root_list: raise NotFound - for item in rv: + rv = { + 'id' : root_id, + 'passed_replies' : len(root_list), + 'total_replies' : reply_counts[root_id], + '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']: + replies = [i for i in full_list if i['parent'] == comment['id']] + comment['passed_replies'] = len(replies) + comment['total_replies'] = reply_counts[comment['id']] + 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'] val = self.cache.get('hash', key.encode('utf-8')) @@ -338,11 +380,11 @@ class API(object): for key in set(item.keys()) - API.FIELDS: item.pop(key) - if request.args.get('plain', '0') == '0': - for item in rv: + if plain: + for item in fetched_list: item['text'] = self.isso.render(item['text']) - return JSON(rv, 200) + return fetched_list @xhr def like(self, environ, request, id):