diff options
-rw-r--r-- | pykolab/xml/attendee.py | 2 | ||||
-rw-r--r-- | tests/functional/test_wallace/test_005_resource_invitation.py | 5 | ||||
-rw-r--r-- | wallace/module_resources.py | 68 |
3 files changed, 62 insertions, 13 deletions
diff --git a/pykolab/xml/attendee.py b/pykolab/xml/attendee.py index 7921280..4a30622 100644 --- a/pykolab/xml/attendee.py +++ b/pykolab/xml/attendee.py @@ -172,7 +172,7 @@ class Attendee(kolabformat.Attendee): def get_displayname(self): name = self.contactreference.get_name() email = self.contactreference.get_email() - return "%s <%s>" % (name, email) if name is not None else email + return "%s <%s>" % (name, email) if not name == "" else email def get_participant_status(self, translated=False): partstat = self.partStat() diff --git a/tests/functional/test_wallace/test_005_resource_invitation.py b/tests/functional/test_wallace/test_005_resource_invitation.py index 096fba8..c21f12c 100644 --- a/tests/functional/test_wallace/test_005_resource_invitation.py +++ b/tests/functional/test_wallace/test_005_resource_invitation.py @@ -34,6 +34,7 @@ SUMMARY:test DESCRIPTION:test ORGANIZER;CN="Doe, John":mailto:john.doe@example.org ATTENDEE;ROLE=REQ-PARTICIPANT;CUTYPE=RESOURCE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:%s +ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=TENTATIVE;CN=Somebody Else:mailto:somebody@else.com TRANSP:OPAQUE END:VEVENT END:VCALENDAR @@ -221,9 +222,11 @@ class TestResourceInvitation(unittest.TestCase): self.room1 = funcs.resource_add("confroom", "Room 101", owner=self.jane['dn'], kolabinvitationpolicy='ACT_ACCEPT_AND_NOTIFY') self.room2 = funcs.resource_add("confroom", "Conference Room B-222") - self.room3 = funcs.resource_add("confroom", "CEOs Office 303", owner=self.jane['dn'], kolabinvitationpolicy='ACT_MANUAL') self.rooms = funcs.resource_add("collection", "Rooms", [ self.room1['dn'], self.room2['dn'] ], self.jane['dn'], kolabinvitationpolicy='ACT_ACCEPT_AND_NOTIFY') + self.room3 = funcs.resource_add("confroom", "CEOs Office 303") + self.viprooms = funcs.resource_add("collection", "VIP Rooms", [ self.room3['dn'] ], self.jane['dn'], kolabinvitationpolicy='ACT_MANUAL') + time.sleep(1) from tests.functional.synchronize import synchronize_once synchronize_once() diff --git a/wallace/module_resources.py b/wallace/module_resources.py index 2f93c6f..f7c9441 100644 --- a/wallace/module_resources.py +++ b/wallace/module_resources.py @@ -268,6 +268,11 @@ def execute(*args, **kw): log.error("Could not find envelope sender attendee: %r" % (e)) continue + # forward owner response comment + comment = itip_event['xml'].get_comment() + if comment: + event.set_comment(str(comment)) + itip_event_ = dict(xml=event, uid=event.get_uid()) if owner_reply == kolabformat.PartAccepted: @@ -598,11 +603,15 @@ def accept_reservation_request(itip_event, resource, delegator=None, confirmed=F owner = get_resource_owner(resource) confirmation_required = False - if not confirmed and resource.has_key('kolabinvitationpolicy'): - for policy in resource['kolabinvitationpolicy']: - if policy & ACT_MANUAL and owner['mail']: - confirmation_required = True - break + if not confirmed: + invitationpolicy = get_resource_invitationpolicy(resource) + log.debug(_("Apply invitation policies %r") % (invitationpolicy), level=9) + + if invitationpolicy is not None: + for policy in invitationpolicy: + if policy & ACT_MANUAL and owner['mail']: + confirmation_required = True + break partstat = 'TENTATIVE' if confirmation_required else 'ACCEPTED' @@ -963,6 +972,37 @@ def get_resource_owner(resource): return None +def get_resource_invitationpolicy(resource): + """ + Get this resource's kolabinvitationpolicy configuration + """ + global auth + + if not resource.has_key('kolabinvitationpolicy') or resource['kolabinvitationpolicy'] is None: + if not auth: + auth = Auth() + auth.connect() + + # get kolabinvitationpolicy attribute from collection + collections = auth.search_entry_by_attribute('uniquemember', resource['dn']) + if not isinstance(collections, list): + collections = [ (collections['dn'],collections) ] + + log.debug("Check collections %r for kolabinvitationpolicy attributes" % (collections), level=9) + + for dn,collection in collections: + # ldap.search_entry_by_attribute() doesn't return the attributes lower-cased + if collection.has_key('kolabInvitationPolicy'): + collection['kolabinvitationpolicy'] = collection['kolabInvitationPolicy'] + + if collection.has_key('kolabinvitationpolicy'): + parse_kolabinvitationpolicy(collection) + resource['kolabinvitationpolicy'] = collection['kolabinvitationpolicy'] + break + + return resource['kolabinvitationpolicy'] if resource.has_key('kolabinvitationpolicy') else None + + def send_response(from_address, itip_events, owner=None): """ Send the given iCal events as a valid iTip response to the organizer. @@ -1033,8 +1073,10 @@ def send_owner_notification(resource, owner, itip_event, success=True): notify = False status = itip_event['xml'].get_attendee_by_email(resource['mail']).get_participant_status(True) - if resource.has_key('kolabinvitationpolicy'): - for policy in resource['kolabinvitationpolicy']: + invitationpolicy = get_resource_invitationpolicy(resource) + + if invitationpolicy is not None: + for policy in invitationpolicy: # TODO: distingish ACCEPTED / DECLINED status notifications? if policy & COND_NOTIFY and owner['mail']: notify = True @@ -1109,9 +1151,10 @@ def send_owner_confirmation(resource, owner, itip_event): receive the reply from the owner. """ - event = itip_event['xml'] uid = itip_event['uid'] + event = itip_event['xml'] organizer = event.get_organizer() + event_attendees = [a.get_displayname() for a in event.get_attendees() if not a.get_cutype() == kolabformat.CutypeResource] # generate new UID and set the resource as organizer (mail, domain) = resource['mail'].split('@') @@ -1119,11 +1162,12 @@ def send_owner_confirmation(resource, owner, itip_event): event.set_organizer(mail + '+' + urllib.quote(uid) + '@' + domain, resource['cn']) itip_event['uid'] = event.get_uid() - # add resource owner as attendee + # add resource owner as (the sole) attendee + event._attendees = [] event.add_attendee(owner['mail'], owner['cn'], rsvp=True, role=kolabformat.Required, participant_status=kolabformat.PartNeedsAction) # flag this iTip message as confirmation type - event.add_custom_property('X-Wallace-MessageType', 'CONFIRMATION') + event.add_custom_property('X-Kolab-InvitationType', 'CONFIRMATION') log.debug( _("Clone invitation for owner confirmation: %r from %r") % ( @@ -1140,6 +1184,7 @@ def send_owner_confirmation(resource, owner, itip_event): Subject: %(summary)s. Date: %(date)s + Participants: %(attendees)s *** This is an automated message, please don't reply by email. *** """)% { @@ -1147,7 +1192,8 @@ def send_owner_confirmation(resource, owner, itip_event): 'orgname': organizer.name(), 'orgemail': organizer.email(), 'summary': event.get_summary(), - 'date': event.get_date_text() + 'date': event.get_date_text(), + 'attendees': ",\n+ ".join(event_attendees) } pykolab.itip.send_request(owner['mail'], itip_event, message_text, |