mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-03-25 08:55:50 +00:00
Less files
This commit is contained in:
parent
47d3b1917d
commit
475671f437
8 changed files with 190 additions and 240 deletions
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.tests.storage.dav
|
||||
|
|
@ -7,43 +6,3 @@
|
|||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from .. import StorageTests
|
||||
import vdirsyncer.exceptions as exceptions
|
||||
from vdirsyncer.storage.base import Item
|
||||
import requests.exceptions
|
||||
|
||||
|
||||
dav_server = os.environ.get('DAV_SERVER', '').strip() or 'radicale_filesystem'
|
||||
if dav_server.startswith('radicale_'):
|
||||
from ._radicale import ServerMixin
|
||||
elif dav_server == 'owncloud':
|
||||
from ._owncloud import ServerMixin
|
||||
else:
|
||||
raise RuntimeError('{} is not a known DAV server.'.format(dav_server))
|
||||
|
||||
try:
|
||||
import radicale
|
||||
radicale_version = radicale.VERSION
|
||||
del radicale
|
||||
except ImportError:
|
||||
radicale_version = None
|
||||
|
||||
|
||||
pytestmark = pytest.mark.xfail(
|
||||
dav_server == 'radicale_database' and radicale_version == '0.8',
|
||||
reason='Database storage of Radicale 0.8 is broken.')
|
||||
|
||||
|
||||
class DavStorageTests(ServerMixin, StorageTests):
|
||||
def test_dav_broken_item(self):
|
||||
item = Item(u'UID:1')
|
||||
s = self._get_storage()
|
||||
try:
|
||||
s.upload(item)
|
||||
except (exceptions.Error, requests.exceptions.HTTPError):
|
||||
pass
|
||||
assert not list(s.list())
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.tests.storage.test_carddav
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
from vdirsyncer.storage.dav.carddav import CarddavStorage
|
||||
from . import DavStorageTests, pytestmark
|
||||
|
||||
|
||||
VCARD_TEMPLATE = u'''BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
FN:Cyrus Daboo
|
||||
N:Daboo;Cyrus
|
||||
ADR;TYPE=POSTAL:;2822 Email HQ;Suite 2821;RFCVille;PA;15213;USA
|
||||
EMAIL;TYPE=INTERNET;TYPE=PREF:cyrus@example.com
|
||||
NICKNAME:me
|
||||
NOTE:Example VCard.
|
||||
ORG:Self Employed
|
||||
TEL;TYPE=WORK;TYPE=VOICE:412 605 0499
|
||||
TEL;TYPE=FAX:412 605 0705
|
||||
URL:http://www.example.com
|
||||
UID:{uid}
|
||||
X-SOMETHING:{r}
|
||||
END:VCARD'''
|
||||
|
||||
|
||||
class TestCarddavStorage(DavStorageTests):
|
||||
storage_class = CarddavStorage
|
||||
item_template = VCARD_TEMPLATE
|
||||
|
|
@ -1,19 +1,59 @@
|
|||
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.tests.storage.test_caldav
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
vdirsyncer.tests.storage.dav.test_main
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
|
||||
import os
|
||||
import pytest
|
||||
import requests.exceptions
|
||||
from vdirsyncer.storage.dav.caldav import CaldavStorage
|
||||
|
||||
from .. import StorageTests
|
||||
import vdirsyncer.exceptions as exceptions
|
||||
from . import DavStorageTests, pytestmark
|
||||
from vdirsyncer.storage.base import Item
|
||||
from vdirsyncer.storage.dav import CaldavStorage, CarddavStorage
|
||||
import requests.exceptions
|
||||
|
||||
|
||||
dav_server = os.environ.get('DAV_SERVER', '').strip() or 'radicale_filesystem'
|
||||
if dav_server.startswith('radicale_'):
|
||||
from ._radicale import ServerMixin
|
||||
elif dav_server == 'owncloud':
|
||||
from ._owncloud import ServerMixin
|
||||
else:
|
||||
raise RuntimeError('{} is not a known DAV server.'.format(dav_server))
|
||||
|
||||
try:
|
||||
import radicale
|
||||
radicale_version = radicale.VERSION
|
||||
del radicale
|
||||
except ImportError:
|
||||
radicale_version = None
|
||||
|
||||
|
||||
pytestmark = pytest.mark.xfail(
|
||||
dav_server == 'radicale_database' and radicale_version == '0.8',
|
||||
reason='Database storage of Radicale 0.8 is broken.')
|
||||
|
||||
|
||||
VCARD_TEMPLATE = u'''BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
FN:Cyrus Daboo
|
||||
N:Daboo;Cyrus
|
||||
ADR;TYPE=POSTAL:;2822 Email HQ;Suite 2821;RFCVille;PA;15213;USA
|
||||
EMAIL;TYPE=INTERNET;TYPE=PREF:cyrus@example.com
|
||||
NICKNAME:me
|
||||
NOTE:Example VCard.
|
||||
ORG:Self Employed
|
||||
TEL;TYPE=WORK;TYPE=VOICE:412 605 0499
|
||||
TEL;TYPE=FAX:412 605 0705
|
||||
URL:http://www.example.com
|
||||
UID:{uid}
|
||||
X-SOMETHING:{r}
|
||||
END:VCARD'''
|
||||
|
||||
|
||||
TASK_TEMPLATE = u'''BEGIN:VCALENDAR
|
||||
|
|
@ -43,13 +83,24 @@ UID:{uid}
|
|||
END:VEVENT
|
||||
END:VCALENDAR'''
|
||||
|
||||
|
||||
templates = {
|
||||
'VCARD': VCARD_TEMPLATE,
|
||||
'VEVENT': EVENT_TEMPLATE,
|
||||
'VTODO': TASK_TEMPLATE
|
||||
}
|
||||
|
||||
|
||||
class DavStorageTests(ServerMixin, StorageTests):
|
||||
def test_dav_broken_item(self):
|
||||
item = Item(u'UID:1')
|
||||
s = self._get_storage()
|
||||
try:
|
||||
s.upload(item)
|
||||
except (exceptions.Error, requests.exceptions.HTTPError):
|
||||
pass
|
||||
assert not list(s.list())
|
||||
|
||||
|
||||
class TestCaldavStorage(DavStorageTests):
|
||||
storage_class = CaldavStorage
|
||||
|
||||
|
|
@ -90,3 +141,8 @@ class TestCaldavStorage(DavStorageTests):
|
|||
a = self.storage_class(item_types='VTODO,VEVENT', **kw)
|
||||
b = self.storage_class(item_types=('VTODO', 'VEVENT'), **kw)
|
||||
assert a.item_types == b.item_types == ('VTODO', 'VEVENT')
|
||||
|
||||
|
||||
class TestCarddavStorage(DavStorageTests):
|
||||
storage_class = CarddavStorage
|
||||
item_template = VCARD_TEMPLATE
|
||||
|
|
@ -12,8 +12,8 @@
|
|||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
from .dav.caldav import CaldavStorage
|
||||
from .dav.carddav import CarddavStorage
|
||||
from .dav import CaldavStorage
|
||||
from .dav import CarddavStorage
|
||||
from .filesystem import FilesystemStorage
|
||||
from .http import HttpStorage
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.storage.dav.base
|
||||
vdirsyncer.storage.dav
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer, Christian Geier and contributors
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
from ..base import Item
|
||||
from ..http import HttpStorageBase
|
||||
from .base import Item
|
||||
from .http import HttpStorageBase
|
||||
import vdirsyncer.exceptions as exceptions
|
||||
import vdirsyncer.log as log
|
||||
import requests
|
||||
|
|
@ -18,6 +18,9 @@ from lxml import etree
|
|||
|
||||
dav_logger = log.get('storage.dav')
|
||||
|
||||
CALDAV_DT_FORMAT = '%Y%m%dT%H%M%SZ'
|
||||
CONFIG_DT_FORMAT = '%Y-%m-%d'
|
||||
|
||||
|
||||
class DavStorage(HttpStorageBase):
|
||||
|
||||
|
|
@ -228,3 +231,122 @@ class DavStorage(HttpStorageBase):
|
|||
'{DAV:}prop').find('{DAV:}getetag').text
|
||||
href = self._normalize_href(element.find('{DAV:}href').text)
|
||||
yield href, etag
|
||||
|
||||
|
||||
|
||||
|
||||
class CaldavStorage(DavStorage):
|
||||
|
||||
fileext = '.ics'
|
||||
item_mimetype = 'text/calendar'
|
||||
dav_header = 'calendar-access'
|
||||
leif_class = 'CalDiscover'
|
||||
|
||||
start_date = None
|
||||
end_date = None
|
||||
|
||||
get_multi_template = '''<?xml version="1.0" encoding="utf-8" ?>
|
||||
<C:calendar-multiget xmlns:D="DAV:"
|
||||
xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||
<D:prop>
|
||||
<D:getetag/>
|
||||
<C:calendar-data/>
|
||||
</D:prop>
|
||||
{hrefs}
|
||||
</C:calendar-multiget>'''
|
||||
|
||||
get_multi_data_query = '{urn:ietf:params:xml:ns:caldav}calendar-data'
|
||||
|
||||
def __init__(self, start_date=None, end_date=None,
|
||||
item_types=('VTODO', 'VEVENT'), **kwargs):
|
||||
'''
|
||||
:param start_date: Start date of timerange to show, default -inf.
|
||||
:param end_date: End date of timerange to show, default +inf.
|
||||
:param item_types: The item types to show from the server. Dependent on
|
||||
server functionality, no clientside validation of results. This
|
||||
currently only affects the `list` method, but this shouldn't cause
|
||||
problems in the normal usecase.
|
||||
'''
|
||||
super(CaldavStorage, self).__init__(**kwargs)
|
||||
if isinstance(item_types, str):
|
||||
item_types = [x.strip() for x in item_types.split(',')]
|
||||
self.item_types = tuple(item_types)
|
||||
if (start_date is None) != (end_date is None):
|
||||
raise ValueError('If start_date is given, '
|
||||
'end_date has to be given too.')
|
||||
elif start_date is not None and end_date is not None:
|
||||
namespace = dict(datetime.__dict__)
|
||||
namespace['start_date'] = self.start_date = \
|
||||
(eval(start_date, namespace) if isinstance(start_date, str)
|
||||
else start_date)
|
||||
self.end_date = \
|
||||
(eval(end_date, namespace) if isinstance(end_date, str)
|
||||
else end_date)
|
||||
|
||||
self._list_template = self._get_list_template()
|
||||
|
||||
def _get_list_template(self):
|
||||
data = '''<?xml version="1.0" encoding="utf-8" ?>
|
||||
<C:calendar-query xmlns:D="DAV:"
|
||||
xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||
<D:prop>
|
||||
<D:getetag/>
|
||||
</D:prop>
|
||||
<C:filter>
|
||||
<C:comp-filter name="VCALENDAR">
|
||||
<C:comp-filter name="{component}">
|
||||
{caldavfilter}
|
||||
</C:comp-filter>
|
||||
</C:comp-filter>
|
||||
</C:filter>
|
||||
</C:calendar-query>'''
|
||||
start = self.start_date
|
||||
end = self.end_date
|
||||
caldavfilter = ''
|
||||
if start is not None and end is not None:
|
||||
start = start.strftime(CALDAV_DT_FORMAT)
|
||||
end = end.strftime(CALDAV_DT_FORMAT)
|
||||
caldavfilter = ('<C:time-range start="{start}" end="{end}"/>'
|
||||
.format(start=start, end=end))
|
||||
return data.format(caldavfilter=caldavfilter, component='{item_type}')
|
||||
|
||||
def list(self):
|
||||
hrefs = set()
|
||||
for t in self.item_types:
|
||||
xml = self._list_template.format(item_type=t)
|
||||
for href, etag in self._list(xml):
|
||||
assert href not in hrefs
|
||||
hrefs.add(href)
|
||||
yield href, etag
|
||||
|
||||
|
||||
class CarddavStorage(DavStorage):
|
||||
|
||||
fileext = '.vcf'
|
||||
item_mimetype = 'text/vcard'
|
||||
dav_header = 'addressbook'
|
||||
leif_class = 'CardDiscover'
|
||||
|
||||
get_multi_template = '''<?xml version="1.0" encoding="utf-8" ?>
|
||||
<C:addressbook-multiget xmlns:D="DAV:"
|
||||
xmlns:C="urn:ietf:params:xml:ns:carddav">
|
||||
<D:prop>
|
||||
<D:getetag/>
|
||||
<C:address-data/>
|
||||
</D:prop>
|
||||
{hrefs}
|
||||
</C:addressbook-multiget>'''
|
||||
|
||||
get_multi_data_query = '{urn:ietf:params:xml:ns:carddav}address-data'
|
||||
|
||||
def list(self):
|
||||
return self._list('''<?xml version="1.0" encoding="utf-8" ?>
|
||||
<C:addressbook-query xmlns:D="DAV:"
|
||||
xmlns:C="urn:ietf:params:xml:ns:carddav">
|
||||
<D:prop>
|
||||
<D:getetag/>
|
||||
</D:prop>
|
||||
<C:filter>
|
||||
<C:comp-filter name="VCARD"/>
|
||||
</C:filter>
|
||||
</C:addressbook-query>''')
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.storage.dav
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.storage.dav.caldav
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Original version from khal: https://github.com/geier/khal
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer, Christian Geier and contributors
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
from .base import DavStorage
|
||||
import datetime
|
||||
|
||||
CALDAV_DT_FORMAT = '%Y%m%dT%H%M%SZ'
|
||||
CONFIG_DT_FORMAT = '%Y-%m-%d'
|
||||
|
||||
|
||||
class CaldavStorage(DavStorage):
|
||||
|
||||
fileext = '.ics'
|
||||
item_mimetype = 'text/calendar'
|
||||
dav_header = 'calendar-access'
|
||||
leif_class = 'CalDiscover'
|
||||
|
||||
start_date = None
|
||||
end_date = None
|
||||
|
||||
get_multi_template = '''<?xml version="1.0" encoding="utf-8" ?>
|
||||
<C:calendar-multiget xmlns:D="DAV:"
|
||||
xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||
<D:prop>
|
||||
<D:getetag/>
|
||||
<C:calendar-data/>
|
||||
</D:prop>
|
||||
{hrefs}
|
||||
</C:calendar-multiget>'''
|
||||
|
||||
get_multi_data_query = '{urn:ietf:params:xml:ns:caldav}calendar-data'
|
||||
|
||||
def __init__(self, start_date=None, end_date=None,
|
||||
item_types=('VTODO', 'VEVENT'), **kwargs):
|
||||
'''
|
||||
:param start_date: Start date of timerange to show, default -inf.
|
||||
:param end_date: End date of timerange to show, default +inf.
|
||||
:param item_types: The item types to show from the server. Dependent on
|
||||
server functionality, no clientside validation of results. This
|
||||
currently only affects the `list` method, but this shouldn't cause
|
||||
problems in the normal usecase.
|
||||
'''
|
||||
super(CaldavStorage, self).__init__(**kwargs)
|
||||
if isinstance(item_types, str):
|
||||
item_types = [x.strip() for x in item_types.split(',')]
|
||||
self.item_types = tuple(item_types)
|
||||
if (start_date is None) != (end_date is None):
|
||||
raise ValueError('If start_date is given, '
|
||||
'end_date has to be given too.')
|
||||
elif start_date is not None and end_date is not None:
|
||||
namespace = dict(datetime.__dict__)
|
||||
namespace['start_date'] = self.start_date = \
|
||||
(eval(start_date, namespace) if isinstance(start_date, str)
|
||||
else start_date)
|
||||
self.end_date = \
|
||||
(eval(end_date, namespace) if isinstance(end_date, str)
|
||||
else end_date)
|
||||
|
||||
self._list_template = self._get_list_template()
|
||||
|
||||
def _get_list_template(self):
|
||||
data = '''<?xml version="1.0" encoding="utf-8" ?>
|
||||
<C:calendar-query xmlns:D="DAV:"
|
||||
xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||
<D:prop>
|
||||
<D:getetag/>
|
||||
</D:prop>
|
||||
<C:filter>
|
||||
<C:comp-filter name="VCALENDAR">
|
||||
<C:comp-filter name="{component}">
|
||||
{caldavfilter}
|
||||
</C:comp-filter>
|
||||
</C:comp-filter>
|
||||
</C:filter>
|
||||
</C:calendar-query>'''
|
||||
start = self.start_date
|
||||
end = self.end_date
|
||||
caldavfilter = ''
|
||||
if start is not None and end is not None:
|
||||
start = start.strftime(CALDAV_DT_FORMAT)
|
||||
end = end.strftime(CALDAV_DT_FORMAT)
|
||||
caldavfilter = ('<C:time-range start="{start}" end="{end}"/>'
|
||||
.format(start=start, end=end))
|
||||
return data.format(caldavfilter=caldavfilter, component='{item_type}')
|
||||
|
||||
def list(self):
|
||||
hrefs = set()
|
||||
for t in self.item_types:
|
||||
xml = self._list_template.format(item_type=t)
|
||||
for href, etag in self._list(xml):
|
||||
assert href not in hrefs
|
||||
hrefs.add(href)
|
||||
yield href, etag
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.storage.dav.carddav
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Original version from pycarddav: https://github.com/geier/pycarddav
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer, Christian Geier and contributors
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
from .base import DavStorage
|
||||
|
||||
|
||||
class CarddavStorage(DavStorage):
|
||||
|
||||
fileext = '.vcf'
|
||||
item_mimetype = 'text/vcard'
|
||||
dav_header = 'addressbook'
|
||||
leif_class = 'CardDiscover'
|
||||
|
||||
get_multi_template = '''<?xml version="1.0" encoding="utf-8" ?>
|
||||
<C:addressbook-multiget xmlns:D="DAV:"
|
||||
xmlns:C="urn:ietf:params:xml:ns:carddav">
|
||||
<D:prop>
|
||||
<D:getetag/>
|
||||
<C:address-data/>
|
||||
</D:prop>
|
||||
{hrefs}
|
||||
</C:addressbook-multiget>'''
|
||||
|
||||
get_multi_data_query = '{urn:ietf:params:xml:ns:carddav}address-data'
|
||||
|
||||
def list(self):
|
||||
return self._list('''<?xml version="1.0" encoding="utf-8" ?>
|
||||
<C:addressbook-query xmlns:D="DAV:"
|
||||
xmlns:C="urn:ietf:params:xml:ns:carddav">
|
||||
<D:prop>
|
||||
<D:getetag/>
|
||||
</D:prop>
|
||||
<C:filter>
|
||||
<C:comp-filter name="VCARD"/>
|
||||
</C:filter>
|
||||
</C:addressbook-query>''')
|
||||
Loading…
Reference in a new issue