plone.restapi/unify-expired-and-excluded-items-handling: Add documentation for locking

Thomas Buchberger <jenkins-z4DKO/[email protected]> Sat, 29 Jul 2017 16:31:59 -0700 (PDT)
Newsgroups gmane.comp.web.zope.plone.cvs
Message-ID <[email protected]>
Repository: plone.restapi
Branch: refs/heads/unify-expired-and-excluded-items-handling
Date: 2017-07-27T10:02:23+02:00
Author: Thomas Buchberger (buchi) <t.buchberger-/8aE7x569Db/[email protected]>
Commit: https://github.com/plone/plone.restapi/commit/61e848796d579d851329632c3e33a1a22a358def

Add documentation for locking

Files changed:
A docs/source/_json/lock.req
A docs/source/_json/lock.resp
A docs/source/_json/lock_get.req
A docs/source/_json/lock_get.resp
A docs/source/_json/lock_nonstealable_timeout.req
A docs/source/_json/lock_nonstealable_timeout.resp
A docs/source/_json/refresh_lock.req
A docs/source/_json/refresh_lock.resp
A docs/source/_json/unlock.req
A docs/source/_json/unlock.resp
A docs/source/locking.rst
M docs/source/index.rst
M src/plone/restapi/tests/test_documentation.py

diff --git a/docs/source/_json/lock.req b/docs/source/_json/lock.req
new file mode 100644
index 00000000..0cba19bb
--- /dev/null
+++ b/docs/source/_json/lock.req
@@ -0,0 +1,3 @@
+POST /plone/front-page/@lock HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/docs/source/_json/lock.resp b/docs/source/_json/lock.resp
new file mode 100644
index 00000000..06da01d4
--- /dev/null
+++ b/docs/source/_json/lock.resp
@@ -0,0 +1,12 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "creator": "admin", 
+  "locked": true, 
+  "name": "plone.locking.stealable", 
+  "stealable": true, 
+  "time": 1477076400.0, 
+  "timeout": 600, 
+  "token": "0.684672730996-0.25195226375-00105A989226:1477076400.000"
+}
\ No newline at end of file
diff --git a/docs/source/_json/lock_get.req b/docs/source/_json/lock_get.req
new file mode 100644
index 00000000..43cd7c0e
--- /dev/null
+++ b/docs/source/_json/lock_get.req
@@ -0,0 +1,3 @@
+GET /plone/front-page/@lock HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/docs/source/_json/lock_get.resp b/docs/source/_json/lock_get.resp
new file mode 100644
index 00000000..52852385
--- /dev/null
+++ b/docs/source/_json/lock_get.resp
@@ -0,0 +1,7 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "locked": false, 
+  "stealable": true
+}
\ No newline at end of file
diff --git a/docs/source/_json/lock_nonstealable_timeout.req b/docs/source/_json/lock_nonstealable_timeout.req
new file mode 100644
index 00000000..40383b76
--- /dev/null
+++ b/docs/source/_json/lock_nonstealable_timeout.req
@@ -0,0 +1,9 @@
+POST /plone/front-page/@lock HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
+Content-Type: application/json
+
+{
+    "stealable": false,
+    "timeout": 3600
+}
\ No newline at end of file
diff --git a/docs/source/_json/lock_nonstealable_timeout.resp b/docs/source/_json/lock_nonstealable_timeout.resp
new file mode 100644
index 00000000..e3927240
--- /dev/null
+++ b/docs/source/_json/lock_nonstealable_timeout.resp
@@ -0,0 +1,12 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "creator": "admin", 
+  "locked": true, 
+  "name": "plone.locking.stealable", 
+  "stealable": true, 
+  "time": 1477076400.0, 
+  "timeout": 3600, 
+  "token": "0.684672730996-0.25195226375-00105A989226:1477076400.000"
+}
\ No newline at end of file
diff --git a/docs/source/_json/refresh_lock.req b/docs/source/_json/refresh_lock.req
new file mode 100644
index 00000000..f1268de1
--- /dev/null
+++ b/docs/source/_json/refresh_lock.req
@@ -0,0 +1,3 @@
+POST /plone/front-page/@refresh-lock HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/docs/source/_json/refresh_lock.resp b/docs/source/_json/refresh_lock.resp
new file mode 100644
index 00000000..06da01d4
--- /dev/null
+++ b/docs/source/_json/refresh_lock.resp
@@ -0,0 +1,12 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "creator": "admin", 
+  "locked": true, 
+  "name": "plone.locking.stealable", 
+  "stealable": true, 
+  "time": 1477076400.0, 
+  "timeout": 600, 
+  "token": "0.684672730996-0.25195226375-00105A989226:1477076400.000"
+}
\ No newline at end of file
diff --git a/docs/source/_json/unlock.req b/docs/source/_json/unlock.req
new file mode 100644
index 00000000..8ea9689a
--- /dev/null
+++ b/docs/source/_json/unlock.req
@@ -0,0 +1,3 @@
+POST /plone/front-page/@unlock HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/docs/source/_json/unlock.resp b/docs/source/_json/unlock.resp
new file mode 100644
index 00000000..52852385
--- /dev/null
+++ b/docs/source/_json/unlock.resp
@@ -0,0 +1,7 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "locked": false, 
+  "stealable": true
+}
\ No newline at end of file
diff --git a/docs/source/index.rst b/docs/source/index.rst
index ea4278fd..a0d8af72 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -28,6 +28,7 @@ Contents
    copymove
    expansion
    workflow
+   locking
    sharing
    registry
    types
diff --git a/docs/source/locking.rst b/docs/source/locking.rst
new file mode 100644
index 00000000..d3fbee27
--- /dev/null
+++ b/docs/source/locking.rst
@@ -0,0 +1,80 @@
+Locking
+=======
+
+Locking an object
+-----------------
+
+To lock an object send a POST request to the ``/@lock`` endpoint.
+
+..  http:example:: curl httpie python-requests
+    :request: _json/lock.req
+
+If the lock operation succeeds, the server will respond with status 200 (OK) and return
+various information about the lock.
+
+.. literalinclude:: _json/lock.resp
+   :language: http
+
+
+By default, locks are stealable. That means that another user can unlock the object.
+If you want to create a non-stealable lock, pass ``"stealable": false`` in the request
+body.
+
+To create a lock with a non-default timeout, you can pass the the timeout value in
+seconds in the request body.
+
+The following example creates a non-stealable lock with a timeout of 1h.
+
+..  http:example:: curl httpie python-requests
+    :request: _json/lock_nonstealable_timeout.req
+
+
+The server responds with status 200 (OK) and returns the lock information.
+
+.. literalinclude:: _json/lock_nonstealable_timeout.resp
+   :language: http
+
+
+Unlocking an object
+-------------------
+
+To unlock an object send a POST request to the ``/@unlock`` endpoint.
+
+..  http:example:: curl httpie python-requests
+    :request: _json/unlock.req
+
+The server responds with status 200 (OK) and returns the lock information.
+
+.. literalinclude:: _json/unlock.resp
+   :language: http
+
+
+Refreshing a lock
+-----------------
+
+An existing lock can be refreshed by sending a POST request to the ``@refresh-lock``
+endpoint.
+
+..  http:example:: curl httpie python-requests
+    :request: _json/refresh_lock.req
+
+The server responds with status 200 (OK) and returns the lock information containing
+the updated creation time.
+
+.. literalinclude:: _json/refresh_lock.resp
+   :language: http
+
+
+Getting lock information
+------------------------
+
+To find out if an object is locked or to get information about the current lock
+you can send a GET request to the ``@lock`` endpoint.
+
+..  http:example:: curl httpie python-requests
+    :request: _json/lock_get.req
+
+The server responds with status 200 (OK) and returns the information about the lock.
+
+.. literalinclude:: _json/lock_get.resp
+   :language: http
diff --git a/src/plone/restapi/tests/test_documentation.py b/src/plone/restapi/tests/test_documentation.py
index cdbc8c3d..2f4c7aa5 100644
--- a/src/plone/restapi/tests/test_documentation.py
+++ b/src/plone/restapi/tests/test_documentation.py
@@ -15,6 +15,7 @@
 from plone.app.testing import pushGlobalRegistry
 from plone.app.testing import setRoles
 from plone.app.textfield.value import RichTextValue
+from plone.locking.interfaces import ITTWLockable
 from plone.namedfile.file import NamedBlobFile
 from plone.namedfile.file import NamedBlobImage
 from plone.registry.interfaces import IRegistry
@@ -24,6 +25,7 @@
 from plone.testing.z2 import Browser
 from zope.component import createObject
 from zope.component import getUtility
+from zope.interface import alsoProvides
 from zope.site.hooks import getSite
 
 import collections
@@ -142,6 +144,7 @@ def setUp(self):
 
         setRoles(self.portal, TEST_USER_ID, ['Manager'])
         self.document = self.create_document()
+        alsoProvides(self.document, ITTWLockable)
 
         transaction.commit()
         self.browser = Browser(self.app)
@@ -978,6 +981,57 @@ def test_tusreplace_post_patch(self):
             upload_url.split('/')[:-1] + ['4e465958b24a46ec8657e6f3be720991'])
         save_request_and_response_for_docs('tusreplace_patch', response)
 
+    def test_locking_lock(self):
+        url = '{}/@lock'.format(self.document.absolute_url())
+        response = self.api_session.post(url)
+        # Replace dynamic lock token with a static one
+        response._content = re.sub(
+            r'"token": "[^"]+"',
+            '"token": "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
+            response.content)
+        save_request_and_response_for_docs('lock', response)
+
+    def test_locking_lock_nonstealable_and_timeout(self):
+        url = '{}/@lock'.format(self.document.absolute_url())
+        response = self.api_session.post(
+            url,
+            json={
+                'stealable': False,
+                'timeout': 3600,
+            },
+        )
+        # Replace dynamic lock token with a static one
+        response._content = re.sub(
+            r'"token": "[^"]+"',
+            '"token": "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
+            response.content)
+        save_request_and_response_for_docs(
+            'lock_nonstealable_timeout', response)
+
+    def test_locking_unlock(self):
+        url = '{}/@lock'.format(self.document.absolute_url())
+        response = self.api_session.post(url)
+        url = '{}/@unlock'.format(self.document.absolute_url())
+        response = self.api_session.post(url)
+        save_request_and_response_for_docs('unlock', response)
+
+    def test_locking_refresh_lock(self):
+        url = '{}/@lock'.format(self.document.absolute_url())
+        response = self.api_session.post(url)
+        url = '{}/@refresh-lock'.format(self.document.absolute_url())
+        response = self.api_session.post(url)
+        # Replace dynamic lock token with a static one
+        response._content = re.sub(
+            r'"token": "[^"]+"',
+            '"token": "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
+            response.content)
+        save_request_and_response_for_docs('refresh_lock', response)
+
+    def test_locking_lockinfo(self):
+        url = '{}/@lock'.format(self.document.absolute_url())
+        response = self.api_session.get(url)
+        save_request_and_response_for_docs('lock_get', response)
+
 
 class TestCommenting(unittest.TestCase):
 



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot