dav: Fully move collection management into Discover

This commit is contained in:
Markus Unterwaditzer 2015-06-04 12:18:18 +02:00
parent ed6a65a6ab
commit 7d41378505
2 changed files with 71 additions and 82 deletions

View file

@ -116,9 +116,6 @@ class ServerMixin(object):
'collection': collection, 'unsafe_href_chars': ''}
if collection is not None:
if storage_backend != 'multifilesystem':
# XXX: https://github.com/Kozea/Radicale/pull/236
rv = self.storage_class.create_collection(**rv)
s = self.storage_class(**rv)
s.delete(*s.upload(get_item()))

View file

@ -82,6 +82,7 @@ def _get_collection_from_url(url):
class Discover(object):
_namespace = None
_resourcetype = None
_homeset_xml = None
_homeset_tag = None
@ -95,8 +96,17 @@ class Discover(object):
</d:propfind>
"""
def __init__(self, session):
self.session = session
def __init__(self, **kwargs):
if kwargs.pop('collection', None) is not None:
raise TypeError('collection argument must not be given.')
discover_args, _ = utils.split_dict(kwargs, lambda key: key in (
'url', 'username', 'password', 'verify', 'auth', 'useragent',
'verify_fingerprint', 'auth_cert',
))
self.session = DavSession(**discover_args)
self.kwargs = kwargs
def find_dav(self):
try:
@ -113,7 +123,11 @@ class Discover(object):
def find_principal(self, url=None):
if url is None:
url = self.find_dav()
try:
return self.find_principal('')
except (HTTPError, exceptions.Error):
return self.find_principal(self.find_dav())
headers = self.session.get_default_headers()
headers['Depth'] = 0
body = """
@ -171,20 +185,60 @@ class Discover(object):
yield {'href': href, 'displayname': displayname}
def discover(self):
for x in self.find_collections():
yield x
for c in self.find_collections():
url = c['href']
collection = _get_collection_from_url(url)
storage_args = dict(self.kwargs)
storage_args.update({'url': url, 'collection': collection,
'collection_human': c['displayname']})
yield storage_args
def create(self, collection):
if collection is None:
collection = _get_collection_from_url(self.kwargs['url'])
for c in self.discover():
if c['collection'] == collection:
return c
home = self.find_home()
url = '{}/{}'.format(home.rstrip('/'), collection)
# Another one of Radicale's specialties: Discovery is broken (returning
# completely wrong URLs at every stage) as of version 0.9.
# https://github.com/Kozea/Radicale/issues/196
try:
for x in self.find_collections(''):
yield x
except (InvalidXMLResponse, HTTPError, exceptions.Error):
pass
url = self._create_collection_impl(url)
except HTTPError as e:
raise NotImplementedError(e)
else:
rv = dict(self.kwargs)
rv['collection'] = collection
rv['url'] = url
return rv
def _create_collection_impl(self, url):
data = '''<?xml version="1.0" encoding="utf-8" ?>
<D:mkcol xmlns:D="DAV:" xmlns:C="{}">
<D:set>
<D:prop>
<D:resourcetype>
<D:collection/>
<C:{}/>
</D:resourcetype>
</D:prop>
</D:set>
</D:mkcol>
'''.format(self._namespace, self._resourcetype)
response = self.session.request(
'MKCOL',
url,
data=data,
headers=self.session.get_default_headers(),
)
return response.url
class CalDiscover(Discover):
_namespace = 'urn:ietf:params:xml:ns:caldav'
_resourcetype = 'calendar'
_homeset_xml = """
<d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
@ -198,6 +252,7 @@ class CalDiscover(Discover):
class CardDiscover(Discover):
_namespace = 'urn:ietf:params:xml:ns:carddav'
_resourcetype = 'addressbook'
_homeset_xml = """
<d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:carddav">
@ -294,74 +349,15 @@ class DavStorage(Storage):
self.username = username
self.url = url
@classmethod
def _get_session(cls, **kwargs):
discover_args, _ = utils.split_dict(kwargs, lambda key: key in (
'url', 'username', 'password', 'verify', 'auth', 'useragent',
'verify_fingerprint', 'auth_cert',
))
return DavSession(**discover_args)
@classmethod
def discover(cls, **kwargs):
if kwargs.pop('collection', None) is not None:
raise TypeError('collection argument must not be given.')
d = cls.discovery_class(cls._get_session(**kwargs))
for c in d.discover():
url = c['href']
collection = _get_collection_from_url(url)
storage_args = dict(kwargs)
storage_args.update({'url': url, 'collection': collection,
'collection_human': c['displayname']})
yield storage_args
d = cls.discovery_class(**kwargs)
return d.discover()
@classmethod
def create_collection(cls, collection, **kwargs):
if collection is None:
collection = _get_collection_from_url(kwargs['url'])
session = cls._get_session(**kwargs)
d = cls.discovery_class(session)
for c in cls.discover(**kwargs):
if c['collection'] == collection:
return c
home = d.find_home()
url = '{}/{}'.format(home.rstrip('/'), collection)
try:
url = cls._create_collection_impl(d, url, kwargs)
except HTTPError as e:
raise NotImplementedError(e)
else:
rv = dict(kwargs)
rv['collection'] = collection
rv['url'] = url
return rv
@classmethod
def _create_collection_impl(cls, d, url, kwargs):
data = '''<?xml version="1.0" encoding="utf-8" ?>
<D:mkcol xmlns:D="DAV:" xmlns:C="{}">
<D:set>
<D:prop>
<D:resourcetype>
<D:collection/>
<C:{}/>
</D:resourcetype>
</D:prop>
</D:set>
</D:mkcol>
'''.format(cls._dav_namespace, cls._dav_resourcetype)
response = d.session.request(
'MKCOL',
url,
data=data,
headers=d.session.get_default_headers(),
)
return response.url
d = cls.discovery_class(**kwargs)
return d.create(collection)
def _normalize_href(self, *args, **kwargs):
return _normalize_href(self.session.url, *args, **kwargs)
@ -588,8 +584,6 @@ class CaldavStorage(DavStorage):
fileext = '.ics'
item_mimetype = 'text/calendar'
discovery_class = CalDiscover
_dav_namespace = 'urn:ietf:params:xml:ns:caldav'
_dav_resourcetype = 'calendar'
start_date = None
end_date = None
@ -723,6 +717,4 @@ class CarddavStorage(DavStorage):
{hrefs}
</C:addressbook-multiget>'''
_dav_namespace = 'urn:ietf:params:xml:ns:carddav'
_dav_resourcetype = 'addressbook'
get_multi_data_query = '{urn:ietf:params:xml:ns:carddav}address-data'