First pass of new structure. test.py is the only entrypoint which works as of this...
[hermes] / package / src / org / maemo / hermes / engine / facebook / service.py
1 import gnome.gconf
2 import org.maemo.hermes.engine.service
3
4 from facebook import Facebook
5 from org.maemo.hermes.engine.names import canonical
6
7 class Service(org.maemo.hermes.engine.service.Service):
8     """Facebook backend for Hermes.
9                 
10        This requires two gconf paths to contain Facebook application keys:
11            /apps/maemo/hermes/key_app
12            /apps/maemo/hermes/key_secret
13        
14        Copyright (c) Andrew Flegg <andrew@bleb.org> 2010.
15        Released under the Artistic Licence."""
16        
17        
18     # -----------------------------------------------------------------------
19     def __init__(self, autocreate = False, gui_callback = None):
20         """Initialise the Facebook service, finding Facebook API keys in gconf and
21            having a gui_callback available."""
22         
23         self._gc  = gnome.gconf.client_get_default()
24         self._gui = gui_callback
25         self._autocreate = autocreate
26         
27         # -- Check the environment is going to work...
28         #
29         if (self._gc.get_string('/desktop/gnome/url-handlers/http/command') == 'epiphany %s'):
30             raise Exception('Browser in gconf invalid (see NB#136012). Installation error.')
31
32         key_app    = self._gc.get_string('/apps/maemo/hermes/key_app')
33         key_secret = self._gc.get_string('/apps/maemo/hermes/key_secret')
34         if key_app is None or key_secret is None:
35             raise Exception('No Facebook application keys found. Installation error.')
36
37         self.fb = Facebook(key_app, key_secret)
38         self.fb.desktop = True
39         
40         self._friends = None
41         self._friends_by_url = {}
42         self._should_create = set()
43
44
45     # -----------------------------------------------------------------------
46     def _do_fb_login(self):
47         """Perform authentication against Facebook and store the result in gconf
48              for later use. Uses the 'need_auth' and 'block_for_auth' methods on
49              the callback class. The former allows a message to warn the user
50              about what is about to happen to be shown; the second is to wait
51              for the user to confirm they have logged in."""
52         self.fb.session_key = None
53         self.fb.secret = None
54         self.fb.uid = None
55         
56         if self._gui:
57             self._gui.need_auth()
58             
59         self.fb.auth.createToken()
60         self.fb.login()
61         
62         if self._gui:
63             self._gui.block_for_auth()
64           
65         session = self.fb.auth.getSession()
66         self._gc.set_string('/apps/maemo/hermes/session_key', session['session_key'])
67         self._gc.set_string('/apps/maemo/hermes/secret_key', session['secret'])
68         self._gc.set_string('/apps/maemo/hermes/uid', str(session['uid']))
69
70    
71     # -----------------------------------------------------------------------
72     def get_friends(self):
73         """Return a list of friends from this service, or 'None' if manual mapping
74            is not supported."""
75            
76         if self._friends:
77             return self._friends.values()
78          
79         if self.fb.session_key is None:
80             self.fb.session_key = self._gc.get_string('/apps/maemo/hermes/session_key')
81             self.fb.secret = self._gc.get_string('/apps/maemo/hermes/secret_key')
82             self.fb.uid = self._gc.get_string('/apps/maemo/hermes/uid')
83         
84         # Check the available session is still valid...
85         while True:
86             try:
87                 if self.fb.users.getLoggedInUser() and self.fb.session_key:
88                     break
89             except FacebookError:
90                 pass
91             self._do_fb_login()
92             
93         self._friends = {}
94         attrs = ['uid', 'name', 'pic_big', 'birthday_date', 'profile_url', 'first_name', 'last_name', 'website']
95         for friend in self.fb.users.getInfo(self.fb.friends.get(), attrs):
96             print "#"
97             friend['key']= canonical(friend['name'])
98             self._friends[friend['key']] = friend
99         
100             if 'profile_url' not in friend:
101                 friend['profile_url'] = "http://www.facebook.com/profile.php?id=" + str(friend ['uid'])
102         
103             self._friends_by_url[friend['profile_url']] = friend
104             friend['pic']  = friend[attrs[2]]
105             friend['account'] = 'Facebook'
106         
107             if 'website' in friend and friend['website']:
108                 friend['homepage'] = friend['website']
109                 
110             if 'birthday_date' in friend and friend['birthday_date']:
111                 self._should_create.add(friend['profile_url'])
112                 
113         return self._friends.values()
114
115     
116     # -----------------------------------------------------------------------
117     def process_contact(self, contact, overwrite = False, friend = None):
118         """Called for each contact in the address book. Any friends linked to
119            from the contact should have their matching updated. The backend should 
120            enrich the contact with any meta-data it can; and return 'True' if any
121            information was updated. If 'friend' is provided, the information should
122            be retrieved from friend. This will be one of the entries from 
123            'get_friends' when manual mapping is being done."""
124            
125         if not self._friends:
126             self.get_friends()
127             
128         matched_friend = None
129         for url in contact.get_urls():
130             if url in self._friends_by_url:
131                 matched_friend = self._friends_by_url[url]
132                 break
133
134         if not matched_friend:
135             for id in contact.get_identifiers():
136                 if id in self._friends:
137                     matched_friend = self._friends[id]
138                     break
139                 
140         if matched_friend:
141             print contact.get_name(), " -> ", matched_friend['profile_url']
142             self._should_create.discard(matched_friend['profile_url'])
143         else:
144             print contact.get_name(), " no match to Facebook with ", contact.get_identifiers()
145             
146     
147     
148     # -----------------------------------------------------------------------
149     def finalise(self, updated, overwrite = False):
150         """Once all contacts have been processed, allows for any tidy-up/additional
151            enrichment. If any contacts are updated at this stage, 'updated' should
152            be added to."""
153
154         if self._autocreate:
155             for url in self._should_create:
156                 print "Need to autocreate:", self._friends_by_url[url]