예제 #1
0
    def search(self, xml, comp_class=None):
        """
        Takes some input XML, does a report query on a calendar object
        and returns the resource objects found.  Partly solves 
        https://github.com/python-caldav/caldav/issues/16

        TODO: this code is duplicated many places, we ought to do more code
        refactoring
        """
        matches = []
        response = self._query(xml, 1, 'report')
        results = self._handle_prop_response(response=response,
                                             props=[cdav.CalendarData()])
        for r in results:
            data = results[r][cdav.CalendarData.tag]
            if comp_class is None:
                comp_class = self._calendar_comp_class_by_data(data)
            if comp_class is None:
                ## Ouch, we really shouldn't get here.  This probably
                ## means we got some bad data from the server.  I've
                ## observed receiving a VCALENDAR from Baikal that did
                ## not contain anything.  Let's assume the data is
                ## void and should not be counted.
                continue
            url = URL(r)
            if url.hostname is None:
                # Quote when result is not a full URL
                r = quote(r)
            matches.append(
                comp_class(self.client,
                           url=self.url.join(r),
                           data=data,
                           parent=self))

        return matches
예제 #2
0
    def testAbsoluteURL(self):
        """Version 0.7.0 does not handle responses with absolute URLs very well, ref https://github.com/python-caldav/caldav/pull/103"""
        ## none of this should initiate any communication
        client = DAVClient(url='http://cal.example.com/')
        principal = Principal(client=client,
                              url='http://cal.example.com/home/bernard/')
        ## now, ask for the calendar_home_set, but first we need to mock up client.propfind
        mocked_response = mock.MagicMock()
        mocked_response.status_code = 207
        mocked_response.reason = 'multistatus'
        mocked_response.headers = {}
        mocked_response.content = """
<xml>
<d:multistatus xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
    <d:response>
        <d:href>http://cal.example.com/home/bernard/</d:href>
        <d:propstat>
            <d:prop>
                <c:calendar-home-set>
                    <d:href>http://cal.example.com/home/bernard/calendars/</d:href>
                </c:calendar-home-set>
            </d:prop>
            <d:status>HTTP/1.1 200 OK</d:status>
        </d:propstat>
    </d:response>
</d:multistatus>
</xml>"""
        mocked_davresponse = DAVResponse(mocked_response)
        client.propfind = mock.MagicMock(return_value=mocked_davresponse)
        bernards_calendars = principal.calendar_home_set
        assert_equal(bernards_calendars.url,
                     URL('http://cal.example.com/home/bernard/calendars/'))
예제 #3
0
    def _query(self,
               root=None,
               depth=0,
               query_method='propfind',
               url=None,
               expected_return_value=None):
        """
        This is an internal method for doing a query.  It's a
        result of code-refactoring work, attempting to consolidate
        similar-looking code into a common method.
        """
        # ref https://bitbucket.org/cyrilrbt/caldav/issues/46 -
        # COMPATIBILITY ISSUE. The lines below seems to solve real
        # world problems, though I believe it's the wrong place to
        # inject the missing slash.
        # TODO: find out why the slash is missing and fix
        # it properly.
        # Background: Collection URLs ends with a slash,
        # non-collection URLs does not end with a slash.  If the
        # slash is missing, Servers MAY pretend it's present (RFC
        # 4918, section 5.2, collection resources), hence only some
        # few servers break when the slash is missing.  RFC 4918
        # specifies that collection URLs end with a slash while
        # non-collection URLs should not end with a slash.
        if url is None:
            url = self.url
            if not url.endswith('/'):
                url = URL(str(url) + '/')

        body = ""
        if root:
            if hasattr(root, 'xmlelement'):
                body = etree.tostring(root.xmlelement(),
                                      encoding="utf-8",
                                      xml_declaration=True)
            else:
                body = root
        ret = getattr(self.client, query_method)(url, body, depth)
        if ret.status == 404:
            raise error.NotFoundError(errmsg(ret))
        if ((expected_return_value is not None
             and ret.status != expected_return_value) or ret.status >= 400):
            raise error.exception_by_method[query_method](errmsg(ret))
        return ret
예제 #4
0
    def children(self, type=None):
        """
        List children, using a propfind (resourcetype) on the parent object,
        at depth = 1.
        """
        c = []

        depth = 1
        properties = {}

        props = [dav.ResourceType(), dav.DisplayName()]
        response = self._query_properties(props, depth)
        properties = self._handle_prop_response(response=response,
                                                props=props,
                                                type=type,
                                                what='tag')

        for path in list(properties.keys()):
            resource_type = properties[path][dav.ResourceType.tag]
            resource_name = properties[path][dav.DisplayName.tag]

            if resource_type == type or type is None:
                url = URL(path)
                if url.hostname is None:
                    # Quote when path is not a full URL
                    path = quote(path)
                # TODO: investigate the RFCs thoroughly - why does a "get
                # members of this collection"-request also return the
                # collection URL itself?
                # And why is the strip_trailing_slash-method needed?
                # The collection URL should always end with a slash according
                # to RFC 2518, section 5.2.
                if (self.url.strip_trailing_slash() !=
                        self.url.join(path).strip_trailing_slash()):
                    c.append(
                        (self.url.join(path), resource_type, resource_name))

        return c
예제 #5
0
    def testURL(self):
        """Exercising the URL class"""
        long_url = "http://*****:*****@www.example.com:8080/caldav.php/?foo=bar"

        # 1) URL.objectify should return a valid URL object almost no matter
        # what's thrown in
        url0 = URL.objectify(None)
        url0b = URL.objectify("")
        url1 = URL.objectify(long_url)
        url2 = URL.objectify(url1)
        url3 = URL.objectify("/bar")
        url4 = URL.objectify(urlparse(str(url1)))
        url5 = URL.objectify(urlparse("/bar"))

        # 2) __eq__ works well
        assert_equal(url1, url2)
        assert_equal(url1, url4)
        assert_equal(url3, url5)

        # 3) str will always return the URL
        assert_equal(str(url1), long_url)
        assert_equal(str(url3), "/bar")
        assert_equal(str(url4), long_url)
        assert_equal(str(url5), "/bar")

        ## 3b) repr should also be exercised.  Returns URL(/bar) now.
        assert ("/bar" in repr(url5))
        assert ("URL" in repr(url5))
        assert (len(repr(url5)) < 12)

        # 4) join method
        url6 = url1.join(url2)
        url7 = url1.join(url3)
        url8 = url1.join(url4)
        url9 = url1.join(url5)
        urlA = url1.join("someuser/calendar")
        urlB = url5.join(url1)
        assert_equal(url6, url1)
        assert_equal(url7, "http://*****:*****@www.example.com:8080/bar")
        assert_equal(url8, url1)
        assert_equal(url9, url7)
        assert_equal(
            urlA,
            "http://*****:*****@www.example.com:8080/caldav.php/someuser/calendar")
        assert_equal(urlB, url1)
        assert_raises(ValueError, url1.join, "http://www.google.com")

        # 4b) join method, with URL as input parameter
        url6 = url1.join(URL.objectify(url2))
        url7 = url1.join(URL.objectify(url3))
        url8 = url1.join(URL.objectify(url4))
        url9 = url1.join(URL.objectify(url5))
        urlA = url1.join(URL.objectify("someuser/calendar"))
        urlB = url5.join(URL.objectify(url1))
        url6b = url6.join(url0)
        url6c = url6.join(url0b)
        url6d = url6.join(None)
        for url6alt in (url6b, url6c, url6d):
            assert_equal(url6, url6alt)
        assert_equal(url6, url1)
        assert_equal(url7, "http://*****:*****@www.example.com:8080/bar")
        assert_equal(url8, url1)
        assert_equal(url9, url7)
        assert_equal(
            urlA,
            "http://*****:*****@www.example.com:8080/caldav.php/someuser/calendar")
        assert_equal(urlB, url1)
        assert_raises(ValueError, url1.join, "http://www.google.com")

        # 5) all urlparse methods will work.  always.
        assert_equal(url1.scheme, 'http')
        assert_equal(url2.path, '/caldav.php/')
        assert_equal(url7.username, 'foo')
        assert_equal(url5.path, '/bar')
        urlC = URL.objectify("https://www.example.com:443/foo")
        assert_equal(urlC.port, 443)

        # 6) is_auth returns True if the URL contains a username.
        assert_equal(urlC.is_auth(), False)
        assert_equal(url7.is_auth(), True)

        # 7) unauth() strips username/password
        assert_equal(url7.unauth(), 'http://www.example.com:8080/bar')

        # 8) strip_trailing_slash
        assert_equal(
            URL('http://www.example.com:8080/bar/').strip_trailing_slash(),
            URL('http://www.example.com:8080/bar'))
        assert_equal(
            URL('http://www.example.com:8080/bar/').strip_trailing_slash(),
            URL('http://www.example.com:8080/bar').strip_trailing_slash())