-
Notifications
You must be signed in to change notification settings - Fork 30
/
linkedin.py
178 lines (133 loc) · 6.43 KB
/
linkedin.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/usr/bin/env python
""" LinkedIn """
__author__ = 'Mike Helmick <[email protected]>'
__version__ = '0.1.5'
import urllib
try:
from urlparse import parse_qsl
except ImportError:
from cgi import parse_qsl
import oauth2 as oauth
import httplib2
try:
import simplejson as json
except ImportError:
try:
import json
except ImportError:
try:
from django.utils import simplejson as json
except ImportError:
raise ImportError('A json library is required to use this python library. Lol, yay for being verbose. ;)')
class LinkedinAPIError(Exception):
def __init__(self, message, code=None):
self.message = message
self.code = code
def __str__(self):
return repr(self.message)
class LinkedinAuthError(LinkedinAPIError): pass
class LinkedinAPI(object):
def __init__(self, api_key=None, api_secret=None, oauth_token=None, oauth_token_secret=None, headers=None, client_args=None, callback_url=None, permissions=None):
self.api_key = api_key
self.api_secret = api_secret
self.oauth_token = oauth_token
self.oauth_secret = oauth_token_secret
self.callback_url = callback_url
self.permissions = permissions
# Authentication URLs
self.request_token_url = 'https://api.linkedin.com/uas/oauth/requestToken'
self.access_token_url = 'https://api.linkedin.com/uas/oauth/accessToken'
# Authentication page in http://developer.linkedin.com/documents/authentication states that
# endpoint is the following not the previous url used.
self.authorize_url = 'https://api.linkedin.com/uas/oauth/authenticate'
if self.callback_url:
self.request_token_url = '%s?oauth_callback=%s' % (self.request_token_url, self.callback_url)
if self.permissions:
delimiter = "&" if self.callback_url else "?"
if type(self.permissions) is list:
permissions = "+".join(self.permissions)
else:
permissions = self.permissions
self.request_token_url = '%s%sscope=%s' % (self.request_token_url, delimiter, permissions)
self.api_base = 'http://api.linkedin.com'
self.api_version = 'v1'
self.api_url = '%s/%s/' % (self.api_base, self.api_version)
# If there's headers, set them. If not, lets
self.headers = headers
if self.headers is None:
self.headers = {'User-agent': 'Linkedin %s' % __version__}
# ALL requests will be json. Enforcing it here...
self.headers.update({'x-li-format': 'json',
'Content-Type': 'application/json'})
self.consumer = None
self.token = None
client_args = client_args or {}
# See if they're authenticating for the first or if they already have some tokens.
# http://michaelhelmick.com/tokens.jpg
if self.api_key is not None and self.api_secret is not None:
self.consumer = oauth.Consumer(key=self.api_key, secret=self.api_secret)
if self.oauth_token is not None and self.oauth_secret is not None:
self.token = oauth.Token(key=oauth_token, secret=oauth_token_secret)
if self.consumer is not None and self.token is not None:
# Authenticated
self.client = oauth.Client(self.consumer, self.token, **client_args)
elif self.consumer is not None:
# Authenticating
self.client = oauth.Client(self.consumer, **client_args)
else:
# Unauthenticated requests (for LinkedIn calls available to public)
self.client = httplib2.Http(**client_args)
def get_authentication_tokens(self):
""" So, you want to get an authentication url?
l = LinkedinAPI(YOUR_CONFIG)
auth_props = l.get_authentication_tokens()
auth_url = auth_props['auth_url']
print auth_url
"""
resp, content = self.client.request(self.request_token_url, 'POST')
status = int(resp['status'])
if status != 200:
raise LinkedinAuthError('There was a problem authenticating you. Error: %s, Message: %s' % (status, content))
request_tokens = dict(parse_qsl(content))
auth_url_params = {
'oauth_token': request_tokens['oauth_token'],
}
request_tokens['auth_url'] = self.authorize_url + '?' + urllib.urlencode(auth_url_params)
return request_tokens
def get_access_token(self, oauth_verifier):
""" After being returned from the callback, call this.
l = LinkedinAPI(YOUR_CONFIG)
authorized_tokens = l.get_access_token(oauth_verifier)
oauth_token = authorized_tokens['oauth_token']
oauth_token_secret = authorized_tokens['oauth_token_secret']
"""
resp, content = self.client.request('%s?oauth_verifier=%s' % (self.access_token_url, oauth_verifier), 'POST')
return dict(parse_qsl(content))
def api_request(self, endpoint, method='GET', fields='', params={}):
url = self.api_url + endpoint
if fields:
url = '%s:(%s)' % (url, fields)
if method == 'POST':
resp, content = self.client.request(url, 'POST', body=json.dumps(params), headers=self.headers)
# As far as I've seen, all POSTs return a 201 and NO body -.-
# So, we'll just return true if it's a post and returns 201
# This will catch a successful post, but continue and throw
# an error if it wasn't successful.
if 'status' in resp and int(resp['status']) == 201:
return True
else:
resp, content = self.client.request('%s?%s' % (url, urllib.urlencode(params)), 'GET', headers=self.headers)
try:
content = json.loads(content)
except json.JSONDecodeError:
raise LinkedinAPIError('Content is not valid JSON, unable to be decoded.')
status = int(resp['status'])
if status < 200 or status >= 300:
raise LinkedinAPIError('Error Code: %d, Message: %s' % (status, content['message']), status)
return content
def get(self, endpoint, fields='', params=None):
params = params or {}
return self.api_request(endpoint, fields=fields, params=params)
def post(self, endpoint, fields='', params=None):
params = params or {}
return self.api_request(endpoint, method='POST', fields=fields, params=params)