d1af8b7801
Added sieve tests (vacation, forwarding and simple sieve scripts) Added some caldav scheduling tests cases and resources planning tests. Added new variables to config.py.in for sieve resources planning tests. Monotone-Parent: d3ab72b923ee1d1bbd604ea5e7e14b54346aa0b3 Monotone-Revision: 53dfb1b04415248644ed626184df1362cd4ee2f1 Monotone-Author: jraby@inverse.ca Monotone-Date: 2011-05-03T12:37:34 Monotone-Branch: ca.inverse.sogo
612 lines
26 KiB
Python
Executable file
612 lines
26 KiB
Python
Executable file
#!/usr/bin/python
|
|
|
|
# setup: username must be super-user or have read-access to PUBLIC events in
|
|
# both attendee and delegate's personal calendar
|
|
|
|
from config import hostname, port, username, password, \
|
|
attendee1, attendee1_delegate, \
|
|
resource_no_overbook, resource_can_overbook
|
|
|
|
import datetime
|
|
import sogotests
|
|
import sys
|
|
import time
|
|
import pytz
|
|
import unittest
|
|
import utilities
|
|
import vobject
|
|
import vobject.base
|
|
import vobject.icalendar
|
|
import webdavlib
|
|
import StringIO
|
|
import xml.etree.ElementTree
|
|
|
|
class CalDAVPropertiesTest(unittest.TestCase):
|
|
def setUp(self):
|
|
self.client = webdavlib.WebDAVClient(hostname, port,
|
|
username, password)
|
|
self.test_calendar \
|
|
= "/SOGo/dav/%s/Calendar/test-dav-properties/" % username
|
|
mkcol = webdavlib.WebDAVMKCOL(self.test_calendar)
|
|
self.client.execute(mkcol)
|
|
|
|
def tearDown(self):
|
|
delete = webdavlib.WebDAVDELETE(self.test_calendar)
|
|
self.client.execute(delete)
|
|
|
|
def testDavScheduleCalendarTransparency(self):
|
|
"""{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp"""
|
|
|
|
## PROPFIND
|
|
propfind = webdavlib.WebDAVPROPFIND(self.test_calendar,
|
|
["{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp"],
|
|
0)
|
|
self.client.execute(propfind)
|
|
response = propfind.response["document"].find('{DAV:}response')
|
|
propstat = response.find('{DAV:}propstat')
|
|
status = propstat.find('{DAV:}status').text[9:12]
|
|
|
|
self.assertEquals(status, "200",
|
|
"schedule-calendar-transp marked as 'Not Found' in response")
|
|
transp = propstat.find('{DAV:}prop/{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp')
|
|
values = transp.getchildren()
|
|
self.assertEquals(len(values), 1, "one and only one element expected")
|
|
value = values[0]
|
|
self.assertTrue(isinstance(value, xml.etree.ElementTree._ElementInterface),
|
|
"schedule-calendar-transp must be an instance of" \
|
|
" %s, not %s"
|
|
% ("_ElementInterface", transp.__class__.__name__))
|
|
ns = value.tag[0:31]
|
|
tag = value.tag[31:]
|
|
self.assertTrue(ns == "{urn:ietf:params:xml:ns:caldav}",
|
|
"schedule-calendar-transp must have a value in"\
|
|
" namespace '%s', not '%s'"
|
|
% ("urn:ietf:params:xml:ns:caldav", ns))
|
|
self.assertTrue(tag == "opaque",
|
|
"schedule-calendar-transp must be 'opaque' on new" \
|
|
" collections, not '%s'" % tag)
|
|
|
|
## PROPPATCH
|
|
newValueNode = "{urn:ietf:params:xml:ns:caldav}thisvaluedoesnotexist"
|
|
proppatch = webdavlib.WebDAVPROPPATCH(self.test_calendar,
|
|
{"{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp": \
|
|
{ newValueNode: True }})
|
|
self.client.execute(proppatch)
|
|
self.assertEquals(proppatch.response["status"], 400,
|
|
"expecting failure when setting transparency to" \
|
|
" an invalid value")
|
|
|
|
newValueNode = "{urn:ietf:params:xml:ns:caldav}transparent"
|
|
proppatch = webdavlib.WebDAVPROPPATCH(self.test_calendar,
|
|
{"{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp": \
|
|
{ newValueNode: True }})
|
|
self.client.execute(proppatch)
|
|
self.assertEquals(proppatch.response["status"], 207,
|
|
"failure (%s) setting transparency to" \
|
|
" 'transparent': '%s'"
|
|
% (proppatch.response["status"],
|
|
proppatch.response["body"]))
|
|
|
|
newValueNode = "{urn:ietf:params:xml:ns:caldav}opaque"
|
|
proppatch = webdavlib.WebDAVPROPPATCH(self.test_calendar,
|
|
{"{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp": \
|
|
{ newValueNode: True }})
|
|
self.client.execute(proppatch)
|
|
self.assertEquals(proppatch.response["status"], 207,
|
|
"failure (%s) setting transparency to" \
|
|
" 'transparent': '%s'"
|
|
% (proppatch.response["status"],
|
|
proppatch.response["body"]))
|
|
|
|
class CalDAVITIPDelegationTest(unittest.TestCase):
|
|
def setUp(self):
|
|
self.client = webdavlib.WebDAVClient(hostname, port,
|
|
username, password)
|
|
utility = utilities.TestUtility(self, self.client)
|
|
(self.user_name, self.user_email) = utility.fetchUserInfo(username)
|
|
(self.attendee1_name, self.attendee1_email) = utility.fetchUserInfo(attendee1)
|
|
(self.attendee1_delegate_name, self.attendee1_delegate_email) = utility.fetchUserInfo(attendee1_delegate)
|
|
(self.res_no_ob_name, self.res_no_ob_email) = utility.fetchUserInfo(resource_no_overbook)
|
|
(self.res_can_ob_name, self.res_can_ob_email) = utility.fetchUserInfo(resource_can_overbook)
|
|
|
|
self.user_calendar = "/SOGo/dav/%s/Calendar/personal/" % username
|
|
self.attendee1_calendar = "/SOGo/dav/%s/Calendar/personal/" % attendee1
|
|
self.attendee1_delegate_calendar = "/SOGo/dav/%s/Calendar/personal/" % attendee1_delegate
|
|
|
|
|
|
def tearDown(self):
|
|
self._deleteEvent(self.client,
|
|
"%stest-delegation.ics" % self.user_calendar, None)
|
|
self._deleteEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_calendar, None)
|
|
self._deleteEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_delegate_calendar,
|
|
None)
|
|
self._deleteEvent(self.client,
|
|
"%stest-add-attendee.ics" % self.user_calendar, None)
|
|
self._deleteEvent(self.client,
|
|
"%stest-add-attendee.ics" % self.attendee1_calendar, None)
|
|
self._deleteEvent(self.client,
|
|
"%stest-no-overbook.ics" % self.user_calendar, None)
|
|
self._deleteEvent(self.client,
|
|
"%stest-no-overbook-overlap.ics" % self.user_calendar, None)
|
|
self._deleteEvent(self.client,
|
|
"%stest-can-overbook.ics" % self.user_calendar, None)
|
|
self._deleteEvent(self.client,
|
|
"%stest-can-overbook-overlap.ics" % self.user_calendar, None)
|
|
|
|
def _newEvent(self, summary="test event", uid="test", transp=0):
|
|
transparency = ("OPAQUE", "TRANSPARENT")
|
|
|
|
newCal = vobject.iCalendar()
|
|
vevent = newCal.add('vevent')
|
|
vevent.add('summary').value = summary
|
|
vevent.add('transp').value = transparency[transp]
|
|
|
|
now = datetime.datetime.now(pytz.timezone("America/Montreal"))
|
|
startdate = vevent.add('dtstart')
|
|
startdate.value = now
|
|
enddate = vevent.add('dtend')
|
|
enddate.value = now + datetime.timedelta(0, 3600)
|
|
vevent.add('uid').value = uid
|
|
vevent.add('dtstamp').value = now
|
|
vevent.add('last-modified').value = now
|
|
vevent.add('created').value = now
|
|
|
|
vevent.add('sequence').value = "0"
|
|
|
|
return newCal
|
|
|
|
def _putEvent(self, client, filename, event, exp_status = 201):
|
|
put = webdavlib.HTTPPUT(filename, event.serialize())
|
|
put.content_type = "text/calendar; charset=utf-8"
|
|
client.execute(put)
|
|
if exp_status is not None:
|
|
self.assertEquals(put.response["status"], exp_status)
|
|
|
|
def _postEvent(self, client, outbox, event, originator, recipients,
|
|
exp_status = 200):
|
|
post = webdavlib.CalDAVPOST(outbox, event.serialize(),
|
|
originator, recipients)
|
|
client.execute(post)
|
|
if exp_status is not None:
|
|
self.assertEquals(post.response["status"], exp_status)
|
|
|
|
def _getEvent(self, client, filename, exp_status = 200):
|
|
get = webdavlib.HTTPGET(filename)
|
|
client.execute(get)
|
|
|
|
if exp_status is not None:
|
|
self.assertEquals(get.response["status"], exp_status)
|
|
|
|
if get.response["headers"]["content-type"].startswith("text/calendar"):
|
|
stream = StringIO.StringIO(get.response["body"])
|
|
event = vobject.base.readComponents(stream).next()
|
|
else:
|
|
event = None
|
|
|
|
return event
|
|
|
|
def _deleteEvent(self, client, filename, exp_status = 204):
|
|
delete = webdavlib.WebDAVDELETE(filename)
|
|
client.execute(delete)
|
|
if exp_status is not None:
|
|
self.assertEquals(delete.response["status"], exp_status)
|
|
|
|
def _eventAttendees(self, event):
|
|
attendees = {}
|
|
|
|
event_component = event.vevent
|
|
for child in event_component.getChildren():
|
|
if child.name == "ATTENDEE":
|
|
try:
|
|
delegated_to = child.delegated_to_param
|
|
except:
|
|
delegated_to = "(none)"
|
|
try:
|
|
delegated_from = child.delegated_from_param
|
|
except:
|
|
delegated_from = "(none)"
|
|
attendees[child.value] = ("%s/%s/%s"
|
|
% (child.partstat_param,
|
|
delegated_to,
|
|
delegated_from))
|
|
|
|
return attendees
|
|
|
|
def _compareAttendees(self, compared_event, event):
|
|
compared_attendees = self._eventAttendees(compared_event)
|
|
compared_emails = compared_attendees.keys()
|
|
self.assertTrue(len(compared_emails) > 0,
|
|
"no attendee found")
|
|
compared_emails.sort()
|
|
|
|
attendees = self._eventAttendees(event)
|
|
emails = attendees.keys()
|
|
emails.sort()
|
|
|
|
self.assertEquals(len(compared_emails), len(emails),
|
|
"number of attendees is not equal"
|
|
+ " (actual: %d, exp: %d)"
|
|
% (len(compared_emails), len(emails)))
|
|
|
|
for email in emails:
|
|
self.assertEquals(compared_attendees[email],
|
|
attendees[email],
|
|
"partstat for attendee '%s' does not match"
|
|
" (actual: '%s', expected: '%s')"
|
|
% (email,
|
|
compared_attendees[email], attendees[email]))
|
|
|
|
def testAddAttendee(self):
|
|
""" add attendee after event creation """
|
|
|
|
# make sure the event doesn't exist
|
|
ics_name = "test-add-attendee.ics"
|
|
self._deleteEvent(self.client,
|
|
"%s%s" % (self.user_calendar,ics_name), None)
|
|
self._deleteEvent(self.client,
|
|
"%s%s" % (self.attendee1_calendar,ics_name), None)
|
|
|
|
# 1. create an event in the organiser's calendar
|
|
event = self._newEvent(summary="Test add attendee", uid="Test add attendee")
|
|
organizer = event.vevent.add('organizer')
|
|
organizer.cn_param = self.user_name
|
|
organizer.value = self.user_email
|
|
self._putEvent(self.client, "%s%s" % (self.user_calendar, ics_name), event)
|
|
|
|
# 2. add an attendee
|
|
event.add("method").value = "REQUEST"
|
|
attendee = event.vevent.add('attendee')
|
|
attendee.cn_param = self.attendee1_name
|
|
attendee.rsvp_param = "TRUE"
|
|
attendee.partstat_param = "NEEDS-ACTION"
|
|
attendee.value = self.attendee1_email
|
|
self._putEvent(self.client, "%s%s" % (self.user_calendar, ics_name), event,
|
|
exp_status=204)
|
|
|
|
|
|
# 3. verify that the attendee has the event
|
|
attendee_event = self._getEvent(self.client, "%s%s" % (self.attendee1_calendar, ics_name))
|
|
|
|
# 4. make sure the received event match the original one
|
|
# XXX is this enough?
|
|
self.assertEquals(event.vevent.uid, attendee_event.vevent.uid)
|
|
|
|
def testResourceNoOverbook(self):
|
|
""" try to overbook a resource """
|
|
|
|
# make sure the event doesn't exist
|
|
ics_name = "test-no-overbook.ics"
|
|
self._deleteEvent(self.client,
|
|
"%s%s" % (self.user_calendar,ics_name), None)
|
|
|
|
ob_ics_name = "test-no-overbook-overlap.ics"
|
|
self._deleteEvent(self.client,
|
|
"%s%s" % (self.user_calendar,ics_name), None)
|
|
|
|
# 1. create an event in the organiser's calendar
|
|
event = self._newEvent(summary="Test no overbook", uid="test no overbook")
|
|
organizer = event.vevent.add('organizer')
|
|
organizer.cn_param = self.user_name
|
|
organizer.value = self.user_email
|
|
attendee = event.vevent.add('attendee')
|
|
attendee.cn_param = self.res_no_ob_name
|
|
attendee.rsvp_param = "TRUE"
|
|
attendee.partstat_param = "NEEDS-ACTION"
|
|
attendee.value = self.res_no_ob_email
|
|
self._putEvent(self.client, "%s%s" % (self.user_calendar, ics_name), event)
|
|
|
|
# 2. create a second event overlapping the first one
|
|
event = self._newEvent(summary="Test no overbook - overlap", uid="test no overbook - overlap")
|
|
organizer = event.vevent.add('organizer')
|
|
organizer.cn_param = self.user_name
|
|
organizer.value = self.user_email
|
|
attendee = event.vevent.add('attendee')
|
|
attendee.cn_param = self.res_no_ob_name
|
|
attendee.rsvp_param = "TRUE"
|
|
attendee.partstat_param = "NEEDS-ACTION"
|
|
attendee.value = self.res_no_ob_email
|
|
|
|
# put the event - should trigger a 403
|
|
self._putEvent(self.client, "%s%s" % (self.user_calendar, ob_ics_name), event, exp_status=403)
|
|
|
|
def testResourceCanOverbook(self):
|
|
""" try to overbook a resource - multiplebookings=0"""
|
|
|
|
# make sure the event doesn't exist
|
|
ics_name = "test-can-overbook.ics"
|
|
self._deleteEvent(self.client,
|
|
"%s%s" % (self.user_calendar,ics_name), None)
|
|
|
|
ob_ics_name = "test-can-overbook-overlap.ics"
|
|
self._deleteEvent(self.client,
|
|
"%s%s" % (self.user_calendar,ob_ics_name), None)
|
|
|
|
# 1. create an event in the organiser's calendar
|
|
event = self._newEvent(summary="Test can overbook", uid="test can overbook")
|
|
organizer = event.vevent.add('organizer')
|
|
organizer.cn_param = self.user_name
|
|
organizer.value = self.user_email
|
|
attendee = event.vevent.add('attendee')
|
|
attendee.cn_param = self.res_can_ob_name
|
|
attendee.rsvp_param = "TRUE"
|
|
attendee.partstat_param = "NEEDS-ACTION"
|
|
attendee.value = self.res_can_ob_email
|
|
self._putEvent(self.client, "%s%s" % (self.user_calendar, ics_name), event)
|
|
|
|
# 2. create a second event overlapping the first one
|
|
event = self._newEvent(summary="Test can overbook - overlap", uid="test can overbook - overlap")
|
|
organizer = event.vevent.add('organizer')
|
|
organizer.cn_param = self.user_name
|
|
organizer.value = self.user_email
|
|
attendee = event.vevent.add('attendee')
|
|
attendee.cn_param = self.res_can_ob_name
|
|
attendee.rsvp_param = "TRUE"
|
|
attendee.partstat_param = "NEEDS-ACTION"
|
|
attendee.value = self.res_can_ob_email
|
|
|
|
# put the event - should be fine since we can overbook this one
|
|
self._putEvent(self.client, "%s%s" % (self.user_calendar, ob_ics_name), event)
|
|
|
|
|
|
def testInvitationDelegation(self):
|
|
""" invitation delegation """
|
|
|
|
# the invitation must not exist
|
|
self._deleteEvent(self.client,
|
|
"%stest-delegation.ics" % self.user_calendar, None)
|
|
self._deleteEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_calendar, None)
|
|
self._deleteEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_delegate_calendar,
|
|
None)
|
|
|
|
# 1. org -> attendee => org: 1, attendee: 1 (pst=N-A), delegate: 0
|
|
|
|
invitation = self._newEvent()
|
|
invitation.add("method").value = "REQUEST"
|
|
organizer = invitation.vevent.add('organizer')
|
|
organizer.cn_param = self.user_name
|
|
organizer.value = self.user_email
|
|
attendee = invitation.vevent.add('attendee')
|
|
attendee.cn_param = self.attendee1_name
|
|
attendee.rsvp_param = "TRUE"
|
|
attendee.partstat_param = "NEEDS-ACTION"
|
|
attendee.value = self.attendee1_email
|
|
|
|
self._postEvent(self.client, self.user_calendar, invitation,
|
|
self.user_email, [self.attendee1_email])
|
|
del invitation.method
|
|
self._putEvent(self.client,
|
|
"%stest-delegation.ics" % self.user_calendar,
|
|
invitation)
|
|
|
|
att_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics"
|
|
% self.attendee1_calendar)
|
|
self._compareAttendees(att_inv, invitation)
|
|
|
|
# 2. attendee delegates to delegate
|
|
# => org: 1 (updated), attendee: 1 (updated,pst=D),
|
|
# delegate: 1 (new,pst=N-A)
|
|
|
|
invitation.add("method").value = "REQUEST"
|
|
attendee1 = invitation.vevent.attendee
|
|
attendee1.partstat_param = "DELEGATED"
|
|
attendee1.delegated_to_param = self.attendee1_delegate_email
|
|
delegate = invitation.vevent.add('attendee')
|
|
delegate.delegated_from_param = self.attendee1_email
|
|
delegate.cn_param = self.attendee1_delegate_name
|
|
delegate.rsvp_param = "TRUE"
|
|
delegate.partstat_param = "NEEDS-ACTION"
|
|
delegate.value = self.attendee1_delegate_email
|
|
|
|
self._postEvent(self.client,
|
|
self.attendee1_calendar, invitation,
|
|
self.attendee1_email, [self.attendee1_delegate_email])
|
|
invitation.method.value = "REPLY"
|
|
self._postEvent(self.client,
|
|
self.attendee1_calendar, invitation,
|
|
self.attendee1_email, [self.user_email])
|
|
del invitation.method
|
|
self._putEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_calendar,
|
|
invitation, 204)
|
|
|
|
del_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics"
|
|
% self.attendee1_delegate_calendar)
|
|
self._compareAttendees(del_inv, invitation)
|
|
org_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics" % self.user_calendar)
|
|
self._compareAttendees(org_inv, invitation)
|
|
|
|
# 3. delegate accepts
|
|
# => org: 1 (updated), attendee: 1 (updated,pst=D),
|
|
# delegate: 1 (accepted,pst=A)
|
|
|
|
invitation.add("method").value = "REPLY"
|
|
delegate.partstat_param = "ACCEPTED"
|
|
self._postEvent(self.client,
|
|
self.attendee1_delegate_calendar, invitation,
|
|
self.attendee1_delegate_email, [self.user_email, self.attendee1_email])
|
|
del invitation.method
|
|
self._putEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_delegate_calendar,
|
|
invitation, 204)
|
|
|
|
org_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics" % self.user_calendar)
|
|
self._compareAttendees(org_inv, invitation)
|
|
att_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_calendar)
|
|
self._compareAttendees(att_inv, invitation)
|
|
|
|
# 4. attendee accepts
|
|
# => org: 1 (updated), attendee: 1 (updated,pst=A),
|
|
# delegate: 0 (cancelled, deleted)
|
|
|
|
cancellation = vobject.iCalendar()
|
|
cancellation.copy(invitation)
|
|
cancellation.add("method").value = "CANCEL"
|
|
cancellation.vevent.sequence.value = "1"
|
|
self._postEvent(self.client,
|
|
self.attendee1_calendar, cancellation,
|
|
self.attendee1_email, [self.attendee1_delegate_email])
|
|
|
|
attendee1 = invitation.vevent.attendee
|
|
attendee1.partstat_param = "ACCEPTED"
|
|
del attendee1.delegated_to_param
|
|
invitation.add("method").value = "REPLY"
|
|
invitation.vevent.remove(delegate)
|
|
self._postEvent(self.client,
|
|
self.attendee1_calendar, invitation,
|
|
self.attendee1_email, [self.user_email])
|
|
|
|
del invitation.method
|
|
self._putEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_calendar,
|
|
invitation, 204)
|
|
|
|
org_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics" % self.user_calendar)
|
|
self._compareAttendees(org_inv, invitation)
|
|
|
|
del_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_delegate_calendar, 404)
|
|
|
|
# 5. org updates inv.
|
|
# => org: 1 (updated), attendee: 1 (updated), delegate: 0
|
|
|
|
invitation.add("method").value = "REQUEST"
|
|
invitation.vevent.summary.value = "Updated invitation"
|
|
invitation.vevent.sequence.value = "1"
|
|
attendee.partstat_param = "NEEDS-ACTION"
|
|
now = datetime.datetime.now()
|
|
invitation.vevent.last_modified.value = now
|
|
invitation.vevent.dtstamp.value = now
|
|
|
|
self._postEvent(self.client, self.user_calendar, invitation,
|
|
self.user_email, [self.attendee1_email])
|
|
|
|
del invitation.method
|
|
self._putEvent(self.client,
|
|
"%stest-delegation.ics" % self.user_calendar,
|
|
invitation, 204)
|
|
|
|
att_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_calendar)
|
|
self._compareAttendees(att_inv, invitation)
|
|
|
|
# 6. attendee delegates to delegate
|
|
# => org: 1 (updated), attendee: 1 (updated), delegate: 1 (new)
|
|
|
|
invitation.add("method").value = "REQUEST"
|
|
attendee1.partstat_param = "DELEGATED"
|
|
attendee1.delegated_to_param = self.attendee1_delegate_email
|
|
|
|
delegate = invitation.vevent.add('attendee')
|
|
delegate.delegated_from_param = self.attendee1_email
|
|
delegate.cn_param = self.attendee1_delegate_name
|
|
delegate.rsvp_param = "TRUE"
|
|
delegate.partstat_param = "NEEDS-ACTION"
|
|
delegate.value = self.attendee1_delegate_email
|
|
|
|
self._postEvent(self.client,
|
|
self.attendee1_calendar, invitation,
|
|
self.attendee1_email, [self.attendee1_delegate_email])
|
|
invitation.method.value = "REPLY"
|
|
self._postEvent(self.client,
|
|
self.attendee1_calendar, invitation,
|
|
self.attendee1_email, [self.user_email])
|
|
del invitation.method
|
|
self._putEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_calendar,
|
|
invitation, 204)
|
|
|
|
org_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics" % self.user_calendar)
|
|
self._compareAttendees(org_inv, invitation)
|
|
del_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics"
|
|
% self.attendee1_delegate_calendar)
|
|
self._compareAttendees(del_inv, invitation)
|
|
|
|
# 7. delegate accepts
|
|
# => org: 1 (updated), attendee: 1 (updated), delegate: 1 (accepted)
|
|
|
|
invitation.add("method").value = "REPLY"
|
|
delegate.partstat_param = "ACCEPTED"
|
|
self._postEvent(self.client,
|
|
self.attendee1_delegate_calendar, invitation,
|
|
self.attendee1_delegate_email, [self.user_email,
|
|
self.attendee1_email])
|
|
del invitation.method
|
|
self._putEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_delegate_calendar,
|
|
invitation, 204)
|
|
|
|
org_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics" % self.user_calendar)
|
|
self._compareAttendees(org_inv, invitation)
|
|
att_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_calendar)
|
|
self._compareAttendees(att_inv, invitation)
|
|
|
|
# 8. org updates inv.
|
|
# => org: 1 (updated), attendee: 1 (updated,partstat unchanged),
|
|
# delegate: 1 (updated,partstat reset)
|
|
|
|
invitation.add("method").value = "REQUEST"
|
|
now = datetime.datetime.now()
|
|
invitation.vevent.last_modified.value = now
|
|
invitation.vevent.dtstamp.value = now
|
|
invitation.vevent.summary.value = "Updated invitation (again)"
|
|
invitation.vevent.sequence.value = "2"
|
|
delegate.partstat_param = "NEEDS-ACTION"
|
|
|
|
self._postEvent(self.client, self.user_calendar, invitation,
|
|
self.user_email, [self.attendee1_email, self.attendee1_delegate_email])
|
|
|
|
del invitation.method
|
|
self._putEvent(self.client,
|
|
"%stest-delegation.ics" % self.user_calendar,
|
|
invitation, 204)
|
|
|
|
att_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_calendar)
|
|
self._compareAttendees(att_inv, invitation)
|
|
del_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_calendar)
|
|
self._compareAttendees(del_inv, invitation)
|
|
|
|
# 9. org cancels invitation
|
|
# => org: 1 (updated), attendee: 0 (cancelled, deleted),
|
|
# delegate: 0 (cancelled, deleted)
|
|
|
|
invitation.add("method").value = "CANCEL"
|
|
now = datetime.datetime.now()
|
|
invitation.vevent.last_modified.value = now
|
|
invitation.vevent.dtstamp.value = now
|
|
invitation.vevent.summary.value = "Cancelled invitation (again)"
|
|
invitation.vevent.sequence.value = "3"
|
|
|
|
self._postEvent(self.client, self.user_calendar, invitation,
|
|
self.user_email, [self.attendee1_email, self.attendee1_delegate_email])
|
|
|
|
del invitation.method
|
|
invitation.vevent.remove(attendee)
|
|
invitation.vevent.remove(delegate)
|
|
self._putEvent(self.client,
|
|
"%stest-delegation.ics" % self.user_calendar,
|
|
invitation, 204)
|
|
|
|
att_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_calendar, 404)
|
|
del_inv = self._getEvent(self.client,
|
|
"%stest-delegation.ics" % self.attendee1_delegate_calendar, 404)
|
|
|
|
if __name__ == "__main__":
|
|
sogotests.runTests()
|