Permalink
Browse files

disquis comments

  • Loading branch information...
d1ffuz0r
d1ffuz0r committed May 5, 2012
1 parent 6d75a8e commit 23a361a32553491ee5e29504f35628bacfad006f
View
@@ -0,0 +1,25 @@
+import urllib
+import urllib2
+
+from django.core.management.base import CommandError
+from django.utils import simplejson as json
+from django.conf import settings
+
+def call(method, data, post=False):
+ """
+ Calls `method` from the DISQUS API with data either in POST or GET.
+ Returns deserialized JSON response.
+ """
+ url = "%s%s" % ('http://disqus.com/api/', method)
+ if post:
+ # POST request
+ url += "/"
+ data = urllib.urlencode(data)
+ else:
+ # GET request
+ url += "?%s" % urllib.urlencode(data)
+ data = ''
+ res = json.load(urllib2.urlopen(url, data))
+ if not res['succeeded']:
+ raise CommandError("'%s' failed: %s\nData: %s" % (method, res['code'], data))
+ return res['message']
View
@@ -0,0 +1,86 @@
+from urllib import urlencode
+import urllib2
+
+from django.utils import simplejson as json
+
+# A custom ProxyHandler for the urllib2 module that will not
+# auto-detect proxy settings
+proxy_support = urllib2.ProxyHandler({})
+opener = urllib2.build_opener(proxy_support)
+urllib2.install_opener(opener)
+
+class DisqusException(Exception):
+ """Exception raised for errors with the DISQUS API."""
+ pass
+
+class DisqusClient(object):
+ """
+ Client for the DISQUS API.
+
+ Example:
+ >>> client = DisqusClient()
+ >>> json = client.get_forum_list(user_api_key=DISQUS_API_KEY)
+ """
+ METHODS = {
+ 'create_post': 'POST',
+ 'get_forum_api_key': 'GET',
+ 'get_forum_list': 'GET',
+ 'get_forum_posts': 'GET',
+ 'get_num_posts': 'GET',
+ 'get_thread_by_url': 'GET',
+ 'get_thread_list': 'GET',
+ 'get_thread_posts': 'GET',
+ 'get_updated_threads': 'GET',
+ 'get_user_name': 'POST',
+ 'moderate_post': 'POST',
+ 'thread_by_identifier': 'POST',
+ 'update_thread': 'POST',
+ }
+
+ def __init__(self, **kwargs):
+ self.api_url = 'http://disqus.com/api/%s/?api_version=1.1'
+ self.__dict__.update(kwargs)
+
+ def __getattr__(self, attr):
+ """
+ Called when an attribute is not found in the usual places
+ (__dict__, class tree) this method will check if the attribute
+ name is a DISQUS API method and call the `call` method.
+ If it isn't in the METHODS dict, it will raise an AttributeError.
+ """
+ if attr in self.METHODS:
+ def call_method(**kwargs):
+ return self.call(attr, **kwargs)
+ return call_method
+ raise AttributeError
+
+ def _get_request(self, request_url, request_method, **params):
+ """
+ Return a urllib2.Request object that has the GET parameters
+ attached to the url or the POST data attached to the object.
+ """
+ if request_method == 'GET':
+ if params:
+ request_url += '&%s' % urlencode(params)
+ request = urllib2.Request(request_url)
+ elif request_method == 'POST':
+ request = urllib2.Request(request_url, urlencode(params,doseq=1))
+ return request
+
+ def call(self, method, **params):
+ """
+ Call the DISQUS API and return the json response.
+ URLError is raised when the request failed.
+ DisqusException is raised when the query didn't succeed.
+ """
+ url = self.api_url % method
+ request = self._get_request(url, self.METHODS[method], **params)
+ try:
+ response = urllib2.urlopen(request)
+ except urllib2.URLError, e:
+ raise
+ else:
+ response_json = json.loads(response.read())
+ if not response_json['succeeded']:
+ raise DisqusException(response_json['message'])
+ return response_json['message']
No changes.
No changes.
@@ -0,0 +1,57 @@
+from optparse import make_option
+
+from django.core.management.base import NoArgsCommand, CommandError
+from django.utils import simplejson as json
+
+from disqus.api import DisqusClient
+
+
+class Command(NoArgsCommand):
+ option_list = NoArgsCommand.option_list + (
+ make_option('--indent', default=None, dest='indent', type='int',
+ help='Specifies the indent level to use when pretty-printing output'),
+ make_option('--filter', default='', dest='filter', type='str',
+ help='Type of entries that should be returned'),
+ make_option('--exclude', default='', dest='exclude', type='str',
+ help='Type of entries that should be excluded from the response'),
+ )
+ help = 'Output DISQUS data in JSON format'
+ requires_model_validation = False
+
+ def handle(self, **options):
+ from django.conf import settings
+
+ client = DisqusClient()
+ indent = options.get('indent')
+ filter_ = options.get('filter')
+ exclude = options.get('exclude')
+
+ # Get a list of all forums for an API key. Each API key can have
+ # multiple forums associated. This application only supports the one
+ # set in the DISQUS_WEBSITE_SHORTNAME variable
+ forum_list = client.get_forum_list(user_api_key=settings.DISQUS_API_KEY)
+ try:
+ forum = [f for f in forum_list\
+ if f['shortname'] == settings.DISQUS_WEBSITE_SHORTNAME][0]
+ except IndexError:
+ raise CommandError("Could not find forum. " +
+ "Please check your " +
+ "'DISQUS_WEBSITE_SHORTNAME' setting.")
+ posts = []
+ has_new_posts = True
+ start = 0
+ step = 100
+ while has_new_posts:
+ new_posts = client.get_forum_posts(
+ user_api_key=settings.DISQUS_API_KEY,
+ forum_id=forum['id'],
+ start=start,
+ limit=start+step,
+ filter=filter_,
+ exclude=exclude)
+ if not new_posts:
+ has_new_posts = False
+ else:
+ start += step
+ posts.append(new_posts)
+ print json.dumps(posts, indent=indent)
@@ -0,0 +1,133 @@
+from optparse import make_option
+import os.path
+
+from django.conf import settings
+from django.contrib import comments
+from django.contrib.sites.models import Site
+from django.core.management.base import NoArgsCommand
+from django.utils import simplejson as json
+
+from disqus.api import DisqusClient
+
+
+class Command(NoArgsCommand):
+ option_list = NoArgsCommand.option_list + (
+ make_option('-d', '--dry-run', action="store_true", dest="dry_run",
+ help='Does not export any comments, but merely outputs' +
+ 'the comments which would have been exported.'),
+ make_option('-s', '--state-file', action="store", dest="state_file",
+ help="Saves the state of the export in the given file " +
+ "and auto-resumes from this file if possible."),
+ )
+ help = 'Export comments from contrib.comments to DISQUS'
+ requires_model_validation = False
+
+ def _get_comments_to_export(self, last_export_id=None):
+ """Return comments which should be exported."""
+ qs = comments.get_model().objects.order_by('pk')\
+ .filter(is_public=True, is_removed=False)
+ if last_export_id is not None:
+ print "Resuming after comment %s" % str(last_export_id)
+ qs = qs.filter(id__gt=last_export_id)
+ return qs
+
+ def _get_last_state(self, state_file):
+ """Checks the given path for the last exported comment's id"""
+ state = None
+ fp = open(state_file)
+ try:
+ state = int(fp.read())
+ print "Found previous state: %d" % (state,)
+ finally:
+ fp.close()
+ return state
+
+ def _save_state(self, state_file, last_pk):
+ """Saves the last_pk into the given state_file"""
+ fp = open(state_file, 'w+')
+ try:
+ fp.write(str(last_pk))
+ finally:
+ fp.close()
+
+ def handle(self, **options):
+ current_site = Site.objects.get_current()
+ client = DisqusClient()
+ verbosity = int(options.get('verbosity'))
+ dry_run = bool(options.get('dry_run'))
+ state_file = options.get('state_file')
+ last_exported_id = None
+
+ if state_file is not None and os.path.exists(state_file):
+ last_exported_id = self._get_last_state(state_file)
+
+ comments = self._get_comments_to_export(last_exported_id)
+ comments_count = comments.count()
+ if verbosity >= 1:
+ print "Exporting %d comment(s)" % comments_count
+
+ # if this is a dry run, we output the comments and exit
+ if dry_run:
+ print comments
+ return
+ # if no comments were found we also exit
+ if not comments_count:
+ return
+
+ # Get a list of all forums for an API key. Each API key can have
+ # multiple forums associated. This application only supports the one
+ # set in the DISQUS_WEBSITE_SHORTNAME variable
+ forum_list = client.get_forum_list(user_api_key=settings.DISQUS_API_KEY)
+ try:
+ forum = [f for f in forum_list\
+ if f['shortname'] == settings.DISQUS_WEBSITE_SHORTNAME][0]
+ except IndexError:
+ raise CommandError("Could not find forum. " +
+ "Please check your " +
+ "'DISQUS_WEBSITE_SHORTNAME' setting.")
+
+ # Get the forum API key
+ forum_api_key = client.get_forum_api_key(
+ user_api_key=settings.DISQUS_API_KEY,
+ forum_id=forum['id'])
+
+ for comment in comments:
+ if verbosity >= 1:
+ print "Exporting comment '%s'" % comment
+
+ # Try to find a thread with the comments URL.
+ url = 'http://%s%s' % (
+ current_site.domain,
+ comment.content_object.get_absolute_url())
+ thread = client.get_thread_by_url(
+ url=url,
+ forum_api_key=forum_api_key)
+
+ # if no thread with the URL could be found, we create a new one.
+ # to do this, we first need to create the thread and then
+ # update the thread with a URL.
+ if not thread:
+ thread = client.thread_by_identifier(
+ forum_api_key=forum_api_key,
+ identifier=unicode(comment.content_object),
+ title=unicode(comment.content_object),
+ )['thread']
+ client.update_thread(
+ forum_api_key=forum_api_key,
+ thread_id=thread['id'],
+ url=url)
+
+ # name and email are optional in contrib.comments but required
+ # in DISQUS. If they are not set, dummy values will be used
+ client.create_post(
+ forum_api_key=forum_api_key,
+ thread_id=thread['id'],
+ message=comment.comment.encode('utf-8'),
+ author_name=comment.userinfo.get('name',
+ 'nobody').encode('utf-8'),
+ author_email=comment.userinfo.get('email',
+ 'nobody@example.org'),
+ author_url=comment.userinfo.get('url', ''),
+ created_at=comment.submit_date.strftime('%Y-%m-%dT%H:%M'))
+ if state_file is not None:
+ self._save_state(state_file, comment.pk)
View
No changes.
@@ -0,0 +1,13 @@
+<script type="text/javascript">
+{% block config_variables %}
+ var disqus_shortname = '{{ shortname }}';
+{{ config|safe }}
+{% endblock %}
+ /* * * DON'T EDIT BELOW THIS LINE * * */
+ (function () {
+ var s = document.createElement('script'); s.async = true;
+ s.type = 'text/javascript';
+ s.src = 'http://' + disqus_shortname + '.disqus.com/count.js';
+ (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
+ }());
+</script>
@@ -0,0 +1,10 @@
+<div id="dsq-recent-comments" class="dsq-widget">
+<script type="text/javascript">
+{% block config_variables %}
+ var disqus_shortname = '{{ shortname }}';
+{{ config|safe }}
+{% endblock %}
+</script>
+<script src='http://{{ shortname }}.disqus.com/recent_comments_widget.js?num_items={{ num_items }}&hide_avatars={{ hide_avatars }}&avatar_size={{ avatar_size }}&excerpt_length={{ excerpt_length }}'>
+</script>
+</div>
@@ -0,0 +1,15 @@
+<div id="disqus_thread"></div>
+<script type="text/javascript">
+/* <![CDATA[ */
+{% block config_variables %}
+ var disqus_shortname = '{{ shortname }}';
+{{ config|safe}}
+{% endblock %}
+ /* * * DON'T EDIT BELOW THIS LINE * * */
+ (function() {
+ var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
+ dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
+ (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
+ })();
+</script>
+<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
No changes.
Oops, something went wrong.

0 comments on commit 23a361a

Please sign in to comment.