Example #1
0
    async def availabilities(self):
        """
        List all availabilities from the calendar.

        Returns:
         * [Availability(), ...]
        """
        # TODO: this is basically a copy of events() - can we do more
        # refactoring and consolidation here?  Maybe it's wrong to do
        # separate methods for journals, todos and events?
        all = []

        data = cdav.CalendarData()
        prop = dav.Prop() + data
        vevent = cdav.CompFilter("VAVAILABILITY")
        vcalendar = cdav.CompFilter("VCALENDAR") + vevent
        filter = cdav.Filter() + vcalendar
        root = cdav.CalendarQuery() + [prop, filter]

        response = await self._query(root, 1, query_method='report')
        results = self._handle_prop_response(response,
                                             props=[cdav.CalendarData()])
        for r in results:
            all.append(
                Availability(self.client,
                             url=self.url.join(r),
                             data=results[r][cdav.CalendarData.tag],
                             parent=self))

        return all
Example #2
0
    async def events(self):
        """
        List all events from the calendar.

        Returns:
         * [Event(), ...]
        """
        all = []

        data = cdav.CalendarData()
        prop = dav.Prop() + data
        vevent = cdav.CompFilter("VEVENT")
        vcalendar = cdav.CompFilter("VCALENDAR") + vevent
        filter = cdav.Filter() + vcalendar
        root = cdav.CalendarQuery() + [prop, filter]

        response = await self._query(root, 1, query_method='report')
        results = self._handle_prop_response(response,
                                             props=[cdav.CalendarData()])
        for r in results:
            all.append(
                Event(self.client,
                      url=self.url.join(r),
                      data=results[r][cdav.CalendarData.tag],
                      parent=self))

        return all
Example #3
0
def test_filter_1():
    """Should not raise an Error."""
    cdav.Filter().append(
        cdav.CompFilter("VCALENDAR").append(
            cdav.CompFilter("VEVENT").append(
                cdav.PropFilter("UID").append(
                    [cdav.TextMatch("pouet", negate=True)]))))
    assert True
Example #4
0
    async def date_search(self, start, end=None, compfilter="VEVENT"):
        """
        Search events by date in the calendar. Recurring events are
        expanded if they are occuring during the specified time frame
        and if an end timestamp is given.

        Parameters:
         * start = datetime.today().
         * end = same as above.
         * compfilter = defaults to events only.  Set to None to fetch all
           calendar components.

        Returns:
         * [CalendarObjectResource(), ...]

        """
        matches = []

        # build the request

        # Some servers will raise an error if we send the expand flag
        # but don't set any end-date - expand doesn't make much sense
        # if we have one recurring event describing an indefinite
        # series of events.  Hence, if the end date is not set, we
        # skip asking for expanded events.
        start = date_to_utc(start)

        if end:
            end = date_to_utc(end)
            data = cdav.CalendarData() + cdav.Expand(start, end)
        else:
            data = cdav.CalendarData()
        prop = dav.Prop() + data

        query = cdav.TimeRange(start, end)
        if compfilter:
            query = cdav.CompFilter(compfilter) + query
        vcalendar = cdav.CompFilter("VCALENDAR") + query
        filter = cdav.Filter() + vcalendar

        root = cdav.CalendarQuery() + [prop, filter]
        response = await self._query(root, 1, 'report')
        results = self._handle_prop_response(response=response,
                                             props=[cdav.CalendarData()])
        for r in results:
            matches.append(
                Event(self.client,
                      url=self.url.join(r),
                      data=results[r][cdav.CalendarData.tag],
                      parent=self))

        return matches
Example #5
0
    async def object_by_uid(self, uid, comp_filter=None):
        """
        Get one event from the calendar.

        Parameters:
         * uid: the event uid

        Returns:
         * Event() or None
        """
        data = cdav.CalendarData()
        prop = dav.Prop() + data

        query = cdav.TextMatch(uid)
        query = cdav.PropFilter("UID") + query
        if comp_filter:
            query = comp_filter + query
        vcalendar = cdav.CompFilter("VCALENDAR") + query
        filter = cdav.Filter() + vcalendar

        root = cdav.CalendarQuery() + [prop, filter]

        response = await self._query(root, 1, 'report')

        if response.status == 404:
            raise error.NotFoundError(errmsg(response))
        elif response.status == 400:
            raise error.ReportError(errmsg(response))

        items_found = response.tree.findall(".//" + dav.Response.tag)
        for r in items_found:
            href = unquote(r.find(".//" + dav.Href.tag).text)
            data = unquote(r.find(".//" + cdav.CalendarData.tag).text)
            # Ref Lucas Verney, we've actually done a substring search, if the
            # uid given in the query is short (i.e. just "0") we're likely to
            # get false positives back from the server.
            #
            # Long uids are folded, so splice the lines together here before
            # attempting a match.
            item_uid = re.search(r'\nUID:((.|\n[ \t])*)\n', data)
            if (not item_uid
                    or re.sub(r'\n[ \t]', '', item_uid.group(1)) != uid):
                continue
            return self._calendar_comp_class_by_data(data)(
                self.client, url=URL.objectify(href), data=data, parent=self)
        raise error.NotFoundError(errmsg(response))
Example #6
0
    async def todos(self,
                    sort_keys=('due', 'priority'),
                    include_completed=False,
                    sort_key=None):
        """
        fetches a list of todo events.

        Parameters:
         * sort_keys: use this field in the VTODO for sorting (iterable of
           lower case string, i.e. ('priority','due')).
         * include_completed: boolean -
           by default, only pending tasks are listed
         * sort_key: DEPRECATED, for backwards compatibility with version 0.4.
        """
        # ref https://www.ietf.org/rfc/rfc4791.txt, section 7.8.9
        matches = []

        # build the request
        data = cdav.CalendarData()
        prop = dav.Prop() + data

        if sort_key:
            sort_keys = (sort_key, )

        if not include_completed:
            # == QUERY 1
            # vnotcompleted = cdav.TextMatch('COMPLETED', negate=True)
            vnotcancelled = cdav.TextMatch('CANCELLED', negate=True)
            # vstatusNotCompleted = cdav.PropFilter(
            #     'STATUS') + vnotcompleted
            vstatusNotCancelled = cdav.PropFilter('STATUS') + vnotcancelled

            vnocompletedate = cdav.PropFilter('COMPLETED') + cdav.NotDefined()
            # vnocanceldate = cdav.PropFilter('CANCELLED') + cdav.NotDefined()
            vtodo = (cdav.CompFilter("VTODO") + vnocompletedate +
                     vstatusNotCancelled)
            # vtodo2 = (cdav.CompFilter("VTODO") + vnostatus)
            vcalendar = cdav.CompFilter("VCALENDAR") + vtodo  # + vtodo2
            filter1 = cdav.Filter() + vcalendar
            root = cdav.CalendarQuery() + [prop, filter1]

            response = await self._query(root, 1, 'report')
            results = self._handle_prop_response(response=response,
                                                 props=[cdav.CalendarData()])
            for r in results:
                matches.append(
                    Todo(self.client,
                         url=self.url.join(r),
                         data=results[r][cdav.CalendarData.tag],
                         parent=self))

            # ==  QUERY 2 == Add all TODO without status
            vnostatus = cdav.PropFilter('STATUS') + cdav.NotDefined()
            vtodo2 = (cdav.CompFilter("VTODO") + vnocompletedate + vnostatus)
            vcalendar2 = cdav.CompFilter("VCALENDAR") + vtodo2
            filter2 = cdav.Filter() + vcalendar2
            root2 = cdav.CalendarQuery() + [prop, filter2]

            response2 = await self._query(root2, 1, 'report')
            results2 = self._handle_prop_response(response=response2,
                                                  props=[cdav.CalendarData()])
            for r in results2:
                matches.append(
                    Todo(self.client,
                         url=self.url.join(r),
                         data=results2[r][cdav.CalendarData.tag],
                         parent=self))
        else:
            vtodo = cdav.CompFilter("VTODO")
            vcalendar = cdav.CompFilter("VCALENDAR") + vtodo
            filter = cdav.Filter() + vcalendar

            root = cdav.CalendarQuery() + [prop, filter]

            response = await self._query(root, 1, 'report')
            results = self._handle_prop_response(response=response,
                                                 props=[cdav.CalendarData()])
            for r in results:
                matches.append(
                    Todo(self.client,
                         url=self.url.join(r),
                         data=results[r][cdav.CalendarData.tag],
                         parent=self))

        def sort_key_func(x):
            ret = []
            vtodo = x.instance.vtodo
            defaults = {
                'due':
                '2050-01-01',
                'dtstart':
                '1970-01-01',
                'priority':
                '0',
                # JA: why compare datetime.strftime('%F%H%M%S')
                # JA: and not simply datetime?
                'isnt_overdue':
                not (hasattr(vtodo, 'due')
                     and vtodo.due.value.strftime('%F%H%M%S') <
                     datetime.datetime.now().strftime('%F%H%M%S')),
                'hasnt_started':
                (hasattr(vtodo, 'dtstart')
                 and vtodo.dtstart.value.strftime('%F%H%M%S') >
                 datetime.datetime.now().strftime('%F%H%M%S'))
            }
            for sort_key in sort_keys:
                val = getattr(vtodo, sort_key, None)
                if val is None:
                    ret.append(defaults.get(sort_key, '0'))
                    continue
                val = val.value
                if hasattr(val, 'strftime'):
                    ret.append(val.strftime('%F%H%M%S'))
                else:
                    ret.append(val)
            return ret

        if sort_keys:
            matches.sort(key=sort_key_func)
        return matches