def doPOSTGet(self, request):
        """
        Return the specified timezone data.
        """

        tzid = request.args.get("tzid", ())
        if len(tzid) != 1:
            raise HTTPError(ErrorResponse(
                responsecode.BAD_REQUEST,
                (calendarserver_namespace, "valid-timezone"),
                "Invalid tzid query parameter",
            ))
        tzid = tzid[0]

        try:
            tzdata = readTZ(tzid)
        except TimezoneException:
            raise HTTPError(ErrorResponse(
                responsecode.NOT_FOUND,
                (calendarserver_namespace, "timezone-available"),
                "Timezone not found",
            ))

        response = Response()
        response.stream = MemoryStream(tzdata)
        response.headers.setHeader("content-type", MimeType.fromString("text/calendar; charset=utf-8"))
        return response
Esempio n. 2
0
    def doPOSTGet(self, request):
        """
        Return the specified timezone data.
        """

        tzid = request.args.get("tzid", ())
        if len(tzid) != 1:
            raise HTTPError(
                ErrorResponse(
                    responsecode.BAD_REQUEST,
                    (calendarserver_namespace, "valid-timezone"),
                    "Invalid tzid query parameter",
                ))
        tzid = tzid[0]

        try:
            tzdata = readTZ(tzid)
        except TimezoneException:
            raise HTTPError(
                ErrorResponse(
                    responsecode.NOT_FOUND,
                    (calendarserver_namespace, "timezone-available"),
                    "Timezone not found",
                ))

        response = Response()
        response.stream = MemoryStream(tzdata)
        response.headers.setHeader(
            "content-type",
            MimeType.fromString("text/calendar; charset=utf-8"))
        return response
Esempio n. 3
0
    def render(self, request):
        response = Response()
        response.stream = MemoryStream((yield self.iCalendarZipArchiveData()))

        # FIXME: Use content-encoding instead?
        response.headers.setHeader(b"content-type",
                                   MimeType.fromString(b"application/zip"))

        returnValue(response)
Esempio n. 4
0
    def render(self, request):
        response = Response()
        response.stream = MemoryStream((yield self.iCalendarZipArchiveData()))

        # FIXME: Use content-encoding instead?
        response.headers.setHeader(
            b"content-type",
            MimeType.fromString(b"application/zip")
        )

        returnValue(response)
Esempio n. 5
0
    def render(self, request):
        # yield self.handleQueryArguments(request)

        htmlContent = yield flattenString(request, self.elementClass())

        response = Response()
        response.stream = MemoryStream(htmlContent)
        response.headers.setHeader(
            b"content-type", MimeType.fromString(b"text/html; charset=utf-8"))

        returnValue(response)
Esempio n. 6
0
    def render(self, request):
        # yield self.handleQueryArguments(request)

        htmlContent = yield flattenString(request, self.elementClass())

        response = Response()
        response.stream = MemoryStream(htmlContent)
        response.headers.setHeader(
            b"content-type", MimeType.fromString(b"text/html; charset=utf-8")
        )

        returnValue(response)
Esempio n. 7
0
    def render(self, request):
        lastID = request.headers.getRawHeaders(u"last-event-id")

        response = Response()
        response.stream = EventStream(self._eventDecoder, self._events, lastID)
        response.headers.setHeader(b"content-type", MimeType.fromString(b"text/event-stream"))

        # Keep track of the event streams
        def cleanupFilter(_request, _response):
            self._streams.remove(response.stream)
            return _response

        request.addResponseFilter(cleanupFilter)
        self._streams.add(response.stream)

        return response
Esempio n. 8
0
    def render(self, request):
        lastID = request.headers.getRawHeaders(u"last-event-id")

        response = Response()
        response.stream = EventStream(self._eventDecoder, self._events, lastID)
        response.headers.setHeader(b"content-type",
                                   MimeType.fromString(b"text/event-stream"))

        # Keep track of the event streams
        def cleanupFilter(_request, _response):
            self._streams.remove(response.stream)
            return _response

        # request.addResponseFilter(cleanupFilter)
        self._streams.add(response.stream)

        return response
Esempio n. 9
0
 def render(self, request):
     """
     Create a L{WebAdminPage} to render HTML content for this request, and
     return a response.
     """
     resourceId = request.args.get('resourceId', [''])[0]
     if resourceId:
         record = yield recordForPrincipalID(self.directory, resourceId)
         yield self.resourceActions(request, record)
     htmlContent = yield flattenString(request, WebAdminPage(self))
     response = Response()
     response.stream = MemoryStream(htmlContent)
     for (header, value) in (
         ("content-type", self.contentType()),
         ("content-encoding", self.contentEncoding()),
     ):
         if value is not None:
             response.headers.setHeader(header, value)
     returnValue(response)
Esempio n. 10
0
 def render(self, request):
     """
     Create a L{WebAdminPage} to render HTML content for this request, and
     return a response.
     """
     resourceId = request.args.get('resourceId', [''])[0]
     if resourceId:
         principal = self.getResourceById(request, resourceId)
         yield self.resourceActions(request, principal)
     htmlContent = yield flattenString(request, WebAdminPage(self))
     response = Response()
     response.stream = MemoryStream(htmlContent)
     for (header, value) in (
             ("content-type", self.contentType()),
             ("content-encoding", self.contentEncoding()),
         ):
         if value is not None:
             response.headers.setHeader(header, value)
     returnValue(response)
    def doGet(self, request):
        """
        Return the specified timezone data.
        """

        tzids = request.args.get("tzid", ())
        if len(tzids) != 1:
            raise HTTPError(JSONResponse(
                responsecode.BAD_REQUEST,
                {
                    "error": "invalid-tzid",
                    "description": "Invalid tzid query parameter",
                },
            ))

        format = request.args.get("format", ("text/calendar",))
        if len(format) != 1 or format[0] not in self.formats:
            raise HTTPError(JSONResponse(
                responsecode.BAD_REQUEST,
                {
                    "error": "invalid-format",
                    "description": "Invalid format query parameter",
                },
            ))
        format = format[0]

        calendar = self.timezones.getTimezone(tzids[0])
        if calendar is None:
            raise HTTPError(JSONResponse(
                responsecode.NOT_FOUND,
                {
                    "error": "missing-tzid",
                    "description": "Tzid could not be found",
                }
            ))

        tzdata = calendar.getText(format=format if format != "text/plain" else None)

        response = Response()
        response.stream = MemoryStream(tzdata)
        response.headers.setHeader("content-type", MimeType.fromString("%s; charset=utf-8" % (format,)))
        return response
Esempio n. 12
0
    def actionGet(self, request, tzid):
        """
        Return the specified timezone data.
        """

        if set(request.args.keys()) - set(("start", "end",)):
            self.problemReport("invalid-action", "Invalid request-URI query parameters", responsecode.BAD_REQUEST)

        accepted_type = bestAcceptType(request.headers.getHeader("accept"), self.formats)
        if accepted_type is None:
            self.problemReport("invalid-format", "Accept header does not match available media types", responsecode.NOT_ACCEPTABLE)

        calendar = self.timezones.getTimezone(tzid)
        if calendar is None:
            self.problemReport("tzid-not-found", "Time zone identifier not found", responsecode.NOT_FOUND)

        tzdata = calendar.getText(format=accepted_type if accepted_type != "text/plain" else None)

        response = Response()
        response.stream = MemoryStream(tzdata)
        response.headers.setHeader("content-type", MimeType.fromString("%s; charset=utf-8" % (accepted_type,)))
        return response
    def actionGet(self, request, tzid):
        """
        Return the specified timezone data.
        """

        if set(request.args.keys()) - set(("start", "end",)):
            self.problemReport("invalid-action", "Invalid request-URI query parameters", responsecode.BAD_REQUEST)

        accepted_type = bestAcceptType(request.headers.getHeader("accept"), self.formats)
        if accepted_type is None:
            self.problemReport("invalid-format", "Accept header does not match available media types", responsecode.NOT_ACCEPTABLE)

        calendar = self.timezones.getTimezone(tzid)
        if calendar is None:
            self.problemReport("tzid-not-found", "Time zone identifier not found", responsecode.NOT_FOUND)

        tzdata = calendar.getText(format=accepted_type if accepted_type != "text/plain" else None)

        response = Response()
        response.stream = MemoryStream(tzdata)
        response.headers.setHeader("content-type", MimeType.fromString("%s; charset=utf-8" % (accepted_type,)))
        return response
Esempio n. 14
0
    principal = yield self.resourceOwnerPrincipal(request)
    organizer = recipient = LocalCalendarUser(principal.canonicalCalendarUserAddress(), principal.record)
    timerange = Period(timerange.start, timerange.end)
    try:
        fbresult = yield FreebusyQuery(organizer=organizer, recipient=recipient, timerange=timerange).generateAttendeeFreeBusyResponse(fbset=fbset, method=None)
    except NumberOfMatchesWithinLimits:
        log.error("Too many matching components in free-busy report")
        raise HTTPError(ErrorResponse(
            responsecode.FORBIDDEN,
            davxml.NumberOfMatchesWithinLimits(),
            "Too many components"
        ))
    except TimeRangeLowerLimit, e:
        raise HTTPError(ErrorResponse(
            responsecode.FORBIDDEN,
            caldavxml.MinDateTime(),
            "Time-range value too far in the past. Must be on or after %s." % (str(e.limit),)
        ))
    except TimeRangeUpperLimit, e:
        raise HTTPError(ErrorResponse(
            responsecode.FORBIDDEN,
            caldavxml.MaxDateTime(),
            "Time-range value too far in the future. Must be on or before %s." % (str(e.limit),)
        ))

    response = Response()
    response.stream = MemoryStream(fbresult.getText(accepted_type))
    response.headers.setHeader("content-type", MimeType.fromString("%s; charset=utf-8" % (accepted_type,)))

    returnValue(response)
    except NumberOfMatchesWithinLimits:
        log.error("Too many matching components in free-busy report")
        raise HTTPError(
            ErrorResponse(responsecode.FORBIDDEN, davxml.NumberOfMatchesWithinLimits(), "Too many components")
        )
    except TimeRangeLowerLimit, e:
        raise HTTPError(
            ErrorResponse(
                responsecode.FORBIDDEN,
                caldavxml.MinDateTime(),
                "Time-range value too far in the past. Must be on or after %s." % (str(e.limit),),
            )
        )
    except TimeRangeUpperLimit, e:
        raise HTTPError(
            ErrorResponse(
                responsecode.FORBIDDEN,
                caldavxml.MaxDateTime(),
                "Time-range value too far in the future. Must be on or before %s." % (str(e.limit),),
            )
        )

    # Now build a new calendar object with the free busy info we have
    fbcalendar = report_common.buildFreeBusyResult(fbinfo, timerange)

    response = Response()
    response.stream = MemoryStream(fbcalendar.getText(accepted_type))
    response.headers.setHeader("content-type", MimeType.fromString("%s; charset=utf-8" % (accepted_type,)))

    returnValue(response)
Esempio n. 16
0
    def _processFBURL(self, request):
        #
        # Check authentication and access controls
        #
        yield self.authorize(request, (davxml.Read(),))

        # Extract query parameters from the URL
        args = ('start', 'end', 'duration', 'token', 'format', 'user',)
        for arg in args:
            setattr(self, arg, request.args.get(arg, [None])[0])

        # Some things we do not handle
        if self.token or self.user:
            raise HTTPError(ErrorResponse(
                responsecode.NOT_ACCEPTABLE,
                (calendarserver_namespace, "supported-query-parameter"),
                "Invalid query parameter",
            ))

        # Check format
        if self.format:
            self.format = self.format.split(";")[0]
            if self.format not in ("text/calendar", "text/plain"):
                raise HTTPError(ErrorResponse(
                    responsecode.NOT_ACCEPTABLE,
                    (calendarserver_namespace, "supported-format"),
                    "Invalid return format requested",
                ))
        else:
            self.format = "text/calendar"

        # Start/end/duration must be valid iCalendar DATE-TIME UTC or DURATION values
        try:
            if self.start:
                self.start = DateTime.parseText(self.start)
                if not self.start.utc():
                    raise ValueError()
            if self.end:
                self.end = DateTime.parseText(self.end)
                if not self.end.utc():
                    raise ValueError()
            if self.duration:
                self.duration = Duration.parseText(self.duration)
        except ValueError:
            raise HTTPError(ErrorResponse(
                responsecode.BAD_REQUEST,
                (calendarserver_namespace, "valid-query-parameters"),
                "Invalid query parameters",
            ))

        # Sanity check start/end/duration

        # End and duration cannot both be present
        if self.end and self.duration:
            raise HTTPError(ErrorResponse(
                responsecode.NOT_ACCEPTABLE,
                (calendarserver_namespace, "valid-query-parameters"),
                "Invalid query parameters",
            ))

        # Duration must be positive
        if self.duration and self.duration.getTotalSeconds() < 0:
            raise HTTPError(ErrorResponse(
                responsecode.BAD_REQUEST,
                (calendarserver_namespace, "valid-query-parameters"),
                "Invalid query parameters",
            ))

        # Now fill in the missing pieces
        if self.start is None:
            self.start = DateTime.getNowUTC()
            self.start.setHHMMSS(0, 0, 0)
        if self.duration:
            self.end = self.start + self.duration
        if self.end is None:
            self.end = self.start + Duration(days=config.FreeBusyURL.TimePeriod)

        # End > start
        if self.end <= self.start:
            raise HTTPError(ErrorResponse(
                responsecode.BAD_REQUEST,
                (calendarserver_namespace, "valid-query-parameters"),
                "Invalid query parameters",
            ))

        # TODO: We should probably verify that the actual time-range is within sensible bounds (e.g. not too far in the past or future and not too long)

        # Now lookup the principal details for the targeted user
        principal = (yield self.parent.principalForRecord())

        # Pick the first mailto cu address or the first other type
        cuaddr = None
        for item in principal.calendarUserAddresses():
            if cuaddr is None:
                cuaddr = item
            if item.startswith("mailto:"):
                cuaddr = item
                break

        # Get inbox details
        inboxURL = principal.scheduleInboxURL()
        if inboxURL is None:
            raise HTTPError(StatusResponse(responsecode.INTERNAL_SERVER_ERROR, "No schedule inbox URL for principal: %s" % (principal,)))
        try:
            inbox = (yield request.locateResource(inboxURL))
        except:
            log.error("No schedule inbox for principal: {p}", p=principal)
            inbox = None
        if inbox is None:
            raise HTTPError(StatusResponse(responsecode.INTERNAL_SERVER_ERROR, "No schedule inbox for principal: %s" % (principal,)))

        organizer = recipient = LocalCalendarUser(cuaddr, principal.record)
        recipient.inbox = inbox._newStoreObject
        attendeeProp = Property("ATTENDEE", recipient.cuaddr)
        timerange = Period(self.start, self.end)

        fbresult = yield FreebusyQuery(
            organizer=organizer,
            recipient=recipient,
            attendeeProp=attendeeProp,
            timerange=timerange,
        ).generateAttendeeFreeBusyResponse()

        response = Response()
        response.stream = MemoryStream(str(fbresult))
        response.headers.setHeader("content-type", MimeType.fromString("%s; charset=utf-8" % (self.format,)))

        returnValue(response)
Esempio n. 17
0
 def render(self, request):
     response = Response()
     response.stream = MemoryStream(self.renderOutput)
     return response
Esempio n. 18
0
    def _processFBURL(self, request):
        #
        # Check authentication and access controls
        #
        yield self.authorize(request, (davxml.Read(),))

        # Extract query parameters from the URL
        args = ('start', 'end', 'duration', 'token', 'format', 'user',)
        for arg in args:
            setattr(self, arg, request.args.get(arg, [None])[0])

        # Some things we do not handle
        if self.token or self.user:
            raise HTTPError(ErrorResponse(
                responsecode.NOT_ACCEPTABLE,
                (calendarserver_namespace, "supported-query-parameter"),
                "Invalid query parameter",
            ))

        # Check format
        if self.format:
            self.format = self.format.split(";")[0]
            if self.format not in ("text/calendar", "text/plain"):
                raise HTTPError(ErrorResponse(
                    responsecode.NOT_ACCEPTABLE,
                    (calendarserver_namespace, "supported-format"),
                    "Invalid return format requested",
                ))
        else:
            self.format = "text/calendar"

        # Start/end/duration must be valid iCalendar DATE-TIME UTC or DURATION values
        try:
            if self.start:
                self.start = DateTime.parseText(self.start)
                if not self.start.utc():
                    raise ValueError()
            if self.end:
                self.end = DateTime.parseText(self.end)
                if not self.end.utc():
                    raise ValueError()
            if self.duration:
                self.duration = Duration.parseText(self.duration)
        except ValueError:
            raise HTTPError(ErrorResponse(
                responsecode.BAD_REQUEST,
                (calendarserver_namespace, "valid-query-parameters"),
                "Invalid query parameters",
            ))

        # Sanity check start/end/duration

        # End and duration cannot both be present
        if self.end and self.duration:
            raise HTTPError(ErrorResponse(
                responsecode.NOT_ACCEPTABLE,
                (calendarserver_namespace, "valid-query-parameters"),
                "Invalid query parameters",
            ))

        # Duration must be positive
        if self.duration and self.duration.getTotalSeconds() < 0:
            raise HTTPError(ErrorResponse(
                responsecode.BAD_REQUEST,
                (calendarserver_namespace, "valid-query-parameters"),
                "Invalid query parameters",
            ))

        # Now fill in the missing pieces
        if self.start is None:
            self.start = DateTime.getNowUTC()
            self.start.setHHMMSS(0, 0, 0)
        if self.duration:
            self.end = self.start + self.duration
        if self.end is None:
            self.end = self.start + Duration(days=config.FreeBusyURL.TimePeriod)

        # End > start
        if self.end <= self.start:
            raise HTTPError(ErrorResponse(
                responsecode.BAD_REQUEST,
                (calendarserver_namespace, "valid-query-parameters"),
                "Invalid query parameters",
            ))

        # TODO: We should probably verify that the actual time-range is within sensible bounds (e.g. not too far in the past or future and not too long)

        # Now lookup the principal details for the targeted user
        principal = (yield self.parent.principalForRecord())

        # Pick the first mailto cu address or the first other type
        cuaddr = None
        for item in principal.calendarUserAddresses():
            if cuaddr is None:
                cuaddr = item
            if item.startswith("mailto:"):
                cuaddr = item
                break

        # Get inbox details
        inboxURL = principal.scheduleInboxURL()
        if inboxURL is None:
            raise HTTPError(StatusResponse(responsecode.INTERNAL_SERVER_ERROR, "No schedule inbox URL for principal: %s" % (principal,)))
        try:
            inbox = (yield request.locateResource(inboxURL))
        except:
            log.error("No schedule inbox for principal: %s" % (principal,))
            inbox = None
        if inbox is None:
            raise HTTPError(StatusResponse(responsecode.INTERNAL_SERVER_ERROR, "No schedule inbox for principal: %s" % (principal,)))

        organizer = recipient = LocalCalendarUser(cuaddr, principal.record)
        recipient.inbox = inbox._newStoreObject
        attendeeProp = Property("ATTENDEE", recipient.cuaddr)
        timerange = Period(self.start, self.end)

        fbresult = yield FreebusyQuery(
            organizer=organizer,
            recipient=recipient,
            attendeeProp=attendeeProp,
            timerange=timerange,
        ).generateAttendeeFreeBusyResponse()

        response = Response()
        response.stream = MemoryStream(str(fbresult))
        response.headers.setHeader("content-type", MimeType.fromString("%s; charset=utf-8" % (self.format,)))

        returnValue(response)
Esempio n. 19
0
 def render(self, request):
     response = Response()
     response.stream = MemoryStream(self.renderOutput)
     return response
Esempio n. 20
0
 def _defer(data):
     response = Response()
     response.stream = MemoryStream(str(data))
     response.headers.setHeader("content-type", MimeType.fromString("text/calendar"))
     return response
Esempio n. 21
0
def http_GET(self, request):

    if self.exists():
        # Special sharing request on a calendar or address book
        if self.isCalendarCollection() or self.isAddressBookCollection():

            # Check for action=share
            if request.args:
                action = request.args.get("action", ("",))
                if len(action) != 1:
                    raise HTTPError(ErrorResponse(
                        responsecode.BAD_REQUEST,
                        (calendarserver_namespace, "valid-action"),
                        "Invalid action parameter: %s" % (action,),
                    ))
                action = action[0]

                dispatch = {
                    "share": self.directShare,
                }.get(action, None)

                if dispatch is None:
                    raise HTTPError(ErrorResponse(
                        responsecode.BAD_REQUEST,
                        (calendarserver_namespace, "supported-action"),
                        "Action not supported: %s" % (action,),
                    ))

                response = (yield dispatch(request))
                returnValue(response)

        else:
            # FIXME: this should be implemented in storebridge.CalendarObject.render

            # Look for calendar access restriction on existing resource.
            parentURL = parentForURL(request.uri)
            parent = (yield request.locateResource(parentURL))
            if isPseudoCalendarCollectionResource(parent):

                # Check authorization first
                yield self.authorize(request, (davxml.Read(),))

                # Accept header handling
                accepted_type = bestAcceptType(request.headers.getHeader("accept"), Component.allowedTypes())
                if accepted_type is None:
                    raise HTTPError(StatusResponse(responsecode.NOT_ACCEPTABLE, "Cannot generate requested data type"))

                caldata = (yield self.componentForUser())

                # Filter any attendee hidden instances
                caldata = HiddenInstanceFilter().filter(caldata)

                if self.accessMode:

                    # Non DAV:owner's have limited access to the data
                    isowner = (yield self.isOwner(request))

                    # Now "filter" the resource calendar data
                    caldata = PrivateEventFilter(self.accessMode, isowner).filter(caldata)

                response = Response()
                response.stream = MemoryStream(caldata.getTextWithTimezones(includeTimezones=not config.EnableTimezonesByReference, format=accepted_type))
                response.headers.setHeader("content-type", MimeType.fromString("%s; charset=utf-8" % (accepted_type,)))

                # Add Schedule-Tag header if property is present
                if self.scheduleTag:
                    response.headers.setHeader("Schedule-Tag", self.scheduleTag)

                returnValue(response)

    # Do normal GET behavior
    response = (yield super(CalDAVResource, self).http_GET(request))
    returnValue(response)
Esempio n. 22
0
        fbresult = yield FreebusyQuery(
            organizer=organizer, recipient=recipient,
            timerange=timerange).generateAttendeeFreeBusyResponse(fbset=fbset,
                                                                  method=None)
    except NumberOfMatchesWithinLimits:
        log.error("Too many matching components in free-busy report")
        raise HTTPError(
            ErrorResponse(responsecode.FORBIDDEN,
                          davxml.NumberOfMatchesWithinLimits(),
                          "Too many components"))
    except TimeRangeLowerLimit, e:
        raise HTTPError(
            ErrorResponse(
                responsecode.FORBIDDEN, caldavxml.MinDateTime(),
                "Time-range value too far in the past. Must be on or after %s."
                % (str(e.limit), )))
    except TimeRangeUpperLimit, e:
        raise HTTPError(
            ErrorResponse(
                responsecode.FORBIDDEN, caldavxml.MaxDateTime(),
                "Time-range value too far in the future. Must be on or before %s."
                % (str(e.limit), )))

    response = Response()
    response.stream = MemoryStream(fbresult.getText(accepted_type))
    response.headers.setHeader(
        "content-type",
        MimeType.fromString("%s; charset=utf-8" % (accepted_type, )))

    returnValue(response)
Esempio n. 23
0
 def _defer(data):
     response = Response()
     response.stream = MemoryStream(str(data))
     response.headers.setHeader(
         "content-type", MimeType.fromString("text/calendar"))
     return response
Esempio n. 24
0
            (caldavxml.ReadFreeBusy(), ))
    except NumberOfMatchesWithinLimits:
        log.error("Too many matching components in free-busy report")
        raise HTTPError(
            ErrorResponse(responsecode.FORBIDDEN,
                          davxml.NumberOfMatchesWithinLimits(),
                          "Too many components"))
    except TimeRangeLowerLimit, e:
        raise HTTPError(
            ErrorResponse(
                responsecode.FORBIDDEN, caldavxml.MinDateTime(),
                "Time-range value too far in the past. Must be on or after %s."
                % (str(e.limit), )))
    except TimeRangeUpperLimit, e:
        raise HTTPError(
            ErrorResponse(
                responsecode.FORBIDDEN, caldavxml.MaxDateTime(),
                "Time-range value too far in the future. Must be on or before %s."
                % (str(e.limit), )))

    # Now build a new calendar object with the free busy info we have
    fbcalendar = report_common.buildFreeBusyResult(fbinfo, timerange)

    response = Response()
    response.stream = MemoryStream(fbcalendar.getText(accepted_type))
    response.headers.setHeader(
        "content-type",
        MimeType.fromString("%s; charset=utf-8" % (accepted_type, )))

    returnValue(response)
Esempio n. 25
0
def http_GET(self, request):

    if self.exists():
        # Special sharing request on a calendar or address book
        if self.isCalendarCollection() or self.isAddressBookCollection():

            # Check for action=share
            if request.args:
                action = request.args.get("action", ("",))
                if len(action) != 1:
                    raise HTTPError(ErrorResponse(
                        responsecode.BAD_REQUEST,
                        (calendarserver_namespace, "valid-action"),
                        "Invalid action parameter: %s" % (action,),
                    ))
                action = action[0]

                dispatch = {
                    "share"   : self.directShare,
                }.get(action, None)

                if dispatch is None:
                    raise HTTPError(ErrorResponse(
                        responsecode.BAD_REQUEST,
                        (calendarserver_namespace, "supported-action"),
                        "Action not supported: %s" % (action,),
                    ))

                response = (yield dispatch(request))
                returnValue(response)

        else:
            # FIXME: this should be implemented in storebridge.CalendarObject.render

            # Look for calendar access restriction on existing resource.
            parentURL = parentForURL(request.uri)
            parent = (yield request.locateResource(parentURL))
            if isPseudoCalendarCollectionResource(parent):

                # Check authorization first
                yield self.authorize(request, (davxml.Read(),))

                # Accept header handling
                accepted_type = bestAcceptType(request.headers.getHeader("accept"), Component.allowedTypes())
                if accepted_type is None:
                    raise HTTPError(StatusResponse(responsecode.NOT_ACCEPTABLE, "Cannot generate requested data type"))

                caldata = (yield self.iCalendarForUser(request))

                # Filter any attendee hidden instances
                caldata = HiddenInstanceFilter().filter(caldata)

                if self.accessMode:

                    # Non DAV:owner's have limited access to the data
                    isowner = (yield self.isOwner(request))

                    # Now "filter" the resource calendar data
                    caldata = PrivateEventFilter(self.accessMode, isowner).filter(caldata)

                response = Response()
                response.stream = MemoryStream(caldata.getTextWithTimezones(includeTimezones=not config.EnableTimezonesByReference, format=accepted_type))
                response.headers.setHeader("content-type", MimeType.fromString("%s; charset=utf-8" % (accepted_type,)))

                # Add Schedule-Tag header if property is present
                if self.scheduleTag:
                    response.headers.setHeader("Schedule-Tag", self.scheduleTag)

                returnValue(response)

    # Do normal GET behavior
    response = (yield super(CalDAVResource, self).http_GET(request))
    returnValue(response)