Repository: plone/plone.restapi (language: python)

Issue:
Error when serializing a Collection that includes Events with recurrences
When you list events in a Collection, and try to serialize it through the REST API, you get the following error

```json
{
  "message": "('Could not adapt', <Occurrence at /Plone/eu/agenda/pentsio-duinak-eskatzeko-elkarretaratzea/2024-09-16>, <InterfaceClass plone.app.contentlisting.interfaces.IContentListingObject>)",
  "type": "TypeError"
}
```

The point is that plone.app.event's `Ocurrence` objects are not `IContentish` and thus are not adaptable to `IContentListingObject`, so [this line](https://github.com/plone/plone.restapi/blob/main/src/plone/restapi/serializer/summary.py#L86) breaks.

The solution on plone.restapi's side should be to defensively call `IContentListingObject` and in plone.app.event's side to define an adapter for `IContentListingObject`.

PRs to come


Discussion / hints:

Fix patch:
diff --git a/news/1809.internal b/news/1809.internal
new file mode 100644
index 000000000..ae905f006
--- /dev/null
+++ b/news/1809.internal
@@ -0,0 +1,2 @@
+Test that recurrence serialization provides correct data
+[erral]


Test patch:
diff --git a/src/plone/restapi/tests/test_serializer_summary.py b/src/plone/restapi/tests/test_serializer_summary.py
index 16b54f7b0..794579241 100644
--- a/src/plone/restapi/tests/test_serializer_summary.py
+++ b/src/plone/restapi/tests/test_serializer_summary.py
@@ -1,19 +1,31 @@
+from datetime import datetime
+from datetime import timedelta
 from DateTime import DateTime
 from plone.app.contentlisting.interfaces import IContentListingObject
+from plone.app.event.dx.traverser import OccurrenceTraverser
 from plone.app.testing import popGlobalRegistry
 from plone.app.testing import pushGlobalRegistry
 from plone.dexterity.utils import createContentInContainer
+from plone.event.interfaces import IEvent
+from plone.event.interfaces import IEventRecurrence
 from plone.restapi.interfaces import ISerializeToJsonSummary
 from plone.restapi.testing import PLONE_RESTAPI_DX_INTEGRATION_TESTING
 from plone.restapi.testing import register_static_uuid_utility
 from Products.CMFCore.utils import getToolByName
 from zope.component import getMultiAdapter
 from zope.component.hooks import getSite
+from zope.interface import alsoProvides
 
 import Missing
 import unittest
 
 
+try:
+    from plone.app.event.adapters import OccurrenceContentListingObject
+except ImportError:
+    OccurrenceContentListingObject = None
+
+
 class TestSummarySerializers(unittest.TestCase):
     layer = PLONE_RESTAPI_DX_INTEGRATION_TESTING
 
@@ -203,3 +215,65 @@ def test_dx_type_summary(self):
             },
             summary,
         )
+
+
+class TestSummarySerializerswithRecurrenceObjects(unittest.TestCase):
+    layer = PLONE_RESTAPI_DX_INTEGRATION_TESTING
+
+    def setUp(self):
+        self.portal = self.layer["portal"]
+        self.request = self.layer["request"]
+
+        pushGlobalRegistry(getSite())
+        register_static_uuid_utility(prefix="c6dcbd55ab2746e199cd4ed458")
+
+        behaviors = self.portal.portal_types.DXTestDocument.behaviors
+        behaviors = behaviors + (
+            "plone.eventbasic",
+            "plone.eventrecurrence",
+        )
+        self.portal.portal_types.DXTestDocument.behaviors = behaviors
+
+        self.event = createContentInContainer(
+            self.portal,
+            "DXTestDocument",
+            id="doc1",
+            title="Lorem Ipsum event",
+            description="Description event",
+            start=datetime.now(),
+            end=datetime.now() + timedelta(hours=1),
+            recurrence="RRULE:FREQ=DAILY;COUNT=3",  # see https://github.com/plone/plone.app.event/blob/master/plone/app/event/tests/base_setup.py
+        )
+
+        alsoProvides(self.event, IEvent)
+        alsoProvides(self.event, IEventRecurrence)
+
+    def tearDown(self):
+        popGlobalRegistry(getSite())
+
+    @unittest.skipIf(
+        OccurrenceContentListingObject is not None,
+        "this test needs a plone.app.event version that does not include a IContentListingObject adapter",
+    )
+    def test_dx_event_with_recurrence_old_version(self):
+        tomorrow = datetime.now() + timedelta(days=1)
+        tomorrow_str = tomorrow.strftime("%Y-%m-%d")
+        ot = OccurrenceTraverser(self.event, self.request)
+        ocurrence = ot.publishTraverse(self.request, tomorrow_str)
+
+        with self.assertRaises(TypeError):
+            getMultiAdapter((ocurrence, self.request), ISerializeToJsonSummary)()
+
+    @unittest.skipIf(
+        OccurrenceContentListingObject is None,
+        "this test needs a plone.app.event version that includes a IContentListingObject adapter",
+    )
+    def test_dx_event_with_recurrence_new_version(self):
+        tomorrow = datetime.now() + timedelta(days=1)
+        tomorrow_str = tomorrow.strftime("%Y-%m-%d")
+        ot = OccurrenceTraverser(self.event, self.request)
+        ocurrence = ot.publishTraverse(self.request, tomorrow_str)
+        summary = getMultiAdapter((ocurrence, self.request), ISerializeToJsonSummary)()
+
+        self.assertEqual(summary["start"], tomorrow_str)
+        self.assertEqual(summary["Title"], ocurrence.Title())