CMSgov/dpc-app

View on GitHub
dpc-consent/src/main/java/gov/cms/dpc/consent/resources/ConsentResource.java

Summary

Maintainability
A
25 mins
Test Coverage
package gov.cms.dpc.consent.resources;

import com.codahale.metrics.annotation.ExceptionMetered;
import com.codahale.metrics.annotation.Timed;
import com.google.common.base.Splitter;
import com.google.inject.name.Named;
import gov.cms.dpc.common.consent.entities.ConsentEntity;
import gov.cms.dpc.consent.jdbi.ConsentDAO;
import gov.cms.dpc.fhir.DPCIdentifierSystem;
import gov.cms.dpc.fhir.FHIRExtractors;
import gov.cms.dpc.fhir.annotations.FHIR;
import gov.cms.dpc.fhir.converters.entities.ConsentEntityConverter;
import io.dropwizard.hibernate.UnitOfWork;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.eclipse.jetty.http.HttpStatus;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Consent;
import org.hl7.fhir.dstu3.model.Identifier;

import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

@Path("v1/Consent")
public class ConsentResource {

    private final ConsentDAO dao;
    private final String fhirReferenceURL;

    @Inject
    ConsentResource(ConsentDAO dao, @Named("fhirReferenceURL") String fhirReferenceURL) {
        this.dao = dao;
        this.fhirReferenceURL = fhirReferenceURL;
    }

    @POST
    @FHIR
    @UnitOfWork
    @ApiOperation(value = "Create a Consent resource")
    @ApiResponses(value = { @ApiResponse(code = 201, message = "Consent resource was created"),
            @ApiResponse(code = 400, message = "Consent resource was not created due to bad request") })
    public Response create(@ApiParam(value = "Consent resource") Consent consent) {
        ConsentEntity entity = ConsentEntityConverter.fromFhir(consent);
        entity = dao.persistConsent(entity);
        Consent result = ConsentEntityConverter.toFhir(entity, fhirReferenceURL);
        return Response.status(Response.Status.CREATED).entity(result).build();
    }

    @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
    @GET
    @FHIR
    @Timed
    @ExceptionMetered
    @UnitOfWork
    @ApiOperation(value = "Search for Consent Entries", notes = "Search for Consent records. " +
            "<p>Must provide ONE OF Consent ID as an _id or identifier, or a patient MBI or HICN to search for.", response = Bundle.class)
    @ApiResponses(@ApiResponse(code = 400, message = "Must provide Consent or Patient id"))
    public List<Consent> search(
            @ApiParam(value = "Consent resource _id") @QueryParam(Consent.SP_RES_ID) Optional<UUID> id,
            @ApiParam(value = "Consent resource identifier") @QueryParam(Consent.SP_IDENTIFIER) Optional<UUID> identifier,
            @ApiParam(value = "Patient Identifier") @QueryParam(Consent.SP_PATIENT) Optional<String> patientId) {

        List<ConsentEntity> entities = new ArrayList<>();

        // Priority order for processing params. If multiple params are passed, we only pay attention to one
        if (id.isPresent()) {
            final Optional<ConsentEntity> consentEntity = this.dao.getConsent(id.get());
            entities = consentEntity.map(List::of).orElse(entities);

        } else if (identifier.isPresent()) {
            // not sure we should support this
            final Optional<ConsentEntity> consentEntity = this.dao.getConsent(identifier.get());
            entities = consentEntity.map(List::of).orElse(entities);

        } else if (patientId.isPresent()) {
            for (String pId : Splitter.on(',').split(patientId.get())) {
                final Identifier patientIdentifier = FHIRExtractors.parseIDFromQueryParam(pId);
                entities.addAll(getEntitiesByPatient(patientIdentifier));
            }

        } else {
            throw new WebApplicationException("Must have some form of Consent Resource ID or Patient ID", Response.Status.BAD_REQUEST);
        }

        return entities
                .stream()
                .map(e -> ConsentEntityConverter.toFhir(e, fhirReferenceURL))
                .collect(Collectors.toList());
    }

    @GET
    @Path("/{consentId}")
    @FHIR
    @Timed
    @ExceptionMetered
    @UnitOfWork
    @ApiOperation(value = "Locate a Consent entry by id")
    @ApiResponses(@ApiResponse(code = 400, message = "invalid id value. Must have a consent resource id"))
    public Consent getConsent(@ApiParam(value = "Consent resource ID", required = true) @PathParam("consentId") UUID consentId) {

        final ConsentEntity consentEntity = this.dao.getConsent(consentId).orElseThrow(() ->
                new WebApplicationException("invalid consent resource id value", HttpStatus.NOT_FOUND_404)
        );

        return ConsentEntityConverter.toFhir(consentEntity, fhirReferenceURL);
    }

    @PUT
    @Path("/{consentId}")
    @FHIR
    @UnitOfWork
    @ApiOperation(value = "Update a Consent resource")
    @ApiResponses(value = { @ApiResponse(code = 200, message = "Consent resource was updated"),
            @ApiResponse(code = 400, message = "Consent resource was not updated due to bad request") })
    public Consent update(@ApiParam(value = "Consent resource ID", required = true) @PathParam("consentId") UUID consentId,
                          @ApiParam(value = "Consent resource", required = true) Consent consent) {
        consent.setId(consentId.toString());
        ConsentEntity entity = ConsentEntityConverter.fromFhir(consent);
        entity = this.dao.persistConsent(entity);
        return ConsentEntityConverter.toFhir(entity, fhirReferenceURL);
    }

    private List<ConsentEntity> getEntitiesByPatient(Identifier patientIdentifier) {
        String field;

        // we have been asked to search for a patient id defined by one among two (soon three!) coding systems
        // we need to determine which database field that system's value is stored in
        switch (DPCIdentifierSystem.fromString(patientIdentifier.getSystem())) {
            case MBI:
                field = "mbi";
                break;
            case HICN:
                field = "hicn";
                break;
            default:
                throw new WebApplicationException("Unknown Patient ID code system", Response.Status.BAD_REQUEST);
        }

        return this.dao.findBy(field, patientIdentifier.getValue());
    }
}