Better collection discovery
This commit is contained in:
parent
058bd454c0
commit
7a0e267f19
@ -355,7 +355,7 @@ class Application(object):
|
|||||||
def do_DELETE(self, environ, read_collections, write_collections, content,
|
def do_DELETE(self, environ, read_collections, write_collections, content,
|
||||||
user):
|
user):
|
||||||
"""Manage DELETE request."""
|
"""Manage DELETE request."""
|
||||||
if not len(write_collections):
|
if not write_collections:
|
||||||
return NOT_ALLOWED
|
return NOT_ALLOWED
|
||||||
|
|
||||||
collection = write_collections[0]
|
collection = write_collections[0]
|
||||||
@ -387,7 +387,7 @@ class Application(object):
|
|||||||
answer = b"<!DOCTYPE html>\n<title>Radicale</title>Radicale works!"
|
answer = b"<!DOCTYPE html>\n<title>Radicale</title>Radicale works!"
|
||||||
return client.OK, headers, answer
|
return client.OK, headers, answer
|
||||||
|
|
||||||
if not len(read_collections):
|
if not read_collections:
|
||||||
return NOT_ALLOWED
|
return NOT_ALLOWED
|
||||||
|
|
||||||
collection = read_collections[0]
|
collection = read_collections[0]
|
||||||
@ -407,8 +407,8 @@ class Application(object):
|
|||||||
else:
|
else:
|
||||||
return client.NOT_FOUND, {}, None
|
return client.NOT_FOUND, {}, None
|
||||||
elif not collection.exists:
|
elif not collection.exists:
|
||||||
log.LOGGER.debug("Collection %s unknown" % collection.name)
|
log.LOGGER.debug("Collection at %s unknown" % environ["PATH_INFO"])
|
||||||
return client.NOT_FOUND
|
return client.NOT_FOUND, {}, None
|
||||||
else:
|
else:
|
||||||
# Get whole collection
|
# Get whole collection
|
||||||
answer_text = collection.text
|
answer_text = collection.text
|
||||||
@ -431,7 +431,7 @@ class Application(object):
|
|||||||
def do_MKCALENDAR(self, environ, read_collections, write_collections,
|
def do_MKCALENDAR(self, environ, read_collections, write_collections,
|
||||||
content, user):
|
content, user):
|
||||||
"""Manage MKCALENDAR request."""
|
"""Manage MKCALENDAR request."""
|
||||||
if not len(write_collections):
|
if not write_collections:
|
||||||
return NOT_ALLOWED
|
return NOT_ALLOWED
|
||||||
|
|
||||||
collection = write_collections[0]
|
collection = write_collections[0]
|
||||||
@ -450,7 +450,7 @@ class Application(object):
|
|||||||
def do_MKCOL(self, environ, read_collections, write_collections, content,
|
def do_MKCOL(self, environ, read_collections, write_collections, content,
|
||||||
user):
|
user):
|
||||||
"""Manage MKCOL request."""
|
"""Manage MKCOL request."""
|
||||||
if not len(write_collections):
|
if not write_collections:
|
||||||
return NOT_ALLOWED
|
return NOT_ALLOWED
|
||||||
|
|
||||||
collection = write_collections[0]
|
collection = write_collections[0]
|
||||||
@ -465,7 +465,7 @@ class Application(object):
|
|||||||
def do_MOVE(self, environ, read_collections, write_collections, content,
|
def do_MOVE(self, environ, read_collections, write_collections, content,
|
||||||
user):
|
user):
|
||||||
"""Manage MOVE request."""
|
"""Manage MOVE request."""
|
||||||
if not len(write_collections):
|
if not write_collections:
|
||||||
return NOT_ALLOWED
|
return NOT_ALLOWED
|
||||||
|
|
||||||
from_collection = write_collections[0]
|
from_collection = write_collections[0]
|
||||||
@ -510,7 +510,8 @@ class Application(object):
|
|||||||
def do_PROPFIND(self, environ, read_collections, write_collections,
|
def do_PROPFIND(self, environ, read_collections, write_collections,
|
||||||
content, user):
|
content, user):
|
||||||
"""Manage PROPFIND request."""
|
"""Manage PROPFIND request."""
|
||||||
# Rights is handled by collection in xmlutils.propfind
|
if not any(collection.exists for collection in read_collections):
|
||||||
|
return client.NOT_FOUND, {}, None
|
||||||
headers = {
|
headers = {
|
||||||
"DAV": "1, 2, 3, calendar-access, addressbook, extended-mkcol",
|
"DAV": "1, 2, 3, calendar-access, addressbook, extended-mkcol",
|
||||||
"Content-Type": "text/xml"}
|
"Content-Type": "text/xml"}
|
||||||
@ -521,7 +522,7 @@ class Application(object):
|
|||||||
def do_PROPPATCH(self, environ, read_collections, write_collections,
|
def do_PROPPATCH(self, environ, read_collections, write_collections,
|
||||||
content, user):
|
content, user):
|
||||||
"""Manage PROPPATCH request."""
|
"""Manage PROPPATCH request."""
|
||||||
if not len(write_collections):
|
if not write_collections:
|
||||||
return NOT_ALLOWED
|
return NOT_ALLOWED
|
||||||
|
|
||||||
collection = write_collections[0]
|
collection = write_collections[0]
|
||||||
@ -536,7 +537,7 @@ class Application(object):
|
|||||||
def do_PUT(self, environ, read_collections, write_collections, content,
|
def do_PUT(self, environ, read_collections, write_collections, content,
|
||||||
user):
|
user):
|
||||||
"""Manage PUT request."""
|
"""Manage PUT request."""
|
||||||
if not len(write_collections):
|
if not write_collections:
|
||||||
return NOT_ALLOWED
|
return NOT_ALLOWED
|
||||||
|
|
||||||
collection = write_collections[0]
|
collection = write_collections[0]
|
||||||
@ -571,7 +572,7 @@ class Application(object):
|
|||||||
def do_REPORT(self, environ, read_collections, write_collections, content,
|
def do_REPORT(self, environ, read_collections, write_collections, content,
|
||||||
user):
|
user):
|
||||||
"""Manage REPORT request."""
|
"""Manage REPORT request."""
|
||||||
if not len(read_collections):
|
if not read_collections:
|
||||||
return NOT_ALLOWED
|
return NOT_ALLOWED
|
||||||
|
|
||||||
collection = read_collections[0]
|
collection = read_collections[0]
|
||||||
|
@ -222,8 +222,7 @@ class Collection(object):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
# Try to guess if the path leads to a collection or an item
|
# Try to guess if the path leads to a collection or an item
|
||||||
if (cls.is_leaf("/".join(attributes[:-1])) or not
|
if cls.is_leaf("/".join(attributes[:-1])):
|
||||||
path.endswith(("/", "/caldav", "/carddav"))):
|
|
||||||
attributes.pop()
|
attributes.pop()
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
|
@ -77,6 +77,10 @@ class Collection(ical.Collection):
|
|||||||
if not os.path.exists(self._filesystem_path):
|
if not os.path.exists(self._filesystem_path):
|
||||||
os.makedirs(self._filesystem_path)
|
os.makedirs(self._filesystem_path)
|
||||||
|
|
||||||
|
def set_mimetype(self, mimetype):
|
||||||
|
self._create_dirs()
|
||||||
|
return super().set_mimetype(mimetype)
|
||||||
|
|
||||||
def save(self, text):
|
def save(self, text):
|
||||||
self._create_dirs()
|
self._create_dirs()
|
||||||
item_types = (
|
item_types = (
|
||||||
@ -185,7 +189,6 @@ class Collection(ical.Collection):
|
|||||||
old_properties = properties.copy()
|
old_properties = properties.copy()
|
||||||
yield properties
|
yield properties
|
||||||
# On exit
|
# On exit
|
||||||
self._create_dirs()
|
|
||||||
if old_properties != properties:
|
if old_properties != properties:
|
||||||
with open(self._props_path, "w") as prop_file:
|
with open(self._props_path, "w") as prop_file:
|
||||||
json.dump(properties, prop_file)
|
json.dump(properties, prop_file)
|
||||||
|
@ -192,9 +192,8 @@ def propfind(path, xml_request, read_collections, write_collections, user=None):
|
|||||||
|
|
||||||
Read rfc4918-9.1 for info.
|
Read rfc4918-9.1 for info.
|
||||||
|
|
||||||
The collections parameter is a list of collections that are
|
The collections parameter is a list of collections that are to be included
|
||||||
to be included in the output. Rights checking has to be done
|
in the output.
|
||||||
by the caller.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Reading request
|
# Reading request
|
||||||
@ -231,6 +230,7 @@ def _propfind_response(path, item, props, user, write=False):
|
|||||||
"""Build and return a PROPFIND response."""
|
"""Build and return a PROPFIND response."""
|
||||||
is_collection = isinstance(item, ical.Collection)
|
is_collection = isinstance(item, ical.Collection)
|
||||||
if is_collection:
|
if is_collection:
|
||||||
|
is_leaf = item.is_leaf(item.path)
|
||||||
with item.props as properties:
|
with item.props as properties:
|
||||||
collection_props = properties
|
collection_props = properties
|
||||||
|
|
||||||
@ -271,15 +271,17 @@ def _propfind_response(path, item, props, user, write=False):
|
|||||||
# This is not a Todo
|
# This is not a Todo
|
||||||
# pylint: disable=W0511
|
# pylint: disable=W0511
|
||||||
human_tag = _tag_from_clark(tag)
|
human_tag = _tag_from_clark(tag)
|
||||||
if is_collection and human_tag in collection_props:
|
if is_collection and is_leaf:
|
||||||
# TODO: what do we have to do if it's not a collection?
|
if human_tag in collection_props:
|
||||||
components = collection_props[human_tag].split(",")
|
components = collection_props[human_tag].split(",")
|
||||||
|
else:
|
||||||
|
components = ("VTODO", "VEVENT", "VJOURNAL")
|
||||||
|
for component in components:
|
||||||
|
comp = ET.Element(_tag("C", "comp"))
|
||||||
|
comp.set("name", component)
|
||||||
|
element.append(comp)
|
||||||
else:
|
else:
|
||||||
components = ("VTODO", "VEVENT", "VJOURNAL")
|
is404 = True
|
||||||
for component in components:
|
|
||||||
comp = ET.Element(_tag("C", "comp"))
|
|
||||||
comp.set("name", component)
|
|
||||||
element.append(comp)
|
|
||||||
# pylint: enable=W0511
|
# pylint: enable=W0511
|
||||||
elif tag == _tag("D", "current-user-principal") and user:
|
elif tag == _tag("D", "current-user-principal") and user:
|
||||||
tag = ET.Element(_tag("D", "href"))
|
tag = ET.Element(_tag("D", "href"))
|
||||||
@ -310,7 +312,7 @@ def _propfind_response(path, item, props, user, write=False):
|
|||||||
if item.is_principal:
|
if item.is_principal:
|
||||||
tag = ET.Element(_tag("D", "principal"))
|
tag = ET.Element(_tag("D", "principal"))
|
||||||
element.append(tag)
|
element.append(tag)
|
||||||
if item.is_leaf(item.path) or (
|
if is_leaf or (
|
||||||
not item.exists and item.resource_type):
|
not item.exists and item.resource_type):
|
||||||
# 2nd case happens when the collection is not stored yet,
|
# 2nd case happens when the collection is not stored yet,
|
||||||
# but the resource type is guessed
|
# but the resource type is guessed
|
||||||
@ -321,23 +323,26 @@ def _propfind_response(path, item, props, user, write=False):
|
|||||||
element.append(tag)
|
element.append(tag)
|
||||||
tag = ET.Element(_tag("D", "collection"))
|
tag = ET.Element(_tag("D", "collection"))
|
||||||
element.append(tag)
|
element.append(tag)
|
||||||
elif tag == _tag("D", "owner") and item.owner_url:
|
elif is_leaf:
|
||||||
element.text = item.owner_url
|
if tag == _tag("D", "owner") and item.owner_url:
|
||||||
elif tag == _tag("CS", "getctag"):
|
element.text = item.owner_url
|
||||||
element.text = item.etag
|
elif tag == _tag("CS", "getctag"):
|
||||||
elif tag == _tag("C", "calendar-timezone"):
|
element.text = item.etag
|
||||||
element.text = ical.serialize(
|
elif tag == _tag("C", "calendar-timezone"):
|
||||||
item.tag, item.headers, item.timezones)
|
element.text = ical.serialize(
|
||||||
elif tag == _tag("D", "displayname"):
|
item.tag, item.headers, item.timezones)
|
||||||
element.text = item.name
|
elif tag == _tag("D", "displayname"):
|
||||||
elif tag == _tag("ICAL", "calendar-color"):
|
element.text = item.name
|
||||||
element.text = item.color
|
elif tag == _tag("ICAL", "calendar-color"):
|
||||||
else:
|
element.text = item.color
|
||||||
human_tag = _tag_from_clark(tag)
|
|
||||||
if human_tag in collection_props:
|
|
||||||
element.text = collection_props[human_tag]
|
|
||||||
else:
|
else:
|
||||||
is404 = True
|
human_tag = _tag_from_clark(tag)
|
||||||
|
if human_tag in collection_props:
|
||||||
|
element.text = collection_props[human_tag]
|
||||||
|
else:
|
||||||
|
is404 = True
|
||||||
|
else:
|
||||||
|
is404 = True
|
||||||
# Not for collections
|
# Not for collections
|
||||||
elif tag == _tag("D", "getcontenttype"):
|
elif tag == _tag("D", "getcontenttype"):
|
||||||
element.text = "%s; component=%s" % (
|
element.text = "%s; component=%s" % (
|
||||||
|
Loading…
Reference in New Issue
Block a user