This file contains the functions to generate short
URLs and tweets from what's currently in the database.
-Copyright (C) 2009 PostgreSQL Global Development Group
+Copyright (C) 2009-2010 PostgreSQL Global Development Group
"""
# Post links to articles on twitter
import psycopg2
import psycopg2.extensions
-import twitter
import urllib
import simplejson as json
import ConfigParser
+import time
+import oauth2 as oauth
class PostToTwitter:
def __init__(self, cfg):
- self.username=cfg.get('twitter','account')
- self.passwd=cfg.get('twitter','password')
+ self.oauth_token = oauth.Token(cfg.get('twitter', 'token'), cfg.get('twitter', 'secret'))
+ self.oauth_consumer = oauth.Consumer(cfg.get('twitter', 'consumer'), cfg.get('twitter', 'consumersecret'))
if cfg.has_option('bit.ly','account'):
self.bitlyuser = cfg.get('bit.ly','account')
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
self.db = psycopg2.connect(c.get('planet','db'))
- # Only set up the connection to twitter when we know we're going to
- # post something.
- self._twitter = None
-
- @property
- def twitter(self):
- if not self._twitter:
- self._twitter=twitter.Api(username=self.username, password=self.passwd)
- return self._twitter
+ def do_post(self, msg):
+ """
+ Actually make a post to twitter!
+
+ Authentication is done through OAuth, which controls the user to whom this is posted.
+ """
+ params = {
+ 'oauth_version': "1.0",
+ 'oauth_nonce': oauth.generate_nonce(),
+ 'oauth_timestamp': int(time.time()),
+ 'oauth_token': self.oauth_token.key,
+ 'oauth_consumer_key': self.oauth_consumer.key,
+ 'status': msg,
+ }
+
+ req = oauth.Request(method="POST",
+ url="https://api.twitter.com/1/statuses/update.json",
+ parameters=params)
+ req.sign_request(oauth.SignatureMethod_HMAC_SHA1(), self.oauth_consumer, self.oauth_token)
+
+ # Make the actual call to twitter
+ instream=urllib.urlopen("https://api.twitter.com/1/statuses/update.json", req.to_postdata())
+ ret=instream.read()
+ instream.close()
+ ret_dict = json.loads(ret)
+ if ret_dict.has_key('created_at'):
+ return
+ if ret_dict.has_key('error'):
+ raise Exception("Could not post to twitter: %s" % ret_dict['error'])
+ raise Exception("Unparseable response from twitter: %s" % ret)
def Run(self):
c = self.db.cursor()
# Now post it to twitter
try:
- status = self.twitter.PostUpdate(msg)
+ self.do_post(msg)
except Exception, e:
print "Error posting to twitter (post %s): %s" % (post[0], e)
# We'll just try again with the next one
--- /dev/null
+#!/usr/bin/env python
+# vim: ai ts=4 sts=4 sw=4
+"""PostgreSQL Planet Aggregator
+
+This file contains simpler wrapper for getting the oauth credentials
+to set up the twitter access.
+
+Copyright (C) 2010 PostgreSQL Global Development Group
+"""
+
+import sys
+import oauth2 as oauth
+import urlparse
+import ConfigParser
+
+cfg = ConfigParser.ConfigParser()
+cfg.read('planet.ini')
+
+if not cfg.has_option('twitter', 'consumer') or not cfg.has_option('twitter', 'consumersecret'):
+ print "Before you can run this, you need to register an application at"
+ print "developer.twitter.com and put the consumer and consumersecret values"
+ print "in the [twitter] section of planet.ini."
+ sys.exit(1)
+
+consumer = oauth.Consumer(cfg.get('twitter', 'consumer'), cfg.get('twitter', 'consumersecret'))
+client = oauth.Client(consumer)
+resp, content = client.request("https://api.twitter.com/oauth/request_token", "GET")
+if resp['status'] != '200':
+ print "request_token call failed!"
+ print resp
+ sys.exit(1)
+req_token_cred = dict(urlparse.parse_qsl(content))
+
+print "Received request token."
+print "Token secret (keep this for the next step): %s" % req_token_cred['oauth_token_secret']
+print ""
+print "Now, go to the following URL:"
+print "https://api.twitter.com/oauth/authorize?oauth_token=%s" % req_token_cred['oauth_token']
+print ""
+
+pin = raw_input('Enter the PIN here:')
+
+token = oauth.Token(req_token_cred['oauth_token'], req_token_cred['oauth_token_secret'])
+client = oauth.Client(consumer, token)
+# Put the PIN on the URL, because it seems to not work to use token.set_verifier()
+resp, content = client.request('https://api.twitter.com/oauth/access_token?oauth_verifier=%s' % pin, "POST")
+if resp['status'] != '200':
+ print "access_token failed!"
+ print resp
+ print content
+ sys.exit(1)
+
+r = dict(urlparse.parse_qsl(content))
+print "Access token received."
+print "Token: %s" % r['oauth_token']
+print "Secret: %s" % r['oauth_token_secret']
+print "Record these two values in planet.ini, and you're good to go!"
+
+
+