com.xlrit.gears.server.graphql.TaskResolver Maven / Gradle / Ivy
The newest version!
package com.xlrit.gears.server.graphql;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import com.xlrit.gears.base.choice.Choice;
import com.xlrit.gears.base.choice.Choices;
import com.xlrit.gears.base.util.Range;
import com.xlrit.gears.engine.facade.EngineFacade;
import com.xlrit.gears.engine.facade.InProgress;
import com.xlrit.gears.engine.flowable.CustomTaskListQuery;
import com.xlrit.gears.engine.security.AuthManager;
import com.fasterxml.jackson.databind.JsonNode;
import graphql.schema.DataFetchingEnvironment;
import lombok.RequiredArgsConstructor;
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
import org.flowable.common.engine.impl.service.CommonEngineServiceImpl;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.service.impl.TaskQueryProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.MutationMapping;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.multipart.MultipartFile;
import static com.xlrit.gears.engine.util.EngineUtils.requireFound;
@Controller
@RequiredArgsConstructor
public class TaskResolver {
private static final Logger LOG = LoggerFactory.getLogger(TaskResolver.class);
private final TaskService taskService;
private final RuntimeService runtimeService;
private final AuthManager authManager;
private final EngineFacade engineFacade;
// === queries === //
@PreAuthorize("isAuthenticated()")
@QueryMapping
public Task task(@Argument String id, DataFetchingEnvironment env) {
TaskQuery query = taskService.createTaskQuery().taskId(id);
if (env.getSelectionSet().contains("error")) {
query.includeTaskLocalVariables();
}
return query.singleResult();
}
@QueryMapping
public Choice choice(@Argument String taskId, @Argument String processDefinitionId, @Argument String path, @Argument String value, @Argument JsonNode values) {
LOG.info("Returning choice for taskId={}, processDefinitionId={}, path={}, value={}, values={}", taskId, processDefinitionId, path, value, values);
Choices choices = engineFacade.getChoices(taskId, processDefinitionId, path, values);
return choices == null ? null : choices.find(value).orElse(null);
}
@QueryMapping
public List extends Choice> choices(@Argument String taskId, @Argument String processDefinitionId, @Argument String path, @Argument String filter, @Argument Range range, @Argument JsonNode values) {
LOG.info("Returning choices for taskId={}, processDefinitionId={}, path={}, filter={}, range={}, values={}", taskId, processDefinitionId, path, filter, range, values);
Choices choices = engineFacade.getChoices(taskId, processDefinitionId, path, values);
return choices == null ? Collections.emptyList() : choices.items(filter, range).collect(Collectors.toList());
}
@PreAuthorize("hasRole('admin')")
@QueryMapping
public List allTasks(@Argument String filter, @Argument Range range) {
return listTasks(filter, range, query -> {});
}
@QueryMapping
public long allTasksCount(@Argument String filter) {
if (!authManager.isAdmin()) return -1L;
return countTasks(filter, query -> {});
}
@QueryMapping
public List assignedTasks(@Argument String filter, @Argument Range range) {
String currentUserId = authManager.getCurrentUserId();
if (currentUserId == null) return Collections.emptyList();
return listTasks(filter, range, query -> query.assignee(currentUserId));
}
@QueryMapping
public long assignedTasksCount(@Argument String filter) {
String currentUserId = authManager.getCurrentUserId();
if (currentUserId == null) return 0L;
return countTasks(filter, query -> query.assignee(currentUserId));
}
@QueryMapping
public List groupTasks(@Argument String filter, @Argument Range range) {
Set currentUserRoleNames = authManager.getCurrentUserRoleNames();
if (currentUserRoleNames == null || currentUserRoleNames.isEmpty()) return Collections.emptyList();
return listTasks(filter, range, query -> query.candidateGroups(currentUserRoleNames).assigned(false));
}
@QueryMapping
public long groupTasksCount(@Argument String filter) {
Set currentUserRoleNames = authManager.getCurrentUserRoleNames();
if (currentUserRoleNames == null || currentUserRoleNames.isEmpty()) return 0L;
return countTasks(filter, query -> query.candidateGroups(currentUserRoleNames).assigned(false));
}
@QueryMapping
public List transferableTasks(@Argument String filter, @Argument Range range) {
String currentUserId = authManager.getCurrentUserId();
Set currentUserRoleNames = authManager.getCurrentUserRoleNames();
if (currentUserId == null || currentUserRoleNames == null || currentUserRoleNames.isEmpty()) return Collections.emptyList();
return listTasks(filter, range, query -> query.candidateGroups(currentUserRoleNames).assigneeNot(currentUserId));
}
@QueryMapping
public long transferableTasksCount(@Argument String filter) {
String currentUserId = authManager.getCurrentUserId();
Set currentUserRoleNames = authManager.getCurrentUserRoleNames();
if (currentUserId == null || currentUserRoleNames == null || currentUserRoleNames.isEmpty()) return 0L;
return countTasks(filter, query -> query.candidateGroups(currentUserRoleNames).assigneeNot(currentUserId));
}
// === mutations === //
@PreAuthorize("isAuthenticated()")
@MutationMapping
public boolean claimTask(@Argument("id") String taskId) {
Objects.requireNonNull(taskId, "taskId must not be null");
engineFacade.claimTask(taskId);
return true;
}
@PreAuthorize("isAuthenticated()")
@MutationMapping
public boolean transferTask(@Argument("id") String taskId, @Argument("currentAssignee") String currentAssignee) {
Objects.requireNonNull(taskId, "taskId must not be null");
Objects.requireNonNull(currentAssignee, "currentAssignee must not be null");
engineFacade.transferTask(taskId, currentAssignee);
return true;
}
@PreAuthorize("isAuthenticated()")
@MutationMapping
public boolean saveTask(@Argument("id") String taskId, @Argument("values") JsonNode formValues, @Argument List files) {
Objects.requireNonNull(taskId, "taskId must not be null");
LOG.info("saveTask: id={}, values={}", taskId, formValues);
if (files != null && !files.isEmpty()) {
LOG.info("saveTask: received files");
for (MultipartFile file : files) {
LOG.info("- name={}, filename={}, type={}", file.getName(), file.getOriginalFilename(), file.getContentType());
}
}
engineFacade.saveTask(taskId, formValues, files);
return true;
}
/** GraphQL type is SubmitResult aka SubmitInProgress | ProcessInstance | ProcessInstanceEnded | InputErrors */
@PreAuthorize("isAuthenticated()")
@MutationMapping
public Object submitTask(@Argument String deploymentId, @Argument("id") String taskId, @Argument JsonNode values, @Argument List files, @Argument Long timeoutMillis) {
Objects.requireNonNull(taskId, "taskId must not be null");
if (timeoutMillis == null) timeoutMillis = Long.MAX_VALUE;
if (files != null && !files.isEmpty()) {
LOG.info("submitTask: received files");
for (MultipartFile file : files) {
LOG.info("- name={}, filename={}, type={}", file.getName(), file.getOriginalFilename(), file.getContentType());
}
}
Future