예제 #1
0
파일: app.py 프로젝트: linkdd/9cal
    def propfind(self, path, collections, request_body, environ):
        """
            Manage PROPFIND request.

            According to [RFC 4918], it should have the following request body :

                <D:propfind>
                    <D:prop>
                        ...
                    </D:prop>
                </D:propfind>

            It should return the following content :

                207 Multi-Status

                <D:multistatus>
                    <D:response>
                        <D:href>calendar uri</D:href>
                        <D:propstat>
                            <D:prop>
                                ...
                            </D:prop>
                            <D:status>...</D:status>
                        </D:propstat>
                    </D:response>
                    ...
                </D:multistatus>
        """

        headers = {
            'DAV': '1, 2, access-control, calendar-access',
            'Content-Type': 'text/xml',
        }

        # Read request

        dom = ET.fromstring(request_body)

        dprop = dom.find(xmlutils.tag('D', 'prop'))
        props = [prop.tag for prop in dprop]

        # Write answer

        multistatus = ET.Element(xmlutils.tag('D', 'multistatus'))

        for collection in collections:
            response = xmlutils.propfind_response(path, collection, props)
            multistatus.append(response)

        return 207, headers, [xmlutils.render(multistatus)]
예제 #2
0
파일: app.py 프로젝트: linkdd/9cal
    def delete(self, path, collections, request_body, environ):
        """
            Manage DELETE request.

            The URL contains the element to delete :

                /path/to/calendar/element-uid.ics : delete an item
                /path/to/calendar/ : delete the whole calendar
        """

        collection = collections[0]

        if collection.path == path.strip('/'):
            # Path match the collection, delete the whole collection
            item = collection

        else:
            # Path match an item, delete the item
            item = collection.get_item(self.wsgi_name_from_path(path, collection))

        if item and environ.get('HTTP_IF_MATCH', item.etag) == item.etag:
            # No ETag precondition, or precondition verified

            if item is collection:
                collection.delete()

            else:
                collection.remove(item.name)

            # Write response body

            multistatus = ET.Element(xmlutils.tag('D', 'multistatus'))
            response = ET.Element(xmlutils.tag('D', 'response'))
            multistatus.append(response)

            href = ET.Element(xmlutils.tag('D', 'href'))
            href.text = path
            response.append(href)

            status = ET.Element(xmlutils.tag('D', 'status'))
            status.text = util.http_response(200)
            response.append(status)

            return 204, {}, [xmlutils.render(multistatus)]

        # No item or ETag precondition not verified
        return 412, {}, []
예제 #3
0
파일: app.py 프로젝트: linkdd/9cal
    def report(self, path, collections, request_body, environ):
        """
            Manage REPORT request.

            According to [RFC 3253], it should return 207 Multi-Status.
            The request body contains :

                <C:calendar-multiget / calendar-query>
                    <D:href>...</D:href>
                    <D:prop>
                        ...
                    </D:prop>
                </C:calendar-multiget / calendar-query>

            It should returns the following content :

                <D:multistatus>
                    <D:response>
                        <D:href>
                        <D:propstat>
                            <D:prop>
                                ...
                            </D:prop>
                            <D:status>...</D:status>
                        </D:propstat>
                    </D:response>
                    ...
                </D:multistatus>
        """

        headers = {
            'Content-Type': 'text/xml',
        }

        collection = collections[0]

        # Parse request body
        dom = ET.fromstring(request_body)

        dprop = dom.find(xmlutils.tag('D', 'prop'))
        properties = [prop.tag for prop in dprop]

        if collection:
            if dom.tag == xmlutils.tag('C', 'calendar-multiget'):
                hrefs = set(href.text for href in dom.findall(xmlutils.tag('D', 'href')))

            else:
                hrefs = (path,)
        else:
            hrefs = ()

        # Write response body
        multistatus = ET.Element(xmlutils.tag('D', 'multistatus'))

        for href in hrefs:
            name = self.wsgi_name_from_path(href, collection)

            if name:
                # The reference is an item

                path = '/'.join(href.split('/')[:-1]) + '/'
                items = (item for item in collection.items if item.name == name)

            else:
                # The reference is a collection
                path = href
                items = collection.components

            # Create a response element for all items
            for item in items:
                response = ET.Element(xmlutils.tag('D', 'response'))
                multistatus.append(response)

                xmlhref = ET.Element(xmlutils.tag('D', 'href'))
                xmlhref.text = '/'.join([path.rstrip('/'), item.name]) + '.ics'
                response.append(xmlhref)

                propstat = ET.Element(xmlutils.tag('D', 'propstat'))
                response.append(propstat)

                prop = ET.Element(xmlutils.tag('D', 'prop'))
                propstat.append(prop)

                for tag in properties:
                    element = ET.Element(tag)

                    if tag == xmlutils.tag('D', 'getetag'):
                        element.text = item.etag

                    elif tag == xmlutils.tag('C', 'calendar-data'):
                        if isinstance(item, ical.Component):
                            element.text = item.to_ical()

                    prop.append(element)

                status = ET.Element(xmlutils.tag('D', 'status'))
                status.text = util.http_response(200)
                propstat.append(status)

        return 207, headers, [xmlutils.render(multistatus)]