3 from oauth import oauth
4 from xml.dom.minidom import parseString
5 from org.maemo.hermes.engine.friend import Friend
7 # httplib.HTTPSConnection.debuglevel = 1
10 """LinkedIn API for Hermes.
12 Copyright (c) Fredrik Wendt <fredrik@wendt.se> 2010.
13 Released under the Artistic Licence."""
16 LI_SERVER = "api.linkedin.com"
17 LI_API_URL = "https://api.linkedin.com"
18 LI_CONN_API_URL = LI_API_URL + "/v1/people/~/connections"
20 REQUEST_TOKEN_URL = LI_API_URL + "/uas/oauth/requestToken"
21 AUTHORIZE_URL = LI_API_URL + "/uas/oauth/authorize"
22 ACCESS_TOKEN_URL = LI_API_URL + "/uas/oauth/accessToken"
25 # -----------------------------------------------------------------------
27 """Initialize the LinkedIn service, finding LinkedIn API keys in gconf and
28 having a gui_callback available."""
30 self._gc = gnome.gconf.client_get_default()
32 # -- Check the environment is going to work...
34 if (self._gc.get_string('/desktop/gnome/url-handlers/http/command') == 'epiphany %s'):
35 raise Exception('Browser in gconf invalid (see NB#136012). Installation error.')
37 api_key = self._gc.get_string('/apps/maemo/hermes/linkedin_api_key')
38 secret_key = self._gc.get_string('/apps/maemo/hermes/linkedin_key_secret')
40 # FIXME: move this to gconf and postinst
41 api_key = '1et4G-VtmtqNfY7gF8PHtxMOf0KNWl9ericlTEtdKJeoA4ubk4wEQwf8lSL8AnYE'
42 secret_key = 'uk--OtmWcxER-Yh6Py5p0VeLPNlDJSMaXj1xfHILoFzrK7fM9eepNo5RbwGdkRo_'
44 if api_key is None or secret_key is None:
45 raise Exception('No LinkedIn application keys found. Installation error.')
47 self.access_token = self._get_access_token_from_gconf()
49 self.consumer = oauth.OAuthConsumer(api_key, secret_key)
50 self.sig_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
52 # IMPROVEMENT: verify that the access_token is valid for at least another hour
53 self._verify_access_token()
56 def authenticate(self, need_auth, block_for_auth):
58 token = self._get_request_token()
59 url = self._get_authorize_url(token)
60 verifier = block_for_auth(url)
61 self._verify_verifier(verifier)
64 # -----------------------------------------------------------------------
65 def get_friends(self):
66 """ Returns a Friend object for each LinkedIn connection."""
68 xml = self._make_api_request(self.LI_CONN_API_URL)
69 dom = parseString(xml)
70 friends = self._parse_dom(dom)
75 # -----------------------------------------------------------------------
76 def _verify_verifier(self, verifier):
78 self.access_token = self._get_access_token(self.request_token, verifier)
79 self._store_access_token_in_gconf()
81 raise Exception("authorization failed, try again")
84 # -----------------------------------------------------------------------
85 def _verify_access_token(self):
89 # -----------------------------------------------------------------------
90 def _store_access_token_in_gconf(self, token_str):
91 self._gc.set_string('/apps/maemo/hermes/linkedin_access_token', token_str)
94 # -----------------------------------------------------------------------
95 def _get_access_token_from_gconf(self):
96 token_str = self._gc.get_string('/apps/maemo/hermes/linkedin_access_token')
97 return oauth.OAuthToken.from_string(token_str)
100 # -----------------------------------------------------------------------
101 def _make_api_request(self, url):
102 print "_make_api_request", url
103 oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token=self.access_token, http_url=url)
104 oauth_request.sign_request(self.sig_method, self.consumer, self.access_token)
105 connection = httplib.HTTPSConnection(self.LI_SERVER)
107 connection.request(oauth_request.http_method, url, headers=oauth_request.to_header())
108 return connection.getresponse().read()
110 raise Exception("Failed to contact LinkedIn at " + url)
113 # -----------------------------------------------------------------------
114 def _parse_dom(self, dom):
115 print "parse_dom", dom
116 def get_first_tag(node, tagName):
117 tags = node.getElementsByTagName(tagName)
118 if tags and len(tags) > 0:
121 def extract(node, tagName):
122 tag = get_first_tag(node, tagName)
124 return tag.firstChild.nodeValue
126 def extract_public_url(node):
127 tag = get_first_tag(node, 'site-standard-profile-request')
129 url = extract(tag, 'url')
130 return url.replace("&", "&")
133 errors = dom.getElementsByTagName('error')
134 if (len(errors) > 0):
135 print "Error" # FIXME: handle this better
139 people = dom.getElementsByTagName('person')
142 fn = extract(p, 'first-name')
143 ln = extract(p, 'last-name')
144 photo_url = extract(p, 'picture-url')
145 id = extract(p, 'id')
146 public_url = extract_public_url(p)
149 friend = Friend(name)
150 friend.add_url(public_url)
152 friend.set_photo_url(photo_url)
154 friends.append(friend)
160 # -----------------------------------------------------------------------
161 def _get_access_token(self, token, verifier):
162 """If the verifier (which was displayed in the browser window) is valid,
163 then an access token is returned which should be used to access data on the service."""
165 oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token=token, verifier=verifier, http_url=self.ACCESS_TOKEN_URL)
166 oauth_request.sign_request(self.sig_method, self.consumer, token)
168 connection = httplib.HTTPSConnection(self.LI_SERVER)
169 connection.request(oauth_request.http_method, self.ACCESS_TOKEN_URL, headers=oauth_request.to_header())
170 response = connection.getresponse()
171 token_str = response.read()
172 self._store_access_token_in_gconf(token_str)
173 return oauth.OAuthToken.from_string(token_str)
176 # -----------------------------------------------------------------------
177 def _get_authorize_url(self, token):
178 """The URL that the user should browse to, in order to authorize the application to acess data"""
180 oauth_request = oauth.OAuthRequest.from_token_and_callback(token=token, http_url=self.AUTHORIZE_URL)
181 return oauth_request.to_url()
184 # -----------------------------------------------------------------------
185 def _get_request_token(self):
186 """Get a request token from LinkedIn"""
188 oauth_consumer_key = self.api_key
189 oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, callback="oob", http_url=self.REQUEST_TOKEN_URL)
190 oauth_request.sign_request(self.sig_method, self.consumer, None)
192 connection = httplib.HTTPSConnection(self.LI_SERVER)
193 connection.request(oauth_request.http_method, self.REQUEST_TOKEN_URL, headers=oauth_request.to_header())
194 response = self.connection.getresponse().read()
196 token = oauth.OAuthToken.from_string(response)