Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POST /runtime/tasks/{taskId} #1471

Closed
Robinyo opened this issue Dec 26, 2018 · 22 comments
Closed

POST /runtime/tasks/{taskId} #1471

Robinyo opened this issue Dec 26, 2018 · 22 comments

Comments

@Robinyo
Copy link

Robinyo commented Dec 26, 2018

Using Flowable's REST API to complete a User task:

curl -H "Content-Type: application/json" 
     -X POST http://admin:test@localhost:8080/flowable-task/process-api/runtime/tasks/1fae489a-070f-11e9-a85e-0242ac110002
     -d "@data-1.json"

data-1.json:

{
  "action" : "complete",
  "variables" : [
    {
        "id": "givenName",
        "name": "Given Name",
        "type": "string",
        "value": "Rob"
    },
    {
        "id": "familyName",
        "name": "Family Name",
        "type": "string",
        "value": "Ferguson"
    },
    {
        "id": "employeeNumber",
        "name": "Employee Number",
        "type": "integer",
        "value": 123456
    },
    {
        "id": "fromDate",
        "name": "From Date",
        "type": "date",
        "value": "2018-12-21T00:00:00+00:00"
    },
    {
        "id": "toDate",
        "name": "To Date",
        "type": "date",
        "value": "2019-01-07T00:00:00+00:00"
    }
  ]
}

Returns:

Status: 200 OK

Despite returning OK it doesn't appear to save the User task's form data:

blank-form

See: https://robferguson.org/blog/2018/12/24/flowable-rest-api-part-1/

@tijsrademakers
Copy link
Contributor

When using the complete task action REST API, it will complete the task and set the variables, but not create a form instance of a submitted form. For that you will need to do another call as well to the Flowable Form Engine REST API:

https://github.com/flowable/flowable-engine/blob/master/modules/flowable-form-rest/src/main/java/org/flowable/form/rest/service/api/form/FormInstanceCollectionResource.java#L139

The Flowable Task application uses the completeTaskWithForm method in the TaskService, but this method is not yet exposed via the REST API. This needs to done in the Task action REST API with another action value like completeWithForm.

@Robinyo
Copy link
Author

Robinyo commented Dec 28, 2018

POST form/form-instances:

curl -H "Content-Type: application/json" -X POST http://admin:test@localhost:8080/flowable-task/form-api/form/form-instances

data-3.json:

{
  "formDefinitionKey": "leave-application-form",
  "processInstanceId": "899b2efe-0af3-11e9-a85e-0242ac110002",
  "variables" :
  {
    "Given Name": "Rob",
    "Family Name": "Ferguson",
    "Employee Number": 123456,
    "From Date": "2018-12-21T00:00:00+00:00",
    "To Date": "2019-01-07T00:00:00+00:00"
  }
}

Returns:

Status: 200 OK

However, if you navigate to the Tasks tab in the Flowable Task app's dashboard it doesn't show the completed task's form data:

screen shot 2018-12-29 at 10 27 42

Is this the expected behaviour?

BTW, the form/form-instances end point is not documented in the OpenAPI docs or in the Forms section of the Flowable docs Users Guide.

In the Form Users Guide form/form-instances the Request body example is incorrect:


   "formDefinitionKey":"simpleForm",
   "taskId":"88",
   "processInstanceId":"66",
   "processDefinitionId":"oneTaskProcess:1:158",
   "businessKey":"myBusinessKey",
   "variables": [
      {
        "name":"input1",
        "value":"test",
      }
   ]
}

For example:

{
  "formDefinitionKey": "leave-application-form",
  "processInstanceId": "899b2efe-0af3-11e9-a85e-0242ac110002",
  "variables" :
  {
    "Given Name": "Rob",
    "Family Name": "Ferguson",
    "Employee Number": 123456,
    "From Date": "2018-12-21T00:00:00+00:00",
    "To Date": "2019-01-07T00:00:00+00:00"
  }
}

See: Flowable-Rest/ Forms API (POST form/form-instances) gives JSON parse error

@tijsrademakers
Copy link
Contributor

In your example post you left out the taskId and processDefinitionId properties, where the taskId property is the most important one because this connects the form instance to the completed task.

Thanks for pointing to the incorrect payload mentioned in the Forms Engine REST API docs, this has been corrected now.

@Robinyo
Copy link
Author

Robinyo commented Dec 30, 2018

See: Flowable examples (includes the example curl scripts, sample JSON payloads and the sample HR App BAR and ZIP files)

GET /runtime/tasks

curl -i 'http://admin:test@localhost:8080/flowable-task/process-api/runtime/tasks'

Returns:

{
    "data": [
        {
            "id": "6e5bc415-0be3-11e9-a85e-0242ac110002",
            "url": "http://localhost:8080/flowable-task/process-api/runtime/tasks/6e5bc415-0be3-11e9-a85e-0242ac110002",
            "owner": null,
            "assignee": "admin",
            "delegationState": null,
            "name": "Fill in a Leave Application Form",
            "description": null,
            "createTime": "2018-12-30T03:31:44.850Z",
            "dueDate": null,
            "priority": 50,
            "suspended": false,
            "taskDefinitionKey": "sid-3BA1F4D1-500F-4766-89BF-519166929F2D",
            "scopeDefinitionId": null,
            "scopeId": null,
            "scopeType": null,
            "tenantId": "",
            "category": null,
            "formKey": "leave-application-form",
            "parentTaskId": null,
            "parentTaskUrl": null,
            "executionId": "6e5bc412-0be3-11e9-a85e-0242ac110002",
            "executionUrl": "http://localhost:8080/flowable-task/process-api/runtime/executions/6e5bc412-0be3-11e9-a85e-0242ac110002",
            "processInstanceId": "6e5bc40f-0be3-11e9-a85e-0242ac110002",
            "processInstanceUrl": "http://localhost:8080/flowable-task/process-api/runtime/process-instances/6e5bc40f-0be3-11e9-a85e-0242ac110002",
            "processDefinitionId": "leave-application-process:1:c5ae6f5e-06f8-11e9-a85e-0242ac110002",
            "processDefinitionUrl": "http://localhost:8080/flowable-task/process-api/repository/process-definitions/leave-application-process:1:c5ae6f5e-06f8-11e9-a85e-0242ac110002",
            "variables": []
        }
    ],
    "total": 1,
    "start": 0,
    "sort": "id",
    "order": "asc",
    "size": 1
}

POST /runtime/tasks

curl -H "Content-Type: application/json" 
     -X POST http://admin:test@localhost:8080/flowable-task/process-api/runtime/tasks/1fae489a-070f-11e9-a85e-0242ac110002
     -d "@data-1.json"

Returns:

Status: 200 OK

POST /form/form-instances

curl -H "Content-Type: application/json" 
     -X POST http://admin:test@localhost:8080/flowable-task/form-api/form/form-instances 
     -d "@data-3.json"

I have updated the POST body (data-3.json) as follows:

{
  "formDefinitionKey": "leave-application-form",
  "processDefinitionId":"leave-application-process:1:c5ae6f5e-06f8-11e9-a85e-0242ac110002",
  "processInstanceId": "6e5bc40f-0be3-11e9-a85e-0242ac110002",
  "taskId": "sid-3BA1F4D1-500F-4766-89BF-519166929F2D",
  "variables" :
  {
    "Given Name": "Rob",
    "Family Name": "Ferguson",
    "Employee Number": 123456,
    "From Date": "2018-12-21T00:00:00+00:00",
    "To Date": "2019-01-07T00:00:00+00:00"
  }
}

Where (using the values returned from GET /runtime/tasks)

formDefinitionKey = formKey
processDefinitionId = processDefinitionId
processInstanceId = processInstanceId
taskId=taskDefinitionKey

Are these correct?

Returns:

Status: 200 OK

As before, if you navigate to the Tasks tab in the Flowable Task app's dashboard it doesn't show the completed task's data in the form.

@tijsrademakers
Copy link
Contributor

tijsrademakers commented Dec 30, 2018

We have added support to get a start and task form in the REST API and allow to start a process instance with a form and complete a task with a form. This should solve the issues mentioned in this issue.

Get process definition start form:

GET /repository/process-definitions/{processDefinitionId}/start-form

Start a process instance with a form

POST /runtime/process-instances
{
 "processDefinitionKey": "testProcess",
 "startFormVariables": [
   {
     "name": "var1",
     "value": "test",
     "type": "string"
   }
  ],
  "outcome": "someOutcome"
}

Get a Task form:

GET /runtime/tasks/{taskId}/form

Complete a Task form:

POST /runtime/tasks/{taskId}
{
 "action": "complete",
 "variables": [
   {
     "name": "var1",
     "value": "test",
     "type": "string"
   }
  ],
  "formDefinitionId": "12345",
  "outcome": "someOutcome"
}

@Robinyo
Copy link
Author

Robinyo commented Dec 30, 2018

As discussed in this post I'm happy to use the Flowable Modeler to model business processes and to create tasks and process instances, however, I'd like to use Flowable's REST API to interact with process instances:

In my initial comments I noted that POST [/runtime/tasks/{taskId} doesn't appear to save the variables in the JSON payload:

{
  "action" : "complete",
  "variables" : [
    {
        "id": "givenName",
        "name": "Given Name",
        "type": "string",
        "value": "Rob"
    },
  
    ...

  ]
}

My understanding that this is the case is based on trying to view the 'completed' task in the Flowable Task App.

As you suggested I then tried to create a form instance (which would mean that the 'completed' task would appear with the variables values populated (i.e., not empty) in the Flowable Task App).

POST /form/form-instances

{
  "formDefinitionKey": "leave-application-form",
  "processDefinitionId":"leave-application-process:1:c5ae6f5e-06f8-11e9-a85e-0242ac110002",
  "processInstanceId": "6e5bc40f-0be3-11e9-a85e-0242ac110002",
  "taskId": "6e5bc40f-0be3-11e9-a85e-0242ac110002",
  "variables" :
  {
    "Given Name": "Rob",
    "Family Name": "Ferguson",
    "Employee Number": 123456,
    "From Date": "2018-12-21T00:00:00+00:00",
    "To Date": "2019-01-07T00:00:00+00:00"
  }
}

Which despite returning 200 (OK) doesn't show the completed task's data in the form:

50530742-bbf40280-0b54-11e9-8b66-89a031377b47

Note: POST form/form-data appears to complete the User task, save the variables in the JSON payload and the 'completed' task appears with the variables values populated (i.e., not empty) in the Flowable Task App:

form-data

@tijsrademakers
Copy link
Contributor

Did you try the new REST API service I mentioned in my previous comment on this issue? The POST to the runtime/tasks/{taskId} does exactly what you are expecting. You only have to provide the formDefinitionId as an additional property in the JSON payload.

@Robinyo
Copy link
Author

Robinyo commented Dec 31, 2018

I'm using the latest flowable/all-in-one Docker image.

The POST to the runtime/tasks/{taskId} does exactly what you are expecting.

POST runtime/tasks

curl -H "Content-Type: application/json" 
     -X POST http://admin:test@localhost:8080/flowable-task/process-api/runtime/tasks/674e5b18-0cab-11e9-a85e-0242ac110002 
     -d "@data-5.json"

You only have to provide the formDefinitionId as an additional property in the JSON payload.

I added the formDefinitionId (formKey) to the payload (data-5.json):

{
  "action" : "complete",
  "formDefinitionId": "leave-application-form",
  "variables" : [
    {
      "id": "givenName",
      "name": "Given Name",
      "type": "string",
      "value": "Rob"
    },
    {
      "id": "familyName",
      "name": "Family Name",
      "type": "string",
      "value": "Ferguson"
    },
    {
      "id": "employeeNumber",
      "name": "Employee Number",
      "type": "integer",
      "value": 123456
    },
    {
      "id": "fromDate",
      "name": "From Date",
      "type": "date",
      "value": "2018-12-21T00:00:00+00:00"
    },
    {
      "id": "toDate",
      "name": "To Date",
      "type": "date",
      "value": "2019-01-07T00:00:00+00:00"
    }
  ]
}

It returns 200 (OK) but the Flowable Task App doesn't show the completed task's variables (i.e., not empty) in the form.

See: Flowable examples (includes the example curl scripts, sample JSON payloads and the sample HR App BAR and ZIP files),

@tijsrademakers
Copy link
Contributor

The changes I mentioned in the issue comment are done on the latest master version, so they are not yet available as part of a Flowable release. There will be a 6.4.1. release coming in the new year.

@Robinyo
Copy link
Author

Robinyo commented Dec 31, 2018

OK, great thanks :)

@xcaptain
Copy link

xcaptain commented Jan 7, 2019

@tijsrademakers I tested the latest source code, GET /runtime/tasks/{taskId}/form works fine for active tasks, but for completed tasks this api returns task not found

@tijsrademakers
Copy link
Contributor

@xcaptain thanks for testing. Yes the runtime endpoint only works active tasks. I'll make sure to add support in the /history/tasks/{taskId}/form REST service as well.

@xcaptain
Copy link

xcaptain commented Jan 8, 2019

@tijsrademakers I'm using

POST /form/form-instance-model/
{
    "taskId": "some task id",
    "formDefinitionKey": "some form def key"
}

to get form data from a task whatever it's active or completed, other fields works fine, but for upload field, the value is empty string, but in the flowable ui task app,

GET flowable-task/app/rest/task-forms/{taskId}

can return the correspond attachment id for the upload field.

Is this a bug or there are any other ways to get the value of a upload type?

@tijsrademakers
Copy link
Contributor

@xcaptain the history REST services have been added now.
Can you explain in a bit more detail how you are handling the upload fields currently? Are you uploading the file right-away when an attachment is added to the upload field like it's done in the Flowable Task app? Or when are you submitting the raw upload content?

@xcaptain
Copy link

xcaptain commented Jan 8, 2019

@tijsrademakers Thank you for the quick update, I tested the latest source, the history task form api returns 404 as follows:
image

As to the upload field, I'm first using the content api to upload a file, as defined in https://github.com/flowable/flowable-engine/blob/master/docs/public-api/references/openapi/content/flowable-oas-content.yaml#L282

POST flowable-task/content-api/content-service/content-items

then use the result content item id as upload field value. Then I use:

GET /content-service/content-items/?taskId=someid

to filter all attachment in the task.

@tijsrademakers
Copy link
Contributor

@xcaptain there are unit tests testing the retrieval of a historic task instance form, so maybe you can do some more debugging/testing to see what is happening?

The DefaultFormFieldHandler handles the submit and retrieval of the content items connected to an upload field. Can you check if a process variable is created with the upload field id? Maybe you can also debug the DefaultFormFieldHandler to see what is happening exactly.

@xcaptain
Copy link

A minor fix related to this issue. #1543

@Robinyo
Copy link
Author

Robinyo commented Jan 9, 2020

Did you try the new REST API service I mentioned in my previous comment on this issue? The POST to the runtime/tasks/{taskId} does exactly what you are expecting. You only have to provide the formDefinitionId as an additional property in the JSON payload.

Yes, (flowable/all-in-one:6.5.0.event-SNAPSHOT).

I used Flowable Task to create a process instance.

Then:

GET  runtime/tasks
GET  runtime/tasks/{taskId}/form
POST runtime/tasks/{taskId}

For example, GET runtime/tasks

curl -H "Content-Type: application/json" \
     -X GET http://flowable-rest:test@localhost:8080/flowable-task/process-api/runtime/tasks

Output:

{
    "data": [
        {
            "id": "36803780-32a0-11ea-85ef-0242ac110004",
            "url": "http://localhost:8080/flowable-task/process-api/runtime/tasks/36803780-32a0-11ea-85ef-0242ac110004",
            "owner": null,
            "assignee": "rob.ferguson",
            "delegationState": null,
            "name": "My First Task",
            "description": "My first Flowable task",
            "createTime": "2020-01-09T05:23:47.875Z",
            "dueDate": null,
            "priority": 50,
            "suspended": false,
            "claimTime": null,
            "taskDefinitionKey": null,
            "scopeDefinitionId": null,
            "scopeId": null,
            "scopeType": null,
            "tenantId": "",
            "category": null,
            "formKey": null,
            "parentTaskId": null,
            "parentTaskUrl": null,
            "executionId": null,
            "executionUrl": null,
            "processInstanceId": null,
            "processInstanceUrl": null,
            "processDefinitionId": null,
            "processDefinitionUrl": null,
            "variables": []
        },
        {
            "id": "40ac7f4b-32b4-11ea-85ef-0242ac110004",
            "url": "http://localhost:8080/flowable-task/process-api/runtime/tasks/40ac7f4b-32b4-11ea-85ef-0242ac110004",
            "owner": null,
            "assignee": "rob.ferguson",
            "delegationState": null,
            "name": "Fill in a Leave Application Form",
            "description": null,
            "createTime": "2020-01-09T07:47:14.877Z",
            "dueDate": null,
            "priority": 50,
            "suspended": false,
            "claimTime": null,
            "taskDefinitionKey": "sid-3BA1F4D1-500F-4766-89BF-519166929F2D",
            "scopeDefinitionId": null,
            "scopeId": null,
            "scopeType": null,
            "tenantId": "",
            "category": null,
            "formKey": "leave-application-form",
            "parentTaskId": null,
            "parentTaskUrl": null,
            "executionId": "40ac5837-32b4-11ea-85ef-0242ac110004",
            "executionUrl": "http://localhost:8080/flowable-task/process-api/runtime/executions/40ac5837-32b4-11ea-85ef-0242ac110004",
            "processInstanceId": "40ac5834-32b4-11ea-85ef-0242ac110004",
            "processInstanceUrl": "http://localhost:8080/flowable-task/process-api/runtime/process-instances/40ac5834-32b4-11ea-85ef-0242ac110004",
            "processDefinitionId": "leave-application-process:1:c0573581-3298-11ea-85ef-0242ac110004",
            "processDefinitionUrl": "http://localhost:8080/flowable-task/process-api/repository/process-definitions/leave-application-process:1:c0573581-3298-11ea-85ef-0242ac110004",
            "variables": []
        }
    ],
    "total": 2,
    "start": 0,
    "sort": "id",
    "order": "asc",
    "size": 2
}

GET runtime/tasks/{formId}/form

curl -H "Content-Type: application/json" \
     -X GET http://flowable-rest:test@localhost:8080/flowable-task/process-api/runtime/tasks/40ac7f4b-32b4-11ea-85ef-0242ac110004/form

Output:

{
    "id": "c064ca14-3298-11ea-85ef-0242ac110004",
    "name": "Leave Application Form",
    "description": null,
    "key": "leave-application-form",
    "version": 1,
    "fields": [
        {
            "fieldType": "FormField",
            "id": "givenName",
            "name": "Given Name",
            "type": "text",
            "value": null,
            "required": true,
            "readOnly": false,
            "overrideId": true,
            "placeholder": "",
            "layout": null
        },
        {
            "fieldType": "FormField",
            "id": "familyName",
            "name": "Family Name",
            "type": "text",
            "value": null,
            "required": true,
            "readOnly": false,
            "overrideId": true,
            "placeholder": null,
            "layout": null
        },
        {
            "fieldType": "FormField",
            "id": "employeeNumber",
            "name": "Employee Number",
            "type": "integer",
            "value": null,
            "required": true,
            "readOnly": false,
            "overrideId": true,
            "placeholder": null,
            "layout": null
        },
        {
            "fieldType": "FormField",
            "id": "fromDate",
            "name": "From Date",
            "type": "date",
            "value": null,
            "required": true,
            "readOnly": false,
            "overrideId": true,
            "placeholder": null,
            "layout": null
        },
        {
            "fieldType": "FormField",
            "id": "toDate",
            "name": "To Date",
            "type": "date",
            "value": null,
            "required": true,
            "readOnly": false,
            "overrideId": true,
            "placeholder": null,
            "layout": null
        }
    ],
    "outcomes": [],
    "outcomeVariableName": null
}

data-7.json:

{
  "action": "complete",
  "assignee": "rob.ferguson",
  "formDefinitionId": "leave-application-form",
  "variables": [
    {
      "id": "employeeNumber",
      "name": "Employee Number",
      "type": "integer",
      "value": 123456
    },
    {
      "id": "givenName",
      "name": "Given Name",
      "type": "string",
      "value": "Rob"
    },
    {
      "id": "familyName",
      "name": "Family Name",
      "type": "string",
      "value": "Ferguson"
    },
    {
      "id": "fromDate",
      "name": "From Date",
      "type": "date",
      "value": "2020-01-07T13:00:00.000Z"
    },
    {
      "id": "toDate",
      "name": "To Date",
      "type": "date",
      "value": "2020-01-16T13:00:00.000Z"
    }
  ],
  "outcome": "completed"
}

POST runtime/tasks

curl -H "Content-Type: application/json" \
     -X POST http://flowable-rest:test@localhost:8080/flowable-task/process-api/runtime/tasks/40ac7f4b-32b4-11ea-85ef-0242ac110004 \
     -d "@data-7.json"

Output:

{
    "message": "Not found",
    "exception": "no deployed form definition found with id 'leave-application-form'"
}

@Robinyo
Copy link
Author

Robinyo commented Jan 9, 2020

See: Flowable examples (includes the example curl scripts, sample JSON payloads and the sample HR App BAR and ZIP files)

@Robinyo
Copy link
Author

Robinyo commented Jan 9, 2020

I checked the Open API Specification V3 for the Process API.

POST runtime/tasks/{taskId}

      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TaskActionRequest'

TaskActionRequest:

    TaskActionRequest:
      type: object
      required:
        - action
      properties:
        action:
          type: string
          example: complete
          description: 'Action to perform: Either complete, claim, delegate or resolve'
        assignee:
          type: string
          example: userWhoClaims/userToDelegateTo
          description: >-
            If action is claim or delegate, you can use this parameter to set
            the assignee associated
        variables:
          type: array
          description: 'If action is complete, you can use this parameter to set variables '
          items:
            $ref: '#/components/schemas/RestVariable'
        transientVariables:
          type: array
          description: >-
            If action is complete, you can use this parameter to set transient
            variables
          items:
            $ref: '#/components/schemas/RestVariable'

If I remove "formDefinitionId" (and "outcome") from the TaskActionRequest the call returns 200 OK.

For example:

before

Completed:

after

However, if you navigate to the Tasks tab in the Flowable Task app's dashboard it doesn't show the completed task's form data:

blank-form

@Robinyo
Copy link
Author

Robinyo commented Jan 9, 2020

Also:

GET runtime/tasks/{formId}/form returns "type": "text"

POST runtime/tasks/{taskId} accepts "type": "string"

Output:

{
    "message": "Bad request",
    "exception": "Converter can only convert strings"
}

@Robinyo
Copy link
Author

Robinyo commented Jan 10, 2020

After a bit more trial and error I got it to work :)

Sample payload:

{
  "action": "complete",
  "assignee": "rob.ferguson",
  "formDefinitionId": "c064ca14-3298-11ea-85ef-0242ac110004",
  "variables": [
    {
      "id": "employeeNumber",
      "name": "employeeNumber",
      "type": "integer",
      "value": 123456
    },
    {
      "id": "givenName",
      "name": "givenName",
      "type": "string",
      "value": "Rob"
    },
    {
      "id": "familyName",
      "name": "familyName",
      "type": "string",
      "value": "Ferguson"
    },
    {
      "id": "fromDate",
      "name": "fromDate",
      "type": "date",
       "value": "2019-12-22T13:00:00.000Z"
    },
    {
      "id": "toDate",
      "name": "toDate",
      "type": "date",
       "value": "2020-01-09T13:00:00.000Z"
    }
  ],
  "outcome": "completed"
}

formDefinitionId is the id attribute returned from GET runtime/tasks/{taskId}/form

Also:

GET runtime/tasks/{formId}/form returns "type": "text"
POST runtime/tasks/{taskId} accepts "type": "string"

Output:

{
    "message": "Bad request",
    "exception": "Converter can only convert strings"
}

And:

GET runtime/tasks/{formId}/form returns:

        {
            "fieldType": "FormField",
            "id": "employeeNumber",
            "name": "Employee Number",
            "type": "integer",
            "value": null,
            "required": true,
            "readOnly": false,
            "overrideId": true,
            "placeholder": null,
            "layout": null
        }

POST runtime/tasks/{taskId} accepts:

    {
      "id": "employeeNumber",
      "name": "employeeNumber",  // "Employee Number"
      "type": "integer",
      "value": 123456
    }

Output:

{
    "message": "Bad request",
    "exception": "Form field employeeNumber is required, but no value was found"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants