d60849edffab8fd30acbc25b8bdfb9b3ec9db11d
[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. This should be used as follows:
8        
9          * Initialise, passing in a GUI callback.
10          * Call Syncjob.
11          * Retrieve information on changes effected.
12          * Call update_contact to enact manual mapping.
13          
14        Copyright (c) Andrew Flegg <andrew@bleb.org> 2010.
15        Released under the Artistic Licence."""
16
17     
18     # -----------------------------------------------------------------------
19     def __init__(self, services, gui_progress=None):
20         """Constructor. Passed a list of services, and a            
21            method which will be invoked with three arguments:
22                 str    Name of current step
23                 int    Current position
24                 int    Maximum value of position."""
25
26         
27         # -- These fields are currently part of the API...
28         #
29         self.updated = []
30         self.matched = []
31         self.unmatched = []
32         self.friends = {}
33         self.addresses = None
34         
35         # -- Other initialisation...
36         #
37         self._services = services
38         self._progress = gui_progress or (lambda msg, i, j: None)
39     
40     
41     # -----------------------------------------------------------------------
42     def run(self, resync=False):
43         """Load information on the authenticated user's friends. Synchronise Facebook
44            profiles to contact database. If resync is false, no existing information
45            will be overwritten."""
46            
47         class FakeContact():
48             def get_name(self):
49                 return "Fredrik Wendt"
50             def get_emails(self):
51                 return ["fredrik@wendt.se", "maemohermes@wendt.se"]
52             def get_photo(self):
53                 return None
54             def get_mapped_to(self):
55                 return set(["facebook", "gravatar"])
56         self.matched = [FakeContact()]
57  
58 #        self._sync_job = SyncJob(services, [FakeContact()], self.progress)
59 #        self._sync_job.run()
60 #        self._sync_job.get_unmatched_friends()
61 #        self._sync_job.get_updated_contacts()
62 #        self._sync_job.get_matched_contacts()
63         pass
64     
65     
66     # -----------------------------------------------------------------------
67     def run_alt(self, overwrite_existing_fields=False):
68         self._progress("Reading contacts...", 1, 10000)
69         
70         contacts = []
71         self.addresses = evolution.ebook.open_addressbook('default')
72         for contact in self.addresses.get_all_contacts():
73             contacts.append(Contact(self.addresses, contact))
74
75         # work out progress bar info
76         total_contacts = len(contacts) * len(self._services)
77         total_ticks    = 6 * total_contacts # Number of distinct loops below
78
79         # warm up
80         current_tick = 1
81         for service in self._services:
82             print "pre-process:", service.get_id()
83             for contact in contacts:
84                 self._progress("Pre-processing contacts...", current_tick, total_ticks)
85                 current_tick += 1
86                 service.pre_process_contact(contact)
87                 
88         # fetch data
89         for service in self._services:
90             print "process_friends:", service.get_id()
91             self._progress("Reading friends...", current_tick, total_ticks)
92             current_tick += len(contacts)
93             service.process_friends()
94         
95         # combine results into one friend
96         for contact in contacts:
97             result = Friend()
98             for service in self._services:
99                 print "process_contact:", service.get_id()
100                 self._progress("Processing contacts...", current_tick, total_ticks)
101                 current_tick += 1
102                 friend = service.process_contact(contact)
103                 if friend:
104                     contact.add_mapping(service.get_id())
105                     friend.decorate(result)
106             
107             if result.get_name() is not None:
108                 self.update_contact(result, overwrite_existing_fields)
109             else:
110                 self.unmatched.append(contact)
111             
112         # give services a chance to create new contacts
113         for service in self._services:
114             print "create_contacts:", service.get_id()
115             to_create = service.get_friends_to_create_contacts_for()
116             tick_increment = len(contacts) / (len(to_create) or 1)
117             print tick_increment, to_create
118             for friend in to_create:
119                 self._progress("Creating contacts...", current_tick, total_ticks)
120                 current_tick += tick_increment
121                 self.create_contact_from_friend(friend)
122                 
123         # finalisation
124         for service in self._services:
125             print "finalize:", service.get_id()
126             self._progress("Finalising...", current_tick, total_ticks)
127             current_tick += len(contacts)
128             service.finalise(self.updated, overwrite_existing_fields)
129             
130         # commit changes
131         tick_increment = total_contacts / (len(self.updated) or 1)
132         print tick_increment, self.updated
133         for contact in self.updated:
134             print "committing changes to:", contact.get_name(), contact
135             self._progress("Saving changes...", current_tick, total_ticks)
136             current_tick += tick_increment
137             self.addresses.commit_contact(contact.get_econtact())
138             
139         self._progress('Finished', 1, -1)
140         
141
142     # -----------------------------------------------------------------------
143     def update_contact(self, contact, friend, resync=False):
144         """Update the given contact with information from the given friend."""
145         
146         print "updating contact ", contact, " with friend ", friend
147         self.updated.append(contact)
148         self.matched.append(contact)
149         if friend.get_source() is not None:
150             contact.add_mapping(friend.get_source())
151
152
153     # -----------------------------------------------------------------------
154     def create_contact_from_friend(self, friend):
155         econtact = evolution.ebook.EContact()
156         econtact.props.full_name = friend['name']
157         econtact.props.given_name = friend['first_name']
158         econtact.props.family_name = friend['last_name']
159         contact = Contact(self.addresses, econtact)
160                 
161         self.addresses.add_contact(contact.get_econtact())
162         self.update_contact(contact, friend)
163         
164         print "Created [%s]" % (contact.get_name())