Пример #1
0
    def test_freebusy(self):
        """
        Test that action=component works.
        """

        yield self.createShare("user01", "puser01")

        calendar1 = yield self.calendarUnderTest(txn=self.theTransactionUnderTest(0), home="user01", name="calendar")
        yield calendar1.createCalendarObjectWithName("1.ics", Component.fromString(self.caldata1))
        yield self.commitTransaction(0)

        fbstart = "{now:04d}0102T000000Z".format(**self.nowYear)
        fbend = "{now:04d}0103T000000Z".format(**self.nowYear)

        shared = yield self.calendarUnderTest(txn=self.theTransactionUnderTest(1), home="puser01", name="shared-calendar")

        fbinfo = FreebusyQuery.FBInfo([], [], [])
        timerange = Period(DateTime.parseText(fbstart), DateTime.parseText(fbend))
        organizer = recipient = (yield calendarUserFromCalendarUserAddress("mailto:[email protected]", self.theTransactionUnderTest(1)))

        freebusy = FreebusyQuery(organizer=organizer, recipient=recipient, timerange=timerange)
        matchtotal = (yield freebusy.generateFreeBusyInfo([shared, ], fbinfo))

        self.assertEqual(matchtotal, 1)
        self.assertEqual(fbinfo[0], [Period.parseText("{now:04d}0102T140000Z/PT1H".format(**self.nowYear)), ])
        self.assertEqual(len(fbinfo[1]), 0)
        self.assertEqual(len(fbinfo[2]), 0)
        yield self.commitTransaction(1)
Пример #2
0
    def test_freebusy(self):
        """
        Test that action=component works.
        """

        yield self.createShare("user01", "puser01")

        calendar1 = yield self.calendarUnderTest(txn=self.theTransactionUnderTest(0), home="user01", name="calendar")
        yield calendar1.createCalendarObjectWithName("1.ics", Component.fromString(self.caldata1))
        yield self.commitTransaction(0)

        fbstart = "{now:04d}0102T000000Z".format(**self.nowYear)
        fbend = "{now:04d}0103T000000Z".format(**self.nowYear)

        shared = yield self.calendarUnderTest(txn=self.theTransactionUnderTest(1), home="puser01", name="shared-calendar")

        fbinfo = FreebusyQuery.FBInfo([], [], [])
        timerange = Period(DateTime.parseText(fbstart), DateTime.parseText(fbend))
        organizer = recipient = (yield calendarUserFromCalendarUserAddress("mailto:[email protected]", self.theTransactionUnderTest(1)))

        freebusy = FreebusyQuery(organizer=organizer, recipient=recipient, timerange=timerange)
        matchtotal = (yield freebusy.generateFreeBusyInfo([shared, ], fbinfo))

        self.assertEqual(matchtotal, 1)
        self.assertEqual(fbinfo[0], [Period.parseText("{now:04d}0102T140000Z/PT1H".format(**self.nowYear)), ])
        self.assertEqual(len(fbinfo[1]), 0)
        self.assertEqual(len(fbinfo[2]), 0)
        yield self.commitTransaction(1)
Пример #3
0
    def test_one_event_event_details(self):
        """
        Test when the calendar is empty.
        """

        data = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:1234-5678
DTSTAMP:20080601T000000Z
DTSTART:%s
DTEND:%s
END:VEVENT
END:VCALENDAR
""" % (self.now_12H.getText(), self.now_13H.getText(),)

        yield self._createCalendarObject(data, "user01", "test.ics")
        calendar = (yield self.calendarUnderTest(home="user01", name="calendar_1"))
        fbinfo = FreebusyQuery.FBInfo([], [], [])
        timerange = Period(self.now, self.now_1D)
        event_details = []

        organizer = recipient = yield calendarUserFromCalendarUserAddress("mailto:[email protected]", self.transactionUnderTest())
        freebusy = FreebusyQuery(organizer=organizer, recipient=recipient, timerange=timerange, event_details=event_details)
        freebusy.same_calendar_user = True
        result = yield freebusy.generateFreeBusyInfo([calendar, ], fbinfo)
        self.assertEqual(result, 1)
        self.assertEqual(fbinfo.busy, [Period(self.now_12H, self.now_13H), ])
        self.assertEqual(len(fbinfo.tentative), 0)
        self.assertEqual(len(fbinfo.unavailable), 0)
        self.assertEqual(len(event_details), 1)
        self.assertEqual(str(event_details[0]), str(tuple(Component.fromString(data).subcomponents())[0]))
Пример #4
0
    def test_no_events(self):
        """
        Test when the calendar is empty.
        """

        calendar = (yield self.calendarUnderTest(home="user01", name="calendar_1"))
        fbinfo = FreebusyQuery.FBInfo([], [], [])
        timerange = Period(self.now, self.now_1D)

        organizer = recipient = yield calendarUserFromCalendarUserAddress("mailto:[email protected]", self.transactionUnderTest())
        freebusy = FreebusyQuery(organizer=organizer, recipient=recipient, timerange=timerange)
        result = (yield freebusy.generateFreeBusyInfo([calendar, ], fbinfo))
        self.assertEqual(result, 0)
        self.assertEqual(len(fbinfo.busy), 0)
        self.assertEqual(len(fbinfo.tentative), 0)
        self.assertEqual(len(fbinfo.unavailable), 0)
Пример #5
0
    def test_one_event_event_details(self):
        """
        Test when the calendar is empty.
        """

        data = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:1234-5678
DTSTAMP:20080601T000000Z
DTSTART:%s
DTEND:%s
END:VEVENT
END:VCALENDAR
""" % (
            self.now_12H.getText(),
            self.now_13H.getText(),
        )

        yield self._createCalendarObject(data, "user01", "test.ics")
        calendar = (yield self.calendarUnderTest(home="user01",
                                                 name="calendar_1"))
        fbinfo = FreebusyQuery.FBInfo([], [], [])
        timerange = Period(self.now, self.now_1D)
        event_details = []

        organizer = recipient = yield calendarUserFromCalendarUserAddress(
            "mailto:[email protected]", self.transactionUnderTest())
        freebusy = FreebusyQuery(organizer=organizer,
                                 recipient=recipient,
                                 timerange=timerange,
                                 event_details=event_details)
        freebusy.same_calendar_user = True
        result = yield freebusy.generateFreeBusyInfo([
            calendar,
        ], fbinfo)
        self.assertEqual(result, 1)
        self.assertEqual(fbinfo.busy, [
            Period(self.now_12H, self.now_13H),
        ])
        self.assertEqual(len(fbinfo.tentative), 0)
        self.assertEqual(len(fbinfo.unavailable), 0)
        self.assertEqual(len(event_details), 1)
        self.assertEqual(
            str(event_details[0]),
            str(tuple(Component.fromString(data).subcomponents())[0]))
Пример #6
0
def report_urn_ietf_params_xml_ns_caldav_free_busy_query(self, request, freebusy):
    """
    Generate a free-busy REPORT.
    (CalDAV-access-09, section 7.8)
    """
    if not self.isCollection():
        log.error("freebusy report is only allowed on collection resources {s!r}", s=self)
        raise HTTPError(StatusResponse(responsecode.FORBIDDEN, "Not a calendar collection"))

    if freebusy.qname() != (caldavxml.caldav_namespace, "free-busy-query"):
        raise ValueError("{CalDAV:}free-busy-query expected as root element, not %s." % (freebusy.sname(),))

    timerange = freebusy.timerange
    if not timerange.valid():
        raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, "Invalid time-range specified"))

    fbset = []

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

    def getCalendarList(calresource, uri):  # @UnusedVariable
        """
        Store the calendars that match the query in L{fbset} which will then be used with the
        freebusy query.

        @param calresource: the L{CalDAVResource} for a calendar collection.
        @param uri: the uri for the calendar collection resource.
        """

        fbset.append(calresource._newStoreObject)
        return succeed(True)

    # Run report taking depth into account
    depth = request.headers.getHeader("depth", "0")
    yield report_common.applyToCalendarCollections(self, request, request.uri, depth, getCalendarList, (caldavxml.ReadFreeBusy(),))

    # Do the actual freebusy query against the set of matched calendars
    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),)
        ))
Пример #7
0
    def recv_freebusy(self, txn, request):
        """
        Process a freebusy cross-pod request. Message arguments as per L{send_freebusy}.

        @param request: request arguments
        @type request: C{dict}
        """

        # Operate on the L{CommonHomeChild}
        calresource, _ignore = yield self._getStoreObjectForRequest(
            txn, request)

        organizer = yield calendarUserFromCalendarUserAddress(
            request["organizer"], txn) if request["organizer"] else None
        recipient = yield calendarUserFromCalendarUserAddress(
            request["recipient"], txn) if request["recipient"] else None

        freebusy = FreebusyQuery(
            organizer=organizer,
            recipient=recipient,
            timerange=Period.parseText(request["timerange"]),
            excludeUID=request["excludeuid"],
            event_details=request["event_details"],
        )
        fbinfo = FreebusyQuery.FBInfo([], [], [])
        matchtotal = yield freebusy.generateFreeBusyInfo(
            [
                calresource,
            ],
            fbinfo,
            matchtotal=request["matchtotal"],
        )

        # Convert L{Period} objects to text for JSON response
        returnValue({
            "fbresults": [
                [item.getText() for item in fbinfo.busy],
                [item.getText() for item in fbinfo.tentative],
                [item.getText() for item in fbinfo.unavailable],
            ],
            "matchtotal":
            matchtotal,
        })
Пример #8
0
    def test_no_events(self):
        """
        Test when the calendar is empty.
        """

        calendar = (yield self.calendarUnderTest(home="user01",
                                                 name="calendar_1"))
        fbinfo = FreebusyQuery.FBInfo([], [], [])
        timerange = Period(self.now, self.now_1D)

        organizer = recipient = yield calendarUserFromCalendarUserAddress(
            "mailto:[email protected]", self.transactionUnderTest())
        freebusy = FreebusyQuery(organizer=organizer,
                                 recipient=recipient,
                                 timerange=timerange)
        result = (yield freebusy.generateFreeBusyInfo([
            calendar,
        ], fbinfo))
        self.assertEqual(result, 0)
        self.assertEqual(len(fbinfo.busy), 0)
        self.assertEqual(len(fbinfo.tentative), 0)
        self.assertEqual(len(fbinfo.unavailable), 0)
Пример #9
0
    def recv_freebusy(self, txn, request):
        """
        Process a freebusy cross-pod request. Message arguments as per L{send_freebusy}.

        @param request: request arguments
        @type request: C{dict}
        """

        # Operate on the L{CommonHomeChild}
        calresource, _ignore = yield self._getStoreObjectForRequest(txn, request)

        organizer = yield calendarUserFromCalendarUserAddress(request["organizer"], txn) if request["organizer"] else None
        recipient = yield calendarUserFromCalendarUserAddress(request["recipient"], txn) if request["recipient"] else None

        freebusy = FreebusyQuery(
            organizer=organizer,
            recipient=recipient,
            timerange=Period.parseText(request["timerange"]),
            excludeUID=request["excludeuid"],
            event_details=request["event_details"],
        )
        fbinfo = FreebusyQuery.FBInfo([], [], [])
        matchtotal = yield freebusy.generateFreeBusyInfo(
            [calresource, ],
            fbinfo,
            matchtotal=request["matchtotal"],
        )

        # Convert L{Period} objects to text for JSON response
        returnValue({
            "fbresults": [
                [item.getText() for item in fbinfo.busy],
                [item.getText() for item in fbinfo.tentative],
                [item.getText() for item in fbinfo.unavailable],
            ],
            "matchtotal": matchtotal,
        })
Пример #10
0
    def generateFreeBusyResponse(self, recipient, responses, organizerProp, uid, event_details):

        # Extract the ATTENDEE property matching current recipient from the calendar data
        cuas = recipient.record.calendarUserAddresses
        attendeeProp = self.scheduler.calendar.getAttendeeProperty(cuas)

        try:
            fbresult = yield FreebusyQuery(
                organizer=self.scheduler.organizer,
                organizerProp=organizerProp,
                recipient=recipient,
                attendeeProp=attendeeProp,
                uid=uid,
                timerange=self.scheduler.timeRange,
                excludeUID=self.scheduler.excludeUID,
                logItems=self.scheduler.logItems,
                event_details=event_details,
            ).generateAttendeeFreeBusyResponse()
        except Exception as e:
            log.failure(
                "Could not determine free busy information for recipient {cuaddr}",
                cuaddr=recipient.cuaddr, level=LogLevel.debug
            )
            log.error(
                "Could not determine free busy information for recipient {cuaddr}: {ex}",
                cuaddr=recipient.cuaddr, ex=e
            )
            err = HTTPError(ErrorResponse(
                responsecode.FORBIDDEN,
                (caldav_namespace, "recipient-permissions"),
                "Could not determine free busy information",
            ))
            responses.add(
                recipient.cuaddr,
                Failure(exc_value=err),
                reqstatus=iTIPRequestStatus.NO_AUTHORITY
            )
            returnValue(False)
        else:
            responses.add(
                recipient.cuaddr,
                responsecode.OK,
                reqstatus=iTIPRequestStatus.SUCCESS,
                calendar=fbresult
            )
            returnValue(True)
Пример #11
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)
Пример #12
0
    def test_simple(self):

        data = (
            (
                "#1.1 No busy time",
                FreebusyQuery.FBInfo([], [], []),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                None,
                None,
                None,
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
END:VFREEBUSY
END:VCALENDAR
""",
            ),
            (
                "#1.2 No busy time with organizerProp & attendeeProp",
                FreebusyQuery.FBInfo([], [], []),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                Property("ORGANIZER", "mailto:[email protected]"),
                Property("ATTENDEE", "mailto:[email protected]"),
                None,
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
ATTENDEE:mailto:[email protected]
ORGANIZER:mailto:[email protected]
END:VFREEBUSY
END:VCALENDAR
""",
            ),
            (
                "#1.3 With single busy time",
                FreebusyQuery.FBInfo([
                    Period.parseText("20080601T120000Z/20080601T130000Z"),
                ], [], []),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                Property("ORGANIZER", "mailto:[email protected]"),
                Property("ATTENDEE", "mailto:[email protected]"),
                None,
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
ATTENDEE:mailto:[email protected]
FREEBUSY;FBTYPE=BUSY:20080601T120000Z/20080601T130000Z
ORGANIZER:mailto:[email protected]
END:VFREEBUSY
END:VCALENDAR
""",
            ),
            (
                "#1.4 With multiple busy time",
                FreebusyQuery.FBInfo(
                    [
                        Period.parseText("20080601T120000Z/20080601T130000Z"),
                        Period.parseText("20080601T140000Z/20080601T150000Z"),
                    ],
                    [],
                    [],
                ),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                Property("ORGANIZER", "mailto:[email protected]"),
                Property("ATTENDEE", "mailto:[email protected]"),
                None,
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
ATTENDEE:mailto:[email protected]
FREEBUSY;FBTYPE=BUSY:20080601T120000Z/20080601T130000Z,20080601T140000Z/20080601T150000Z
ORGANIZER:mailto:[email protected]
END:VFREEBUSY
END:VCALENDAR
""",
            ),
            (
                "#1.5 With multiple busy time, some overlap",
                FreebusyQuery.FBInfo(
                    [
                        Period.parseText("20080601T120000Z/20080601T130000Z"),
                        Period.parseText("20080601T123000Z/20080601T133000Z"),
                        Period.parseText("20080601T140000Z/20080601T150000Z"),
                        Period.parseText("20080601T150000Z/20080601T160000Z"),
                    ],
                    [],
                    [],
                ),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                Property("ORGANIZER", "mailto:[email protected]"),
                Property("ATTENDEE", "mailto:[email protected]"),
                None,
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
ATTENDEE:mailto:[email protected]
FREEBUSY;FBTYPE=BUSY:20080601T120000Z/20080601T133000Z,20080601T140000Z/20080601T160000Z
ORGANIZER:mailto:[email protected]
END:VFREEBUSY
END:VCALENDAR
""",
            ),
            (
                "#1.6 With all busy time types",
                FreebusyQuery.FBInfo(
                    [
                        Period.parseText("20080601T120000Z/20080601T130000Z"),
                        Period.parseText("20080601T140000Z/20080601T150000Z"),
                    ],
                    [
                        Period.parseText("20080601T140000Z/20080601T150000Z"),
                    ],
                    [
                        Period.parseText("20080601T160000Z/20080601T170000Z"),
                    ],
                ),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                Property("ORGANIZER", "mailto:[email protected]"),
                Property("ATTENDEE", "mailto:[email protected]"),
                None,
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
ATTENDEE:mailto:[email protected]
FREEBUSY;FBTYPE=BUSY:20080601T120000Z/20080601T130000Z,20080601T140000Z/20080601T150000Z
FREEBUSY;FBTYPE=BUSY-TENTATIVE:20080601T140000Z/20080601T150000Z
FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20080601T160000Z/20080601T170000Z
ORGANIZER:mailto:[email protected]
END:VFREEBUSY
END:VCALENDAR
""",
            ),
            (
                "#1.7 With single busy time and event details",
                FreebusyQuery.FBInfo(
                    [
                        Period.parseText("20080601T120000Z/20080601T130000Z"),
                    ],
                    [],
                    [],
                ),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                Property("ORGANIZER", "mailto:[email protected]"),
                Property("ATTENDEE", "mailto:[email protected]"),
                [
                    tuple(
                        Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:1234-5678
DTSTAMP:20080601T000000Z
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
END:VEVENT
END:VCALENDAR
""").subcomponents())[0],
                ],
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
END:VEVENT
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
ATTENDEE:mailto:[email protected]
FREEBUSY;FBTYPE=BUSY:20080601T120000Z/20080601T130000Z
ORGANIZER:mailto:[email protected]
END:VFREEBUSY
END:VCALENDAR
""",
            ),
        )

        for description, fbinfo, timerange, organizerProp, attendeeProp, event_details, calendar in data:
            freebusy = FreebusyQuery(organizerProp=organizerProp,
                                     attendeeProp=attendeeProp,
                                     timerange=timerange,
                                     event_details=event_details)
            result = freebusy.buildFreeBusyResult(fbinfo)
            self.assertEqual(normalizeiCalendarText(str(result)),
                             calendar.replace("\n", "\r\n"),
                             msg=description)
Пример #13
0
    def test_simple(self):

        data = (
            (
                "#1.1 No busy time",
                FreebusyQuery.FBInfo([], [], []),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                None,
                None,
                None,
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
END:VFREEBUSY
END:VCALENDAR
""",
            ),
            (
                "#1.2 No busy time with organizerProp & attendeeProp",
                FreebusyQuery.FBInfo([], [], []),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                Property("ORGANIZER", "mailto:[email protected]"),
                Property("ATTENDEE", "mailto:[email protected]"),
                None,
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
ATTENDEE:mailto:[email protected]
ORGANIZER:mailto:[email protected]
END:VFREEBUSY
END:VCALENDAR
""",
            ),
            (
                "#1.3 With single busy time",
                FreebusyQuery.FBInfo([Period.parseText("20080601T120000Z/20080601T130000Z"), ], [], []),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                Property("ORGANIZER", "mailto:[email protected]"),
                Property("ATTENDEE", "mailto:[email protected]"),
                None,
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
ATTENDEE:mailto:[email protected]
FREEBUSY;FBTYPE=BUSY:20080601T120000Z/20080601T130000Z
ORGANIZER:mailto:[email protected]
END:VFREEBUSY
END:VCALENDAR
""",
            ),
            (
                "#1.4 With multiple busy time",
                FreebusyQuery.FBInfo(
                    [
                        Period.parseText("20080601T120000Z/20080601T130000Z"),
                        Period.parseText("20080601T140000Z/20080601T150000Z"),
                    ],
                    [],
                    [],
                ),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                Property("ORGANIZER", "mailto:[email protected]"),
                Property("ATTENDEE", "mailto:[email protected]"),
                None,
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
ATTENDEE:mailto:[email protected]
FREEBUSY;FBTYPE=BUSY:20080601T120000Z/20080601T130000Z,20080601T140000Z/20080601T150000Z
ORGANIZER:mailto:[email protected]
END:VFREEBUSY
END:VCALENDAR
""",
            ),
            (
                "#1.5 With multiple busy time, some overlap",
                FreebusyQuery.FBInfo(
                    [
                        Period.parseText("20080601T120000Z/20080601T130000Z"),
                        Period.parseText("20080601T123000Z/20080601T133000Z"),
                        Period.parseText("20080601T140000Z/20080601T150000Z"),
                        Period.parseText("20080601T150000Z/20080601T160000Z"),
                    ],
                    [],
                    [],
                ),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                Property("ORGANIZER", "mailto:[email protected]"),
                Property("ATTENDEE", "mailto:[email protected]"),
                None,
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
ATTENDEE:mailto:[email protected]
FREEBUSY;FBTYPE=BUSY:20080601T120000Z/20080601T133000Z,20080601T140000Z/20080601T160000Z
ORGANIZER:mailto:[email protected]
END:VFREEBUSY
END:VCALENDAR
""",
            ),
            (
                "#1.6 With all busy time types",
                FreebusyQuery.FBInfo(
                    [
                        Period.parseText("20080601T120000Z/20080601T130000Z"),
                        Period.parseText("20080601T140000Z/20080601T150000Z"),
                    ],
                    [
                        Period.parseText("20080601T140000Z/20080601T150000Z"),
                    ],
                    [
                        Period.parseText("20080601T160000Z/20080601T170000Z"),
                    ],
                ),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                Property("ORGANIZER", "mailto:[email protected]"),
                Property("ATTENDEE", "mailto:[email protected]"),
                None,
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
ATTENDEE:mailto:[email protected]
FREEBUSY;FBTYPE=BUSY:20080601T120000Z/20080601T130000Z,20080601T140000Z/20080601T150000Z
FREEBUSY;FBTYPE=BUSY-TENTATIVE:20080601T140000Z/20080601T150000Z
FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20080601T160000Z/20080601T170000Z
ORGANIZER:mailto:[email protected]
END:VFREEBUSY
END:VCALENDAR
""",
            ),
            (
                "#1.7 With single busy time and event details",
                FreebusyQuery.FBInfo(
                    [Period.parseText("20080601T120000Z/20080601T130000Z"), ],
                    [],
                    [],
                ),
                Period.parseText("20080601T000000Z/20080602T000000Z"),
                Property("ORGANIZER", "mailto:[email protected]"),
                Property("ATTENDEE", "mailto:[email protected]"),
                [
                    tuple(Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:1234-5678
DTSTAMP:20080601T000000Z
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
END:VEVENT
END:VCALENDAR
""").subcomponents())[0],
                ],
                """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
END:VEVENT
BEGIN:VFREEBUSY
DTSTART:20080601T000000Z
DTEND:20080602T000000Z
ATTENDEE:mailto:[email protected]
FREEBUSY;FBTYPE=BUSY:20080601T120000Z/20080601T130000Z
ORGANIZER:mailto:[email protected]
END:VFREEBUSY
END:VCALENDAR
""",
            ),
        )

        for description, fbinfo, timerange, organizerProp, attendeeProp, event_details, calendar in data:
            freebusy = FreebusyQuery(organizerProp=organizerProp, attendeeProp=attendeeProp, timerange=timerange, event_details=event_details)
            result = freebusy.buildFreeBusyResult(fbinfo)
            self.assertEqual(normalizeiCalendarText(str(result)), calendar.replace("\n", "\r\n"), msg=description)