diff --git a/src/main/java/in/projecteka/consentmanager/consent/ConsentArtefactQueryGenerator.java b/src/main/java/in/projecteka/consentmanager/consent/ConsentArtefactQueryGenerator.java deleted file mode 100644 index 0cdb4158c..000000000 --- a/src/main/java/in/projecteka/consentmanager/consent/ConsentArtefactQueryGenerator.java +++ /dev/null @@ -1,57 +0,0 @@ -package in.projecteka.consentmanager.consent; - -import in.projecteka.consentmanager.consent.model.ConsentArtefact; -import in.projecteka.consentmanager.consent.model.ConsentStatus; -import in.projecteka.consentmanager.consent.model.HIPConsentArtefactRepresentation; -import in.projecteka.consentmanager.consent.model.Query; -import in.projecteka.consentmanager.consent.model.QueryRepresentation; -import io.vertx.core.json.JsonObject; -import io.vertx.sqlclient.Tuple; -import lombok.AllArgsConstructor; -import reactor.core.publisher.Mono; - -import java.time.LocalDateTime; -import java.util.List; - -import static in.projecteka.consentmanager.common.Serializer.from; - -@AllArgsConstructor -public class ConsentArtefactQueryGenerator { - private static final String INSERT_CONSENT_ARTEFACT_QUERY = "INSERT INTO consent_artefact" + - " (consent_request_id, consent_artefact_id, patient_id, consent_artefact, signature, status) VALUES" + - " ($1, $2, $3, $4, $5, $6)"; - private static final String INSERT_HIP_CONSENT_ARTEFACT_QUERY = "INSERT INTO hip_consent_artefact" + - " (consent_request_id, consent_artefact_id, patient_id, consent_artefact, signature, status) VALUES" + - " ($1, $2, $3, $4, $5, $6)"; - private static final String UPDATE_CONSENT_REQUEST_STATUS_QUERY = "UPDATE consent_request SET status=$1, " + - "date_modified=$2 WHERE request_id=$3"; - - public Mono toQueries(String requestId, - String patientId, - ConsentArtefact consentArtefact, - HIPConsentArtefactRepresentation hipConsentArtefact, - String consentArtefactSignature) { - Query insertCA = new Query(INSERT_CONSENT_ARTEFACT_QUERY, - Tuple.of(requestId, - consentArtefact.getConsentId(), - patientId, - new JsonObject(from(consentArtefact)), - consentArtefactSignature, - ConsentStatus.GRANTED.toString())); - Query insertHIPCA = new Query(INSERT_HIP_CONSENT_ARTEFACT_QUERY, - Tuple.of(requestId, - hipConsentArtefact.getConsentDetail().getConsentId(), - patientId, - new JsonObject(from(hipConsentArtefact.getConsentDetail())), - consentArtefactSignature, - ConsentStatus.GRANTED.toString())); - Query updateConsentReqStatus = new Query(UPDATE_CONSENT_REQUEST_STATUS_QUERY, - Tuple.of(ConsentStatus.GRANTED.toString(), - LocalDateTime.now(), - requestId)); - return Mono.just(QueryRepresentation.builder() - .queries(List.of(insertCA, insertHIPCA, updateConsentReqStatus)) - .hipConsentArtefactRepresentations(List.of(hipConsentArtefact)) - .build()); - } -} diff --git a/src/main/java/in/projecteka/consentmanager/consent/ConsentArtefactRepository.java b/src/main/java/in/projecteka/consentmanager/consent/ConsentArtefactRepository.java index 82c137a87..f30ac4f78 100644 --- a/src/main/java/in/projecteka/consentmanager/consent/ConsentArtefactRepository.java +++ b/src/main/java/in/projecteka/consentmanager/consent/ConsentArtefactRepository.java @@ -9,8 +9,10 @@ import in.projecteka.consentmanager.consent.model.HIPConsentArtefactRepresentation; import in.projecteka.consentmanager.consent.model.ListResult; import in.projecteka.consentmanager.consent.model.Query; +import in.projecteka.consentmanager.consent.model.QueryRepresentation; import in.projecteka.consentmanager.consent.model.response.ConsentArtefactRepresentation; import io.vertx.core.AsyncResult; +import io.vertx.core.json.JsonObject; import io.vertx.pgclient.PgPool; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.RowSet; @@ -53,6 +55,14 @@ public class ConsentArtefactRepository { "WHERE patient_id=$1 AND (status=$2 OR $2 IS NULL)"; private static final String FAILED_TO_RETRIEVE_CA = "Failed to retrieve Consent Artifact."; private static final String FAILED_TO_SAVE_CONSENT_ARTEFACT = "Failed to save consent artefact"; + private static final String FAILED_TO_UPDATE_STATUS = "Failed to update status"; + private static final String CAN_NOT_INITIALIZE_TRANSACTION = "Can not get connection."; + private static final String INSERT_CONSENT_ARTEFACT_QUERY = "INSERT INTO consent_artefact" + + " (consent_request_id, consent_artefact_id, patient_id, consent_artefact, signature, status) VALUES" + + " ($1, $2, $3, $4, $5, $6)"; + private static final String INSERT_HIP_CONSENT_ARTEFACT_QUERY = "INSERT INTO hip_consent_artefact" + + " (consent_request_id, consent_artefact_id, patient_id, consent_artefact, signature, status) VALUES" + + " ($1, $2, $3, $4, $5, $6)"; static { String s = "SELECT status, consent_artefact, signature, date_modified FROM "; @@ -65,17 +75,22 @@ public class ConsentArtefactRepository { private final PgPool dbClient; - public Mono process(List queries) { - return doInTransaction(queries); + public Mono grantConsentRequest(String requestId, List artefactQueries) { + List queriesInTransaction = new ArrayList<>(artefactQueries); + queriesInTransaction.add(new Query(UPDATE_CONSENT_REQUEST_STATUS_QUERY, + Tuple.of(ConsentStatus.GRANTED.toString(), + LocalDateTime.now(), + requestId))); + return doInTransaction(queriesInTransaction, FAILED_TO_SAVE_CONSENT_ARTEFACT); } - private Mono doInTransaction(List queries) { + private Mono doInTransaction(List queries, String contextErrorMessage) { return Mono.create(monoSink -> dbClient.begin(connectionAttempt -> { if (connectionAttempt.succeeded()) { - TransactionContext context = new TransactionContext(connectionAttempt.result(), monoSink); - context.executeInTransaction(queries.iterator(), FAILED_TO_SAVE_CONSENT_ARTEFACT); + TransactionContext context = new TransactionContext(connectionAttempt.result(), monoSink, contextErrorMessage); + context.executeInTransaction(queries.iterator()); } else { - monoSink.error(new RuntimeException("Can not get connectionAttempt to storage.")); + monoSink.error(new RuntimeException(CAN_NOT_INITIALIZE_TRANSACTION)); } })); } @@ -192,15 +207,8 @@ public Flux getConsentArtefacts(ConsentStatus consentStatus) { } public Mono updateStatus(String consentId, String consentRequestId, ConsentStatus status) { - return Mono.create(monoSink -> dbClient.begin(connectionAttempt -> { - var queries = getUpdateQueries(consentId, consentRequestId, status); - if (connectionAttempt.succeeded()) { - TransactionContext context = new TransactionContext(connectionAttempt.result(), monoSink); - context.executeInTransaction(queries.iterator(), "Failed to update status"); - } else { - monoSink.error(new RuntimeException("Can not get connectionAttempt to storage.")); - } - })); + List queries = getUpdateQueries(consentId, consentRequestId, status); + return doInTransaction(queries, FAILED_TO_UPDATE_STATUS); } public Mono updateConsentArtefactStatus(String consentId, ConsentStatus status) { @@ -263,4 +271,29 @@ private ConsentArtefactRepresentation getConsentArtefactRepresentation(Row row) .signature(row.getString(SIGNATURE)) .build(); } + + public Mono artefactQueries(String requestId, + String patientId, + ConsentArtefact consentArtefact, + HIPConsentArtefactRepresentation hipConsentArtefact, + String consentArtefactSignature) { + Query insertCA = new Query(INSERT_CONSENT_ARTEFACT_QUERY, + Tuple.of(requestId, + consentArtefact.getConsentId(), + patientId, + JsonObject.mapFrom(consentArtefact), + consentArtefactSignature, + ConsentStatus.GRANTED.toString())); + Query insertHIPCA = new Query(INSERT_HIP_CONSENT_ARTEFACT_QUERY, + Tuple.of(requestId, + hipConsentArtefact.getConsentDetail().getConsentId(), + patientId, + JsonObject.mapFrom(hipConsentArtefact.getConsentDetail()), + consentArtefactSignature, + ConsentStatus.GRANTED.toString())); + return Mono.just(QueryRepresentation.builder() + .queries(List.of(insertCA, insertHIPCA)) + .hipConsentArtefactRepresentations(List.of(hipConsentArtefact)) + .build()); + } } diff --git a/src/main/java/in/projecteka/consentmanager/consent/ConsentConfiguration.java b/src/main/java/in/projecteka/consentmanager/consent/ConsentConfiguration.java index a45a1a6ef..e15ae48c9 100644 --- a/src/main/java/in/projecteka/consentmanager/consent/ConsentConfiguration.java +++ b/src/main/java/in/projecteka/consentmanager/consent/ConsentConfiguration.java @@ -81,7 +81,6 @@ public ConsentManager consentRequestService(WebClient.Builder builder, new PatientServiceClient(builder, identityService::authenticate, linkServiceProperties.getUrl()), new CMProperties(identityService.getConsentManagerId()), conceptValidator, - new ConsentArtefactQueryGenerator(), new ConsentManagerClient(builder, gatewayServiceProperties.getBaseUrl(), identityService::authenticate, diff --git a/src/main/java/in/projecteka/consentmanager/consent/ConsentManager.java b/src/main/java/in/projecteka/consentmanager/consent/ConsentManager.java index 156af6500..fd90b21eb 100644 --- a/src/main/java/in/projecteka/consentmanager/consent/ConsentManager.java +++ b/src/main/java/in/projecteka/consentmanager/consent/ConsentManager.java @@ -90,7 +90,6 @@ public class ConsentManager { private final PatientServiceClient patientServiceClient; private final CMProperties cmProperties; private final ConceptValidator conceptValidator; - private final ConsentArtefactQueryGenerator consentArtefactQueryGenerator; private final ConsentManagerClient consentManagerClient; private static boolean isSameRequester(ConsentArtefact consentDetail, String requesterId) { @@ -291,19 +290,19 @@ private Mono> generateConsentArtefacts(St List grantedConsents, String patientId, ConsentRequestDetail consentRequest) { - return getAllQueries(requestId, grantedConsents, patientId, consentRequest) - .map(caQueries -> caQueries.stream().reduce(QueryRepresentation::add).get()) - .flatMap(queryRepresentation -> consentArtefactRepository.process(queryRepresentation.getQueries()) + return artefactRepresentations(requestId, grantedConsents, patientId, consentRequest) + .map(representations -> representations.stream().reduce(QueryRepresentation::add).get()) + .flatMap(queryRepresentation -> consentArtefactRepository.grantConsentRequest(requestId, queryRepresentation.getQueries()) .thenReturn(queryRepresentation.getHipConsentArtefactRepresentations())); } - private Mono> getAllQueries(String requestId, - List grantedConsents, - String patientId, - ConsentRequestDetail consentRequest) { + private Mono> artefactRepresentations(String requestId, + List grantedConsents, + String patientId, + ConsentRequestDetail consentRequest) { return Flux.fromIterable(grantedConsents) .flatMap(grantedConsent -> toConsentArtefact(consentRequest, grantedConsent) - .flatMap(consentArtefact -> consentArtefactQueryGenerator.toQueries(requestId, + .flatMap(consentArtefact -> consentArtefactRepository.artefactQueries(requestId, patientId, consentArtefact, from(consentArtefact, GRANTED), diff --git a/src/main/java/in/projecteka/consentmanager/consent/TransactionContext.java b/src/main/java/in/projecteka/consentmanager/consent/TransactionContext.java index 2a37ecc04..b0193a6bb 100644 --- a/src/main/java/in/projecteka/consentmanager/consent/TransactionContext.java +++ b/src/main/java/in/projecteka/consentmanager/consent/TransactionContext.java @@ -1,18 +1,23 @@ package in.projecteka.consentmanager.consent; import in.projecteka.consentmanager.consent.model.Query; +import io.vertx.core.AsyncResult; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.RowSet; import io.vertx.sqlclient.Transaction; import reactor.core.publisher.MonoSink; import java.util.Iterator; public class TransactionContext { - private final Transaction transaction; - private final MonoSink sink; + private Transaction transaction; + private MonoSink sink; + private final String txErrorMsg; - public TransactionContext(Transaction transaction, MonoSink sink) { + public TransactionContext(Transaction transaction, MonoSink sink, String txErrorMsg) { this.transaction = transaction; this.sink = sink; + this.txErrorMsg = txErrorMsg; } private void commit() { @@ -20,31 +25,34 @@ private void commit() { if (result.succeeded()) { this.sink.success(); } else { - error(new RuntimeException(result.cause().getMessage())); + error(new RuntimeException(this.txErrorMsg, result.cause())); } }); } private void error(RuntimeException e) { + //this.transaction.rollback(); this.sink.error(e); } - public void executeInTransaction(Iterator iterator, String message) { + public void executeInTransaction(Iterator iterator) { if (iterator.hasNext()) { Query query = iterator.next(); transaction.preparedQuery(query.getQueryString()) .execute(query.getParams(), - handler -> { - if (handler.succeeded()) { - if (iterator.hasNext()) { - executeInTransaction(iterator, message); - } else { - commit(); - } - } else { - error(new RuntimeException(message)); - } - }); + handler -> handleResponseAndExecNext(handler, iterator)); + } + } + + private void handleResponseAndExecNext(AsyncResult> handler, Iterator iterator) { + if (handler.succeeded()) { + if (iterator.hasNext()) { + executeInTransaction(iterator); + } else { + commit(); + } + } else { + error(new RuntimeException(this.txErrorMsg, handler.cause())); } } } diff --git a/src/test/java/in/projecteka/consentmanager/consent/ConsentManagerTest.java b/src/test/java/in/projecteka/consentmanager/consent/ConsentManagerTest.java index 55d2cc5da..fbe74c93e 100644 --- a/src/test/java/in/projecteka/consentmanager/consent/ConsentManagerTest.java +++ b/src/test/java/in/projecteka/consentmanager/consent/ConsentManagerTest.java @@ -110,7 +110,6 @@ public void setUp() throws JOSEException { RSAKeyGenerator rsKG = new RSAKeyGenerator(2048); keyPair = rsKG.generate().toKeyPair(); CMProperties cmProperties = new CMProperties("NCG"); - ConsentArtefactQueryGenerator queryGenerator = new ConsentArtefactQueryGenerator(); consentManager = new ConsentManager(userClient, repository, consentArtefactRepository, @@ -121,7 +120,6 @@ public void setUp() throws JOSEException { patientServiceClient, cmProperties, conceptValidator, - queryGenerator, consentManagerClient); } diff --git a/src/test/java/in/projecteka/consentmanager/consent/ConsentRequestUserJourneyTest.java b/src/test/java/in/projecteka/consentmanager/consent/ConsentRequestUserJourneyTest.java index 242d5ba30..a8761fe06 100644 --- a/src/test/java/in/projecteka/consentmanager/consent/ConsentRequestUserJourneyTest.java +++ b/src/test/java/in/projecteka/consentmanager/consent/ConsentRequestUserJourneyTest.java @@ -15,16 +15,21 @@ import in.projecteka.consentmanager.consent.model.ConsentPurpose; import in.projecteka.consentmanager.consent.model.ConsentRequest; import in.projecteka.consentmanager.consent.model.ConsentRequestDetail; +import in.projecteka.consentmanager.consent.model.HIPConsentArtefact; +import in.projecteka.consentmanager.consent.model.HIPConsentArtefactRepresentation; +import in.projecteka.consentmanager.consent.model.PatientReference; +import in.projecteka.consentmanager.consent.model.Query; +import in.projecteka.consentmanager.consent.model.QueryRepresentation; import in.projecteka.consentmanager.consent.model.HIPReference; import in.projecteka.consentmanager.consent.model.HIType; import in.projecteka.consentmanager.consent.model.HIUReference; import in.projecteka.consentmanager.consent.model.ListResult; -import in.projecteka.consentmanager.consent.model.PatientReference; import in.projecteka.consentmanager.consent.model.request.RequestedDetail; import in.projecteka.consentmanager.consent.model.response.ConsentApprovalResponse; import in.projecteka.consentmanager.consent.model.response.ConsentRequestsRepresentation; import in.projecteka.consentmanager.consent.model.response.RequestCreatedRepresentation; import in.projecteka.consentmanager.dataflow.DataFlowBroadcastListener; +import io.vertx.sqlclient.Tuple; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import org.hamcrest.Matchers; @@ -174,7 +179,6 @@ public class ConsentRequestUserJourneyTest { " }\n" + " ]\n" + "}"; - @AfterAll public static void tearDown() throws IOException { clientRegistryServer.shutdown(); @@ -184,6 +188,7 @@ public static void tearDown() throws IOException { gatewayServer.shutdown(); } + private final String requestedConsentJson = "{\n" + " \"status\": \"REQUESTED\",\n" + " \"createdAt\": \"2020-03-14T10:51:05.466\",\n" + @@ -223,7 +228,6 @@ public static void tearDown() throws IOException { " \"lastUpdated\": \"2020-03-14T12:00:52.091\",\n" + " \"id\": \"30d02f6d-de17-405e-b4ab-d31b2bb799d7\"\n" + " }"; - @Test public void shouldAcceptConsentRequest() { var authToken = string(); @@ -361,6 +365,8 @@ public void shouldSendNotificationMessage() { public void shouldApproveConsentGrant() throws JsonProcessingException { var token = string(); String patientId = "ashok.kumar@ncg"; + String consentRequestId = "30d02f6d-de17-405e-b4ab-d31b2bb799d7"; + String grantedConsentId = "grantedForHIP10000005"; var consentRequestDetail = OBJECT_MAPPER.readValue(requestedConsentJson, ConsentRequestDetail.class); load(userServer, "{}"); load(identityServer, "{}"); @@ -393,17 +399,18 @@ public void shouldApproveConsentGrant() throws JsonProcessingException { when(repository.insert(any(), any())).thenReturn(Mono.empty()); when(postConsentRequestNotification.broadcastConsentRequestNotification(captor.capture())) .thenReturn(Mono.empty()); - when(repository.requestOf("30d02f6d-de17-405e-b4ab-d31b2bb799d7", "REQUESTED", patientId)) + when(repository.requestOf(consentRequestId, "REQUESTED", patientId)) .thenReturn(Mono.just(consentRequestDetail)); when(pinVerificationTokenService.validateToken(token, scope)) .thenReturn(Mono.just(new Caller(patientId, false, "randomSessionId"))); - when(consentArtefactRepository.process(any())).thenReturn(Mono.empty()); + when(consentArtefactRepository.artefactQueries(any(), any(), any(), any(), any())).thenReturn(queryRepresentation(grantedConsentId)); + when(consentArtefactRepository.grantConsentRequest(eq(consentRequestId), any())).thenReturn(Mono.empty()); when(consentNotificationPublisher.publish(any())).thenReturn(Mono.empty()); when(conceptValidator.validateHITypes(anyList())).thenReturn(Mono.just(true)); when(centralRegistry.providerWith(eq("10000005"))).thenReturn(Mono.just(Provider.builder().build())); webTestClient.post() - .uri("/consent-requests/30d02f6d-de17-405e-b4ab-d31b2bb799d7/approve") + .uri("/consent-requests/" + consentRequestId + "/approve") .accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON) .header("Authorization", token) @@ -414,6 +421,21 @@ public void shouldApproveConsentGrant() throws JsonProcessingException { .value(ConsentApprovalResponse::getConsents, Matchers.notNullValue()); } + private Mono queryRepresentation(String consentId) { + HIPConsentArtefact consentArtefact = new HIPConsentArtefact(); + consentArtefact.setConsentId(consentId); + var rep = new HIPConsentArtefactRepresentation(); + rep.setConsentDetail(consentArtefact); + Query insertCA = new Query("create consent artefact for HIU", + Tuple.of(consentId)); + Query insertHIPCA = new Query("create consent artefact for HIP", + Tuple.of(consentId)); + return Mono.just(QueryRepresentation.builder() + .queries(List.of(insertCA, insertHIPCA)) + .hipConsentArtefactRepresentations(List.of(rep)) + .build()); + } + @Test public void shouldNotApproveConsentGrantForInvalidCareContext() throws JsonProcessingException { var token = string(); @@ -462,7 +484,7 @@ public void shouldNotApproveConsentGrantForInvalidCareContext() throws JsonProce .thenReturn(Mono.just(new Caller(patientId, false))); when(repository.requestOf("30d02f6d-de17-405e-b4ab-d31b2bb799d7", "REQUESTED", patientId)) .thenReturn(Mono.just(consentRequestDetail)); - when(consentArtefactRepository.process(any())).thenReturn(Mono.empty()); + when(consentArtefactRepository.grantConsentRequest(eq("30d02f6d-de17-405e-b4ab-d31b2bb799d"), any())).thenReturn(Mono.empty()); when(consentNotificationPublisher.publish(any())).thenReturn(Mono.empty()); when(conceptValidator.validateHITypes(anyList())).thenReturn(Mono.just(true));