Explorar o código

Merge pull request #1928 from pbiering/support-discussion-1926

Support discussion 1926
Peter Bieringer hai 3 meses
pai
achega
3521f2731a

+ 2 - 0
CHANGELOG.md

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

+ 19 - 3
radicale/app/put.py

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

+ 4 - 1
radicale/item/filter.py

@@ -354,7 +354,10 @@ def visit_time_ranges(vobject_item: vobject.base.Component, child_name: str,
         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)

+ 16 - 0
radicale/tests/static/broken-vcards.vcf

@@ -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 - 0
radicale/tests/static/broken-vcards2-no_uid.vcf

@@ -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 - 0
radicale/tests/static/broken-vcards2.vcf

@@ -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 - 0
radicale/tests/static/broken-vevents.ics

@@ -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 - 0
radicale/tests/test_base.py

@@ -142,6 +142,20 @@ permissions: RrWw""")
         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/")
@@ -201,6 +215,34 @@ permissions: RrWw""")
         _, 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/")