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, {}, []
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)]
def propfind_response(path, item, props): """ Perform a PROPFIND on ``item`` """ is_collection = isinstance(item, ical.Collection) if is_collection: with item.props as properties: collection_props = properties response = ET.Element(tag('D', 'response')) href = ET.Element(tag('D', 'href')) href.text = item.name response.append(href) propstat404 = ET.Element(tag('D', 'propstat')) propstat200 = ET.Element(tag('D', 'propstat')) response.append(propstat200) prop404 = ET.Element(tag('D', 'prop')) propstat404.append(prop404) prop200 = ET.Element(tag('D', 'prop')) propstat200.append(prop200) for xmltag in props: element = ET.Element(xmltag) tag_not_found = False if xmltag == tag('D', 'getetag'): element.text = item.etag elif xmltag == tag('D', 'principal-URL'): xmltag = ET.Element(tag('D', 'href')) xmltag.text = path element.append(xmltag) elif xmltag in ( tag('D', 'principal-collection-set'), tag('C', 'calendar-user-address-set'), tag('C', 'calendar-home-set') ): xmltag = ET.Element(tag('D', 'href')) xmltag.text = path element.append(xmltag) elif xmltag == tag('C', 'supported-calendar-component-set'): for component in ("VTODO", "VEVENT", "VJOURNAL"): comp = ET.Element(tag('C', 'comp')) comp.set('name', component) element.append(comp) elif xmltag == tag('D', 'current-user-principal'): xmltag = ET.Element(tag('D', 'href')) xmltag.text = path element.append(xmltag) elif xmltag == tag('D', 'current-user-privilege-set'): privilege = ET.Element(tag('D', 'privilege')) privilege.append(ET.Element(tag('D', 'all'))) element.append(privilege) elif xmltag == tag('D', 'supported-report-set'): for report_name in ( 'principal-property-search', 'sync-collection', 'expand-property', 'principal-search-property-set' ): supported = ET.Element(tag('D', 'supported-report')) report_tag = ET.Element(tag('D', 'report')) report_tag.text = report_name supported.append(report_tag) element.append(supported) elif is_collection: # Only for collections if xmltag == tag('D', 'getcontenttype'): element.text = item.mimetype elif xmltag == tag('D', 'resourcetype'): xmltag = ET.Element(tag('C', item.resource_type)) element.append(xmltag) xmltag = ET.Element(tag('D', 'collection')) element.append(xmltag) elif xmltag == tag('D', 'owner'): element.text = os.path.dirname(path) elif xmltag == tag('CS', 'getctag'): element.text = item.etag elif xmltag == tag('C', 'calendar-timezone'): element.text = item.timezones.to_ical() else: tagname = tag_clark(xmltag) if tagname in collection_props: element.text = collection_props[tagname] else: tag_not_found = True # Not for collections elif xmltag == tag('D', 'getcontenttype'): element.text = '{0}; component={1}'.format(item.mimetype, item.tag.lower()) elif xmltag == tag('D', 'resourcetype'): # Must be empty for non-collection element pass else: tag_not_found = True if tag_not_found: prop404.append(element) else: prop200.append(element) status200 = ET.Element(tag('D', 'status')) status200.text = http_response(200) propstat200.append(status200) status404 = ET.Element(tag('D', 'status')) status404.text = http_response(404) propstat404.append(status404) if len(prop404): response.append(propstat404) return response