Skip to content

Commit

Permalink
Documentation about @translations endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
erral committed Mar 24, 2017
1 parent e5d5f3c commit f07dc4c
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 2 deletions.
6 changes: 6 additions & 0 deletions docs/source/_json/translations_delete.req
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
DELETE /plone/en/test-document/@translations HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Content-Type: application/json

{"language": "es"}
2 changes: 2 additions & 0 deletions docs/source/_json/translations_delete.resp
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
HTTP/1.1 204 No Content

3 changes: 3 additions & 0 deletions docs/source/_json/translations_get.req
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
GET /plone/en/test-document/@translations HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
13 changes: 13 additions & 0 deletions docs/source/_json/translations_get.resp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
HTTP/1.1 200 OK
Content-Type: application/json

{
"@id": "http://localhost:55001/plone/en/test-document",
"language": "en",
"translations": [
{
"@id": "http://localhost:55001/plone/es/test-document",
"language": "es"
}
]
}
6 changes: 6 additions & 0 deletions docs/source/_json/translations_post.req
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
POST /plone/en/test-document/@translations HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Content-Type: application/json

{"id": "http://localhost:55001/plone/es/test-document"}
5 changes: 5 additions & 0 deletions docs/source/_json/translations_post.resp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
HTTP/1.1 201 Created
Content-Type: application/json
Location: http://localhost:55001/plone/en/test-document

{}
2 changes: 1 addition & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Contents
vocabularies
customization
conventions
translations

.. include:: ../../README.rst

Expand All @@ -48,4 +49,3 @@ Appendix, Indices and tables
glossary

* :ref:`genindex`

60 changes: 60 additions & 0 deletions docs/source/translations.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
Translations
============

Since Plone 5 the product `plone.app.multilingual`_ is included in the base
Plone installation although it is not enabled by default. plone.restapi
provides a `@translations` endpoint to handle the translation information
of the content objects.

Once we have installed `plone.app.multilingual`_ and enabled more than one
language we can link two content-items of different languages to be the
translation of each other issuing a `POST` query to the `@translations`
endpoint including the `id` of the content which should be linked to. The
`id` of the content must be a full URL of the content object:


.. http:example:: curl httpie python-requests
:request: _json/translations_post.req


.. note::
"id" is a required field and needs to point to an existing content on the site.

The API will return a `201 Created` response if the linking was successful.


.. literalinclude:: _json/translations_post.resp
:language: http


After linking the contents we can get the list of the translations of that
content item by issuing a ``GET`` request on the `@translations` endpoint of
that content item.:

.. http:example:: curl httpie python-requests
:request: _json/translations_get.req

.. literalinclude:: _json/translations_get.resp
:language: http


To unlink the content, issue a ``DELETE`` request on the `@translations`
endpoint of the content item and provide the language code you want to unlink.:


.. http:example:: curl httpie python-requests
:request: _json/translations_delete.req

.. note::
"language" is a required field.

.. literalinclude:: _json/translations_delete.resp
:language: http

.. note::
The `@translations` endpoint works also when using `Products.LinguaPlone`_
in Plone 4.3.x


.. _`plone.app.multilingual`: https://pypi.python.org/pypi/plone.app.multilingual
.. _`Products.LinguaPlone`: https://pypi.python.org/pypi/Products.LinguaPlone.
8 changes: 8 additions & 0 deletions src/plone/restapi/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@

import requests
import collective.MockMailHost
import pkg_resources


try:
pkg_resources.get_distribution('plone.app.multilingual')
PAM_INSTALLED = True
except pkg_resources.DistributionNotFound:
PAM_INSTALLED = False


def set_available_languages():
Expand Down
79 changes: 78 additions & 1 deletion src/plone/restapi/tests/test_documentation.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
# -*- coding: utf-8 -*-
from Products.CMFCore.utils import getToolByName
from datetime import datetime
from DateTime import DateTime
from datetime import timedelta
from freezegun import freeze_time
from plone import api
from plone.app.testing import popGlobalRegistry
from plone.app.testing import pushGlobalRegistry
from plone.app.testing import applyProfile
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.app.textfield.value import RichTextValue
from plone.dexterity.utils import createContentInContainer
from plone.namedfile.file import NamedBlobFile
from plone.namedfile.file import NamedBlobImage
from plone.restapi.testing import PLONE_RESTAPI_DX_FUNCTIONAL_TESTING
from plone.restapi.testing import register_static_uuid_utility
from plone.restapi.testing import RelativeSession
from plone.restapi.testing import PAM_INSTALLED
from plone.testing.z2 import Browser
from zope.site.hooks import getSite

Expand All @@ -25,7 +29,6 @@
import transaction
import unittest


REQUEST_HEADER_KEYS = [
'accept',
'authorization',
Expand Down Expand Up @@ -777,3 +780,77 @@ def test_documentation_sharing_folder_post(self):
json=payload
)
save_request_and_response_for_docs('sharing_folder_post', response)


if PAM_INSTALLED:
from plone.app.multilingual.interfaces import ITranslationManager
from plone.restapi.testing import PLONE_RESTAPI_DX_PAM_FUNCTIONAL_TESTING

class TestPAMDocumentation(unittest.TestCase):

layer = PLONE_RESTAPI_DX_PAM_FUNCTIONAL_TESTING

def setUp(self):
self.app = self.layer['app']
self.request = self.layer['request']
self.portal = self.layer['portal']
self.portal_url = self.portal.absolute_url()

self.time_freezer = freeze_time("2016-10-21 19:00:00")
self.frozen_time = self.time_freezer.start()

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)

setRoles(self.portal, TEST_USER_ID, ['Manager'])

language_tool = getToolByName(self.portal, 'portal_languages')
language_tool.addSupportedLanguage('en')
language_tool.addSupportedLanguage('es')
applyProfile(self.portal, 'plone.app.multilingual:default')
self.en_content = createContentInContainer(
self.portal['en'], 'Document', title='Test document')
self.es_content = createContentInContainer(
self.portal['es'], 'Document', title='Test document')

import transaction
transaction.commit()
self.browser = Browser(self.app)
self.browser.handleErrors = False
self.browser.addHeader(
'Authorization',
'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,)
)

def tearDown(self):
self.time_freezer.stop()

def test_documentation_translations_post(self):
response = self.api_session.post(
'{}/@translations'.format(self.en_content.absolute_url()),
json={
'id': self.es_content.absolute_url()
}
)
save_request_and_response_for_docs('translations_post', response)

def test_documentation_translations_get(self):
ITranslationManager(self.en_content).register_translation(
'es', self.es_content)
transaction.commit()
response = self.api_session.get(
'{}/@translations'.format(self.en_content.absolute_url()))

save_request_and_response_for_docs('translations_get', response)

def test_documentation_translations_delete(self):
ITranslationManager(self.en_content).register_translation(
'es', self.es_content)
transaction.commit()
response = self.api_session.delete(
'{}/@translations'.format(self.en_content.absolute_url()),
json={
"language": "es"
})
save_request_and_response_for_docs('translations_delete', response)

0 comments on commit f07dc4c

Please sign in to comment.