Fix overzealous matching on URL; and fix "Non-string URLs" from Twitter.
[hermes] / package / src / org / maemo / hermes / engine / friend.py
1 class Friend():
2     """Encapsulate the data from a remote service.
3     
4        Copyright (c) Fredrik Wendt <fredrik@wendt.se> 2010.
5        Released under the Artistic Licence."""
6
7     
8     def __init__(self, name=None, source=None, props=None):
9         """ source is source service, such as LinkedIn """
10         self._attributes = {};
11         if name: self._set('fn', name)
12         self._multi_attributes = {}
13         self._source = source
14         if props:
15             for key in props:
16                 self._set(key, props[key])
17         
18     def __getitem__(self, key):
19         return self._safe_get(key)
20                               
21     def __unicode__(self):
22         return self.__repr__()
23     
24     def __repr__(self):
25         return "Friend %s" % self.get_name()
26     
27     # public accessors -----------------
28     
29     def add_url(self, url):
30         if url:
31             if not isinstance(url, basestring):
32                 print url
33                 raise Exception('Not valid to add non-string URLs')
34             self._add('url', url)
35     
36     def add_phone(self, phone):
37         if phone:
38             self._add('phone', phone)
39         
40     def get_birthday_date(self):
41         return self._safe_get('bday')
42     
43     def get_contact(self):
44         return self._safe_get('contact')
45     
46     def get_name(self):
47         return self._safe_get('fn')
48     
49     def get_source(self):
50         return self._source
51     
52     def set_source(self, source):
53         self._source = source
54     
55     def get_nickname(self):
56         return self._safe_get("nickname")
57     
58     def get_urls(self):
59         try: return self._multi_attributes['url'] 
60         except: return []
61     
62     def get_phones(self):
63         try: return self._multi_attributes['phone'] 
64         except: return []
65         
66     def get_photo_url(self):
67         return self._safe_get('photo-url')
68     
69     def has_birthday_date(self):
70         return self._has('bday')
71     
72     def is_empty(self):
73         for a in self._attributes:
74             return False
75         for a in self._multi_attributes:
76             return False
77         return True
78     
79     def set_name(self, name):
80         self._set('fn', name)
81     
82     def set_nickname(self, nickname):
83         self._set('nickname', nickname)
84         
85     def set_birthday_date(self, date):
86         self._set('bday', date)
87         
88     def set_contact(self, contact):
89         self._set('contact', contact)
90         
91     def set_photo_url(self, url):
92         self._set('photo-url', url)
93     
94     def update_from_friend(self, other_friend, overwrite=False):
95         """
96         Overwrites any attributes in this friend, with attributes from other_friend
97         """
98         
99         self._attributes.update(other_friend._attributes)
100         
101         for key in other_friend._multi_attributes.keys():
102             for value in other_friend._multi_attributes[key]:
103                 self._add(key, value)
104      
105     def update_contact(self, contact, overwrite=False):
106         """Updates the contact with information from this object,
107            without overwriting unless overwrite is set to True.
108            Returns flag indicating if anything *was* changed."""
109         
110         def set_birthday(arg):
111             # Hackily assumes Facebook format (mm/d[/y])
112             date_str = arg.split('/')
113             date_str.append('0')
114             return contact.set_birthday(int(date_str[1]),
115                                         int(date_str[0]),
116                                         int(date_str[2]))
117
118         updated = False
119         if overwrite or contact.get_photo() is None:    updated += self._if_defined('photo-url', contact.set_photo)
120         if overwrite or contact.get_nickname() is None: updated += self._if_defined('nickname', contact.set_nickname)
121         if overwrite or contact.get_birthday() is None: updated += self._if_defined('bday', set_birthday)
122         if self._multi_attributes.has_key('url'):
123             for url in self._multi_attributes['url']:
124                 updated += contact.add_url(url)
125
126         if self._multi_attributes.has_key('phone'):
127             for phone in self._multi_attributes['phone']:
128                 updated += contact.add_phone(phone)
129                 
130         return updated
131
132
133     # private helpers -----------------------
134     #
135     def _add(self, key, value):
136         if value is not None:
137             if not self._multi_attributes.has_key(key):
138                 self._multi_attributes[key] = []
139 #            print "%s ADD %s to %s" % (self, key, value)
140             self._multi_attributes[key].append(value)
141     
142     def _contains(self, key, value):
143         if self._attributes.has_key(key):
144             return value == self._attributes[key]
145         if self._multi_attributes.has_key(key):
146             return value in self._multi_attributes[key]
147         return False
148     
149     def _if_defined(self, key, callback):
150         return self._attributes.has_key(key) and callback(self._attributes[key]) or False
151     
152     def _has(self, key):
153         return self._attributes.has_key(key) or self._multi_attributes.has_key(key)
154     
155     def _safe_get(self, key):
156         try: return self._attributes[key]
157         except: return None
158         
159     def _set(self, key, value):
160         if value is not None:
161 #            print "%s SET %s to %s" % (self, key, value)
162             self._attributes[key] = value
163