4ea03cee0bce671df85ea1397ccee2e9b7f59c3a
[hermes] / package / src / org / maemo / hermes / engine / facebook / service.py
1 import org.maemo.hermes.engine.service
2
3 from org.maemo.hermes.engine.names import canonical
4 from org.maemo.hermes.engine.friend import Friend
5
6 class Service(org.maemo.hermes.engine.service.Service):
7     """Facebook backend for Hermes.
8                 
9        Copyright (c) Andrew Flegg <andrew@bleb.org> 2010.
10        Copyright (c) Fredrik Wendt <fredrik@wendt.se> 2010.
11        Released under the Artistic Licence."""
12        
13     attrs = ['uid', 'name', 'pic_big', 'birthday_date', 'profile_url', 'first_name', 'last_name', 'website']
14
15
16     # -----------------------------------------------------------------------
17     def __init__(self, facebook, create_birthday_only = False):
18         self.fb = facebook
19         
20         self._friends_by_name = {}
21         self._friends_by_url = {}
22         self._friends_by_contact = {}
23         self._contacts_by_friend = {}
24         self._friends_without_contact = set()
25         self._known_urls = set()
26
27
28     # -----------------------------------------------------------------------
29     def get_friends(self):
30         """Returns all friends on Facebook"""
31         
32         return self._contacts_by_friend.keys()
33     
34     
35     # -----------------------------------------------------------------------
36     def get_contacts_with_match(self):
37         """Returns a dict, where each key value pair is a contact (key) that 
38            matched a friend (value)"""
39
40         return self._friends_by_contact
41     
42     
43     # -----------------------------------------------------------------------
44     def get_unmatched_friends(self):
45         """Returns a list of all friends that didn't match a contact."""
46          
47         return self._friends_by_name.values()
48
49
50     # -----------------------------------------------------------------------
51     def pre_process_contact(self, contact):
52         """Registers URLs of all previous mappings, and makes sure that any 
53            friend with such a URL don't get match by name."""
54            
55         for url in contact.get_urls():
56             self._known_urls.add(url)
57     
58     
59     # -----------------------------------------------------------------------
60     def process_friends(self):
61         """Retreives data from Facebook and parse that into Friend 
62            objects."""
63         
64         def if_defined(data, key, callback):
65             if key in data and data[key]:
66                 callback(data[key])
67         
68         friends_data = self._get_friends_data()
69         for data in friends_data:
70             key = canonical(data['name']) # FIXME: deal with name collision
71             friend = self._create_friend(data['name'])
72         
73             if 'profile_url' not in data:
74                 data['profile_url'] = "http://www.facebook.com/profile.php?id=" + str(data['uid'])
75         
76             if_defined(data, 'website', friend.add_url)
77             if_defined(data, 'profile_url', friend.add_url)
78             if_defined(data, 'birthday_date', friend.set_birthday_date)
79
80             if_defined(data, 'pic_big', friend.set_photo_url)
81             
82             if friend.has_birthday_date(): # FIXME: remove this, either you want to add your contacts or not? 
83                 self._friends_without_contact.add(friend)
84             url = data['profile_url']
85             self._friends_by_url[url] = friend
86             
87             if url not in self._known_urls:
88                 self._friends_by_name[key] = friend
89
90
91     # -----------------------------------------------------------------------
92     def process_contact(self, contact):
93         """If the contact is matched with a friend, that friend is returned,
94            otherwise None."""
95            
96         matched_friend = None
97         if self._friends_by_contact.has_key(contact):
98             matched_friend = self._friends_by_contact[contact]
99         
100         # we might get a hit if the friend has setup a URL with another service,
101         # such as putting the id link to Facebook on the Twitter account's profile
102         if not matched_friend:
103             for url in contact.get_urls():
104                 if url in self._friends_by_url:
105                     matched_friend = self._friends_by_url[url]
106                     self._register_match(contact, matched_friend)
107                     break
108
109         if not matched_friend:
110             for id in contact.get_identifiers():
111                 if id in self._friends_by_name:
112                     matched_friend = self._friends_by_name.pop(id)
113                     self._register_match(contact, matched_friend)
114                     break
115                 
116         return matched_friend
117     
118
119     # -----------------------------------------------------------------------
120     def _register_match(self, contact, friend):
121         friend.set_contact(contact)
122         self._friends_without_contact.discard(friend)
123         self._friends_by_contact[contact] = friend
124         self._contacts_by_friend[friend] = contact
125
126
127     # -----------------------------------------------------------------------
128     def _get_friends_data(self):
129         """Returns a list of dicts, where each dict represents the raw data
130            of a friend"""
131         
132         return self.fb.users.getInfo(self.fb.friends.get(), Service.attrs)