ebb0c60ce80715afb3e889649af30a75aa88fb0b
[hermes] / package / src / org / maemo / hermes / engine / linkedin / api.py
1 import re
2 import httplib
3 import gnome.gconf
4 from oauth import oauth
5 from xml.dom.minidom import parseString
6 from org.maemo.hermes.engine.phonenumber import PhoneNumber
7 from org.maemo.hermes.engine.friend import Friend
8
9 class LinkedInApi():
10     """LinkedIn API for Hermes.
11                 
12        Copyright (c) Fredrik Wendt <fredrik@wendt.se> 2010.
13        Copyright (c) Andrew Flegg <andrew@bleb.org> 2010.
14        Released under the Artistic Licence."""
15     
16     LI_API_URL = "https://api.linkedin.com"
17     LI_CONN_API_URL = LI_API_URL + "/v1/people/~/connections:(id,first-name,last-name,picture-url,site-standard-profile-request:(url),date-of-birth,main-address,location:(country:(code)),phone-numbers,member-url-resources)"
18     LI_PROFILE_API_URL = LI_API_URL + "/v1/people/~"
19     
20     
21     # -----------------------------------------------------------------------
22     def __init__(self, consumer, api_request):
23         """Instantiate with an OAuth consumer"""
24         self.consumer = consumer
25         self._make_api_request = api_request
26     
27
28     # -----------------------------------------------------------------------
29     def verify_verifier(self, access_token):
30         try:
31             xml = self._make_api_request(self.LI_PROFILE_API_URL)
32             dom = parseString(xml)
33             friends = self._parse_dom(dom)
34             return friends[0].get_name()
35         except Exception, e:
36             import traceback
37             traceback.print_exc()
38             raise Exception("LinkedIn authorization failed, try again")
39
40     
41     
42     # -----------------------------------------------------------------------
43     def get_friends(self):
44         """ Returns a Friend object for each LinkedIn connection."""
45         
46         xml = self._make_api_request(self.LI_CONN_API_URL)
47         dom = parseString(xml)
48         friends = self._parse_dom(dom)
49
50         return friends
51         
52
53     # -----------------------------------------------------------------------
54     def get_friend_details(self, url, header_value):
55         oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token=self.access_token, http_url=url)
56         oauth_request.sign_request(self.sig_method, self.consumer, self.access_token)
57
58         headers = oauth_request.to_header()
59         headers[u'x-li-auth-token'] = header_value
60         connection = httplib.HTTPConnection("api.linkedin.com")
61         connection.request(oauth_request.http_method, url, headers=headers)
62         data = connection.getresponse().read()
63         return data
64
65
66     # -----------------------------------------------------------------------
67     def _parse_dom(self, dom):
68         def get_first_tag(node, tagName):
69             if node:
70                 tags = node.getElementsByTagName(tagName)
71                 if tags and len(tags) > 0:
72                     return tags[0]
73         
74         def extract(node, tagName):
75             tag = get_first_tag(node, tagName)
76             if tag:
77                 return tag.firstChild.nodeValue
78             
79         def extract_public_url(node):
80             tag = get_first_tag(node, 'site-standard-profile-request')
81             if tag:
82                 url = extract(tag, 'url').replace("&amp;", "&")
83                 return re.sub('[?&](auth|trk)\w*=[^&]*', '', url)
84             
85         def extract_phone_numbers(node):
86             country = extract(get_first_tag(node, 'country'), 'code')
87             tag = get_first_tag(node, 'phone-numbers')
88             numbers = []
89             if tag:
90                 for element in tag.childNodes:
91                     if element.nodeName != 'phone-number':
92                         continue
93                      
94                     phone_type = extract(element, 'phone-type')
95                     device = phone_type == 'mobile' and phone_type or None
96                     type = phone_type in set(['home', 'work']) and phone_type or None
97                     
98                     number = PhoneNumber(extract(element, 'phone-number'), device = device, type = type, country = country)
99                     numbers.append(number)
100             return numbers
101         
102         def extract_urls(node):
103             tag = get_first_tag(node, 'member-url-resources')
104             urls = []
105             if tag:
106                 for element in tag.getElementsByTagName('url'):
107                     urls.append(element.firstChild.nodeValue.replace("&amp;", "&"))
108             return urls
109         
110         def extract_birthday(node):
111             tag = get_first_tag(node, 'date-of-birth')
112             bday = None
113             if tag:
114                 month = extract(tag, 'month')
115                 day   = extract(tag, 'day')
116                 year  = extract(tag, 'year')
117                 if month and day:
118                     bday = '%s/%s' % (extract(tag, 'month'), extract(tag, 'day'))
119                     if year:
120                         bday = '%s/%s' % (bday, year)
121                     
122             return bday
123         
124         # look for errors
125         errors = dom.getElementsByTagName('error')
126         if (errors and len(errors) > 0):
127             details = ""
128             try:
129                 details = " (" + extract(errors[0], "message") + ")"
130             except:
131                 pass
132             raise Exception("LinkedIn communication errors detected" + details)
133         
134         friends = []
135         people = dom.getElementsByTagName('person')
136         for p in people:
137             fn = extract(p, 'first-name')
138             ln = extract(p, 'last-name')
139             photo_url = extract(p, 'picture-url')
140             id = extract(p, 'id')
141             public_url = extract_public_url(p)
142             bday = extract_birthday(p)
143
144             name = fn + " " + ln
145             friend = Friend(name)
146             friend.add_url(public_url)
147             if photo_url:
148                 friend.set_photo_url(photo_url)
149                 
150             if bday:
151                 friend.set_birthday_date(bday)
152                 
153             for number in extract_phone_numbers(p):
154                 friend.add_phone(number)
155                 
156             for url in extract_urls(p):
157                 friend.add_url(url)
158             
159             friends.append(friend)
160
161         return friends