Working Copy

Note

This is only available on Plone 5.

Plone has the “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’s ready to be published without having to edit the original object.

This process has several steps of it’s life cycle:

Create working Copy (aka Check-out)

The user initiates the process and creates a “working copy” by “checking out” the content:

http

POST /plone/document/@workingcopy HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i -X POST http://nohost/plone/document/@workingcopy -H 'Accept: application/json' --user admin:secret

httpie

http POST http://nohost/plone/document/@workingcopy Accept:application/json -a admin:secret

python-requests

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:

http

GET /plone/document/@workingcopy HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i http://nohost/plone/document/@workingcopy -H 'Accept: application/json' --user admin:secret

httpie

http http://nohost/plone/document/@workingcopy Accept:application/json -a admin:secret

python-requests

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",
        "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 (working_copy).

http

GET /plone/document HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i http://nohost/plone/document -H 'Accept: application/json' --user admin:secret

httpie

http http://nohost/plone/document Accept:application/json -a admin:secret

python-requests

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"
        },
        "breadcrumbs": {
            "@id": "http://localhost:55001/plone/document/@breadcrumbs"
        },
        "contextnavigation": {
            "@id": "http://localhost:55001/plone/document/@contextnavigation"
        },
        "navigation": {
            "@id": "http://localhost:55001/plone/document/@navigation"
        },
        "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",
    "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",
        "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",
    "next_item": {
        "@id": "http://localhost:55001/plone/copy_of_document",
        "@type": "Document",
        "description": "",
        "title": "Test document"
    },
    "parent": {
        "@id": "http://localhost:55001/plone",
        "@type": "Plone Site",
        "description": "",
        "title": "Plone site"
    },
    "previous_item": {},
    "relatedItems": [],
    "review_state": "private",
    "rights": "",
    "subjects": [],
    "table_of_contents": null,
    "text": null,
    "title": "Test document",
    "version": "current",
    "working_copy": {
        "@id": "http://localhost:55001/plone/copy_of_document",
        "created": "1995-07-31T13:45: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 (working_copy_of):

http

GET /plone/copy_of_document HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i http://nohost/plone/copy_of_document -H 'Accept: application/json' --user admin:secret

httpie

http http://nohost/plone/copy_of_document Accept:application/json -a admin:secret

python-requests

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"
        },
        "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"
        },
        "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",
    "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",
    "next_item": {},
    "parent": {
        "@id": "http://localhost:55001/plone",
        "@type": "Plone Site",
        "description": "",
        "title": "Plone site"
    },
    "previous_item": {
        "@id": "http://localhost:55001/plone/document",
        "@type": "Document",
        "description": "",
        "title": "Test document"
    },
    "relatedItems": [],
    "review_state": "private",
    "rights": "",
    "subjects": [],
    "table_of_contents": null,
    "text": null,
    "title": "Test document",
    "version": "current",
    "working_copy": {
        "@id": "http://localhost:55001/plone/copy_of_document",
        "created": "1995-07-31T13:45: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 in there, or “check-in” the working copy.

http

PATCH /plone/copy_of_document/@workingcopy HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i -X PATCH http://nohost/plone/copy_of_document/@workingcopy -H 'Accept: application/json' --user admin:secret

httpie

http PATCH http://nohost/plone/copy_of_document/@workingcopy Accept:application/json -a admin:secret

python-requests

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 checkout and delete the working copy (in both the original and the working copy):

http

DELETE /plone/copy_of_document/@workingcopy HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i -X DELETE http://nohost/plone/copy_of_document/@workingcopy -H 'Accept: application/json' --user admin:secret

httpie

http DELETE http://nohost/plone/copy_of_document/@workingcopy Accept:application/json -a admin:secret

python-requests

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, but that is handled by plone.app.iterate internals.