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 api_key = self._gc.get_string('/apps/maemo/hermes/linkedin_key')
33 secret_key = self._gc.get_string('/apps/maemo/hermes/linkedin_secret')
35 if api_key is None or secret_key is None:
36 raise Exception('No LinkedIn application keys found. Installation error.')
38 self.access_token = self._get_access_token_from_gconf()
40 self.consumer = oauth.OAuthConsumer(api_key, secret_key)
41 self.sig_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
43 # IMPROVEMENT: verify that the access_token is valid for at least another hour
44 self._verify_access_token()
47 # -----------------------------------------------------------------------
48 def authenticate(self, need_auth, block_for_auth):
50 token = self._get_request_token()
51 url = self._get_authorize_url(token)
52 verifier = block_for_auth(True)
53 self._verify_verifier(verifier)
56 # -----------------------------------------------------------------------
57 def get_friends(self):
58 """ Returns a Friend object for each LinkedIn connection."""
60 xml = self._make_api_request(self.LI_CONN_API_URL)
61 dom = parseString(xml)
62 friends = self._parse_dom(dom)
67 # -----------------------------------------------------------------------
68 def _verify_verifier(self, verifier):
70 self.access_token = self._get_access_token(self.request_token, verifier)
71 self._store_access_token_in_gconf()
73 raise Exception("authorization failed, try again")
76 # -----------------------------------------------------------------------
77 def _verify_access_token(self):
81 # -----------------------------------------------------------------------
82 def _store_access_token_in_gconf(self, token_str):
83 self._gc.set_string('/apps/maemo/hermes/linkedin_access_token', token_str)
86 # -----------------------------------------------------------------------
87 def _get_access_token_from_gconf(self):
88 token_str = self._gc.get_string('/apps/maemo/hermes/linkedin_access_token')
89 return oauth.OAuthToken.from_string(token_str)
92 # -----------------------------------------------------------------------
93 def _make_api_request(self, url):
94 print "_make_api_request", url
95 oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token=self.access_token, http_url=url)
96 oauth_request.sign_request(self.sig_method, self.consumer, self.access_token)
97 connection = httplib.HTTPSConnection(self.LI_SERVER)
99 connection.request(oauth_request.http_method, url, headers=oauth_request.to_header())
100 return connection.getresponse().read()
102 raise Exception("Failed to contact LinkedIn at " + url)
105 # -----------------------------------------------------------------------
106 def _parse_dom(self, dom):
107 print "parse_dom", dom
108 def get_first_tag(node, tagName):
109 tags = node.getElementsByTagName(tagName)
110 if tags and len(tags) > 0:
113 def extract(node, tagName):
114 tag = get_first_tag(node, tagName)
116 return tag.firstChild.nodeValue
118 def extract_public_url(node):
119 tag = get_first_tag(node, 'site-standard-profile-request')
121 url = extract(tag, 'url')
122 return url.replace("&", "&")
125 errors = dom.getElementsByTagName('error')
126 if (len(errors) > 0):
127 print "Error" # FIXME: handle this better
131 people = dom.getElementsByTagName('person')
134 fn = extract(p, 'first-name')
135 ln = extract(p, 'last-name')
136 photo_url = extract(p, 'picture-url')
137 id = extract(p, 'id')
138 public_url = extract_public_url(p)
141 friend = Friend(name)
142 friend.add_url(public_url)
144 friend.set_photo_url(photo_url)
146 friends.append(friend)
152 # -----------------------------------------------------------------------
153 def _get_access_token(self, token, verifier):
154 """If the verifier (which was displayed in the browser window) is valid,
155 then an access token is returned which should be used to access data on the service."""
157 oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token=token, verifier=verifier, http_url=self.ACCESS_TOKEN_URL)
158 oauth_request.sign_request(self.sig_method, self.consumer, token)
160 connection = httplib.HTTPSConnection(self.LI_SERVER)
161 connection.request(oauth_request.http_method, self.ACCESS_TOKEN_URL, headers=oauth_request.to_header())
162 response = connection.getresponse()
163 token_str = response.read()
164 self._store_access_token_in_gconf(token_str)
165 return oauth.OAuthToken.from_string(token_str)
168 # -----------------------------------------------------------------------
169 def _get_authorize_url(self, token):
170 """The URL that the user should browse to, in order to authorize the application to acess data"""
172 oauth_request = oauth.OAuthRequest.from_token_and_callback(token=token, http_url=self.AUTHORIZE_URL)
173 return oauth_request.to_url()
176 # -----------------------------------------------------------------------
177 def _get_request_token(self):
178 """Get a request token from LinkedIn"""
180 oauth_consumer_key = self.api_key
181 oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, callback="oob", http_url=self.REQUEST_TOKEN_URL)
182 oauth_request.sign_request(self.sig_method, self.consumer, None)
184 connection = httplib.HTTPSConnection(self.LI_SERVER)
185 connection.request(oauth_request.http_method, self.REQUEST_TOKEN_URL, headers=oauth_request.to_header())
186 response = self.connection.getresponse().read()
188 token = oauth.OAuthToken.from_string(response)