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 def authenticate(self, need_auth, block_for_auth):
49 token = self._get_request_token()
50 url = self._get_authorize_url(token)
51 verifier = block_for_auth(url)
52 self._verify_verifier(verifier)
55 # -----------------------------------------------------------------------
56 def get_friends(self):
57 """ Returns a Friend object for each LinkedIn connection."""
59 xml = self._make_api_request(self.LI_CONN_API_URL)
60 dom = parseString(xml)
61 friends = self._parse_dom(dom)
66 # -----------------------------------------------------------------------
67 def _verify_verifier(self, verifier):
69 self.access_token = self._get_access_token(self.request_token, verifier)
70 self._store_access_token_in_gconf()
72 raise Exception("authorization failed, try again")
75 # -----------------------------------------------------------------------
76 def _verify_access_token(self):
80 # -----------------------------------------------------------------------
81 def _store_access_token_in_gconf(self, token_str):
82 self._gc.set_string('/apps/maemo/hermes/linkedin_access_token', token_str)
85 # -----------------------------------------------------------------------
86 def _get_access_token_from_gconf(self):
87 token_str = self._gc.get_string('/apps/maemo/hermes/linkedin_access_token')
88 return oauth.OAuthToken.from_string(token_str)
91 # -----------------------------------------------------------------------
92 def _make_api_request(self, url):
93 print "_make_api_request", url
94 oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token=self.access_token, http_url=url)
95 oauth_request.sign_request(self.sig_method, self.consumer, self.access_token)
96 connection = httplib.HTTPSConnection(self.LI_SERVER)
98 connection.request(oauth_request.http_method, url, headers=oauth_request.to_header())
99 return connection.getresponse().read()
101 raise Exception("Failed to contact LinkedIn at " + url)
104 # -----------------------------------------------------------------------
105 def _parse_dom(self, dom):
106 print "parse_dom", dom
107 def get_first_tag(node, tagName):
108 tags = node.getElementsByTagName(tagName)
109 if tags and len(tags) > 0:
112 def extract(node, tagName):
113 tag = get_first_tag(node, tagName)
115 return tag.firstChild.nodeValue
117 def extract_public_url(node):
118 tag = get_first_tag(node, 'site-standard-profile-request')
120 url = extract(tag, 'url')
121 return url.replace("&", "&")
124 errors = dom.getElementsByTagName('error')
125 if (len(errors) > 0):
126 print "Error" # FIXME: handle this better
130 people = dom.getElementsByTagName('person')
133 fn = extract(p, 'first-name')
134 ln = extract(p, 'last-name')
135 photo_url = extract(p, 'picture-url')
136 id = extract(p, 'id')
137 public_url = extract_public_url(p)
140 friend = Friend(name)
141 friend.add_url(public_url)
143 friend.set_photo_url(photo_url)
145 friends.append(friend)
151 # -----------------------------------------------------------------------
152 def _get_access_token(self, token, verifier):
153 """If the verifier (which was displayed in the browser window) is valid,
154 then an access token is returned which should be used to access data on the service."""
156 oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token=token, verifier=verifier, http_url=self.ACCESS_TOKEN_URL)
157 oauth_request.sign_request(self.sig_method, self.consumer, token)
159 connection = httplib.HTTPSConnection(self.LI_SERVER)
160 connection.request(oauth_request.http_method, self.ACCESS_TOKEN_URL, headers=oauth_request.to_header())
161 response = connection.getresponse()
162 token_str = response.read()
163 self._store_access_token_in_gconf(token_str)
164 return oauth.OAuthToken.from_string(token_str)
167 # -----------------------------------------------------------------------
168 def _get_authorize_url(self, token):
169 """The URL that the user should browse to, in order to authorize the application to acess data"""
171 oauth_request = oauth.OAuthRequest.from_token_and_callback(token=token, http_url=self.AUTHORIZE_URL)
172 return oauth_request.to_url()
175 # -----------------------------------------------------------------------
176 def _get_request_token(self):
177 """Get a request token from LinkedIn"""
179 oauth_consumer_key = self.api_key
180 oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, callback="oob", http_url=self.REQUEST_TOKEN_URL)
181 oauth_request.sign_request(self.sig_method, self.consumer, None)
183 connection = httplib.HTTPSConnection(self.LI_SERVER)
184 connection.request(oauth_request.http_method, self.REQUEST_TOKEN_URL, headers=oauth_request.to_header())
185 response = self.connection.getresponse().read()
187 token = oauth.OAuthToken.from_string(response)