From 061a562090ac490bbc69dd1b35dfbefa7809187b Mon Sep 17 00:00:00 2001 From: Timo Stollenwerk Date: Mon, 17 Apr 2017 08:21:48 +0200 Subject: [PATCH 1/3] Add navigation and breadcrumbs as top-level services. --- CHANGES.rst | 8 +++ .../restapi/services/breadcrumbs/__init__.py | 0 .../services/breadcrumbs/configure.zcml | 13 +++++ src/plone/restapi/services/breadcrumbs/get.py | 17 ++++++ src/plone/restapi/services/configure.zcml | 2 + .../restapi/services/navigation/__init__.py | 0 .../services/navigation/configure.zcml | 13 +++++ src/plone/restapi/services/navigation/get.py | 17 ++++++ .../tests/test_services_breadcrumbs.py | 51 ++++++++++++++++++ .../restapi/tests/test_services_navigation.py | 54 +++++++++++++++++++ 10 files changed, 175 insertions(+) create mode 100644 src/plone/restapi/services/breadcrumbs/__init__.py create mode 100644 src/plone/restapi/services/breadcrumbs/configure.zcml create mode 100644 src/plone/restapi/services/breadcrumbs/get.py create mode 100644 src/plone/restapi/services/navigation/__init__.py create mode 100644 src/plone/restapi/services/navigation/configure.zcml create mode 100644 src/plone/restapi/services/navigation/get.py create mode 100644 src/plone/restapi/tests/test_services_breadcrumbs.py create mode 100644 src/plone/restapi/tests/test_services_navigation.py diff --git a/CHANGES.rst b/CHANGES.rst index 698ef41f5f..e74eb321e0 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,13 @@ Changelog 1.0a13 (unreleased) ------------------- +New Features: + +- Add navigation and breadcrumbs as top-level services. Deprecate navigation + and breadcrumbs as components. + [timo] + + Bugfixes: - Add the title to the workflow history in the @workflow endpoint. This fixes @@ -13,6 +20,7 @@ Bugfixes: - Don't fetch unnecessary PasswordResetTool in Plone 5.1 [tomgross] + 1.0a12 (2017-04-03) ------------------- diff --git a/src/plone/restapi/services/breadcrumbs/__init__.py b/src/plone/restapi/services/breadcrumbs/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/plone/restapi/services/breadcrumbs/configure.zcml b/src/plone/restapi/services/breadcrumbs/configure.zcml new file mode 100644 index 0000000000..0c39c889ca --- /dev/null +++ b/src/plone/restapi/services/breadcrumbs/configure.zcml @@ -0,0 +1,13 @@ + + + + + diff --git a/src/plone/restapi/services/breadcrumbs/get.py b/src/plone/restapi/services/breadcrumbs/get.py new file mode 100644 index 0000000000..b8d9b97aac --- /dev/null +++ b/src/plone/restapi/services/breadcrumbs/get.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +from plone.restapi.services import Service +from zope.component import getMultiAdapter + + +class BreadcrumbsGet(Service): + + def reply(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 diff --git a/src/plone/restapi/services/configure.zcml b/src/plone/restapi/services/configure.zcml index a8c77c5cea..4c495bba27 100644 --- a/src/plone/restapi/services/configure.zcml +++ b/src/plone/restapi/services/configure.zcml @@ -2,10 +2,12 @@ xmlns="http://namespaces.zope.org/zope"> + + diff --git a/src/plone/restapi/services/navigation/__init__.py b/src/plone/restapi/services/navigation/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/plone/restapi/services/navigation/configure.zcml b/src/plone/restapi/services/navigation/configure.zcml new file mode 100644 index 0000000000..05e200e434 --- /dev/null +++ b/src/plone/restapi/services/navigation/configure.zcml @@ -0,0 +1,13 @@ + + + + + diff --git a/src/plone/restapi/services/navigation/get.py b/src/plone/restapi/services/navigation/get.py new file mode 100644 index 0000000000..a2bf05047e --- /dev/null +++ b/src/plone/restapi/services/navigation/get.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +from plone.restapi.services import Service +from zope.component import getMultiAdapter + + +class NavigationGet(Service): + + def reply(self): + tabs = getMultiAdapter((self.context, self.request), + name="portal_tabs_view") + result = [] + for tab in tabs.topLevelTabs(): + result.append({ + 'title': tab.get('title', tab.get('name')), + 'url': tab['url'] + '' + }) + return result diff --git a/src/plone/restapi/tests/test_services_breadcrumbs.py b/src/plone/restapi/tests/test_services_breadcrumbs.py new file mode 100644 index 0000000000..59dfc00842 --- /dev/null +++ b/src/plone/restapi/tests/test_services_breadcrumbs.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +from plone.app.testing import setRoles +from plone.app.testing import SITE_OWNER_NAME +from plone.app.testing import SITE_OWNER_PASSWORD +from plone.app.testing import TEST_USER_ID +from plone.dexterity.utils import createContentInContainer +from plone.restapi.testing import PLONE_RESTAPI_DX_FUNCTIONAL_TESTING +from plone.restapi.testing import RelativeSession + +import transaction +import unittest + + +class TestServicesBreadcrumbs(unittest.TestCase): + + layer = PLONE_RESTAPI_DX_FUNCTIONAL_TESTING + + def setUp(self): + self.app = self.layer['app'] + self.portal = self.layer['portal'] + self.portal_url = self.portal.absolute_url() + setRoles(self.portal, TEST_USER_ID, ['Manager']) + + self.api_session = RelativeSession(self.portal_url) + self.api_session.headers.update({'Accept': 'application/json'}) + self.api_session.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) + + self.folder = createContentInContainer( + self.portal, u'Folder', + id=u'folder', + title=u'Some Folder') + createContentInContainer( + self.folder, u'Document', + id=u'doc1', + title=u'A document') + transaction.commit() + + def test_breadcrumbs(self): + response = self.api_session.get('/folder/doc1/@breadcrumbs') + + self.assertEqual(response.status_code, 200) + self.assertEqual( + response.json(), + [{ + 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' + }] + ) diff --git a/src/plone/restapi/tests/test_services_navigation.py b/src/plone/restapi/tests/test_services_navigation.py new file mode 100644 index 0000000000..ad55a612ed --- /dev/null +++ b/src/plone/restapi/tests/test_services_navigation.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +from plone.app.testing import setRoles +from plone.app.testing import SITE_OWNER_NAME +from plone.app.testing import SITE_OWNER_PASSWORD +from plone.app.testing import TEST_USER_ID +from plone.dexterity.utils import createContentInContainer +from plone.restapi.testing import PLONE_RESTAPI_DX_FUNCTIONAL_TESTING +from plone.restapi.testing import RelativeSession + +import transaction +import unittest + + +class TestServicesNavigation(unittest.TestCase): + + layer = PLONE_RESTAPI_DX_FUNCTIONAL_TESTING + + def setUp(self): + self.app = self.layer['app'] + self.portal = self.layer['portal'] + self.portal_url = self.portal.absolute_url() + setRoles(self.portal, TEST_USER_ID, ['Manager']) + + self.api_session = RelativeSession(self.portal_url) + self.api_session.headers.update({'Accept': 'application/json'}) + self.api_session.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) + + self.folder = createContentInContainer( + self.portal, u'Folder', + id=u'folder', + title=u'Some Folder') + createContentInContainer( + self.folder, u'Document', + id=u'doc1', + title=u'A document') + transaction.commit() + + def test_navigation(self): + response = self.api_session.get('/folder/@navigation') + + self.assertEqual(response.status_code, 200) + self.assertEqual( + response.json(), + [ + { + u'title': u'Home', + u'url': u'http://localhost:55001/plone' + }, + { + u'title': u'Some Folder', + u'url': u'http://localhost:55001/plone/folder' + } + ] + ) From 70481ec19f8359f2c8a68b3934b74c8089362061 Mon Sep 17 00:00:00 2001 From: Timo Stollenwerk Date: Mon, 17 Apr 2017 19:14:48 +0200 Subject: [PATCH 2/3] Add docs for breadcrumbs and navigation; Add deprecation message to components docs. --- docs/source/breadcrumbs.rst | 12 ++++++++++++ docs/source/components.rst | 5 +++++ docs/source/index.rst | 2 ++ docs/source/navigation.rst | 12 ++++++++++++ 4 files changed, 31 insertions(+) create mode 100644 docs/source/breadcrumbs.rst create mode 100644 docs/source/navigation.rst diff --git a/docs/source/breadcrumbs.rst b/docs/source/breadcrumbs.rst new file mode 100644 index 0000000000..f377ff3087 --- /dev/null +++ b/docs/source/breadcrumbs.rst @@ -0,0 +1,12 @@ +Breadcrumbs +=========== + +Getting the breadcrumbs for the current page: + +.. http:example:: curl httpie python-requests + :request: _json/breadcrumbs.req + +Example response: + +.. literalinclude:: _json/breadcrumbs.resp + :language: http diff --git a/docs/source/components.rst b/docs/source/components.rst index f052d35dff..49db73734e 100644 --- a/docs/source/components.rst +++ b/docs/source/components.rst @@ -1,8 +1,13 @@ Components ========== +.. warning:: + The @components endpoint is deprecated and will be removed in plone.restapi + 1.0b1. :doc:`breadcrumbs` and :doc:`navigation` are now top-level endpoints. + How to get pages components (i.e. everything but the main content), like breadcrumbs, navigations, actions, etc. + Breadcrumbs ----------- diff --git a/docs/source/index.rst b/docs/source/index.rst index 66c5b74261..761a46d3d3 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -30,6 +30,8 @@ Contents types users components + breadcrumbs + navigation serialization searching vocabularies diff --git a/docs/source/navigation.rst b/docs/source/navigation.rst new file mode 100644 index 0000000000..8027e2d640 --- /dev/null +++ b/docs/source/navigation.rst @@ -0,0 +1,12 @@ +Navigation +========== + +Getting the top navigation items: + +.. http:example:: curl httpie python-requests + :request: _json/navigation.req + +Example response: + +.. literalinclude:: _json/navigation.resp + :language: http From 026859efffee42e20721a56f101616adf936064e Mon Sep 17 00:00:00 2001 From: Timo Stollenwerk Date: Sat, 29 Apr 2017 22:40:13 +0200 Subject: [PATCH 3/3] Add deprecation message on @components endpoint. Enable deprecation messages on buildout. --- base.cfg | 1 + src/plone/restapi/services/components/get.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/base.cfg b/base.cfg index 342d538558..3ff9311fbb 100644 --- a/base.cfg +++ b/base.cfg @@ -21,6 +21,7 @@ auto-checkout = recipe = plone.recipe.zope2instance user = admin:admin http-address = 8080 +deprecation-warnings = on eggs = Plone Pillow diff --git a/src/plone/restapi/services/components/get.py b/src/plone/restapi/services/components/get.py index ec75b447fc..65345dd389 100644 --- a/src/plone/restapi/services/components/get.py +++ b/src/plone/restapi/services/components/get.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from plone.restapi.services import Service +from zope.deprecation import deprecate from zope.component import getMultiAdapter from zope.interface import implements from zope.publisher.interfaces import IPublishTraverse @@ -66,6 +67,10 @@ def _render_component(self, component_id): return self._wrap_component_items(items, component_id) + @deprecate( + 'The "@components" endpoint is deprecated. Please call the ' + '"@breadcrumbs" and the "@navigation" endpoints on the site root.' + ) def reply(self): components = [] for component_id in self._component_ids: