Пример #1
0
class TimeRange(FilterBase):
    """
    Specifies a time for testing components against.
    """

    serialized_name = "TimeRange"

    def __init__(self, xml_element):

        super(TimeRange, self).__init__(xml_element)
        if xml_element is None:
            return

        # One of start or end must be present
        if "start" not in xml_element.attributes and "end" not in xml_element.attributes:
            raise ValueError(
                "One of 'start' or 'end' must be present in CALDAV:time-range")

        self.start = DateTime.parseText(
            xml_element.attributes["start"]
        ) if "start" in xml_element.attributes else None
        self.end = DateTime.parseText(
            xml_element.attributes["end"]
        ) if "end" in xml_element.attributes else None
        self.tzinfo = None

    def _deserialize(self, data):
        """
        Convert a JSON compatible serialization of this object into the actual object.
        """
        self.start = DateTime.parseText(
            data["start"]) if data["start"] else None
        self.end = DateTime.parseText(data["end"]) if data["end"] else None
        self.tzinfo = Timezone(tzid=data["tzinfo"]) if data["tzinfo"] else None

    def serialize(self):
        """
        Create a JSON compatible serialization of this object - will be used in a cross-pod request.
        """
        result = super(TimeRange, self).serialize()
        result.update({
            "start":
            self.start.getText() if self.start else None,
            "end":
            self.end.getText() if self.end else None,
            "tzinfo":
            self.tzinfo.getTimezoneID() if self.tzinfo else None,
        })
        return result

    def settzinfo(self, tzinfo):
        """
        Set the default timezone to use with this query.
        @param tzinfo: a L{Timezone} to use.
        """

        # Give tzinfo to any TimeRange we have
        self.tzinfo = tzinfo

    def valid(self, level=0):
        """
        Indicate whether the time-range is valid (must be date-time in UTC).

        @return:      True if valid, False otherwise
        """

        if self.start is not None and self.start.isDateOnly():
            log.info("start attribute in <time-range> is not a date-time: %s" %
                     (self.start, ))
            return False
        if self.end is not None and self.end.isDateOnly():
            log.info("end attribute in <time-range> is not a date-time: %s" %
                     (self.end, ))
            return False
        if self.start is not None and not self.start.utc():
            log.info("start attribute in <time-range> is not UTC: %s" %
                     (self.start, ))
            return False
        if self.end is not None and not self.end.utc():
            log.info("end attribute in <time-range> is not UTC: %s" %
                     (self.end, ))
            return False

        # No other tests
        return True

    def match(self, property, access=None):
        """
        NB This is only called when doing a time-range match on a property.
        """
        if property is None:
            return False
        else:
            return property.containsTimeRange(self.start, self.end,
                                              self.tzinfo)

    def matchinstance(self, component, instances):
        """
        Test whether this time-range element causes a match to the specified component
        using the specified set of instances to determine the expanded time ranges.
        @param component: the L{Component} to test.
        @param instances: the list of expanded instances.
        @return: True if the time-range query matches, False otherwise.
        """
        if component is None:
            return False

        assert instances is not None or self.end is None, "Failure to expand instance for time-range filter: %r" % (
            self, )

        # Special case open-ended unbounded
        if instances is None:
            if component.getRecurrenceIDUTC() is None:
                return True
            else:
                # See if the overridden component's start is past the start
                start, _ignore_end = component.getEffectiveStartEnd()
                if start is None:
                    return True
                else:
                    return start >= self.start

        # Handle alarms as a special case
        alarms = (component.name() == "VALARM")
        if alarms:
            testcomponent = component._parent
        else:
            testcomponent = component

        for key in instances:
            instance = instances[key]

            # First make sure components match
            if not testcomponent.same(instance.component):
                continue

            if alarms:
                # Get all the alarm triggers for this instance and test each one
                triggers = instance.getAlarmTriggers()
                for trigger in triggers:
                    if timeRangesOverlap(trigger, None, self.start, self.end,
                                         self.tzinfo):
                        return True
            else:
                # Regular instance overlap test
                if timeRangesOverlap(instance.start, instance.end, self.start,
                                     self.end, self.tzinfo):
                    return True

        return False
Пример #2
0
class TimeRange (FilterBase):
    """
    Specifies a time for testing components against.
    """

    serialized_name = "TimeRange"

    def __init__(self, xml_element):

        super(TimeRange, self).__init__(xml_element)
        if xml_element is None:
            return

        # One of start or end must be present
        if "start" not in xml_element.attributes and "end" not in xml_element.attributes:
            raise ValueError("One of 'start' or 'end' must be present in CALDAV:time-range")

        self.start = DateTime.parseText(xml_element.attributes["start"]) if "start" in xml_element.attributes else None
        self.end = DateTime.parseText(xml_element.attributes["end"]) if "end" in xml_element.attributes else None
        self.tzinfo = None


    def _deserialize(self, data):
        """
        Convert a JSON compatible serialization of this object into the actual object.
        """
        self.start = DateTime.parseText(data["start"]) if data["start"] else None
        self.end = DateTime.parseText(data["end"]) if data["end"] else None
        self.tzinfo = Timezone(tzid=data["tzinfo"]) if data["tzinfo"] else None


    def serialize(self):
        """
        Create a JSON compatible serialization of this object - will be used in a cross-pod request.
        """
        result = super(TimeRange, self).serialize()
        result.update({
            "start": self.start.getText() if self.start else None,
            "end": self.end.getText() if self.end else None,
            "tzinfo": self.tzinfo.getTimezoneID() if self.tzinfo else None,
        })
        return result


    def settzinfo(self, tzinfo):
        """
        Set the default timezone to use with this query.
        @param tzinfo: a L{Timezone} to use.
        """

        # Give tzinfo to any TimeRange we have
        self.tzinfo = tzinfo


    def valid(self, level=0):
        """
        Indicate whether the time-range is valid (must be date-time in UTC).

        @return:      True if valid, False otherwise
        """

        if self.start is not None and self.start.isDateOnly():
            log.info("start attribute in <time-range> is not a date-time: %s" % (self.start,))
            return False
        if self.end is not None and self.end.isDateOnly():
            log.info("end attribute in <time-range> is not a date-time: %s" % (self.end,))
            return False
        if self.start is not None and not self.start.utc():
            log.info("start attribute in <time-range> is not UTC: %s" % (self.start,))
            return False
        if self.end is not None and not self.end.utc():
            log.info("end attribute in <time-range> is not UTC: %s" % (self.end,))
            return False

        # No other tests
        return True


    def match(self, property, access=None):
        """
        NB This is only called when doing a time-range match on a property.
        """
        if property is None:
            return False
        else:
            return property.containsTimeRange(self.start, self.end, self.tzinfo)


    def matchinstance(self, component, instances):
        """
        Test whether this time-range element causes a match to the specified component
        using the specified set of instances to determine the expanded time ranges.
        @param component: the L{Component} to test.
        @param instances: the list of expanded instances.
        @return: True if the time-range query matches, False otherwise.
        """
        if component is None:
            return False

        assert instances is not None or self.end is None, "Failure to expand instance for time-range filter: %r" % (self,)

        # Special case open-ended unbounded
        if instances is None:
            if component.getRecurrenceIDUTC() is None:
                return True
            else:
                # See if the overridden component's start is past the start
                start, _ignore_end = component.getEffectiveStartEnd()
                if start is None:
                    return True
                else:
                    return start >= self.start

        # Handle alarms as a special case
        alarms = (component.name() == "VALARM")
        if alarms:
            testcomponent = component._parent
        else:
            testcomponent = component

        for key in instances:
            instance = instances[key]

            # First make sure components match
            if not testcomponent.same(instance.component):
                continue

            if alarms:
                # Get all the alarm triggers for this instance and test each one
                triggers = instance.getAlarmTriggers()
                for trigger in triggers:
                    if timeRangesOverlap(trigger, None, self.start, self.end, self.tzinfo):
                        return True
            else:
                # Regular instance overlap test
                if timeRangesOverlap(instance.start, instance.end, self.start, self.end, self.tzinfo):
                    return True

        return False