How to print tweets from twitter by a known access token? - python

from rauth.service import OAuth1Service
class TwitterClient:
KNOWN_USERS = ['177512438-pJTdMgOPLJ8hCQFfDbPmkU3LRcCSHZd5VqoM3WaY', '7Z50XjV1CqDF1753Rzd4MkzSYN1oCY2FaaFtAZU']
def __init__(self):
# Get a real consumer key & secret from https://dev.twitter.com/apps/new
self.twitter = OAuth1Service(
name='twitter',
consumer_key='ZjXNoqpLfhQvYBgkjrrvxQ',
consumer_secret='8O4NjcsNed8uGICjDLNTjPiNwqjPezovWZIVru1c',
request_token_url='https://api.twitter.com/oauth/request_token',
access_token_url='https://api.twitter.com/oauth/access_token',
authorize_url='https://api.twitter.com/oauth/authorize',
base_url='https://api.twitter.com/1/')
#self.KNOWN_USERS = ['177512438-pJTdMgOPLJ8hCQFfDbPmkU3LRcCSHZd5VqoM3WaY', '7Z50XjV1CqDF1753Rzd4MkzSYN1oCY2FaaFtAZU']
def new_session(self):
request_token, request_token_secret = self.twitter.get_request_token()
authorize_url = self.twitter.get_authorize_url(request_token)
print 'Visit this URL in your browser: ' + authorize_url
pin = raw_input('Enter PIN from browser: ')
session = self.twitter.get_auth_session(request_token,
request_token_secret,
method='POST',
data={'oauth_verifier': pin})
print session.access_token, session.access_token_secret # Save this to database
return session
def reuse_session(self, user2):
access_token = user2[0]
access_token_secret = user2[1]
session = self.twitter.get_session((access_token, access_token_secret))
return session
def init_session(self, user2):
if user2[0] == self.KNOWN_USERS[0] and user2[1] == self.KNOWN_USERS[1] : session = self.reuse_session(user2)
else : session = self.new_session()
return session
def list_tweets(self, user2):
session = self.init_session(user2)
params = {'include_rts': 1, # Include retweets
'count': 10} # 10 tweets
r = session.get('statuses/home_timeline.json', params=params)
for i, tweet in enumerate(r.json(), 1):
handle = tweet['user']['screen_name'].encode('utf-8')
text = tweet['text'].encode('utf-8')
print '{0}. #{1} - {2}'.format(i, handle, text)
tc = TwitterClient()
user1 = ['177512438-pJTdMgOPLJ8hCQFfDbPmkU3LRcCSHZd5VqoM3WaY', '7Z50XjV1CqDF1753Rzd4MkzSYN1oCY2FaaFtAZU']
tc.list_tweets( user1 )
But this gives the following error in line 50:
string indices must be integer
So instead I write this:
from rauth.service import OAuth1Service
class TwitterClient:
KNOWN_USERS = { # (access_token, access_token_secret)
'user1' : ('177512438-pJTdMgOPLJ8hCQFfDbPmkU3LRcCSHZd5VqoM3WaY', '7Z50XjV1CqDF1753Rzd4MkzSYN1oCY2FaaFtAZU')
}
def __init__(self):
# Get a real consumer key & secret from https://dev.twitter.com/apps/new
self.twitter = OAuth1Service(
name='twitter',
consumer_key='ZjXNoqpLfhQvYBgkjrrvxQ',
consumer_secret='8O4NjcsNed8uGICjDLNTjPiNwqjPezovWZIVru1c',
request_token_url='https://api.twitter.com/oauth/request_token',
access_token_url='https://api.twitter.com/oauth/access_token',
authorize_url='https://api.twitter.com/oauth/authorize',
base_url='https://api.twitter.com/1.1/')
def new_session(self):
request_token, request_token_secret = self.twitter.get_request_token()
authorize_url = self.twitter.get_authorize_url(request_token)
print 'Visit this URL in your browser: ' + authorize_url
pin = raw_input('Enter PIN from browser: ')
session = self.twitter.get_auth_session(request_token,
request_token_secret,
method='POST',
data={'oauth_verifier': pin})
print session.access_token, session.access_token_secret # Save this to database
return session
def reuse_session(self, user1):
access_token, access_token_secret = self.KNOWN_USERS[user1]
session = self.twitter.get_session((access_token, access_token_secret))
return session
def init_session(self, user1):
if user1 in self.KNOWN_USERS : session = self.reuse_session(user1)
else : session = self.new_session()
return session
def list_tweets(self, user1):
session = self.reuse_session(user1)
params = {'include_rts': 1, # Include retweets
'count': 10} # 10 tweets
r = session.get('statuses/home_timeline.json', params=params)
print r.json
#for i, tweet in enumerate(r.json(), 1):
#handle = tweet['user']['screen_name'].encode('utf-8')
#text = tweet['text'].encode('utf-8')
#print '{0}. - {2}'.format(i, text)
tc = TwitterClient()
tc.list_tweets('user1')
But I get the following error:
<bound method Response.json of <Response [401]>>

With the minimal information you've given us, I'm guessing your GET request is failing, causing you to receive a JSON object that looks like this:
{"errors":[{"message":"Bad Authentication data","code":215}]}
This will decode as a dictionary, and when you iterate over it you'll get the keys in the dictionary, which are strings. When you attempt to index into those strings using dictionary keys, you'll get the error that you can only index into strings (or any sequences) using integers.
Verify this by printing r.json() before iterating over it. Fix it by reading the error message you're getting back and remedying the problem it's reporting to you.

Related

Last.fm API invalid method signature but valid when getting session key

I wanna make python client for Last.fm API. I wanna build kind of library.
I managed to get and set a session by getting a session key. Afterwards, I try to call a POST method that requires API_key, api_signature and session key. So I use the APi key I have, same api_signature I used to get the session key and the session key itself.
But I get an "invalid method signature" even though I use the same api_signature for the POST calls.
import json
import webbrowser
from hashlib import md5
import urllib3
class PyLast():
def __init__(self, API_KEY, SECRET, SESSION_KEY=None):
self.__API_KEY__ = API_KEY
self.__SECRET__ = SECRET
self.__SESSION_KEY__ = SESSION_KEY
self.__api_signature__ = None
if SESSION_KEY is None:
self.__is_authorized__ = False
else:
self.__is_authorized__ = True
self.__http__ = urllib3.PoolManager()
def request_token(self):
print("Getting the token...")
url = 'http://ws.audioscrobbler.com/2.0/?method=auth.gettoken&api_key={}&format=json'.format(self.__API_KEY__)
req_response = self.__http__.request('GET', url, headers={'User-Agent' : 'Mozilla/5.0'})
if req_response.status == 200:
json_data = json.loads(req_response.data.decode('utf-8'))
TOKEN = json_data['token']
self.__TOKEN__ = TOKEN
return TOKEN
else:
print("Error with code " + req_response.status)
def authorize(self):
if not self.__is_authorized__:
url = 'http://www.last.fm/api/auth/?api_key={}&token={}'.format(self.__API_KEY__, self.__TOKEN__)
# open browser to authorize app
webbrowser.open(url, new=0, autoraise=True)
# Make sure authorized
self.__is_authorized__ = True
def start_session(self):
if self.__is_authorized__:
data = "api_key{}methodauth.getSessiontoken{}{}" \
.format(self.__API_KEY__, self.__TOKEN__, self.__SECRET__).encode(
encoding='utf-8')
self.__api_signature__ = md5(data).hexdigest()
url = 'http://ws.audioscrobbler.com/2.0/?method=auth.getSession&api_key={}&token={}&api_sig={}&format=json'.format(
self.__API_KEY__, self.__TOKEN__, self.__api_signature__)
req_response = self.__http__.request('GET', url)
if req_response.status == 200:
json_data = json.loads(req_response.data.decode('utf-8'))
session_key = json_data['session']['key']
self.__SESSION_KEY__ = session_key
url = 'http://ws.audioscrobbler.com/2.0/?method=track.love&api_key={}&api_sig={}&sk={}&artist=cher&track=believe&format=json'.format(
self.__API_KEY__, self.__api_signature__, self.__SESSION_KEY__)
req_response = self.__http__.request('POST', url)
return self.__SESSION_KEY__
else:
print("Error with code " + str(req_response.status))
else:
print("Not authorized!")
I found a solution. The problem was that I was using the same parameters used to generate session key to make a POST call. The right way to sign a method for Last.fm API is to build the api_sig from the POST method we want to use. for example, to generate api_sig for track.love we use these parameters:
data = {"api_key": API_KEY,
"method": "track.love",
"track" : "yellow",
"artist" :"coldplay",
"sk" : SESSION_KEY
}
keys = sorted(data.keys())
param = [k+data[k] for k in keys]
param = "".join(param) + SECRET
api_sig = md5(param.encode()).hexdigest() # this api_sig used to sign track.love call.

How to maintain the oauth session object between requests with django?

I am using the Requests-Oauthlib1 workflow to authenticate on a site with oauth 1 from django.
I think I am not using the one obvious way to do it.
The way I have implemented it:
/oauth - Gets the request token and returns the oauth authorization url
def oauth(request):
oauth_service = Oauth_service()
key, secret = oauth_service.obtain_request_token()
message = oauth_service.get_authorization_url()
return HttpResponse(message)
/oauthcomplete - oauth success redirects here, but I am now creating a new instance of the Oath_Service which won't have the request token and secret
def oauth_complete(request):
oauth_service = Oauth_service()
verifier = oauth_service.get_verifier(request.build_absolute_uri())
return HttpResponse("Verified with {}".format(verifier))
oauth_service.py
class Oauth_service:
'''
Class used to commuicate with an Oauth magento
'''
BASE_URL = 'https://xxx'
RETRIEVE_REQUEST_TOKEN_PATH = '/oauth/initiate'
ADMIN_AUTHORIZATION_PATH = '/admin/oauth_authorize'
RETRIEVE_ACCESS_TOKEN_PATH = '/oauth/token'
OAUTH_CONSUMER_KEY = 'xxx'
OAUTH_SECRET_KEY = 'xxx'
OAUTH_SIGNATURE_METHOD = 'HMAC-SHA1'
CALLBACK_URL = 'http://127.0.0.1:8000/models/oauth_complete'
oauth = OAuth1Session(
OAUTH_CONSUMER_KEY,
client_secret=OAUTH_SECRET_KEY,
callback_uri=CALLBACK_URL,
)
resource_owner_key = ''
resource_owner_secret = ''
verifier = ''
def obtain_request_token(self):
'''
step 1 in oauth process
'''
request_token_url = self.BASE_URL + self.RETRIEVE_REQUEST_TOKEN_PATH
headers = {
'Accept': 'application/json'
}
fetch_response = self.oauth.fetch_request_token(request_token_url, verify=False, headers=headers)
self.resource_owner_key = fetch_response.get('oauth_token')
self.resource_owner_secret = fetch_response.get('oauth_token_secret')
return self.resource_owner_key, self.resource_owner_secret
def get_authorization_url(self):
base_authorization_url = self.BASE_URL + self.ADMIN_AUTHORIZATION_PATH
authorization_url = self.oauth.authorization_url(base_authorization_url)
return 'Please go here and authorize, {}'.format(authorization_url)
def get_verifier(self, url):
oauth_response = self.oauth.parse_authorization_response(url)
verifier = oauth_response.get('oauth_verifier')
return verifier
It feels like I am doing this in a strange way with use of class variables that are updated but do not persist. As those class variables won't be their when a new instance of the service is created.
I am trying to maintain the OauthSession1 instance during the full oauth workflow.

Python backend, Login with facebook, error: "An active access token must be used to.."

I would like to create a working "login with facebook" button. There are many posts on this issue but I cannot find one tat helps.
It ALMOST works. I do get a short lived token to, together with app-id and client secret, request an access token. And i ALSO get the access token back in json.
However, when I append it like so:
'https://graph.facebook.com/v2.4/me?%s&fields=name,id,email' % token
I get the dreaded:
An active access token must be used to query information about the current user
Here's the output (... = elipsis):
short lived access token received 2Q ... 8ZD
send request for long lived access token to: https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id=1234 ... 3c8&fb_exchange_token=2Q ... 8ZD
result = h.request(url, 'GET')[1] was: {"access_token":"ABC ... MN","token_type":"bearer","expires_in":5174030}
token is now: ABC...MN
url sent for API access:https://graph.facebook.com/v2.4/me?ABC...Mn&fields=name,id,email
API JSON result: {"error":{"message":"An active access token must be used to query information about the current user.","type":"OAuthException","code":2500,"fbtrace_id":"CQ8FmaVqTnl"}}
It stems from this original code:
def fbconnect():
"""Connect to facebook."""
if request.args.get('state') != login_session['state']:
response = make_response(json.dumps('Invalid state parameter.'), 401)
response.headers['Content-Type'] = 'application/json'
return response
access_token = request.data
print "short lived access token received %s " % access_token
app_id = json.loads(open('fb_client_secrets.json', 'r').read())[
'web']['app_id']
app_secret = json.loads(
open('fb_client_secrets.json', 'r').read())['web']['app_secret']
url = 'https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id=%s&client_secret=%s&fb_exchange_token=%s' % (
app_id, app_secret, access_token)
print "send request for long lived access token to: "+url
h = httplib2.Http()
result = h.request(url, 'GET')[1]
print "result = h.request(url, 'GET')[1] was: " + result
token = json.loads(result) # h.request(url, 'GET')[0]
# print "token is now: " + token
token = token['access_token']
token = str(token)
print "token is now: " + token
# Use token to get user info from API
# userinfo_url = "https://graph.facebook.com/v2.4/me"
url = 'https://graph.facebook.com/v2.4/me?%s&fields=name,id,email' % token
h = httplib2.Http()
result = h.request(url, 'GET')[1]
print "url sent for API access:%s" % url
print "API JSON result: %s" % result
data = json.loads(result)
login_session['provider'] = 'facebook'
login_session['username'] = data["name"]
login_session['email'] = data["email"]
login_session['facebook_id'] = data["id"]

python with Quickbooks Online API v3

I need some help implementing a python app that accesses the Quickbooks API. I have successfully written several apps that use APIs, but once we get into the OAuth world, I get a bit lost.
At any rate, I found the quickbooks-python wrapper here:
https://github.com/troolee/quickbooks-python
but there are zero examples of working code showing how to implement properly. I imagine that a more experienced python programmer could figure out how to make this work without any instructions, but it seems like I'm missing the basics.
If I could get it connected, I could probably get it to work from there...
It seems like the documentation on github jumps around and for a more experienced programmer, would probably make perfect sense. But I'm just not following...
from quickbooks import *
consumerKey = "fromApiConsole"
consumerSecret = "fromApiConsole"
callbackUrl = "https://quickbooks.api.intuit.com/v3"
qbObject = QuickBooks(
consumer_key = consumerKey,
consumer_secret = consumerSecret,
callback_url = callbackUrl
)
authorize_url = qbObject.get_authorize_url() # will create a service, and further set up the qbObject.
oauth_token = request.GET['oauth_token']
oauth_verifier = request.GET['oauth_verifier']
realm_id = request.GET['realmId']
session = qbObject.get_access_tokens(oauth_verifier)
# say you want access to the reports
reportType = "ProfitAndLoss"
url = "https://quickbooks.api.intuit.com/v3/company/asdfasdfas/"
url += "reports/%s" % reportType
r = session.request( #This is just a Rauth request
"POST",
url,
header_auth = True,
realm = realm_id,
params={"format":"json"}
)
qb = QuickBooks(
consumer_key = consumerKey,
consumer_secret = consumerSecret,
access_token = qbtoken.access_token, # the stored token
access_token_secret = qbtoken.access_token_secret, # the stored secret
company_id = qbtoken.realm_id #the stored realm_id
)
qbText = str(qb.query_objects(business_object, params, query_tail))
print qbText
I am pretty sure that I am:
importing the wrong modules/classes
missing huge pieces of code to "glue together" the samples found on github
not using django here and i know the request class above is in django, but i'd really like to just make this work as a python script without using django
not getting the token/identifier/realmId from the initial authorize_url function. it prints on the screen, but i'm not sure how to grab it...
The end goal here is really just to connect and get a P&L statement from Quickbooks Online. If I can get that far, I am sure I can get the rest of what I need out of the API. I don't really need to CHANGE anything, I'm just looking to include data from the reports into some dashboards.
* UPDATE *
okay, i figured out how to get it to connect, but i'm not sure how to get to the reports.
the answer was this, which was on the prior API page:
Accessing the API
Once you've gotten a hold of your QuickBooks access tokens, you can create a QB object:
qb = QuickBooks(consumer_key = QB_OAUTH_CONSUMER_KEY,
consumer_secret = QB_OAUTH_CONSUMER_SECRET,
access_token = QB_ACCESS_TOKEN,
access_token_secret = QB_ACCESS_TOKEN_SECRET,
company_id = QB_REALM_ID
)
still trying to get the basic reports...
Okay, so here's how to make this work. I'm focused on the reports, so here's how you can get reports from Quickbooks Online API using Python:
1) Go to https://github.com/finoptimal-dev/quickbooks-python and download the code
2) Make sure you have rauth installed. If you are on AWS/EC2, simply:
sudo yum install rauth
3) Edit the quickbooks2.py file and add the following to the END:
qb = QuickBooks(consumer_key = QB_OAUTH_CONSUMER_KEY,
consumer_secret = QB_OAUTH_CONSUMER_SECRET,
access_token = QB_ACCESS_TOKEN,
access_token_secret = QB_ACCESS_TOKEN_SECRET,
company_id = QB_REALM_ID
)
4) Setup a sandbox application on the Quickbooks site here: https://developer.intuit.com/v2/ui#/app/startcreate (you will have to create a developer account if you don't already have one)
5) Once setup, you can go to the "Keys" tab of the App and grab the App Token, OAuth Consumer Key and OAuth Consumer Secret.
6) Go to the Intuit Developer Playground at https://appcenter.intuit.com/Playground/OAuth/IA and use the info from step #5 to obtain the Access Token and Access Token Secret.
7) Change the variables in Step #3 to the correct values. For QB_REALM_ID, this is the Company ID. You can get this in the sandbox by logging into https://developer.intuit.com/v2/ui#/sandbox and looking for Company ID.
7) add the following code below the code from step #3 above
print qb.get_report('ProfitAndLoss','summarize_column_by=Month&start_date=2014-01-01&end_date=2014-12-31')
I use the above dates b/c the Quickbooks Sandbox company has no Income/Expense data in 2015, so you have to pick dates in 2014.
8) IMPORTANT: To use with the Quickbooks Sandbox for reporting purposes, you need to change the get_report() function to use the base_url_v3 instead of being hard-coded to the production URL.
Look for a row in the get_report() function that looks like this:
url = "https://quickbooks.api.intuit.com/v3/company/%s/" % \
and change it to this:
url = self.base_url_v3 + "/company/%s/" % \
9) Now you can change base_url_v3 all the way at the top to this:
base_url_v3 = "https://sandbox-quickbooks.api.intuit.com/v3"
10) And now you should now be able to run:
python quickbooks2.py
You should see a bunch of JSON data from the Quickbooks Sandbox company.
11) You can explore a bit to test out the appropriate URLs here: https://developer.intuit.com/apiexplorer?apiname=V3QBO#Reports
12) The report reference is here: https://developer.intuit.com/docs/0100_accounting/0400_references/reports and this shows you which parameters you can use. To test parameters in the Explorer, you enter them in the "Request Body" section.
I struggled with this for a while and finally figured it out. Hope this helps someone else.
I do not have much experience with Python but someone had shared this code with me for oauth earlier.If you have additional questions on the code, I will not be able to answer them.
NOTE: The below code also makes calls to V2 QBO apis. Please do not use that part as it is deprecated.
See if it helps-
Import Python
from rauth import OAuth1Session, OAuth1Service
import xml.etree.ElementTree as ET
import xmltodict
class QuickBooks():
"""A wrapper class around Python's Rauth module for Quickbooks the API"""
access_token = ''
access_token_secret = ''
consumer_key = ''
consumer_secret = ''
company_id = 0
callback_url = ''
session = None
base_url_v3 = "https://quickbooks.api.intuit.com/v3"
base_url_v2 = "https://qbo.intuit.com/qbo1"
request_token_url = "https://oauth.intuit.com/oauth/v1/get_request_token"
access_token_url = "https://oauth.intuit.com/oauth/v1/get_access_token"
authorize_url = "https://appcenter.intuit.com/Connect/Begin"
# Things needed for authentication
qbService = None
request_token = ''
request_token_secret = ''
def __init__(self, **args):
if 'consumer_key' in args:
self.consumer_key = args['consumer_key']
if 'consumer_secret' in args:
self.consumer_secret = args['consumer_secret']
if 'access_token' in args:
self.access_token = args['access_token']
if 'access_token_secret' in args:
self.access_token_secret = args['access_token_secret']
if 'company_id' in args:
self.company_id = args['company_id']
if 'callback_url' in args:
self.callback_url = args['callback_url']
def get_authorize_url(self):
"""Returns the Authorize URL as returned by QB,
and specified by OAuth 1.0a.
:return URI:
"""
self.qbService = OAuth1Service(
name = None,
consumer_key = self.consumer_key,
consumer_secret = self.consumer_secret,
request_token_url = self.request_token_url,
access_token_url = self.access_token_url,
authorize_url = self.authorize_url,
base_url = None
)
self.request_token, self.request_token_secret = self.qbService.get_request_token(
params={'oauth_callback':self.callback_url}
)
return self.qbService.get_authorize_url(self.request_token)
def get_access_tokens(self, oauth_verifier):
"""Wrapper around get_auth_session, returns session, and sets
access_token and access_token_secret on the QB Object.
:param oauth_verifier: the oauth_verifier as specified by OAuth 1.0a
"""
session = self.qbService.get_auth_session(
self.request_token,
self.request_token_secret,
data={'oauth_verifier': oauth_verifier})
self.access_token = session.access_token
self.access_token_secret = session.access_token_secret
return session
def create_session(self):
if self.consumer_secret and self.consumer_key and self.access_token_secret and self.access_token:
# print "hi"
session = OAuth1Session(self.consumer_key,
self.consumer_secret,
self.access_token,
self.access_token_secret,
)
# print session
self.session = session
else:
pass
#TODO: raise an error
return self.session
def keep_trying(self, r_type, url, header_auth, realm, payload=''):
if self.session != None:
session = self.session
else:
session = self.create_session()
self.session = session
trying = True
tries = 0
while trying:
print url
tries += 1
if "v2" in url:
r = session.request(r_type, url, header_auth, realm, data=payload)
r_dict = xmltodict.parse(r.text)
# print "DICT", r_dict
if "FaultInfo" not in r_dict or tries > 4:
trying = False
else:
# url = "https://qb.sbfinance.intuit.com/v3/company/184010684/query?query=SELECT * FROM JournalEntry"
# url = "https://quickbooks.api.intuit.com/v3/company/184010684/journalentry/24772"
# url = "https://quickbooks.api.intuit.com/v3/company/184010684/query?query='SELECT+*+FROM+JournalEntry'"
# url = "https://qb.sbfinance.intuit.com/v3/company/184010684/query?query=SELECT%20%2A%20FROM%20JournalEntry&"
print url, r_type
headers = {'Accept': 'application/json'}
r = session.request(r_type, url, header_auth, realm, headers = headers)
# r.headers
print "\n\n INITIAL TEXT \n\n", r.text
print "request headers:", r.request.headers
print "request URL:", r.request.url
print "response headers:", r.headers
r_dict = r.text
if "Fault" not in r_dict or tries > 4:
trying = False
r_dict = []
return r_dict
def fetch_customer(self, pk):
if pk:
url = self.base_url_v2 + "/resource/customer/v2/%s/%s" % ( self.company_id, pk)
r_dict = self.keep_trying("GET", url, True, self.company_id)
return r_dict['Customer']
def fetch_customers(self, all=False, page_num=0, limit=10):
if self.session != None:
session = self.session
else:
session = self.create_session()
self.session = session
# We use v2 of the API, because what the fuck, v3.
url = self.base_url_v2
url += "/resource/customers/v2/%s" % (self.company_id)
customers = []
if all:
counter = 1
more = True
while more:
payload = {
"ResultsPerPage":30,
"PageNum":counter,
}
trying = True
# Because the QB API is so iffy, let's try until we get an non-error
# Rewrite this to use same code as above.
while trying:
r = session.request("POST", url, header_auth = True, data = payload, realm = self.company_id)
root = ET.fromstring(r.text)
if root[1].tag != "{http://www.intuit.com/sb/cdm/baseexceptionmodel/xsd}ErrorCode":
trying = False
else:
print "Failed"
session.close()
qb_name = "{http://www.intuit.com/sb/cdm/v2}"
for child in root:
# print child.tag, child.text
if child.tag == "{http://www.intuit.com/sb/cdm/qbo}Count":
if int(child.text) < 30:
more = False
print "Found all customers"
if child.tag == "{http://www.intuit.com/sb/cdm/qbo}CdmCollections":
for customer in child:
customers += [xmltodict.parse(ET.tostring(customer))]
counter += 1
# more = False
# print more
else:
payload = {
"ResultsPerPage":str(limit),
"PageNum":str(page_num),
}
r = session.request("POST", url, header_auth = True, data = payload, realm = self.company_id)
root = ET.fromstring(r.text)
#TODO: parse for all customers
return customers
def fetch_sales_term(self, pk):
if pk:
url = self.base_url_v2 + "/resource/sales-term/v2/%s/%s" % ( self.company_id, pk)
r_dict = self.keep_trying("GET", url, True, self.company_id)
return r_dict
def fetch_invoices(self, **args):
if "query" in args:
payload = ""
if "customer" in args['query']:
payload = {
"Filter":"CustomerId :Equals: %s" % (args['query']['customer'])
}
# while more:
url = self.base_url_v2 + "/resource/invoices/v2/%s/" % (self.company_id)
r_dict = self.keep_trying("POST", url, True, self.company_id, payload)
invoices = r_dict['qbo:SearchResults']['qbo:CdmCollections']['Invoice']
return invoices
elif "pk" in args:
# TODO: Not tested
url = self.base_url_v2 + "/resource/invoice/v2/%s/%s" % ( self.company_id, args['pk'])
r_dict = self.keep_trying("GET", url, True, self.company_id)
return r_dict
else:
url = self.base_url_v2 + "/resource/invoices/v2/%s/" % (self.company_id)
r_dict = self.keep_trying("POST", url, True, self.company_id, payload)
return "BLAH"
def fetch_journal_entries(self, **args):
""" Because of the beautiful way that journal entries are organized
with QB, you're still going to have to filter these results for the
actual entity you're interested in. Luckily it only returns the entries
that are relevant to your search
:param query: a dictionary that includes 'customer', and the QB id of the
customer
"""
if "query" in args:
payload = {}
more = True
counter = 1
journal_entries = []
if "customer" in args['query']:
payload = {
"Filter":"CustomerId :Equals: %s" % (args['query']['customer'])
}
# payload = {
# "query":"SELECT * FROM JournalEntry",
# }
while more:
payload["ResultsPerPage"] = 30
payload["PageNum"] = counter
# url = self.base_url_v2 + "/resource/journal-entries/v2/%s/" % (self.company_id)
# url = self.base_url_v3 + "/company/%s/query" % (self.company_id)
url = "https://qb.sbfinance.intuit.com/v3/company/184010684/query?query=SELECT%20%2A%20FROM%20JournalEntry&"
r_dict = self.keep_trying("GET", url, True, self.company_id, payload)
more = False
# print r_dict['qbo:SearchResults']['qbo:Count']
counter = counter + 1
# if int(r_dict['qbo:SearchResults']['qbo:Count']) < 30:
# more = False
# journal_entry_set = r_dict['qbo:SearchResults']['qbo:CdmCollections']['JournalEntry']
# journal_entries += [journal_entry_set]
return []
# return r_dict['qbo:SearchResults']['qbo:CdmCollections']['JournalEntry']
elif "pk" in args:
# TODO: Not Tested
url = self.base_url_v2 + "/resource/journal-entry/v2/%s/%s" % ( self.company_id, args['pk'])
r_dict = self.keep_trying("GET", url, True, self.company_id)
return r_dict
else:
url = self.base_url_v2 + "/resource/journal-entries/v2/%s/" % (self.company_id)
r_dict = self.keep_trying("POST", url, True, self.company_id)
print r_dict
return "BLAH"

invalid signature from fatsecret API using rauth

I have successfully followed the rauth OAuth1 examples to get my access tokens, and hence retrieve data from the fatsecret API. I store my access_token and access_token_secret in a shelve database. My problem is that I am receiving an "invalid signature" error when I try to use my stored tokens to retrieve more data later on.
Here is my original script to get tokens and retrieve the exercise_entries.get method:
from rauth.service import OAuth1Service
import shelve
api_url = 'http://platform.fatsecret.com/rest/server.api'
shelf = shelve.open('token_shelf.db')
fatsecret = OAuth1Service(
consumer_key = 'xxxxxxxxxxxxx',
consumer_secret = 'xxxxxxxxxxxxx',
name = 'fatsecret',
request_token_url = 'http://www.fatsecret.com/oauth/request_token',
access_token_url = 'http://www.fatsecret.com/oauth/access_token',
authorize_url = 'http://www.fatsecret.com/oauth/authorize')
request_token, request_token_secret = fatsecret.get_request_token(
method = 'GET',
params = {'oauth_callback':'oob'})
authorize_url = fatsecret.get_authorize_url(request_token)
print 'Visit this URL in your browser: ' + authorize_url
pin = raw_input('Enter PIN from browser: ')
shelf['fatsecret_request_token'] = request_token
shelf['fatsecret_request_token_secret'] = request_token_secret
shelf['fatsecret_pin'] = pin
session = fatsecret.get_auth_session(
request_token,
request_token_secret,
params={'oauth_verifier': pin}
)
shelf['fatsecret_access_token'] = session.access_token
shelf['fatsecret_access_token_secret'] = session.access_token_secret
my_params = {'method': 'exercise_entries.get', 'format': 'json'}
r = session.get(api_url, params=my_params)
print r.json()
print r.content
shelf.close()
I then try to restore my access_token and access_token_secret from the shelf and open a new session, but I am told I have an invalid signature.
from rauth.service import OAuth1Service
import shelve
api_url = 'http://platform.fatsecret.com/rest/server.api'
shelf = shelve.open('token_shelf.db')
fs_access_token = shelf['fatsecret_access_token']
fs_access_token_secret = shelf['fatsecret_access_token']
fatsecret = OAuth1Service(
consumer_key = 'xxxxxxxxxxxxx',
consumer_secret = 'xxxxxxxxxxxxx',
name = 'fatsecret',
request_token_url = 'http://www.fatsecret.com/oauth/request_token',
access_token_url = 'http://www.fatsecret.com/oauth/access_token',
authorize_url = 'http://www.fatsecret.com/oauth/authorize')
session = fatsecret.get_session((fs_access_token,fs_access_token_secret))
my_params = {'method': 'exercise_entries.get', 'format': 'json'}
r = session.get(api_url,params=my_params)
print r.content
print r.url
shelf.close()
This returns r.content as:
{ "error": {"code": 8, "message": "Invalid signature: oauth_signature 'ccZpSYAPSn+umkTxcAVH7EChVvw='" }}
and r.url is:
http://platform.fatsecret.com/rest/server.api?oauth_nonce=604416f368159818e3ad8252a0da323be16319a3&format=json&oauth_consumer_key=xxxxxxxxxxxxx&oauth_timestamp=1390015877&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_token=xxxxxxxxxxxxx&oauth_signature=l4Ricqpbbwl%2BHPS2ItLLnvXQo%2FA%3D&method=exercise_entries.get
The only thing that catches my eye is that the r.url parameters do not seem to be lexigraphically sorted, but I don't know if that accurately reflects what was sent to fatsecret, and anyway it worked fine in the first script.
I have tried something similar using OAuth1Session instead of OAuth1Service, but I receive exactly the same results.
I'd appreciate any help to get this working.
I checked this code countless times and couldn't find anything wrong. As I added in extra printing for debugging I noticed that I retrieved access_token twice on line 6 of my re-use session. After all that it was just a typo.
Change:
fs_access_token = shelf['fatsecret_access_token']
fs_access_token_secret = shelf['fatsecret_access_token']
To:
fs_access_token = shelf['fatsecret_access_token']
fs_access_token_secret = shelf['fatsecret_access_token_secret']
So the above code is actually a good demonstration of authenticating with the fatsecret api with python.

Categories