Exemplo n.º 1
0
    def acceptShare(self, request, inviteUID, summary):

        # Accept the share
        try:
            shareeView = yield self._newStoreHome.acceptShare(
                inviteUID, summary)
        except DirectoryRecordNotFoundError:
            # Missing sharer record => fail request
            raise HTTPError(
                ErrorResponse(
                    responsecode.FORBIDDEN,
                    (calendarserver_namespace, "invalid-share"),
                    "Invite UID not valid",
                ))
        if shareeView is None:
            raise HTTPError(
                ErrorResponse(
                    responsecode.FORBIDDEN,
                    (calendarserver_namespace, "invalid-share"),
                    "Invite UID not valid",
                ))

        # Return the URL of the shared collection
        sharedAsURL = joinURL(self.url(), shareeView.shareName())
        returnValue(
            XMLResponse(code=responsecode.OK,
                        element=customxml.SharedAs(
                            element.HRef.fromString(sharedAsURL))))
Exemplo n.º 2
0
    def doPOSTExpand(self, request):
        """
        Expand a timezone within specified start/end dates.
        """

        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",
            ))

        try:
            start = request.args.get("start", ())
            if len(start) != 1:
                raise ValueError()
            start = DateTime.parseText(start[0])
        except ValueError:
            raise HTTPError(ErrorResponse(
                responsecode.BAD_REQUEST,
                (calendarserver_namespace, "valid-start-date"),
                "Invalid start query parameter",
            ))

        try:
            end = request.args.get("end", ())
            if len(end) != 1:
                raise ValueError()
            end = DateTime.parseText(end[0])
            if end <= start:
                raise ValueError()
        except ValueError:
            raise HTTPError(ErrorResponse(
                responsecode.BAD_REQUEST,
                (calendarserver_namespace, "valid-end-date"),
                "Invalid end query parameter",
            ))

        # Now do the expansion (but use a cache to avoid re-calculating TZs)
        observances = self.cache.get((tzid, start, end), None)
        if observances is None:
            observances = tzexpand(tzdata, start, end)
            self.cache[(tzid, start, end)] = observances

        # Turn into XML
        result = customxml.TZData(
            *[customxml.Observance(customxml.Onset(onset), customxml.UTCOffset(utc_offset)) for onset, utc_offset in observances]
        )
        return XMLResponse(responsecode.OK, result)
Exemplo n.º 3
0
    def http_GET(self, request):
        """
        The server-info GET method.
        """

        yield self.authorize(request, (davxml.Read(), ))

        returnValue(XMLResponse(responsecode.OK, config.ServerInfo))
Exemplo n.º 4
0
    def doPOSTList(self, request):
        """
        Return a list of all timezones known to the server.
        """

        tzids = listTZs()
        tzids.sort()
        result = customxml.TZIDs(*[customxml.TZID(tzid) for tzid in tzids])
        return XMLResponse(responsecode.OK, result)
Exemplo n.º 5
0
    def directShare(self, request):
        """
        Directly bind an accessible calendar/address book collection into the
        current principal's calendar/addressbook home.

        @param request: the request triggering this action
        @type request: L{IRequest}

        @return: the (asynchronous) HTTP result to respond to the direct-share
            request.
        @rtype: L{Deferred} firing L{txweb2.http.Response}, failing with
            L{HTTPError}
        """

        # Need to have at least DAV:read to do this
        yield self.authorize(request, (element.Read(), ))

        # Find current principal
        authz_principal = self.currentPrincipal(request).children[0]
        if not isinstance(authz_principal, element.HRef):
            raise HTTPError(
                ErrorResponse(
                    responsecode.FORBIDDEN,
                    (calendarserver_namespace, "valid-principal"),
                    "Current user principal not a DAV:href",
                ))
        principalURL = str(authz_principal)
        if not principalURL:
            raise HTTPError(
                ErrorResponse(
                    responsecode.FORBIDDEN,
                    (calendarserver_namespace, "valid-principal"),
                    "Current user principal not specified",
                ))
        sharee = (yield request.locateResource(principalURL))

        # Check enabled for service
        from twistedcaldav.directory.principal import DirectoryCalendarPrincipalResource
        if not isinstance(sharee, DirectoryCalendarPrincipalResource):
            raise HTTPError(
                ErrorResponse(
                    responsecode.FORBIDDEN,
                    (calendarserver_namespace, "invalid-principal"),
                    "Current user principal is not a calendar/addressbook enabled principal",
                ))

        # Get the home collection
        if self.isCalendarCollection():
            shareeHomeResource = yield sharee.calendarHome(request)
        elif self.isAddressBookCollection() or self.isGroup():
            shareeHomeResource = yield sharee.addressBookHome(request)
        else:
            raise HTTPError(
                ErrorResponse(
                    responsecode.FORBIDDEN,
                    (calendarserver_namespace, "invalid-principal"),
                    "No calendar/addressbook home for principal",
                ))

        # TODO: Make sure principal is not sharing back to themselves
        hostURL = (yield self.canonicalURL(request))
        shareeHomeURL = shareeHomeResource.url()
        if hostURL.startswith(shareeHomeURL):
            raise HTTPError(
                ErrorResponse(
                    responsecode.FORBIDDEN,
                    (calendarserver_namespace, "invalid-share"),
                    "Can't share your own calendar or addressbook",
                ))

        # Accept it
        shareeView = yield self._newStoreObject.directShareWithUser(
            sharee.principalUID())

        # Return the URL of the shared calendar
        sharedAsURL = joinURL(shareeHomeResource.url(), shareeView.name())
        returnValue(
            XMLResponse(code=responsecode.OK,
                        element=customxml.SharedAs(
                            element.HRef.fromString(sharedAsURL))))
Exemplo n.º 6
0
    def doCapabilities(self, request):
        """
        Return a list of all timezones known to the server.
        """

        # Determine min/max date-time for iSchedule
        now = DateTime.getNowUTC()
        minDateTime = DateTime(now.getYear(), 1, 1, 0, 0, 0,
                               Timezone.UTCTimezone)
        minDateTime.offsetYear(-1)
        maxDateTime = DateTime(now.getYear(), 1, 1, 0, 0, 0,
                               Timezone.UTCTimezone)
        maxDateTime.offsetYear(10)

        dataTypes = []
        dataTypes.append(
            ischedulexml.CalendarDataType(**{
                "content-type": "text/calendar",
                "version": "2.0",
            }))
        if config.EnableJSONData:
            dataTypes.append(
                ischedulexml.CalendarDataType(
                    **{
                        "content-type": "application/calendar+json",
                        "version": "2.0",
                    }))

        componentTypes = []
        from twistedcaldav.ical import allowedSchedulingComponents
        for name in allowedSchedulingComponents:
            if name == "VFREEBUSY":
                componentTypes.append(
                    ischedulexml.Component(ischedulexml.Method(name="REQUEST"),
                                           name=name))
            else:
                componentTypes.append(
                    ischedulexml.Component(ischedulexml.Method(name="REQUEST"),
                                           ischedulexml.Method(name="CANCEL"),
                                           ischedulexml.Method(name="REPLY"),
                                           name=name))

        result = ischedulexml.QueryResult(
            ischedulexml.Capabilities(
                ischedulexml.Version.fromString(
                    config.Scheduling.iSchedule.SerialNumber),
                ischedulexml.Versions(
                    ischedulexml.Version.fromString("1.0"), ),
                ischedulexml.SchedulingMessages(*componentTypes),
                ischedulexml.CalendarDataTypes(*dataTypes),
                ischedulexml.Attachments(ischedulexml.External(), ),
                ischedulexml.MaxContentLength.fromString(
                    config.MaxResourceSize),
                ischedulexml.MinDateTime.fromString(minDateTime.getText()),
                ischedulexml.MaxDateTime.fromString(maxDateTime.getText()),
                ischedulexml.MaxInstances.fromString(
                    config.MaxAllowedInstances),
                ischedulexml.MaxRecipients.fromString(
                    config.MaxAttendeesPerInstance),
                ischedulexml.Administrator.fromString(
                    request.unparseURL(params="", querystring="",
                                       fragment="")),
            ), )
        response = XMLResponse(responsecode.OK, result)
        response.headers.addRawHeader(
            ISCHEDULE_CAPABILITIES,
            str(config.Scheduling.iSchedule.SerialNumber))
        return response