def writeProperty(self, property, request): assert isinstance(property, davxml.WebDAVElement) # Strictly speaking CS:calendar-availability is a live property in the sense that the # server enforces what can be stored, however it need not actually # exist so we cannot list it in liveProperties on this resource, since its # its presence there means that hasProperty will always return True for it. if property.qname() == customxml.CalendarAvailability.qname(): if not property.valid(): raise HTTPError(ErrorResponse( responsecode.CONFLICT, (caldav_namespace, "valid-calendar-data"), description="Invalid property" )) yield self.parent._newStoreHome.setAvailability(property.calendar()) returnValue(None) elif property.qname() == caldavxml.CalendarFreeBusySet.qname(): # Verify that the calendars added in the PROPPATCH are valid. We do not check # whether existing items in the property are still valid - only new ones. property.children = [davxml.HRef(normalizeURL(str(href))) for href in property.children] new_calendars = set([str(href) for href in property.children]) old_calendars = set() for cal in (yield self.parent._newStoreHome.calendars()): if cal.isUsedForFreeBusy(): old_calendars.add(HRef(joinURL(self.parent.url(), cal.name()))) added_calendars = new_calendars.difference(old_calendars) for href in added_calendars: cal = (yield request.locateResource(str(href))) if cal is None or not cal.exists() or not isCalendarCollectionResource(cal): # Validate that href's point to a valid calendar. raise HTTPError(ErrorResponse( responsecode.CONFLICT, (caldav_namespace, "valid-calendar-url"), "Invalid URI", )) # Remove old ones for href in old_calendars.difference(new_calendars): cal = (yield request.locateResource(str(href))) if cal is not None and cal.exists() and isCalendarCollectionResource(cal) and cal._newStoreObject.isUsedForFreeBusy(): yield cal._newStoreObject.setUsedForFreeBusy(False) # Add new ones for href in new_calendars: cal = (yield request.locateResource(str(href))) if cal is not None and cal.exists() and isCalendarCollectionResource(cal) and not cal._newStoreObject.isUsedForFreeBusy(): yield cal._newStoreObject.setUsedForFreeBusy(True) returnValue(None) elif property.qname() in (caldavxml.ScheduleDefaultCalendarURL.qname(), customxml.ScheduleDefaultTasksURL.qname()): yield self.writeDefaultCalendarProperty(request, property) returnValue(None) yield super(ScheduleInboxResource, self).writeProperty(property, request)
def test_normalizeURL(self): """ normalizeURL() """ self.assertEquals(util.normalizeURL("http://server//foo"), "http://server/foo") self.assertEquals(util.normalizeURL("http://server/foo/.."), "http://server/") self.assertEquals(util.normalizeURL("/foo/bar/..//"), "/foo") self.assertEquals(util.normalizeURL("/foo/bar/.//"), "/foo/bar") self.assertEquals(util.normalizeURL("//foo///bar/../baz"), "/foo/baz") self.assertEquals(util.normalizeURL("//foo///bar/./baz"), "/foo/bar/baz") self.assertEquals(util.normalizeURL("///../"), "/") self.assertEquals(util.normalizeURL("/.."), "/")
def writeDefaultCalendarProperty(self, request, property): """ Write either the default VEVENT or VTODO calendar property, validating and canonicalizing the value """ if property.qname() == caldavxml.ScheduleDefaultCalendarURL.qname(): ctype = "VEVENT" error_element = (caldav_namespace, "valid-schedule-default-calendar-URL") elif property.qname() == customxml.ScheduleDefaultTasksURL.qname(): ctype = "VTODO" error_element = (calendarserver_namespace, "valid-schedule-default-tasks-URL") else: returnValue(None) # Verify that the calendar added in the PROPPATCH is valid. property.children = [davxml.HRef(normalizeURL(str(href))) for href in property.children] new_calendar = [str(href) for href in property.children] cal = None if len(new_calendar) == 1: cal = (yield request.locateResource(str(new_calendar[0]))) else: raise HTTPError(ErrorResponse( responsecode.BAD_REQUEST, error_element, "Invalid HRef in property", )) if cal is None or not cal.exists(): raise HTTPError(ErrorResponse( responsecode.BAD_REQUEST, error_element, "HRef is not a valid calendar", )) try: # Now set it on the new store object yield self.parent._newStoreHome.setDefaultCalendar(cal._newStoreObject, ctype) except InvalidDefaultCalendar as e: raise HTTPError(ErrorResponse( responsecode.CONFLICT, error_element, str(e), ))
# By policy we will never allow a depth:infinity propfind if depth == "infinity": raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, davxml.PropfindFiniteDepth())) # Look for Prefer header first, then try Brief prefer = request.headers.getHeader("prefer", {}) returnMinimal = any([key == "return" and value == "minimal" for key, value, _ignore_args in prefer]) noRoot = any([key == "depth-noroot" and value is None for key, value, _ignore_args in prefer]) if not returnMinimal: returnMinimal = request.headers.getHeader("brief", False) xml_responses = [] # FIXME: take advantage of the new generative properties of findChildren my_url = normalizeURL(request_uri) if self.isCollection() and not my_url.endswith("/"): my_url += "/" # Do some optimization of access control calculation by determining any inherited ACLs outside of # the child resource loop and supply those to the checkPrivileges on each child. filtered_aces = (yield self.inheritedACEsforChildren(request)) if depth in ("1", "infinity") and noRoot: resources = [] else: resources = [(responsecode.OK, self, my_url)] yield self.findChildrenFaster( depth, request,
returnMinimal = any([ key == "return" and value == "minimal" for key, value, _ignore_args in prefer ]) noRoot = any([ key == "depth-noroot" and value is None for key, value, _ignore_args in prefer ]) if not returnMinimal: returnMinimal = request.headers.getHeader("brief", False) xml_responses = [] # FIXME: take advantage of the new generative properties of findChildren my_url = normalizeURL(request_uri) if self.isCollection() and not my_url.endswith("/"): my_url += "/" # Do some optimization of access control calculation by determining any inherited ACLs outside of # the child resource loop and supply those to the checkPrivileges on each child. filtered_aces = (yield self.inheritedACEsforChildren(request)) if depth in ("1", "infinity") and noRoot: resources = [] else: resources = [(responsecode.OK, self, my_url)] yield self.findChildrenFaster( depth, request,