plone.restapi/translate-workflow-titles: Make breadcrumbs component expandable

Thomas Buchberger <jenkins-z4DKO/[email protected]>
Newsgroups gmane.comp.web.zope.plone.cvs
Message-ID <[email protected]>
Repository: plone.restapi
Branch: refs/heads/translate-workflow-titles
Date: 2017-07-25T11:48:31+02:00
Author: Thomas Buchberger (buchi) <t.buchberger-/8aE7x569Db/[email protected]>
Commit: https://github.com/plone/plone.restapi/commit/526b397c9c2562072e55a056d01d16f24d1b7568

Make breadcrumbs component expandable

Files changed:
A src/plone/restapi/services/components/breadcrumbs.py
M docs/source/_json/collection.resp
M docs/source/_json/content_get.resp
M docs/source/_json/content_post.resp
M docs/source/_json/document.resp
M docs/source/_json/event.resp
M docs/source/_json/file.resp
M docs/source/_json/folder.resp
M docs/source/_json/image.resp
M docs/source/_json/jwt_logged_in.resp
M docs/source/_json/link.resp
M docs/source/_json/newsitem.resp
M docs/source/_json/siteroot.resp
M src/plone/restapi/serializer/expansion.py
M src/plone/restapi/services/components/configure.zcml
M src/plone/restapi/services/components/get.py
M src/plone/restapi/tests/test_components.py

diff --git a/docs/source/_json/collection.resp b/docs/source/_json/collection.resp
index ac162329..7640e732 100644
--- a/docs/source/_json/collection.resp
+++ b/docs/source/_json/collection.resp
@@ -3,6 +3,9 @@ Content-Type: application/json
 
 {
   "@components": {
+    "breadcrumbs": {
+      "@id": "http://localhost:55001/plone/collection/@components/breadcrumbs"
+    }, 
     "navigation": {
       "@id": "http://localhost:55001/plone/collection/@components/navigation"
     }
diff --git a/docs/source/_json/content_get.resp b/docs/source/_json/content_get.resp
index ad1e0345..2a7b48ee 100644
--- a/docs/source/_json/content_get.resp
+++ b/docs/source/_json/content_get.resp
@@ -3,6 +3,9 @@ Content-Type: application/json
 
 {
   "@components": {
+    "breadcrumbs": {
+      "@id": "http://localhost:55001/plone/folder/my-document/@components/breadcrumbs"
+    }, 
     "navigation": {
       "@id": "http://localhost:55001/plone/folder/my-document/@components/navigation"
     }
diff --git a/docs/source/_json/content_post.resp b/docs/source/_json/content_post.resp
index 4cde4d25..36da1d20 100644
--- a/docs/source/_json/content_post.resp
+++ b/docs/source/_json/content_post.resp
@@ -4,6 +4,9 @@ Location: http://localhost:55001/plone/folder/my-document
 
 {
   "@components": {
+    "breadcrumbs": {
+      "@id": "http://localhost:55001/plone/folder/my-document/@components/breadcrumbs"
+    }, 
     "navigation": {
       "@id": "http://localhost:55001/plone/folder/my-document/@components/navigation"
     }
diff --git a/docs/source/_json/document.resp b/docs/source/_json/document.resp
index 87a16856..e3aadc15 100644
--- a/docs/source/_json/document.resp
+++ b/docs/source/_json/document.resp
@@ -3,6 +3,9 @@ Content-Type: application/json
 
 {
   "@components": {
+    "breadcrumbs": {
+      "@id": "http://localhost:55001/plone/front-page/@components/breadcrumbs"
+    }, 
     "navigation": {
       "@id": "http://localhost:55001/plone/front-page/@components/navigation"
     }
diff --git a/docs/source/_json/event.resp b/docs/source/_json/event.resp
index d749122d..974db379 100644
--- a/docs/source/_json/event.resp
+++ b/docs/source/_json/event.resp
@@ -3,6 +3,9 @@ Content-Type: application/json
 
 {
   "@components": {
+    "breadcrumbs": {
+      "@id": "http://localhost:55001/plone/event/@components/breadcrumbs"
+    }, 
     "navigation": {
       "@id": "http://localhost:55001/plone/event/@components/navigation"
     }
diff --git a/docs/source/_json/file.resp b/docs/source/_json/file.resp
index ed46fc3c..515cfeb8 100644
--- a/docs/source/_json/file.resp
+++ b/docs/source/_json/file.resp
@@ -3,6 +3,9 @@ Content-Type: application/json
 
 {
   "@components": {
+    "breadcrumbs": {
+      "@id": "http://localhost:55001/plone/file/@components/breadcrumbs"
+    }, 
     "navigation": {
       "@id": "http://localhost:55001/plone/file/@components/navigation"
     }
diff --git a/docs/source/_json/folder.resp b/docs/source/_json/folder.resp
index 19685167..4a12e3eb 100644
--- a/docs/source/_json/folder.resp
+++ b/docs/source/_json/folder.resp
@@ -3,6 +3,9 @@ Content-Type: application/json
 
 {
   "@components": {
+    "breadcrumbs": {
+      "@id": "http://localhost:55001/plone/folder/@components/breadcrumbs"
+    }, 
     "navigation": {
       "@id": "http://localhost:55001/plone/folder/@components/navigation"
     }
diff --git a/docs/source/_json/image.resp b/docs/source/_json/image.resp
index 4d2b0751..df1bd765 100644
--- a/docs/source/_json/image.resp
+++ b/docs/source/_json/image.resp
@@ -3,6 +3,9 @@ Content-Type: application/json
 
 {
   "@components": {
+    "breadcrumbs": {
+      "@id": "http://localhost:55001/plone/image/@components/breadcrumbs"
+    }, 
     "navigation": {
       "@id": "http://localhost:55001/plone/image/@components/navigation"
     }
diff --git a/docs/source/_json/jwt_logged_in.resp b/docs/source/_json/jwt_logged_in.resp
index 331ee0c9..d9a441ca 100644
--- a/docs/source/_json/jwt_logged_in.resp
+++ b/docs/source/_json/jwt_logged_in.resp
@@ -3,6 +3,9 @@ Content-Type: application/json
 
 {
   "@components": {
+    "breadcrumbs": {
+      "@id": "http://localhost:55001/plone/@components/breadcrumbs"
+    }, 
     "navigation": {
       "@id": "http://localhost:55001/plone/@components/navigation"
     }
diff --git a/docs/source/_json/link.resp b/docs/source/_json/link.resp
index 05360f3e..6eba0e69 100644
--- a/docs/source/_json/link.resp
+++ b/docs/source/_json/link.resp
@@ -3,6 +3,9 @@ Content-Type: application/json
 
 {
   "@components": {
+    "breadcrumbs": {
+      "@id": "http://localhost:55001/plone/link/@components/breadcrumbs"
+    }, 
     "navigation": {
       "@id": "http://localhost:55001/plone/link/@components/navigation"
     }
diff --git a/docs/source/_json/newsitem.resp b/docs/source/_json/newsitem.resp
index b0013e66..ae9f6d09 100644
--- a/docs/source/_json/newsitem.resp
+++ b/docs/source/_json/newsitem.resp
@@ -3,6 +3,9 @@ Content-Type: application/json
 
 {
   "@components": {
+    "breadcrumbs": {
+      "@id": "http://localhost:55001/plone/newsitem/@components/breadcrumbs"
+    }, 
     "navigation": {
       "@id": "http://localhost:55001/plone/newsitem/@components/navigation"
     }
diff --git a/docs/source/_json/siteroot.resp b/docs/source/_json/siteroot.resp
index 46705593..30894897 100644
--- a/docs/source/_json/siteroot.resp
+++ b/docs/source/_json/siteroot.resp
@@ -3,6 +3,9 @@ Content-Type: application/json
 
 {
   "@components": {
+    "breadcrumbs": {
+      "@id": "http://localhost:55001/plone/@components/breadcrumbs"
+    }, 
     "navigation": {
       "@id": "http://localhost:55001/plone/@components/navigation"
     }
diff --git a/src/plone/restapi/serializer/expansion.py b/src/plone/restapi/serializer/expansion.py
index 6253f69c..825d34ba 100644
--- a/src/plone/restapi/serializer/expansion.py
+++ b/src/plone/restapi/serializer/expansion.py
@@ -11,7 +11,17 @@ def expandable_elements(context, request):
     res = {}
     for element in elements:
         if element[0] in expands:
-            res.update(element[1](expand=True))
+            update_dict_recursively(res, element[1](expand=True))
         else:
-            res.update(element[1](expand=False))
+            update_dict_recursively(res, element[1](expand=False))
     return res
+
+
+def update_dict_recursively(d, u):
+    for key, value in u.iteritems():
+        if isinstance(value, dict):
+            r = update_dict_recursively(d.get(key, {}), value)
+            d[key] = r
+        else:
+            d[key] = u[key]
+    return d
diff --git a/src/plone/restapi/services/components/breadcrumbs.py b/src/plone/restapi/services/components/breadcrumbs.py
new file mode 100644
index 00000000..24287963
--- /dev/null
+++ b/src/plone/restapi/services/components/breadcrumbs.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+from plone.restapi.interfaces import IExpandableElement
+from zope.component import adapter
+from zope.component import getMultiAdapter
+from zope.interface import Interface
+from zope.interface import implementer
+
+
+@implementer(IExpandableElement)
+@adapter(Interface, Interface)
+class Breadcrumbs(object):
+
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+
+    def __call__(self, expand=False):
+        if not expand:
+            return {'@components': {'breadcrumbs': {
+                '@id': '{}/@components/breadcrumbs'.format(
+                    self.context.absolute_url()),
+            }}}
+
+        breadcrumbs_view = getMultiAdapter((self.context, self.request),
+                                           name="breadcrumbs_view")
+        result = []
+        for crumb in breadcrumbs_view.breadcrumbs():
+            result.append({
+                'title': crumb['Title'],
+                'url': crumb['absolute_url']
+            })
+        return {'@components': {'breadcrumbs': result}}
diff --git a/src/plone/restapi/services/components/configure.zcml b/src/plone/restapi/services/components/configure.zcml
index fa6faebd..da8a360e 100644
--- a/src/plone/restapi/services/components/configure.zcml
+++ b/src/plone/restapi/services/components/configure.zcml
@@ -11,5 +11,6 @@
     />
 
     <adapter factory=".navigation.Navigation" name="navigation"/>
+    <adapter factory=".breadcrumbs.Breadcrumbs" name="breadcrumbs"/>
 
 </configure>
\ No newline at end of file
diff --git a/src/plone/restapi/services/components/get.py b/src/plone/restapi/services/components/get.py
index f580e3a1..5947d0c3 100644
--- a/src/plone/restapi/services/components/get.py
+++ b/src/plone/restapi/services/components/get.py
@@ -1,8 +1,8 @@
 # -*- coding: utf-8 -*-
 from plone.restapi.services import Service
+from plone.restapi.services.components.breadcrumbs import Breadcrumbs
 from plone.restapi.services.components.navigation import Navigation
 from zope.deprecation import deprecate
-from zope.component import getMultiAdapter
 from zope.interface import implements
 from zope.publisher.interfaces import IPublishTraverse
 
@@ -34,23 +34,13 @@ def _wrap_component_items(self, items, component_id):
         }
         return component
 
-    def get_breadcrumbs(self):
-        breadcrumbs_view = getMultiAdapter((self.context, self.request),
-                                           name="breadcrumbs_view")
-        result = []
-        for crumb in breadcrumbs_view.breadcrumbs():
-            result.append({
-                'title': crumb['Title'],
-                'url': crumb['absolute_url']
-            })
-        return result
-
     def _render_component(self, component_id):
         if component_id == 'navigation':
             items = Navigation(self.context, self.request)(expand=True)[
                 '@components']['navigation']
         elif component_id == 'breadcrumbs':
-            items = self.get_breadcrumbs()
+            items = Breadcrumbs(self.context, self.request)(expand=True)[
+                '@components']['breadcrumbs']
         else:
             raise NotImplementedError(
                 'This endpoint does not currently support the '
diff --git a/src/plone/restapi/tests/test_components.py b/src/plone/restapi/tests/test_components.py
index 3006146a..1c7e232b 100644
--- a/src/plone/restapi/tests/test_components.py
+++ b/src/plone/restapi/tests/test_components.py
@@ -54,6 +54,26 @@ def test_breadcrumb(self):
             }]
         )
 
+    def test_collapsed_breadcrumbs_in_content_serialization(self):
+        obj = self.api_session.get('/folder').json()
+        self.assertIn('@components', obj)
+        self.assertIn('breadcrumbs', obj['@components'])
+        self.assertIn('@id', obj['@components']['breadcrumbs'])
+
+    def test_expanded_breadcrumbs_in_content_serialization(self):
+        obj = self.api_session.get('/folder/doc1?expand=breadcrumbs').json()
+        self.assertIn('@components', obj)
+        self.assertIn('breadcrumbs', obj['@components'])
+        self.assertEqual(
+            [{
+                u'url': u'http://localhost:55001/plone/folder',
+                u'title': u'Some Folder'
+            }, {
+                u'url': u'http://localhost:55001/plone/folder/doc1',
+                u'title': u'A document'
+            }],
+            obj['@components']['breadcrumbs'])
+
     def test_navigation(self):
         response = self.api_session.get('/folder/@components/navigation')
 



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.