Improve message about credential expiry
[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, service_id, facebook, create_birthday_only = False):
18         self.fb = facebook
19         self._service_id = service_id
20         self._create_birthday_only = create_birthday_only
21         
22         self._friends_by_name = {}
23         self._friends_by_url = {}
24         self._friends_by_contact = {}
25         self._contacts_by_friend = {}
26         self._friends_without_contact = set()
27         self._known_urls = set()
28
29
30     # -----------------------------------------------------------------------
31     def get_friends_to_create_contacts_for(self):
32         friends = []
33         if self._create_birthday_only:
34             for friend in self._friends_without_contact:
35                 if friend.is_interesting():
36                     friends.append(friend)
37                     
38         return friends
39     
40     
41     # -----------------------------------------------------------------------
42     def get_friends(self):
43         """Returns all friends on Facebook"""
44         
45         return self._friends_by_url.values()
46     
47     
48     # -----------------------------------------------------------------------
49     def get_contacts_with_match(self):
50         """Returns a dict, where each key value pair is a contact (key) that 
51            matched a friend (value)"""
52
53         return self._friends_by_contact
54     
55     
56     # -----------------------------------------------------------------------
57     def get_unmatched_friends(self):
58         """Returns a list of all friends that didn't match a contact."""
59          
60         return self._friends_without_contact
61
62
63     # -----------------------------------------------------------------------
64     def pre_process_contact(self, contact):
65         """Registers URLs of all previous mappings, and makes sure that any 
66            friend with such a URL don't get match by name."""
67            
68         for url in contact.get_urls():
69             self._known_urls.add(url)
70     
71     
72     # -----------------------------------------------------------------------
73     def process_friends(self):
74         """Retreives data from Facebook and parse that into Friend 
75            objects."""
76         
77         def if_defined(data, key, callback):
78             if key in data and data[key]:
79                 callback(data[key])
80         
81         try:
82             friends_data = self.fb.get_friends()
83             for data in friends_data:
84                 friend = Friend(data['name'])
85             
86                 if 'link' not in data:
87                     data['link'] = "http://www.facebook.com/profile.php?id=" + str(data['id'])
88             
89                 if_defined(data, 'website', friend.add_url)
90                 if_defined(data, 'link', friend.add_url)
91                 if_defined(data, 'birthday', friend.set_birthday_date)
92     
93                 if_defined(data, 'picture', friend.set_photo_url)
94                 
95                 url = data['link']
96                 friend.add_url(url)
97                 self._register_friend(friend)
98         except Exception, e:
99             if e.message == 'Unauthorised':
100                 raise org.maemo.hermes.engine.service.CredentialsExpiredException('Facebook')
101             else:
102                 raise e
103
104     # -----------------------------------------------------------------------
105     def process_contact(self, contact):
106         """If the contact is matched with a friend, that friend is returned,
107            otherwise None."""
108            
109         matched_friend = None
110         if self._friends_by_contact.has_key(contact):
111             matched_friend = self._friends_by_contact[contact]
112         
113         # we might get a hit if the friend has setup a URL with another service,
114         # such as putting the id link to Facebook on the Twitter account's profile
115         if not matched_friend:
116             for url in contact.get_urls():
117                 if url in self._friends_by_url:
118                     matched_friend = self._friends_by_url[url]
119                     self._register_match(contact, matched_friend)
120                     break
121
122         if not matched_friend:
123             for id in contact.get_identifiers():
124                 if id in self._friends_by_name:
125                     matched_friend = self._friends_by_name.pop(id)
126                     self._register_match(contact, matched_friend)
127                     break
128                 
129         return matched_friend
130     
131
132     # -----------------------------------------------------------------------
133     def _register_friend(self, friend):
134         self._friends_without_contact.add(friend)
135         
136         for url in friend.get_urls():
137             if self.is_profile_url(url):
138                 self._friends_by_url[url] = friend
139
140         if self._allow_friend_to_match_by_name(friend):
141             key = canonical(friend.get_name())
142             self._friends_by_name[key] = friend
143
144
145     # -----------------------------------------------------------------------
146     def is_profile_url(self, url):
147         """Return True if this is a URL for this service."""
148
149         return url and "facebook.com" in url
150
151
152     # -----------------------------------------------------------------------
153     def _allow_friend_to_match_by_name(self, friend):
154         for url in friend.get_urls():
155             if url in self._known_urls:
156                 return False
157         return True
158
159
160     # -----------------------------------------------------------------------
161     def _register_match(self, contact, friend):
162         friend.set_contact(contact)
163         self._friends_without_contact.discard(friend)
164         self._friends_by_contact[contact] = friend
165         self._contacts_by_friend[friend] = contact