32
32
THE SOFTWARE.
33
33
"""
34
34
35
- import random
36
- import time
37
35
import urllib
38
36
import urllib2
39
- import urlparse
37
+ import StringIO
40
38
41
39
try :
42
40
import simplejson
43
41
except ImportError :
44
42
# Have django or are running in the Google App Engine?
45
43
from django .utils import simplejson
46
44
47
- VERSION = '1.0 '
45
+ VERSION = '1.1 '
48
46
49
47
class Error (RuntimeError ):
50
48
"""Generic exception class."""
@@ -70,23 +68,26 @@ class Client(object):
70
68
71
69
def __init__ (self , client_id , client_secret , access_token = None ,
72
70
refresh_token = None , timeout = None ):
73
-
74
71
if not client_id or not client_secret :
75
72
raise ValueError ("Client_id and client_secret must be set." )
76
-
77
73
self .client_id = client_id
78
74
self .client_secret = client_secret
79
75
self .timeout = timeout
80
76
self .access_token = access_token
81
77
self .refresh_token = refresh_token
78
+ self ._authorization_redirect_uri = None
82
79
83
80
def authorization_url (self , auth_uri = None , redirect_uri = None , scope = None , state = None ,
84
81
access_type = 'offline' , approval_prompt = None ):
85
82
""" Get the URL to redirect the user for client authorization """
86
83
if redirect_uri is None :
87
84
redirect_uri = self .redirect_uri
85
+ if redirect_uri :
86
+ self ._authorization_redirect_uri = redirect_uri
88
87
if auth_uri is None :
89
88
auth_uri = self .auth_uri
89
+ if not auth_uri :
90
+ raise ValueError ("an auth_uri is required" )
90
91
if scope is None :
91
92
scope = self .scope
92
93
@@ -111,12 +112,12 @@ def authorization_url(self, auth_uri=None, redirect_uri=None, scope=None, state=
111
112
112
113
def redeem_code (self , refresh_uri = None , redirect_uri = None , code = None , scope = None ):
113
114
"""Get an access token from the supplied code """
114
-
115
- # prepare required args
116
115
if code is None :
117
- raise ValueError ("Code must be set." )
116
+ raise ValueError ("Code must be set. see see http://tools.ietf.org/html/draft-ietf-oauth-v2-20#section-4.1.3 " )
118
117
if redirect_uri is None :
119
118
redirect_uri = self .redirect_uri
119
+ if self ._authorization_redirect_uri and redirect_uri != self ._authorization_redirect_uri :
120
+ raise ValueError ("redirect_uri mismatch. see http://tools.ietf.org/html/draft-ietf-oauth-v2-20#section-4.1.3" )
120
121
if refresh_uri is None :
121
122
refresh_uri = self .refresh_uri
122
123
if scope is None :
@@ -126,10 +127,10 @@ def redeem_code(self, refresh_uri=None, redirect_uri=None, code=None, scope=None
126
127
'client_id' : self .client_id ,
127
128
'client_secret' : self .client_secret ,
128
129
'code' : code ,
129
- 'redirect_uri' : redirect_uri ,
130
130
'grant_type' : 'authorization_code' ,
131
131
}
132
-
132
+ if redirect_uri is not None :
133
+ data ['redirect_uri' ] = redirect_uri
133
134
if scope is not None :
134
135
data ['scope' ] = scope
135
136
body = urllib .urlencode (data )
@@ -225,6 +226,8 @@ def request(self, uri, body, headers, method='GET'):
225
226
raise ValueError (response .read ())
226
227
227
228
def handle_rate_limit (self ):
229
+ import random
230
+ import time
228
231
time .sleep (1 + random .random () * 3 )
229
232
230
233
@@ -252,6 +255,44 @@ def stats(self, short_url):
252
255
return self .request (stat_url , None , headers )
253
256
254
257
258
+ class BufferAPI (GooglAPI ):
259
+ auth_uri = 'https://bufferapp.com/oauth2/authorize'
260
+ refresh_uri = 'https://api.bufferapp.com/1/oauth2/token.json'
261
+ scope = None
262
+ service = 'buffer'
263
+ data_uri = 'https://api.bufferapp.com/1/'
264
+
265
+ def authorization_url (self , ** kwargs ):
266
+ # Buffer doesn't use access_type
267
+ kwargs ['access_type' ] = None
268
+ return super (BufferAPI , self ).authorization_url (** kwargs )
269
+
270
+ def get_profiles (self ):
271
+ url = self .data_uri + 'profiles.json'
272
+ headers = {'Content-Type' : 'application/json' }
273
+ return self .request (url , None , headers )
274
+
275
+ def get_info (self ):
276
+ url = self .data_uri + 'info/configuration.json'
277
+ headers = {'Content-Type' : 'application/json' }
278
+ return self .request (url , None , headers )
279
+
280
+ def get_pending (self , profile_id ):
281
+ url = self .data_uri + 'profiles/%s/updates/pending.json' % profile_id
282
+ headers = {'Content-Type' : 'application/json' }
283
+ return self .request (url , None , headers )
284
+
285
+ def post_update (self , profile_ids , message ):
286
+ url = self .data_uri + 'updates/create.json'
287
+ import urllib
288
+ data = [('text' , urllib .urlencode (message )), ('shorten' , 1 )]
289
+ for pid in profile_ids :
290
+ data .append (('profile_ids[]' , pid ))
291
+ body = urllib .urlencode (data )
292
+ headers = {'Content-type' : 'application/x-www-form-urlencoded' }
293
+ return self .request (url , body , headers )
294
+
295
+
255
296
class GAnalyticsAPI (GooglAPI ):
256
297
# OAuth API
257
298
refresh_uri = 'https://accounts.google.com/o/oauth2/token'
@@ -305,40 +346,3 @@ def list(self, uid, count):
305
346
headers = {'Content-Type' : 'application/json' }
306
347
data = self .request (url , None , headers )
307
348
return data
308
-
309
-
310
- class BufferAPI (GooglAPI ):
311
- auth_uri = 'https://bufferapp.com/oauth2/authorize'
312
- refresh_uri = 'https://api.bufferapp.com/1/oauth2/token.json'
313
- scope = None
314
- service = 'buffer'
315
- data_uri = 'https://api.bufferapp.com/1/'
316
-
317
- def refresh_access_token (self , refresh_uri = None , refresh_token = None , grant_type = 'authorization_code' ):
318
- # Buffer wants a different grant_type than Google
319
- return super (BufferAPI , self ).refresh_access_token (refresh_uri = refresh_uri , refresh_token = refresh_token , grant_type = grant_type )
320
-
321
- # data API
322
- def get_profiles (self ):
323
- url = self .data_uri + 'profiles.json'
324
- headers = {'Content-Type' : 'application/json' }
325
- return self .request (url , None , headers )
326
-
327
- def get_info (self ):
328
- url = self .data_uri + 'info/configuration.json'
329
- headers = {'Content-Type' : 'application/json' }
330
- return self .request (url , None , headers )
331
-
332
- def get_pending (profile_id ):
333
- url = self .data_uri + 'profiles/%s/updates/pending.json' % profile_id
334
- headers = {'Content-Type' : 'application/json' }
335
- return self .request (url , None , headers )
336
-
337
- def post_update (profile_ids , message ):
338
- url = self .data_uri + 'updates/create.json' % profile_id
339
- import urllib
340
- data = [('text' , urllib .urlencode (message )), ('shorten' , 1 )]
341
- for pid in profile_ids :
342
- data .append (('profile_ids[]' , pid ))
343
- body = urllib .urlencode (data )
344
- return self .request (url , body , headers )
0 commit comments