@ -589,6 +589,9 @@ a client should be able to discover further resources in the API.
"priorities" : {
"href" : "/api/v3/priorities"
},
"relations" : {
"href" : "/api/v3/relations"
},
"statuses" : {
"href" : "/api/v3/statuses"
},
@ -2233,46 +2236,595 @@ Lists the columns available for work packages of this project in the form of fie
+ Response 400 (application/hal+json)
Occurs when the client did not send an empty request body.
Occurs when the client did not send an empty request body.
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:InvalidRequestBody",
"message": "The request body was not empty."
}
+ Response 403 (application/hal+json)
Returned if the client does not have sufficient permissions.
**Required permission:** for own queries none; for public queries: manage public queries
*Note that you will only receive this error, if you are at least allowed to see the corresponding query.*
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:MissingPermission",
"message": "You are not allowed to unstar this query."
}
+ Response 404 (application/hal+json)
Returned if the query does not exist or the client does not have sufficient permissions to see it.
**Required condition:** query belongs to user or query is public
**Required permission:** view work package in queries project
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:NotFound",
"message": "The specified query does not exist."
}
# Group Relations
Work packages may be related to each other in different ways.
```
+--------------+ +--------------+
| | 1 1 | |
| Work package +-------------+--------------+ Work package |
| | from | to | |
+--------------+ | +--------------+
+------+-------+
| Relation |
+--------------+
| type |
| reverseType |
| description |
| delay |
+--------------+
```
## Actions
| Link | Description | Condition |
|:-------------------:| -------------------------------------------------------------------- | --------------------------------------------- |
| update | Updates the relation between two work packages via a form | **Permission**: manage work package relations |
| updateImmediately | Updates the relation between two work packages | **Permission**: manage work package relations |
| delete | Destroys the relation between the two work packages | **Permission**: manage work package relations |
## Linked Properties
| Link | Description | Type | Constraints | Supported operations | Condition |
|:-------------:|-------------------------------------- | ------------- | ----------- | -------------------- | --------------------------------------------- |
| self | This relation | Relation | not null | READ | **Permission**: view work packages |
| schema | The schema of this relation | Schema | not null | READ | |
| from | The emanating work package | WorkPackage | not null | READ | **Permission**: view work packages |
| to | The work package the relation ends in | WorkPackage | not null | READ | **Permission**: view work packages |
## Local Properties
| Property | Description | Type | Constraints | Supported operations |
| :---------------:| ------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------- | -------------------- |
| id | Relation ID | Integer | x > 0 | READ |
| name | The internationalized name of this kind of relation | String | | READ
| type | Which kind of relation (blocks, precedes, etc.) | String | in: relates, duplicates, duplicated, blocks, blocked, precedes, follows, includes, partof, requires, required | READ / WRITE |
| reverseType | The kind of relation from the other WP's perspective | String | in: relates, duplicates, duplicated, blocks, blocked, precedes, follows, includes, partof, requires, required | READ |
| description | Short text further describing the relation | String | | READ / WRITE |
| delay* | The delay in days between closing of `from` and start of `to` | Integer | x >= 0 | READ / WRITE |
\* Only applicable for some relation types such as "follows". You can check using the relation by schema
endpoint at `/api/v3/relations/schema/{type}`.
## Relation [/api/v3/relations/{id}]
+ Model
+ Body
{
"_links":
{
"self":
{
"href": "/api/v3/relations/1"
},
"update":
{
"href": "/api/v3/relations/1/form",
"method": "POST"
},
"updateImmediately":
{
"href": "/api/v3/relations/1",
"method": "PATCH"
},
"delete":
{
"href": "/api/v3/relations/1",
"method": "DELETE"
},
"from":
{
"href": "/api/v3/work_packages/42",
"title": "Steel Delivery"
},
"to":
{
"href": "/api/v3/work_packages/84",
"title": "Bending the steel"
}
},
"_type": "Relation",
"id": 1,
"name": "precedes",
"type": "precedes",
"reverseType": "follows",
"description": "We can't bend the steel before it's been delivered!",
"delay": 0
}
## View Relation [GET]
+ Parameters
+ id (required, integer, `1`) ... Relation id
+ Response 200 (application/hal+json)
[Relation][]
+ Response 404 (application/hal+json)
Returned if the relation does not exist or the client does not have sufficient permissions to see it.
**Required permission:** view work packages for the involved work packages
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:NotFound",
"message": "The specified relation does not exist."
}
## Edit Relation [PATCH]
When calling this endpoint the client provides a single object, containing the properties and links that it wants to change, in the body.
It is only allowed to provide properties or links supporting the **write** operation.
Note that changing the `type` of a relation invariably also changes the respective `reverseType` as well as the "name" of it.
The returned Relation object will reflect that change. For instance if you change a Relation's
`type` to "follows" then the `reverseType` will be changed to `precedes`.
+ Parameters
+ id (required, integer, `1`) ... Relation ID
+ Request Update Relation (application/json)
+ Body
{
"type": "blocks",
"description": "Actually the supplier has to bend the steel before they can deliver it."
"delay": 3
}
+ Response 200 (application/hal+json)
[Relation][]
+ Response 400 (application/hal+json)
Occurs when the client did not send a valid JSON object in the request body.
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:InvalidRequestBody",
"message": "The request body was not a single JSON object."
}
+ Response 404 (application/hal+json)
Returned if the relation does not exist or the client does not have sufficient permissions to see it.
**Required permission:** manage work package relations
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:NotFound",
"message": "The specified relation does not exist."
}
+ Response 422 (application/hal+json)
Returned if:
* the client tries to modify a read-only property (`PropertyIsReadOnly`)
* a constraint for a property was violated (`PropertyConstraintViolation`)
* the client provides a link to an invalid resource (`ResourceTypeMismatch`) or a
work package that does not exist or for which the client does not have sufficient permissions
to see it (**required permissions**: `view work packages` for the involved work packages).
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation",
"message": "Delay must be a number greater than or equal to 0",
"_embedded": {
"details": {
"attribute": "delay"
}
}
}
## Delete Relation [DELETE]
Deletes the relation.
+ Parameters
+ id (required, integer, `1`) ... Relation ID
+ Response 204 (application/hal+json)
Returned if the relation was deleted successfully.
The response body is empty.
+ Body
+ Response 403 (application/hal+json)
Returned if the client does not have sufficient permissions.
**Required permission:** manage work package relations
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:MissingPermission",
"message": "You are not allowed to delete this relation."
}
+ Response 404 (application/hal+json)
Returned if the relation does not exist or the client does not have sufficient permissions to see it.
**Required permission:** manage work package relations
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:NotFound",
"message": "The specified relation does not exist."
}
## Relation schema [/api/v3/relations/schema]
+ Model
+ Body
{
"_type": "Schema",
"_links": {
"self": { "href": "/api/v3/relations/schema" }
},
"id": {
"name": "ID",
"type": "Integer",
"writable": false
},
"type": {
"name": "Type",
"type": "String",
"writable": true
},
"reverseType": {
"name": "Reverse Type",
"type": "String",
"writable": false
},
"description": {
"name": "Description",
"type": "String",
"writable": true
},
"from": {
"name": "From work package",
"type": "WorkPackage",
"writable": false
},
"to": {
"name": "To work package",
"type": "WorkPackage",
"writable": false
},
"delay": {
"name": "Delay",
"type": "Integer",
"writable": true
}
}
## View relation schema [GET]
+ Response 200 (application/hal+json)
[Relation schema][]
## Relation schema for type [/api/v3/relations/schema/{type}]
The exact schema for a relation may depend on it's type.
For instance the "follows" relation has an additional "delay" field which is not
applicable for the other relations.
## View relation schema for type [GET]
+ Parameters
+ type (required, string, `follows`) ... Type of the schema
+ Response 200 (application/hal+json)
[Relation schema][]
+ Response 404 (application/hal+json)
Returned if the relation type does not exist or the client does not have sufficient permissions to see it.
**Required permission:** manage work package relations
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:NotFound",
"message": "The specified relation type does not exist."
}
## Relations [/api/v3/relations?offset,pageSize,filters,sortBy]
+ Model
+ Body
{
"_links":
{
"self":
{
"href": "/api/v3/relations"
}
},
"total": 3,
"count": 1,
"_type": "Collection",
"_embedded":
{
"elements": [
{
"_links":
{
"self":
{
"href": "/api/v3/relations/1"
},
"update":
{
"href": "/api/v3/relations/1/form",
"method": "POST"
},
"updateImmediately":
{
"href": "/api/v3/relations/1",
"method": "PATCH"
},
"delete":
{
"href": "/api/v3/relations/1",
"method": "DELETE"
},
"from":
{
"href": "/api/v3/work_packages/42",
"title": "Steel Delivery"
},
"to":
{
"href": "/api/v3/work_packages/84",
"title": "Bending the steel"
}
},
"_type": "Relation",
"id": 1,
"name": "precedes",
"type": "precedes",
"reverseType": "follows",
"description": "We can't bend the steel before it's been delivered!",
"delay": 0
}
]
}
}
## List Relations [GET]
Lists all relations according to the given (optional, logically conjunctive) filters and ordered by ID.
The response only includes relations between work packages which the user is allowed to see.
+ Parameters
+ offset = `0` (optional, integer, `5`) ... Page number inside the requested collection
+ pageSize (optional, integer, `20`) ... Number of elements to display per page
+ filters (optional, string, `[{ "from": { "operator": "=", "values": 42 }" }]`) ... JSON specifying filter conditions.
Accepts the same format as returned by the [queries](#queries) endpoint. Valid fields to filter by are:
`from` (ID of work package from which the filtered relations emanates), `to` (ID of work package to which this related points),
`involved` (ID of either the `from` or the `to` work package.), `type` (The type of relation to filter by, e.g. "follows")
+ sortBy (optional, string, `[["type", "asc"]]`) ... JSON specifying sort criteria.
Accepts the same format as returned by the [queries](#queries) endpoint.
+ Response 200 (application/hal+json)
[Relations][]
## Relation edit form [/api/v3/relations/{id}/form]
This endpoint returns a form to allow a guided creation of a new work package relation.
The returned form will be pre-filled with default values for every property, if available.
For more details and all possible responses see the general specification of [Forms](#forms).
+ Model
+ Body
{
"_links": {
"self": { "href": "/api/v3/relations/form" },
"validate": {
"href": "/api/v3/relations/form",
"method": "POST"
},
"commit": {
"href": "/api/v3/relations",
"method": "PATCH"
}
},
"_type": "Form",
"_embedded": {
"payload": {
"_links": {
"from": { "href": "/api/v3/work_packages/4534" },
"to": { "href": "/api/v3/work_packages/3857" }
},
"_type": "WorkPackage",
"type": "follows",
"delay": 3,
"description": "let it rest for 3 days"
},
"schema": {
"_type": "Schema",
"_links": {
"self": { "href": "/api/v3/relations/schema" }
},
"id": {
"name": "ID",
"type": "Integer",
"writable": false
},
"type": {
"name": "Type",
"type": "String",
"writable": true,
"allowedValues": [
"relates", "duplicates", "duplicated", "blocks", "blocked",
"precedes", "follows", "includes", "partof", "requires", "required"
]
},
"reverseType": {
"name": "Reverse Type",
"type": "String",
"writable": false
},
"description": {
"name": "Description",
"type": "String",
"writable": true
},
"from": {
"name": "From work package",
"type": "WorkPackage",
"writeable": false
},
"to": {
"name": "To work package",
"type": "WorkPackage",
"writable": false
},
"delay": {
"name": "Delay",
"type": "Integer",
"writable": true
}
},
"validationErrors": {
"from": {
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:BadExampleError",
"message": "For the purpose of this example we need a validation error. The remainder of the response pretends there were no errors."
}
}
}
}
## Relation edit form [POST]
+ Body
+ Request
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:InvalidRequestBody",
"message": "The request body was not empty."
"_type": "Relation",
"type": "follows",
"description": "let it rest for 3 days",
"delay": 3
}
+ Parameters
+ id (required, integer, `1`) ... ID of the relation being modified
+ Response 200 (application/hal+json)
[Relation edit form][]
+ Response 403 (application/hal+json)
Returned if the client does not have sufficient permissions.
**Required permission:** for own queries none; for public queries: manage public queries
**Required permission:** manage work package relation s
*Note that you will only receive this error, if you are at least allowed to see the corresponding query.*
*Note that you will only receive this error, if you are at least allowed to see the involved work packages .*
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:MissingPermission",
"message": "You are not allowed to unstar this query."
"message": "You are not allowed to edit the specified relation ."
}
+ Response 404 (application/hal+json)
Returned if the query does not exist or the client does not have sufficient permissions to see it.
**Required condition:** query belongs to user or query is public
Returned if the relation does not exist or the client does not have sufficient permissions to see it.
**Required permission:** view work package in queries project
**Required permission:** view (involved) work package(s), manage work package relations
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:NotFound",
"message": "The specified query does not exist."
"message": "The specified relation does not exist."
}
# Group Revisions
@ -4211,6 +4763,7 @@ Note that due to sharing this might be more than the versions *defined* by that
| updateImmediately | Directly perform edits on a work package | **Permission**: edit work package |
| watch | Add current user to WP watchers | logged in; not watching |
| unwatch | Remove current user from WP watchers | logged in; watching |
| addRelation | Adds a relation to this work package. | **Permission**: manage wp relations |
| addWatcher | Add any user to WP watchers | **Permission**: add watcher |
| previewMarkup | Post markup (e.g. textile) here to receive an HTML-rendered response | |
| addComment | Post comment to WP | **Permission**: add work package notes |
@ -4231,6 +4784,7 @@ Note that due to sharing this might be more than the versions *defined* by that
| priority | The priority of the work package | Priority | not null | READ / WRITE | |
| project | The project to which the work package belongs | Project | not null | READ / WRITE | |
| responsible | The person that is responsible for the overall outcome | User | | READ / WRITE | |
| relations | Relations this work package is involved in | Relation | | READ | **Permission** view work packages |
| revisions | Revisions that are referencing the work package | Revision | | READ | **Permission** view changesets |
| status | The current status of the work package | Status | not null | READ / WRITE | |
| timeEntries | All time entries logged on the work package. Please note that this is a link to an HTML resource for now and as such, the link is subject to change. | N/A | | READ | **Permission** view time entries |
@ -4323,6 +4877,10 @@ the human readable name of custom fields.*
"href": "/api/v3/users/23",
"title": "Laron Leuschke - Alaina5788"
},
"relations": {
"href": "/api/v3/work_packages/1528/relations",
"title": "Show relations"
},
"revisions": {
"href": "/api/v3/work_packages/1528/revisions"
},
@ -4374,7 +4932,7 @@ the human readable name of custom fields.*
"templated": true
},
"addRelation": {
"href": "/api/v3/work_packages/1528/ relations",
"href": "/api/v3/relations",
"method": "post",
"title": "Add relation"
},
@ -5064,6 +5622,259 @@ For more details and all possible responses see the general specification of [Fo
[Example Form][]
## Relations [/api/v3/work_packages/{work_package_id}/relations]
## Create Relation [POST]
When calling this endpoint the client provides a single object, containing at least the properties and links that are required, in the body.
The required fields of a Relation can be found in its schema, which is embedded in the respective form.
Note that it is only allowed to provide properties or links supporting the write operation.
+ Parameters
+ work_package_id (required, integer, `1`) ... Work package id
+ Request Create Relation (application/json)
+ Body
{
"_links":
{
"from": "/api/v3/work_packages/42",
"to": "/api/v3/work_packages/84"
}
"type": "duplicates",
"description": "This is the same thing. Let's track it in one place only, shall we?"
}
+ Response 201 (application/hal+json)
[Relation][]
+ Response 400 (application/hal+json)
Occurs when the client did not send a valid JSON object in the request body.
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:InvalidRequestBody",
"message": "The request body was not a single JSON object."
}
+ Response 403 (application/hal+json)
Returned if the client does not have sufficient permissions.
**Required permission:** manage work package relations
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:MissingPermission",
"message": "You are not allowed to create a relation."
}
+ Response 409 (application/hal+json)
Returned if there already exists a relation between the given work packages of **any** type
or if the relation is not allowed.
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:UpdateConflict",
"message": "A relation of that type between the work packages either already exists or is not allowed."
}
+ Response 422 (application/hal+json)
Returned if:
* the client tries to write a read-only property (`PropertyIsReadOnly`)
* a constraint for a property was violated (`PropertyConstraintViolation`)
* the client provides a link to an invalid resource (`ResourceTypeMismatch`)
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation",
"message": "Delay must be a number greater than or equal to 0",
"_embedded": {
"details": {
"attribute": "delay"
}
}
}
## List relations [GET]
Lists all relations this work package is involved in.
+ Parameters
+ work_package_id (required, integer, `1`) ... Work package id
+ Response 302 (text/plain)
+ Headers
Location: /api/v3/relations?involved={work_package_id}
+ Body
You are being redirected to /api/v3/relations?involved={work_package_id}
## Work Package Relation Form [/api/v3/work_packages/{id}/relations/form]
+ Model
+ Body
{
"_links": {
"self": { "href": "/api/v3/relations/form" },
"validate": {
"href": "/api/v3/relations/form",
"method": "POST"
},
"commit": {
"href": "/api/v3/relations",
"method": "PATCH"
}
},
"_type": "Form",
"_embedded": {
"payload": {
"_links": {
"from": { "href": "/api/v3/work_packages/4534" },
"to": { "href": "/api/v3/work_packages/3857" }
},
"_type": "WorkPackage",
"type": "follows",
"delay": 3,
"description": "let it rest for 3 days"
},
"schema": {
"_type": "Schema",
"id": {
"name": "ID",
"type": "Integer",
"writable": false
},
"type": {
"name": "Type",
"type": "String",
"writable": true,
"allowedValues": [
"relates", "duplicates", "duplicated", "blocks", "blocked",
"precedes", "follows", "includes", "partof", "requires", "required"
]
},
"reverseType": {
"name": "Reverse Type",
"type": "String",
"writable": false
},
"description": {
"name": "Description",
"type": "String",
"writable": true
},
"from": {
"_links": {
"allowedValues": [
{ "href": "/api/v3/work_packages/{id}" }
]
},
"name": "From work package",
"type": "WorkPackage",
"writable": true
},
"to": {
"_links": {
"allowedValues": {
"href": "/api/v3/work_packages/{id}/available_relation_candidates",
"title": "Available work packages to relate to"
}
},
"name": "To work package",
"type": "WorkPackage",
"writable": true
},
"delay": {
"name": "Delay",
"type": "Integer",
"writable": true
}
},
"validationErrors": {
"from": {
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:BadExampleError",
"message": "For the purpose of this example we need a validation error. The remainder of the response pretends there were no errors."
}
}
}
}
## Relation create form [POST]
+ Request
{
"_type": "Relation",
"type": "follows",
"from": { "href": "/api/v3/work_packages/3493" },
"to": { "href": "/api/v3/work_packages/4582" },
"description": "let it rest for 3 days",
"delay": 3
}
+ Parameters
+ id (required, integer, `1`) ... ID of the relation being modified
+ Response 200 (application/hal+json)
[Work Package Relation Form][]
+ Response 403 (application/hal+json)
Returned if the client does not have sufficient permissions.
**Required permission:** manage work package relations
*Note that you will only receive this error, if you are at least allowed to see the involved work packages.*
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:MissingPermission",
"message": "You are not allowed to edit the specified relation."
}
+ Response 404 (application/hal+json)
Returned if the relation does not exist or the client does not have sufficient permissions to see it.
**Required permission:** view (involved) work package(s), manage work package relations
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:NotFound",
"message": "The specified relation does not exist."
}
## Watchers [/api/v3/work_packages/{work_package_id}/watchers]
+ Model
@ -5330,6 +6141,79 @@ If the request succeeds, the specified user is not watching the work package any
"message": "The specified work package does not exist."
}
## Available relation candidates [/api/v3/work_packages/{id}/available_relation_candidates?filters,query,offset,pageSize]
Lists work packages with which this work package can be in a relation.
Only sound candidates are returned. For instance a work package cannot stand in relation to itself,
and a work package that follows another cannot precede it.
Candidates can be filtered. Most commonly one will want to filter by subject.
You can do this through the `filters` parameter which works just like the work package index.
For instance to find all work packages with "rollout" in their subject:
```
?filters=[{"subject":{"operator":"~","values":["rollout"]}}]
```
For convenience there is also a simple `query` parameter which is a shortcut for listing work packages
whose ID or subject contain the given string.
```
?query=112
```
+ Model
+ Body
{
"_links": {
"self": { "href": "/api/v3/projects/14/work_packages" }
},
"total": 2,
"count": 2,
"_type": "Collection",
"_embedded": {
"elements": [
{
"_type": "WorkPackage",
"_links": {
"self": {
"href": "/api/v3/work_packages/1"
}
},
"id": 1,
"subject": "Skipped other properties for brevity"
},
{
"_type": "WorkPackage",
"_links": {
"self": {
"href": "/api/v3/work_packages/2"
}
},
"id": 2,
"subject": "Skipped other properties for brevity"
}]
}
}
## Available relation candidates [GET]
+ Parameters
+ offset = `1` (optional, integer, `25`) ... Page number inside the requested collection.
+ pageSize (optional, integer, `25`) ... Number of elements to display per page.
+ filters (optional, string, `[{ "status_id": { "operator": "o", "values": null }" }]`) ... JSON specifying filter conditions.
Accepts the same format as returned by the [queries](#queries) endpoint.
+ query (optional, string, `"rollout"`) ... Shortcut for filtering by ID or subject
+ Response 200 (application/hal+json)
[Available relation candidates][]
## Available Watchers [/api/v3/work_packages/{id}/available_watchers]
+ Model