def test_calendar_query_bogus_timezone_id(self): """ Partial retrieval of events by time range. (CalDAV-access-09, section 7.6.1) """ TimezoneCache.create() self.addCleanup(TimezoneCache.clear) calendar_properties = ( davxml.GETETag(), caldavxml.CalendarData(), ) query_timerange = caldavxml.TimeRange( start="%04d1001T000000Z" % (DateTime.getToday().getYear(), ), end="%04d1101T000000Z" % (DateTime.getToday().getYear(), ), ) query = caldavxml.CalendarQuery( davxml.PropertyContainer(*calendar_properties), caldavxml.Filter( caldavxml.ComponentFilter( caldavxml.ComponentFilter( query_timerange, name="VEVENT", ), name="VCALENDAR", ), ), caldavxml.TimeZoneID.fromString("bogus"), ) result = yield self.calendar_query( query, got_xml=None, expected_code=responsecode.FORBIDDEN) self.assertTrue("valid-timezone" in result)
def readProperty(self, property, request): if type(property) is tuple: qname = property else: qname = property.qname() namespace, name = qname if namespace == dav_namespace: if name == "resourcetype": result = davxml.ResourceType.empty # @UndefinedVariable return result elif name == "getetag": result = davxml.GETETag( ETag(hashlib.md5(self.vCardText()).hexdigest()).generate()) return result elif name == "getcontenttype": mimeType = MimeType('text', 'vcard', {}) result = davxml.GETContentType(generateContentType(mimeType)) return result elif name == "getcontentlength": result = davxml.GETContentLength.fromString( str(len(self.vCardText()))) return result elif name == "getlastmodified": if self.vCard().hasProperty("REV"): modDatetime = parse_date(self.vCard().propertyValue("REV")) else: modDatetime = datetime.datetime.utcnow() # strip time zone because time zones are unimplemented in davxml.GETLastModified.fromDate d = modDatetime.date() t = modDatetime.time() modDatetimeNoTZ = datetime.datetime(d.year, d.month, d.day, t.hour, t.minute, t.second, t.microsecond, None) result = davxml.GETLastModified.fromDate(modDatetimeNoTZ) return result elif name == "creationdate": if self.vCard().hasProperty( "REV"): # use modification date property if it exists creationDatetime = parse_date( self.vCard().propertyValue("REV")) else: creationDatetime = datetime.datetime.utcnow() result = davxml.CreationDate.fromDate(creationDatetime) return result elif name == "displayname": # AddressBook.app uses N. Use FN or UID instead? result = davxml.DisplayName.fromString( self.vCard().propertyValue("N")) return result elif namespace == twisted_dav_namespace: return super(ABDirectoryQueryResult, self).readProperty(property, request) return self._directoryBackedAddressBook.readProperty(property, request)
def test_calendar_query_timezone(self): """ Partial retrieval of events by time range. (CalDAV-access-09, section 7.6.1) """ TimezoneCache.create() self.addCleanup(TimezoneCache.clear) tzid1 = "Etc/GMT+1" tz1 = Component(None, pycalendar=readVTZ(tzid1)) calendar_properties = ( davxml.GETETag(), caldavxml.CalendarData(), ) query_timerange = caldavxml.TimeRange( start="%04d1001T000000Z" % (DateTime.getToday().getYear(), ), end="%04d1101T000000Z" % (DateTime.getToday().getYear(), ), ) query = caldavxml.CalendarQuery( davxml.PropertyContainer(*calendar_properties), caldavxml.Filter( caldavxml.ComponentFilter( caldavxml.ComponentFilter( query_timerange, name="VEVENT", ), name="VCALENDAR", ), ), caldavxml.TimeZone.fromCalendar(tz1), ) def got_xml(doc): if not isinstance(doc.root_element, davxml.MultiStatus): self.fail( "REPORT response XML root element is not multistatus: %r" % (doc.root_element, )) return self.calendar_query(query, got_xml)
def test_calendar_query_wrong_timezone_elements(self): """ Partial retrieval of events by time range. (CalDAV-access-09, section 7.6.1) """ TimezoneCache.create() self.addCleanup(TimezoneCache.clear) tzid1 = "Etc/GMT+1" tz1 = Component(None, pycalendar=readVTZ(tzid1)) calendar_properties = ( davxml.GETETag(), caldavxml.CalendarData(), ) query_timerange = caldavxml.TimeRange( start="%04d1001T000000Z" % (DateTime.getToday().getYear(), ), end="%04d1101T000000Z" % (DateTime.getToday().getYear(), ), ) query = caldavxml.CalendarQuery( davxml.PropertyContainer(*calendar_properties), caldavxml.Filter( caldavxml.ComponentFilter( caldavxml.ComponentFilter( query_timerange, name="VEVENT", ), name="VCALENDAR", ), ), caldavxml.TimeZone.fromCalendar(tz1), ) query.children += (caldavxml.TimeZoneID.fromString(tzid1), ) result = yield self.calendar_query( query, got_xml=None, expected_code=responsecode.BAD_REQUEST) self.assertTrue("Only one of" in result)
def simple_event_multiget(self, cal_uri, okuids, baduids, data=None, no_init=False, withData=True): cal_uri = joinURL("/calendars/users/wsanchez", cal_uri) props = (davxml.GETETag(), ) if withData: props += (caldavxml.CalendarData(), ) children = [] children.append(davxml.PropertyContainer(*props)) okhrefs = [joinURL(cal_uri, x + ".ics") for x in okuids] badhrefs = [joinURL(cal_uri, x + ".ics") for x in baduids] for href in okhrefs + badhrefs: children.append(davxml.HRef.fromString(href)) query = caldavxml.CalendarMultiGet(*children) def got_xml(doc): if not isinstance(doc.root_element, davxml.MultiStatus): self.fail( "REPORT response XML root element is not multistatus: %r" % (doc.root_element, )) for response in doc.root_element.childrenOfType( davxml.PropertyStatusResponse): href = str(response.childOfType(davxml.HRef)) for propstat in response.childrenOfType(davxml.PropertyStatus): status = propstat.childOfType(davxml.Status) if status.code != responsecode.OK: self.fail( "REPORT failed (status %s) to locate properties: %r" % (status.code, href)) properties = propstat.childOfType( davxml.PropertyContainer).children for property in properties: qname = property.qname() if qname == (davxml.dav_namespace, "getetag"): continue if qname != (caldavxml.caldav_namespace, "calendar-data"): self.fail( "Response included unexpected property %r" % (property, )) result_calendar = property.calendar() if result_calendar is None: self.fail( "Invalid response CalDAV:calendar-data: %r" % (property, )) uid = result_calendar.resourceUID() if uid in okuids: okuids.remove(uid) else: self.fail("Got calendar for unexpected UID %r" % (uid, )) if data: original_calendar = ical.Component.fromString( data[uid]) else: original_filename = file( os.path.join(self.holidays_dir, uid + ".ics")) original_calendar = ical.Component.fromStream( original_filename) self.assertEqual(result_calendar, original_calendar) for response in doc.root_element.childrenOfType( davxml.StatusResponse): href = str(response.childOfType(davxml.HRef)) propstatus = response.childOfType(davxml.PropertyStatus) if propstatus is not None: status = propstatus.childOfType(davxml.Status) else: status = response.childOfType(davxml.Status) if status.code != responsecode.OK: if href in okhrefs: self.fail( "REPORT failed (status %s) to locate properties: %r" % (status.code, href)) else: if href in badhrefs: badhrefs.remove(href) continue else: self.fail("Got unexpected href %r" % (href, )) if withData and (len(okuids) + len(badhrefs)): self.fail("Some components were not returned: %r, %r" % (okuids, badhrefs)) return self.calendar_query(cal_uri, query, got_xml, data, no_init)
def simple_vcard_query(self, vcard_uri, vcard_filter, uids, withData=True, limit=None): vcard_uri = joinURL("/addressbooks/users/wsanchez", vcard_uri) props = ( davxml.GETETag(), ) if withData: props += ( carddavxml.AddressData(), ) query = carddavxml.AddressBookQuery( davxml.PropertyContainer(*props), carddavxml.Filter( vcard_filter, ), ) def got_xml(doc): if not isinstance(doc.root_element, davxml.MultiStatus): self.fail("REPORT response XML root element is not multistatus: %r" % (doc.root_element,)) count = 0 for response in doc.root_element.childrenOfType(davxml.PropertyStatusResponse): for propstat in response.childrenOfType(davxml.PropertyStatus): status = propstat.childOfType(davxml.Status) if status.code == responsecode.INSUFFICIENT_STORAGE_SPACE and limit is not None: continue if status.code != responsecode.OK: self.fail("REPORT failed (status %s) to locate properties: %r" % (status.code, propstat)) elif limit is not None: count += 1 continue properties = propstat.childOfType(davxml.PropertyContainer).children for property in properties: qname = property.qname() if qname == (davxml.dav_namespace, "getetag"): continue if qname != (carddavxml.carddav_namespace, "address-data"): self.fail("Response included unexpected property %r" % (property,)) result_addressbook = property.address() if result_addressbook is None: self.fail("Invalid response CardDAV:address-data: %r" % (property,)) uid = result_addressbook.resourceUID() if uid in uids: uids.remove(uid) else: self.fail("Got addressbook for unexpected UID %r" % (uid,)) original_filename = file(os.path.join(self.vcards_dir, uid + ".vcf")) original_addressbook = vcard.Component.fromStream(original_filename) self.assertEqual(result_addressbook, original_addressbook) if limit is not None and count != limit: self.fail("Wrong number of limited results: %d" % (count,)) return self.addressbook_query(vcard_uri, query, got_xml)
def test_calendar_query_time_range(self): """ Partial retrieval of events by time range. (CalDAV-access-09, section 7.6.1) """ calendar_properties = ( davxml.GETETag(), caldavxml.CalendarData( caldavxml.CalendarComponent( caldavxml.AllProperties(), caldavxml.CalendarComponent( caldavxml.Property(name="X-ABC-GUID"), caldavxml.Property(name="UID"), caldavxml.Property(name="DTSTART"), caldavxml.Property(name="DTEND"), caldavxml.Property(name="DURATION"), caldavxml.Property(name="EXDATE"), caldavxml.Property(name="EXRULE"), caldavxml.Property(name="RDATE"), caldavxml.Property(name="RRULE"), caldavxml.Property(name="LOCATION"), caldavxml.Property(name="SUMMARY"), name="VEVENT", ), caldavxml.CalendarComponent( caldavxml.AllProperties(), caldavxml.AllComponents(), name="VTIMEZONE", ), name="VCALENDAR", ), ), ) query_timerange = caldavxml.TimeRange( start="%04d1001T000000Z" % (DateTime.getToday().getYear(), ), end="%04d1101T000000Z" % (DateTime.getToday().getYear(), ), ) query = caldavxml.CalendarQuery( davxml.PropertyContainer(*calendar_properties), caldavxml.Filter( caldavxml.ComponentFilter( caldavxml.ComponentFilter( query_timerange, name="VEVENT", ), name="VCALENDAR", ), ), ) def got_xml(doc): if not isinstance(doc.root_element, davxml.MultiStatus): self.fail( "REPORT response XML root element is not multistatus: %r" % (doc.root_element, )) for response in doc.root_element.childrenOfType( davxml.PropertyStatusResponse): properties_to_find = [p.qname() for p in calendar_properties] for propstat in response.childrenOfType(davxml.PropertyStatus): status = propstat.childOfType(davxml.Status) properties = propstat.childOfType( davxml.PropertyContainer).children if status.code != responsecode.OK: self.fail( "REPORT failed (status %s) to locate properties: %r" % (status.code, properties)) for property in properties: qname = property.qname() if qname in properties_to_find: properties_to_find.remove(qname) else: self.fail( "REPORT found property we didn't ask for: %r" % (property, )) if isinstance(property, caldavxml.CalendarData): cal = property.calendar() instances = cal.expandTimeRanges( query_timerange.end) vevents = [ x for x in cal.subcomponents() if x.name() == "VEVENT" ] if not TimeRange(query_timerange).matchinstance( vevents[0], instances): self.fail( "REPORT property %r returned calendar %s outside of request time range %r" % (property, property.calendar, query_timerange)) return self.calendar_query(query, got_xml)
def simple_event_query(self, event_filter, uids, withData=True): props = (davxml.GETETag(), ) if withData: props += (caldavxml.CalendarData(), ) query = caldavxml.CalendarQuery( davxml.PropertyContainer(*props), caldavxml.Filter( caldavxml.ComponentFilter( caldavxml.ComponentFilter( event_filter, name="VEVENT", ), name="VCALENDAR", ), ), ) def got_xml(doc): if not isinstance(doc.root_element, davxml.MultiStatus): self.fail( "REPORT response XML root element is not multistatus: %r" % (doc.root_element, )) for response in doc.root_element.childrenOfType( davxml.PropertyStatusResponse): for propstat in response.childrenOfType(davxml.PropertyStatus): status = propstat.childOfType(davxml.Status) if status.code != responsecode.OK: self.fail( "REPORT failed (status %s) to locate properties: %r" % (status.code, propstat)) properties = propstat.childOfType( davxml.PropertyContainer).children for property in properties: qname = property.qname() if qname == (davxml.dav_namespace, "getetag"): continue if qname != (caldavxml.caldav_namespace, "calendar-data"): self.fail( "Response included unexpected property %r" % (property, )) result_calendar = property.calendar() if result_calendar is None: self.fail( "Invalid response CalDAV:calendar-data: %r" % (property, )) uid = result_calendar.resourceUID() if uid in uids: uids.remove(uid) else: self.fail("Got calendar for unexpected UID %r" % (uid, )) original_filename = file( os.path.join(self.holidays_dir, uid + ".ics")) original_calendar = ical.Component.fromStream( original_filename) self.assertEqual(result_calendar, original_calendar) return self.calendar_query(query, got_xml)