content: /*
   * Copyright 2017-2025 Hyland Software, Inc. and its affiliates.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.activiti.cloud.starter.tests.helper;
  
  import static org.assertj.core.api.Assertions.assertThat;
  
  import java.util.List;
  import java.util.Map;
  import org.activiti.api.task.model.Task;
  import org.activiti.api.task.model.builders.TaskPayloadBuilder;
  import org.activiti.api.task.model.payloads.AssignTaskPayload;
  import org.activiti.api.task.model.payloads.CandidateGroupsPayload;
  import org.activiti.api.task.model.payloads.CandidateUsersPayload;
  import org.activiti.api.task.model.payloads.CompleteTaskPayload;
  import org.activiti.api.task.model.payloads.CreateTaskPayload;
  import org.activiti.api.task.model.payloads.CreateTaskVariablePayload;
  import org.activiti.api.task.model.payloads.SaveTaskPayload;
  import org.activiti.api.task.model.payloads.UpdateTaskPayload;
  import org.activiti.api.task.model.payloads.UpdateTaskVariablePayload;
  import org.activiti.cloud.api.model.shared.CloudVariableInstance;
  import org.activiti.cloud.api.process.model.impl.CandidateGroup;
  import org.activiti.cloud.api.process.model.impl.CandidateUser;
  import org.activiti.cloud.api.task.model.CloudTask;
  import org.springframework.boot.test.context.TestComponent;
  import org.springframework.boot.test.web.client.TestRestTemplate;
  import org.springframework.core.ParameterizedTypeReference;
  import org.springframework.hateoas.CollectionModel;
  import org.springframework.hateoas.EntityModel;
  import org.springframework.hateoas.PagedModel;
  import org.springframework.http.HttpEntity;
  import org.springframework.http.HttpMethod;
  import org.springframework.http.HttpStatus;
  import org.springframework.http.ResponseEntity;
  import org.springframework.util.LinkedMultiValueMap;
  
  @TestComponent
  public class TaskRestTemplate {
  
      private static final String TASK_RELATIVE_URL = "/v1/tasks";
      private static final String ADMIN_TASK_RELATIVE_URL = "/admin/v1/tasks";
      private static final LinkedMultiValueMap<String, String> CONTENT_TYPE_HEADER = new LinkedMultiValueMap<>(
          Map.of("Content-type", List.of("application/json"))
      );
  
      private static final ParameterizedTypeReference<CloudTask> TASK_RESPONSE_TYPE = new ParameterizedTypeReference<CloudTask>() {};
      private static final ParameterizedTypeReference<PagedModel<CloudTask>> PAGED_TASKS_RESPONSE_TYPE = new ParameterizedTypeReference<PagedModel<CloudTask>>() {};
      private static final ParameterizedTypeReference<CollectionModel<EntityModel<CandidateUser>>> CANDIDATE_USERS_RESPONSE_TYPE = new ParameterizedTypeReference<CollectionModel<EntityModel<CandidateUser>>>() {};
      private static final ParameterizedTypeReference<CollectionModel<EntityModel<CandidateGroup>>> CANDIDATES_GROUPS_RESPONSE_TYPE = new ParameterizedTypeReference<CollectionModel<EntityModel<CandidateGroup>>>() {};
      private static final ParameterizedTypeReference<Void> VOID_RESPONSE_TYPE = new ParameterizedTypeReference<Void>() {};
  
      private TestRestTemplate testRestTemplate;
  
      public TaskRestTemplate(TestRestTemplate testRestTemplate) {
          this.testRestTemplate = testRestTemplate;
      }
  
      public ResponseEntity<CloudTask> complete(Task task) {
          return complete(task, null);
      }
  
      public ResponseEntity<CloudTask> adminComplete(Task task) {
          return adminComplete(task, null);
      }
  
      public ResponseEntity<CloudTask> complete(Task task, CompleteTaskPayload completeTaskPayload) {
          return complete(task, TASK_RELATIVE_URL, completeTaskPayload);
      }
  
      public ResponseEntity<CloudTask> adminComplete(Task task, CompleteTaskPayload completeTaskPayload) {
          return complete(task, ADMIN_TASK_RELATIVE_URL, completeTaskPayload);
      }
  
      private ResponseEntity<CloudTask> complete(Task task, String baseURL, CompleteTaskPayload completeTaskPayload) {
          ResponseEntity<CloudTask> responseEntity = testRestTemplate.exchange(
              baseURL.concat("/").concat(task.getId()).concat("/complete"),
              HttpMethod.POST,
              completeTaskPayload != null
                  ? new HttpEntity<>(completeTaskPayload, CONTENT_TYPE_HEADER)
                  : new HttpEntity<>(CONTENT_TYPE_HEADER),
              TASK_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode().value()).isEqualTo(HttpStatus.OK.value());
          return responseEntity;
      }
  
      public ResponseEntity<CloudTask> delete(Task task) {
          return delete(task, TASK_RELATIVE_URL);
      }
  
      public ResponseEntity<CloudTask> adminDelete(Task task) {
          return delete(task, ADMIN_TASK_RELATIVE_URL);
      }
  
      private ResponseEntity<CloudTask> delete(Task task, String taskVarRelativeUrl) {
          ResponseEntity<CloudTask> responseEntity = testRestTemplate.exchange(
              taskVarRelativeUrl.concat("/").concat(task.getId()),
              HttpMethod.DELETE,
              null,
              TASK_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode().value()).isEqualTo(HttpStatus.OK.value());
          return responseEntity;
      }
  
      public ResponseEntity<CloudTask> claim(Task task) {
          return claim(task.getId());
      }
  
      public ResponseEntity<CloudTask> claim(String taskId) {
          ResponseEntity<CloudTask> responseEntity = testRestTemplate.exchange(
              TASK_RELATIVE_URL.concat("/").concat(taskId).concat("/claim"),
              HttpMethod.POST,
              null,
              TASK_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public ResponseEntity<CloudTask> release(Task task) {
          return release(task.getId());
      }
  
      public ResponseEntity<CloudTask> release(String taskId) {
          ResponseEntity<CloudTask> responseEntity = testRestTemplate.exchange(
              TASK_RELATIVE_URL.concat("/").concat(taskId).concat("/release"),
              HttpMethod.POST,
              null,
              TASK_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public ResponseEntity<CloudTask> adminAssignTask(AssignTaskPayload assignTask) {
          return testRestTemplate.exchange(
              ADMIN_TASK_RELATIVE_URL.concat("/").concat(assignTask.getTaskId()).concat("/assign"),
              HttpMethod.POST,
              new HttpEntity<>(assignTask),
              TASK_RESPONSE_TYPE
          );
      }
  
      public ResponseEntity<CollectionModel<EntityModel<CandidateUser>>> getUserCandidates(String taskId) {
          ResponseEntity<CollectionModel<EntityModel<CandidateUser>>> responseEntity = testRestTemplate.exchange(
              TASK_RELATIVE_URL.concat("/").concat(taskId).concat("/candidate-users"),
              HttpMethod.GET,
              null,
              CANDIDATE_USERS_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public ResponseEntity<Void> addUserCandidates(CandidateUsersPayload candidateUsers) {
          ResponseEntity<Void> responseEntity = testRestTemplate.exchange(
              TASK_RELATIVE_URL.concat("/").concat(candidateUsers.getTaskId()).concat("/candidate-users"),
              HttpMethod.POST,
              new HttpEntity<>(candidateUsers),
              VOID_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public ResponseEntity<Void> deleteUserCandidates(CandidateUsersPayload candidateUsers) {
          ResponseEntity<Void> responseEntity = testRestTemplate.exchange(
              TASK_RELATIVE_URL.concat("/").concat(candidateUsers.getTaskId()).concat("/candidate-users"),
              HttpMethod.DELETE,
              new HttpEntity<>(candidateUsers),
              VOID_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public ResponseEntity<CollectionModel<EntityModel<CandidateGroup>>> getGroupCandidates(String taskId) {
          ResponseEntity<CollectionModel<EntityModel<CandidateGroup>>> responseEntity = testRestTemplate.exchange(
              TASK_RELATIVE_URL.concat("/").concat(taskId).concat("/candidate-groups"),
              HttpMethod.GET,
              null,
              CANDIDATES_GROUPS_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public ResponseEntity<Void> addGroupCandidates(CandidateGroupsPayload candidateGroups) {
          ResponseEntity<Void> responseEntity = testRestTemplate.exchange(
              TASK_RELATIVE_URL.concat("/").concat(candidateGroups.getTaskId()).concat("/candidate-groups"),
              HttpMethod.POST,
              new HttpEntity<>(candidateGroups),
              VOID_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public ResponseEntity<Void> deleteGroupCandidates(CandidateGroupsPayload candidateGroups) {
          ResponseEntity<Void> responseEntity = testRestTemplate.exchange(
              TASK_RELATIVE_URL.concat("/").concat(candidateGroups.getTaskId()).concat("/candidate-groups"),
              HttpMethod.DELETE,
              new HttpEntity<>(candidateGroups),
              VOID_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public PagedModel<CloudTask> getSubTasks(CloudTask parentTask) {
          ResponseEntity<PagedModel<CloudTask>> responseEntity = testRestTemplate.exchange(
              TASK_RELATIVE_URL.concat("/").concat(parentTask.getId()).concat("/subtasks"),
              HttpMethod.GET,
              null,
              new ParameterizedTypeReference<PagedModel<CloudTask>>() {}
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity.getBody();
      }
  
      public CloudTask createTask(CreateTaskPayload createTask) {
          return createTask(new HttpEntity<>(createTask, CONTENT_TYPE_HEADER));
      }
  
      private CloudTask createTask(HttpEntity<?> requestEntity) {
          ResponseEntity<CloudTask> responseEntity = testRestTemplate.exchange(
              TASK_RELATIVE_URL,
              HttpMethod.POST,
              requestEntity,
              TASK_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity.getBody();
      }
  
      public CloudTask createTask(Map<String, Object> jsonAsMap) {
          return createTask(new HttpEntity<>(jsonAsMap, CONTENT_TYPE_HEADER));
      }
  
      public ResponseEntity<PagedModel<CloudTask>> getTasks() {
          return getTasks(TASK_RELATIVE_URL);
      }
  
      public ResponseEntity<PagedModel<CloudTask>> adminGetTasks() {
          return getTasks(ADMIN_TASK_RELATIVE_URL);
      }
  
      private ResponseEntity<PagedModel<CloudTask>> getTasks(String baseURL) {
          return testRestTemplate.exchange(baseURL, HttpMethod.GET, null, PAGED_TASKS_RESPONSE_TYPE);
      }
  
      public ResponseEntity<CloudTask> getTask(String taskId) {
          return getTask(taskId, TASK_RELATIVE_URL);
      }
  
      public ResponseEntity<CloudTask> adminGetTask(String taskId) {
          return getTask(taskId, ADMIN_TASK_RELATIVE_URL);
      }
  
      private ResponseEntity<CloudTask> getTask(String taskId, String baseURL) {
          ResponseEntity<CloudTask> responseEntity = testRestTemplate.exchange(
              baseURL.concat("/").concat(taskId),
              HttpMethod.GET,
              null,
              TASK_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public void updateTask(UpdateTaskPayload updateTask) {
          updateTask(updateTask, TASK_RELATIVE_URL);
      }
  
      public void adminUpdateTask(UpdateTaskPayload updateTask) {
          updateTask(updateTask, ADMIN_TASK_RELATIVE_URL);
      }
  
      private void updateTask(UpdateTaskPayload updateTask, String baseURL) {
          updateTask(updateTask.getTaskId(), updateTask, baseURL);
      }
  
      public void updateTask(String taskId, UpdateTaskPayload updateTask) {
          updateTask(taskId, updateTask, TASK_RELATIVE_URL);
      }
  
      public void adminUpdateTask(String taskId, UpdateTaskPayload updateTask) {
          updateTask(taskId, updateTask, ADMIN_TASK_RELATIVE_URL);
      }
  
      private void updateTask(String taskId, UpdateTaskPayload updateTask, String baseURL) {
          ResponseEntity<CloudTask> responseEntity = testRestTemplate.exchange(
              baseURL.concat("/").concat(taskId),
              HttpMethod.PUT,
              new HttpEntity<>(updateTask, CONTENT_TYPE_HEADER),
              TASK_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
      }
  
      public ResponseEntity<Void> createVariable(String taskId, String name, Object value) {
          CreateTaskVariablePayload createTaskVariablePayload = TaskPayloadBuilder
              .createVariable()
              .withVariable(name, value)
              .build();
  
          HttpEntity<CreateTaskVariablePayload> requestEntity = new HttpEntity<>(
              createTaskVariablePayload,
              CONTENT_TYPE_HEADER
          );
          ResponseEntity<Void> responseEntity = testRestTemplate.exchange(
              TaskRestTemplate.TASK_RELATIVE_URL.concat("/").concat(taskId).concat("/variables"),
              HttpMethod.POST,
              requestEntity,
              VOID_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public ResponseEntity<Void> updateVariable(String taskId, String name, Object value) {
          UpdateTaskVariablePayload updateTaskVariablePayload = TaskPayloadBuilder
              .updateVariable()
              .withVariable(name, value)
              .build();
  
          HttpEntity<UpdateTaskVariablePayload> requestEntity = new HttpEntity<>(
              updateTaskVariablePayload,
              CONTENT_TYPE_HEADER
          );
          ResponseEntity<Void> responseEntity = testRestTemplate.exchange(
              TaskRestTemplate.TASK_RELATIVE_URL.concat("/").concat(taskId).concat("/variables/{variableName}"),
              HttpMethod.PUT,
              requestEntity,
              VOID_RESPONSE_TYPE,
              name
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public ResponseEntity<CollectionModel<CloudVariableInstance>> getVariables(String taskId) {
          ResponseEntity<CollectionModel<CloudVariableInstance>> responseEntity = testRestTemplate.exchange(
              TaskRestTemplate.TASK_RELATIVE_URL.concat("/").concat(taskId).concat("/variables"),
              HttpMethod.GET,
              new HttpEntity<>(CONTENT_TYPE_HEADER),
              new ParameterizedTypeReference<CollectionModel<CloudVariableInstance>>() {}
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public ResponseEntity<Void> adminCreateVariable(String taskId, String name, Object value) {
          CreateTaskVariablePayload createTaskVariablePayload = TaskPayloadBuilder
              .createVariable()
              .withVariable(name, value)
              .build();
  
          HttpEntity<CreateTaskVariablePayload> requestEntity = new HttpEntity<>(createTaskVariablePayload, null);
          ResponseEntity<Void> responseEntity = testRestTemplate.exchange(
              TaskRestTemplate.ADMIN_TASK_RELATIVE_URL.concat("/").concat(taskId).concat("/variables"),
              HttpMethod.POST,
              requestEntity,
              VOID_RESPONSE_TYPE
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public ResponseEntity<Void> adminUpdateVariable(String taskId, String name, Object value) {
          UpdateTaskVariablePayload updateTaskVariablePayload = TaskPayloadBuilder
              .updateVariable()
              .withVariable(name, value)
              .build();
  
          HttpEntity<UpdateTaskVariablePayload> requestEntity = new HttpEntity<>(updateTaskVariablePayload, null);
          ResponseEntity<Void> responseEntity = testRestTemplate.exchange(
              TaskRestTemplate.ADMIN_TASK_RELATIVE_URL.concat("/").concat(taskId).concat("/variables/{variableName}"),
              HttpMethod.PUT,
              requestEntity,
              VOID_RESPONSE_TYPE,
              name
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public ResponseEntity<CollectionModel<CloudVariableInstance>> adminGetVariables(String taskId) {
          ResponseEntity<CollectionModel<CloudVariableInstance>> responseEntity = testRestTemplate.exchange(
              TaskRestTemplate.ADMIN_TASK_RELATIVE_URL.concat("/").concat(taskId).concat("/variables"),
              HttpMethod.GET,
              null,
              new ParameterizedTypeReference<CollectionModel<CloudVariableInstance>>() {}
          );
          assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
          return responseEntity;
      }
  
      public ResponseEntity<Void> save(Task task, SaveTaskPayload saveTaskPayload) {
          ResponseEntity<Void> responseEntity = testRestTemplate.exchange(
              TASK_RELATIVE_URL.concat("/").concat(task.getId()).concat("/save"),
              HttpMethod.POST,
              saveTaskPayload != null
                  ? new HttpEntity<>(saveTaskPayload, CONTENT_TYPE_HEADER)
                  : new HttpEntity<>(CONTENT_TYPE_HEADER),
              VOID_RESPONSE_TYPE
          );
  
          return responseEntity;
      }
  
      public ResponseEntity<CloudTask> userAssignTask(AssignTaskPayload assignTask) {
          ResponseEntity<CloudTask> responseEntity = testRestTemplate.exchange(
              TASK_RELATIVE_URL.concat("/").concat(assignTask.getTaskId()).concat("/assign"),
              HttpMethod.POST,
              new HttpEntity<>(assignTask, CONTENT_TYPE_HEADER),
              TASK_RESPONSE_TYPE
          );
          return responseEntity;
      }
  }
  