# Task System The task system lets editors assign work items ("tasks") to other users or groups. A task is a piece of content stored in a per-user task container. Each user gets their own container, automatically created when their member area is set up. Tasks carry an initiator, one or more responsibles, an action, a due date, optional rich text, and an optional relation to a related content object. The most common case -- asking a colleague to review a specific page -- is exposed through the dedicated `@task-review` REST endpoint, which is a thin shortcut around creating a task. ## Overview The system is built from two content types and a three-state workflow: - **TaskContainer** -- a singleton folder living inside each user's home folder (id `tasks`). It is created automatically when a member area is created and on first login. It is excluded from navigation and cannot be moved or copied. - **Task** -- the actual work item, created inside a TaskContainer. Its title is derived from the action and the title of the related content (for example `review - My Page`). A task always has: - an **initiator** (defaults to the current user), - one or more **responsibles** (users and/or groups), - an **action** (chosen from a configurable vocabulary), - a **due date** (defaults to 14 days from creation), - optional **rich text**, - an optional **related** content relation. When a task is created or modified, the responsible principals are granted the `Contributor` role locally on the task, so they can see and work on it. ## Actions The set of available actions is configured in the registry record `wcs.backend.tasksystem.actions`. It is a list of `Title:value` strings. The shipped default is: ```text Information:info Review:review Aufgabe:task ``` The part before the colon is the human-readable title shown in the form; the part after the colon is the stored value. The first entry is used as the default action for a newly created task. To add or rename actions, edit this registry record. ## Task Review Workflow Tasks use the `task_workflow`. It has three states and is German-labelled: | State (`review_state`) | Title | Meaning | |-------------------------------------|----------|----------------------------------| | `task_workflow--STATUS--offen` | Offen | Open, not started yet | | `task_workflow--STATUS--in-arbeit` | In Arbeit| In progress | | `task_workflow--STATUS--erledigt` | Erledigt | Done | New tasks start in **Offen**. The available transitions are: - **Offen → In Arbeit** (`mit arbeit beginnen`) - **Offen → Erledigt** (`erledigen`) - **In Arbeit → Erledigt** (`erledigen`) - **In Arbeit → Offen** (`wieder eröffnen`) - **Erledigt → Offen** (`wieder eröffnen`) ```text ┌──────────────────────────────┐ │ │ ▼ mit arbeit │ wieder ┌──────┐ beginnen ┌────────┐ eröffnen │ Offen│ ───────────────────▶ │In Arbeit│ └──────┘ └────────┘ │ \ │ │ \ erledigen │ erledigen │ \ ▼ │ \ ┌─────────┐ │ └────────────────▶│ Erledigt│ │ wieder └─────────┘ └────────────────────────────┘ eröffnen ``` All transitions are user-triggered and guarded by the `Contributor`, `Manager`, and `Owner` roles -- the responsibles of a task (who receive `Contributor` locally) can therefore move it through the workflow. ## Due Date Indexing The `due_date` field is exposed to the catalog through a `due_date` indexer, so tasks can be searched and sorted by their deadline. ## REST API ### POST @task-review Creates a review task for the current context. This is a convenience wrapper around posting a new `Task` into the current user's task container. The endpoint is available on any folderish content. It takes the responsible(s) from the request body and fills in the rest automatically: - `initiator` is set to the current user, - `related` is set to the context the endpoint was called on, - `@type` is set to `Task`, - `action` is set to `review`. The `responsible` property is **required**; omitting it returns a `400 Bad Request`. Any additional task fields (for example `text` or `due_date`) may be passed in the body and are forwarded to the created task. The created task is stored in the **calling user's** task container, with the context page as its related content. ```http POST /Plone/topics/my-page/@task-review HTTP/1.1 Host: localhost:8080 Accept: application/json Content-Type: application/json { "responsible": ["user:editor1"], "text": "
Please review the updated figures.
" } ``` The response is the standard serialization of the newly created `Task` object. #### Consuming @task-review **JavaScript:** ```javascript async function requestReview(pageUrl, responsibles, message) { const response = await fetch(`${pageUrl}/@task-review`, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ responsible: responsibles, text: message }) }); if (!response.ok) { throw new Error(`Review request failed: ${response.status}`); } return response.json(); } // Usage const task = await requestReview( 'http://localhost:8080/Plone/topics/my-page', ['user:editor1', 'group:editors'], 'Please review.
' ); console.log(task['@id']); ``` **Python:** ```python import requests response = requests.post( 'http://localhost:8080/Plone/topics/my-page/@task-review', auth=('initiator', 'password'), headers={ 'Accept': 'application/json', 'Content-Type': 'application/json', }, json={ 'responsible': ['user:editor1'], 'text': 'Please review.
', }, ) response.raise_for_status() print(response.json()['@id']) ``` The `responsible` values use the standard Plone principal token format: `user: