mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-27 14:57:41 +00:00
Add join_collection to DavStorage
This commit is contained in:
parent
f6f103d1c1
commit
9ede54ed9b
2 changed files with 75 additions and 41 deletions
|
|
@ -186,13 +186,16 @@ def _get_coll(pair_name, storage_name, collection, discovered, config):
|
||||||
args = cls.join_collection(collection=collection, **config)
|
args = cls.join_collection(collection=collection, **config)
|
||||||
args['type'] = storage_type
|
args['type'] = storage_type
|
||||||
return args
|
return args
|
||||||
except NotImplementedError:
|
except NotImplementedError as e:
|
||||||
|
cli_logger.error(e)
|
||||||
raise CliError(
|
raise CliError(
|
||||||
'{pair}: Unable to find collection {collection!r} for storage '
|
'{pair}: Unable to find or create collection {collection!r} '
|
||||||
'{storage!r}. A same-named collection was found for the other '
|
'for storage {storage!r}. A same-named collection was found '
|
||||||
'storage, and vdirsyncer is configured to synchronize '
|
'for the other storage, and vdirsyncer is configured to '
|
||||||
'those.'.format(pair=pair_name, collection=collection,
|
'synchronize these two collections. Please create the '
|
||||||
storage=storage_name))
|
'collection yourself.'
|
||||||
|
.format(pair=pair_name, collection=collection,
|
||||||
|
storage=storage_name))
|
||||||
|
|
||||||
|
|
||||||
def _collections_for_pair_impl(status_path, name_a, name_b, pair_name,
|
def _collections_for_pair_impl(status_path, name_a, name_b, pair_name,
|
||||||
|
|
|
||||||
|
|
@ -71,13 +71,18 @@ def _catch_generator_exceptions(f):
|
||||||
try:
|
try:
|
||||||
for x in f(*args, **kwargs):
|
for x in f(*args, **kwargs):
|
||||||
yield x
|
yield x
|
||||||
except RequestException:
|
except RequestException, exceptions.Error:
|
||||||
import traceback
|
pass
|
||||||
dav_logger.debug(traceback.format_exc())
|
|
||||||
return inner
|
return inner
|
||||||
|
|
||||||
|
|
||||||
class Discover(object):
|
class Discover(object):
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# So we just brute-force a lot of paths here.
|
||||||
|
|
||||||
_resourcetype = None
|
_resourcetype = None
|
||||||
_homeset_xml = None
|
_homeset_xml = None
|
||||||
_homeset_tag = None
|
_homeset_tag = None
|
||||||
|
|
@ -94,8 +99,10 @@ class Discover(object):
|
||||||
def __init__(self, session):
|
def __init__(self, session):
|
||||||
self.session = session
|
self.session = session
|
||||||
|
|
||||||
def find_principal(self, url):
|
def find_principal(self):
|
||||||
return list(self._find_principal(url)) or ['']
|
for server in self.find_dav():
|
||||||
|
for x in list(self._find_principal(server)) or ['']:
|
||||||
|
yield x
|
||||||
|
|
||||||
@_catch_generator_exceptions
|
@_catch_generator_exceptions
|
||||||
def _find_principal(self, url):
|
def _find_principal(self, url):
|
||||||
|
|
@ -122,6 +129,9 @@ class Discover(object):
|
||||||
if principal.tag.endswith('href'):
|
if principal.tag.endswith('href'):
|
||||||
yield principal.text
|
yield principal.text
|
||||||
|
|
||||||
|
def find_dav(self):
|
||||||
|
return list(self._find_dav()) or ['']
|
||||||
|
|
||||||
@_catch_generator_exceptions
|
@_catch_generator_exceptions
|
||||||
def _find_dav(self):
|
def _find_dav(self):
|
||||||
response = self.session.request('GET', self._well_known_uri,
|
response = self.session.request('GET', self._well_known_uri,
|
||||||
|
|
@ -129,31 +139,24 @@ class Discover(object):
|
||||||
is_subpath=False)
|
is_subpath=False)
|
||||||
yield response.headers.get('Location', '')
|
yield response.headers.get('Location', '')
|
||||||
|
|
||||||
def find_dav(self):
|
|
||||||
return list(self._find_dav()) or ['']
|
|
||||||
|
|
||||||
def discover(self):
|
def discover(self):
|
||||||
"""discover all the user's CalDAV or CardDAV collections on the server
|
"""discover all the user's CalDAV or CardDAV collections on the server
|
||||||
:returns: a list of the user's collections (as urls)
|
:returns: a list of the user's collections (as urls)
|
||||||
:rtype: list(unicode)
|
:rtype: list(unicode)
|
||||||
"""
|
"""
|
||||||
# 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
|
|
||||||
#
|
|
||||||
# So we just brute-force a lot of paths here.
|
|
||||||
|
|
||||||
done = set()
|
done = set()
|
||||||
for dav in self.find_dav():
|
for collection in self.find_collections():
|
||||||
for principal in list(self._find_principal(dav)) or ['']:
|
collection['href'] = href = \
|
||||||
for home in itertools.chain(self._find_homes(principal), ['']):
|
utils.urlparse.urljoin(self.session.url, collection['href'])
|
||||||
for collection in self._find_collections(home):
|
if href not in done:
|
||||||
collection['href'] = href = \
|
done.add(href)
|
||||||
utils.urlparse.urljoin(self.session.url,
|
yield collection
|
||||||
collection['href'])
|
|
||||||
if href not in done:
|
def find_homes(self):
|
||||||
done.add(href)
|
for principal in self.find_principal():
|
||||||
yield collection
|
for x in self._find_homes(principal):
|
||||||
|
yield x
|
||||||
|
|
||||||
@_catch_generator_exceptions
|
@_catch_generator_exceptions
|
||||||
def _find_homes(self, principal):
|
def _find_homes(self, principal):
|
||||||
|
|
@ -169,6 +172,11 @@ class Discover(object):
|
||||||
if homeset.tag.endswith('href'):
|
if homeset.tag.endswith('href'):
|
||||||
yield homeset.text
|
yield homeset.text
|
||||||
|
|
||||||
|
def find_collections(self):
|
||||||
|
for home in itertools.chain(self.find_homes(), ['']):
|
||||||
|
for x in self._find_collections(home):
|
||||||
|
yield x
|
||||||
|
|
||||||
@_catch_generator_exceptions
|
@_catch_generator_exceptions
|
||||||
def _find_collections(self, home):
|
def _find_collections(self, home):
|
||||||
"""find all CalDAV collections under `home`"""
|
"""find all CalDAV collections under `home`"""
|
||||||
|
|
@ -311,30 +319,53 @@ class DavStorage(Storage):
|
||||||
self.url = url
|
self.url = url
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_discovery_instance(cls, url, **kwargs):
|
def _get_session(cls, **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 (
|
discover_args, _ = utils.split_dict(kwargs, lambda key: key in (
|
||||||
'username', 'password', 'verify', 'auth', 'useragent',
|
'url', 'username', 'password', 'verify', 'auth', 'useragent',
|
||||||
'verify_fingerprint',
|
'verify_fingerprint',
|
||||||
))
|
))
|
||||||
return cls.discovery_class(DavSession(url=url, **discover_args))
|
return DavSession(**discover_args)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def discover(cls, **kwargs):
|
def discover(cls, **kwargs):
|
||||||
for c in cls._get_discovery_instance(**kwargs).discover():
|
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']
|
url = c['href']
|
||||||
_, collection = url.rstrip('/').rsplit('/', 1)
|
_, collection = url.rstrip('/').rsplit('/', 1)
|
||||||
storage_args = {'url': url, 'collection': collection,
|
storage_args = dict(kwargs)
|
||||||
'collection_human': c['displayname']}
|
storage_args.update({'url': url, 'collection': collection,
|
||||||
storage_args.update(kwargs)
|
'collection_human': c['displayname']})
|
||||||
yield storage_args
|
yield storage_args
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def join_collection(cls, **kwargs):
|
def join_collection(cls, collection, **kwargs):
|
||||||
d = cls._get_discovery_instance(**kwargs)
|
session = cls._get_session(**kwargs)
|
||||||
|
d = cls.discovery_class(session)
|
||||||
|
|
||||||
|
for c in cls.discover(**kwargs):
|
||||||
|
if c['collection'] == collection:
|
||||||
|
return c
|
||||||
|
|
||||||
|
homes = list(d.find_homes())
|
||||||
|
if len(homes) != 1:
|
||||||
|
raise NotImplementedError('Not sure where to create {r!}, {} '
|
||||||
|
'homeset-URLs found (need exactly 1).'
|
||||||
|
.format(collection, len(homes)))
|
||||||
|
|
||||||
|
try:
|
||||||
|
collection_url = '{}/{}'.format(homes[0].rstrip('/'), collection)
|
||||||
|
response = d.session.request('MKCOL', collection_url,
|
||||||
|
is_subpath=False)
|
||||||
|
except RequestException as e:
|
||||||
|
raise NotImplementedError(e)
|
||||||
|
else:
|
||||||
|
rv = dict(kwargs)
|
||||||
|
rv['collection'] = collection
|
||||||
|
rv['url'] = response.url
|
||||||
|
return rv
|
||||||
|
|
||||||
def _normalize_href(self, *args, **kwargs):
|
def _normalize_href(self, *args, **kwargs):
|
||||||
return _normalize_href(self.session.url, *args, **kwargs)
|
return _normalize_href(self.session.url, *args, **kwargs)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue