From 5b8ffde2a51636720f303d7753344c2c8a7d27c0 Mon Sep 17 00:00:00 2001 From: Ivan Dyedov Date: Sun, 24 Mar 2013 15:39:44 -0400 Subject: [PATCH 1/4] initial commit of disqus_static plugin, a plugin for allowing you to fetch disqus comments from their API and embed them into your templates at HTML generation time. --- pelicanext/disqus_static/README.rst | 61 +++++++++++++++++++++++ pelicanext/disqus_static/disqus_static.py | 41 +++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 pelicanext/disqus_static/README.rst create mode 100644 pelicanext/disqus_static/disqus_static.py diff --git a/pelicanext/disqus_static/README.rst b/pelicanext/disqus_static/README.rst new file mode 100644 index 0000000..fac6c8d --- /dev/null +++ b/pelicanext/disqus_static/README.rst @@ -0,0 +1,61 @@ +Disqus static comment plugin for Pelican +==================================== + +This plugin adds a disqus_comments property to all articles. +Comments are fetched at generation time using disqus API. + +Installation +------------ +Because we use disqus API to retrieve the comments you need to create an application at +http://disqus.com/api/applications/ which will provide you with a secret and public keys for the API. + +Put ``disqus_static.py`` plugin in ``plugins`` folder in pelican installation +and use the following in your settings:: + + PLUGINS = [u"pelican.plugins.disqus_static"] + + DISQUS_SITENAME = u'YOUR_SITENAME' + DISQUS_SECRET_KEY = u'YOUR_SECRET_KEY' + DISQUS_PUBLIC_KEY = u'YOUR_PUBLIC_KEY' + +Usage +----- + +Example use of the comments in templates: +.. code-block:: html+jinja + + {% if article.disqus_comments %} +
+

{{ article.disqus_comments|length }} comments

+ +
+ {% endif %} + +TODO +----- + + - handle replies to comments properly and maintain parent-child relationships + - test for sites with over 100 comments (I think disqus API only returns 100 items per request) diff --git a/pelicanext/disqus_static/disqus_static.py b/pelicanext/disqus_static/disqus_static.py new file mode 100644 index 0000000..78b56e5 --- /dev/null +++ b/pelicanext/disqus_static/disqus_static.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +""" +Disqus static comment plugin for Pelican +==================================== +This plugin adds a disqus_comments property to all articles. +Comments are fetched at generation time using disqus API. +""" + +from disqusapi import DisqusAPI +from pelican import signals + +def initialized(pelican): + from pelican.settings import _DEFAULT_CONFIG + _DEFAULT_CONFIG.setdefault('DISQUS_SECRET_KEY', '') + _DEFAULT_CONFIG.setdefault('DISQUS_PUBLIC_KEY', '') + if pelican: + pelican.settings.setdefault('DISQUS_SECRET_KEY', '') + pelican.settings.setdefault('DISQUS_PUBLIC_KEY', '') + +def disqus_static(generator): + disqus = DisqusAPI(generator.settings['DISQUS_SECRET_KEY'], + generator.settings['DISQUS_PUBLIC_KEY']) + threads = disqus.threads.list(forum=generator.settings['DISQUS_SITENAME']) + thread_dict = {} # disqus thread id => title + for thread in threads: + thread_dict[thread['id']] = thread['title'] + posts = disqus.posts.list(forum=generator.settings['DISQUS_SITENAME']) + post_dict = {} # title => [post1, post2, ...] + for post in posts: + if post['thread'] not in thread_dict.keys(): + continue + if thread_dict[post['thread']] not in post_dict.keys(): + post_dict[thread_dict[post['thread']]] = [] + post_dict[thread_dict[post['thread']]].append(post) + for article in generator.articles: + if article.title in post_dict: + article.disqus_comments = post_dict[article.title] + +def register(): + signals.initialized.connect(initialized) + signals.article_generator_finalized.connect(disqus_static) From c29e08209312ff35514ef219723e5098c9a0338c Mon Sep 17 00:00:00 2001 From: Ivan Dyedov Date: Sun, 24 Mar 2013 15:47:27 -0400 Subject: [PATCH 2/4] fix README markdown display --- pelicanext/disqus_static/README.rst | 57 ++++++++++++++--------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/pelicanext/disqus_static/README.rst b/pelicanext/disqus_static/README.rst index fac6c8d..05c68b6 100644 --- a/pelicanext/disqus_static/README.rst +++ b/pelicanext/disqus_static/README.rst @@ -21,38 +21,37 @@ and use the following in your settings:: Usage ----- -Example use of the comments in templates: .. code-block:: html+jinja - {% if article.disqus_comments %} -
-

{{ article.disqus_comments|length }} comments

-
    - {% for comment in article.disqus_comments %} -
  • -
    -
    - Avatar -
    -
    -
    - {{ comment.author.name }} - {{ comment.createdAt }} -
    -
    -
    -
    - {{ comment.message }} + {% if article.disqus_comments %} +
    +

    {{ article.disqus_comments|length }} comments

    +
      + {% for comment in article.disqus_comments %} +
    • +
      +
      + Avatar +
      +
      +
      + {{ comment.author.name }} + {{ comment.createdAt }} +
      +
      +
      +
      + {{ comment.message }} +
      +
      +
      +
      -
    -
    -
    -
    -
  • - {% endfor %} -
-
- {% endif %} + + {% endfor %} + + + {% endif %} TODO ----- From 4e7a4bd592d902b8ab3e625c5e99f55a33d60fa8 Mon Sep 17 00:00:00 2001 From: Ivan Dyedov Date: Sun, 24 Mar 2013 16:13:47 -0400 Subject: [PATCH 3/4] make the disqus_static plugin work for sites with over 25 comments --- pelicanext/disqus_static/README.rst | 4 +++- pelicanext/disqus_static/disqus_static.py | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pelicanext/disqus_static/README.rst b/pelicanext/disqus_static/README.rst index 05c68b6..9bcc84f 100644 --- a/pelicanext/disqus_static/README.rst +++ b/pelicanext/disqus_static/README.rst @@ -9,6 +9,9 @@ Installation Because we use disqus API to retrieve the comments you need to create an application at http://disqus.com/api/applications/ which will provide you with a secret and public keys for the API. +We use disqus-python package for communication with disqus API: +``pip install disqus-python`` + Put ``disqus_static.py`` plugin in ``plugins`` folder in pelican installation and use the following in your settings:: @@ -57,4 +60,3 @@ TODO ----- - handle replies to comments properly and maintain parent-child relationships - - test for sites with over 100 comments (I think disqus API only returns 100 items per request) diff --git a/pelicanext/disqus_static/disqus_static.py b/pelicanext/disqus_static/disqus_static.py index 78b56e5..c775474 100644 --- a/pelicanext/disqus_static/disqus_static.py +++ b/pelicanext/disqus_static/disqus_static.py @@ -6,7 +6,7 @@ This plugin adds a disqus_comments property to all articles. Comments are fetched at generation time using disqus API. """ -from disqusapi import DisqusAPI +from disqusapi import DisqusAPI, Paginator from pelican import signals def initialized(pelican): @@ -20,11 +20,13 @@ def initialized(pelican): def disqus_static(generator): disqus = DisqusAPI(generator.settings['DISQUS_SECRET_KEY'], generator.settings['DISQUS_PUBLIC_KEY']) - threads = disqus.threads.list(forum=generator.settings['DISQUS_SITENAME']) + threads = Paginator(disqus.threads.list, + forum=generator.settings['DISQUS_SITENAME']) thread_dict = {} # disqus thread id => title for thread in threads: thread_dict[thread['id']] = thread['title'] - posts = disqus.posts.list(forum=generator.settings['DISQUS_SITENAME']) + + posts = Paginator(disqus.posts.list, forum=generator.settings['DISQUS_SITENAME']) post_dict = {} # title => [post1, post2, ...] for post in posts: if post['thread'] not in thread_dict.keys(): @@ -32,6 +34,7 @@ def disqus_static(generator): if thread_dict[post['thread']] not in post_dict.keys(): post_dict[thread_dict[post['thread']]] = [] post_dict[thread_dict[post['thread']]].append(post) + for article in generator.articles: if article.title in post_dict: article.disqus_comments = post_dict[article.title] From 77c7de21c5ac7b2e345d1fe6d948fb98d1fb26d5 Mon Sep 17 00:00:00 2001 From: Ivan Dyedov Date: Thu, 28 Mar 2013 18:25:11 -0400 Subject: [PATCH 4/4] add support for child posts --- pelicanext/disqus_static/README.rst | 24 +++++------ pelicanext/disqus_static/disqus_static.py | 51 +++++++++++++++++++---- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/pelicanext/disqus_static/README.rst b/pelicanext/disqus_static/README.rst index 9bcc84f..4e96548 100644 --- a/pelicanext/disqus_static/README.rst +++ b/pelicanext/disqus_static/README.rst @@ -28,11 +28,11 @@ Usage {% if article.disqus_comments %}
-

{{ article.disqus_comments|length }} comments

+

{{ article.disqus_comment_count }} comments

    - {% for comment in article.disqus_comments %} + {% for comment in article.disqus_comments recursive %}
  • -
    +
    Avatar
    @@ -41,22 +41,20 @@ Usage {{ comment.author.name }} {{ comment.createdAt }} -
    -
    -
    - {{ comment.message }} -
    +
    +
    + {{ comment.message }}
    + {% if comment.children %} +
      + {{ loop(comment.children) }} +
    + {% endif %}
  • {% endfor %}
{% endif %} - -TODO ------ - - - handle replies to comments properly and maintain parent-child relationships diff --git a/pelicanext/disqus_static/disqus_static.py b/pelicanext/disqus_static/disqus_static.py index c775474..3cb4473 100644 --- a/pelicanext/disqus_static/disqus_static.py +++ b/pelicanext/disqus_static/disqus_static.py @@ -20,24 +20,59 @@ def initialized(pelican): def disqus_static(generator): disqus = DisqusAPI(generator.settings['DISQUS_SECRET_KEY'], generator.settings['DISQUS_PUBLIC_KEY']) + # first retrieve the threads threads = Paginator(disqus.threads.list, forum=generator.settings['DISQUS_SITENAME']) - thread_dict = {} # disqus thread id => title + # build a {thread_id: title} dict + thread_dict = {} for thread in threads: thread_dict[thread['id']] = thread['title'] - posts = Paginator(disqus.posts.list, forum=generator.settings['DISQUS_SITENAME']) - post_dict = {} # title => [post1, post2, ...] + # now retrieve the posts + posts = Paginator(disqus.posts.list, + forum=generator.settings['DISQUS_SITENAME']) + + # build a {post_id: [child_post1, child_post2, ...]} dict + child_dict = {} for post in posts: - if post['thread'] not in thread_dict.keys(): - continue - if thread_dict[post['thread']] not in post_dict.keys(): - post_dict[thread_dict[post['thread']]] = [] - post_dict[thread_dict[post['thread']]].append(post) + if post['id'] not in child_dict.keys(): + child_dict[post['id']] = [] + if post['parent'] is not None: + if str(post['parent']) not in child_dict.keys(): + child_dict[str(post['parent'])] = [] + child_dict[str(post['parent'])].append(post) + + # build a {title: [post1, post2, ...]} dict + post_dict = {} + for post in posts: + build_post_dict(post_dict, child_dict, thread_dict, post) for article in generator.articles: if article.title in post_dict: article.disqus_comments = post_dict[article.title] + article.disqus_comment_count = sum([ + postcounter(post) for post in post_dict[article.title]]) + +def postcounter(node): + return 1 + sum([postcounter(n) for n in node['children']]) + +def build_post_dict(post_dict, child_dict, thread_dict, post): + if post['thread'] not in thread_dict.keys(): + return # invalid thread, should never happen + + build_child_dict(child_dict, post) + + if post['parent'] is not None: + return # this is a child post, don't want to display it here + + if thread_dict[post['thread']] not in post_dict.keys(): + post_dict[thread_dict[post['thread']]] = [] + post_dict[thread_dict[post['thread']]].append(post) + +def build_child_dict(child_dict, post): + post['children'] = child_dict[post['id']] + for child in child_dict[post['id']]: + build_child_dict(child_dict, child) def register(): signals.initialized.connect(initialized)