All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fivefaces.structureclient.controller.UserFacingApiController Maven / Gradle / Ivy

The newest version!
package com.fivefaces.structureclient.controller;

import com.fivefaces.cloud.file_storage.FileService;
import com.fivefaces.cloud.workflow.WorkflowExecutionResult;
import com.fivefaces.cloud.workflow.WorkflowRepo;
import com.fivefaces.cloud.workflow.WorkflowService;
import com.fivefaces.cloud.workflow.awsonprem.model.WorkflowStructure;
import com.fivefaces.integration.MessageTransmitter;
import com.fivefaces.setting.entity.Setting;
import com.fivefaces.setting.service.SettingService;
import com.fivefaces.structure.query.builder.StructureQuery;
import com.fivefaces.structure.service.StructureJsonMapper;
import com.fivefaces.structure.service.StructureService;
import com.fivefaces.structure.service.model.StructureCreateRequest;
import com.fivefaces.structureclient.controller.exception.ForbiddenAccessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.json.JSONObject;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.fivefaces.structureclient.config.security.SecurityConstants.PATIENT_API_PATH;
import static com.fivefaces.structureclient.config.security.SecurityConstants.UNMANNED_API_PATH;
import static com.fivefaces.structureclient.config.security.SecurityConstants.USER_API_PATH;

@RestController
@RequiredArgsConstructor
@Slf4j
@RequestMapping(value = {USER_API_PATH + "/v1", PATIENT_API_PATH + "/v1", UNMANNED_API_PATH + "/v1"},
        produces = MediaType.APPLICATION_JSON_VALUE)
public class UserFacingApiController extends AbstractStructureController {

    private static final String FILE_SERVICE_DESTINATION = "File Service File Destination";
    private final WorkflowRepo workflowRepo;
    private final WorkflowService workflowService;
    private final FileService fileService;
    private final SettingService settingService;
    private final StructureService structureService;
    private final StructureJsonMapper structureJsonMapper;
    private final MessageTransmitter messageTransmitter;

    @PostMapping("/query")
    @ResponseBody
    public ResponseEntity>> handleQuery(@RequestBody final Map query) {
        log.info("/query\n" + query);
        return ResponseEntity.ok(query(StructureQuery.fromGenerics(query).build()));
    }

    @PostMapping("/count")
    @ResponseBody
    public ResponseEntity handleCount(@RequestBody final Map query) {
        log.info("/count\n" + query);
        return ResponseEntity.ok(count(StructureQuery.fromGenerics(query).build()));
    }

    @PostMapping("/namedQuery")
    @ResponseBody
    public ResponseEntity>> handleNamedQuery(@RequestBody final Map input) {
        log.info("/namedQuery\n" + new JSONObject(input));
        Setting sqlQuery = settingService.getSettingByName("NamedQuery " + input.get("queryName"));
        return ResponseEntity.ok(namedQuery(sqlQuery.getValue(), (Map) input.get("params")));
    }

    @PostMapping("/queries")
    @ResponseBody
    public ResponseEntity>>> handleQueries(@RequestBody final Map queries) {
        Map>> results = queries(queries);
        return ResponseEntity.ok(results);
    }

    @PostMapping("/query/file")
    @ResponseBody
    public ResponseEntity>> handleFileQuery(@RequestBody final Map query) {
        log.info("/query\n" + query);
        List> queryResult = query(StructureQuery.fromGenerics(query).build());
        queryResult.forEach(this::addFileLink);
        return ResponseEntity.ok(queryResult);
    }

    @PostMapping(value = "/instantiateWorkflowMultipart", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    @ResponseBody
    public ResponseEntity instantiateWorkflowMultipart(Authentication authentication,
                                                                                @RequestBody final Map payload,
                                                                                @RequestParam(required = false) MultipartFile file) throws IOException {
        log.info("/instantiateWorkflowMultipart\n" + payload);
        WorkflowStructure workflow = getAndValidateWorkflowForUser(authentication, payload);
        addAttachment(payload, file);
        WorkflowExecutionResult result = executeNowOrLater(payload, workflow, false);
        return ResponseEntity.ok(result);
    }

    @PostMapping("/instantiateSyncWorkflow")
    @ResponseBody
    public ResponseEntity instantiateSyncWorkflow(Authentication authentication,
                                                                           @RequestBody final Map payload) {
        log.info("/instantiateSyncWorkflow\n" + payload);
        WorkflowStructure workflow = getAndValidateWorkflowForUser(authentication, payload);
        WorkflowExecutionResult result = executeNowOrLater(payload, workflow, true);
        return ResponseEntity.ok(result);
    }

    @PostMapping("/instantiateWorkflow")
    @ResponseBody
    public ResponseEntity instantiateWorkflow(Authentication authentication,
                                                                       @RequestBody final Map payload) {
        log.info("/instantiateWorkflow\n" + payload);
        WorkflowStructure workflow = getAndValidateWorkflowForUser(authentication, payload);
        WorkflowExecutionResult result = executeNowOrLater(payload, workflow, false);
        return ResponseEntity.ok(result);
    }

    @PostMapping("/workflowExecutionStatus")
    @ResponseBody
    public ResponseEntity instantiateWorkflow(@RequestBody final Map payload) {
        log.info("/workflowExecutionStatus\n" + payload);
        String executionId = (String) payload.get("executionId");
        WorkflowExecutionResult result = workflowService.getExecutionResult(executionId);
        if ("FAILED".equals(result.getStatus())) {
            throw new WorkflowFailedException("Workflow failed", result);
        }
        return ResponseEntity.ok(result);
    }


    @PostMapping("/getQueueWithService")
    @ResponseBody
    public ResponseEntity handleGetQueueWithService(@RequestBody final String jsonInput) {
        final List jsonValues = geQueueWithService(jsonInput);
        return ResponseEntity.ok(jsonValues.get(0).toString());
    }

    @PostMapping("/transmit")
    @ResponseBody
    public ResponseEntity transmitMessage(@RequestBody final String payload) {
        JSONObject jsonObject = new JSONObject(payload);
        String responseBody;
        try {
            responseBody = messageTransmitter.transmitMessage(jsonObject);
            return ResponseEntity.ok(responseBody);
        } catch (Exception e) {
            return ResponseEntity.badRequest().build();
        }
    }

    private void addAttachment(Map payload, MultipartFile file) throws IOException {
        if (file == null) {
            return;
        }
        Map query = (Map) payload.get("query");
        Map identifiers = (Map) query.get("identifiers");
        if (!identifiers.containsKey("attachments")) {
            identifiers.put("attachments", new ArrayList<>());
        }
        List> attachments = (List>) identifiers.get("attachments");
        attachments.add(createAttachmentForFile(file));
    }

    private void addAuthorization(Map json, Authentication authentication) {
        Map query = (Map) json.get("query");
        query.put("authorization", authentication.getPrincipal());
    }

    private Map createAttachmentForFile(MultipartFile file) throws IOException {
        Map attachment = new HashMap<>();
        String fileDestination = settingService.getSettingByName("File Service File Destination").getValue();
        String fullFilePath = fileService.saveFile(fileDestination, file.getOriginalFilename(), file.getBytes());
        attachment.put("type", file.getContentType());
        attachment.put("canonicalFilePath", fullFilePath);
        return attachment;
    }

    private WorkflowExecutionResult delayExecution(final Map query) {
        StructureCreateRequest request = new StructureCreateRequest();
        request.setUsername("WORKFLOW_DELAY");
        request.setType("delayedWorkflow");
        request.setQuery(query);
        try {
            structureService.create(request);
        } catch (Exception e) {
            throw new WorkflowFailedException("Could not delay workflow execution", new WorkflowExecutionResult(null, "FAILED", null, null));
        }
        return new WorkflowExecutionResult(null, "PENDING", null, null);
    }

    private void addFileLink(Map q) {
        String link = "";
        if (q.get("attachments") != null) {
            List> attachments = (List>) q.get("attachments");
            Map attachment = attachments.get(0);
            if (attachment != null) {
                String fileKey = attachment.get("canonicalFilePath");
                link = getFileUrl(fileKey);
            }
        }
        q.put("link", link);
    }

    private String getFileUrl(String fileKey) {
        String fileDestination = settingService.getSettingByName(FILE_SERVICE_DESTINATION).getValue();
        return fileService.getFileUrl(fileDestination, fileKey);
    }

    private WorkflowExecutionResult executeNowOrLater(Map payload, WorkflowStructure workflow, boolean sync) {
        if (payload.containsKey("executeAtUTC")) {
            return delayExecution(payload);
        } else {
            WorkflowExecutionResult result = executeNow(payload, workflow, sync);
            if ("FAILED".equals(result.getStatus())) {
                throw new WorkflowFailedException("Workflow " + payload.get("workflow") + " failed", result);
            }
            return result;
        }
    }

    private WorkflowExecutionResult executeNow(Map payload, WorkflowStructure workflow, boolean sync) {
        String input = structureJsonMapper.write(payload);
        if (sync) {
            return workflowService.instantiateSyncWorkflow(workflow, input);
        } else {
            return workflowService.instantiateWorkflow(workflow, input);
        }
    }

    private WorkflowStructure getAndValidateWorkflowForUser(Authentication authentication, Map payload) {
        String workflowName = (String) payload.get("workflow");
        WorkflowStructure workflow = workflowRepo.findWorkflowByName(workflowName);
        validateUserForWorkflow(authentication, workflow);
        addAuthorization(payload, authentication);
        return workflow;
    }

    private void validateUserForWorkflow(Authentication authentication, WorkflowStructure workflow) {
        if (CollectionUtils.isEmpty(workflow.getAllowedRoles())) {
            return;
        }
        if (!hasAnyRole(authentication, workflow.getAllowedRoles())) {
            throw new ForbiddenAccessException("You don't have authorization to start workflow " + workflow.getName());
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy