Exemple #1
0
    def date_search(self,
                    start,
                    end=None,
                    compfilter="VEVENT",
                    expand="maybe"):
        # type (TimeStamp, TimeStamp, str, str) -> CalendarObjectResource
        """
        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.
         * expand - should recurrent events be expanded?  (to preserve 
           backward-compatibility the default "maybe" will be changed into True 
           unless the date_search is open-ended)

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

        """
        matches = []

        # build the request

        ## for backward compatibility - expand should be false
        ## in an open-ended date search, otherwise true
        if expand == 'maybe':
            expand = end

        # 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.  I think it's appropriate to raise an error
        # in this case.
        if not end and expand:
            raise error.ReportError(
                "an open-ended date search cannot be expanded")
        elif expand:
            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 = 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
Exemple #2
0
    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:
            vnotcompleted = cdav.TextMatch('COMPLETED', negate=True)
            vnotcancelled = cdav.TextMatch('CANCELLED', negate=True)
            vstatusNotCompleted = cdav.PropFilter(
                'STATUS') + vnotcompleted + cdav.NotDefined()
            vstatusNotCancelled = cdav.PropFilter(
                'STATUS') + vnotcancelled + cdav.NotDefined()
            vnocompletedate = cdav.PropFilter('COMPLETED') + cdav.NotDefined()
            vtodo = (cdav.CompFilter("VTODO") + vnocompletedate +
                     vstatusNotCompleted + vstatusNotCancelled)
        else:
            vtodo = cdav.CompFilter("VTODO")
        vcalendar = cdav.CompFilter("VCALENDAR") + vtodo
        filter = cdav.Filter() + vcalendar

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

        response = 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
Exemple #3
0
    def test_xml_parsing(self):
        """
        DAVResponse has quite some code to parse the XML received from the
        server.  This test contains real XML received from various
        caldav servers, and the expected result from the parse
        methods.
        """
        xml = """
<multistatus xmlns="DAV:">
  <response xmlns="DAV:">
    <href>/</href>
    <propstat>
      <prop>
        <current-user-principal xmlns="DAV:">
          <href xmlns="DAV:">/17149682/principal/</href>
        </current-user-principal>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
</multistatus>
"""
        expected_result = {
            '/': {
                '{DAV:}current-user-principal': '/17149682/principal/'
            }
        }

        assert_equal(
            MockedDAVResponse(xml).expand_simple_props(
                props=[dav.CurrentUserPrincipal()]), expected_result)

        xml = """
<multistatus xmlns="DAV:">
  <response xmlns="DAV:">
    <href>/17149682/principal/</href>
    <propstat>
      <prop>
        <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">
          <href xmlns="DAV:">https://p62-caldav.icloud.com:443/17149682/calendars/</href>
        </calendar-home-set>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
</multistatus>"""
        expected_result = {
            '/17149682/principal/': {
                '{urn:ietf:params:xml:ns:caldav}calendar-home-set':
                'https://p62-caldav.icloud.com:443/17149682/calendars/'
            }
        }
        assert_equal(
            MockedDAVResponse(xml).expand_simple_props(
                props=[cdav.CalendarHomeSet()]), expected_result)

        xml = """
<multistatus xmlns="DAV:">
  <response xmlns="DAV:">
    <href>/</href>
    <propstat>
      <prop>
        <current-user-principal xmlns="DAV:">
          <href xmlns="DAV:">/17149682/principal/</href>
        </current-user-principal>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
</multistatus>"""
        expected_result = {
            '/': {
                '{DAV:}current-user-principal': '/17149682/principal/'
            }
        }
        assert_equal(
            MockedDAVResponse(xml).expand_simple_props(
                props=[dav.CurrentUserPrincipal()]), expected_result)

        xml = """
<multistatus xmlns="DAV:">
  <response>
    <href>/17149682/calendars/testcalendar-84439d0b-ce46-4416-b978-7b4009122c64/</href>
    <propstat>
      <prop>
                </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
    <propstat>
      <prop>
        <calendar-data xmlns="urn:ietf:params:xml:ns:caldav"/>
      </prop>
      <status>HTTP/1.1 404 Not Found</status>
    </propstat>
  </response>
  <response>
    <href>/17149682/calendars/testcalendar-84439d0b-ce46-4416-b978-7b4009122c64/20010712T182145Z-123401%40example.com.ics</href>
    <propstat>
      <prop>
        <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VEVENT
UID:[email protected]
DTSTAMP:20060712T182145Z
DTSTART:20060714T170000Z
DTEND:20060715T040000Z
SUMMARY:Bastille Day Party
END:VEVENT
END:VCALENDAR
</calendar-data>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
</multistatus>
"""
        expected_result = {
            '/17149682/calendars/testcalendar-84439d0b-ce46-4416-b978-7b4009122c64/':
            {
                '{urn:ietf:params:xml:ns:caldav}calendar-data': None
            },
            '/17149682/calendars/testcalendar-84439d0b-ce46-4416-b978-7b4009122c64/[email protected]':
            {
                '{urn:ietf:params:xml:ns:caldav}calendar-data':
                'BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//Example Corp.//CalDAV Client//EN\nBEGIN:VEVENT\nUID:[email protected]\nDTSTAMP:20060712T182145Z\nDTSTART:20060714T170000Z\nDTEND:20060715T040000Z\nSUMMARY:Bastille Day Party\nEND:VEVENT\nEND:VCALENDAR\n'
            }
        }
        assert_equal(
            MockedDAVResponse(xml).expand_simple_props(
                props=[cdav.CalendarData()]), expected_result)

        xml = """
<multistatus xmlns="DAV:">
  <response xmlns="DAV:">
    <href>/17149682/calendars/</href>
    <propstat>
      <prop>
        <resourcetype xmlns="DAV:">
          <collection/>
        </resourcetype>
        <displayname xmlns="DAV:">Ny Test</displayname>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
  <response xmlns="DAV:">
    <href>/17149682/calendars/06888b87-397f-11eb-943b-3af9d3928d42/</href>
    <propstat>
      <prop>
        <resourcetype xmlns="DAV:">
          <collection/>
          <calendar xmlns="urn:ietf:params:xml:ns:caldav"/>
        </resourcetype>
        <displayname xmlns="DAV:">calfoo3</displayname>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
  <response xmlns="DAV:">
    <href>/17149682/calendars/inbox/</href>
    <propstat>
      <prop>
        <resourcetype xmlns="DAV:">
          <collection/>
          <schedule-inbox xmlns="urn:ietf:params:xml:ns:caldav"/>
        </resourcetype>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
    <propstat>
      <prop>
        <displayname xmlns="DAV:"/>
      </prop>
      <status>HTTP/1.1 404 Not Found</status>
    </propstat>
  </response>
  <response xmlns="DAV:">
    <href>/17149682/calendars/testcalendar-e2910e0a-feab-4b51-b3a8-55828acaa912/</href>
    <propstat>
      <prop>
        <resourcetype xmlns="DAV:">
          <collection/>
          <calendar xmlns="urn:ietf:params:xml:ns:caldav"/>
        </resourcetype>
        <displayname xmlns="DAV:">Yep</displayname>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
</multistatus>
"""
        expected_result = {
            '/17149682/calendars/': {
                '{DAV:}resourcetype': ['{DAV:}collection'],
                '{DAV:}displayname': 'Ny Test'
            },
            '/17149682/calendars/06888b87-397f-11eb-943b-3af9d3928d42/': {
                '{DAV:}resourcetype': [
                    '{DAV:}collection',
                    '{urn:ietf:params:xml:ns:caldav}calendar'
                ],
                '{DAV:}displayname':
                'calfoo3'
            },
            '/17149682/calendars/inbox/': {
                '{DAV:}resourcetype': [
                    '{DAV:}collection',
                    '{urn:ietf:params:xml:ns:caldav}schedule-inbox'
                ],
                '{DAV:}displayname':
                None
            },
            '/17149682/calendars/testcalendar-e2910e0a-feab-4b51-b3a8-55828acaa912/':
            {
                '{DAV:}resourcetype': [
                    '{DAV:}collection',
                    '{urn:ietf:params:xml:ns:caldav}calendar'
                ],
                '{DAV:}displayname':
                'Yep'
            }
        }
        assert_equal(
            MockedDAVResponse(xml).expand_simple_props(
                props=[dav.DisplayName()],
                multi_value_props=[dav.ResourceType()]), expected_result)

        xml = """
<multistatus xmlns="DAV:">
  <response xmlns="DAV:">
    <href>/17149682/calendars/testcalendar-f96b3bf0-09e1-4f3d-b891-3a25c99a2894/</href>
    <propstat>
      <prop>
        <getetag xmlns="DAV:">"kkkgopik"</getetag>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
  <response xmlns="DAV:">
    <href>/17149682/calendars/testcalendar-f96b3bf0-09e1-4f3d-b891-3a25c99a2894/1761bf8c-6363-11eb-8fe4-74e5f9bfd8c1.ics</href>
    <propstat>
      <prop>
        <getetag xmlns="DAV:">"kkkgorwx"</getetag>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
  <response xmlns="DAV:">
    <href>/17149682/calendars/testcalendar-f96b3bf0-09e1-4f3d-b891-3a25c99a2894/20010712T182145Z-123401%40example.com.ics</href>
    <propstat>
      <prop>
        <getetag xmlns="DAV:">"kkkgoqqu"</getetag>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
  <sync-token>HwoQEgwAAAh4yw8ntwAAAAAYAhgAIhUIopml463FieB4EKq9+NSn04DrkQEoAA==</sync-token>
</multistatus>
"""
        expected_results = {
            '/17149682/calendars/testcalendar-f96b3bf0-09e1-4f3d-b891-3a25c99a2894/':
            {
                '{DAV:}getetag': '"kkkgopik"',
                '{urn:ietf:params:xml:ns:caldav}calendar-data': None
            },
            '/17149682/calendars/testcalendar-f96b3bf0-09e1-4f3d-b891-3a25c99a2894/1761bf8c-6363-11eb-8fe4-74e5f9bfd8c1.ics':
            {
                '{DAV:}getetag': '"kkkgorwx"',
                '{urn:ietf:params:xml:ns:caldav}calendar-data': None
            },
            '/17149682/calendars/testcalendar-f96b3bf0-09e1-4f3d-b891-3a25c99a2894/[email protected]':
            {
                '{DAV:}getetag': '"kkkgoqqu"',
                '{urn:ietf:params:xml:ns:caldav}calendar-data': None
            }
        }