Add support for creating contacts from "interesting" friends on LinkedIn. Completes...
[hermes] / package / src / org / maemo / hermes / engine / hermes.py
1 from org.maemo.hermes.engine.friend import Friend
2 from org.maemo.hermes.engine.contact import Contact
3 import evolution
4
5 class Hermes:
6     """Encapsulate the process of syncing online friends' information with the
7        Evolution contacts' database.
8        
9        Copyright (c) Andrew Flegg <andrew@bleb.org> 2010.
10        Released under the Artistic Licence."""
11
12     
13     # -----------------------------------------------------------------------
14     def __init__(self, services, gui_progress=None):
15         """Constructor. Passed a list of services, and a            
16            method which will be invoked with three arguments:
17                 str    Name of current step
18                 int    Current position
19                 int    Maximum value of position."""
20
21         
22         # -- These fields are currently part of the API...
23         #
24         self.updated = []
25         self.matched = []
26         self.unmatched = []
27         self.friends = {}
28         self.address_book = None
29         
30         # -- Other initialisation...
31         #
32         self._services = services
33         self._progress = gui_progress or (lambda msg, i, j: None)
34     
35     
36     # -----------------------------------------------------------------------
37     def run(self, overwrite_existing_fields=False):
38         self._progress("Reading contacts...", 1, 10000)
39         
40         contacts = []
41         self.address_book = self._get_address_book()
42         for econtact in self.address_book.get_all_contacts():
43             contacts.append(self._create_contact_wrapper(econtact))
44
45         # work out progress bar info
46         total_contacts = len(contacts) * len(self._services)
47         total_ticks    = 6 * total_contacts # Number of distinct loops below
48
49         # warm up
50         current_tick = 1
51         for service in self._services:
52             print "pre-process:", service.get_id()
53             for contact in contacts:
54                 self._progress("Pre-processing contacts...", current_tick, total_ticks)
55                 current_tick += 1
56                 service.pre_process_contact(contact)
57                 
58         # fetch data
59         for service in self._services:
60             print "process_friends:", service.get_id()
61             self._progress("Reading friends...", current_tick, total_ticks)
62             current_tick += len(contacts)
63             service.process_friends()
64         
65         # combine results into one friend
66         for contact in contacts:
67             result = Friend()
68             for service in self._services:
69                 print "process_contact:", service.get_id()
70                 self._progress("Processing contacts...", current_tick, total_ticks)
71                 current_tick += 1
72                 friend = service.process_contact(contact)
73                 if friend:
74                     contact.add_mapping(service.get_id())
75                     result.update_from_friend(friend)
76             
77             if result.get_name() is not None:
78                 self.update_contact(contact, result, overwrite_existing_fields)
79             else:
80                 self.unmatched.append(contact)
81             
82         # give services a chance to create new contacts
83         for service in self._services:
84             print "create_contacts:", service.get_id()
85             to_create = service.get_friends_to_create_contacts_for()
86             tick_increment = len(contacts) / (len(to_create) or 1)
87             print tick_increment, to_create
88             for friend in to_create:
89                 self._progress("Creating contacts...", current_tick, total_ticks)
90                 current_tick += tick_increment
91                 if friend.is_interesting():
92                     friend.set_source(service.get_id())
93                     self.create_contact_from_friend(friend)
94                 
95         # finalisation
96         for service in self._services:
97             print "finalize:", service.get_id()
98             self._progress("Finalising...", current_tick, total_ticks)
99             current_tick += len(contacts)
100             service.finalise(self.updated, overwrite_existing_fields)
101             for friend in service.get_unmatched_friends():
102                 friend.set_source(service.get_id())
103                 key = unicode(friend.get_name()).encode('trans') + "_" + service.get_id()
104                 self.friends[key] = friend
105             
106         # commit changes
107         tick_increment = total_contacts / (len(self.updated) or 1)
108         print tick_increment, self.updated
109         for contact in self.updated:
110             print "committing changes to:", contact.get_name(), contact
111             self._progress("Saving changes...", current_tick, total_ticks)
112             current_tick += tick_increment
113             self.address_book.commit_contact(contact.get_econtact())
114             
115         self._progress('Finished', 1, -1)
116         
117
118     # -----------------------------------------------------------------------
119     def update_contact(self, contact, friend, resync=False, commit=False):
120         """Update the given contact with information from the given friend."""
121         
122         print "updating contact ", contact, " with friend ", friend
123         if friend.update_contact(contact, resync):
124             self.updated.append(contact)
125             if commit:
126                 self.address_book.commit_contact(contact.get_econtact())
127
128         self.matched.append(contact)
129         if friend.get_source() is not None:
130             contact.add_mapping(friend.get_source())
131
132
133     # -----------------------------------------------------------------------
134     def create_contact_from_friend(self, friend):
135         econtact = self._create_empty_contact(friend)
136         contact = self._create_contact_wrapper(econtact)
137                 
138         self.address_book.add_contact(contact.get_econtact())
139         self.update_contact(contact, friend)
140         
141         print "Created [%s]" % (contact.get_name())
142         
143         
144     # -----------------------------------------------------------------------
145     def _get_address_book(self):
146         return evolution.ebook.open_addressbook('default')
147
148     # -----------------------------------------------------------------------
149     def _create_empty_contact(self, friend):
150         econtact = evolution.ebook.EContact()
151         econtact.props.given_name = friend['first_name']
152         econtact.props.family_name = friend['last_name']
153         econtact.props.full_name = friend.get_name()
154         return econtact
155     
156     # -----------------------------------------------------------------------
157     def _create_contact_wrapper(self, econtact):
158         return Contact(self.address_book, econtact)