Less files

This commit is contained in:
Markus Unterwaditzer 2014-03-26 18:11:26 +01:00
parent 47d3b1917d
commit 475671f437
8 changed files with 190 additions and 240 deletions

View file

@ -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())

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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>''')

View file

@ -1,8 +0,0 @@
# -*- coding: utf-8 -*-
'''
vdirsyncer.storage.dav
~~~~~~~~~~~~~~~~~~~~~~
:copyright: (c) 2014 Markus Unterwaditzer
:license: MIT, see LICENSE for more details.
'''

View file

@ -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

View file

@ -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>''')