Working Copy#
Note
This feature is available only on Plone 5 or greater.
Plone has a working copy feature provided by the core package plone.app.iterate
.
It allows the users to create a working copy of a published or live content object, and work with it until it is ready to be published without having to edit the original object.
This process has several steps in its life cycle.
Create working copy (a.k.a., check-out)#
The user initiates the process and creates a working copy by checking out the content:
POST /plone/document/@workingcopy HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
curl -i -X POST http://nohost/plone/document/@workingcopy -H "Accept: application/json" --user admin:secret
http POST http://nohost/plone/document/@workingcopy Accept:application/json -a admin:secret
requests.post('http://nohost/plone/document/@workingcopy', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
…and receives the response:
HTTP/1.1 201 Created
Content-Type: application/json
Location: http://localhost:55001/plone/document
{
"@id": "http://localhost:55001/plone/copy_of_document"
}
Get the working copy#
A working copy has been created and can be accessed querying the content:
GET /plone/document/@workingcopy HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
curl -i -X GET http://nohost/plone/document/@workingcopy -H "Accept: application/json" --user admin:secret
http http://nohost/plone/document/@workingcopy Accept:application/json -a admin:secret
requests.get('http://nohost/plone/document/@workingcopy', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
…and receives the response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"working_copy": {
"@id": "http://localhost:55001/plone/copy_of_document",
"created": "1995-07-31T13:45:00+00:00",
"creator_name": "admin",
"creator_url": "http://localhost:55001/plone/author/admin",
"title": "Test document"
},
"working_copy_of": null
}
The GET
content of any object also states the location of the working copy, if any, as working_copy
:
GET /plone/document HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
curl -i -X GET http://nohost/plone/document -H "Accept: application/json" --user admin:secret
http http://nohost/plone/document Accept:application/json -a admin:secret
requests.get('http://nohost/plone/document', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json
{
"@components": {
"actions": {
"@id": "http://localhost:55001/plone/document/@actions"
},
"aliases": {
"@id": "http://localhost:55001/plone/document/@aliases"
},
"breadcrumbs": {
"@id": "http://localhost:55001/plone/document/@breadcrumbs"
},
"contextnavigation": {
"@id": "http://localhost:55001/plone/document/@contextnavigation"
},
"navigation": {
"@id": "http://localhost:55001/plone/document/@navigation"
},
"navroot": {
"@id": "http://localhost:55001/plone/document/@navroot"
},
"types": {
"@id": "http://localhost:55001/plone/document/@types"
},
"workflow": {
"@id": "http://localhost:55001/plone/document/@workflow"
}
},
"@id": "http://localhost:55001/plone/document",
"@type": "Document",
"UID": "SomeUUID000000000000000000000001",
"allow_discussion": false,
"contributors": [],
"created": "1995-07-31T13:45:00+00:00",
"creators": [
"test_user_1_"
],
"description": "",
"effective": null,
"exclude_from_nav": false,
"expires": null,
"id": "document",
"is_folderish": false,
"language": "",
"layout": "document_view",
"lock": {
"created": "1995-07-31T17:30:00+00:00",
"creator": "admin",
"creator_name": "admin",
"creator_url": "http://localhost:55001/plone/author/admin",
"locked": true,
"name": "iterate.lock",
"stealable": false,
"time": 807211800.0,
"timeout": 4294967280,
"token": "0.12345678901234567-0.98765432109876543-00105A989226:1630609830.249"
},
"modified": "1995-07-31T17:30:00+00:00",
"next_item": {},
"parent": {
"@id": "http://localhost:55001/plone",
"@type": "Plone Site",
"description": "",
"title": "Plone site",
"type_title": "Plone Site"
},
"previous_item": {},
"relatedItems": [],
"review_state": "private",
"rights": "",
"subjects": [],
"table_of_contents": null,
"text": null,
"title": "Test document",
"type_title": "Page",
"version": "current",
"working_copy": {
"@id": "http://localhost:55001/plone/copy_of_document",
"created": "1995-07-31T13:45:00+00:00",
"creator_name": "admin",
"creator_url": "http://localhost:55001/plone/author/admin",
"title": "Test document"
},
"working_copy_of": null
}
The GET
content of any a working copy also returns the original as working_copy_of
:
GET /plone/copy_of_document HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
curl -i -X GET http://nohost/plone/copy_of_document -H "Accept: application/json" --user admin:secret
http http://nohost/plone/copy_of_document Accept:application/json -a admin:secret
requests.get('http://nohost/plone/copy_of_document', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json
{
"@components": {
"actions": {
"@id": "http://localhost:55001/plone/copy_of_document/@actions"
},
"aliases": {
"@id": "http://localhost:55001/plone/copy_of_document/@aliases"
},
"breadcrumbs": {
"@id": "http://localhost:55001/plone/copy_of_document/@breadcrumbs"
},
"contextnavigation": {
"@id": "http://localhost:55001/plone/copy_of_document/@contextnavigation"
},
"navigation": {
"@id": "http://localhost:55001/plone/copy_of_document/@navigation"
},
"navroot": {
"@id": "http://localhost:55001/plone/copy_of_document/@navroot"
},
"types": {
"@id": "http://localhost:55001/plone/copy_of_document/@types"
},
"workflow": {
"@id": "http://localhost:55001/plone/copy_of_document/@workflow"
}
},
"@id": "http://localhost:55001/plone/copy_of_document",
"@type": "Document",
"UID": "SomeUUID000000000000000000000002",
"allow_discussion": false,
"contributors": [],
"created": "1995-07-31T13:45:00+00:00",
"creators": [
"test_user_1_"
],
"description": "",
"effective": null,
"exclude_from_nav": false,
"expires": null,
"id": "copy_of_document",
"is_folderish": false,
"language": "",
"layout": "document_view",
"lock": {
"locked": false,
"stealable": true
},
"modified": "1995-07-31T17:30:00+00:00",
"next_item": {},
"parent": {
"@id": "http://localhost:55001/plone",
"@type": "Plone Site",
"description": "",
"title": "Plone site",
"type_title": "Plone Site"
},
"previous_item": {},
"relatedItems": [],
"review_state": "private",
"rights": "",
"subjects": [],
"table_of_contents": null,
"text": null,
"title": "Test document",
"type_title": "Page",
"version": "current",
"working_copy": {
"@id": "http://localhost:55001/plone/copy_of_document",
"created": "1995-07-31T13:45:00+00:00",
"creator_name": "admin",
"creator_url": "http://localhost:55001/plone/author/admin",
"title": "Test document"
},
"working_copy_of": {
"@id": "http://localhost:55001/plone/document",
"title": "Test document"
}
}
Check-in#
Once the user has finished editing the working copy and wants to update the original with the changes, they would check in the working copy:
PATCH /plone/copy_of_document/@workingcopy HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
curl -i -X PATCH http://nohost/plone/copy_of_document/@workingcopy -H "Accept: application/json" --user admin:secret
http PATCH http://nohost/plone/copy_of_document/@workingcopy Accept:application/json -a admin:secret
requests.patch('http://nohost/plone/copy_of_document/@workingcopy', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
…and receives the response:
HTTP/1.1 204 No Content
The working copy is deleted afterwards as a result of this process.
The PATCH
can also be issued in the original (baseline) object.
Delete the working copy (cancel check-out)#
If you want to cancel the check-out and delete the working copy (in both the original and the working copy):
DELETE /plone/copy_of_document/@workingcopy HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
curl -i -X DELETE http://nohost/plone/copy_of_document/@workingcopy -H "Accept: application/json" --user admin:secret
http DELETE http://nohost/plone/copy_of_document/@workingcopy Accept:application/json -a admin:secret
requests.delete('http://nohost/plone/copy_of_document/@workingcopy', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
and receives the response:
HTTP/1.1 204 No Content
When a working copy is deleted using the normal DELETE
action, it also deletes the relation and cancels the check-out.
That is handled by plone.app.iterate
internals.