1.1 --- a/imiptools/content.py Sat Jan 24 23:55:24 2015 +0100
1.2 +++ b/imiptools/content.py Sun Jan 25 00:18:48 2015 +0100
1.3 @@ -180,6 +180,28 @@
1.4 remove_period(freebusy, uid)
1.5 store.set_freebusy(attendee, freebusy)
1.6
1.7 +def remove_from_freebusy_for_other(freebusy, user, other, uid, store):
1.8 +
1.9 + """
1.10 + For the given 'user', remove for the 'other' party periods from 'freebusy'
1.11 + that are associated with 'uid' in the 'store'.
1.12 + """
1.13 +
1.14 + remove_period(freebusy, uid)
1.15 + store.set_freebusy_for_other(user, freebusy, other)
1.16 +
1.17 +def _update_freebusy(freebusy, periods, transp, uid):
1.18 +
1.19 + """
1.20 + Update the free/busy details with the given 'periods', 'transp' setting and
1.21 + 'uid'.
1.22 + """
1.23 +
1.24 + remove_period(freebusy, uid)
1.25 +
1.26 + for start, end in periods:
1.27 + insert_period(freebusy, (start, end, uid, transp))
1.28 +
1.29 def update_freebusy(freebusy, attendee, periods, transp, uid, store):
1.30
1.31 """
1.32 @@ -187,12 +209,18 @@
1.33 'periods', 'transp' setting and 'uid' in the 'store'.
1.34 """
1.35
1.36 - remove_period(freebusy, uid)
1.37 + _update_freebusy(freebusy, periods, transp, uid)
1.38 + store.set_freebusy(attendee, freebusy)
1.39 +
1.40 +def update_freebusy_for_other(freebusy, user, other, periods, transp, uid, store):
1.41
1.42 - for start, end in periods:
1.43 - insert_period(freebusy, (start, end, uid, transp))
1.44 + """
1.45 + For the given 'user', update the free/busy details of 'other' with the given
1.46 + 'periods', 'transp' setting and 'uid' in the 'store'.
1.47 + """
1.48
1.49 - store.set_freebusy(attendee, freebusy)
1.50 + _update_freebusy(freebusy, periods, transp, uid)
1.51 + store.set_freebusy_for_other(user, freebusy, other)
1.52
1.53 def can_schedule(freebusy, periods, uid):
1.54
1.55 @@ -358,25 +386,53 @@
1.56 def remove_from_freebusy(self, freebusy, attendee):
1.57 remove_from_freebusy(freebusy, attendee, self.uid, self.store)
1.58
1.59 + def remove_from_freebusy_for_other(self, freebusy, user, other):
1.60 + remove_from_freebusy_for_other(freebusy, user, other, self.uid, self.store)
1.61 +
1.62 def update_freebusy(self, freebusy, attendee, periods):
1.63 return update_freebusy(freebusy, attendee, periods, self.get_value("TRANSP"), self.uid, self.store)
1.64
1.65 + def update_freebusy_for_other(self, freebusy, user, other, periods):
1.66 + return update_freebusy_for_other(freebusy, user, other, periods, self.get_value("TRANSP"), self.uid, self.store)
1.67 +
1.68 def can_schedule(self, freebusy, periods):
1.69 return can_schedule(freebusy, periods, self.uid)
1.70
1.71 - def filter_by_senders(self, values):
1.72 - addresses = map(get_address, values)
1.73 + def filter_by_senders(self, mapping):
1.74 +
1.75 + """
1.76 + Return a list of items from 'mapping' filtered using sender information.
1.77 + """
1.78 +
1.79 if self.senders:
1.80 - return self.senders.intersection(addresses)
1.81 - else:
1.82 - return addresses
1.83 +
1.84 + # Get a mapping from senders to identities.
1.85 +
1.86 + identities = self.get_sender_identities(mapping)
1.87 +
1.88 + # Find the senders that are valid.
1.89 +
1.90 + senders = map(get_address, identities)
1.91 + valid = self.senders.intersection(senders)
1.92
1.93 - def filter_by_recipients(self, values):
1.94 - addresses = map(get_address, values)
1.95 + # Return the true identities.
1.96 +
1.97 + return [identities[get_uri(address)] for address in valid]
1.98 + else:
1.99 + return mapping
1.100 +
1.101 + def filter_by_recipients(self, mapping):
1.102 +
1.103 + """
1.104 + Return a list of items from 'mapping' filtered using recipient
1.105 + information.
1.106 + """
1.107 +
1.108 if self.recipients:
1.109 - return self.recipients.intersection(addresses)
1.110 + addresses = map(get_address, mapping)
1.111 + return map(get_uri, self.recipients.intersection(addresses))
1.112 else:
1.113 - return addresses
1.114 + return mapping
1.115
1.116 def require_organiser_and_attendees(self, from_organiser=True):
1.117
1.118 @@ -388,39 +444,46 @@
1.119 """
1.120
1.121 attendee_map = uri_dict(self.get_value_map("ATTENDEE"))
1.122 - organiser = uri_item(self.get_item("ORGANIZER"))
1.123 + organiser_item = uri_item(self.get_item("ORGANIZER"))
1.124
1.125 - # Only provide details for recipients who are also attendees.
1.126 + # Only provide details for attendees who sent/receive the message.
1.127
1.128 - filter_fn = from_organiser and self.filter_by_recipients or self.filter_by_senders
1.129 + attendee_filter_fn = from_organiser and self.filter_by_recipients or self.filter_by_senders
1.130
1.131 attendees = {}
1.132 - for attendee in map(get_uri, filter_fn(attendee_map)):
1.133 + for attendee in attendee_filter_fn(attendee_map):
1.134 attendees[attendee] = attendee_map[attendee]
1.135
1.136 - if not attendees or not organiser:
1.137 + if not attendees or not organiser_item:
1.138 + return None
1.139 +
1.140 + # Only provide details for an organiser who sent/receives the message.
1.141 +
1.142 + organiser_filter_fn = from_organiser and self.filter_by_senders or self.filter_by_recipients
1.143 +
1.144 + if not organiser_filter_fn(dict([organiser_item])):
1.145 return None
1.146
1.147 - return organiser, attendees
1.148 + return organiser_item, attendees
1.149
1.150 - def validate_identities(self, items):
1.151 + def get_sender_identities(self, mapping):
1.152
1.153 """
1.154 - Validate the 'items' against the known senders, obtaining sent-by
1.155 - addresses from attributes provided by the items.
1.156 + Return a mapping from actual senders to the identities for which they
1.157 + have provided data, extracting this information from the given
1.158 + 'mapping'.
1.159 """
1.160
1.161 - # Reject organisers that do not match any senders.
1.162 + senders = {}
1.163
1.164 - identities = []
1.165 -
1.166 - for value, attr in items:
1.167 - identities.append(value)
1.168 + for value, attr in mapping.items():
1.169 sent_by = attr.get("SENT-BY")
1.170 if sent_by:
1.171 - identities.append(get_uri(sent_by))
1.172 + senders[get_uri(sent_by)] = value
1.173 + else:
1.174 + senders[value] = value
1.175
1.176 - return self.filter_by_senders(identities)
1.177 + return senders
1.178
1.179 def get_object(self, user, objtype):
1.180
1.181 @@ -452,8 +515,18 @@
1.182 # NOTE: and make it invalid. Thus, attendance information may also be
1.183 # NOTE: checked.
1.184
1.185 - _attendee, old_attr = get_item(obj, "ATTENDEE")
1.186 - _attendee, new_attr = self.get_item("ATTENDEE")
1.187 + for _attendee, old_attr in get_items(obj, "ATTENDEE"):
1.188 + if _attendee == attendee:
1.189 + break
1.190 + else:
1.191 + return False
1.192 +
1.193 + for _attendee, new_attr in self.get_items("ATTENDEE"):
1.194 + if _attendee == attendee:
1.195 + break
1.196 + else:
1.197 + return False
1.198 +
1.199 old_partstat = old_attr.get("PARTSTAT")
1.200 new_partstat = new_attr.get("PARTSTAT")
1.201