Tasks
In iCL, whenever you need to inform a user, that (s)he has to perform an inspection/check/activity, you can create a task. A task defines which user (or team) is assigned, what workbook is to be used and can carry along custom data. Should any workbook of the inspection contain a field with the same name and a suitable type, the custom data will be used to fill it in once the inspection starts. Therefore, tasks are a powerful way to plan your teams activities.
- For an in-depth explanation of tasks, see the documentation.
- For a first walkthrough on how to use the task API, see the walkthrough here
In order to create, update or delete a task in iCL Portal, the following REST service can be used. Endpoint: /api/services/custom/externaltask
1. Querying tasks​
Url: /getall HTTP method: GET Example:
GET https://dev.iclportal.com/api/services/custom/externaltask/getall HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept-Encoding: gzip, deflate
Authorization: Bearer ..the auth_token...
Example 2: querying all tasks that were modified since a specific point in time, sorts them by their modification and returns only the first 20 of them:
GET https://dev.iclportal.com/api/services/custom/externaltask/getall?$filter=LastModificationTime+ge+datetime%272016-06-19T01:00:00%27&$inlinecount=allpages&$orderby=LastModificationTime+desc&$top=20 HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept-Encoding: gzip, deflate
Authorization: Bearer ..the auth_token...
Parameters: This is an ODATA 3.0 Endpoint allowing you to query the tasks in the system.
you can use all the attributes of the returned json objects to create a query. However, due to the ODATA specification, you must uppercase them in the query. As this is a convention in JSON and the JavaScript world, our results are returned with the attribute names lowercased.
Example: You get a task like:
{"externalId":"<ID_PROVIDED_BY_EXTERNAL_APPLICATION>","title":"New Task", …}
As you can see, the “externalId” attribute is starting with a lowercased letter. If you, however, query the ODATA endpoint using “externalId”, you need to uppercase its first letter:
/getall?$filter=ExternalId+eq+….
dynamic properties are not available in this interface
2. Creating a new task​
Url: /post HTTP method: POST
Example:
POST https://dev.iclportal.com/api/services/custom/externaltask/Post HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept-Encoding: gzip, deflate
Authorization: Bearer ..the auth_token...
{"externalId":"<ID_PROVIDED_BY_EXTERNAL_APPLICATION>",title":"New Task","teamName":"team01","workbookName":"physical_inspection","assignedUserName":"alexander.marek","description":"Description","startDate":"2015-12-28T23:00:00.000Z","dueDate":"2015-12-29T23:00:00.000Z","category":"severe_defects", “itemsToInspect”:[<ID_OR_EXTERNALID_OF_EXISTING_ITEM>]}
Parameters: The parameters are provided in the HTTP request body using a JSON object.
The externalTask object has the following fields:
Name | Type | Required? | Description |
---|---|---|---|
externalId | string | required | Has to be a unique identifier provided by the external application |
title | string | required | The title of the task |
teamName | string | required | The name of the team to associate the task with. For this to work, team names must be unique. |
workbookName | string | required | the name of the workbook that belongs to this task. For this to work, workbook names must be unique. |
assignedUserName | string | required | The unique username of the user, which has to perform this task. (i.e. the inspectors username) You can also specify the inspectors e-mail address. |
description | string | An optional description of the task | |
startDate | string | An optional startdate for the task. Note: dates must be provided as UTC and as valid ISO 8601 date string. Format: yyyy-MM-ddTHH:mm:ss.fffZ Example: 2015-12-29T23:00:00.000Z | |
duedate | string | An optional duedate for the task. Note: dates must be provided as UTC and as valid ISO 8601 date string. Format: yyyy-MM-ddTHH:mm:ss.fffZ Example: 2015-12-29T23:00:00.000Z | |
itemsToInspect | string[] | If a workbook is created to inspect a specific content type (e.g. a building), then you can specify the task which building has to be inspected. Provide an array of strings, where each value can be either the externalid of a content item or its internal contentitemid (the id that you get from the api/content/<contenttypename> api) | |
any other property | string/number/boolean | If a field does not match any of the previously defined names, it is considered a custom property of the task and stored in iCL Portal (see field “category” in the following example) Note: 1) dates must be provided as UTC and as valid ISO 8601 date string. Format: yyyy-MM-ddTHH:mm:ss.fffZ Example: 2015-12-29T23:00:00.000Z 2) Numbers must be provided as valid JSON numbers: Example: { “numberfield”:33.2 } 3) Booleans must be provided as valid JSON boolen values Example: { “istrue” : true } |
Remarks:
- All tasks added via this interface will automatically be published.
- The json object can contain any other field which will be stored by iCL Portal as custom property of the given task. (see field “category” in the following example)
POST https://dev.iclportal.com/api/services/custom/externaltask/Post HTTP/1.1
Authorization: Bearer ..the auth_token...
If all goes well, the server will return a 200 OK response such as:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
{"success":true,"error":null,"unAuthorizedRequest":false}
The result object
Name | Type | Description |
---|---|---|
success | boolean | Specifies, if the request was successful. If “false” is returned, some error has occurred. |
result | string/number/boolean/object | Contains an arbitrary result object given the service returns any result. |
error | object | If any error has occurred, such as validation errors, the success field will indicate “false” and the error field will contain a JSON object containing further details. |
unAuthorizedRequest | Boolean | Returns “true” if the user did not have enough permissions to execute the service method. |
If the task is not valid, it will send a 200 OK response along with an error object, encoded as JSON in the response body. In this example, the server complains, that the task did not have a title specified, although it is a required field:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
{"success":false,"result":null,"error":{"code":0,"message":"Your request is not valid!","details":"The following errors were detected during validation.\r\n - 'Title' should not be empty.\r\n","validationErrors":[{"message":"'Title' should not be empty.","members":["title"]}]},"unAuthorizedRequest":false}
The error object
Name | Type | Description |
---|---|---|
code | number | For future use |
message | string | A general user-readable error message title |
details | string | A general user-readable error message |
validationErrors | array | Contains validationError objects for each invalid field. |
The validationError object
Name | Type | Description |
---|---|---|
code | number | For future use |
message | string | A user-readable message explaining why a field was not valid. |
members | string | A list of fields that this error message belongs to. |
3. Reading a task​
Url: /get
HTTP method: POST
Example:
POST https://dev.iclportal.com/api/services/custom/externaltask/get HTTP/1.1
Accept: application/json, text/plain, */*
Authorization: Bearer ..the auth_token...
{"externalId":"<ID_PROVIDED_BY_EXTERNAL_APPLICATION>"}
The server will respond with a 200 OK containing a result object in the response body:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost
Access-Control-Allow-Credentials: true
Authorization: Bearer ..the auth_token...
{"success":true,"result”: {"externalId":"<ID_PROVIDED_BY_EXTERNAL_APPLICATION>", “inspectionId”:”<some uuid>”,”title":"New Task","teamName":"team01","workbookName":"physical_inspection","assignedUserName":"alexander.marek","description":"Description","startDate":"2015-12-28T23:00:00.000Z","dueDate":"2015-12-29T23:00:00.000Z",state:”new”,"category":"severe_defects", “itemsToInspect”:[“building01”]}
,"error":null,"unAuthorizedRequest":false}
The returned fields are the same ones that are sent when creating or updating a task, with these exceptions:
Name | Type | Description |
---|---|---|
state | string | The current state of the task. This can be either: “New”, “Assigned”, “Active”, “Closed”, or “Canceled” Note however, that at the moment the service only allows to create tasks with a valid user, so the state “New” should never be returned. (As soon as a “New” task has a user specified, it transitions to state “Assigned”) |
inspectionId | string | Once a user actually starts to perform the task, an inspection is created which all collected data (answers, pictures, reports, …) is associated with. |
4. Editing a task​
Url: /put
HTTP method: PUT
Editing a task works the same way as creating a task. Only the HTTP method and URL differ. See 3.1
Example:
PUT https://dev.iclportal.com/api/services/custom/externaltask/Put HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate
Authorization: Bearer ..the auth_token...
{"externalId":"<ID_PROVIDED_BY_EXTERNAL_APPLICATION>",title":"New Task","teamName":"team01","workbookName":"physical_inspection","assignedUserName":"alexander.marek","description":"Description","startDate":"2015-12-28T23:00:00.000Z","dueDate":"2015-12-29T23:00:00.000Z","category":"severe_defects", “itemsToInspect”:[“building01”]}
5. Deleting a task​
Allows to delete all tasks that are still waiting to be performed. As soon as a user starts to perform a given task, it is not deletable anymore.
Url: /delete
HTTP method: DELETE
Example:
POST https://dev.iclportal.com/api/services/custom/externaltask/delete HTTP/1.1
Accept: application/json, text/plain, */*
Authorization: Bearer ..the auth_token...
{"externalTaskIds": ["<ID_PROVIDED_BY_EXTERNAL_APPLICATION>"] }
the deleteTaskRequest object
Name | Type | Required? | Description |
---|---|---|---|
externalTaskIds | array | Required, min-length:1 | Contains the external IDs of the tasks that should be deleted. |
The server will respond with a 200 OK containing a result object in the response body.
6. Cancelling a task​
When a user has already started to perform a task, it will transition to the “Active” state and not be deletable anymore. Instead it has to be cancelled.
Url: /cancel
HTTP method: POST
Example:
POST https://dev.iclportal.com/api/services/custom/externaltask/cancel HTTP/1.1
Accept: application/json, text/plain, */*
Authorization: Bearer ..the auth_token...
{"externalTaskIds": ["<ID_PROVIDED_BY_EXTERNAL_APPLICATION>"] }
The deleteTaskRequest object
Name | Type | Required? | Description |
---|---|---|---|
externalTaskIds | array | Required, min-length:1 | Contains the external IDs of the tasks that should be cancelled. |
The server will respond with a 200 OK containing a result object in the response body.
7. Restarting a Task​
When a task has been cancelled, there is only one way to re-activate it. This is by restarting this task. (in iCL Portal, we call it “re-publish”)
Note: You can only restart a “cancelled” task, otherwise the server will return an error.
As soon as a task has been “restarted”, it transitions from “cancelled” to the state “assigned”. In this state the task can be modified and deleted.
Url: /restart
HTTP method: POST
Example:
POST https://dev.iclportal.com/api/services/custom/externaltask/restart HTTP/1.1
Accept: application/json, text/plain, */*
Authorization: Bearer ..the auth_token...
{"externalTaskIds": ["<ID_PROVIDED_BY_EXTERNAL_APPLICATION>"] }
The deleteTaskRequest object:
Name | Type | Required? | Description |
---|---|---|---|
externalTaskIds | array | Required, min-length:1 | Contains the external IDs of the tasks that should be cancelled. |
The server will respond with a 200 OK containing a result object in the response body
Sample request and response​
Request:
POST http://dev.iclportal.com/api/services/custom/externalTask/post HTTP/1.1
Host: dev.iclportal.com
Connection: keep-alive
Accept: application/json, text/plain, */*
Authorization: Bearer ..the auth_token...
Content-Type: application/json;charset=UTF-8
Content-Length: 256
{
"externalId" : "20160201_EN_1223",
"title" : "Inspection Report",
"teamName" : "Vienna",
"workbookName" : "EN-ContainerInspection",
"assignedUserName" : "inspector_vienna",
"description" : "",
"startDate" : "",
"dueDate" : ""
}
Response:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 204
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=e5d47670de5ad1288df9014426822f51f791b2950adeeaad1f1233637a362b8e;Path=/;Domain=dev.iclportal.com
Date: Mon, 25 Jan 2016 11:23:53 GMT
{"success":false,"result":null,"error":{"code":0,"message":"No workbook with the name or title 'EN-ContainerInspection' could be found","details":null,"validationErrors":null},"unAuthorizedRequest":false}
8. Getting changes of Tasks​
In many cases, you will want to get the latest information of iCL Portal tasks and inspections in your legacy system. A naive approach would be to use the task get endpoint to poll for changes of every task that is not yet marked as completed or cancelled in your system.
While this may technically work, it does not scale well. Imagine the number of unnecessary requests you would have to make to the iCL Portal API to get the latest information of all your tasks.
Instead, you can this endpoint to get a list of all tasks that have changed since a given timestamp.
For a more in-depth example, see the incremental changes walkthrough.
GET https://dev.iclportal.com/api/services/custom/externalTask/GetChanges HTTP/1.1
Accept: application/json
Authorization: Bearer HwBUGEn1p9S5BJi6iM.....
Response gives us the tasks (as expected) but includes a nextChangeToken
and nextLink
that can be used to get the next 500 changed tasks/inspections.
{
"result": {
"results": [
{
"id": "5bb89fe4-25dd-4014-b00e-c3ed05c15213",
"inspectionId": null,
"externalId": "TSK___000001",
"title": "Task 000000",
"workbookId": "baf7b34d-825a-443b-bf5e-928ff83d9c2e",
"workbookTitle": "test iWorkbook",
"workbookVersionCode": 52,
"assignedUserId": 4,
"assignedUserName": "antoine gadget",
"description": null,
"startDate": null,
"dueDate": null,
"state": 1,
"isSelfAssignable": true,
"workAreaId": "6058f602-f55b-45b2-90b2-9081869f7774",
"workAreaTitle": "test",
"isPublished": true,
"actualStart": null,
"actualEnd": null,
"sentDate": null,
"hasTask": true,
"lastModificationTime": "2022-10-21T13:16:23.583Z",
"inspectedItems": null,
"isDeleted": false // <-- you also get deleted tasks/inspections!
},
... many many more... (500 total)
],
"nextChangeToken": "AAAAAAAFpYA",
"nextLink": "https://dev.iclportal.com/api/services/custom/externalTask/GetChanges?changeToken=AAAAAAAFpYA"
},
"targetUrl": null,
"success": true,
"error": null,
"unAuthorizedRequest": false,
"__abp": true
}
As this endpoint is for getting any incremental changes, it also returns deleted tasks, so that you can remove them from your system accordingly.
As there are no more changes, the system simply returns the latest change available, which is usually the very same change token we just used in the request.
However, you can use this mechanism to get straight to the last page of changed inspections/tasks by using the highest possible change token __________8
This comes in handy, if you only want to start for getting changes from now on and do not wish to go through all the historical changes.