Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Changelog

## 3.5.10.dev
* Improve: logging of broken calendar items during PUT
* Add: logging of broken contact items during PUT

## 3.5.9
* Extend: [auth] add support for type http_remote_user
Expand Down
22 changes: 19 additions & 3 deletions radicale/app/put.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,13 @@ def prepare(vobject_items: List[vobject.base.Component], path: str,
logger.debug("Prepare item with UID '%s'", item.uid)
try:
item.prepare()
except ValueError as e:
except (RuntimeError, ValueError, AttributeError) as e:
if logger.isEnabledFor(logging.DEBUG):
logger.warning("Problem during prepare item with UID '%s' (content below): %s\n%s", item.uid, e, item._text)
if item._text is None:
content = vobject_item
else:
content = item._text
logger.warning("Problem during prepare item with UID '%s' (content below): %s\n%s", item.uid, e, content)
else:
logger.warning("Problem during prepare item with UID '%s' (content suppressed in this loglevel): %s", item.uid, e)
raise
Expand All @@ -104,7 +108,19 @@ def prepare(vobject_items: List[vobject.base.Component], path: str,
for vobject_item in vobject_items:
item = radicale_item.Item(collection_path=collection_path,
vobject_item=vobject_item)
item.prepare()
logger.debug("Prepare item with UID '%s'", item.uid)
try:
item.prepare()
except (RuntimeError, ValueError, AttributeError) as e:
if logger.isEnabledFor(logging.DEBUG):
if item._text is None:
content = vobject_item
else:
content = item._text
logger.warning("Problem during prepare item with UID '%s' (content below): %s\n%s", item.uid, e, content)
else:
logger.warning("Problem during prepare item with UID '%s' (content suppressed in this loglevel): %s", item.uid, e)
raise
items.append(item)
elif not write_whole_collection:
vobject_item, = vobject_items
Expand Down
5 changes: 4 additions & 1 deletion radicale/item/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,10 @@ def get_children(components: Iterable[vobject.base.Component]) -> Iterator[
for child, is_recurrence, recurrences in get_children(
vobject_item.vevent_list):
# TODO: check if there's a timezone
dtstart = child.dtstart.value
try:
dtstart = child.dtstart.value
except AttributeError:
raise AttributeError("missing DTSTART")

if child.rruleset:
dtstarts, infinity = getrruleset(child, recurrences)
Expand Down
16 changes: 16 additions & 0 deletions radicale/tests/static/broken-vcards.vcf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
BEGIN:VCARD
VERSION:3.0
PRODID:-//Inverse inc.//SOGo Connector 1.0//EN
UID:C68582D2-2E60-0001-C2C0-000000000000.vcf
X-MOZILLA-HTML:FALSE
EMAIL;TYPE=work:test-misses-N-or-FN@example.com
X-RADICALE-NAME:C68582D2-2E60-0001-C2C0-000000000000.vcf
END:VCARD
BEGIN:VCARD
VERSION:3.0
PRODID:-//Inverse inc.//SOGo Connector 1.0//EN
UID:C68582D2-2E60-0001-C2C0-000000000001.vcf
X-MOZILLA-HTML:FALSE
EMAIL;TYPE=work:test-misses-N-or-FN@example1.com
X-RADICALE-NAME:C68582D2-2E60-0001-C2C0-000000000001.vcf
END:VCARD
16 changes: 16 additions & 0 deletions radicale/tests/static/broken-vcards2-no_uid.vcf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
BEGIN:VCARD
VERSION:3.0
PRODID:-//Inverse inc.//SOGo Connector 1.0//EN
UID:C68582D2-2E60-0001-C2C0-000000000000.vcf
X-MOZILLA-HTML:FALSE
EMAIL;TYPE=work:test-misses-N-or-FN@example.com
FN:Test Example
X-RADICALE-NAME:C68582D2-2E60-0001-C2C0-000000000000.vcf
END:VCARD
BEGIN:VCARD
VERSION:3.0
PRODID:-//Inverse inc.//SOGo Connector 1.0//EN
X-MOZILLA-HTML:FALSE
EMAIL;TYPE=work:test-misses-N-or-FN@example1.com
X-RADICALE-NAME:C68582D2-2E60-0001-C2C0-000000000001.vcf
END:VCARD
17 changes: 17 additions & 0 deletions radicale/tests/static/broken-vcards2.vcf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
BEGIN:VCARD
VERSION:3.0
PRODID:-//Inverse inc.//SOGo Connector 1.0//EN
UID:C68582D2-2E60-0001-C2C0-000000000000.vcf
X-MOZILLA-HTML:FALSE
EMAIL;TYPE=work:test-misses-N-or-FN@example.com
FN:Test Example
X-RADICALE-NAME:C68582D2-2E60-0001-C2C0-000000000000.vcf
END:VCARD
BEGIN:VCARD
VERSION:3.0
PRODID:-//Inverse inc.//SOGo Connector 1.0//EN
UID:C68582D2-2E60-0001-C2C0-000000000001.vcf
X-MOZILLA-HTML:FALSE
EMAIL;TYPE=work:test-misses-N-or-FN@example1.com
X-RADICALE-NAME:C68582D2-2E60-0001-C2C0-000000000001.vcf
END:VCARD
25 changes: 25 additions & 0 deletions radicale/tests/static/broken-vevents.ics
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
BEGIN:VCALENDAR
PRODID:-//Radicale//NONSGML Radicale Server//EN
VERSION:2.0
BEGIN:VEVENT
CREATED:20160725T060147Z
LAST-MODIFIED:20160727T193435Z
DTSTAMP:20160727T193435Z
UID:040000008200E00074C5B7101A82E00800000000
SUMMARY:Good ICS
STATUS:CONFIRMED
X-MOZ-LASTACK:20160727T193435Z
DTSTART;TZID=Europe/Budapest:20160727T170000
DTEND;TZID=Europe/Budapest:20160727T223000
CLASS:PUBLIC
X-LIC-ERROR:No value for LOCATION property. Removing entire property:
END:VEVENT
BEGIN:VEVENT
CREATED:20160725T060147Z
LAST-MODIFIED:20160727T193435Z
DTSTAMP:20160727T193435Z
UID:040000008200E00074C5B7101A82E00800000001
CLASS:PUBLIC
X-LIC-ERROR:No value for LOCATION property. Removing entire property:
END:VEVENT
END:VCALENDAR
42 changes: 42 additions & 0 deletions radicale/tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,20 @@ def test_add_event(self) -> None:
assert "Event" in answer
assert "UID:event" in answer

def test_add_event_broken(self) -> None:
"""Add a broken event."""
self.mkcalendar("/calendar.ics/")
event = get_file_content("broken-vevent.ics")
path = "/calendar.ics/broken-vevent.ics"
self.put(path, event, check=400)

def test_add_events_broken2(self) -> None:
"""Add a broken event (2nd one is broken)."""
self.mkcalendar("/calendar.ics/")
event = get_file_content("broken-vevents.ics")
path = "/calendar.ics/"
self.put(path, event, check=400)

def test_add_event_without_uid(self) -> None:
"""Add an event without UID."""
self.mkcalendar("/calendar.ics/")
Expand Down Expand Up @@ -201,6 +215,34 @@ def test_add_contact(self) -> None:
_, answer = self.get(path)
assert "UID:contact1" in answer

def test_add_contact_broken(self) -> None:
"""Add a broken contact."""
self.create_addressbook("/contacts.vcf/")
contact = get_file_content("broken-vcard.vcf")
path = "/contacts.vcf/broken-vcards.vcf"
self.put(path, contact, check=400)

def test_add_contacts_broken(self) -> None:
"""Add broken contacts."""
self.create_addressbook("/contacts.vcf/")
contact = get_file_content("broken-vcards.vcf")
path = "/contacts.vcf/"
self.put(path, contact, check=400)

def test_add_contacts_broken2(self) -> None:
"""Add broken contacts (only 2nd one is broken)."""
self.create_addressbook("/contacts.vcf/")
contact = get_file_content("broken-vcards2.vcf")
path = "/contacts.vcf/"
self.put(path, contact, check=400)

def test_add_contacts_broken2_no_uid(self) -> None:
"""Add broken contacts (only 2nd one is broken and has no UID)."""
self.create_addressbook("/contacts.vcf/")
contact = get_file_content("broken-vcards2-no_uid.vcf")
path = "/contacts.vcf/"
self.put(path, contact, check=400)

def test_add_contact_photo_with_data_uri(self) -> None:
"""Test workaround for broken PHOTO data from InfCloud"""
self.create_addressbook("/contacts.vcf/")
Expand Down