Example #1
0
    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("/.."), "/")
Example #3
0
    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),
            ))
Example #4
0
    # 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,
Example #5
0
    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,