2010-05-20 18:09:10 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
#
|
|
|
|
# Copyright under the latest Apache License 2.0
|
2010-05-21 15:10:58 +00:00
|
|
|
#
|
|
|
|
# Patched for hrafn to include fixes to issues 2, 3, 9, 10
|
|
|
|
#
|
|
|
|
# Additional patch to make it work with the 'dev' branch of python-twitter
|
2010-05-20 18:09:10 +00:00
|
|
|
|
|
|
|
'''A class the inherits everything from python-twitter and allows oauth based access
|
|
|
|
|
|
|
|
Requires:
|
|
|
|
python-twitter
|
|
|
|
simplejson
|
|
|
|
oauth
|
|
|
|
'''
|
|
|
|
|
|
|
|
__author__ = "Hameedullah Khan <hameed@hameedkhan.net>"
|
|
|
|
__version__ = "0.2"
|
|
|
|
|
|
|
|
|
2010-05-21 00:51:20 +00:00
|
|
|
from twitter import Api,NewUserFromJsonDict
|
2010-05-20 20:51:51 +00:00
|
|
|
from twitter_pb2 import User
|
2010-05-20 18:09:10 +00:00
|
|
|
|
2010-05-21 15:10:58 +00:00
|
|
|
import logging
|
2010-05-20 20:51:51 +00:00
|
|
|
import simplejson
|
|
|
|
import oauth.oauth as oauth
|
2010-05-21 15:10:58 +00:00
|
|
|
import time
|
|
|
|
from urllib import urlencode
|
|
|
|
from urllib2 import BaseHandler
|
2010-05-20 18:09:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
# Taken from oauth implementation at: http://github.com/harperreed/twitteroauth-python/tree/master
|
|
|
|
REQUEST_TOKEN_URL = 'https://twitter.com/oauth/request_token'
|
|
|
|
ACCESS_TOKEN_URL = 'https://twitter.com/oauth/access_token'
|
|
|
|
AUTHORIZATION_URL = 'http://twitter.com/oauth/authorize'
|
|
|
|
SIGNIN_URL = 'http://twitter.com/oauth/authenticate'
|
|
|
|
|
2010-05-21 15:10:58 +00:00
|
|
|
class LoggingHandler(BaseHandler):
|
|
|
|
""" debugging handler that logs HTTP errors """
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
# ensures that this handler runs first
|
|
|
|
self.handler_order=0
|
|
|
|
|
|
|
|
def http_error_default(self, req, fp, code, msg, hdrs):
|
|
|
|
logging.debug("%s %s: %s" % (code, msg, fp.read()))
|
|
|
|
|
|
|
|
|
2010-05-20 18:09:10 +00:00
|
|
|
|
|
|
|
class OAuthApi(Api):
|
|
|
|
def __init__(self, consumer_key, consumer_secret, access_token=None):
|
|
|
|
if access_token:
|
|
|
|
Api.__init__(self,access_token.key, access_token.secret)
|
|
|
|
else:
|
|
|
|
Api.__init__(self)
|
|
|
|
self._Consumer = oauth.OAuthConsumer(consumer_key, consumer_secret)
|
|
|
|
self._signature_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
|
|
|
|
self._access_token = access_token
|
|
|
|
|
|
|
|
|
|
|
|
def _GetOpener(self):
|
2010-05-21 15:10:58 +00:00
|
|
|
opener = self._urllib.build_opener(LoggingHandler())
|
2010-05-20 18:09:10 +00:00
|
|
|
return opener
|
|
|
|
|
|
|
|
def _FetchUrl(self,
|
|
|
|
url,
|
|
|
|
post_data=None,
|
|
|
|
parameters=None,
|
|
|
|
no_cache=None):
|
|
|
|
'''Fetch a URL, optionally caching for a specified time.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
url: The URL to retrieve
|
|
|
|
post_data:
|
|
|
|
A dict of (str, unicode) key/value pairs. If set, POST will be used.
|
|
|
|
parameters:
|
|
|
|
A dict whose key/value pairs should encoded and added
|
|
|
|
to the query string. [OPTIONAL]
|
|
|
|
no_cache: If true, overrides the cache on the current request
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
A string containing the body of the response.
|
|
|
|
'''
|
|
|
|
# Build the extra parameters dict
|
|
|
|
extra_params = {}
|
|
|
|
if self._default_params:
|
|
|
|
extra_params.update(self._default_params)
|
|
|
|
if parameters:
|
|
|
|
extra_params.update(parameters)
|
|
|
|
|
|
|
|
# Add key/value parameters to the query string of the url
|
|
|
|
#url = self._BuildUrl(url, extra_params=extra_params)
|
|
|
|
|
2010-05-21 15:10:58 +00:00
|
|
|
if post_data is not None:
|
2010-05-20 18:09:10 +00:00
|
|
|
http_method = "POST"
|
2010-05-21 15:10:58 +00:00
|
|
|
post_data=dict([(k, self._Encode(v)) for k, v in post_data.items()])
|
2010-05-20 18:09:10 +00:00
|
|
|
extra_params.update(post_data)
|
|
|
|
else:
|
|
|
|
http_method = "GET"
|
|
|
|
|
|
|
|
req = self._makeOAuthRequest(url, parameters=extra_params,
|
|
|
|
http_method=http_method)
|
|
|
|
self._signRequest(req, self._signature_method)
|
|
|
|
|
|
|
|
|
|
|
|
# Get a url opener that can handle Oauth basic auth
|
|
|
|
opener = self._GetOpener()
|
|
|
|
|
|
|
|
|
2010-05-21 15:10:58 +00:00
|
|
|
if post_data is not None:
|
2010-05-20 18:09:10 +00:00
|
|
|
encoded_post_data = req.to_postdata()
|
2010-05-21 15:10:58 +00:00
|
|
|
req_url = req.get_normalized_http_url()
|
2010-05-20 18:09:10 +00:00
|
|
|
else:
|
2010-05-21 15:10:58 +00:00
|
|
|
encoded_post_data = None
|
|
|
|
req_url = req.to_url()
|
|
|
|
|
|
|
|
|
2010-05-20 18:09:10 +00:00
|
|
|
# Open and return the URL immediately if we're not going to cache
|
|
|
|
# OR we are posting data
|
2010-05-21 15:10:58 +00:00
|
|
|
if encoded_post_data or no_cache or not self._cache or not self._cache_timeout:
|
|
|
|
url_data = opener.open(req_url, encoded_post_data).read()
|
2010-05-20 18:09:10 +00:00
|
|
|
opener.close()
|
|
|
|
else:
|
|
|
|
# Unique keys are a combination of the url and the username
|
|
|
|
if self._username:
|
2010-05-21 15:10:58 +00:00
|
|
|
key = self._username + ':' + url + '?' + urlencode(extra_params)
|
2010-05-20 18:09:10 +00:00
|
|
|
else:
|
2010-05-21 15:10:58 +00:00
|
|
|
key = url + '?' + urlencode(extra_params)
|
2010-05-20 18:09:10 +00:00
|
|
|
|
|
|
|
# See if it has been cached before
|
|
|
|
last_cached = self._cache.GetCachedTime(key)
|
|
|
|
|
|
|
|
# If the cached version is outdated then fetch another and store it
|
|
|
|
if not last_cached or time.time() >= last_cached + self._cache_timeout:
|
2010-05-21 15:10:58 +00:00
|
|
|
url_data = opener.open(req_url, encoded_post_data).read()
|
2010-05-20 18:09:10 +00:00
|
|
|
opener.close()
|
|
|
|
self._cache.Set(key, url_data)
|
|
|
|
else:
|
|
|
|
url_data = self._cache.Get(key)
|
|
|
|
|
|
|
|
# Always return the latest version
|
|
|
|
return url_data
|
|
|
|
|
|
|
|
def _makeOAuthRequest(self, url, token=None,
|
|
|
|
parameters=None, http_method="GET"):
|
|
|
|
'''Make a OAuth request from url and parameters
|
|
|
|
|
|
|
|
Args:
|
|
|
|
url: The Url to use for creating OAuth Request
|
|
|
|
parameters:
|
|
|
|
The URL parameters
|
|
|
|
http_method:
|
|
|
|
The HTTP method to use
|
|
|
|
Returns:
|
|
|
|
A OAauthRequest object
|
|
|
|
'''
|
|
|
|
if not token:
|
|
|
|
token = self._access_token
|
|
|
|
request = oauth.OAuthRequest.from_consumer_and_token(
|
|
|
|
self._Consumer, token=token,
|
|
|
|
http_url=url, parameters=parameters,
|
|
|
|
http_method=http_method)
|
|
|
|
return request
|
|
|
|
|
|
|
|
def _signRequest(self, req, signature_method=oauth.OAuthSignatureMethod_HMAC_SHA1()):
|
|
|
|
'''Sign a request
|
|
|
|
|
|
|
|
Reminder: Created this function so incase
|
|
|
|
if I need to add anything to request before signing
|
|
|
|
|
|
|
|
Args:
|
|
|
|
req: The OAuth request created via _makeOAuthRequest
|
|
|
|
signate_method:
|
|
|
|
The oauth signature method to use
|
|
|
|
'''
|
|
|
|
req.sign_request(signature_method, self._Consumer, self._access_token)
|
|
|
|
|
|
|
|
|
|
|
|
def getAuthorizationURL(self, token, url=AUTHORIZATION_URL):
|
|
|
|
'''Create a signed authorization URL
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
A signed OAuthRequest authorization URL
|
|
|
|
'''
|
|
|
|
req = self._makeOAuthRequest(url, token=token)
|
|
|
|
self._signRequest(req)
|
|
|
|
return req.to_url()
|
|
|
|
|
|
|
|
def getSigninURL(self, token, url=SIGNIN_URL):
|
|
|
|
'''Create a signed Sign-in URL
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
A signed OAuthRequest Sign-in URL
|
|
|
|
'''
|
|
|
|
|
|
|
|
signin_url = self.getAuthorizationURL(token, url)
|
|
|
|
return signin_url
|
|
|
|
|
2010-05-20 22:03:35 +00:00
|
|
|
def getAccessToken(self, pin=None, url=ACCESS_TOKEN_URL):
|
|
|
|
params = None
|
|
|
|
if pin:
|
|
|
|
params = {'oauth_verifier': pin}
|
|
|
|
token = self._FetchUrl(url, parameters=params, no_cache=True)
|
2010-05-20 18:09:10 +00:00
|
|
|
return oauth.OAuthToken.from_string(token)
|
|
|
|
|
|
|
|
def getRequestToken(self, url=REQUEST_TOKEN_URL):
|
|
|
|
'''Get a Request Token from Twitter
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
A OAuthToken object containing a request token
|
|
|
|
'''
|
|
|
|
resp = self._FetchUrl(url, no_cache=True)
|
|
|
|
token = oauth.OAuthToken.from_string(resp)
|
|
|
|
return token
|
|
|
|
|
2010-05-21 15:10:58 +00:00
|
|
|
def GetUserInfo(self, url='http://api.twitter.com/1/account/verify_credentials.json'):
|
2010-05-20 18:09:10 +00:00
|
|
|
'''Get user information from twitter
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
Returns the twitter.User object
|
|
|
|
'''
|
|
|
|
json = self._FetchUrl(url)
|
|
|
|
data = simplejson.loads(json)
|
|
|
|
self._CheckForTwitterError(data)
|
2010-05-21 00:51:20 +00:00
|
|
|
return NewUserFromJsonDict(data)
|
2010-05-20 18:09:10 +00:00
|
|
|
|